summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAbe Levkoy <alevkoy@chromium.org>2022-12-21 15:50:04 -0700
committerChromeos LUCI <chromeos-scoped@luci-project-accounts.iam.gserviceaccount.com>2023-03-17 21:08:20 +0000
commit768903a5bf71508226d5adf52b8cabef8a783e42 (patch)
tree78a27a02999a30ebca352c6e6a1454b8e52af378
parent3cb733a9e63ae9969565c70428703c31efd57486 (diff)
downloadchrome-ec-768903a5bf71508226d5adf52b8cabef8a783e42.tar.gz
TCPMv2: Ignore data role mismatch during DRS
After a successful Data Role Swap message sequence, the PE and TC take one more task loop cycle to update the canonical data role. During this interval, do not check the data role of incoming messages. BUG=b:262345042 TEST=Maintain connection with monitor despite message ~2 ms after DRS BRANCH=none LOW_COVERAGE_REASON=native_posix doesn't model state transition timing Change-Id: I4e3e12d52e1817b583f2f774318231ee18e99b07 Signed-off-by: Abe Levkoy <alevkoy@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/4121103 Reviewed-by: Keith Short <keithshort@chromium.org>
-rw-r--r--common/mock/usb_prl_mock.c4
-rw-r--r--common/usbc/usb_pe_drp_sm.c9
-rw-r--r--common/usbc/usb_prl_sm.c18
-rw-r--r--include/usb_prl_sm.h8
4 files changed, 37 insertions, 2 deletions
diff --git a/common/mock/usb_prl_mock.c b/common/mock/usb_prl_mock.c
index 769cd6073c..e69ad38712 100644
--- a/common/mock/usb_prl_mock.c
+++ b/common/mock/usb_prl_mock.c
@@ -63,6 +63,10 @@ void prl_execute_hard_reset(int port)
mock_prl_port[port].last_tx_type = TCPCI_MSG_TX_HARD_RESET;
}
+void prl_set_data_role_check(int port, bool enable)
+{
+}
+
enum pd_rev_type prl_get_rev(int port, enum tcpci_msg_type partner)
{
return PD_REV30;
diff --git a/common/usbc/usb_pe_drp_sm.c b/common/usbc/usb_pe_drp_sm.c
index aa93f1cdc3..0264837057 100644
--- a/common/usbc/usb_pe_drp_sm.c
+++ b/common/usbc/usb_pe_drp_sm.c
@@ -4666,6 +4666,14 @@ static void pe_drs_evaluate_swap_entry(int port)
* PE_DRS_DFP_UFP_Accept_Swap states embedded here.
*/
send_ctrl_msg(port, TCPCI_MSG_SOP, PD_CTRL_ACCEPT);
+ /*
+ * The PD spec implies that the PE transitions through
+ * PE_DRS_*_Accept_Swap and PE_DRS_Change and updates the data
+ * role instantaneously, but this PE doesn't. During the
+ * transition, do not validate the data role of incoming
+ * messages, in case the port partner transitioned faster.
+ */
+ prl_set_data_role_check(port, false);
} else {
/*
* PE_DRS_UFP_DFP_Reject_Swap and PE_DRS_DFP_UFP_Reject_Swap
@@ -4717,6 +4725,7 @@ static void pe_drs_change_run(int port)
/* Update the data role */
pe[port].data_role = pd_get_data_role(port);
+ prl_set_data_role_check(port, true);
if (pe[port].data_role == PD_ROLE_DFP)
PE_CLR_FLAG(port, PE_FLAGS_DR_SWAP_TO_DFP);
diff --git a/common/usbc/usb_prl_sm.c b/common/usbc/usb_prl_sm.c
index 2c09a4450c..076adae40d 100644
--- a/common/usbc/usb_prl_sm.c
+++ b/common/usbc/usb_prl_sm.c
@@ -120,6 +120,8 @@ __maybe_unused static void print_flag(const char *group, int set_or_clear,
#define PRL_FLAGS_ABORT BIT(9)
/* Flag to note current TX message uses chunking */
#define PRL_FLAGS_CHUNKING BIT(10)
+/* Flag to disable checking data role on incoming messages. */
+#define PRL_FLAGS_IGNORE_DATA_ROLE BIT(11)
struct bit_name {
int value;
@@ -139,6 +141,7 @@ static __const_data const struct bit_name flag_bit_names[] = {
{ PRL_FLAGS_MSG_RECEIVED, "PRL_FLAGS_MSG_RECEIVED" },
{ PRL_FLAGS_ABORT, "PRL_FLAGS_ABORT" },
{ PRL_FLAGS_CHUNKING, "PRL_FLAGS_CHUNKING" },
+ { PRL_FLAGS_IGNORE_DATA_ROLE, "PRL_FLAGS_IGNORE_DATA_ROLE" },
};
__maybe_unused static void print_bits(const char *group, const char *desc,
@@ -559,6 +562,14 @@ void prl_execute_hard_reset(int port)
task_wake(PD_PORT_TO_TASK_ID(port));
}
+void prl_set_data_role_check(int port, bool enable)
+{
+ if (enable)
+ RCH_CLR_FLAG(port, PRL_FLAGS_IGNORE_DATA_ROLE);
+ else
+ RCH_SET_FLAG(port, PRL_FLAGS_IGNORE_DATA_ROLE);
+}
+
int prl_is_running(int port)
{
return local_state[port] == SM_RUN;
@@ -2199,9 +2210,12 @@ static void prl_rx_wait_for_phy_message(const int port, int evt)
* defined in [USB Type-C 2.0] Shall be performed."
*
* The spec lists no required state for this check, so centralize it by
- * processing this requirement in the PRL RX.
+ * processing this requirement in the PRL RX. Because the TCPM does not
+ * swap data roles instantaneously, disable this check during the
+ * transition.
*/
- if (PD_HEADER_GET_SOP(header) == TCPCI_MSG_SOP &&
+ if (!RCH_CHK_FLAG(port, PRL_FLAGS_IGNORE_DATA_ROLE) &&
+ PD_HEADER_GET_SOP(header) == TCPCI_MSG_SOP &&
PD_HEADER_DROLE(header) == pd_get_data_role(port)) {
CPRINTS("C%d Error: Data role mismatch (0x%08x)", port, header);
tc_start_error_recovery(port);
diff --git a/include/usb_prl_sm.h b/include/usb_prl_sm.h
index 5671f8300e..5dda58a733 100644
--- a/include/usb_prl_sm.h
+++ b/include/usb_prl_sm.h
@@ -143,4 +143,12 @@ void prl_hard_reset_complete(int port);
*/
void prl_execute_hard_reset(int port);
+/**
+ * Enables or disables checking the data role on incoming messages.
+ *
+ * @param port USB-C port number
+ * @param enable True to enable checking, false to disable checking
+ */
+void prl_set_data_role_check(int port, bool enable);
+
#endif /* __CROS_EC_USB_PRL_H */