summaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
authorKeith Short <keithshort@chromium.org>2020-09-17 11:53:20 -0600
committerCommit Bot <commit-bot@chromium.org>2020-09-18 03:08:28 +0000
commita345cfc8ca330248e84250b6b962e1a6670bc3f2 (patch)
tree64150ea9ed7dfdfa252d715e04d74e333539f222 /common
parent4ded82ed6126087288fb93ec0e6e1b0a279ba2f3 (diff)
downloadchrome-ec-a345cfc8ca330248e84250b6b962e1a6670bc3f2.tar.gz
tcpmv2: Retry PR Swap if partner sends Wait response
For the SRC to SNK PR Swap, if the partner responds with Wait, retry the PR swap request up to 5 times, delaying tPRSwapWait (100ms) between retries. This change removes the PE_FLAGS_WAITING_DR_SWAP flag. The flag was only set, never checked, and never cleared by any code in the PE. BUG=b:168808976 BRANCH=none TEST=make buildall TEST=Connect Gatkex creek board, verify PR swap from SRC to SNK after receiving Wait message. Signed-off-by: Keith Short <keithshort@chromium.org> Change-Id: I4854ab03bd771feee33fa1ae71aa9407f2d4f109 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2417148 Reviewed-by: Diana Z <dzigterman@chromium.org> Reviewed-by: Abe Levkoy <alevkoy@chromium.org>
Diffstat (limited to 'common')
-rw-r--r--common/usbc/usb_pe_drp_sm.c71
1 files changed, 62 insertions, 9 deletions
diff --git a/common/usbc/usb_pe_drp_sm.c b/common/usbc/usb_pe_drp_sm.c
index 8544433e28..1b3b30801e 100644
--- a/common/usbc/usb_pe_drp_sm.c
+++ b/common/usbc/usb_pe_drp_sm.c
@@ -128,8 +128,11 @@
#define PE_FLAGS_FAST_ROLE_SWAP_SIGNALED BIT(21)
/* TODO: POLICY decision: Triggers a DR SWAP attempt from UFP to DFP */
#define PE_FLAGS_DR_SWAP_TO_DFP BIT(22)
-/* Flag to trigger a message resend after receiving a WAIT from port partner */
-#define PE_FLAGS_WAITING_DR_SWAP BIT(23)
+/*
+ * TODO: POLICY decision
+ * Flag to trigger a message resend after receiving a WAIT from port partner
+ */
+#define PE_FLAGS_WAITING_PR_SWAP BIT(23)
/* FLAG to track if port partner is dualrole capable */
#define PE_FLAGS_PORT_PARTNER_IS_DUALROLE BIT(24)
/* FLAG is set when an AMS is initiated locally. ie. AP requested a PR_SWAP */
@@ -195,6 +198,14 @@
#define N_VCONN_SWAP_COUNT 3
/*
+ * Counter to track how many times to attempt SRC to SNK PR swaps before giving
+ * up.
+ *
+ * Note: This is not a part of power delivery specification
+ */
+#define N_SNK_SRC_PR_SWAP_COUNT 5
+
+/*
* ChromeOS policy:
* For PD2.0, We must be DFP before sending Discover Identity message
* to the port partner. Attempt to DR SWAP from UFP to DFP
@@ -633,6 +644,12 @@ static struct policy_engine {
uint64_t sink_request_timer;
/*
+ * This timer tracks the time after receiving a Wait message in response
+ * to a PR_Swap message.
+ */
+ uint64_t pr_swap_wait_timer;
+
+ /*
* This timer combines the PSSourceOffTimer and PSSourceOnTimer timers.
* For PSSourceOffTimer, when this DRP device is currently acting as a
* Sink, this timer times out on a PS_RDY Message during a Power Role
@@ -723,6 +740,13 @@ static struct policy_engine {
uint32_t dr_swap_attempt_counter;
/*
+ * This counter tracks how many PR Swap messages are sent when the
+ * partner responds with a Wait message. Only used during SRC to SNK
+ * PR swaps
+ */
+ uint8_t src_snk_pr_swap_counter;
+
+ /*
* This counter maintains a count of VCONN swap requests. If VCONN swap
* isn't successful after N_VCONN_SWAP_COUNT, the port calls
* dpm_vdm_naked().
@@ -1417,6 +1441,11 @@ static void pe_update_pdo_flags(int port, uint32_t pdo)
void pd_request_power_swap(int port)
{
+ /*
+ * Always reset the SRC to SNK PR swap counter when a PR swap is
+ * requested by policy.
+ */
+ pe[port].src_snk_pr_swap_counter = 0;
pe_dpm_request(port, DPM_REQUEST_PR_SWAP);
}
@@ -2290,6 +2319,12 @@ static void pe_src_ready_run(int port)
return;
}
+ if (PE_CHK_FLAG(port, PE_FLAGS_WAITING_PR_SWAP) &&
+ get_time().val > pe[port].pr_swap_wait_timer) {
+ PE_CLR_FLAG(port, PE_FLAGS_WAITING_PR_SWAP);
+ PE_SET_DPM_REQUEST(port, DPM_REQUEST_PR_SWAP);
+ }
+
if (pe[port].wait_and_add_jitter_timer == TIMER_DISABLED ||
get_time().val > pe[port].wait_and_add_jitter_timer) {
@@ -3752,10 +3787,6 @@ static void pe_drs_send_swap_run(int port)
} else if ((type == PD_CTRL_REJECT) ||
(type == PD_CTRL_WAIT) ||
(type == PD_CTRL_NOT_SUPPORTED)) {
- if (type == PD_CTRL_WAIT)
- PE_SET_FLAG(port,
- PE_FLAGS_WAITING_DR_SWAP);
-
pe_set_ready_state(port);
return;
}
@@ -3961,12 +3992,25 @@ static void pe_prs_src_snk_send_swap_run(int port)
if ((ext == 0) && (cnt == 0)) {
if (type == PD_CTRL_ACCEPT) {
+ pe[port].src_snk_pr_swap_counter = 0;
tc_request_power_swap(port);
set_state_pe(port,
PE_PRS_SRC_SNK_TRANSITION_TO_OFF);
- } else if ((type == PD_CTRL_REJECT) ||
- (type == PD_CTRL_WAIT))
+ } else if (type == PD_CTRL_REJECT) {
+ pe[port].src_snk_pr_swap_counter = 0;
set_state_pe(port, PE_SRC_READY);
+ } else if (type == PD_CTRL_WAIT) {
+ if (pe[port].src_snk_pr_swap_counter <
+ N_SNK_SRC_PR_SWAP_COUNT) {
+ PE_SET_FLAG(port,
+ PE_FLAGS_WAITING_PR_SWAP);
+ pe[port].pr_swap_wait_timer =
+ get_time().val +
+ PD_T_PR_SWAP_WAIT;
+ }
+ pe[port].src_snk_pr_swap_counter++;
+ set_state_pe(port, PE_SRC_READY);
+ }
return;
}
}
@@ -3988,6 +4032,13 @@ static void pe_prs_snk_src_evaluate_swap_entry(int port)
{
print_current_state(port);
+ /*
+ * Cancel any pending PR swap request due to a received Wait since the
+ * partner just sent us a PR swap message.
+ */
+ PE_CLR_FLAG(port, PE_FLAGS_WAITING_PR_SWAP);
+ pe[port].src_snk_pr_swap_counter = 0;
+
if (!pd_check_power_swap(port)) {
/* PE_PRS_SNK_SRC_Reject_Swap state embedded here */
send_ctrl_msg(port, TCPC_TX_SOP, PD_CTRL_REJECT);
@@ -5937,9 +5988,11 @@ static void pe_dr_src_get_source_cap_run(int port)
*/
pd_set_src_caps(port, cnt, payload);
if (pe[port].src_caps[0] &
- PDO_FIXED_UNCONSTRAINED)
+ PDO_FIXED_UNCONSTRAINED) {
+ pe[port].src_snk_pr_swap_counter = 0;
PE_SET_DPM_REQUEST(port,
DPM_REQUEST_PR_SWAP);
+ }
set_state_pe(port, PE_SRC_READY);
} else if (type == PD_CTRL_REJECT ||