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
This commit is contained in:
Vic Yang
2012-02-27 13:41:32 -08:00
parent b2b5455f32
commit 13b5c41951
6 changed files with 285 additions and 0 deletions

View File

@@ -0,0 +1,37 @@
/* 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.
*/
/* Link-specific thermal configuration module for Chrome EC */
#include "thermal.h"
#include "board.h"
struct thermal_config_t thermal_config[TEMP_SENSOR_COUNT] = {
/* I2C_CPU-Die */
{THERMAL_CONFIG_NEED_VS, {THERMAL_THRESHOLD_DISABLE_ALL}},
/* I2C_CPU-Object */
{THERMAL_CONFIG_NEED_VS, {313, 323, 343, 353, 358}},
/* I2C_PCH-Die */
{THERMAL_CONFIG_NEED_VS, {THERMAL_THRESHOLD_DISABLE_ALL}},
/* I2C_PCH-Object */
{THERMAL_CONFIG_NEED_VS, {THERMAL_THRESHOLD_DISABLE,
THERMAL_THRESHOLD_DISABLE, 343, THERMAL_THRESHOLD_DISABLE, 358}},
/* I2C_DDR-Die */
{THERMAL_CONFIG_NEED_VS, {THERMAL_THRESHOLD_DISABLE_ALL}},
/* I2C_DDR-Object */
{THERMAL_CONFIG_NEED_VS, {THERMAL_THRESHOLD_DISABLE,
THERMAL_THRESHOLD_DISABLE, 343, THERMAL_THRESHOLD_DISABLE, 358}},
/* I2C_Charger-Die */
{THERMAL_CONFIG_NEED_VS, {THERMAL_THRESHOLD_DISABLE_ALL}},
/* I2C_Charger-Object */
{THERMAL_CONFIG_NEED_VS, {THERMAL_THRESHOLD_DISABLE,
THERMAL_THRESHOLD_DISABLE, 343, THERMAL_THRESHOLD_DISABLE, 358}},
/* ECInternal */
{THERMAL_CONFIG_NO_FLAG, {THERMAL_THRESHOLD_DISABLE,
THERMAL_THRESHOLD_DISABLE, 343, THERMAL_THRESHOLD_DISABLE, 373}},
/* PECI */
{THERMAL_CONFIG_WARNING_ON_FAIL | THERMAL_CONFIG_NEED_CPU,
{328, 338, 343, 348, 353}},
};

View File

@@ -10,3 +10,4 @@ CHIP:=lm4
board-y=board.o
board-$(CONFIG_TEMP_SENSOR)+=board_temp_sensor.o
board-$(CONFIG_TASK_THERMAL)+=board_thermal.o

View File

@@ -16,6 +16,7 @@
#define CONFIG_TASK_LIST \
TASK(WATCHDOG, watchdog_task, NULL) \
TASK(TEMPSENSOR, temp_sensor_task, NULL) \
TASK(THERMAL, thermal_task, NULL) \
TASK(PWM, pwm_task, NULL) \
TASK(KEYSCAN, keyboard_scan_task, NULL) \
TASK(POWERBTN, power_button_task, NULL) \

View File

@@ -16,6 +16,7 @@ common-$(CONFIG_TASK_GAIAPOWER)+=gaia_power.o
common-$(CONFIG_FLASH)+=flash_commands.o
common-$(CONFIG_PSTORE)+=pstore_commands.o
common-$(CONFIG_PWM)+=pwm_commands.o
common-$(CONFIG_TASK_THERMAL)+=thermal.o
common-$(CONFIG_TEMP_SENSOR)+=temp_sensor.o
common-$(CONFIG_TMP006)+=tmp006.o
common-$(CONFIG_LIGHTBAR)+=leds.o

195
common/thermal.c Normal file
View File

@@ -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);

50
include/thermal.h Normal file
View File

@@ -0,0 +1,50 @@
/* 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 */
#ifndef __CROS_EC_THERMAL_H
#define __CROS_EC_THERMAL_H
#include "util.h"
#define THERMAL_CONFIG_NO_FLAG 0x0
#define THERMAL_CONFIG_WARNING_ON_FAIL 0x1
#define THERMAL_CONFIG_NEED_VS 0x2
#define THERMAL_CONFIG_NEED_CPU 0x4
/* Set a threshold temperature to this value to disable the threshold limit. */
#define THERMAL_THRESHOLD_DISABLE 0
/* This macro is used to disable all threshold for a sensor.
* The value 0 expands to all field in the array 'thresholds'. Change this
* if THERMAL_THRESHOLD_DISABLE is no longer 0.
*/
#define THERMAL_THRESHOLD_DISABLE_ALL 0
enum thermal_threshold {
/* Low fan speed */
THRESHOLD_FAN_LO = 0,
/* High fan speed */
THRESHOLD_FAN_HI,
/* Issue overheating warning */
THRESHOLD_WARNING,
/* Shut down CPU */
THRESHOLD_CPU_DOWN,
/* Shut down everything we can */
THRESHOLD_POWER_DOWN,
THRESHOLD_COUNT
};
/* Configuration for temperature sensor. Temperature value in degree K. */
struct thermal_config_t {
/* Configuration flags. */
int8_t config_flags;
/* Threshold temperatures. */
int16_t thresholds[THRESHOLD_COUNT];
};
#endif /* __CROS_EC_THERMAL_H */