Add background temperature monitoring daemon

This enables temperature display in the Web portal,
and lays the groundwork for a future fan control
service.
parent 4458da8d
......@@ -139,9 +139,11 @@ uint8_t kestrel_basic_init_complete = 0;
// Thread identifiers
k_tid_t kestrel_service_thread_id = NULL;
k_tid_t kestrel_console_thread_id = NULL;
k_tid_t thermal_service_thread_id = NULL;
// Mutexes
struct k_mutex vuart1_access_mutex;
struct k_mutex occ_access_mutex;
// Console structures
const struct shell *host_console_service_task_shell = NULL;
......@@ -1737,6 +1739,13 @@ static int process_interrupts_stage2(void)
uint8_t led_post_code = (((post_code >> 8) & 0xf) << 4) | (post_code & 0xf);
set_led_bank_display(led_post_code);
if (post_code == 0xfefe)
{
host_power_status = HOST_POWER_STATUS_RUNNING;
set_led_bank_display(0);
display_character('0' + 2 + host_power_status, 0); // STATUS CODE
}
if (enable_post_code_console_output)
{
KESTREL_LOG("[POST CODE] %d.%d", (post_code >> 8) & 0xff, post_code & 0xff);
......@@ -2183,6 +2192,7 @@ static int disable_avsbus_pmbus(const cpu_info_t *cpu_info, int cpu_count)
void power_off_chassis(void)
{
host_power_status = HOST_POWER_STATUS_POWERING_OFF;
display_character('0' + 2 + host_power_status, 0); // STATUS CODE
// Disable PMBUS
if (disable_avsbus_pmbus(g_cpu_info, configured_cpu_count))
......@@ -2196,6 +2206,7 @@ void power_off_chassis(void)
run_post_shutdown_bmc_peripheral_teardown();
host_power_status = HOST_POWER_STATUS_OFFLINE;
display_character('0' + 2 + host_power_status, 0); // STATUS CODE
}
static int power_on_chassis(void)
......@@ -2207,12 +2218,14 @@ static int power_on_chassis(void)
uint8_t byte;
host_power_status = HOST_POWER_STATUS_POWERING_ON;
display_character('0' + 2 + host_power_status, 0); // STATUS CODE
// Verify communication with platform control FPGA
platform_fpga_identifier[0] = i2c_read_register_byte((uint8_t *)I2CMASTER4_BASE, HOST_PLATFORM_FPGA_I2C_ADDRESS, 0x0c, NULL);
if (platform_fpga_identifier[0] == 0xff)
{
host_power_status = HOST_POWER_STATUS_OFFLINE;
display_character('0' + 2 + host_power_status, 0); // STATUS CODE
return -1;
}
platform_fpga_identifier[1] = i2c_read_register_byte((uint8_t *)I2CMASTER4_BASE, HOST_PLATFORM_FPGA_I2C_ADDRESS, 0x0d, NULL);
......@@ -2222,6 +2235,7 @@ static int power_on_chassis(void)
(platform_fpga_identifier[3] != 0x20))
{
host_power_status = HOST_POWER_STATUS_OFFLINE;
display_character('0' + 2 + host_power_status, 0); // STATUS CODE
return -1;
}
KESTREL_LOG("Platform FPGA communication verified");
......@@ -2280,7 +2294,8 @@ static int power_on_chassis(void)
return -5;
}
host_power_status = HOST_POWER_STATUS_RUNNING;
host_power_status = HOST_POWER_STATUS_IPLING;
display_character('0' + 2 + host_power_status, 0); // STATUS CODE
return 0;
}
......@@ -3447,6 +3462,7 @@ int kestrel_init(void)
#if (WITH_ZEPHYR)
// Initialize mutexes
k_mutex_init(&vuart1_access_mutex);
k_mutex_init(&occ_access_mutex);
#endif
for (int i = 0; i < MAX_CPUS_SUPPORTED; i++)
......
......@@ -30,8 +30,9 @@
#define HOST_POWER_STATUS_OFFLINE 0
#define HOST_POWER_STATUS_POWERING_ON 1
#define HOST_POWER_STATUS_RUNNING 2
#define HOST_POWER_STATUS_POWERING_OFF 3
#define HOST_POWER_STATUS_IPLING 2
#define HOST_POWER_STATUS_RUNNING 3
#define HOST_POWER_STATUS_POWERING_OFF 4
#define KESTREL_VERSION_MAJOR 0
#define KESTREL_VERSION_MINOR 1
......@@ -56,6 +57,8 @@ extern uint8_t host_power_status;
#if (WITH_ZEPHYR)
extern k_tid_t kestrel_service_thread_id;
extern k_tid_t kestrel_console_thread_id;
extern k_tid_t thermal_service_thread_id;
extern struct k_mutex occ_access_mutex;
extern const struct shell *host_console_service_task_shell;
#endif
......
......@@ -233,6 +233,11 @@ static int kestrel_shell_cmd_occcontrol(const struct shell *shell, size_t argc,
}
if (strcmp(argv[1], "poll") == 0) {
if (k_mutex_lock(&occ_access_mutex, K_MSEC(1000)) != 0) {
printk("Unable to acquire OCC mutex in a timely manner! %s:%d\n", __FILE__, __LINE__);
return -EAGAIN;
}
if (occ_poll(0, 0x2400, IBM_POWER9_SBE_OCC_RESPONSE_SIZE, response_data, &response_length))
{
shell_print(shell, "OCC not responding!");
......@@ -249,6 +254,13 @@ static int kestrel_shell_cmd_occcontrol(const struct shell *shell, size_t argc,
shell_print(shell, "Temperature sensor 0x%08x: %d° C", host_cpu_temperature_sensor_data[sensor_number].sensor_id, host_cpu_temperature_sensor_data[sensor_number].temperature_c);
}
}
k_mutex_unlock(&occ_access_mutex);
}
else {
shell_print(shell, "%s: Invalid parameter", argv[0]);
print_kestrel_occcontrol_command_usage(shell, argv[0]);
return -1;
}
return 0;
......
......@@ -12,6 +12,7 @@ LOG_MODULE_REGISTER(webportal, LOG_LEVEL_DBG);
#include <data/json.h>
#include "simple_pwm.h"
#include "sbe_fsi.h"
#include "webportal.h"
#include "redfish.h"
......@@ -160,6 +161,9 @@ const char* host_power_status_to_string(int power_status)
else if (power_status == HOST_POWER_STATUS_POWERING_ON) {
return "Powering On";
}
else if (power_status == HOST_POWER_STATUS_IPLING) {
return "Initial Program Load";
}
else if (power_status == HOST_POWER_STATUS_RUNNING) {
return "Online";
}
......@@ -201,6 +205,17 @@ int host_status_handler(struct mg_connection *conn, void *cbdata)
mg_printf(conn, "PWM channel %d - %d%% (%d RPM)<br>\n", i, (pwm_values[i] * 100) / 256, tach_values[i]);
}
mg_printf(conn, "</div>");
if (host_cpu_temperature_sensor_count != 0)
{
mg_printf(conn, "<p>");
mg_printf(conn, "<b>Thermal</b><br>");
mg_printf(conn, "<div style=\"margin-left: 20px\">");
for (i = 0; i < host_cpu_temperature_sensor_count; i++)
{
mg_printf(conn, "Sensor 0x%08x: %d° C<br>\n", host_cpu_temperature_sensor_data[i].sensor_id, host_cpu_temperature_sensor_data[i].temperature_c);
}
mg_printf(conn, "</div>");
}
mg_printf(conn, "<p>");
mg_printf(conn, "<b>Control</b><br>");
mg_printf(conn, "<div style=\"margin-left: 20px\">");
......
......@@ -17,6 +17,7 @@ LOG_MODULE_REGISTER(kestrel_init, LOG_LEVEL_DBG);
#include "webservice.h"
#include "flash_filesystem.h"
#include "sbe_fsi.h"
#include "kestrel.h"
static struct gpio_callback host_power_button_callback_data;
......@@ -30,6 +31,9 @@ static struct k_sem kestrel_init_thread_lock;
static K_THREAD_STACK_DEFINE(kestrel_service_thread_stack, 16384);
static struct k_thread kestrel_service_thread_data;
static K_THREAD_STACK_DEFINE(thermal_service_thread_stack, 16384);
static struct k_thread thermal_service_thread_data;
#define KESTREL_IDLE_THREAD_PRIORITY K_PRIO_PREEMPT(CONFIG_NUM_PREEMPT_PRIORITIES - 1)
#define BUTTON_PRESS_DEBOUNCE_DELAY_MS 200
......@@ -60,6 +64,37 @@ static void kestrel_service_thread(void)
}
}
static void thermal_service_thread(void)
{
uint8_t response_data[IBM_POWER9_SBE_OCC_RESPONSE_SIZE];
size_t response_length = 0;
while (1) {
if (host_power_status == HOST_POWER_STATUS_RUNNING)
{
if (k_mutex_lock(&occ_access_mutex, K_MSEC(1000)) != 0) {
printk("Unable to acquire OCC mutex in a timely manner! %s:%d\n", __FILE__, __LINE__);
continue;
}
if (occ_poll(0, 0x2400, IBM_POWER9_SBE_OCC_RESPONSE_SIZE, response_data, &response_length))
{
// Unable to read sensors
host_cpu_temperature_sensor_count = 0;
}
k_mutex_unlock(&occ_access_mutex);
k_usleep(100000);
}
else
{
host_cpu_temperature_sensor_count = 0;
k_usleep(100000);
}
}
}
void host_power_button_pressed(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
static uint64_t last_press = 0;
......@@ -197,6 +232,12 @@ void main(void)
NULL, NULL, NULL, KESTREL_SERVICE_THREAD_PRIORITY, 0, K_NO_WAIT);
k_thread_name_set(kestrel_service_thread_id, "kestrel_service");
thermal_service_thread_id = k_thread_create(&thermal_service_thread_data, thermal_service_thread_stack,
K_THREAD_STACK_SIZEOF(thermal_service_thread_stack),
(k_thread_entry_t)thermal_service_thread,
NULL, NULL, NULL, KESTREL_SERVICE_THREAD_PRIORITY, 0, K_NO_WAIT);
k_thread_name_set(thermal_service_thread_id, "thermal_service");
// Run late setup
configure_gpios();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment