summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTodd Broch <tbroch@chromium.org>2014-12-14 14:19:33 -0800
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-01-07 08:45:34 +0000
commitc0f64b13e981fd0c2901e1c33d7f6e52287ca0df (patch)
tree6521f942c2a993d24266e5a12cd71d816ec5fc0b
parentfaf09e290519569fa1b9d7ac27035606afcb08d6 (diff)
downloadchrome-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.c1
-rw-r--r--common/usb_pd_protocol.c60
-rw-r--r--include/usb_pd.h7
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);