summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJett Rink <jettrink@chromium.org>2018-10-18 13:52:45 -0600
committerchrome-bot <chrome-bot@chromium.org>2018-10-28 13:54:11 -0700
commit149190dd3a823d835be71ec4b4e4ae9e5120c774 (patch)
tree8f734d2d0b3c71ff0b24f6078739b881febb9ec3
parente5e282e43718b7acd706a717dc0fa9a821505dfd (diff)
downloadchrome-ec-149190dd3a823d835be71ec4b4e4ae9e5120c774.tar.gz
usb-pd: send more request after wait
When we are not in an explicit contract, we still need to send more requests attempts when we receive a WAIT control command. Otherwise, the port partner can issue a hard reset. BRANCH=none BUG=b:117498337 TEST=hard reset boot loop goes away with this CL. Change-Id: Iabe8f086659dc0d7a405fa9f17495fb1c61494cc Signed-off-by: Jett Rink <jettrink@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1289311 Commit-Ready: Edward Hill <ecgh@chromium.org> Reviewed-by: Edward Hill <ecgh@chromium.org>
-rw-r--r--common/usb_pd_protocol.c72
-rw-r--r--test/usb_pd.c85
2 files changed, 120 insertions, 37 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index e9e86be32b..988443aba1 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -1381,6 +1381,7 @@ static void handle_data_request(int port, uint16_t head,
case PD_DATA_SOURCE_CAP:
if ((pd[port].task_state == PD_STATE_SNK_DISCOVERY)
|| (pd[port].task_state == PD_STATE_SNK_TRANSITION)
+ || (pd[port].task_state == PD_STATE_SNK_REQUESTED)
#ifdef CONFIG_USB_PD_VBUS_DETECT_NONE
|| (pd[port].task_state ==
PD_STATE_SNK_HARD_RESET_RECOVER)
@@ -1650,49 +1651,46 @@ static void handle_ctrl_request(int port, uint16_t head,
set_state(port, PD_STATE_SNK_READY);
else if (pd[port].task_state == PD_STATE_SNK_REQUESTED) {
/*
- * Explicit Contract in place
+ * On reception of a WAIT message, transition to
+ * PD_STATE_SNK_READY after PD_T_SINK_REQUEST ms to
+ * send another request.
*
- * On reception of a WAIT message, transition to
- * PD_STATE_SNK_READY after PD_T_SINK_REQUEST ms to
- * send another reqest.
+ * On reception of a REJECT message, transition to
+ * PD_STATE_SNK_READY but don't resend the request if
+ * we already have a contract in place.
*
- * On reception of a REJECT messag, transition to
- * PD_STATE_SNK_READY but don't resend the request.
- *
- * NO Explicit Contract in place
- *
- * On reception of a WAIT or REJECT message,
- * transition to PD_STATE_SNK_DISCOVERY
+ * On reception of a REJECT message without a contract,
+ * transition to PD_STATE_SNK_DISCOVERY instead.
*/
- if (pd[port].flags & PD_FLAGS_EXPLICIT_CONTRACT) {
- /* We have an explicit contract */
- if (type == PD_CTRL_WAIT) {
- /*
- * Trigger a new power request when
- * we enter PD_STATE_SNK_READY
- */
- pd[port].new_power_request = 1;
+ if (type == PD_CTRL_WAIT) {
+ /*
+ * Trigger a new power request when
+ * we enter PD_STATE_SNK_READY
+ */
+ pd[port].new_power_request = 1;
- /*
- * After the request is triggered,
- * make sure the request is sent.
- */
- pd[port].prev_request_mv = 0;
+ /*
+ * After the request is triggered,
+ * make sure the request is sent.
+ */
+ pd[port].prev_request_mv = 0;
- /*
- * Transition to PD_STATE_SNK_READY
- * after PD_T_SINK_REQUEST ms.
- */
- set_state_timeout(port, get_time().val +
- PD_T_SINK_REQUEST,
- PD_STATE_SNK_READY);
- } else {
- /* The request was rejected */
- set_state(port, PD_STATE_SNK_READY);
- }
+ /*
+ * Transition to PD_STATE_SNK_READY
+ * after PD_T_SINK_REQUEST ms.
+ */
+ set_state_timeout(port,
+ get_time().val +
+ PD_T_SINK_REQUEST,
+ PD_STATE_SNK_READY);
} else {
- /* No explicit contract */
- set_state(port, PD_STATE_SNK_DISCOVERY);
+ /* The request was rejected */
+ const int in_contract =
+ pd[port].flags &
+ PD_FLAGS_EXPLICIT_CONTRACT;
+ set_state(port,
+ in_contract ? PD_STATE_SNK_READY
+ : PD_STATE_SNK_DISCOVERY);
}
}
#endif
diff --git a/test/usb_pd.c b/test/usb_pd.c
index 1d8f91f8d8..9365983b35 100644
--- a/test/usb_pd.c
+++ b/test/usb_pd.c
@@ -647,6 +647,90 @@ static int test_request_with_wait(void)
return EC_SUCCESS;
}
+static int test_request_with_wait_no_src_cap(void)
+{
+#ifdef CONFIG_USB_PD_GIVE_BACK
+ uint32_t expected_rdo = RDO_FIXED(1, 900, PD_MIN_CURRENT_MA,
+ RDO_CAP_MISMATCH | RDO_GIVE_BACK);
+#else
+ uint32_t expected_rdo = RDO_FIXED(1, 900, 900, RDO_CAP_MISMATCH);
+#endif
+ uint8_t port = PORT0;
+
+ plug_in_source(port, 0);
+ task_wake(PD_PORT_TO_TASK_ID(port));
+ task_wait_event(2 * PD_T_CC_DEBOUNCE + 100 * MSEC);
+ TEST_ASSERT(pd_port[port].polarity == 0);
+
+ /* We're in SNK_DISCOVERY now. Let's send the source cap. */
+ simulate_source_cap(port, 0);
+ task_wait_event(30 * MSEC);
+ TEST_ASSERT(verify_goodcrc(port,
+ PD_ROLE_SINK, pd_port[port].msg_rx_id));
+
+ /* Wait for the power request */
+ task_wake(PD_PORT_TO_TASK_ID(port));
+ task_wait_event(35 * MSEC); /* tSenderResponse: 24~30 ms */
+ inc_rx_id(port);
+
+ /* Process the request */
+ TEST_ASSERT(pd_test_tx_msg_verify_sop(port));
+ TEST_ASSERT(pd_test_tx_msg_verify_short(port,
+ PD_HEADER(PD_DATA_REQUEST, PD_ROLE_SINK, PD_ROLE_UFP,
+ pd_port[port].msg_tx_id, 1, pd_port[port].rev, 0)));
+ TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_rdo));
+ TEST_ASSERT(pd_test_tx_msg_verify_crc(port));
+ TEST_ASSERT(pd_test_tx_msg_verify_eop(port));
+
+ task_wake(PD_PORT_TO_TASK_ID(port));
+ task_wait_event(30 * MSEC);
+
+ /* Request is good. Send GoodCRC */
+ simulate_goodcrc(port, PD_ROLE_SOURCE, pd_port[port].msg_tx_id);
+ task_wake(PD_PORT_TO_TASK_ID(0));
+ task_wait_event(30 * MSEC);
+ inc_tx_id(port);
+
+ /* We're in SNK_REQUESTED. Send wait */
+ simulate_wait(port);
+ task_wait_event(30 * MSEC);
+ TEST_ASSERT(verify_goodcrc(0, PD_ROLE_SINK, pd_port[port].msg_rx_id));
+
+ task_wake(PD_PORT_TO_TASK_ID(port));
+ task_wait_event(30 * MSEC);
+ inc_rx_id(port);
+
+ /*
+ * Some port partners do not send another SRC_CAP and expect us to send
+ * another REQUEST 100ms after the WAIT.
+ */
+ task_wake(PD_PORT_TO_TASK_ID(port));
+ task_wait_event(100 * MSEC); /* tSinkRequest: 100 ms */
+ inc_rx_id(port);
+
+ /* Process the request */
+ TEST_ASSERT(pd_test_tx_msg_verify_sop(port));
+ TEST_ASSERT(pd_test_tx_msg_verify_short(port,
+ PD_HEADER(PD_DATA_REQUEST, PD_ROLE_SINK, PD_ROLE_UFP,
+ pd_port[port].msg_tx_id, 1, pd_port[port].rev, 0)));
+ TEST_ASSERT(pd_test_tx_msg_verify_word(port, expected_rdo));
+ TEST_ASSERT(pd_test_tx_msg_verify_crc(port));
+ TEST_ASSERT(pd_test_tx_msg_verify_eop(port));
+
+ task_wake(PD_PORT_TO_TASK_ID(port));
+ task_wait_event(30 * MSEC);
+
+ /* Request was good. Send GoodCRC */
+ simulate_goodcrc(port, PD_ROLE_SOURCE, pd_port[port].msg_tx_id);
+ task_wake(PD_PORT_TO_TASK_ID(port));
+ task_wait_event(30 * MSEC);
+ inc_tx_id(port);
+
+ /* We're done */
+ unplug(port);
+ return EC_SUCCESS;
+}
+
static int test_request_with_reject(void)
{
#ifdef CONFIG_USB_PD_GIVE_BACK
@@ -825,6 +909,7 @@ void run_test(void)
RUN_TEST(test_request);
RUN_TEST(test_sink);
RUN_TEST(test_request_with_wait);
+ RUN_TEST(test_request_with_wait_no_src_cap);
RUN_TEST(test_request_with_wait_and_contract);
RUN_TEST(test_request_with_reject);