diff options
-rw-r--r-- | common/acpi.c | 6 | ||||
-rw-r--r-- | common/build.mk | 1 | ||||
-rw-r--r-- | common/dptf.c | 188 | ||||
-rw-r--r-- | common/temp_sensor.c | 2 | ||||
-rw-r--r-- | common/thermal.c | 129 | ||||
-rw-r--r-- | include/config.h | 17 | ||||
-rw-r--r-- | include/console_channel.inc | 3 |
7 files changed, 214 insertions, 132 deletions
diff --git a/common/acpi.c b/common/acpi.c index 58bb658a84..f4aba3af9b 100644 --- a/common/acpi.c +++ b/common/acpi.c @@ -29,7 +29,7 @@ static int __bss_slow acpi_data_count; /* Test byte in ACPI memory space */ static uint8_t __bss_slow acpi_mem_test; -#ifdef CONFIG_TEMP_SENSOR +#ifdef CONFIG_DPTF static int __bss_slow dptf_temp_sensor_id; /* last sensor ID written */ static int __bss_slow dptf_temp_threshold; /* last threshold written */ #endif @@ -153,7 +153,7 @@ int acpi_ap_to_ec(int is_cmd, uint8_t value, uint8_t *resultptr) result = dptf_get_fan_duty_target(); break; #endif -#ifdef CONFIG_TEMP_SENSOR +#ifdef CONFIG_DPTF case EC_ACPI_MEM_TEMP_ID: result = dptf_query_next_sensor_event(); break; @@ -198,7 +198,7 @@ int acpi_ap_to_ec(int is_cmd, uint8_t value, uint8_t *resultptr) dptf_set_fan_duty_target(data); break; #endif -#ifdef CONFIG_TEMP_SENSOR +#ifdef CONFIG_DPTF case EC_ACPI_MEM_TEMP_ID: dptf_temp_sensor_id = data; break; diff --git a/common/build.mk b/common/build.mk index 1163699960..2e0eb3e946 100644 --- a/common/build.mk +++ b/common/build.mk @@ -40,6 +40,7 @@ common-$(CONFIG_COMMON_RUNTIME)+=hooks.o main.o system.o shared_mem.o common-$(CONFIG_COMMON_TIMER)+=timer.o common-$(CONFIG_CRC8)+= crc8.o common-$(CONFIG_DEVICE_STATE)+=device_state.o +common-$(CONFIG_DPTF)+=dptf.o common-$(CONFIG_EXTENSION_COMMAND)+=extension.o common-$(CONFIG_EXTPOWER_GPIO)+=extpower_gpio.o common-$(CONFIG_FANS)+=fan.o pwm.o diff --git a/common/dptf.c b/common/dptf.c new file mode 100644 index 0000000000..638427c3b3 --- /dev/null +++ b/common/dptf.c @@ -0,0 +1,188 @@ +/* Copyright 2016 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. + */ + +#include "atomic.h" +#include "common.h" +#include "console.h" +#include "dptf.h" +#include "hooks.h" +#include "host_command.h" +#include "temp_sensor.h" +#include "util.h" + +/* Console output macros */ +#define CPUTS(outstr) cputs(CC_DPTF, outstr) +#define CPRINTS(format, args...) cprints(CC_DPTF, format, ## args) + +/*****************************************************************************/ +/* DPTF temperature thresholds */ + +static struct { + int temp; /* degrees K, negative for disabled */ + cond_t over; /* watch for crossings */ +} dptf_threshold[TEMP_SENSOR_COUNT][DPTF_THRESHOLDS_PER_SENSOR]; + +static void dptf_init(void) +{ + int id, t; + + for (id = 0; id < TEMP_SENSOR_COUNT; id++) + for (t = 0; t < DPTF_THRESHOLDS_PER_SENSOR; t++) { + dptf_threshold[id][t].temp = -1; + cond_init(&dptf_threshold[id][t].over, 0); + } + +} +DECLARE_HOOK(HOOK_INIT, dptf_init, HOOK_PRIO_DEFAULT); + +/* Keep track of which triggered sensor thresholds the AP has seen */ +static uint32_t dptf_seen; + +int dptf_query_next_sensor_event(void) +{ + int id; + + for (id = 0; id < TEMP_SENSOR_COUNT; id++) + if (dptf_seen & (1 << id)) { /* atomic? */ + atomic_clear(&dptf_seen, (1 << id)); + return id; + } + + return -1; +} + +/* Return true if any threshold transition occurs. */ +static int dpft_check_temp_threshold(int sensor_id, int temp) +{ + int tripped = 0; + int max, i; + + for (i = 0; i < DPTF_THRESHOLDS_PER_SENSOR; i++) { + + max = dptf_threshold[sensor_id][i].temp; + if (max < 0) /* disabled? */ + continue; + + if (temp >= max) + cond_set_true(&dptf_threshold[sensor_id][i].over); + else if (temp <= max - DPTF_THRESHOLD_HYSTERESIS) + cond_set_false(&dptf_threshold[sensor_id][i].over); + + if (cond_went_true(&dptf_threshold[sensor_id][i].over)) { + CPRINTS("DPTF over threshold [%d][%d", + sensor_id, i); + atomic_or(&dptf_seen, (1 << sensor_id)); + tripped = 1; + } + if (cond_went_false(&dptf_threshold[sensor_id][i].over)) { + CPRINTS("DPTF under threshold [%d][%d", + sensor_id, i); + atomic_or(&dptf_seen, (1 << sensor_id)); + tripped = 1; + } + } + + return tripped; +} + +void dptf_set_temp_threshold(int sensor_id, int temp, int idx, int enable) +{ + CPRINTS("DPTF sensor %d, threshold %d C, index %d, %sabled", + sensor_id, K_TO_C(temp), idx, enable ? "en" : "dis"); + + if (enable) { + /* Don't update threshold condition if already enabled */ + if (dptf_threshold[sensor_id][idx].temp == -1) + cond_init(&dptf_threshold[sensor_id][idx].over, 0); + dptf_threshold[sensor_id][idx].temp = temp; + atomic_clear(&dptf_seen, (1 << sensor_id)); + } else { + dptf_threshold[sensor_id][idx].temp = -1; + } +} + +/*****************************************************************************/ +/* EC-specific thermal controls */ + +test_mockable_static void smi_sensor_failure_warning(void) +{ + CPRINTS("can't read any temp sensors!"); + host_set_single_event(EC_HOST_EVENT_THERMAL); +} + +static void thermal_control_dptf(void) +{ + int i, t, rv; + int dptf_tripped; + int num_sensors_read; + + dptf_tripped = 0; + num_sensors_read = 0; + + /* go through all the sensors */ + for (i = 0; i < TEMP_SENSOR_COUNT; ++i) { + rv = temp_sensor_read(i, &t); + if (rv != EC_SUCCESS) + continue; + else + num_sensors_read++; + /* and check the dptf thresholds */ + dptf_tripped |= dpft_check_temp_threshold(i, t); + } + + if (!num_sensors_read) { + /* + * Trigger a SMI event if we can't read any sensors. + * + * In theory we could do something more elaborate like forcing + * the system to shut down if no sensors are available after + * several retries. This is a very unlikely scenario - + * particularly on LM4-based boards, since the LM4 has its own + * internal temp sensor. It's most likely to occur during + * bringup of a new board, where we haven't debugged the I2C + * bus to the sensors; forcing a shutdown in that case would + * merely hamper board bringup. + */ + smi_sensor_failure_warning(); + } + + /* Don't forget to signal any DPTF thresholds */ + if (dptf_tripped) + host_set_single_event(EC_HOST_EVENT_THERMAL_THRESHOLD); +} + +/* Wait until after the sensors have been read */ +DECLARE_HOOK(HOOK_SECOND, thermal_control_dptf, HOOK_PRIO_TEMP_SENSOR_DONE); + +/*****************************************************************************/ +/* Console commands */ + +static int command_dptftemp(int argc, char **argv) +{ + int id, t; + int temp, trig; + + ccprintf("sensor thresh0 thresh1\n"); + for (id = 0; id < TEMP_SENSOR_COUNT; id++) { + ccprintf(" %2d", id); + for (t = 0; t < DPTF_THRESHOLDS_PER_SENSOR; t++) { + temp = dptf_threshold[id][t].temp; + trig = cond_is_true(&dptf_threshold[id][t].over); + if (temp < 0) + ccprintf(" --- "); + else + ccprintf(" %3d%c", temp, + trig ? '*' : ' '); + } + ccprintf(" %s\n", temp_sensors[id].name); + } + + ccprintf("AP seen mask: 0x%08x\n", dptf_seen); + return EC_SUCCESS; +} +DECLARE_CONSOLE_COMMAND(dptftemp, command_dptftemp, + NULL, + "Print DPTF thermal parameters (degrees Kelvin)", + NULL); diff --git a/common/temp_sensor.c b/common/temp_sensor.c index 4f1a8d7701..7586fa9945 100644 --- a/common/temp_sensor.c +++ b/common/temp_sensor.c @@ -111,6 +111,7 @@ static int command_temps(int argc, char **argv) switch (rv) { case EC_SUCCESS: ccprintf("%d K = %d C", t, K_TO_C(t)); +#ifdef CONFIG_THROTTLE_AP if (thermal_params[i].temp_fan_off && thermal_params[i].temp_fan_max) ccprintf(" %d%%", @@ -118,6 +119,7 @@ static int command_temps(int argc, char **argv) thermal_params[i].temp_fan_off, thermal_params[i].temp_fan_max, t)); +#endif ccprintf("\n"); break; case EC_ERROR_NOT_POWERED: diff --git a/common/thermal.c b/common/thermal.c index a2563f1785..d8a0ba52de 100644 --- a/common/thermal.c +++ b/common/thermal.c @@ -7,11 +7,9 @@ * implementation from the original version that shipped on Link. */ -#include "atomic.h" #include "chipset.h" #include "common.h" #include "console.h" -#include "dptf.h" #include "fan.h" #include "hooks.h" #include "host_command.h" @@ -26,93 +24,6 @@ #define CPRINTS(format, args...) cprints(CC_THERMAL, format, ## args) /*****************************************************************************/ -/* DPTF temperature thresholds */ - -static struct { - int temp; /* degrees K, negative for disabled */ - cond_t over; /* watch for crossings */ -} dptf_threshold[TEMP_SENSOR_COUNT][DPTF_THRESHOLDS_PER_SENSOR]; - -static void dptf_init(void) -{ - int id, t; - - for (id = 0; id < TEMP_SENSOR_COUNT; id++) - for (t = 0; t < DPTF_THRESHOLDS_PER_SENSOR; t++) { - dptf_threshold[id][t].temp = -1; - cond_init(&dptf_threshold[id][t].over, 0); - } - -} -DECLARE_HOOK(HOOK_INIT, dptf_init, HOOK_PRIO_DEFAULT); - -/* Keep track of which triggered sensor thresholds the AP has seen */ -static uint32_t dptf_seen; - -int dptf_query_next_sensor_event(void) -{ - int id; - - for (id = 0; id < TEMP_SENSOR_COUNT; id++) - if (dptf_seen & (1 << id)) { /* atomic? */ - atomic_clear(&dptf_seen, (1 << id)); - return id; - } - - return -1; -} - -/* Return true if any threshold transition occurs. */ -static int dpft_check_temp_threshold(int sensor_id, int temp) -{ - int tripped = 0; - int max, i; - - for (i = 0; i < DPTF_THRESHOLDS_PER_SENSOR; i++) { - - max = dptf_threshold[sensor_id][i].temp; - if (max < 0) /* disabled? */ - continue; - - if (temp >= max) - cond_set_true(&dptf_threshold[sensor_id][i].over); - else if (temp <= max - DPTF_THRESHOLD_HYSTERESIS) - cond_set_false(&dptf_threshold[sensor_id][i].over); - - if (cond_went_true(&dptf_threshold[sensor_id][i].over)) { - CPRINTS("DPTF over threshold [%d][%d", - sensor_id, i); - atomic_or(&dptf_seen, (1 << sensor_id)); - tripped = 1; - } - if (cond_went_false(&dptf_threshold[sensor_id][i].over)) { - CPRINTS("DPTF under threshold [%d][%d", - sensor_id, i); - atomic_or(&dptf_seen, (1 << sensor_id)); - tripped = 1; - } - } - - return tripped; -} - -void dptf_set_temp_threshold(int sensor_id, int temp, int idx, int enable) -{ - CPRINTS("DPTF sensor %d, threshold %d C, index %d, %sabled", - sensor_id, K_TO_C(temp), idx, enable ? "en" : "dis"); - - if (enable) { - /* Don't update threshold condition if already enabled */ - if (dptf_threshold[sensor_id][idx].temp == -1) - cond_init(&dptf_threshold[sensor_id][idx].over, 0); - dptf_threshold[sensor_id][idx].temp = temp; - atomic_clear(&dptf_seen, (1 << sensor_id)); - } else { - dptf_threshold[sensor_id][idx].temp = -1; - } -} - -/*****************************************************************************/ /* EC-specific thermal controls */ test_mockable_static void smi_sensor_failure_warning(void) @@ -146,7 +57,6 @@ static void thermal_control(void) int num_valid_limits[EC_TEMP_THRESH_COUNT]; int num_sensors_read; int fmax; - int dptf_tripped; int temp_fan_configured; /* Get ready to count things */ @@ -155,7 +65,6 @@ static void thermal_control(void) memset(num_valid_limits, 0, sizeof(num_valid_limits)); num_sensors_read = 0; fmax = 0; - dptf_tripped = 0; temp_fan_configured = 0; /* go through all the sensors */ @@ -191,9 +100,6 @@ static void thermal_control(void) temp_fan_configured = 1; } - - /* and check the dptf thresholds */ - dptf_tripped |= dpft_check_temp_threshold(i, t); } if (!num_sensors_read) { @@ -266,10 +172,6 @@ static void thermal_control(void) fan_set_percent_needed(i, fmax); #endif } - - /* Don't forget to signal any DPTF thresholds */ - if (dptf_tripped) - host_set_single_event(EC_HOST_EVENT_THERMAL_THRESHOLD); } /* Wait until after the sensors have been read */ @@ -349,36 +251,6 @@ DECLARE_CONSOLE_COMMAND(thermalset, command_thermalset, " Use -1 to skip.", NULL); - -static int command_dptftemp(int argc, char **argv) -{ - int id, t; - int temp, trig; - - ccprintf("sensor thresh0 thresh1\n"); - for (id = 0; id < TEMP_SENSOR_COUNT; id++) { - ccprintf(" %2d", id); - for (t = 0; t < DPTF_THRESHOLDS_PER_SENSOR; t++) { - temp = dptf_threshold[id][t].temp; - trig = cond_is_true(&dptf_threshold[id][t].over); - if (temp < 0) - ccprintf(" --- "); - else - ccprintf(" %3d%c", temp, - trig ? '*' : ' '); - } - ccprintf(" %s\n", temp_sensors[id].name); - } - - ccprintf("AP seen mask: 0x%08x\n", dptf_seen); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(dptftemp, command_dptftemp, - NULL, - "Print DPTF thermal parameters (degrees Kelvin)", - NULL); - - /*****************************************************************************/ /* Host commands. We'll reuse the host command number, but this is version 1, * not version 0. Different structs, different meanings. @@ -414,4 +286,3 @@ static int thermal_command_get_threshold(struct host_cmd_handler_args *args) DECLARE_HOST_COMMAND(EC_CMD_THERMAL_GET_THRESHOLD, thermal_command_get_threshold, EC_VER_MASK(1)); - diff --git a/include/config.h b/include/config.h index d3b15932cf..0142e1286c 100644 --- a/include/config.h +++ b/include/config.h @@ -1768,6 +1768,13 @@ /* Compile common code for throttling the CPU based on the temp sensors */ #undef CONFIG_THROTTLE_AP +/* + * If defined, dptf is enabled to manage thermals. + * + * NOTE: This doesn't mean that thermal control is completely taken care by + * DPTF. We have some hybrid solutions where the EC still manages the fans. + */ +#undef CONFIG_DPTF /*****************************************************************************/ /* TPM-like configuration */ @@ -2246,6 +2253,16 @@ #endif /******************************************************************************/ +/* + * DPTF must have temperature sensor enabled to get the readings for + * generating DPTF thresholds events. + */ +#if defined(CONFIG_DPTF) && !defined(CONFIG_TEMP_SENSOR) +#define CONFIG_TEMP_SENSOR +#endif + + +/******************************************************************************/ /* The Matrix Keyboard Protocol depends on MKBP events. */ #ifdef CONFIG_KEYBOARD_PROTOCOL_MKBP #define CONFIG_MKBP_EVENT diff --git a/include/console_channel.inc b/include/console_channel.inc index f6aefd7e6c..4faeff5281 100644 --- a/include/console_channel.inc +++ b/include/console_channel.inc @@ -60,6 +60,9 @@ CONSOLE_CHANNEL(CC_SWITCH, "switch") #endif CONSOLE_CHANNEL(CC_SYSTEM, "system") CONSOLE_CHANNEL(CC_TASK, "task") +#ifdef CONFIG_DPTF +CONSOLE_CHANNEL(CC_DPTF, "dptf") +#endif CONSOLE_CHANNEL(CC_THERMAL, "thermal") CONSOLE_CHANNEL(CC_TPM, "tpm") CONSOLE_CHANNEL(CC_USB, "usb") |