Skip to content

Commit

Permalink
Merge tag 'usb-6.14-rc3' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/gregkh/usb

Pull USB fixes from Greg KH:
 "Here are some small USB driver fixes, and new device ids, for
  6.14-rc3. Lots of tiny stuff for reported problems, including:

   - new device ids and quirks

   - usb hub crash fix found by syzbot

   - dwc2 driver fix

   - dwc3 driver fixes

   - uvc gadget driver fix

   - cdc-acm driver fixes for a variety of different issues

   - other tiny bugfixes

  Almost all of these have been in linux-next this week, and all have
  passed 0-day testing"

* tag 'usb-6.14-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (25 commits)
  usb: typec: tcpm: PSSourceOffTimer timeout in PR_Swap enters ERROR_RECOVERY
  usb: roles: set switch registered flag early on
  usb: gadget: uvc: Fix unstarted kthread worker
  USB: quirks: add USB_QUIRK_NO_LPM quirk for Teclast dist
  usb: gadget: core: flush gadget workqueue after device removal
  USB: gadget: f_midi: f_midi_complete to call queue_work
  usb: core: fix pipe creation for get_bMaxPacketSize0
  usb: dwc3: Fix timeout issue during controller enter/exit from halt state
  USB: Add USB_QUIRK_NO_LPM quirk for sony xperia xz1 smartphone
  USB: cdc-acm: Fill in Renesas R-Car D3 USB Download mode quirk
  usb: cdc-acm: Fix handling of oversized fragments
  usb: cdc-acm: Check control transfer buffer size before access
  usb: xhci: Restore xhci_pci support for Renesas HCs
  USB: pci-quirks: Fix HCCPARAMS register error for LS7A EHCI
  USB: serial: option: drop MeiG Smart defines
  USB: serial: option: fix Telit Cinterion FN990A name
  USB: serial: option: add Telit Cinterion FN990B compositions
  USB: serial: option: add MeiG Smart SLM828
  usb: gadget: f_midi: fix MIDI Streaming descriptor lengths
  usb: dwc2: gadget: remove of_node reference upon udc_stop
  ...
  • Loading branch information
