summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--board/host/board.c13
-rw-r--r--board/host/board.h9
-rw-r--r--common/temp_sensor.c2
-rw-r--r--common/thermal.c13
-rw-r--r--include/common.h2
-rw-r--r--test/build.mk5
-rw-r--r--test/thermal.c236
-rw-r--r--test/thermal.tasklist3
8 files changed, 274 insertions, 9 deletions
diff --git a/board/host/board.c b/board/host/board.c
index 5c1603767a..10d8d1d3c4 100644
--- a/board/host/board.c
+++ b/board/host/board.c
@@ -6,9 +6,22 @@
#include "board.h"
#include "gpio.h"
+#include "temp_sensor.h"
const struct gpio_info gpio_list[GPIO_COUNT] = {
{"EC_INT", 0, 0, 0, 0},
{"LID_OPEN", 0, 0, 0, 0},
{"POWER_BUTTON_L", 0, 0, 0, 0},
};
+
+static int dummy_temp_get_val(int idx, int *temp_ptr)
+{
+ *temp_ptr = 0;
+ return EC_SUCCESS;
+}
+
+const struct temp_sensor_t temp_sensors[TEMP_SENSOR_COUNT] = {
+ {"CPU", TEMP_SENSOR_TYPE_CPU, dummy_temp_get_val, 0, 3},
+ {"Board", TEMP_SENSOR_TYPE_BOARD, dummy_temp_get_val, 0, 3},
+ {"Case", TEMP_SENSOR_TYPE_CASE, dummy_temp_get_val, 0, 0},
+};
diff --git a/board/host/board.h b/board/host/board.h
index 154a49fa60..4e4c4e7080 100644
--- a/board/host/board.h
+++ b/board/host/board.h
@@ -13,6 +13,7 @@
#define CONFIG_KEYBOARD_PROTOCOL_MKBP
#define CONFIG_LID_SWITCH
#define CONFIG_POWER_BUTTON
+#define CONFIG_TEMP_SENSOR
enum gpio_signal {
GPIO_EC_INT,
@@ -22,4 +23,12 @@ enum gpio_signal {
GPIO_COUNT
};
+enum temp_sensor_id {
+ TEMP_SENSOR_CPU = 0,
+ TEMP_SENSOR_BOARD,
+ TEMP_SENSOR_CASE,
+
+ TEMP_SENSOR_COUNT
+};
+
#endif /* __BOARD_H */
diff --git a/common/temp_sensor.c b/common/temp_sensor.c
index 3079e3b2a8..e33d787b9c 100644
--- a/common/temp_sensor.c
+++ b/common/temp_sensor.c
@@ -24,7 +24,7 @@
/* Default temperature to report in mapped memory */
#define MAPPED_TEMP_DEFAULT (296 - EC_TEMP_SENSOR_OFFSET)
-int temp_sensor_read(enum temp_sensor_id id, int *temp_ptr)
+test_mockable int temp_sensor_read(enum temp_sensor_id id, int *temp_ptr)
{
const struct temp_sensor_t *sensor;
diff --git a/common/thermal.c b/common/thermal.c
index 00970c6081..0015f5cca6 100644
--- a/common/thermal.c
+++ b/common/thermal.c
@@ -27,7 +27,8 @@
* temp_sensor_type. Threshold values for overheated action first (warning,
* prochot, power-down), followed by fan speed stepping thresholds.
*/
-static struct thermal_config_t thermal_config[TEMP_SENSOR_TYPE_COUNT] = {
+test_export_static struct thermal_config_t
+ thermal_config[TEMP_SENSOR_TYPE_COUNT] = {
/* TEMP_SENSOR_TYPE_CPU */
{THERMAL_CONFIG_WARNING_ON_FAIL,
{373, 378, 383, 327, 335, 343, 351, 359} } ,
@@ -38,8 +39,8 @@ static struct thermal_config_t thermal_config[TEMP_SENSOR_TYPE_COUNT] = {
};
/* Fan speed settings. Real max RPM is about 9300. */
-static const int fan_speed[THERMAL_FAN_STEPS + 1] = {0, 3000, 4575, 6150,
- 7725, -1};
+test_export_static const int fan_speed[THERMAL_FAN_STEPS + 1] =
+ {0, 3000, 4575, 6150, 7725, -1};
/* Number of consecutive overheated events for each temperature sensor. */
static int8_t ot_count[TEMP_SENSOR_COUNT][THRESHOLD_COUNT + THERMAL_FAN_STEPS];
@@ -159,7 +160,9 @@ static inline void update_and_check_stat(int temp,
const int16_t threshold = config->thresholds[threshold_id];
const int delay = temp_sensors[sensor_id].action_delay_sec;
- if (threshold > 0 && temp >= threshold) {
+ if (threshold <= 0) {
+ ot_count[sensor_id][threshold_id] = 0;
+ } else if (temp >= threshold) {
++ot_count[sensor_id][threshold_id];
if (ot_count[sensor_id][threshold_id] >= delay) {
ot_count[sensor_id][threshold_id] = delay;
@@ -174,8 +177,6 @@ static inline void update_and_check_stat(int temp,
* threshold causing overheated actions to trigger repeatedly.
*/
overheated[threshold_id] = 1;
- } else {
- ot_count[sensor_id][threshold_id] = 0;
}
}
diff --git a/include/common.h b/include/common.h
index 5ac49537e7..8ee20620db 100644
--- a/include/common.h
+++ b/include/common.h
@@ -77,9 +77,11 @@ enum ec_error_list {
#ifdef TEST_BUILD
#define test_mockable __attribute__((weak))
#define test_mockable_static __attribute__((weak))
+#define test_export_static
#else
#define test_mockable
#define test_mockable_static static
+#define test_export_static static
#endif
#endif /* __CROS_EC_COMMON_H */
diff --git a/test/build.mk b/test/build.mk
index 1c1b8dd713..3100f0df49 100644
--- a/test/build.mk
+++ b/test/build.mk
@@ -10,7 +10,7 @@ test-list-y=pingpong timer_calib timer_dos timer_jump mutex utils
#disable: powerdemo
# TODO(victoryang): Fix these tests:
-# thermal scancode typematic charging
+# scancode typematic charging
test-list-$(BOARD_bds)+=
test-list-$(BOARD_daisy)+=kb_scan flash stress
@@ -26,6 +26,7 @@ test-list-$(BOARD_slippy)=
# Emulator tests
test-list-host=mutex pingpong utils kb_scan kb_mkbp lid_sw power_button hooks
+test-list-host+=thermal
flash-y=flash.o
hooks-y=hooks.o
@@ -37,6 +38,8 @@ pingpong-y=pingpong.o
power_button-y=power_button.o
powerdemo-y=powerdemo.o
stress-y=stress.o
+thermal-y=thermal.o
+thermal-scale=200
timer_calib-y=timer_calib.o
timer_dos-y=timer_dos.o
utils-y=utils.o
diff --git a/test/thermal.c b/test/thermal.c
new file mode 100644
index 0000000000..7af14038ed
--- /dev/null
+++ b/test/thermal.c
@@ -0,0 +1,236 @@
+/* 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 thermal engine.
+ */
+
+#include "board.h"
+#include "common.h"
+#include "console.h"
+#include "hooks.h"
+#include "host_command.h"
+#include "temp_sensor.h"
+#include "test_util.h"
+#include "thermal.h"
+#include "timer.h"
+#include "util.h"
+
+static int mock_temp[TEMP_SENSOR_COUNT];
+static int fan_rpm;
+static int cpu_throttled;
+static int cpu_down;
+
+extern struct thermal_config_t thermal_config[TEMP_SENSOR_TYPE_COUNT];
+extern const int fan_speed[THERMAL_FAN_STEPS + 1];
+
+/*****************************************************************************/
+/* Mock functions */
+
+int temp_sensor_read(enum temp_sensor_id id, int *temp_ptr)
+{
+ if (mock_temp[id] >= 0) {
+ *temp_ptr = mock_temp[id];
+ return EC_SUCCESS;
+ } else {
+ return -mock_temp[id];
+ }
+}
+
+void pwm_set_fan_rpm_mode(int rpm_mode)
+{
+ /* Do nothing */
+}
+
+void pwm_set_fan_target_rpm(int rpm)
+{
+ fan_rpm = rpm;
+}
+
+void chipset_force_shutdown(void)
+{
+ cpu_down = 1;
+}
+
+void chipset_throttle_cpu(int throttled)
+{
+ cpu_throttled = throttled;
+}
+
+/*****************************************************************************/
+/* Test utilities */
+
+/* Test shorthands */
+#define T_CPU TEMP_SENSOR_CPU
+#define T_BOARD TEMP_SENSOR_BOARD
+#define T_CASE TEMP_SENSOR_CASE
+#define THRESHOLD(x, y) (thermal_config[x].thresholds[y])
+#define FAN_THRESHOLD(x, y) THRESHOLD(x, THRESHOLD_COUNT + (y))
+
+static void reset_mock_temp(void)
+{
+ int i;
+ enum temp_sensor_type type;
+ for (i = 0; i < TEMP_SENSOR_COUNT; ++i) {
+ type = temp_sensors[i].type;
+ mock_temp[i] = FAN_THRESHOLD(type, 0) - 1;
+ }
+}
+
+static int wait_fan_rpm(int rpm, int timeout_secs)
+{
+ do {
+ if (fan_rpm == rpm)
+ return 1;
+ usleep(SECOND);
+ } while (timeout_secs--);
+
+ return 0;
+}
+
+static int wait_value(int *v, int target, int timeout_secs)
+{
+ do {
+ if (*v == target)
+ return 1;
+ usleep(SECOND);
+ } while (timeout_secs--);
+
+ return 0;
+}
+
+static int wait_set(int *v, int timeout_secs)
+{
+ return wait_value(v, 1, timeout_secs);
+}
+
+static int wait_clear(int *v, int timeout_secs)
+{
+ return wait_value(v, 0, timeout_secs);
+}
+
+/*****************************************************************************/
+/* Tests */
+
+static int test_init_val(void)
+{
+ /* Initial mock temperature values are all zero. */
+ TEST_ASSERT(cpu_throttled == 0);
+ TEST_ASSERT(cpu_down == 0);
+ TEST_ASSERT(!(host_get_events() &
+ EC_HOST_EVENT_MASK(EC_HOST_EVENT_THERMAL_OVERLOAD)));
+ TEST_ASSERT(!(host_get_events() &
+ EC_HOST_EVENT_MASK(EC_HOST_EVENT_THERMAL_SHUTDOWN)));
+
+ return EC_SUCCESS;
+}
+
+static int test_cpu_fan(void)
+{
+ reset_mock_temp();
+
+ /*
+ * Increase CPU temperature to first fan step and check if
+ * the fan comes up.
+ */
+ mock_temp[T_CPU] = FAN_THRESHOLD(T_CPU, 0);
+ TEST_ASSERT(wait_fan_rpm(fan_speed[1], 11));
+
+ /* Increase CPU temperature to second fan step */
+ mock_temp[T_CPU] = FAN_THRESHOLD(T_CPU, 1);
+ TEST_ASSERT(wait_fan_rpm(fan_speed[2], 11));
+
+ /* Test threshold hysteresis */
+ mock_temp[T_CPU]--;
+ usleep(15 * SECOND);
+ TEST_ASSERT(fan_rpm == fan_speed[2]);
+
+ /* Test action delay */
+ mock_temp[T_CPU] = FAN_THRESHOLD(T_CPU, 4);
+ usleep((temp_sensors[T_CPU].action_delay_sec - 1) * SECOND);
+ TEST_ASSERT(fan_rpm == fan_speed[2]);
+ mock_temp[T_CPU] = FAN_THRESHOLD(T_CPU, 0);
+
+ return EC_SUCCESS;
+}
+
+static int test_safety(void)
+{
+ reset_mock_temp();
+
+ /* Trigger CPU throttling */
+ mock_temp[T_CPU] = THRESHOLD(T_CPU, THRESHOLD_WARNING);
+ TEST_ASSERT(wait_set(&cpu_throttled, 11));
+ TEST_ASSERT(host_get_events() &
+ EC_HOST_EVENT_MASK(EC_HOST_EVENT_THERMAL_OVERLOAD));
+
+ /* Lower temperature. CPU not throttled anymore. */
+ mock_temp[T_CPU] = THRESHOLD(T_CPU, THRESHOLD_WARNING) - 5;
+ TEST_ASSERT(wait_clear(&cpu_throttled, 2));
+
+ /* Thermal shutdown */
+ mock_temp[T_CPU] = THRESHOLD(T_CPU, THRESHOLD_CPU_DOWN);
+ TEST_ASSERT(wait_set(&cpu_down, 11));
+ TEST_ASSERT(host_get_events() &
+ EC_HOST_EVENT_MASK(EC_HOST_EVENT_THERMAL_SHUTDOWN));
+
+ mock_temp[T_CPU] = 0;
+ usleep(SECOND);
+ cpu_down = 0;
+
+ mock_temp[T_CPU] = THRESHOLD(T_CPU, THRESHOLD_POWER_DOWN);
+ TEST_ASSERT(wait_set(&cpu_down, 11));
+ TEST_ASSERT(host_get_events() &
+ EC_HOST_EVENT_MASK(EC_HOST_EVENT_THERMAL_SHUTDOWN));
+
+ return EC_SUCCESS;
+}
+
+static int test_sensor_failure(void)
+{
+ reset_mock_temp();
+
+ /* Failure due to sensor not powered should be ignored */
+ mock_temp[T_CPU] = -EC_ERROR_NOT_POWERED;
+ usleep(5 * SECOND);
+ TEST_ASSERT(!(host_get_events() &
+ EC_HOST_EVENT_MASK(EC_HOST_EVENT_THERMAL)));
+
+ /* Other failure should be pumped up to host */
+ mock_temp[T_CPU] = -EC_ERROR_UNKNOWN;
+ usleep(5 * SECOND);
+ TEST_ASSERT(host_get_events() &
+ EC_HOST_EVENT_MASK(EC_HOST_EVENT_THERMAL));
+
+ return EC_SUCCESS;
+}
+
+static int check_assumption(void)
+{
+ TEST_ASSERT((int)TEMP_SENSOR_CPU == (int)TEMP_SENSOR_TYPE_CPU);
+ TEST_ASSERT((int)TEMP_SENSOR_BOARD == (int)TEMP_SENSOR_TYPE_BOARD);
+ TEST_ASSERT((int)TEMP_SENSOR_CASE == (int)TEMP_SENSOR_TYPE_CASE);
+
+ TEST_ASSERT(temp_sensors[T_CPU].action_delay_sec != 0);
+
+ TEST_ASSERT(thermal_config[T_CPU].config_flags &
+ THERMAL_CONFIG_WARNING_ON_FAIL);
+
+ return EC_SUCCESS;
+}
+
+void run_test(void)
+{
+ test_reset();
+
+ /* Test assumptions */
+ RUN_TEST(check_assumption);
+
+ RUN_TEST(test_init_val);
+ RUN_TEST(test_cpu_fan);
+ /* No tests for board and case temp sensors as they are ignored. */
+ RUN_TEST(test_safety);
+ RUN_TEST(test_sensor_failure);
+
+ test_print_result();
+}
diff --git a/test/thermal.tasklist b/test/thermal.tasklist
index 26cfc53453..ab0b5484f5 100644
--- a/test/thermal.tasklist
+++ b/test/thermal.tasklist
@@ -14,4 +14,5 @@
* 'd' in an opaque parameter passed to the routine at startup
* 's' is the stack size in bytes; must be a multiple of 8
*/
-#define CONFIG_TEST_TASK_LIST /* No test task */
+#define CONFIG_TEST_TASK_LIST \
+ TASK_TEST(THERMAL, thermal_task, NULL, TASK_STACK_SIZE)