diff options
author | Todd Broch <tbroch@chromium.org> | 2014-12-14 14:19:33 -0800 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-01-07 08:45:34 +0000 |
commit | c0f64b13e981fd0c2901e1c33d7f6e52287ca0df (patch) | |
tree | 6521f942c2a993d24266e5a12cd71d816ec5fc0b | |
parent | faf09e290519569fa1b9d7ac27035606afcb08d6 (diff) | |
download | chrome-ec-c0f64b13e981fd0c2901e1c33d7f6e52287ca0df.tar.gz |
pd: vdm: Add VDM related timeouts and busy response handling.
Initial VDM implementation had a very conservative 500msec timeout period. This
CL adds the timeouts defined in the USB-PD specification for various commands.
Additionally it adds a state to the vdm state machine to allow proper busy
response handling.
Signed-off-by: Todd Broch <tbroch@chromium.org>
BRANCH=samus
BUG=chrome-os-partner:30645
TEST=manual,
Alternate mode and flashing still work. Creating a VDM responder which returns
busy shows retries from initiator after at least 100msec.
Change-Id: I79f5da557ca9faf63d2299bb77009f6d98a782bd
Reviewed-on: https://chromium-review.googlesource.com/235682
Reviewed-by: Alec Berg <alecaberg@chromium.org>
Tested-by: Todd Broch <tbroch@chromium.org>
Commit-Queue: Todd Broch <tbroch@chromium.org>
-rw-r--r-- | common/usb_pd_policy.c | 1 | ||||
-rw-r--r-- | common/usb_pd_protocol.c | 60 | ||||
-rw-r--r-- | include/usb_pd.h | 7 |
3 files changed, 63 insertions, 5 deletions
diff --git a/common/usb_pd_policy.c b/common/usb_pd_policy.c index abfb3d0035..81a8ab7c85 100644 --- a/common/usb_pd_policy.c +++ b/common/usb_pd_policy.c @@ -526,7 +526,6 @@ int pd_svdm(int port, int cnt, uint32_t *payload, uint32_t **rpayload) case CMD_DISCOVER_SVID: case CMD_DISCOVER_MODES: /* resend if its discovery */ - payload[0] |= VDO_CMDT(CMDT_INIT); rsize = 1; break; case CMD_ENTER_MODE: diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 6915ff2f5c..98b14a2736 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -193,6 +193,7 @@ enum vdm_states { /* Anything >0 represents an active state */ VDM_STATE_READY = 1, VDM_STATE_BUSY = 2, + VDM_STATE_WAIT_RSP_BUSY = 3, }; #ifdef CONFIG_USB_PD_DUAL_ROLE @@ -264,9 +265,13 @@ static struct pd_protocol { /* PD state for Vendor Defined Messages */ enum vdm_states vdm_state; + /* Timeout for the current vdm state. Set to 0 for no timeout. */ + timestamp_t vdm_timeout; /* next Vendor Defined Message to send */ uint32_t vdo_data[VDO_MAX_SIZE]; uint8_t vdo_count; + /* VDO to retry if UFP responder replied busy. */ + uint32_t vdo_retry; /* Attached ChromeOS device id, RW hash, and current RO / RW image */ uint16_t dev_id; @@ -716,13 +721,24 @@ static void handle_vdm_request(int port, int cnt, uint32_t *payload) uint32_t *rdata; if (pd[port].vdm_state == VDM_STATE_BUSY) { - pd[port].vdm_state = VDM_STATE_DONE; CPRINTF("VDM/%d [%02d] %08x", cnt, PD_VDO_CMD(payload[0]), payload[0]); if (PD_VDO_SVDM(payload[0])) for (i = 1; i < cnt; i++) CPRINTF(" %08x", payload[i]); CPRINTF("\n"); + + /* If UFP responded busy retry after timeout */ + if (PD_VDO_CMDT(payload[0]) == CMDT_RSP_BUSY) { + pd[port].vdm_timeout.val = get_time().val + + PD_T_VDM_BUSY; + pd[port].vdm_state = VDM_STATE_WAIT_RSP_BUSY; + pd[port].vdo_retry = (payload[0] & ~VDO_CMDT_MASK) | + CMDT_INIT; + return; + } else { + pd[port].vdm_state = VDM_STATE_DONE; + } } if (PD_VDO_SVDM(payload[0])) @@ -1355,11 +1371,36 @@ static inline int pdo_busy(int port) return rv; } +static uint64_t vdm_get_ready_timeout(uint32_t vdm_hdr) +{ + uint64_t timeout; + int cmd = PD_VDO_CMD(vdm_hdr); + + /* its not a structured VDM command */ + if (!PD_VDO_SVDM(vdm_hdr)) + return 500*MSEC; + + switch (PD_VDO_CMDT(vdm_hdr)) { + case CMDT_INIT: + if ((cmd == CMD_ENTER_MODE) || (cmd == CMD_EXIT_MODE)) + timeout = PD_T_VDM_WAIT_MODE_E; + else + timeout = PD_T_VDM_SNDR_RSP; + break; + default: + if ((cmd == CMD_ENTER_MODE) || (cmd == CMD_EXIT_MODE)) + timeout = PD_T_VDM_E_MODE; + else + timeout = PD_T_VDM_RCVR_RSP; + break; + } + return timeout; +} + static void pd_vdm_send_state_machine(int port, int incoming_packet) { int res; uint16_t header; - static uint64_t vdm_timeout; switch (pd[port].vdm_state) { case VDM_STATE_READY: @@ -1389,13 +1430,24 @@ static void pd_vdm_send_state_machine(int port, int incoming_packet) pd[port].vdm_state = VDM_STATE_ERR_SEND; } else { pd[port].vdm_state = VDM_STATE_BUSY; - vdm_timeout = get_time().val + 500*MSEC; + pd[port].vdm_timeout.val = get_time().val + + vdm_get_ready_timeout(pd[port].vdo_data[0]); + } + break; + case VDM_STATE_WAIT_RSP_BUSY: + /* wait and then initiate request again */ + if (get_time().val > pd[port].vdm_timeout.val) { + pd[port].vdo_data[0] = pd[port].vdo_retry; + pd[port].vdo_count = 1; + pd[port].vdm_state = VDM_STATE_READY; } break; case VDM_STATE_BUSY: /* Wait for VDM response or timeout */ - if (get_time().val > vdm_timeout) + if (pd[port].vdm_timeout.val && + (get_time().val > pd[port].vdm_timeout.val)) { pd[port].vdm_state = VDM_STATE_ERR_TMOUT; + } break; default: break; diff --git a/include/usb_pd.h b/include/usb_pd.h index 4a89e7d220..b1d72d1402 100644 --- a/include/usb_pd.h +++ b/include/usb_pd.h @@ -139,6 +139,13 @@ enum pd_errors { /* from USB Type-C Specification Table 5-1 */ #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 */ + /* function table for entered mode */ struct amode_fx { int (*status)(int port, uint32_t *payload); |