summaryrefslogtreecommitdiff
path: root/drivers/usb/host
diff options
context:
space:
mode:
authorWesley Cheng <quic_wcheng@quicinc.com>2025-04-09 22:47:38 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-04-11 14:02:30 +0300
commitb85a2ebda1034881d09e6127726dc78950669474 (patch)
treeab07f8835c6637689a6c5384b3bd866e25bfa854 /drivers/usb/host
parent000ab7dab5b8ed4f788ea7714e2df82275db5f7f (diff)
downloadlinux-b85a2ebda1034881d09e6127726dc78950669474.tar.xz
usb: host: xhci: Notify xHCI sideband on transfer ring free
In the case of handling a USB bus reset, the xhci_discover_or_reset_device can run without first notifying the xHCI sideband client driver to stop or prevent the use of the transfer ring. It was seen that when a bus reset situation happened, the USB offload driver was attempting to fetch the xHCI transfer ring information, which was already freed. Tested-by: Puma Hsu <pumahsu@google.com> Tested-by: Daehwan Jung <dh10.jung@samsung.com> Signed-off-by: Wesley Cheng <quic_wcheng@quicinc.com> Acked-by: Mark Brown <broonie@kernel.org> Link: https://lore.kernel.org/r/20250409194804.3773260-6-quic_wcheng@quicinc.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r--drivers/usb/host/xhci-sideband.c29
-rw-r--r--drivers/usb/host/xhci.c3
2 files changed, 31 insertions, 1 deletions
diff --git a/drivers/usb/host/xhci-sideband.c b/drivers/usb/host/xhci-sideband.c
index 742bbc6c2d9b..d49f9886dd84 100644
--- a/drivers/usb/host/xhci-sideband.c
+++ b/drivers/usb/host/xhci-sideband.c
@@ -89,6 +89,30 @@ __xhci_sideband_remove_endpoint(struct xhci_sideband *sb, struct xhci_virt_ep *e
/* sideband api functions */
/**
+ * xhci_sideband_notify_ep_ring_free - notify client of xfer ring free
+ * @sb: sideband instance for this usb device
+ * @ep_index: usb endpoint index
+ *
+ * Notifies the xHCI sideband client driver of a xHCI transfer ring free
+ * routine. This will allow for the client to ensure that all transfers
+ * are completed.
+ *
+ * The callback should be synchronous, as the ring free happens after.
+ */
+void xhci_sideband_notify_ep_ring_free(struct xhci_sideband *sb,
+ unsigned int ep_index)
+{
+ struct xhci_sideband_event evt;
+
+ evt.type = XHCI_SIDEBAND_XFER_RING_FREE;
+ evt.evt_data = &ep_index;
+
+ if (sb->notify_client)
+ sb->notify_client(sb->intf, &evt);
+}
+EXPORT_SYMBOL_GPL(xhci_sideband_notify_ep_ring_free);
+
+/**
* xhci_sideband_add_endpoint - add endpoint to sideband access list
* @sb: sideband instance for this usb device
* @host_ep: usb host endpoint
@@ -342,7 +366,9 @@ EXPORT_SYMBOL_GPL(xhci_sideband_interrupter_id);
* Return: pointer to a new xhci_sideband instance if successful. NULL otherwise.
*/
struct xhci_sideband *
-xhci_sideband_register(struct usb_interface *intf, enum xhci_sideband_type type)
+xhci_sideband_register(struct usb_interface *intf, enum xhci_sideband_type type,
+ int (*notify_client)(struct usb_interface *intf,
+ struct xhci_sideband_event *evt))
{
struct usb_device *udev = interface_to_usbdev(intf);
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
@@ -381,6 +407,7 @@ xhci_sideband_register(struct usb_interface *intf, enum xhci_sideband_type type)
sb->vdev = vdev;
sb->intf = intf;
sb->type = type;
+ sb->notify_client = notify_client;
vdev->sideband = sb;
spin_unlock_irq(&xhci->lock);
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index b361312e05ed..cfda35004754 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -20,6 +20,7 @@
#include <linux/string_choices.h>
#include <linux/dmi.h>
#include <linux/dma-mapping.h>
+#include <linux/usb/xhci-sideband.h>
#include "xhci.h"
#include "xhci-trace.h"
@@ -3919,6 +3920,8 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
}
if (ep->ring) {
+ if (ep->sideband)
+ xhci_sideband_notify_ep_ring_free(ep->sideband, i);
xhci_debugfs_remove_endpoint(xhci, virt_dev, i);
xhci_free_endpoint_ring(xhci, virt_dev, i);
}