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>
Sat, 6 Sep 2025 13:30:26 +0000 (15:30 +0200)
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 1f6fdfaa34bf123f78befe98581c13f66d6731df..b2a568a5bc9b0ba5c50b7031d8e21ee09cefa349 100644 (file)
@@ -2426,17 +2426,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(