diff options
author | Denis Brockus <dbrockus@google.com> | 2021-09-22 13:13:45 -0600 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-10-26 21:31:21 +0000 |
commit | 1f1103b4b875a4ce12fb666fa69572747e02996c (patch) | |
tree | 6c46879812c319dc80d6b416e37383ad3478cc5c | |
parent | 3e21911a0bfecd03957ecb6d9d0bdd77e469bc09 (diff) | |
download | chrome-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.mk | 1 | ||||
-rw-r--r-- | common/usbc/usb_pd_timer.c | 9 | ||||
-rw-r--r-- | include/usb_pd_timer.h | 54 | ||||
-rw-r--r-- | test/build.mk | 2 | ||||
-rw-r--r-- | test/test_config.h | 6 | ||||
-rw-r--r-- | test/usb_pd_timer.c | 168 | ||||
-rw-r--r-- | test/usb_pd_timer.tasklist | 10 |
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 + |