separate dptf logic from existing thermal logic.

Signed-off-by: Ravi Chandra Sadineni <ravisadineni@chromium.org>

BRANCH=none
BUG=chromium:631848
TEST=make buildall -j

Change-Id: I718a29b067d37af477306f9bebfcb8e71d84d4ee
Reviewed-on: https://chromium-review.googlesource.com/363008
Commit-Ready: David Hendricks <dhendrix@chromium.org>
Tested-by: David Hendricks <dhendrix@chromium.org>
Reviewed-by: David Hendricks <dhendrix@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Reviewed-by: Duncan Laurie <dlaurie@google.com>
This commit is contained in:
Ravi Chandra Sadineni
2016-07-25 18:06:29 -07:00
committed by chrome-bot
parent bcb0de22a4
commit 78a875eadb
7 changed files with 214 additions and 132 deletions

View File

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

View File

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

188
common/dptf.c Normal file
View File

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

View File

@@ -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:

View File

@@ -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"
@@ -25,93 +23,6 @@
#define CPUTS(outstr) cputs(CC_THERMAL, outstr)
#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 */
@@ -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));

View File

@@ -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 */
@@ -2245,6 +2252,16 @@
#define CONFIG_TEMP_SENSOR
#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

View File

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