diff options
author | Vic Yang <victoryang@chromium.org> | 2012-02-27 13:41:32 -0800 |
---|---|---|
committer | Vic Yang <victoryang@chromium.org> | 2012-02-28 16:51:54 -0800 |
commit | 13b5c41951c2da3e90ac115a3dbe8aaddb959782 (patch) | |
tree | 60737feac456fc38c591d8d209b295fe7fcaa660 /common/thermal.c | |
parent | b2b5455f327804bd1f72b3c617745fd5c5ca086b (diff) | |
download | chrome-ec-13b5c41951c2da3e90ac115a3dbe8aaddb959782.tar.gz |
Thermal Engine
The thermal engine monitors the temperature readings from all sensors.
For each sensor, five threshold temperatures can be set:
1. Low fan speed.
2. High fan speed.
3. SMI warning.
4. Shutdown CPU.
5. Shutdown everything we can.
Each of these thresholds can be set to either a fixed value or disabled.
Currently the real implementation of SMI warning and shutting down is
left as TODO, as indicated in the comment.
Signed-off-by: Vic Yang <victoryang@chromium.org>
BUG=chrome-os-partner:8250
TEST=Manually change threshold value to test all actions can be triggered.
Change-Id: If168dcff78ef2d7a3203cb227e1739a08eca961e
Diffstat (limited to 'common/thermal.c')
-rw-r--r-- | common/thermal.c | 195 |
1 files changed, 195 insertions, 0 deletions
diff --git a/common/thermal.c b/common/thermal.c new file mode 100644 index 0000000000..ffcd0986fd --- /dev/null +++ b/common/thermal.c @@ -0,0 +1,195 @@ +/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved. + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +/* Thermal engine module for Chrome EC */ + +#include "board.h" +#include "console.h" +#include "gpio.h" +#include "pwm.h" +#include "task.h" +#include "temp_sensor.h" +#include "thermal.h" +#include "uart.h" +#include "util.h" +#include "x86_power.h" + +/* Defined in board_thermal.c. Must be in the same order + * as in enum temp_sensor_id. */ +extern struct thermal_config_t thermal_config[TEMP_SENSOR_COUNT]; + +/* Number of consecutive overheated events for each temperature sensor. */ +static int8_t ot_count[TEMP_SENSOR_COUNT][THRESHOLD_COUNT]; + +/* Flag that indicate if each threshold is reached. + * Note that higher threshold reached does not necessarily mean lower thresholds + * are reached (since we can disable any threshold.) */ +static int8_t overheated[THRESHOLD_COUNT]; + + +static void smi_overheated_warning(void) +{ + /* TODO: crosbug.com/p/8249 */ +} + + +static void smi_sensor_failure_warning(void) +{ + /* TODO: crosbug.com/p/8249 */ +} + + +static void overheated_action(void) +{ + if (overheated[THRESHOLD_POWER_DOWN]) { + x86_power_force_shutdown(); + return; + } + + if (overheated[THRESHOLD_CPU_DOWN]) + x86_power_cpu_overheated(1); + else { + x86_power_cpu_overheated(0); + if (overheated[THRESHOLD_WARNING]) + smi_overheated_warning(); + } + + if (overheated[THRESHOLD_FAN_HI]) + pwm_set_fan_target_rpm(-1); /* Max RPM. */ + else if (overheated[THRESHOLD_FAN_LO]) + pwm_set_fan_target_rpm(6000); + else + pwm_set_fan_target_rpm(0); +} + + +/* Update counter and check if the counter has reached delay limit. + * Note that we have 10 seconds delay to prevent one error value triggering + * overheated action. */ +static inline void update_and_check_stat(int temp, + int sensor_id, + int threshold_id) +{ + const struct thermal_config_t *config = thermal_config + sensor_id; + const int16_t threshold = config->thresholds[threshold_id]; + + if (threshold > 0 && temp >= threshold) { + ++ot_count[sensor_id][threshold_id]; + if (ot_count[sensor_id][threshold_id] >= 10) { + ot_count[sensor_id][threshold_id] = 10; + overheated[threshold_id] = 1; + } + } + else + ot_count[sensor_id][threshold_id] = 0; +} + + +static void thermal_process(void) +{ + int i, j; + int cur_temp; + + for (i = 0; i < THRESHOLD_COUNT; ++i) + overheated[i] = 0; + + for (i = 0; i < TEMP_SENSOR_COUNT; ++i) { + int flag = thermal_config[i].config_flags; + + if (flag & THERMAL_CONFIG_NEED_VS && + gpio_get_level(GPIO_PGOOD_1_8VS) == 0) + continue; + + if (flag & THERMAL_CONFIG_NEED_CPU && + x86_power_in_S0() == 0) + continue; + + cur_temp = temp_sensor_read(i); + /* Sensor failure. */ + /* TODO: PECI temperature sensor is currently flaky and thus + * sensor failure is now ignored. Change this when we have + * reliable PECI temperature sensor. */ + if (cur_temp == -1) { + if (flag & THERMAL_CONFIG_WARNING_ON_FAIL) + smi_sensor_failure_warning(); + continue; + } + for (j = 0; j < THRESHOLD_COUNT; ++j) + update_and_check_stat(cur_temp, i, j); + } + + overheated_action(); +} + + +void thermal_task(void) +{ + while (1) { + thermal_process(); + /* Wait 1s */ + task_wait_msg(1000000); + } +} + +/*****************************************************************************/ +/* Console commands */ + +static void print_thermal_config(int sensor_id) +{ + const struct thermal_config_t *config = thermal_config + sensor_id; + uart_printf("Sensor %d:\n", sensor_id); + uart_printf("\tFan Low: %d K \n", + config->thresholds[THRESHOLD_FAN_LO]); + uart_printf("\tFan High: %d K \n", + config->thresholds[THRESHOLD_FAN_HI]); + uart_printf("\tWarning: %d K \n", + config->thresholds[THRESHOLD_WARNING]); + uart_printf("\tCPU Down: %d K \n", + config->thresholds[THRESHOLD_CPU_DOWN]); + uart_printf("\tPower Down: %d K \n", + config->thresholds[THRESHOLD_POWER_DOWN]); +} + + +static int command_thermal_config(int argc, char **argv) +{ + char *e; + int sensor_id, threshold_id, value; + + if (argc != 2 && argc != 4) { + uart_puts("Usage: thermal <sensor> [<threshold_id> <value>]\n"); + return EC_ERROR_UNKNOWN; + } + + sensor_id = strtoi(argv[1], &e, 0); + if ((e && *e) || sensor_id < 0 || sensor_id >= TEMP_SENSOR_COUNT) { + uart_puts("Bad sensor ID.\n"); + return EC_ERROR_UNKNOWN; + } + + if (argc == 2) { + print_thermal_config(sensor_id); + return EC_SUCCESS; + } + + threshold_id = strtoi(argv[2], &e, 0); + if ((e && *e) || threshold_id < 0 || threshold_id >= THRESHOLD_COUNT) { + uart_puts("Bad threshold ID.\n"); + return EC_ERROR_UNKNOWN; + } + + value = strtoi(argv[3], &e, 0); + if ((e && *e) || value < 0) { + uart_puts("Bad threshold value.\n"); + return EC_ERROR_UNKNOWN; + } + + thermal_config[sensor_id].thresholds[threshold_id] = value; + uart_printf("Setting threshold %d of sensor %d to %d\n", + threshold_id, sensor_id, value); + + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(thermal, command_thermal_config); |