summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorBill Richardson <wfrichar@chromium.org>2013-09-06 13:01:48 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2013-09-11 01:49:48 +0000
commit793b52f327b20ee5897dc04093ac30a5d000d6e9 (patch)
treeb85f745c8c3f0d3d877733d18caadb626e56927b /common
parente6401d2e83939a63cbd156fa193f9768063d9325 (diff)
downloadchrome-ec-793b52f327b20ee5897dc04093ac30a5d000d6e9.tar.gz
Handle multiple independent sources and types of CPU throttling
Depending on the system, the AP can be throttled in at least two different ways - politely, where it's just asked to slow down a bit, and forcefully using a hardware signal (like PROCHOT). In addition, the request for throttling can come from multiple tasks. This CL provides a single interface, specifying both the type of throttling desired and the source of the throttling request. For each type, any source can can start throttling, but all sources must agree before it stops. The changes are protected by a mutex, so that requests from multiple tasks don't interfere with each other. BUG=chrome-os-partner:20739,chromium:287985,chromium:287983 BRANCH=ToT TEST=manual Build-time test: cd src/platform/ec make BOARD=falco runtests Run-time test: Lower the temp thresholds, turn the fan off, and watch the throttling turn off and on as things heat up. For example, on the EC console: > temps PECI : 339 K = 66 C ECInternal : 324 K = 51 C G781Internal : 328 K = 55 C G781External : 327 K = 54 C > thermalset 0 341 343 sensor warn high halt fan_off fan_max name 0 341 343 383 333 363 PECI 1 0 0 0 0 0 ECInternal 2 0 0 0 0 0 G781Internal 3 0 0 0 0 0 G781External > > temps PECI : 339 K = 66 C ECInternal : 324 K = 51 C G781Internal : 328 K = 55 C G781External : 327 K = 54 C > > fanduty 0 Setting fan duty cycle to 0% > > apthrottle AP throttling type 0 is off (0x00000000) AP throttling type 1 is off (0x00000000) > [430.152000 thermal WARN] [430.152233 event set 0x00020000] [430.152497 event clear 0x00020000] [430.152714 ACPI query = 18] [430.152444 sci 0x00020000] [430.153051 set AP throttling type 0 to on (0x00000001)] > gpioget CPU_PROCHOT 0 CPU_PROCHOT > [436.153742 thermal HIGH] [436.153979 set AP throttling type 1 to on (0x00000001)] > gpioget CPU_PROCHOT 1* CPU_PROCHOT > [441.155319 thermal no longer high] [441.155587 set AP throttling type 1 to off (0x00000000)] [442.155604 thermal HIGH] [442.155841 set AP throttling type 1 to on (0x00000001)] [446.156623 thermal no longer high] [446.156890 set AP throttling type 1 to off (0x00000000)] temps PECI : 343 K = 70 C ECInternal : 324 K = 51 C G781Internal : 328 K = 55 C G781External : 327 K = 54 C > [447.156827 thermal HIGH] [447.157064 set AP throttling type 1 to on (0x00000001)] apthrottle AP throttling type 0 is on (0x00000001) AP throttling type 1 is on (0x00000001) > gpioget CPU_PROCHOT 1 CPU_PROCHOT > Now turn the fan back on: > fanauto > [456.159306 thermal no longer high] [456.159574 set AP throttling type 1 to off (0x00000000)] > apthrottle AP throttling type 0 is on (0x00000001) AP throttling type 1 is off (0x00000000) > temps PECI : 341 K = 68 C ECInternal : 324 K = 51 C G781Internal : 328 K = 55 C G781External : 327 K = 54 C > [473.163905 thermal no longer warn] [473.164168 event set 0x00040000] [473.164453 event clear 0x00040000] [473.164670 ACPI query = 19] [473.164379 sci 0x00040000] [473.164987 set AP throttling type 0 to off (0x00000000)] temps PECI : 340 K = 67 C ECInternal : 324 K = 51 C G781Internal : 328 K = 55 C G781External : 327 K = 54 C > > apthrottle AP throttling type 0 is off (0x00000000) AP throttling type 1 is off (0x00000000) > Change-Id: I9ee1491a637d7766395c71e57483fbd9177ea554 Signed-off-by: Bill Richardson <wfrichar@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/168802
Diffstat (limited to 'common')
-rw-r--r--common/build.mk1
-rw-r--r--common/chipset_haswell.c3
-rw-r--r--common/extpower_falco.c36
-rw-r--r--common/mock_charger.c3
-rw-r--r--common/thermal.c9
-rw-r--r--common/throttle_ap.c96
6 files changed, 132 insertions, 16 deletions
diff --git a/common/build.mk b/common/build.mk
index a97d9fdf2e..3256982ef0 100644
--- a/common/build.mk
+++ b/common/build.mk
@@ -9,6 +9,7 @@
common-y=main.o util.o console_output.o uart_buffering.o
common-y+=memory_commands.o shared_mem.o system_common.o hooks.o
common-y+=gpio_common.o version.o printf.o queue.o getset.o
+common-y+=throttle_ap.o
common-$(BOARD_bolt)+=battery_link.o
common-$(BOARD_daisy)+=extpower_snow.o
diff --git a/common/chipset_haswell.c b/common/chipset_haswell.c
index 1885f76d3c..fcdd00bdc4 100644
--- a/common/chipset_haswell.c
+++ b/common/chipset_haswell.c
@@ -106,7 +106,8 @@ void chipset_reset(int cold_reset)
void chipset_throttle_cpu(int throttle)
{
- /* FIXME CPRINTF("[%T %s(%d)]\n", __func__, throttle);*/
+ if (chipset_in_state(CHIPSET_STATE_ON))
+ gpio_set_level(GPIO_CPU_PROCHOT, throttle);
}
enum x86_state x86_chipset_init(void)
diff --git a/common/extpower_falco.c b/common/extpower_falco.c
index 2730a06e3c..ff1166f778 100644
--- a/common/extpower_falco.c
+++ b/common/extpower_falco.c
@@ -26,6 +26,7 @@
#include "hooks.h"
#include "host_command.h"
#include "smart_battery.h"
+#include "throttle_ap.h"
#include "util.h"
/* Console output macros */
@@ -194,21 +195,34 @@ bad:
CPRINTF("[%T ERROR: can't talk to charger: %d]\n", r);
}
-test_export_static int ap_is_throttled;
-static void set_throttle(int on)
+
+/* We need to OR all the possible reasons to throttle in order to decide
+ * whether it should happen or not. Use one bit per reason.
+ */
+#define BATT_REASON_OFFSET 0
+#define AC_REASON_OFFSET NUM_BATT_THRESHOLDS
+BUILD_ASSERT(NUM_BATT_THRESHOLDS + NUM_AC_THRESHOLDS < 32);
+
+test_export_static uint32_t ap_is_throttled;
+static void set_throttle(int on, int whosays)
{
- host_throttle_cpu(on);
- ap_is_throttled = on;
+ if (on)
+ ap_is_throttled |= (1 << whosays);
+ else
+ ap_is_throttled &= ~(1 << whosays);
+
+ throttle_ap(ap_is_throttled ? THROTTLE_ON : THROTTLE_OFF,
+ THROTTLE_SOFT, THROTTLE_SRC_POWER);
}
test_export_static
-void check_threshold(int current, struct adapter_limits *lim)
+void check_threshold(int current, struct adapter_limits *lim, int whoami)
{
if (lim->triggered) {
/* watching for current to drop */
if (current < lim->lo_val) {
if (++lim->count >= lim->lo_cnt) {
- set_throttle(0);
+ set_throttle(0, whoami);
lim->count = 0;
lim->triggered = 0;
}
@@ -219,7 +233,7 @@ void check_threshold(int current, struct adapter_limits *lim)
/* watching for current to rise */
if (current > lim->hi_val) {
if (++lim->count >= lim->hi_cnt) {
- set_throttle(1);
+ set_throttle(1, whoami);
lim->count = 0;
lim->triggered = 1;
}
@@ -251,7 +265,8 @@ void watch_battery_closely(struct power_state_context *ctx)
/* Check limits against DISCHARGE current, not CHARGE current! */
for (i = 0; i < NUM_BATT_THRESHOLDS; i++)
- check_threshold(-current, &batt_limits[i]); /* invert sign! */
+ check_threshold(-current, &batt_limits[i], /* invert sign! */
+ i + BATT_REASON_OFFSET);
}
void watch_adapter_closely(struct power_state_context *ctx)
@@ -288,13 +303,14 @@ void watch_adapter_closely(struct power_state_context *ctx)
/* Check all the thresholds. */
current = adc_read_channel(ADC_CH_CHARGER_CURRENT);
for (i = 0; i < NUM_AC_THRESHOLDS; i++)
- check_threshold(current, &ad_limits[ac_adapter][ac_turbo][i]);
+ check_threshold(current, &ad_limits[ac_adapter][ac_turbo][i],
+ i + AC_REASON_OFFSET);
}
static int command_adapter(int argc, char **argv)
{
enum adapter_type v = identify_adapter();
- ccprintf("Adapter %s (%dmv), turbo %d, AP_throttled %d\n",
+ ccprintf("Adapter %s (%dmv), turbo %d, ap_is_throttled 0x%08x\n",
ad_name[v], last_mv, ac_turbo, ap_is_throttled);
return EC_SUCCESS;
}
diff --git a/common/mock_charger.c b/common/mock_charger.c
index ebbf5e87bb..f63eebbea3 100644
--- a/common/mock_charger.c
+++ b/common/mock_charger.c
@@ -73,8 +73,9 @@ int charger_set_current(int current)
if (current > info->current_max)
current = info->current_max;
+ if (mock_current != current)
+ uart_printf("Charger set current: %d\n", current);
mock_current = current;
- uart_printf("Charger set current: %d\n", current);
return EC_SUCCESS;
}
diff --git a/common/thermal.c b/common/thermal.c
index 638bd0c0f7..c51b5dc01a 100644
--- a/common/thermal.c
+++ b/common/thermal.c
@@ -15,6 +15,7 @@
#include "host_command.h"
#include "temp_sensor.h"
#include "thermal.h"
+#include "throttle_ap.h"
#include "timer.h"
#include "util.h"
@@ -131,18 +132,18 @@ static void thermal_control(void)
if (cond_went_true(&cond_hot[EC_TEMP_THRESH_HIGH])) {
CPRINTF("[%T thermal HIGH]\n");
- chipset_throttle_cpu(1);
+ throttle_ap(THROTTLE_ON, THROTTLE_HARD, THROTTLE_SRC_THERMAL);
} else if (cond_went_false(&cond_hot[EC_TEMP_THRESH_HIGH])) {
CPRINTF("[%T thermal no longer high]\n");
- chipset_throttle_cpu(0);
+ throttle_ap(THROTTLE_OFF, THROTTLE_HARD, THROTTLE_SRC_THERMAL);
}
if (cond_went_true(&cond_hot[EC_TEMP_THRESH_WARN])) {
CPRINTF("[%T thermal WARN]\n");
- host_throttle_cpu(1);
+ throttle_ap(THROTTLE_ON, THROTTLE_SOFT, THROTTLE_SRC_THERMAL);
} else if (cond_went_false(&cond_hot[EC_TEMP_THRESH_WARN])) {
CPRINTF("[%T thermal no longer warn]\n");
- host_throttle_cpu(0);
+ throttle_ap(THROTTLE_OFF, THROTTLE_SOFT, THROTTLE_SRC_THERMAL);
}
/* Max fan needed is what's needed. */
diff --git a/common/throttle_ap.c b/common/throttle_ap.c
new file mode 100644
index 0000000000..0c671842db
--- /dev/null
+++ b/common/throttle_ap.c
@@ -0,0 +1,96 @@
+/* Copyright (c) 2013 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.
+ */
+
+/* Common chipset throttling code for Chrome EC */
+
+#include "chipset.h"
+#include "common.h"
+#include "console.h"
+#include "host_command.h"
+#include "task.h"
+#include "throttle_ap.h"
+#include "util.h"
+
+/* Console output macros */
+#define CPUTS(outstr) cputs(CC_CHIPSET, outstr)
+#define CPRINTF(format, args...) cprintf(CC_CHIPSET, format, ## args)
+
+/*****************************************************************************/
+/* This enforces the virtual OR of all throttling sources. */
+static struct mutex throttle_mutex;
+static uint32_t throttle_request[NUM_THROTTLE_TYPES];
+
+void throttle_ap(enum throttle_level level,
+ enum throttle_type type,
+ enum throttle_sources source)
+{
+ uint32_t tmpval, bitmask;
+
+ mutex_lock(&throttle_mutex);
+
+ bitmask = (1 << source);
+
+ switch (level) {
+ case THROTTLE_ON:
+ throttle_request[type] |= bitmask;
+ break;
+ case THROTTLE_OFF:
+ throttle_request[type] &= ~bitmask;
+ break;
+ }
+
+ tmpval = throttle_request[type]; /* save for printing */
+
+ switch (type) {
+ case THROTTLE_SOFT:
+#ifdef HAS_TASK_HOSTCMD
+ host_throttle_cpu(tmpval);
+#endif
+ break;
+ case THROTTLE_HARD:
+#ifdef CONFIG_CHIPSET_CAN_THROTTLE
+ chipset_throttle_cpu(tmpval);
+#endif
+ break;
+
+ case NUM_THROTTLE_TYPES:
+ /* Make the compiler shut up. Don't use 'default', because
+ * we still want to catch any new types.
+ */
+ break;
+ }
+
+ mutex_unlock(&throttle_mutex);
+
+ /* print outside the mutex */
+ CPRINTF("[%T set AP throttling type %d to %s (0x%08x)]\n",
+ type, tmpval ? "on" : "off", tmpval);
+
+}
+
+/*****************************************************************************/
+/* Console commands */
+
+static int command_apthrottle(int argc, char **argv)
+{
+ int i;
+ uint32_t tmpval;
+
+ for (i = 0; i < NUM_THROTTLE_TYPES; i++) {
+ mutex_lock(&throttle_mutex);
+ tmpval = throttle_request[i];
+ mutex_unlock(&throttle_mutex);
+
+ ccprintf("AP throttling type %d is %s (0x%08x)\n", i,
+ tmpval ? "on" : "off", tmpval);
+ }
+
+ return EC_SUCCESS;
+}
+DECLARE_CONSOLE_COMMAND(apthrottle, command_apthrottle,
+ NULL,
+ "Display the AP throttling state",
+ NULL);
+