diff options
author | Jack Pham <jackp@codeaurora.org> | 2016-10-25 19:13:37 -0700 |
---|---|---|
committer | Jack Pham <jackp@codeaurora.org> | 2016-10-26 09:11:04 -0700 |
commit | df63068acb2ce8f5410fda353795311d8132f550 (patch) | |
tree | 1f0e3e545eb9f6935032754d3ae1618e195276fc /drivers/usb | |
parent | 46aa49c1188a77f52dc4969f82292c176d8f399b (diff) |
usb: pd: Fix sink hard reset looping bug
commit f2449fb61a25 ("usb: pd: Clear PD_IN_HARD_RESET in
PE_SNK_TRANSITION_TO_DEFAULT") introduced a subtle bug by
moving the clearing of the pd->hard_reset flag in sink mode
to the PE_SNK_TRANSITION_TO_DEFAULT state. This caused a
regression in which the state machine acts as if it had
received a hard reset signal and infinitely loops back there.
The cycle could only be broken if a physical disconnect happens.
Fix this by renaming the flag to hard_reset_recvd and only using
it when receiving, and not sending a hard reset.
Change-Id: I04008d0bfc9a874e08b45f78a937004e9f37527d
Signed-off-by: Jack Pham <jackp@codeaurora.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/pd/policy_engine.c | 30 |
1 files changed, 12 insertions, 18 deletions
diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index a72c874f19a5..2eef9052bd00 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -274,7 +274,7 @@ struct usbpd { struct extcon_dev *extcon; enum usbpd_state current_state; - bool hard_reset; + bool hard_reset_recvd; u8 rx_msg_type; u8 rx_msg_len; u32 rx_payload[7]; @@ -487,16 +487,12 @@ static int pd_eval_src_caps(struct usbpd *pd, const u32 *src_caps) static void pd_send_hard_reset(struct usbpd *pd) { - int ret; - usbpd_dbg(&pd->dev, "send hard reset"); /* Force CC logic to source/sink to keep Rp/Rd unchanged */ set_power_role(pd, pd->current_pr); pd->hard_reset_count++; - ret = pd_phy_signal(HARD_RESET_SIG, 5); /* tHardResetComplete */ - if (!ret) - pd->hard_reset = true; + pd_phy_signal(HARD_RESET_SIG, 5); /* tHardResetComplete */ pd->in_pr_swap = false; } @@ -522,7 +518,7 @@ static void phy_sig_received(struct usbpd *pd, enum pd_sig_type type) /* Force CC logic to source/sink to keep Rp/Rd unchanged */ set_power_role(pd, pd->current_pr); - pd->hard_reset = true; + pd->hard_reset_recvd = true; kick_sm(pd, 0); } @@ -754,8 +750,6 @@ static void usbpd_set_state(struct usbpd *pd, enum usbpd_state next_state) break; case PE_SRC_TRANSITION_TO_DEFAULT: - pd->hard_reset = false; - if (pd->vconn_enabled) regulator_disable(pd->vconn); regulator_disable(pd->vbus); @@ -1403,7 +1397,7 @@ static void usbpd_sm(struct work_struct *w) pd->in_pr_swap = false; pd->pd_connected = false; pd->in_explicit_contract = false; - pd->hard_reset = false; + pd->hard_reset_recvd = false; pd->caps_count = 0; pd->hard_reset_count = 0; pd->src_cap_id = 0; @@ -1456,7 +1450,9 @@ static void usbpd_sm(struct work_struct *w) } /* Hard reset? */ - if (pd->hard_reset) { + if (pd->hard_reset_recvd) { + pd->hard_reset_recvd = false; + val.intval = 1; power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val); @@ -1829,8 +1825,6 @@ static void usbpd_sm(struct work_struct *w) break; case PE_SNK_TRANSITION_TO_DEFAULT: - pd->hard_reset = false; - val.intval = 0; power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val); @@ -2117,11 +2111,11 @@ static int psy_changed(struct notifier_block *nb, unsigned long evt, void *ptr) * During hard reset when VBUS goes to 0 the CC logic * will report this as a disconnection. In those cases * it can be ignored, however the downside is that - * pd->hard_reset can be momentarily true even when a - * non-PD capable source is attached, and can't be - * distinguished from a physical disconnect. In that - * case, allow for the common case of disconnecting - * from an SDP. + * we can also happen to be in the SNK_Transition_to_default + * state due to a hard reset attempt even with a non-PD + * capable source, in which a physical disconnect may get + * masked. In that case, allow for the common case of + * disconnecting from an SDP. * * The less common case is a PD-capable SDP which will * result in a hard reset getting treated like a |