diff options
author | Jett Rink <jettrink@chromium.org> | 2018-10-18 13:52:45 -0600 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2018-10-28 13:54:11 -0700 |
commit | 149190dd3a823d835be71ec4b4e4ae9e5120c774 (patch) | |
tree | 8f734d2d0b3c71ff0b24f6078739b881febb9ec3 | |
parent | e5e282e43718b7acd706a717dc0fa9a821505dfd (diff) | |
download | chrome-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.c | 72 | ||||
-rw-r--r-- | test/usb_pd.c | 85 |
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); |