usb: typec: tcpm: Fix VDMs sometimes not being forwarded to alt-mode drivers

Commit a20dcf53ea98 ("usb: typec: tcpm: Respond Not_Supported if no
snk_vdo"), stops tcpm_pd_data_request() calling tcpm_handle_vdm_request()
when port->nr_snk_vdo is not set. But the VDM might be intended for an
altmode-driver, in which case nr_snk_vdo does not matter.

This change breaks the forwarding of connector hotplug (HPD) events
for displayport altmode on devices which don't set nr_snk_vdo.

tcpm_pd_data_request() is the only caller of tcpm_handle_vdm_request(),
so we can move the nr_snk_vdo check to inside it, at which point we
have already looked up the altmode device so we can check for this too.

Doing this check here also ensures that vdm_state gets set to
VDM_STATE_DONE if it was VDM_STATE_BUSY, even if we end up with
responding with PD_MSG_CTRL_NOT_SUPP later.

Note that tcpm_handle_vdm_request() was already sending
PD_MSG_CTRL_NOT_SUPP in some circumstances, after moving the nr_snk_vdo
check the same error-path is now taken when that check fails. So that
we have only one error-path for this and not two. Replace the
tcpm_queue_message(PD_MSG_CTRL_NOT_SUPP) used by the existing error-path
with the more robust tcpm_pd_handle_msg() from the (now removed) second
error-path.

Fixes: a20dcf53ea98 ("usb: typec: tcpm: Respond Not_Supported if no snk_vdo")
Cc: stable <stable@vger.kernel.org>
Cc: Kyle Tso <kyletso@google.com>
Acked-by: Heikki Krogerus <heikki.krogerus@linux.intel.com>
Acked-by: Kyle Tso <kyletso@google.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Link: https://lore.kernel.org/r/20210816154632.381968-1-hdegoede@redhat.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by Hans de Goede and committed by Greg Kroah-Hartman 5571ea31 7c60610d

Changed files
+7 -6
drivers
usb
typec
tcpm
+7 -6
drivers/usb/typec/tcpm/tcpm.c
··· 1737 1737 return rlen; 1738 1738 } 1739 1739 1740 + static void tcpm_pd_handle_msg(struct tcpm_port *port, 1741 + enum pd_msg_request message, 1742 + enum tcpm_ams ams); 1743 + 1740 1744 static void tcpm_handle_vdm_request(struct tcpm_port *port, 1741 1745 const __le32 *payload, int cnt) 1742 1746 { ··· 1768 1764 port->vdm_state = VDM_STATE_DONE; 1769 1765 } 1770 1766 1771 - if (PD_VDO_SVDM(p[0])) { 1767 + if (PD_VDO_SVDM(p[0]) && (adev || tcpm_vdm_ams(port) || port->nr_snk_vdo)) { 1772 1768 rlen = tcpm_pd_svdm(port, adev, p, cnt, response, &adev_action); 1773 1769 } else { 1774 1770 if (port->negotiated_rev >= PD_REV30) 1775 - tcpm_queue_message(port, PD_MSG_CTRL_NOT_SUPP); 1771 + tcpm_pd_handle_msg(port, PD_MSG_CTRL_NOT_SUPP, NONE_AMS); 1776 1772 } 1777 1773 1778 1774 /* ··· 2475 2471 NONE_AMS); 2476 2472 break; 2477 2473 case PD_DATA_VENDOR_DEF: 2478 - if (tcpm_vdm_ams(port) || port->nr_snk_vdo) 2479 - tcpm_handle_vdm_request(port, msg->payload, cnt); 2480 - else if (port->negotiated_rev > PD_REV20) 2481 - tcpm_pd_handle_msg(port, PD_MSG_CTRL_NOT_SUPP, NONE_AMS); 2474 + tcpm_handle_vdm_request(port, msg->payload, cnt); 2482 2475 break; 2483 2476 case PD_DATA_BIST: 2484 2477 port->bist_request = le32_to_cpu(msg->payload[0]);