summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorAbe Levkoy <alevkoy@chromium.org>2021-09-13 12:16:34 -0600
committerCommit Bot <commit-bot@chromium.org>2021-10-26 21:31:20 +0000
commit3e21911a0bfecd03957ecb6d9d0bdd77e469bc09 (patch)
tree16d193949eab8b38c0bc2be0f9584f51d19c754b /common
parent5166325d0870520c32f7523debb353a2254d4cde (diff)
downloadchrome-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.c96
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);
}