diff options
| author | Jack Pham <jackp@codeaurora.org> | 2016-11-17 11:26:55 -0800 |
|---|---|---|
| committer | Jack Pham <jackp@codeaurora.org> | 2016-11-23 15:03:14 -0800 |
| commit | dd1a207e6ee09ae399ab2abfc9498f23bfb8d9f3 (patch) | |
| tree | 1299746bc71333179350e4766babfc55cd4c3b9b | |
| parent | d854b01d5525c3cc16149ab1b1dac296e77a5a65 (diff) | |
usb: pd: Fix VDM and misc timing issues
Decrease the wait time from 5ms to 2ms when preparing a VDM
response to ensure that it gets sent out timely within
tSenderResponse (15ms). To avoid possible collision with an
incoming packet, check that there has not been any queued Rx
message just prior to sending a VDM. Also check the result of the
transmit and simply try again later if -EBUSY is returned.
While at it, fix a couple other miscellaneous timing issues.
Setting PD_ACTIVE=1 has considerable delay due to the charger's
voting mechanism, so move setting it to after starting the
SenderResponse timer when sending the Source Capabilities, and
similarly after sending a Request as a sink, in order to make
sure response timing is met. For source hard reset, increase the
tSrcRecover delay slightly from the spec minimum to account for
additional VBUS rise/fall delays before sending PS_RDY. Finally,
add a delay for VCONN_SWAP before sending PS_RDY for similar reason.
Change-Id: I5760fadb66cad6faf02e95a1e1bb975289ef8e9f
Signed-off-by: Jack Pham <jackp@codeaurora.org>
| -rw-r--r-- | drivers/usb/pd/policy_engine.c | 52 |
1 files changed, 36 insertions, 16 deletions
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index e00ab418e155..e03a649e847c 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -167,7 +167,7 @@ static void *usbpd_ipc_log; #define PS_TRANSITION_TIME 450 #define SRC_CAP_TIME 120 #define SRC_TRANSITION_TIME 25 -#define SRC_RECOVER_TIME 660 +#define SRC_RECOVER_TIME 750 #define PS_HARD_RESET_TIME 25 #define PS_SOURCE_ON 400 #define PS_SOURCE_OFF 750 @@ -438,7 +438,9 @@ static int pd_send_msg(struct usbpd *pd, u8 hdr_type, const u32 *data, /* MessageID incremented regardless of Tx error */ pd->tx_msgid = (pd->tx_msgid + 1) & PD_MAX_MSG_ID; - if (ret != num_data * sizeof(u32)) + if (ret < 0) + return ret; + else if (ret != num_data * sizeof(u32)) return -EIO; return 0; } @@ -1014,7 +1016,7 @@ int usbpd_send_vdm(struct usbpd *pd, u32 vdm_hdr, const u32 *vdos, int num_vdos) pd->vdm_tx = vdm_tx; /* slight delay before queuing to prioritize handling of incoming VDM */ - kick_sm(pd, 5); + kick_sm(pd, 2); return 0; } @@ -1232,21 +1234,32 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) static void handle_vdm_tx(struct usbpd *pd) { int ret; + unsigned long flags; /* only send one VDM at a time */ if (pd->vdm_tx) { u32 vdm_hdr = pd->vdm_tx->data[0]; + /* bail out and try again later if a message just arrived */ + spin_lock_irqsave(&pd->rx_lock, flags); + if (!list_empty(&pd->rx_q)) { + spin_unlock_irqrestore(&pd->rx_lock, flags); + return; + } + spin_unlock_irqrestore(&pd->rx_lock, flags); + ret = pd_send_msg(pd, MSG_VDM, pd->vdm_tx->data, pd->vdm_tx->size, SOP_MSG); if (ret) { - usbpd_err(&pd->dev, "Error sending VDM command %d\n", - SVDM_HDR_CMD(pd->vdm_tx->data[0])); - usbpd_set_state(pd, pd->current_pr == PR_SRC ? + usbpd_err(&pd->dev, "Error (%d) sending VDM command %d\n", + ret, SVDM_HDR_CMD(pd->vdm_tx->data[0])); + + /* retry when hitting PE_SRC/SNK_Ready again */ + if (ret != -EBUSY) + usbpd_set_state(pd, pd->current_pr == PR_SRC ? PE_SRC_SEND_SOFT_RESET : PE_SNK_SEND_SOFT_RESET); - /* retry when hitting PE_SRC/SNK_Ready again */ return; } @@ -1258,7 +1271,7 @@ static void handle_vdm_tx(struct usbpd *pd) SVDM_HDR_CMD_TYPE(vdm_hdr) == SVDM_CMD_TYPE_INITIATOR && SVDM_HDR_CMD(vdm_hdr) <= USBPD_SVDM_DISCOVER_SVIDS) { if (pd->vdm_tx_retry) { - usbpd_err(&pd->dev, "Previous Discover VDM command %d not ACKed/NAKed\n", + usbpd_dbg(&pd->dev, "Previous Discover VDM command %d not ACKed/NAKed\n", SVDM_HDR_CMD( pd->vdm_tx_retry->data[0])); kfree(pd->vdm_tx_retry); @@ -1337,6 +1350,13 @@ static void vconn_swap(struct usbpd *pd) pd->vconn_enabled = true; + /* + * Small delay to ensure Vconn has ramped up. This is well + * below tVCONNSourceOn (100ms) so we still send PS_RDY within + * the allowed time. + */ + usleep_range(5000, 10000); + ret = pd_send_msg(pd, MSG_PS_RDY, NULL, 0, SOP_MSG); if (ret) { usbpd_err(&pd->dev, "Error sending PS_RDY\n"); @@ -1543,10 +1563,6 @@ static void usbpd_sm(struct work_struct *w) break; } - val.intval = 1; - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_PD_ACTIVE, &val); - /* transmit was successful if GoodCRC was received */ pd->caps_count = 0; pd->hard_reset_count = 0; @@ -1555,6 +1571,10 @@ static void usbpd_sm(struct work_struct *w) /* wait for REQUEST */ pd->current_state = PE_SRC_SEND_CAPABILITIES_WAIT; kick_sm(pd, SENDER_RESPONSE_TIME); + + val.intval = 1; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PD_ACTIVE, &val); break; case PE_SRC_SEND_CAPABILITIES_WAIT: @@ -1723,16 +1743,16 @@ static void usbpd_sm(struct work_struct *w) POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val); - val.intval = 1; - power_supply_set_property(pd->usb_psy, - POWER_SUPPLY_PROP_PD_ACTIVE, &val); - /* save the PDOs so userspace can further evaluate */ memcpy(&pd->received_pdos, rx_msg->payload, sizeof(pd->received_pdos)); pd->src_cap_id++; usbpd_set_state(pd, PE_SNK_EVALUATE_CAPABILITY); + + val.intval = 1; + power_supply_set_property(pd->usb_psy, + POWER_SUPPLY_PROP_PD_ACTIVE, &val); } else if (pd->hard_reset_count < 3) { usbpd_set_state(pd, PE_SNK_HARD_RESET); } else if (pd->pd_connected) { |
