]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
usb: typec: tcpm: properly deliver cable vdms to altmode drivers
authorRD Babiera <rdbabiera@google.com>
Thu, 21 Aug 2025 20:37:57 +0000 (20:37 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 19 Sep 2025 14:35:51 +0000 (16:35 +0200)
commit f34bfcc77b18375a87091c289c2eb53c249787b4 upstream.

tcpm_handle_vdm_request delivers messages to the partner altmode or the
cable altmode depending on the SVDM response type, which is incorrect.
The partner or cable should be chosen based on the received message type
instead.

Also add this filter to ADEV_NOTIFY_USB_AND_QUEUE_VDM, which is used when
the Enter Mode command is responded to by a NAK on SOP or SOP' and when
the Exit Mode command is responded to by an ACK on SOP.

Fixes: 7e7877c55eb1 ("usb: typec: tcpm: add alt mode enter/exit/vdm support for sop'")
Cc: stable@vger.kernel.org
Signed-off-by: RD Babiera <rdbabiera@google.com>
Reviewed-by: Badhri Jagan Sridharan <badhri@google.com>
Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Link: https://lore.kernel.org/r/20250821203759.1720841-2-rdbabiera@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/typec/tcpm/tcpm.c

index 43e3dac5129fa5882362a42ea9f6c1721734c72c..92ce01b7d049facc0485bca629be0466535a74d1 100644 (file)
@@ -2375,17 +2375,21 @@ static void tcpm_handle_vdm_request(struct tcpm_port *port,
                case ADEV_NONE:
                        break;
                case ADEV_NOTIFY_USB_AND_QUEUE_VDM:
-                       WARN_ON(typec_altmode_notify(adev, TYPEC_STATE_USB, NULL));
-                       typec_altmode_vdm(adev, p[0], &p[1], cnt);
+                       if (rx_sop_type == TCPC_TX_SOP_PRIME) {
+                               typec_cable_altmode_vdm(adev, TYPEC_PLUG_SOP_P, p[0], &p[1], cnt);
+                       } else {
+                               WARN_ON(typec_altmode_notify(adev, TYPEC_STATE_USB, NULL));
+                               typec_altmode_vdm(adev, p[0], &p[1], cnt);
+                       }
                        break;
                case ADEV_QUEUE_VDM:
-                       if (response_tx_sop_type == TCPC_TX_SOP_PRIME)
+                       if (rx_sop_type == TCPC_TX_SOP_PRIME)
                                typec_cable_altmode_vdm(adev, TYPEC_PLUG_SOP_P, p[0], &p[1], cnt);
                        else
                                typec_altmode_vdm(adev, p[0], &p[1], cnt);
                        break;
                case ADEV_QUEUE_VDM_SEND_EXIT_MODE_ON_FAIL:
-                       if (response_tx_sop_type == TCPC_TX_SOP_PRIME) {
+                       if (rx_sop_type == TCPC_TX_SOP_PRIME) {
                                if (typec_cable_altmode_vdm(adev, TYPEC_PLUG_SOP_P,
                                                            p[0], &p[1], cnt)) {
                                        int svdm_version = typec_get_cable_svdm_version(