mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2026-01-06 15:01:35 +00:00
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
619 lines
15 KiB
C
619 lines
15 KiB
C
/* 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.
|
|
*
|
|
* Test GPIO extpower module.
|
|
*/
|
|
|
|
#include "adc.h"
|
|
#include "common.h"
|
|
#include "console.h"
|
|
#include "extpower.h"
|
|
#include "gpio.h"
|
|
#include "hooks.h"
|
|
#include "host_command.h"
|
|
#include "test_util.h"
|
|
#include "timer.h"
|
|
#include "util.h"
|
|
#include "chipset.h"
|
|
#include "chipset_x86_common.h"
|
|
|
|
/* Normally private stuff from the modules we're going to test */
|
|
#include "adapter_externs.h"
|
|
|
|
/* Local state */
|
|
static int mock_ac;
|
|
static int mock_id;
|
|
static int mock_current;
|
|
static struct power_state_context ctx;
|
|
|
|
static void test_reset_mocks(void)
|
|
{
|
|
mock_ac = 0;
|
|
mock_id = 0;
|
|
mock_current = 0;
|
|
memset(&ctx, 0, sizeof(ctx));
|
|
}
|
|
|
|
/* Mocked functions from the rest of the EC */
|
|
|
|
int gpio_get_level(enum gpio_signal signal)
|
|
{
|
|
if (signal == GPIO_AC_PRESENT)
|
|
return mock_ac;
|
|
return 0;
|
|
}
|
|
|
|
int adc_read_channel(enum adc_channel ch)
|
|
{
|
|
switch (ch) {
|
|
case ADC_AC_ADAPTER_ID_VOLTAGE:
|
|
return mock_id;
|
|
case ADC_CH_CHARGER_CURRENT:
|
|
return mock_current;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int charger_set_input_current(int input_current)
|
|
{
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
int charger_get_option(int *option)
|
|
{
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
|
|
int charger_set_option(int option)
|
|
{
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
void chipset_throttle_cpu(int throttle)
|
|
{
|
|
/* PROCHOT, ugh. */
|
|
}
|
|
|
|
/* Local functions to control the mocked functions. */
|
|
|
|
static void change_ac(int val)
|
|
{
|
|
mock_ac = val;
|
|
extpower_interrupt(GPIO_AC_PRESENT);
|
|
msleep(50);
|
|
}
|
|
|
|
static void set_id(int val)
|
|
{
|
|
mock_id = val;
|
|
}
|
|
|
|
/* Specify as discharge current */
|
|
static void mock_batt(int cur)
|
|
{
|
|
ctx.curr.batt.current = -cur;
|
|
}
|
|
|
|
/* And the tests themselves... */
|
|
|
|
/*
|
|
* Run through the known ID ranges, making sure that values inside are
|
|
* correctly identified, and values outside are not. We'll skip the default
|
|
* ADAPTER_UNKNOWN range, of course.
|
|
*
|
|
* NOTE: This assumes that the ranges have a gap between them.
|
|
*/
|
|
static int test_identification(void)
|
|
{
|
|
int i;
|
|
|
|
test_reset_mocks();
|
|
|
|
for (i = 1; i < NUM_ADAPTER_TYPES; i++) {
|
|
|
|
change_ac(0);
|
|
TEST_ASSERT(ac_adapter == ADAPTER_UNKNOWN);
|
|
|
|
set_id(ad_id_vals[i].lo - 1);
|
|
change_ac(1);
|
|
TEST_ASSERT(ac_adapter == ADAPTER_UNKNOWN);
|
|
|
|
change_ac(0);
|
|
TEST_ASSERT(ac_adapter == ADAPTER_UNKNOWN);
|
|
|
|
set_id(ad_id_vals[i].lo);
|
|
change_ac(1);
|
|
TEST_ASSERT(ac_adapter == i);
|
|
|
|
change_ac(0);
|
|
TEST_ASSERT(ac_adapter == ADAPTER_UNKNOWN);
|
|
|
|
set_id(ad_id_vals[i].hi);
|
|
change_ac(1);
|
|
TEST_ASSERT(ac_adapter == i);
|
|
|
|
change_ac(0);
|
|
TEST_ASSERT(ac_adapter == ADAPTER_UNKNOWN);
|
|
|
|
set_id(ad_id_vals[i].hi + 1);
|
|
change_ac(1);
|
|
TEST_ASSERT(ac_adapter == ADAPTER_UNKNOWN);
|
|
}
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
/* Helper function */
|
|
static void test_turbo_init(void)
|
|
{
|
|
/* Battery is awake and in good shape */
|
|
ctx.curr.error = 0;
|
|
ctx.curr.batt.state_of_charge = 25;
|
|
|
|
/* Adapter is present and known */
|
|
set_id(ad_id_vals[1].lo + 1);
|
|
change_ac(1);
|
|
}
|
|
|
|
/* Test all the things that can turn turbo mode on and off */
|
|
static int test_turbo(void)
|
|
{
|
|
test_reset_mocks();
|
|
|
|
/* There's only one path that can enable turbo. Check it first. */
|
|
test_turbo_init();
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(ac_turbo == 1);
|
|
|
|
/* Now test things that turn turbo off. */
|
|
|
|
test_turbo_init();
|
|
ctx.curr.error = 1;
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(ac_turbo == 0);
|
|
|
|
test_turbo_init();
|
|
ctx.curr.batt.state_of_charge = 5;
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(ac_turbo == 0);
|
|
|
|
test_turbo_init();
|
|
set_id(ad_id_vals[1].lo - 1);
|
|
change_ac(1);
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(ac_turbo == 0);
|
|
|
|
test_turbo_init();
|
|
change_ac(0);
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(ac_turbo == -1);
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
/* Check the detection logic on one set of struct adapter_limits */
|
|
static int test_thresholds_sequence(int entry)
|
|
{
|
|
struct adapter_limits *lim = &ad_limits[ac_adapter][ac_turbo][entry];
|
|
int longtime = MAX(lim->lo_cnt, lim->hi_cnt) + 2;
|
|
int i;
|
|
|
|
/* reset, by staying low for a long time */
|
|
mock_current = lim->lo_val - 1;
|
|
for (i = 1; i < longtime; i++)
|
|
check_threshold(mock_current, lim);
|
|
TEST_ASSERT(lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
/* midrange for a long time shouldn't do anything */
|
|
mock_current = (lim->lo_val + lim->hi_val) / 2;
|
|
for (i = 1; i < longtime; i++)
|
|
check_threshold(mock_current, lim);
|
|
TEST_ASSERT(lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
/* above high limit for not quite long enough */
|
|
mock_current = lim->hi_val + 1;
|
|
for (i = 1; i < lim->hi_cnt; i++)
|
|
check_threshold(mock_current, lim);
|
|
TEST_ASSERT(lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
/* drop below the high limit once */
|
|
mock_current = lim->hi_val - 1;
|
|
check_threshold(mock_current, lim);
|
|
TEST_ASSERT(lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
/* now back up - that should have reset the count */
|
|
mock_current = lim->hi_val + 1;
|
|
for (i = 1; i < lim->hi_cnt; i++)
|
|
check_threshold(mock_current, lim);
|
|
TEST_ASSERT(lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
/* one more ought to do it */
|
|
check_threshold(mock_current, lim);
|
|
TEST_ASSERT(lim->triggered == 1);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* going midrange for a long time shouldn't change anything */
|
|
mock_current = (lim->lo_val + lim->hi_val) / 2;
|
|
for (i = 1; i < longtime; i++)
|
|
check_threshold(mock_current, lim);
|
|
TEST_ASSERT(lim->triggered == 1);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* below low limit for not quite long enough */
|
|
mock_current = lim->lo_val - 1;
|
|
for (i = 1; i < lim->lo_cnt; i++)
|
|
check_threshold(mock_current, lim);
|
|
TEST_ASSERT(lim->triggered == 1);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* back above the low limit once */
|
|
mock_current = lim->lo_val + 1;
|
|
check_threshold(mock_current, lim);
|
|
TEST_ASSERT(lim->triggered == 1);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* now back down - that should have reset the count */
|
|
mock_current = lim->lo_val - 1;
|
|
for (i = 1; i < lim->lo_cnt; i++)
|
|
check_threshold(mock_current, lim);
|
|
TEST_ASSERT(lim->triggered == 1);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* One more ought to do it */
|
|
check_threshold(mock_current, lim);
|
|
TEST_ASSERT(lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
/*
|
|
* Check all sets of thresholds. This probably doesn't add much value, but at
|
|
* least it ensures that they're somewhat sane.
|
|
*/
|
|
static int test_thresholds(void)
|
|
{
|
|
int e;
|
|
|
|
for (ac_adapter = 0; ac_adapter < NUM_ADAPTER_TYPES; ac_adapter++)
|
|
for (ac_turbo = 0; ac_turbo < NUM_AC_TURBO_STATES; ac_turbo++)
|
|
for (e = 0; e < NUM_AC_THRESHOLDS; e++)
|
|
TEST_ASSERT(EC_SUCCESS ==
|
|
test_thresholds_sequence(e));
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
static int test_batt(void)
|
|
{
|
|
struct adapter_limits *l, *h;
|
|
int longtime;
|
|
int i;
|
|
|
|
/* NB: struct adapter_limits assumes hi_val > lo_val, so the values in
|
|
* batt_limits[] indicate discharge current (mA). However, the value
|
|
* returned from battery_current() is postive for charging, and
|
|
* negative for discharging.
|
|
*/
|
|
|
|
/* We're assuming two limits, mild and urgent. */
|
|
TEST_ASSERT(NUM_BATT_THRESHOLDS == 2);
|
|
/* Find out which is which */
|
|
if (batt_limits[0].hi_val > batt_limits[1].hi_val) {
|
|
h = &batt_limits[0];
|
|
l = &batt_limits[1];
|
|
} else {
|
|
h = &batt_limits[1];
|
|
l = &batt_limits[0];
|
|
}
|
|
|
|
/* Find a time longer than all sample count limits */
|
|
for (i = longtime = 0; i < NUM_BATT_THRESHOLDS; i++)
|
|
longtime = MAX(longtime,
|
|
MAX(batt_limits[i].lo_cnt,
|
|
batt_limits[i].hi_cnt));
|
|
longtime += 2;
|
|
|
|
test_reset_mocks();
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
/* reset, by staying low for a long time */
|
|
for (i = 1; i < longtime; i++)
|
|
watch_battery_closely(&ctx);
|
|
TEST_ASSERT(l->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
/* mock_batt() specifies the DISCHARGE current. Charging
|
|
* should do nothing, no matter how high. */
|
|
mock_batt(-(h->hi_val + 2));
|
|
for (i = 1; i < longtime; i++)
|
|
watch_battery_closely(&ctx);
|
|
TEST_ASSERT(l->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
/* midrange for a long time shouldn't do anything */
|
|
mock_batt((l->lo_val + l->hi_val) / 2);
|
|
for (i = 1; i < longtime; i++)
|
|
watch_battery_closely(&ctx);
|
|
TEST_ASSERT(l->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
/* above high limit for not quite long enough */
|
|
mock_batt(l->hi_val + 1);
|
|
for (i = 1; i < l->hi_cnt; i++)
|
|
watch_battery_closely(&ctx);
|
|
TEST_ASSERT(l->count != 0);
|
|
TEST_ASSERT(l->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
/* drop below the high limit once */
|
|
mock_batt(l->hi_val - 1);
|
|
watch_battery_closely(&ctx);
|
|
TEST_ASSERT(l->count == 0);
|
|
TEST_ASSERT(l->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
/* now back up */
|
|
mock_batt(l->hi_val + 1);
|
|
for (i = 1; i < l->hi_cnt; i++)
|
|
watch_battery_closely(&ctx);
|
|
TEST_ASSERT(l->count != 0);
|
|
TEST_ASSERT(l->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
/* one more ought to do it */
|
|
watch_battery_closely(&ctx);
|
|
TEST_ASSERT(l->triggered == 1);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* going midrange for a long time shouldn't change anything */
|
|
mock_batt((l->lo_val + l->hi_val) / 2);
|
|
for (i = 1; i < longtime; i++)
|
|
watch_battery_closely(&ctx);
|
|
TEST_ASSERT(l->triggered == 1);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* charge for not quite long enough */
|
|
mock_batt(-1);
|
|
for (i = 1; i < l->lo_cnt; i++)
|
|
watch_battery_closely(&ctx);
|
|
TEST_ASSERT(l->triggered == 1);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* back above the low limit once */
|
|
mock_batt(l->lo_val + 1);
|
|
watch_battery_closely(&ctx);
|
|
TEST_ASSERT(l->triggered == 1);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* now charge again - that should have reset the count */
|
|
mock_batt(-1);
|
|
for (i = 1; i < l->lo_cnt; i++)
|
|
watch_battery_closely(&ctx);
|
|
TEST_ASSERT(l->triggered == 1);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* One more ought to do it */
|
|
watch_battery_closely(&ctx);
|
|
TEST_ASSERT(l->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
/* Check the high limits too, just for fun */
|
|
mock_batt(h->hi_val + 1);
|
|
for (i = 1; i < h->hi_cnt; i++)
|
|
watch_battery_closely(&ctx);
|
|
TEST_ASSERT(h->triggered == 0);
|
|
/* one more */
|
|
watch_battery_closely(&ctx);
|
|
TEST_ASSERT(h->triggered == 1);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
static int test_batt_vs_adapter(void)
|
|
{
|
|
/* Only need one set of adapter thresholds for this test */
|
|
struct adapter_limits *a_lim;
|
|
|
|
/* Same structs are used for battery thresholds */
|
|
struct adapter_limits *b_lim;
|
|
|
|
int longtime;
|
|
int i;
|
|
|
|
/* For adapter, we'll use ADAPTER_UNKNOWN, Turbo off, softer limits */
|
|
a_lim = &ad_limits[0][0][0];
|
|
|
|
/* NB: struct adapter_limits assumes hi_val > lo_val, so the values in
|
|
* batt_limits[] indicate discharge current (mA). However, the value
|
|
* returned from battery_current() is postive for charging, and
|
|
* negative for discharging.
|
|
*/
|
|
|
|
/* We're assuming two limits, mild and urgent. */
|
|
TEST_ASSERT(NUM_BATT_THRESHOLDS == 2);
|
|
/* Find out which is which. We want the mild one. */
|
|
if (batt_limits[0].hi_val > batt_limits[1].hi_val)
|
|
b_lim = &batt_limits[1];
|
|
else
|
|
b_lim = &batt_limits[0];
|
|
|
|
|
|
/* DANGER: we need these two to not be in sync. */
|
|
TEST_ASSERT(a_lim->hi_cnt == 16);
|
|
TEST_ASSERT(b_lim->hi_cnt == 16);
|
|
/* Now that we know they're the same, let's change one */
|
|
b_lim->hi_cnt = 12;
|
|
|
|
/* DANGER: We also rely on these values */
|
|
TEST_ASSERT(a_lim->lo_cnt == 80);
|
|
TEST_ASSERT(b_lim->lo_cnt == 50);
|
|
|
|
|
|
/* Find a time longer than all sample count limits */
|
|
longtime = MAX(MAX(a_lim->lo_cnt, a_lim->hi_cnt),
|
|
MAX(b_lim->lo_cnt, b_lim->hi_cnt)) + 2;
|
|
|
|
|
|
test_reset_mocks(); /* everything == 0 */
|
|
ctx.curr.batt.state_of_charge = 25;
|
|
change_ac(1);
|
|
|
|
/* make sure no limits are triggered by staying low for a long time */
|
|
mock_current = a_lim->lo_val - 1; /* charger current is safe */
|
|
mock_batt(-1); /* battery is charging */
|
|
|
|
for (i = 1; i < longtime; i++)
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(a_lim->triggered == 0);
|
|
TEST_ASSERT(b_lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
|
|
/* battery discharge current is too high for almost long enough */
|
|
mock_batt(b_lim->hi_val + 1);
|
|
for (i = 1; i < b_lim->hi_cnt; i++)
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(b_lim->count != 0);
|
|
TEST_ASSERT(b_lim->triggered == 0);
|
|
TEST_ASSERT(a_lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
/* one more ought to do it */
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(b_lim->triggered == 1);
|
|
TEST_ASSERT(a_lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
|
|
/* charge for not quite long enough */
|
|
mock_batt(-1);
|
|
for (i = 1; i < b_lim->lo_cnt; i++)
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(b_lim->triggered == 1);
|
|
TEST_ASSERT(a_lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* and one more */
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(b_lim->triggered == 0);
|
|
TEST_ASSERT(a_lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
|
|
/* Now adapter current is too high for almost long enough */
|
|
mock_current = a_lim->hi_val + 1;
|
|
for (i = 1; i < a_lim->hi_cnt; i++)
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(a_lim->triggered == 0);
|
|
TEST_ASSERT(b_lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
/* one more ought to do it */
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(a_lim->triggered == 1);
|
|
TEST_ASSERT(b_lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* below low limit for not quite long enough */
|
|
mock_current = a_lim->lo_val - 1;
|
|
for (i = 1; i < a_lim->lo_cnt; i++)
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(a_lim->triggered == 1);
|
|
TEST_ASSERT(b_lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* One more ought to do it */
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(a_lim->triggered == 0);
|
|
TEST_ASSERT(b_lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
|
|
/* Now both are high, but battery hi_cnt is shorter */
|
|
mock_batt(b_lim->hi_val + 1);
|
|
mock_current = a_lim->hi_val + 1;
|
|
for (i = 1; i < b_lim->hi_cnt; i++) /* just under battery limit */
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(a_lim->triggered == 0);
|
|
TEST_ASSERT(b_lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
/* one more should kick the battery threshold */
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(a_lim->triggered == 0);
|
|
TEST_ASSERT(b_lim->triggered == 1);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* don't quite reach the adapter threshold */
|
|
for (i = 1; i < a_lim->hi_cnt - b_lim->hi_cnt; i++)
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(a_lim->triggered == 0);
|
|
TEST_ASSERT(b_lim->triggered == 1);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* okay, now */
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(a_lim->triggered == 1);
|
|
TEST_ASSERT(b_lim->triggered == 1);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* Leave battery high, let the adapter come down */
|
|
mock_current = a_lim->lo_val - 1;
|
|
for (i = 1; i < a_lim->lo_cnt; i++)
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(a_lim->triggered == 1);
|
|
TEST_ASSERT(b_lim->triggered == 1);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* One more ought to do it for the adapter */
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(a_lim->triggered == 0);
|
|
TEST_ASSERT(b_lim->triggered == 1);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* now charge the battery again */
|
|
mock_batt(-1);
|
|
for (i = 1; i < b_lim->lo_cnt; i++)
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(b_lim->triggered == 1);
|
|
TEST_ASSERT(a_lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled);
|
|
|
|
/* and one more */
|
|
watch_adapter_closely(&ctx);
|
|
TEST_ASSERT(b_lim->triggered == 0);
|
|
TEST_ASSERT(a_lim->triggered == 0);
|
|
TEST_ASSERT(ap_is_throttled == 0);
|
|
|
|
return EC_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
void run_test(void)
|
|
{
|
|
test_reset();
|
|
test_chipset_on();
|
|
|
|
RUN_TEST(test_identification);
|
|
RUN_TEST(test_turbo);
|
|
RUN_TEST(test_thresholds);
|
|
RUN_TEST(test_batt);
|
|
|
|
RUN_TEST(test_batt_vs_adapter);
|
|
|
|
test_print_result();
|
|
}
|