Message ID | 20190316155712.16630-1-hdegoede@redhat.com (mailing list archive) |
---|---|
State | Mainlined |
Commit | 976daf9d1199932df80e7b04546d1a1bd4ed5ece |
Headers | show |
Series | [v2] usb: typec: tcpm: Try PD-2.0 if sink does not respond to 3.0 source-caps | expand |
On Sat, Mar 16, 2019 at 04:57:12PM +0100, Hans de Goede wrote: > PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and > simply ignore any src PDOs which the sink does not understand such as PPS > but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message, > causing contract negotiation to fail. > > This commit fixes such sinks not working by re-trying the contract > negotiation with PD-2.0 source-caps messages if we don't have a contract > after PD_N_HARD_RESET_COUNT hard-reset attempts. > > The problem fixed by this commit was noticed with a Type-C to VGA dongle. > LGTM. Reviewed-by: Guenter Roeck <linux@roeck-us.net> One question though: Shouldn't tcpm_pd_send_source_caps() filter out PD 3.0 only capabilities if the revision is reduced ? Thanks, Guenter > Signed-off-by: Hans de Goede <hdegoede@redhat.com> > --- > The Type-C to VGA dongle on which this encountered looks like this one: > https://www.aliexpress.com/item/Male-USB-3-1-Type-C-USB-C-to-Female-VGA-Adapter-Cable-10Gbps-for-New/32898274476.html > --- > Changes in v2: > -Refactor the patch to avoid a check vs use race wrt negotiated_rev > --- > drivers/usb/typec/tcpm/tcpm.c | 27 ++++++++++++++++++++++++++- > 1 file changed, 26 insertions(+), 1 deletion(-) > > diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c > index f1c39a3c7534..d34e945e5d09 100644 > --- a/drivers/usb/typec/tcpm/tcpm.c > +++ b/drivers/usb/typec/tcpm/tcpm.c > @@ -37,6 +37,7 @@ > S(SRC_ATTACHED), \ > S(SRC_STARTUP), \ > S(SRC_SEND_CAPABILITIES), \ > + S(SRC_SEND_CAPABILITIES_TIMEOUT), \ > S(SRC_NEGOTIATE_CAPABILITIES), \ > S(SRC_TRANSITION_SUPPLY), \ > S(SRC_READY), \ > @@ -2966,10 +2967,34 @@ static void run_state_machine(struct tcpm_port *port) > /* port->hard_reset_count = 0; */ > port->caps_count = 0; > port->pd_capable = true; > - tcpm_set_state_cond(port, hard_reset_state(port), > + tcpm_set_state_cond(port, SRC_SEND_CAPABILITIES_TIMEOUT, > PD_T_SEND_SOURCE_CAP); > } > break; > + case SRC_SEND_CAPABILITIES_TIMEOUT: > + /* > + * Error recovery for a PD_DATA_SOURCE_CAP reply timeout. > + * > + * PD 2.0 sinks are supposed to accept src-capabilities with a > + * 3.0 header and simply ignore any src PDOs which the sink does > + * not understand such as PPS but some 2.0 sinks instead ignore > + * the entire PD_DATA_SOURCE_CAP message, causing contract > + * negotiation to fail. > + * > + * After PD_N_HARD_RESET_COUNT hard-reset attempts, we try > + * sending src-capabilities with a lower PD revision to > + * make these broken sinks work. > + */ > + if (port->hard_reset_count < PD_N_HARD_RESET_COUNT) { > + tcpm_set_state(port, HARD_RESET_SEND, 0); > + } else if (port->negotiated_rev > PD_REV20) { > + port->negotiated_rev--; > + port->hard_reset_count = 0; > + tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0); > + } else { > + tcpm_set_state(port, hard_reset_state(port), 0); > + } > + break; > case SRC_NEGOTIATE_CAPABILITIES: > ret = tcpm_pd_check_request(port); > if (ret < 0) { > -- > 2.20.1 >
On Sat, Mar 16, 2019 at 04:57:12PM +0100, Hans de Goede wrote: > PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and > simply ignore any src PDOs which the sink does not understand such as PPS > but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message, > causing contract negotiation to fail. > > This commit fixes such sinks not working by re-trying the contract > negotiation with PD-2.0 source-caps messages if we don't have a contract > after PD_N_HARD_RESET_COUNT hard-reset attempts. > > The problem fixed by this commit was noticed with a Type-C to VGA dongle. > > Signed-off-by: Hans de Goede <hdegoede@redhat.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Also applied to my typec-next branch: https://github.com/krohei/linux/commit/35e8c23e398ad03e7d9268a11a0408f8642da6d0 > --- > The Type-C to VGA dongle on which this encountered looks like this one: > https://www.aliexpress.com/item/Male-USB-3-1-Type-C-USB-C-to-Female-VGA-Adapter-Cable-10Gbps-for-New/32898274476.html > --- > Changes in v2: > -Refactor the patch to avoid a check vs use race wrt negotiated_rev > --- > drivers/usb/typec/tcpm/tcpm.c | 27 ++++++++++++++++++++++++++- > 1 file changed, 26 insertions(+), 1 deletion(-) > > diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c > index f1c39a3c7534..d34e945e5d09 100644 > --- a/drivers/usb/typec/tcpm/tcpm.c > +++ b/drivers/usb/typec/tcpm/tcpm.c > @@ -37,6 +37,7 @@ > S(SRC_ATTACHED), \ > S(SRC_STARTUP), \ > S(SRC_SEND_CAPABILITIES), \ > + S(SRC_SEND_CAPABILITIES_TIMEOUT), \ > S(SRC_NEGOTIATE_CAPABILITIES), \ > S(SRC_TRANSITION_SUPPLY), \ > S(SRC_READY), \ > @@ -2966,10 +2967,34 @@ static void run_state_machine(struct tcpm_port *port) > /* port->hard_reset_count = 0; */ > port->caps_count = 0; > port->pd_capable = true; > - tcpm_set_state_cond(port, hard_reset_state(port), > + tcpm_set_state_cond(port, SRC_SEND_CAPABILITIES_TIMEOUT, > PD_T_SEND_SOURCE_CAP); > } > break; > + case SRC_SEND_CAPABILITIES_TIMEOUT: > + /* > + * Error recovery for a PD_DATA_SOURCE_CAP reply timeout. > + * > + * PD 2.0 sinks are supposed to accept src-capabilities with a > + * 3.0 header and simply ignore any src PDOs which the sink does > + * not understand such as PPS but some 2.0 sinks instead ignore > + * the entire PD_DATA_SOURCE_CAP message, causing contract > + * negotiation to fail. > + * > + * After PD_N_HARD_RESET_COUNT hard-reset attempts, we try > + * sending src-capabilities with a lower PD revision to > + * make these broken sinks work. > + */ > + if (port->hard_reset_count < PD_N_HARD_RESET_COUNT) { > + tcpm_set_state(port, HARD_RESET_SEND, 0); > + } else if (port->negotiated_rev > PD_REV20) { > + port->negotiated_rev--; > + port->hard_reset_count = 0; > + tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0); > + } else { > + tcpm_set_state(port, hard_reset_state(port), 0); > + } > + break; > case SRC_NEGOTIATE_CAPABILITIES: > ret = tcpm_pd_check_request(port); > if (ret < 0) { > -- > 2.20.1 thanks,
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c index f1c39a3c7534..d34e945e5d09 100644 --- a/drivers/usb/typec/tcpm/tcpm.c +++ b/drivers/usb/typec/tcpm/tcpm.c @@ -37,6 +37,7 @@ S(SRC_ATTACHED), \ S(SRC_STARTUP), \ S(SRC_SEND_CAPABILITIES), \ + S(SRC_SEND_CAPABILITIES_TIMEOUT), \ S(SRC_NEGOTIATE_CAPABILITIES), \ S(SRC_TRANSITION_SUPPLY), \ S(SRC_READY), \ @@ -2966,10 +2967,34 @@ static void run_state_machine(struct tcpm_port *port) /* port->hard_reset_count = 0; */ port->caps_count = 0; port->pd_capable = true; - tcpm_set_state_cond(port, hard_reset_state(port), + tcpm_set_state_cond(port, SRC_SEND_CAPABILITIES_TIMEOUT, PD_T_SEND_SOURCE_CAP); } break; + case SRC_SEND_CAPABILITIES_TIMEOUT: + /* + * Error recovery for a PD_DATA_SOURCE_CAP reply timeout. + * + * PD 2.0 sinks are supposed to accept src-capabilities with a + * 3.0 header and simply ignore any src PDOs which the sink does + * not understand such as PPS but some 2.0 sinks instead ignore + * the entire PD_DATA_SOURCE_CAP message, causing contract + * negotiation to fail. + * + * After PD_N_HARD_RESET_COUNT hard-reset attempts, we try + * sending src-capabilities with a lower PD revision to + * make these broken sinks work. + */ + if (port->hard_reset_count < PD_N_HARD_RESET_COUNT) { + tcpm_set_state(port, HARD_RESET_SEND, 0); + } else if (port->negotiated_rev > PD_REV20) { + port->negotiated_rev--; + port->hard_reset_count = 0; + tcpm_set_state(port, SRC_SEND_CAPABILITIES, 0); + } else { + tcpm_set_state(port, hard_reset_state(port), 0); + } + break; case SRC_NEGOTIATE_CAPABILITIES: ret = tcpm_pd_check_request(port); if (ret < 0) {
PD 2.0 sinks are supposed to accept src-capabilities with a 3.0 header and simply ignore any src PDOs which the sink does not understand such as PPS but some 2.0 sinks instead ignore the entire PD_DATA_SOURCE_CAP message, causing contract negotiation to fail. This commit fixes such sinks not working by re-trying the contract negotiation with PD-2.0 source-caps messages if we don't have a contract after PD_N_HARD_RESET_COUNT hard-reset attempts. The problem fixed by this commit was noticed with a Type-C to VGA dongle. Signed-off-by: Hans de Goede <hdegoede@redhat.com> --- The Type-C to VGA dongle on which this encountered looks like this one: https://www.aliexpress.com/item/Male-USB-3-1-Type-C-USB-C-to-Female-VGA-Adapter-Cable-10Gbps-for-New/32898274476.html --- Changes in v2: -Refactor the patch to avoid a check vs use race wrt negotiated_rev --- drivers/usb/typec/tcpm/tcpm.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-)