5.0-stable review patch.  If anyone has any objections, please let me know.

------------------

From: Hans de Goede <hdego...@redhat.com>

commit 976daf9d1199932df80e7b04546d1a1bd4ed5ece upstream.

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 <hdego...@redhat.com>
Reviewed-by: Guenter Roeck <li...@roeck-us.net>
Cc: stable <sta...@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>

---
 drivers/usb/typec/tcpm/tcpm.c |   27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

--- 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 tcp
                        /* 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) {


Reply via email to