diff options
author | Caveh Jalali <caveh@chromium.org> | 2019-06-12 00:59:17 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-11-05 07:07:22 +0000 |
commit | 1b4515c4b4332e9a6d20104f3289ef8a26b86d4b (patch) | |
tree | f6228d4f7a6586f7c42e60d6fc85e5e3cf1ff2ac | |
parent | b8f0185b055109c43ae3c80ed6f6b89f2107eb9c (diff) | |
download | chrome-ec-1b4515c4b4332e9a6d20104f3289ef8a26b86d4b.tar.gz |
pd_protocol: add hard_reset_complete_timer
certain chargers have noisy CC lines which can prevent overly
sensitive TCPCs from detecting a bus idle state. this means the TCPC
will not send out messages such as hard_reset. this condition may not
clear which means our pd_task() will retry sending hard_resets.
although we specify a "timeout" for the event loop in this state, the
timeout can be ignored by the event wait when there are pending
events. this gets us into a tight event processing loop that starves
the watchdog!
the solution is to add an explicit timeout timer when processing the
PD_STATE_HARD_RESET_SEND state.
BUG=b:134702480
BRANCH=none
TEST=no more EC watchdog on affected systems
Change-Id: I1ae871f5d8fc99f6906ddd18741bbf68dcb6e935
Signed-off-by: Caveh Jalali <caveh@chromium.org>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1889431
Tested-by: Nitin Kolluru <nkolluru@google.com>
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
(cherry picked from commit b0828291b501289f4c1d3726ab545cf3efd06d13)
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1899327
Reviewed-by: Caveh Jalali <caveh@google.com>
Commit-Queue: Caveh Jalali <caveh@google.com>
-rw-r--r-- | common/usb_pd_protocol.c | 68 | ||||
-rw-r--r-- | include/usb_pd.h | 38 |
2 files changed, 69 insertions, 37 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index a634c8ef0b..14b190765e 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -249,6 +249,11 @@ static struct pd_protocol { * of our own. */ uint64_t ready_state_holdoff_timer; + /* + * PD 2.0 spec, section 6.5.11.1 + * When we can give up on a HARD_RESET transmission. + */ + uint64_t hard_reset_complete_timer; } pd[CONFIG_USB_PD_PORT_COUNT]; #ifdef CONFIG_COMMON_RUNTIME @@ -4128,8 +4133,10 @@ void pd_task(void *u) break; case PD_STATE_HARD_RESET_SEND: hard_reset_count++; - if (pd[port].last_state != pd[port].task_state) + if (pd[port].last_state != pd[port].task_state) { hard_reset_sent = 0; + pd[port].hard_reset_complete_timer = 0; + } #ifdef CONFIG_CHARGE_MANAGER if (pd[port].last_state == PD_STATE_SNK_DISCOVERY || (pd[port].last_state == PD_STATE_SOFT_RESET && @@ -4149,29 +4156,52 @@ void pd_task(void *u) } #endif - /* try sending hard reset until it succeeds */ - if (!hard_reset_sent) { - if (pd_transmit(port, TCPC_TX_HARD_RESET, - 0, NULL) < 0) { - timeout = 10*MSEC; + if (hard_reset_sent) + break; + + if (pd_transmit(port, TCPC_TX_HARD_RESET, 0, NULL) < + 0) { + /* + * likely a non-idle channel + * TCPCI r2.0 v1.0 4.4.15: + * the TCPC does not retry HARD_RESET + * but we can try periodically until the timer + * expires. + */ + now = get_time(); + if (pd[port].hard_reset_complete_timer == 0) { + pd[port].hard_reset_complete_timer = + now.val + + PD_T_HARD_RESET_COMPLETE; + timeout = PD_T_HARD_RESET_RETRY; + break; + } + if (now.val < + pd[port].hard_reset_complete_timer) { + CPRINTS("C%d: Retrying hard reset", + port); + timeout = PD_T_HARD_RESET_RETRY; break; } - - /* successfully sent hard reset */ - hard_reset_sent = 1; /* - * If we are source, delay before cutting power - * to allow sink time to get hard reset. + * PD 2.0 spec, section 6.5.11.1 + * Pretend TX_HARD_RESET succeeded after + * timeout. */ - if (pd[port].power_role == PD_ROLE_SOURCE) { - set_state_timeout(port, - get_time().val + PD_T_PS_HARD_RESET, - PD_STATE_HARD_RESET_EXECUTE); - } else { - set_state(port, + } + + hard_reset_sent = 1; + /* + * If we are source, delay before cutting power + * to allow sink time to get hard reset. + */ + if (pd[port].power_role == PD_ROLE_SOURCE) { + set_state_timeout(port, + get_time().val + PD_T_PS_HARD_RESET, PD_STATE_HARD_RESET_EXECUTE); - timeout = 10*MSEC; - } + } else { + set_state(port, PD_STATE_HARD_RESET_EXECUTE); + timeout = 10 * MSEC; } break; case PD_STATE_HARD_RESET_EXECUTE: diff --git a/include/usb_pd.h b/include/usb_pd.h index f822949ca7..a45dde0565 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -150,19 +150,21 @@ enum pd_rx_errors { #define SVID_DISCOVERY_MAX 16 /* Timers */ -#define PD_T_SINK_TX (18*MSEC) /* between 16ms and 20 */ -#define PD_T_CHUNK_SENDER_RSP (24*MSEC) /* between 24ms and 30ms */ -#define PD_T_CHUNK_SENDER_REQ (24*MSEC) /* between 24ms and 30ms */ -#define PD_T_SEND_SOURCE_CAP (100*MSEC) /* between 100ms and 200ms */ -#define PD_T_SINK_WAIT_CAP (600*MSEC) /* between 310ms and 620ms */ -#define PD_T_SINK_TRANSITION (35*MSEC) /* between 20ms and 35ms */ -#define PD_T_SOURCE_ACTIVITY (45*MSEC) /* between 40ms and 50ms */ -#define PD_T_SENDER_RESPONSE (30*MSEC) /* between 24ms and 30ms */ -#define PD_T_PS_TRANSITION (500*MSEC) /* between 450ms and 550ms */ -#define PD_T_PS_SOURCE_ON (480*MSEC) /* between 390ms and 480ms */ -#define PD_T_PS_SOURCE_OFF (920*MSEC) /* between 750ms and 920ms */ -#define PD_T_PS_HARD_RESET (25*MSEC) /* between 25ms and 35ms */ -#define PD_T_ERROR_RECOVERY (25*MSEC) /* 25ms */ +#define PD_T_SINK_TX (18*MSEC) /* between 16ms and 20 */ +#define PD_T_CHUNK_SENDER_RSP (24*MSEC) /* between 24ms and 30ms */ +#define PD_T_CHUNK_SENDER_REQ (24*MSEC) /* between 24ms and 30ms */ +#define PD_T_HARD_RESET_COMPLETE (5*MSEC) /* between 4ms and 5ms*/ +#define PD_T_HARD_RESET_RETRY (1*MSEC) /* 1ms */ +#define PD_T_SEND_SOURCE_CAP (100*MSEC) /* between 100ms and 200ms */ +#define PD_T_SINK_WAIT_CAP (600*MSEC) /* between 310ms and 620ms */ +#define PD_T_SINK_TRANSITION (35*MSEC) /* between 20ms and 35ms */ +#define PD_T_SOURCE_ACTIVITY (45*MSEC) /* between 40ms and 50ms */ +#define PD_T_SENDER_RESPONSE (30*MSEC) /* between 24ms and 30ms */ +#define PD_T_PS_TRANSITION (500*MSEC) /* between 450ms and 550ms */ +#define PD_T_PS_SOURCE_ON (480*MSEC) /* between 390ms and 480ms */ +#define PD_T_PS_SOURCE_OFF (920*MSEC) /* between 750ms and 920ms */ +#define PD_T_PS_HARD_RESET (25*MSEC) /* between 25ms and 35ms */ +#define PD_T_ERROR_RECOVERY (25*MSEC) /* 25ms */ #define PD_T_CC_DEBOUNCE (100*MSEC) /* between 100ms and 200ms */ /* DRP_SNK + DRP_SRC must be between 50ms and 100ms with 30%-70% duty cycle */ #define PD_T_DRP_SNK (40*MSEC) /* toggle time for sink DRP */ @@ -190,11 +192,11 @@ enum pd_rx_errors { #define PD_T_AME (1*SECOND) /* timeout from UFP attach to Alt Mode Entry */ /* VDM Timers ( USB PD Spec Rev2.0 Table 6-30 )*/ -#define PD_T_VDM_BUSY (100*MSEC) /* at least 100ms */ -#define PD_T_VDM_E_MODE (25*MSEC) /* enter/exit the same max */ -#define PD_T_VDM_RCVR_RSP (15*MSEC) /* max of 15ms */ -#define PD_T_VDM_SNDR_RSP (30*MSEC) /* max of 30ms */ -#define PD_T_VDM_WAIT_MODE_E (100*MSEC) /* enter/exit the same max */ +#define PD_T_VDM_BUSY (100*MSEC) /* at least 100ms */ +#define PD_T_VDM_E_MODE (25*MSEC) /* enter/exit the same max */ +#define PD_T_VDM_RCVR_RSP (15*MSEC) /* max of 15ms */ +#define PD_T_VDM_SNDR_RSP (30*MSEC) /* max of 30ms */ +#define PD_T_VDM_WAIT_MODE_E (100*MSEC) /* enter/exit the same max */ /* function table for entered mode */ struct amode_fx { |