diff options
author | Abe Levkoy <alevkoy@chromium.org> | 2021-09-13 12:16:34 -0600 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-10-26 21:31:20 +0000 |
commit | 3e21911a0bfecd03957ecb6d9d0bdd77e469bc09 (patch) | |
tree | 16d193949eab8b38c0bc2be0f9584f51d19c754b /common | |
parent | 5166325d0870520c32f7523debb353a2254d4cde (diff) | |
download | chrome-ec-3e21911a0bfecd03957ecb6d9d0bdd77e469bc09.tar.gz |
TCPMv2: Support 64 timers
Use arrays of 32-bit fields to store PD timer status for each port.
Provide a mechanism to perform atomic operations on the appropriate
fields for each timer.
BUG=b:141363146
TEST=make run-usb_pe_drp
BRANCH=none
Signed-off-by: Abe Levkoy <alevkoy@chromium.org>
Change-Id: I23bb4aa9df569cec7088f5b9e451e86372eaabb7
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3171334
Reviewed-by: Denis Brockus <dbrockus@chromium.org>
Reviewed-by: Keith Short <keithshort@chromium.org>
Commit-Queue: Denis Brockus <dbrockus@chromium.org>
Diffstat (limited to 'common')
-rw-r--r-- | common/usbc/usb_pd_timer.c | 96 |
1 files changed, 79 insertions, 17 deletions
diff --git a/common/usbc/usb_pd_timer.c b/common/usbc/usb_pd_timer.c index 67a574904f..11cc9e3758 100644 --- a/common/usbc/usb_pd_timer.c +++ b/common/usbc/usb_pd_timer.c @@ -4,32 +4,51 @@ */ #include "assert.h" +#include "atomic.h" #include "common.h" #include "console.h" #include "limits.h" +#include "math_util.h" #include "system.h" #include "usb_pd_timer.h" #include "usb_tc_sm.h" #define MAX_PD_PORTS CONFIG_USB_PD_PORT_MAX_COUNT #define MAX_PD_TIMERS PD_TIMER_COUNT -#define PD_TIMERS_ALL_MASK ((uint32_t)(((uint64_t)1 << PD_TIMER_COUNT) - 1)) +#define PD_TIMERS_ALL_MASK (UINT64_MAX >> (64 - PD_TIMER_COUNT)) #define MAX_EXPIRE (0x7FFFFFFF) #define NO_TIMEOUT (-1) #define EXPIRE_NOW (0) -#define PD_SET_ACTIVE(p, m) atomic_or(&timer_active[p], (m)) -#define PD_CLR_ACTIVE(p, m) atomic_clear_bits(&timer_active[p], (m)) -#define PD_CHK_ACTIVE(p, m) (timer_active[p] & (m)) - -#define PD_SET_DISABLED(p, m) atomic_or(&timer_disabled[p], (m)) -#define PD_CLR_DISABLED(p, m) atomic_clear_bits(&timer_disabled[p], (m)) -#define PD_CHK_DISABLED(p, m) (timer_disabled[p] & (m)) - -static uint32_t timer_active[MAX_PD_PORTS]; -static uint32_t timer_disabled[MAX_PD_PORTS]; +#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))) + +#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))) + +#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]; 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); /* * CONFIG_CMD_PD_TIMER debug variables @@ -82,9 +101,52 @@ __maybe_unused static __const_data const char * const pd_timer_names[] = { * already and will always return that it is still expired. This timer state * will not adjust the task scheduling timeout value. */ + +/* + * Performs an atomic operation on a PD timer bit field. Atomic operations + * require 32-bit operands, but there are more than 32 timers, so choose the + * correct operand and modify the mask accordingly. + * + * @param op Atomic operation function to call + * @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( + atomic_val_t (*op)(atomic_t*, atomic_val_t), + uint32_t *const timer_field, const uint64_t mask_val) +{ + uint32_t *atomic_timer_field; + union mask64_t { + struct { +#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + uint32_t lo; + uint32_t hi; +#elif (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) + uint32_t hi; + uint32_t lo; +#endif + }; + uint64_t val; + } mask; + + /* + * High-order mask bits correspond to field [0]. Low-order mask bits + * correspond to field [1]. + */ + mask.val = mask_val; + if (mask.hi) { + atomic_timer_field = timer_field; + (void)op(atomic_timer_field, mask.hi); + } + if (mask.lo) { + atomic_timer_field = timer_field + 1; + (void)op(atomic_timer_field, mask.lo); + } +} + static void pd_timer_inactive(int port, enum pd_task_timer timer) { - uint32_t mask = 1 << timer; + uint64_t mask = bitmask_uint64(timer); if (PD_CHK_ACTIVE(port, mask)) { PD_CLR_ACTIVE(port, mask); @@ -97,14 +159,14 @@ static void pd_timer_inactive(int port, enum pd_task_timer timer) static bool pd_timer_is_active(int port, enum pd_task_timer timer) { - uint32_t mask = 1 << timer; + uint64_t mask = bitmask_uint64(timer); return PD_CHK_ACTIVE(port, mask); } static bool pd_timer_is_inactive(int port, enum pd_task_timer timer) { - uint32_t mask = 1 << timer; + uint64_t mask = bitmask_uint64(timer); return !PD_CHK_ACTIVE(port, mask) && !PD_CHK_DISABLED(port, mask); } @@ -123,7 +185,7 @@ void pd_timer_init(int port) void pd_timer_enable(int port, enum pd_task_timer timer, uint32_t expires_us) { - uint32_t mask = 1 << timer; + uint64_t mask = bitmask_uint64(timer); if (!PD_CHK_ACTIVE(port, mask)) { PD_SET_ACTIVE(port, mask); @@ -140,7 +202,7 @@ void pd_timer_enable(int port, enum pd_task_timer timer, uint32_t expires_us) void pd_timer_disable(int port, enum pd_task_timer timer) { - uint32_t mask = 1 << timer; + uint64_t mask = bitmask_uint64(timer); if (PD_CHK_ACTIVE(port, mask)) { PD_CLR_ACTIVE(port, mask); @@ -179,7 +241,7 @@ void pd_timer_disable_range(int port, enum pd_timer_range range) bool pd_timer_is_disabled(int port, enum pd_task_timer timer) { - uint32_t mask = 1 << timer; + uint64_t mask = bitmask_uint64(timer); return PD_CHK_DISABLED(port, mask); } |