summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Brockus <dbrockus@google.com>2021-09-22 13:13:45 -0600
committerCommit Bot <commit-bot@chromium.org>2021-10-26 21:31:21 +0000
commit1f1103b4b875a4ce12fb666fa69572747e02996c (patch)
tree6c46879812c319dc80d6b416e37383ad3478cc5c
parent3e21911a0bfecd03957ecb6d9d0bdd77e469bc09 (diff)
downloadchrome-ec-1f1103b4b875a4ce12fb666fa69572747e02996c.tar.gz
TCPMv2: Add PD timer unit test
Basic checks to verify setting/clearing bits for all of the currently allocated PD timers works properly BUG=b:141363146 BRANCH=none TEST=make run-usb_pd_timer Signed-off-by: Denis Brockus <dbrockus@google.com> Change-Id: I22e237d367a3b3cb28c4a9d88d6c5c375f3b44cf Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3176394 Tested-by: Abe Levkoy <alevkoy@chromium.org> Reviewed-by: Denis Brockus <dbrockus@chromium.org> Reviewed-by: Yuval Peress <peress@google.com> Commit-Queue: Denis Brockus <dbrockus@chromium.org> Auto-Submit: Denis Brockus <dbrockus@chromium.org>
-rw-r--r--common/usbc/build.mk1
-rw-r--r--common/usbc/usb_pd_timer.c9
-rw-r--r--include/usb_pd_timer.h54
-rw-r--r--test/build.mk2
-rw-r--r--test/test_config.h6
-rw-r--r--test/usb_pd_timer.c168
-rw-r--r--test/usb_pd_timer.tasklist10
7 files changed, 247 insertions, 3 deletions
diff --git a/common/usbc/build.mk b/common/usbc/build.mk
index 48ab5351b8..60e2347741 100644
--- a/common/usbc/build.mk
+++ b/common/usbc/build.mk
@@ -46,6 +46,7 @@ all-obj-$(CONFIG_USB_PD_ALT_MODE_UFP_DP)+=$(_usbc_dir)usb_pd_dp_ufp.o
endif # CONFIG_USB_PD_TCPMV2
# For testing
+all-obj-$(CONFIG_TEST_USB_PD_TIMER)+=$(_usbc_dir)usb_pd_timer.o
all-obj-$(CONFIG_TEST_USB_PE_SM)+=$(_usbc_dir)usbc_pd_policy.o
all-obj-$(CONFIG_TEST_USB_PE_SM)+=$(_usbc_dir)usb_pe_drp_sm.o
all-obj-$(CONFIG_TEST_SM)+=$(_usbc_dir)usb_sm.o
diff --git a/common/usbc/usb_pd_timer.c b/common/usbc/usb_pd_timer.c
index 11cc9e3758..97aa699737 100644
--- a/common/usbc/usb_pd_timer.c
+++ b/common/usbc/usb_pd_timer.c
@@ -44,8 +44,11 @@
(timer_disabled[p][1] & (m)))
#define TIMER_FIELD_NUM_UINT32S 2
-static uint32_t timer_active[MAX_PD_PORTS][TIMER_FIELD_NUM_UINT32S];
-static uint32_t timer_disabled[MAX_PD_PORTS][TIMER_FIELD_NUM_UINT32S];
+
+test_mockable_static
+uint32_t timer_active[MAX_PD_PORTS][TIMER_FIELD_NUM_UINT32S];
+test_mockable_static
+uint32_t timer_disabled[MAX_PD_PORTS][TIMER_FIELD_NUM_UINT32S];
static uint64_t timer_expires[MAX_PD_PORTS][MAX_PD_TIMERS];
BUILD_ASSERT(sizeof(timer_active[0]) * CHAR_BIT >= PD_TIMER_COUNT);
BUILD_ASSERT(sizeof(timer_disabled[0]) * CHAR_BIT >= PD_TIMER_COUNT);
@@ -111,7 +114,7 @@ __maybe_unused static __const_data const char * const pd_timer_names[] = {
* @param timer_field Array of timer fields to operate on
* @param mask_val 64-bit mask to apply to the timer field
*/
-static void pd_timer_atomic_op(
+test_mockable_static void pd_timer_atomic_op(
atomic_val_t (*op)(atomic_t*, atomic_val_t),
uint32_t *const timer_field, const uint64_t mask_val)
{
diff --git a/include/usb_pd_timer.h b/include/usb_pd_timer.h
index d4ff5dfe4a..5746e76430 100644
--- a/include/usb_pd_timer.h
+++ b/include/usb_pd_timer.h
@@ -294,4 +294,58 @@ int pd_timer_next_expiration(int port);
*/
void pd_timer_dump(int port);
+#ifdef TEST_BUILD
+/*****************************************************************************
+ * TEST_BUILD section
+ *
+ * This is solely for the use of unit testing. Most of the inner workings
+ * of PD timer are internal static, so they have to be allowed access in
+ * order to unit test the basics of the code.
+ *
+ * If you are interested in the workings of PD timers please refer to
+ * common/usbc/usb_pd_timer.c
+ */
+
+/* exported: number of USB-C ports */
+#define MAX_PD_PORTS CONFIG_USB_PD_PORT_MAX_COUNT
+/* exported: number of uint32_t fields for bit mask to all timers */
+#define TIMER_FIELD_NUM_UINT32S 2
+
+/* PD timers have three possible states: Active, Inactive and Disabled */
+/* exported: timer_active indicates if a timer is currently active */
+extern uint32_t timer_active[MAX_PD_PORTS][TIMER_FIELD_NUM_UINT32S];
+/* exported: timer_disabled indicates if a timer is currently disabled */
+extern uint32_t timer_disabled[MAX_PD_PORTS][TIMER_FIELD_NUM_UINT32S];
+
+/* exported: do not call directly, only for the defined macros */
+extern void pd_timer_atomic_op(
+ atomic_val_t (*op)(atomic_t*, atomic_val_t),
+ uint32_t *const timer_field, const uint64_t mask);
+
+/* exported: set/clear/check the current timer_active for a timer */
+#define PD_SET_ACTIVE(p, m) pd_timer_atomic_op( \
+ atomic_or, \
+ timer_active[p], \
+ (m))
+#define PD_CLR_ACTIVE(p, m) pd_timer_atomic_op( \
+ atomic_clear_bits, \
+ timer_active[p], \
+ (m))
+#define PD_CHK_ACTIVE(p, m) ((timer_active[p][0] & ((m) >> 32)) | \
+ (timer_active[p][1] & (m)))
+
+/* exported: set/clear/check the current timer_disabled for a timer */
+#define PD_SET_DISABLED(p, m) pd_timer_atomic_op( \
+ atomic_or, \
+ timer_disabled[p], \
+ (m))
+#define PD_CLR_DISABLED(p, m) pd_timer_atomic_op( \
+ atomic_clear_bits, \
+ timer_disabled[p], \
+ (m))
+#define PD_CHK_DISABLED(p, m) ((timer_disabled[p][0] & ((m) >> 32)) | \
+ (timer_disabled[p][1] & (m)))
+
+#endif /* TEST_BUILD */
+
#endif /* __CROS_EC_USB_PD_TIMER_H */
diff --git a/test/build.mk b/test/build.mk
index e695654b18..cdaca18bc4 100644
--- a/test/build.mk
+++ b/test/build.mk
@@ -86,6 +86,7 @@ test-list-host += usb_pd
test-list-host += usb_pd_giveback
test-list-host += usb_pd_rev30
test-list-host += usb_pd_pdo_fixed
+test-list-host += usb_pd_timer
test-list-host += usb_ppc
test-list-host += usb_sm_framework_h3
test-list-host += usb_sm_framework_h2
@@ -212,6 +213,7 @@ usb_pd-y=usb_pd.o
usb_pd_giveback-y=usb_pd.o
usb_pd_rev30-y=usb_pd.o
usb_pd_pdo_fixed-y=usb_pd_pdo_fixed_test.o
+usb_pd_timer-y=usb_pd_timer.o
usb_ppc-y=usb_ppc.o
usb_sm_framework_h3-y=usb_sm_framework_h3.o
usb_sm_framework_h2-y=usb_sm_framework_h3.o
diff --git a/test/test_config.h b/test/test_config.h
index a60393dc42..53b8658e1d 100644
--- a/test/test_config.h
+++ b/test/test_config.h
@@ -381,6 +381,12 @@ int ncp15wb_calculate_temp(uint16_t adc);
#define CONFIG_SW_CRC
#endif
+#if defined(TEST_USB_PD_TIMER)
+#define CONFIG_USB_PD_PORT_MAX_COUNT 1
+#define CONFIG_MATH_UTIL
+#define CONFIG_TEST_USB_PD_TIMER
+#endif
+
#if defined(TEST_USB_PRL)
#define CONFIG_USB_PD_PORT_MAX_COUNT 1
#define CONFIG_USB_PD_REV30
diff --git a/test/usb_pd_timer.c b/test/usb_pd_timer.c
new file mode 100644
index 0000000000..38ed0cda78
--- /dev/null
+++ b/test/usb_pd_timer.c
@@ -0,0 +1,168 @@
+/* Copyright 2021 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 USB PD timer module.
+ */
+#include "atomic.h"
+#include "test_util.h"
+#include "timer.h"
+#include "usb_pd_timer.h"
+
+/*
+ * Verify the operation of the underlying bit operations underlying the timer
+ * module. This is technically redundant with the higher level test below, but
+ * it is useful for catching bugs during timer changes.
+ */
+int test_pd_timers_bit_ops(void)
+{
+ int bit;
+ const int port = 0;
+
+ /*
+ * Initialization calling pd_timer_init will initialize the port's
+ * active timer to be clear and disabled timer to be set for all mask
+ * bits
+ */
+ pd_timer_init(port);
+ for (bit = 0; bit < PD_TIMER_COUNT; ++bit)
+ TEST_EQ(PD_CHK_ACTIVE(port, 1ULL << bit), 0ULL, "%llu");
+ for (bit = 0; bit < PD_TIMER_COUNT; ++bit)
+ TEST_NE(PD_CHK_DISABLED(port, 1ULL << bit), 0ULL, "%llu");
+
+ /*
+ * Set one active bit at a time and verify it is the only bit set. Reset
+ * the bit on each iteration of the bit loop.
+ */
+ for (bit = 0; bit < PD_TIMER_COUNT; ++bit) {
+ TEST_EQ(PD_CHK_ACTIVE(port, 1ULL << bit), 0ULL, "%llu");
+ PD_SET_ACTIVE(port, 1ULL << bit);
+ for (int i = 0; i < PD_TIMER_COUNT; ++i) {
+ if (i != bit)
+ TEST_EQ(PD_CHK_ACTIVE(port, 1ULL << i), 0ULL,
+ "%llu");
+ else
+ TEST_NE(PD_CHK_ACTIVE(port, 1ULL << i), 0ULL,
+ "%llu");
+ }
+ PD_CLR_ACTIVE(port, 1ULL << bit);
+ }
+
+ /*
+ * Clear one disabled bit at a time and verify it is the only bit clear.
+ * Reset the bit on each iteration of the bit loop.
+ */
+ for (bit = 0; bit < PD_TIMER_COUNT; ++bit) {
+ TEST_NE(PD_CHK_DISABLED(port, 1ULL << bit), 0ULL, "%llu");
+ PD_CLR_DISABLED(port, 1ULL << bit);
+ for (int i = 0; i < PD_TIMER_COUNT; ++i) {
+ if (i != bit)
+ TEST_NE(PD_CHK_DISABLED(port, 1ULL << i), 0ULL,
+ "%llu");
+ else
+ TEST_EQ(PD_CHK_DISABLED(port, 1ULL << i), 0ULL,
+ "%llu");
+ }
+ PD_SET_DISABLED(port, 1ULL << bit);
+ }
+
+ return EC_SUCCESS;
+}
+
+int test_pd_timers(void)
+{
+ int bit;
+ int ms_to_expire;
+ const int port = 0;
+
+ /*
+ * Initialization calling pd_timer_init will initialize the port's
+ * active timer to be clear and disabled timer to be set for all mask
+ * bits.
+ */
+ pd_timer_init(port);
+
+ /* Verify all timers are disabled. */
+ for (bit = 0; bit < PD_TIMER_COUNT; ++bit)
+ TEST_ASSERT(pd_timer_is_disabled(port, bit));
+
+ /* Enable some timers. */
+ for (bit = 0; bit < 5; ++bit)
+ pd_timer_enable(0, bit, (bit + 1) * 50);
+
+ /* Verify all timers for enabled/disabled. */
+ for (bit = 0; bit < PD_TIMER_COUNT; ++bit) {
+ if (bit < 5)
+ TEST_ASSERT(!pd_timer_is_disabled(port, bit));
+ else
+ TEST_ASSERT(pd_timer_is_disabled(port, bit));
+ }
+
+ /* Disable the first timer; verify all timers for enabled/disabled. */
+ pd_timer_disable(port, 0);
+ TEST_ASSERT(pd_timer_is_disabled(port, 0));
+ for (bit = 1; bit < 5; ++bit)
+ TEST_ASSERT(!pd_timer_is_disabled(port, bit));
+ for (; bit < PD_TIMER_COUNT; ++bit)
+ TEST_ASSERT(pd_timer_is_disabled(port, bit));
+
+ /*
+ * Verify finding the next timer to expire.
+ *
+ * Timer at BIT(1) is the next to expire and originally had an expire
+ * time of 100ms. So allow for the test's simulated time lapse and
+ * verify in the 90-100 range.
+ */
+ ms_to_expire = pd_timer_next_expiration(port);
+ TEST_GE(ms_to_expire, 90, "%d");
+ TEST_LE(ms_to_expire, 100, "%d");
+
+ /* Enable the timers in the PRL range. */
+ for (bit = PR_TIMER_START; bit <= PR_TIMER_END; ++bit)
+ pd_timer_enable(port, bit, 20);
+
+ /* Verify all timers for enabled/disabled. */
+ for (bit = 0; bit < PD_TIMER_COUNT; ++bit) {
+ if ((bit > 0 && bit < 5) ||
+ (bit >= PR_TIMER_START && bit <= PR_TIMER_END))
+ TEST_ASSERT(!pd_timer_is_disabled(port, bit));
+ else
+ TEST_ASSERT(pd_timer_is_disabled(port, bit));
+ }
+ /* Verify that the PRL timers haven't expired yet. */
+ for (bit = PR_TIMER_START; bit <= PR_TIMER_END; ++bit)
+ TEST_ASSERT(!pd_timer_is_expired(port, bit));
+
+ /* Allow the PRL timers to expire and verify that they have expired. */
+ msleep(21);
+ for (bit = PR_TIMER_START; bit <= PR_TIMER_END; ++bit)
+ TEST_ASSERT(pd_timer_is_expired(port, bit));
+
+ /* Disable the PRL range. */
+ pd_timer_disable_range(port, PR_TIMER_RANGE);
+ /* Verify all timers for enabled/disabled. */
+ TEST_ASSERT(pd_timer_is_disabled(port, 0));
+ for (bit = 1; bit < 5; ++bit)
+ TEST_ASSERT(!pd_timer_is_disabled(port, bit));
+ for (; bit < PD_TIMER_COUNT; ++bit)
+ TEST_ASSERT(pd_timer_is_disabled(port, bit));
+
+ /*
+ * Disable the PE timer range, which contains the previously enabled
+ * timers 1-5.
+ */
+ pd_timer_disable_range(port, PE_TIMER_RANGE);
+ /* Verify all timers are disabled. */
+ for (bit = 0; bit < PD_TIMER_COUNT; ++bit)
+ TEST_ASSERT(pd_timer_is_disabled(port, bit));
+
+ return EC_SUCCESS;
+}
+
+void run_test(int argc, char **argv)
+{
+ RUN_TEST(test_pd_timers_bit_ops);
+ RUN_TEST(test_pd_timers);
+
+ test_print_result();
+}
diff --git a/test/usb_pd_timer.tasklist b/test/usb_pd_timer.tasklist
new file mode 100644
index 0000000000..9a1e6b3e08
--- /dev/null
+++ b/test/usb_pd_timer.tasklist
@@ -0,0 +1,10 @@
+/* Copyright 2021 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.
+ */
+
+/**
+ * See CONFIG_TASK_LIST in config.h for details.
+ */
+#define CONFIG_TEST_TASK_LIST
+