diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-08 16:33:04 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-08-08 16:33:04 -0700 |
| commit | 91a73db6970aa7cd3d2ea73a4a11eeb3519737db (patch) | |
| tree | 1be7599fde2c72a77b5b378a3dfda6dad639b763 | |
| parent | e4836b67bad62f10e142f8dd71e67473778de518 (diff) | |
| parent | 3d26cd1f3ff25cebd10d4b0e8188cf40dade28e9 (diff) | |
Merge tag 'usb-7.2-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB / Thunderbolt fixes from Greg KH:
"Here are some small USB and Thunderbolt driver fixes for 7.2-rc7 that
resolve some reported issues. Included in here are:
- new quirk for some broken USB devices
- thunderbolt device fixes for reported issues
- usb gadget driver fix
- usb atm driver fix
- xhci driver fixes.
- other minor USB driver fixes
All of these have been in linux-next this week with no reported
issues"
* tag 'usb-7.2-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb:
usb: xhci: use BIT_ULL for CRCR bits to fix incorrect 64bit mask
usb: quirks: Add ShanWan gamepad to quirk list
usb: hub: Split announce_device() to log device identity before enumeration
usb: core: Add quirk for 255-bytes initial config read
usb: atm: cxacru: properly kill rcv_urb on error in cxacru_cm()
usb: misc: usbio: check ibuf_len against rxbuf_len in bulk msg
usb: gadget: f_ncm: Use unsigned int for ndp_index
usb: cdnsp: fix incorrect endian conversions for APB timeout register
thunderbolt: Initialize ->domain_released completion before it is being used
thunderbolt: icm: Preserve USB4 proxy data-valid bit
thunderbolt: Bound the DROM dual link port number before indexing sw->ports
thunderbolt: Fix bandwidth group reservation indexing
thunderbolt: stream: Unmap buffers with mapped size
| -rw-r--r-- | Documentation/admin-guide/kernel-parameters.txt | 5 | ||||
| -rw-r--r-- | drivers/thunderbolt/eeprom.c | 9 | ||||
| -rw-r--r-- | drivers/thunderbolt/icm.c | 2 | ||||
| -rw-r--r-- | drivers/thunderbolt/nhi.c | 4 | ||||
| -rw-r--r-- | drivers/thunderbolt/stream.c | 2 | ||||
| -rw-r--r-- | drivers/thunderbolt/tb.c | 2 | ||||
| -rw-r--r-- | drivers/usb/atm/cxacru.c | 2 | ||||
| -rw-r--r-- | drivers/usb/cdns3/cdnsp-gadget.c | 4 | ||||
| -rw-r--r-- | drivers/usb/core/config.c | 32 | ||||
| -rw-r--r-- | drivers/usb/core/hub.c | 16 | ||||
| -rw-r--r-- | drivers/usb/core/quirks.c | 7 | ||||
| -rw-r--r-- | drivers/usb/gadget/function/f_ncm.c | 2 | ||||
| -rw-r--r-- | drivers/usb/host/xhci.h | 12 | ||||
| -rw-r--r-- | drivers/usb/misc/usbio.c | 2 | ||||
| -rw-r--r-- | include/linux/usb/quirks.h | 3 |
15 files changed, 76 insertions, 28 deletions
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index b5493a7f8f22..3d35270dddef 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -8169,6 +8169,11 @@ Kernel parameters q = USB_QUIRK_FORCE_ONE_CONFIG (Device claims zero configurations, forcing to 1); + r = USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE (Device + fails during initialization when asked for + 9-bytes configuration descriptor request. + Ask for 255-bytes request instead to mirror + Windows' behavior); Example: quirks=0781:5580:bk,0a5c:5834:gij usbhid.mousepoll= diff --git a/drivers/thunderbolt/eeprom.c b/drivers/thunderbolt/eeprom.c index 5681c17f82ec..2a13fa6888ba 100644 --- a/drivers/thunderbolt/eeprom.c +++ b/drivers/thunderbolt/eeprom.c @@ -394,9 +394,16 @@ static int tb_drom_parse_entry_port(struct tb_switch *sw, return -EIO; } port->link_nr = entry->link_nr; - if (entry->has_dual_link_port) + if (entry->has_dual_link_port) { + if (entry->dual_link_port_nr > sw->config.max_port_number) { + tb_sw_warn(sw, + "port entry has invalid dual link port number %u\n", + entry->dual_link_port_nr); + return -EIO; + } port->dual_link_port = &port->sw->ports[entry->dual_link_port_nr]; + } } return 0; } diff --git a/drivers/thunderbolt/icm.c b/drivers/thunderbolt/icm.c index 10fefac3b1d9..669807f0eaf8 100644 --- a/drivers/thunderbolt/icm.c +++ b/drivers/thunderbolt/icm.c @@ -2341,7 +2341,7 @@ static int icm_usb4_switch_op(struct tb_switch *sw, u16 opcode, u32 *metadata, if (tx_data_len) { request.data_len_valid |= ICM_USB4_SWITCH_DATA_VALID; if (tx_data_len < ARRAY_SIZE(request.data)) - request.data_len_valid = + request.data_len_valid |= tx_data_len & ICM_USB4_SWITCH_DATA_LEN_MASK; memcpy(request.data, tx_data, tx_data_len * sizeof(u32)); } diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c index 0f795ea58756..35e3c119d5ee 100644 --- a/drivers/thunderbolt/nhi.c +++ b/drivers/thunderbolt/nhi.c @@ -1226,6 +1226,8 @@ int nhi_probe(struct tb_nhi *nhi) return dev_err_probe(dev, res, "NHI specific init failed\n"); } + init_completion(&nhi->domain_released); + tb = nhi_select_cm(nhi); if (!tb) return dev_err_probe(dev, -ENODEV, @@ -1233,8 +1235,6 @@ int nhi_probe(struct tb_nhi *nhi) dev_dbg(dev, "NHI initialized, starting thunderbolt\n"); - init_completion(&nhi->domain_released); - res = tb_domain_add(tb, host_reset); if (res) { /* diff --git a/drivers/thunderbolt/stream.c b/drivers/thunderbolt/stream.c index c1f5c55583d0..4cc86d8d6491 100644 --- a/drivers/thunderbolt/stream.c +++ b/drivers/thunderbolt/stream.c @@ -257,7 +257,7 @@ static void tbstream_ring_free(struct tbstream_ring *ring) if (sf->frame.buffer_phy) dma_unmap_page(dma_dev, sf->frame.buffer_phy, - tb_ring_frame_size(&sf->frame), dir); + TB_MAX_FRAME_SIZE, dir); sf->frame.buffer_phy = 0; if (sf->page) __free_page(sf->page); diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c index 76323255439a..f43f2d952372 100644 --- a/drivers/thunderbolt/tb.c +++ b/drivers/thunderbolt/tb.c @@ -609,7 +609,7 @@ static int tb_consumed_dp_bandwidth(struct tb *tb, int *consumed_up, int *consumed_down) { - int group_reserved[MAX_GROUPS] = {}; + int group_reserved[MAX_GROUPS + 1] = {}; struct tb_cm *tcm = tb_priv(tb); struct tb_tunnel *tunnel; bool downstream; diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index f1900c567ba4..429ac20a8999 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -700,6 +700,8 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm, ret = offd; usb_dbg(instance->usbatm, "cm %#x\n", cm); fail: + if (ret < 0) + usb_kill_urb(instance->rcv_urb); mutex_unlock(&instance->cm_serialize); err: return ret; diff --git a/drivers/usb/cdns3/cdnsp-gadget.c b/drivers/usb/cdns3/cdnsp-gadget.c index a5275c2fb43b..7a516e509198 100644 --- a/drivers/usb/cdns3/cdnsp-gadget.c +++ b/drivers/usb/cdns3/cdnsp-gadget.c @@ -163,9 +163,9 @@ static void cdnsp_set_apb_timeout_value(struct cdnsp_device *pdev) offset = cdnsp_find_next_ext_cap(base, offset, D_XEC_PRE_REGS_CAP); reg = base + offset + REG_CHICKEN_BITS_3_OFFSET; - val = le32_to_cpu(readl(reg)); + val = readl(reg); val = CHICKEN_APB_TIMEOUT_SET(val, cdns->override_apb_timeout); - writel(cpu_to_le32(val), reg); + writel(val, reg); } static void cdnsp_set_chicken_bits_2(struct cdnsp_device *pdev, u32 bit) diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c index 45e20c6d76c0..346a2faa9bb8 100644 --- a/drivers/usb/core/config.c +++ b/drivers/usb/core/config.c @@ -912,6 +912,18 @@ int usb_get_configuration(struct usb_device *dev) unsigned char *bigbuffer; struct usb_config_descriptor *desc; int result; + size_t usb_config_req_size; + + /* + * We usually start by grabbing the first 9-bytes descriptor so we know + * how long the whole configuration is. Some devices with quirky + * firmware will fail enumeration, so if the quirk is set, use 255 instead, + * mirroring the behavior of Windows. + */ + if (dev->quirks & USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE) + usb_config_req_size = 255; + else + usb_config_req_size = USB_DT_CONFIG_SIZE; if (ncfg > USB_MAXCONFIG) { dev_notice(ddev, "too many configurations: %d, " @@ -938,15 +950,13 @@ int usb_get_configuration(struct usb_device *dev) if (!dev->rawdescriptors) return -ENOMEM; - desc = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL); + desc = kmalloc(usb_config_req_size, GFP_KERNEL); if (!desc) return -ENOMEM; for (cfgno = 0; cfgno < ncfg; cfgno++) { - /* We grab just the first descriptor so we know how long - * the whole configuration is */ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, - desc, USB_DT_CONFIG_SIZE); + desc, usb_config_req_size); if (result < 0) { dev_err(ddev, "unable to read config index %d " "descriptor/%s: %d\n", cfgno, "start", result); @@ -956,16 +966,14 @@ int usb_get_configuration(struct usb_device *dev) dev->descriptor.bNumConfigurations = cfgno; break; } else if (result < 4) { - dev_err(ddev, "config index %d descriptor too short " - "(expected %i, got %i)\n", cfgno, - USB_DT_CONFIG_SIZE, result); + dev_err(ddev, "config index %d descriptor too short (asked for %zu, got %i)\n", + cfgno, usb_config_req_size, result); result = -EINVAL; goto err; } length = max_t(int, le16_to_cpu(desc->wTotalLength), USB_DT_CONFIG_SIZE); - /* Now that we know the length, get the whole thing */ bigbuffer = kmalloc(length, GFP_KERNEL); if (!bigbuffer) { result = -ENOMEM; @@ -975,6 +983,13 @@ int usb_get_configuration(struct usb_device *dev) if (dev->quirks & USB_QUIRK_DELAY_INIT) msleep(200); + /* Skip the second read if we already got everything */ + if (result >= length) { + memcpy(bigbuffer, desc, length); + goto store_and_parse; + } + + /* Get the whole thing */ result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno, bigbuffer, length); if (result < 0) { @@ -989,6 +1004,7 @@ int usb_get_configuration(struct usb_device *dev) length = result; } +store_and_parse: dev->rawdescriptors[cfgno] = bigbuffer; result = usb_parse_configuration(dev, cfgno, diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 5262e11c12cd..d92bf887739d 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2401,7 +2401,7 @@ static void show_string(struct usb_device *udev, char *id, char *string) dev_info(&udev->dev, "%s: %s\n", id, string); } -static void announce_device(struct usb_device *udev) +static void announce_device_ids(struct usb_device *udev) { u16 bcdDevice = le16_to_cpu(udev->descriptor.bcdDevice); @@ -2410,6 +2410,10 @@ static void announce_device(struct usb_device *udev) le16_to_cpu(udev->descriptor.idVendor), le16_to_cpu(udev->descriptor.idProduct), bcdDevice >> 8, bcdDevice & 0xff); +} + +static void announce_device_strings(struct usb_device *udev) +{ dev_info(&udev->dev, "New USB device strings: Mfr=%d, Product=%d, SerialNumber=%d\n", udev->descriptor.iManufacturer, @@ -2420,7 +2424,8 @@ static void announce_device(struct usb_device *udev) show_string(udev, "SerialNumber", udev->serial); } #else -static inline void announce_device(struct usb_device *udev) { } +static inline void announce_device_ids(struct usb_device *udev) { } +static inline void announce_device_strings(struct usb_device *udev) { } #endif @@ -2651,6 +2656,9 @@ int usb_new_device(struct usb_device *udev) device_init_wakeup(&udev->dev, 0); } + /* Announce the device identity */ + announce_device_ids(udev); + /* Tell the runtime-PM framework the device is active */ pm_runtime_set_active(&udev->dev); pm_runtime_get_noresume(&udev->dev); @@ -2672,8 +2680,8 @@ int usb_new_device(struct usb_device *udev) udev->dev.devt = MKDEV(USB_DEVICE_MAJOR, (((udev->bus->busnum-1) * 128) + (udev->devnum-1))); - /* Tell the world! */ - announce_device(udev); + /* Announce the device's product, manufacturer and serial number */ + announce_device_strings(udev); if (udev->serial) add_device_randomness(udev->serial, strlen(udev->serial)); diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index 87ee2d938bc0..b5b577f0b931 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -142,6 +142,10 @@ static int quirks_param_set(const char *value, const struct kernel_param *kp) break; case 'q': flags |= USB_QUIRK_FORCE_ONE_CONFIG; + break; + case 'r': + flags |= USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE; + break; /* Ignore unrecognized flag characters */ } } @@ -589,6 +593,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x2386, 0x350e), .driver_info = USB_QUIRK_NO_LPM }, + /* ShanWan Wireless Gamepad */ + { USB_DEVICE(0x2563, 0x0575), .driver_info = USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE }, + /* UGREEN 35871 - BOS descriptor fetch hangs at SuperSpeed Plus */ { USB_DEVICE(0x2b89, 0x5871), .driver_info = USB_QUIRK_NO_BOS }, diff --git a/drivers/usb/gadget/function/f_ncm.c b/drivers/usb/gadget/function/f_ncm.c index 64eabda2f546..bf02545b37a2 100644 --- a/drivers/usb/gadget/function/f_ncm.c +++ b/drivers/usb/gadget/function/f_ncm.c @@ -1171,7 +1171,7 @@ static int ncm_unwrap_ntb(struct gether *port, unsigned char *ntb_ptr = skb->data; __le16 *tmp; unsigned index, index2; - int ndp_index; + unsigned int ndp_index; unsigned dg_len, dg_len2; unsigned ndp_len; unsigned block_len; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 2d3941b5e1e3..708e3ccc5d87 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -190,13 +190,13 @@ struct xhci_op_regs { /* CRCR - Command Ring Control Register - cmd_ring bitmasks */ /* bit 0 - Cycle bit indicates the ownership of the command ring */ -#define CMD_RING_CYCLE BIT(0) +#define CMD_RING_CYCLE BIT_ULL(0) /* stop ring operation after completion of the currently executing command */ -#define CMD_RING_PAUSE BIT(1) +#define CMD_RING_PAUSE BIT_ULL(1) /* stop ring immediately - abort the currently executing command */ -#define CMD_RING_ABORT BIT(2) +#define CMD_RING_ABORT BIT_ULL(2) /* true: command ring is running */ -#define CMD_RING_RUNNING BIT(3) +#define CMD_RING_RUNNING BIT_ULL(3) /* bits 63:6 - Command Ring pointer */ #define CMD_RING_PTR_MASK GENMASK_ULL(63, 6) @@ -271,7 +271,7 @@ struct xhci_intr_reg { * bit 3 - Event Handler Busy (EHB), whether the event ring is scheduled to be serviced by * a work queue (or delayed service routine)? */ -#define ERST_EHB BIT(3) +#define ERST_EHB BIT_ULL(3) /* bits 63:4 - Event Ring Dequeue Pointer */ #define ERST_PTR_MASK GENMASK_ULL(63, 4) @@ -502,7 +502,7 @@ struct xhci_ep_ctx { #define CTX_TO_MAX_ESIT_PAYLOAD(p) (((p) >> 16) & 0xffff) /* deq bitmasks */ -#define EP_CTX_CYCLE_MASK BIT(0) +#define EP_CTX_CYCLE_MASK BIT_ULL(0) /* bits 63:4 - TR Dequeue Pointer */ #define TR_DEQ_PTR_MASK GENMASK_ULL(63, 4) diff --git a/drivers/usb/misc/usbio.c b/drivers/usb/misc/usbio.c index 3c2474dca810..fe093e7760d5 100644 --- a/drivers/usb/misc/usbio.c +++ b/drivers/usb/misc/usbio.c @@ -265,7 +265,7 @@ int usbio_bulk_msg(struct auxiliary_device *adev, u8 type, u8 cmd, bool last, lockdep_assert_held(&usbio->bulk_mutex); if ((obuf_len > (usbio->txbuf_len - sizeof(*bpkt))) || - (ibuf_len > (usbio->txbuf_len - sizeof(*bpkt)))) + (ibuf_len > (usbio->rxbuf_len - sizeof(*bpkt)))) return -EMSGSIZE; if (ibuf_len) diff --git a/include/linux/usb/quirks.h b/include/linux/usb/quirks.h index b3cc7beab4a3..a4043b33c2c2 100644 --- a/include/linux/usb/quirks.h +++ b/include/linux/usb/quirks.h @@ -81,4 +81,7 @@ /* Device claims zero configurations, forcing to 1 */ #define USB_QUIRK_FORCE_ONE_CONFIG BIT(18) +/* Use a 255 bytes config descriptor request mirroring windows behavior */ +#define USB_QUIRK_WINDOWS_CONFIG_REQ_SIZE BIT(19) + #endif /* __LINUX_USB_QUIRKS_H */ |