torvalds committed Feb 16, 2025
2 parents ba643b6 + 659f5d5 commit 6bfcc5f
Show file tree
Hide file tree
Showing 16 changed files with 139 additions and 45 deletions.
28 changes: 21 additions & 7 deletions drivers/usb/class/cdc-acm.c
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
static void acm_ctrl_irq(struct urb *urb)
{
struct acm *acm = urb->context;
struct usb_cdc_notification *dr = urb->transfer_buffer;
struct usb_cdc_notification *dr;
unsigned int current_size = urb->actual_length;
unsigned int expected_size, copy_size, alloc_size;
int retval;
Expand All @@ -398,14 +398,25 @@ static void acm_ctrl_irq(struct urb *urb)

usb_mark_last_busy(acm->dev);

if (acm->nb_index)
if (acm->nb_index == 0) {
/*
* The first chunk of a message must contain at least the
* notification header with the length field, otherwise we
* can't get an expected_size.
*/
if (current_size < sizeof(struct usb_cdc_notification)) {
dev_dbg(&acm->control->dev, "urb too short\n");
goto exit;
}
dr = urb->transfer_buffer;
} else {
dr = (struct usb_cdc_notification *)acm->notification_buffer;

}
/* size = notification-header + (optional) data */
expected_size = sizeof(struct usb_cdc_notification) +
le16_to_cpu(dr->wLength);

if (current_size < expected_size) {
if (acm->nb_index != 0 || current_size < expected_size) {
/* notification is transmitted fragmented, reassemble */
if (acm->nb_size < expected_size) {
u8 *new_buffer;
Expand Down Expand Up @@ -1727,13 +1738,16 @@ static const struct usb_device_id acm_ids[] = {
{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
},
{ USB_DEVICE(0x045b, 0x023c), /* Renesas USB Download mode */
{ USB_DEVICE(0x045b, 0x023c), /* Renesas R-Car H3 USB Download mode */
.driver_info = DISABLE_ECHO, /* Don't echo banner */
},
{ USB_DEVICE(0x045b, 0x0247), /* Renesas R-Car D3 USB Download mode */
.driver_info = DISABLE_ECHO, /* Don't echo banner */
},
{ USB_DEVICE(0x045b, 0x0248), /* Renesas USB Download mode */
{ USB_DEVICE(0x045b, 0x0248), /* Renesas R-Car M3-N USB Download mode */
.driver_info = DISABLE_ECHO, /* Don't echo banner */
},
{ USB_DEVICE(0x045b, 0x024D), /* Renesas USB Download mode */
{ USB_DEVICE(0x045b, 0x024D), /* Renesas R-Car E3 USB Download mode */
.driver_info = DISABLE_ECHO, /* Don't echo banner */
},
{ USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; [email protected] */
Expand Down
14 changes: 12 additions & 2 deletions drivers/usb/core/hub.c
Original file line number Diff line number Diff line change
Expand Up @@ -1848,6 +1848,17 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
desc = intf->cur_altsetting;
hdev = interface_to_usbdev(intf);

/*
* The USB 2.0 spec prohibits hubs from having more than one
* configuration or interface, and we rely on this prohibition.
* Refuse to accept a device that violates it.
*/
if (hdev->descriptor.bNumConfigurations > 1 ||
hdev->actconfig->desc.bNumInterfaces > 1) {
dev_err(&intf->dev, "Invalid hub with more than one config or interface\n");
return -EINVAL;
}

/*
* Set default autosuspend delay as 0 to speedup bus suspend,
* based on the below considerations:
Expand Down Expand Up @@ -4698,7 +4709,6 @@ void usb_ep0_reinit(struct usb_device *udev)
EXPORT_SYMBOL_GPL(usb_ep0_reinit);

#define usb_sndaddr0pipe() (PIPE_CONTROL << 30)
#define usb_rcvaddr0pipe() ((PIPE_CONTROL << 30) | USB_DIR_IN)

static int hub_set_address(struct usb_device *udev, int devnum)
{
Expand Down Expand Up @@ -4804,7 +4814,7 @@ static int get_bMaxPacketSize0(struct usb_device *udev,
for (i = 0; i < GET_MAXPACKET0_TRIES; ++i) {
/* Start with invalid values in case the transfer fails */
buf->bDescriptorType = buf->bMaxPacketSize0 = 0;
rc = usb_control_msg(udev, usb_rcvaddr0pipe(),
rc = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
USB_DT_DEVICE << 8, 0,
buf, size,
Expand Down
6 changes: 6 additions & 0 deletions drivers/usb/core/quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -435,6 +435,9 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x0c45, 0x7056), .driver_info =
USB_QUIRK_IGNORE_REMOTE_WAKEUP },

/* Sony Xperia XZ1 Compact (lilac) smartphone in fastboot mode */
{ USB_DEVICE(0x0fce, 0x0dde), .driver_info = USB_QUIRK_NO_LPM },

/* Action Semiconductor flash disk */
{ USB_DEVICE(0x10d6, 0x2200), .driver_info =
USB_QUIRK_STRING_FETCH_255 },
Expand Down Expand Up @@ -525,6 +528,9 @@ static const struct usb_device_id usb_quirk_list[] = {
/* Blackmagic Design UltraStudio SDI */
{ USB_DEVICE(0x1edb, 0xbd4f), .driver_info = USB_QUIRK_NO_LPM },

/* Teclast disk */
{ USB_DEVICE(0x1f75, 0x0917), .driver_info = USB_QUIRK_NO_LPM },

/* Hauppauge HVR-950q */
{ USB_DEVICE(0x2040, 0x7200), .driver_info =
USB_QUIRK_CONFIG_INTF_STRINGS },
Expand Down
1 change: 1 addition & 0 deletions drivers/usb/dwc2/gadget.c
Original file line number Diff line number Diff line change
Expand Up @@ -4615,6 +4615,7 @@ static int dwc2_hsotg_udc_stop(struct usb_gadget *gadget)
spin_lock_irqsave(&hsotg->lock, flags);

hsotg->driver = NULL;
hsotg->gadget.dev.of_node = NULL;
hsotg->gadget.speed = USB_SPEED_UNKNOWN;
hsotg->enabled = 0;

Expand Down
1 change: 1 addition & 0 deletions drivers/usb/dwc3/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,7 @@ struct dwc3_event_buffer {
/**
* struct dwc3_ep - device side endpoint representation
* @endpoint: usb endpoint
* @nostream_work: work for handling bulk NoStream
* @cancelled_list: list of cancelled requests for this endpoint
* @pending_list: list of pending requests for this endpoint
* @started_list: list of started requests on this endpoint
Expand Down
34 changes: 34 additions & 0 deletions drivers/usb/dwc3/gadget.c
Original file line number Diff line number Diff line change
Expand Up @@ -2629,10 +2629,38 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
{
u32 reg;
u32 timeout = 2000;
u32 saved_config = 0;

if (pm_runtime_suspended(dwc->dev))
return 0;

/*
* When operating in USB 2.0 speeds (HS/FS), ensure that
* GUSB2PHYCFG.ENBLSLPM and GUSB2PHYCFG.SUSPHY are cleared before starting
* or stopping the controller. This resolves timeout issues that occur
* during frequent role switches between host and device modes.
*
* Save and clear these settings, then restore them after completing the
* controller start or stop sequence.
*
* This solution was discovered through experimentation as it is not
* mentioned in the dwc3 programming guide. It has been tested on an
* Exynos platforms.
*/
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
if (reg & DWC3_GUSB2PHYCFG_SUSPHY) {
saved_config |= DWC3_GUSB2PHYCFG_SUSPHY;
reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
}

if (reg & DWC3_GUSB2PHYCFG_ENBLSLPM) {
saved_config |= DWC3_GUSB2PHYCFG_ENBLSLPM;
reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
}

if (saved_config)
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);

reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (is_on) {
if (DWC3_VER_IS_WITHIN(DWC3, ANY, 187A)) {
Expand Down Expand Up @@ -2660,6 +2688,12 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
reg &= DWC3_DSTS_DEVCTRLHLT;
} while (--timeout && !(!is_on ^ !reg));

if (saved_config) {
reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
reg |= saved_config;
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
}

if (!timeout)
return -ETIMEDOUT;

Expand Down
19 changes: 14 additions & 5 deletions drivers/usb/gadget/function/f_midi.c
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ f_midi_complete(struct usb_ep *ep, struct usb_request *req)
/* Our transmit completed. See if there's more to go.
* f_midi_transmit eats req, don't queue it again. */
req->length = 0;
f_midi_transmit(midi);
queue_work(system_highpri_wq, &midi->work);
return;
}
break;
Expand Down Expand Up @@ -907,6 +907,15 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)

status = -ENODEV;

/*
* Reset wMaxPacketSize with maximum packet size of FS bulk transfer before
* endpoint claim. This ensures that the wMaxPacketSize does not exceed the
* limit during bind retries where configured dwc3 TX/RX FIFO's maxpacket
* size of 512 bytes for IN/OUT endpoints in support HS speed only.
*/
bulk_in_desc.wMaxPacketSize = cpu_to_le16(64);
bulk_out_desc.wMaxPacketSize = cpu_to_le16(64);

/* allocate instance-specific endpoints */
midi->in_ep = usb_ep_autoconfig(cdev->gadget, &bulk_in_desc);
if (!midi->in_ep)
Expand Down Expand Up @@ -1000,11 +1009,11 @@ static int f_midi_bind(struct usb_configuration *c, struct usb_function *f)
}

/* configure the endpoint descriptors ... */
ms_out_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->in_ports);
ms_out_desc.bNumEmbMIDIJack = midi->in_ports;
ms_out_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->out_ports);
ms_out_desc.bNumEmbMIDIJack = midi->out_ports;

ms_in_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->out_ports);
ms_in_desc.bNumEmbMIDIJack = midi->out_ports;
ms_in_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->in_ports);
ms_in_desc.bNumEmbMIDIJack = midi->in_ports;

/* ... and add them to the list */
endpoint_descriptor_index = i;
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/gadget/function/uvc_video.c
Original file line number Diff line number Diff line change
Expand Up @@ -818,7 +818,7 @@ int uvcg_video_init(struct uvc_video *video, struct uvc_device *uvc)
return -EINVAL;

/* Allocate a kthread for asynchronous hw submit handler. */
video->kworker = kthread_create_worker(0, "UVCG");
video->kworker = kthread_run_worker(0, "UVCG");
if (IS_ERR(video->kworker)) {
uvcg_err(&video->uvc->func, "failed to create UVCG kworker\n");
return PTR_ERR(video->kworker);
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/gadget/udc/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1543,8 +1543,8 @@ void usb_del_gadget(struct usb_gadget *gadget)

kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
sysfs_remove_link(&udc->dev.kobj, "gadget");
flush_work(&gadget->work);
device_del(&gadget->dev);
flush_work(&gadget->work);
ida_free(&gadget_id_numbers, gadget->id_number);
cancel_work_sync(&udc->vbus_work);
device_unregister(&udc->dev);
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/gadget/udc/renesas_usb3.c
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ struct renesas_usb3_request {
struct list_head queue;
};

#define USB3_EP_NAME_SIZE 8
#define USB3_EP_NAME_SIZE 16
struct renesas_usb3_ep {
struct usb_ep ep;
struct renesas_usb3 *usb3;
Expand Down
9 changes: 9 additions & 0 deletions drivers/usb/host/pci-quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -958,6 +958,15 @@ static void quirk_usb_disable_ehci(struct pci_dev *pdev)
* booting from USB disk or using a usb keyboard
*/
hcc_params = readl(base + EHCI_HCC_PARAMS);

/* LS7A EHCI controller doesn't have extended capabilities, the
* EECP (EHCI Extended Capabilities Pointer) field of HCCPARAMS
* register should be 0x0 but it reads as 0xa0. So clear it to
* avoid error messages on boot.
*/
if (pdev->vendor == PCI_VENDOR_ID_LOONGSON && pdev->device == 0x7a14)
hcc_params &= ~(0xffL << 8);

offset = (hcc_params >> 8) & 0xff;
while (offset && --count) {
pci_read_config_dword(pdev, offset, &cap);
Expand Down
7 changes: 4 additions & 3 deletions drivers/usb/host/xhci-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -653,16 +653,17 @@ int xhci_pci_common_probe(struct pci_dev *dev, const struct pci_device_id *id)
}
EXPORT_SYMBOL_NS_GPL(xhci_pci_common_probe, "xhci");

static const struct pci_device_id pci_ids_reject[] = {
/* handled by xhci-pci-renesas */
/* handled by xhci-pci-renesas if enabled */
static const struct pci_device_id pci_ids_renesas[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0014) },
{ PCI_DEVICE(PCI_VENDOR_ID_RENESAS, 0x0015) },
{ /* end: all zeroes */ }
};

static int xhci_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
if (pci_match_id(pci_ids_reject, dev))
if (IS_ENABLED(CONFIG_USB_XHCI_PCI_RENESAS) &&
pci_match_id(pci_ids_renesas, dev))
return -ENODEV;

return xhci_pci_common_probe(dev, id);
Expand Down
2 changes: 1 addition & 1 deletion drivers/usb/phy/phy-generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop)
if (of_property_read_u32(node, "clock-frequency", &clk_rate))
clk_rate = 0;

needs_clk = of_property_read_bool(node, "clocks");
needs_clk = of_property_present(node, "clocks");
}
nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset",
GPIOD_ASIS);
Expand Down
5 changes: 3 additions & 2 deletions drivers/usb/roles/class.c
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,11 @@ usb_role_switch_register(struct device *parent,
dev_set_name(&sw->dev, "%s-role-switch",
desc->name ? desc->name : dev_name(parent));

sw->registered = true;

ret = device_register(&sw->dev);
if (ret) {
sw->registered = false;
put_device(&sw->dev);
return ERR_PTR(ret);
}
Expand All @@ -399,8 +402,6 @@ usb_role_switch_register(struct device *parent,
dev_warn(&sw->dev, "failed to add component\n");
}

sw->registered = true;

/* TODO: Symlinks for the host port and the device controller. */

return sw;
Expand Down
Loading

0 comments on commit 6bfcc5f

Please sign in to comment.