summaryrefslogtreecommitdiff
path: root/drivers/usb/core
diff options
context:
space:
mode:
authorMathias Nyman <mathias.nyman@linux.intel.com>2025-05-14 16:25:20 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2025-06-27 11:05:22 +0100
commit8bc30532b9784c6bd1a39361a30f664d745da3d1 (patch)
tree8dc3a6c19b48d3343ffc09bb6c2477dd2045e546 /drivers/usb/core
parentf78b3fdd2c7f7d9a3d34f9146bb90b152f044f61 (diff)
downloadlinux-8bc30532b9784c6bd1a39361a30f664d745da3d1.tar.gz
linux-8bc30532b9784c6bd1a39361a30f664d745da3d1.tar.bz2
linux-8bc30532b9784c6bd1a39361a30f664d745da3d1.zip
usb: Flush altsetting 0 endpoints before reinitializating them after reset.
commit 89bb3dc13ac29a563f4e4c555e422882f64742bd upstream. usb core avoids sending a Set-Interface altsetting 0 request after device reset, and instead relies on calling usb_disable_interface() and usb_enable_interface() to flush and reset host-side of those endpoints. xHCI hosts allocate and set up endpoint ring buffers and host_ep->hcpriv during usb_hcd_alloc_bandwidth() callback, which in this case is called before flushing the endpoint in usb_disable_interface(). Call usb_disable_interface() before usb_hcd_alloc_bandwidth() to ensure URBs are flushed before new ring buffers for the endpoints are allocated. Otherwise host driver will attempt to find and remove old stale URBs from a freshly allocated new ringbuffer. Cc: stable <stable@kernel.org> Fixes: 4fe0387afa89 ("USB: don't send Set-Interface after reset") Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Link: https://lore.kernel.org/r/20250514132520.225345-1-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/hub.c16
1 files changed, 14 insertions, 2 deletions
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 4ff49d0ff4dd..f0739bc9e25a 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -6040,6 +6040,7 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
struct usb_hub *parent_hub;
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
struct usb_device_descriptor descriptor;
+ struct usb_interface *intf;
struct usb_host_bos *bos;
int i, j, ret = 0;
int port1 = udev->portnum;
@@ -6103,6 +6104,18 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
if (!udev->actconfig)
goto done;
+ /*
+ * Some devices can't handle setting default altsetting 0 with a
+ * Set-Interface request. Disable host-side endpoints of those
+ * interfaces here. Enable and reset them back after host has set
+ * its internal endpoint structures during usb_hcd_alloc_bandwith()
+ */
+ for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+ intf = udev->actconfig->interface[i];
+ if (intf->cur_altsetting->desc.bAlternateSetting == 0)
+ usb_disable_interface(udev, intf, true);
+ }
+
mutex_lock(hcd->bandwidth_mutex);
ret = usb_hcd_alloc_bandwidth(udev, udev->actconfig, NULL, NULL);
if (ret < 0) {
@@ -6134,12 +6147,11 @@ static int usb_reset_and_verify_device(struct usb_device *udev)
*/
for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
struct usb_host_config *config = udev->actconfig;
- struct usb_interface *intf = config->interface[i];
struct usb_interface_descriptor *desc;
+ intf = config->interface[i];
desc = &intf->cur_altsetting->desc;
if (desc->bAlternateSetting == 0) {
- usb_disable_interface(udev, intf, true);
usb_enable_interface(udev, intf, true);
ret = 0;
} else {