Skip to content

Commit d9f5f13

Browse files
author
Desnes Nunes
committed
usb: host: xhci: Notify xHCI sideband on transfer ring free
JIRA: https://issues.redhat.com/browse/RHEL-116016 commit b85a2eb Author: Wesley Cheng <quic_wcheng@quicinc.com> Date: Wed, 9 Apr 2025 12:47:38 -0700 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> Signed-off-by: Desnes Nunes <desnesn@redhat.com>
1 parent 83a590f commit d9f5f13

File tree

3 files changed

+60
-2
lines changed

3 files changed

+60
-2
lines changed

drivers/usb/host/xhci-sideband.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,30 @@ __xhci_sideband_remove_endpoint(struct xhci_sideband *sb, struct xhci_virt_ep *e
8888

8989
/* sideband api functions */
9090

91+
/**
92+
* xhci_sideband_notify_ep_ring_free - notify client of xfer ring free
93+
* @sb: sideband instance for this usb device
94+
* @ep_index: usb endpoint index
95+
*
96+
* Notifies the xHCI sideband client driver of a xHCI transfer ring free
97+
* routine. This will allow for the client to ensure that all transfers
98+
* are completed.
99+
*
100+
* The callback should be synchronous, as the ring free happens after.
101+
*/
102+
void xhci_sideband_notify_ep_ring_free(struct xhci_sideband *sb,
103+
unsigned int ep_index)
104+
{
105+
struct xhci_sideband_event evt;
106+
107+
evt.type = XHCI_SIDEBAND_XFER_RING_FREE;
108+
evt.evt_data = &ep_index;
109+
110+
if (sb->notify_client)
111+
sb->notify_client(sb->intf, &evt);
112+
}
113+
EXPORT_SYMBOL_GPL(xhci_sideband_notify_ep_ring_free);
114+
91115
/**
92116
* xhci_sideband_add_endpoint - add endpoint to sideband access list
93117
* @sb: sideband instance for this usb device
@@ -342,7 +366,9 @@ EXPORT_SYMBOL_GPL(xhci_sideband_interrupter_id);
342366
* Return: pointer to a new xhci_sideband instance if successful. NULL otherwise.
343367
*/
344368
struct xhci_sideband *
345-
xhci_sideband_register(struct usb_interface *intf, enum xhci_sideband_type type)
369+
xhci_sideband_register(struct usb_interface *intf, enum xhci_sideband_type type,
370+
int (*notify_client)(struct usb_interface *intf,
371+
struct xhci_sideband_event *evt))
346372
{
347373
struct usb_device *udev = interface_to_usbdev(intf);
348374
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)
381407
sb->vdev = vdev;
382408
sb->intf = intf;
383409
sb->type = type;
410+
sb->notify_client = notify_client;
384411
vdev->sideband = sb;
385412

386413
spin_unlock_irq(&xhci->lock);

drivers/usb/host/xhci.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/string_choices.h>
2121
#include <linux/dmi.h>
2222
#include <linux/dma-mapping.h>
23+
#include <linux/usb/xhci-sideband.h>
2324

2425
#include "xhci.h"
2526
#include "xhci-trace.h"
@@ -3911,6 +3912,8 @@ static int xhci_discover_or_reset_device(struct usb_hcd *hcd,
39113912
}
39123913

39133914
if (ep->ring) {
3915+
if (ep->sideband)
3916+
xhci_sideband_notify_ep_ring_free(ep->sideband, i);
39143917
xhci_debugfs_remove_endpoint(xhci, virt_dev, i);
39153918
xhci_free_endpoint_ring(xhci, virt_dev, i);
39163919
}

include/linux/usb/xhci-sideband.h

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,20 @@ enum xhci_sideband_type {
2121
XHCI_SIDEBAND_VENDOR,
2222
};
2323

24+
enum xhci_sideband_notify_type {
25+
XHCI_SIDEBAND_XFER_RING_FREE,
26+
};
27+
28+
/**
29+
* struct xhci_sideband_event - sideband event
30+
* @type: notifier type
31+
* @evt_data: event data
32+
*/
33+
struct xhci_sideband_event {
34+
enum xhci_sideband_notify_type type;
35+
void *evt_data;
36+
};
37+
2438
/**
2539
* struct xhci_sideband - representation of a sideband accessed usb device.
2640
* @xhci: The xhci host controller the usb device is connected to
@@ -30,6 +44,7 @@ enum xhci_sideband_type {
3044
* @type: xHCI sideband type
3145
* @mutex: mutex for sideband operations
3246
* @intf: USB sideband client interface
47+
* @notify_client: callback for xHCI sideband sequences
3348
*
3449
* FIXME usb device accessed via sideband Keeping track of sideband accessed usb devices.
3550
*/
@@ -44,10 +59,14 @@ struct xhci_sideband {
4459
struct mutex mutex;
4560

4661
struct usb_interface *intf;
62+
int (*notify_client)(struct usb_interface *intf,
63+
struct xhci_sideband_event *evt);
4764
};
4865

4966
struct xhci_sideband *
50-
xhci_sideband_register(struct usb_interface *intf, enum xhci_sideband_type type);
67+
xhci_sideband_register(struct usb_interface *intf, enum xhci_sideband_type type,
68+
int (*notify_client)(struct usb_interface *intf,
69+
struct xhci_sideband_event *evt));
5170
void
5271
xhci_sideband_unregister(struct xhci_sideband *sb);
5372
int
@@ -71,4 +90,13 @@ void
7190
xhci_sideband_remove_interrupter(struct xhci_sideband *sb);
7291
int
7392
xhci_sideband_interrupter_id(struct xhci_sideband *sb);
93+
94+
#if IS_ENABLED(CONFIG_USB_XHCI_SIDEBAND)
95+
void xhci_sideband_notify_ep_ring_free(struct xhci_sideband *sb,
96+
unsigned int ep_index);
97+
#else
98+
static inline void xhci_sideband_notify_ep_ring_free(struct xhci_sideband *sb,
99+
unsigned int ep_index)
100+
{ }
101+
#endif /* IS_ENABLED(CONFIG_USB_XHCI_SIDEBAND) */
74102
#endif /* __LINUX_XHCI_SIDEBAND_H */

0 commit comments

Comments
 (0)