Commit de879a8d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull USB fixes from Greg KH:
 "Here are a few small USB driver fixes for 5.12-rc6 to resolve reported
  problems.

  They include:

   - a number of cdc-acm fixes for reported problems. It seems more
     people are using this driver lately...

   - dwc3 driver fixes for reported problems, and fixes for the fixes :)

   - dwc2 driver fixes for reported issues.

   - musb driver fix.

   - new USB quirk additions.

  All of these have been in linux-next for a while with no reported
  issues"

* tag 'usb-5.12-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (23 commits)
  usb: dwc2: Prevent core suspend when port connection flag is 0
  usb: dwc2: Fix HPRT0.PrtSusp bit setting for HiKey 960 board.
  usb: musb: Fix suspend with devices connected for a64
  usb: xhci-mtk: fix broken streams issue on 0.96 xHCI
  usb: dwc3: gadget: Clear DEP flags after stop transfers in ep disable
  usbip: vhci_hcd fix shift out-of-bounds in vhci_hub_control()
  USB: quirks: ignore remote wake-up on Fibocom L850-GL LTE modem
  USB: cdc-acm: do not log successful probe on later errors
  USB: cdc-acm: always claim data interface
  USB: cdc-acm: use negation for NULL checks
  USB: cdc-acm: clean up probe error labels
  USB: cdc-acm: drop redundant driver-data reset
  USB: cdc-acm: drop redundant driver-data assignment
  USB: cdc-acm: fix use-after-free after probe failure
  USB: cdc-acm: fix double free on probe failure
  USB: cdc-acm: downgrade message to debug
  USB: cdc-acm: untangle a circular dependency between callback and softint
  cdc-acm: fix BREAK rx code path adding necessary calls
  usb: gadget: udc: amd5536udc_pci fix null-ptr-dereference
  usb: dwc3: pci: Enable dis_uX_susphy_quirk for Intel Merrifield
  ...
parents 57fbdb15 93f67280
Loading
Loading
Loading
Loading
+70 −50
Original line number Diff line number Diff line
@@ -147,17 +147,29 @@ static inline int acm_set_control(struct acm *acm, int control)
#define acm_send_break(acm, ms) \
	acm_ctrl_msg(acm, USB_CDC_REQ_SEND_BREAK, ms, NULL, 0)

static void acm_kill_urbs(struct acm *acm)
static void acm_poison_urbs(struct acm *acm)
{
	int i;

	usb_kill_urb(acm->ctrlurb);
	usb_poison_urb(acm->ctrlurb);
	for (i = 0; i < ACM_NW; i++)
		usb_kill_urb(acm->wb[i].urb);
		usb_poison_urb(acm->wb[i].urb);
	for (i = 0; i < acm->rx_buflimit; i++)
		usb_kill_urb(acm->read_urbs[i]);
		usb_poison_urb(acm->read_urbs[i]);
}

static void acm_unpoison_urbs(struct acm *acm)
{
	int i;

	for (i = 0; i < acm->rx_buflimit; i++)
		usb_unpoison_urb(acm->read_urbs[i]);
	for (i = 0; i < ACM_NW; i++)
		usb_unpoison_urb(acm->wb[i].urb);
	usb_unpoison_urb(acm->ctrlurb);
}


/*
 * Write buffer management.
 * All of these assume proper locks taken by the caller.
@@ -226,6 +238,7 @@ static int acm_start_wb(struct acm *acm, struct acm_wb *wb)

	rc = usb_submit_urb(wb->urb, GFP_ATOMIC);
	if (rc < 0) {
		if (rc != -EPERM)
			dev_err(&acm->data->dev,
				"%s - usb_submit_urb(write bulk) failed: %d\n",
				__func__, rc);
@@ -313,8 +326,10 @@ static void acm_process_notification(struct acm *acm, unsigned char *buf)
			acm->iocount.dsr++;
		if (difference & ACM_CTRL_DCD)
			acm->iocount.dcd++;
		if (newctrl & ACM_CTRL_BRK)
		if (newctrl & ACM_CTRL_BRK) {
			acm->iocount.brk++;
			tty_insert_flip_char(&acm->port, 0, TTY_BREAK);
		}
		if (newctrl & ACM_CTRL_RI)
			acm->iocount.rng++;
		if (newctrl & ACM_CTRL_FRAMING)
@@ -480,11 +495,6 @@ static void acm_read_bulk_callback(struct urb *urb)
	dev_vdbg(&acm->data->dev, "got urb %d, len %d, status %d\n",
		rb->index, urb->actual_length, status);

	if (!acm->dev) {
		dev_dbg(&acm->data->dev, "%s - disconnected\n", __func__);
		return;
	}

	switch (status) {
	case 0:
		usb_mark_last_busy(acm->dev);
@@ -649,7 +659,8 @@ static void acm_port_dtr_rts(struct tty_port *port, int raise)

	res = acm_set_control(acm, val);
	if (res && (acm->ctrl_caps & USB_CDC_CAP_LINE))
		dev_err(&acm->control->dev, "failed to set dtr/rts\n");
		/* This is broken in too many devices to spam the logs */
		dev_dbg(&acm->control->dev, "failed to set dtr/rts\n");
}

static int acm_port_activate(struct tty_port *port, struct tty_struct *tty)
@@ -731,6 +742,7 @@ static void acm_port_shutdown(struct tty_port *port)
	 * Need to grab write_lock to prevent race with resume, but no need to
	 * hold it due to the tty-port initialised flag.
	 */
	acm_poison_urbs(acm);
	spin_lock_irq(&acm->write_lock);
	spin_unlock_irq(&acm->write_lock);

@@ -747,7 +759,8 @@ static void acm_port_shutdown(struct tty_port *port)
		usb_autopm_put_interface_async(acm->control);
	}

	acm_kill_urbs(acm);
	acm_unpoison_urbs(acm);

}

static void acm_tty_cleanup(struct tty_struct *tty)
@@ -1296,13 +1309,6 @@ static int acm_probe(struct usb_interface *intf,
	if (!combined_interfaces && intf != control_interface)
		return -ENODEV;

	if (!combined_interfaces && usb_interface_claimed(data_interface)) {
		/* valid in this context */
		dev_dbg(&intf->dev, "The data interface isn't available\n");
		return -EBUSY;
	}


	if (data_interface->cur_altsetting->desc.bNumEndpoints < 2 ||
	    control_interface->cur_altsetting->desc.bNumEndpoints == 0)
		return -EINVAL;
@@ -1323,8 +1329,8 @@ static int acm_probe(struct usb_interface *intf,
	dev_dbg(&intf->dev, "interfaces are valid\n");

	acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
	if (acm == NULL)
		goto alloc_fail;
	if (!acm)
		return -ENOMEM;

	tty_port_init(&acm->port);
	acm->port.ops = &acm_port_ops;
@@ -1341,7 +1347,7 @@ static int acm_probe(struct usb_interface *intf,

	minor = acm_alloc_minor(acm);
	if (minor < 0)
		goto alloc_fail1;
		goto err_put_port;

	acm->minor = minor;
	acm->dev = usb_dev;
@@ -1372,15 +1378,15 @@ static int acm_probe(struct usb_interface *intf,

	buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
	if (!buf)
		goto alloc_fail1;
		goto err_put_port;
	acm->ctrl_buffer = buf;

	if (acm_write_buffers_alloc(acm) < 0)
		goto alloc_fail2;
		goto err_free_ctrl_buffer;

	acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
	if (!acm->ctrlurb)
		goto alloc_fail3;
		goto err_free_write_buffers;

	for (i = 0; i < num_rx_buf; i++) {
		struct acm_rb *rb = &(acm->read_buffers[i]);
@@ -1389,13 +1395,13 @@ static int acm_probe(struct usb_interface *intf,
		rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
								&rb->dma);
		if (!rb->base)
			goto alloc_fail4;
			goto err_free_read_urbs;
		rb->index = i;
		rb->instance = acm;

		urb = usb_alloc_urb(0, GFP_KERNEL);
		if (!urb)
			goto alloc_fail4;
			goto err_free_read_urbs;

		urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
		urb->transfer_dma = rb->dma;
@@ -1416,8 +1422,8 @@ static int acm_probe(struct usb_interface *intf,
		struct acm_wb *snd = &(acm->wb[i]);

		snd->urb = usb_alloc_urb(0, GFP_KERNEL);
		if (snd->urb == NULL)
			goto alloc_fail5;
		if (!snd->urb)
			goto err_free_write_urbs;

		if (usb_endpoint_xfer_int(epwrite))
			usb_fill_int_urb(snd->urb, usb_dev, acm->out,
@@ -1435,7 +1441,7 @@ static int acm_probe(struct usb_interface *intf,

	i = device_create_file(&intf->dev, &dev_attr_bmCapabilities);
	if (i < 0)
		goto alloc_fail5;
		goto err_free_write_urbs;

	if (h.usb_cdc_country_functional_desc) { /* export the country data */
		struct usb_cdc_country_functional_desc * cfd =
@@ -1480,20 +1486,21 @@ static int acm_probe(struct usb_interface *intf,
	acm->nb_index = 0;
	acm->nb_size = 0;

	dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);

	acm->line.dwDTERate = cpu_to_le32(9600);
	acm->line.bDataBits = 8;
	acm_set_line(acm, &acm->line);

	usb_driver_claim_interface(&acm_driver, data_interface, acm);
	usb_set_intfdata(data_interface, acm);
	if (!acm->combined_interfaces) {
		rv = usb_driver_claim_interface(&acm_driver, data_interface, acm);
		if (rv)
			goto err_remove_files;
	}

	tty_dev = tty_port_register_device(&acm->port, acm_tty_driver, minor,
			&control_interface->dev);
	if (IS_ERR(tty_dev)) {
		rv = PTR_ERR(tty_dev);
		goto alloc_fail6;
		goto err_release_data_interface;
	}

	if (quirks & CLEAR_HALT_CONDITIONS) {
@@ -1501,32 +1508,39 @@ static int acm_probe(struct usb_interface *intf,
		usb_clear_halt(usb_dev, acm->out);
	}

	dev_info(&intf->dev, "ttyACM%d: USB ACM device\n", minor);

	return 0;
alloc_fail6:

err_release_data_interface:
	if (!acm->combined_interfaces) {
		/* Clear driver data so that disconnect() returns early. */
		usb_set_intfdata(data_interface, NULL);
		usb_driver_release_interface(&acm_driver, data_interface);
	}
err_remove_files:
	if (acm->country_codes) {
		device_remove_file(&acm->control->dev,
				&dev_attr_wCountryCodes);
		device_remove_file(&acm->control->dev,
				&dev_attr_iCountryCodeRelDate);
		kfree(acm->country_codes);
	}
	device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
alloc_fail5:
	usb_set_intfdata(intf, NULL);
err_free_write_urbs:
	for (i = 0; i < ACM_NW; i++)
		usb_free_urb(acm->wb[i].urb);
alloc_fail4:
err_free_read_urbs:
	for (i = 0; i < num_rx_buf; i++)
		usb_free_urb(acm->read_urbs[i]);
	acm_read_buffers_free(acm);
	usb_free_urb(acm->ctrlurb);
alloc_fail3:
err_free_write_buffers:
	acm_write_buffers_free(acm);
alloc_fail2:
err_free_ctrl_buffer:
	usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
alloc_fail1:
err_put_port:
	tty_port_put(&acm->port);
alloc_fail:

	return rv;
}

@@ -1540,8 +1554,14 @@ static void acm_disconnect(struct usb_interface *intf)
	if (!acm)
		return;

	mutex_lock(&acm->mutex);
	acm->disconnected = true;
	/*
	 * there is a circular dependency. acm_softint() can resubmit
	 * the URBs in error handling so we need to block any
	 * submission right away
	 */
	acm_poison_urbs(acm);
	mutex_lock(&acm->mutex);
	if (acm->country_codes) {
		device_remove_file(&acm->control->dev,
				&dev_attr_wCountryCodes);
@@ -1560,7 +1580,6 @@ static void acm_disconnect(struct usb_interface *intf)
		tty_kref_put(tty);
	}

	acm_kill_urbs(acm);
	cancel_delayed_work_sync(&acm->dwork);

	tty_unregister_device(acm_tty_driver, acm->minor);
@@ -1602,7 +1621,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
	if (cnt)
		return 0;

	acm_kill_urbs(acm);
	acm_poison_urbs(acm);
	cancel_delayed_work_sync(&acm->dwork);
	acm->urbs_in_error_delay = 0;

@@ -1615,6 +1634,7 @@ static int acm_resume(struct usb_interface *intf)
	struct urb *urb;
	int rv = 0;

	acm_unpoison_urbs(acm);
	spin_lock_irq(&acm->write_lock);

	if (--acm->susp_count)
+4 −0
Original line number Diff line number Diff line
@@ -498,6 +498,10 @@ static const struct usb_device_id usb_quirk_list[] = {
	/* DJI CineSSD */
	{ USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM },

	/* Fibocom L850-GL LTE Modem */
	{ USB_DEVICE(0x2cb7, 0x0007), .driver_info =
			USB_QUIRK_IGNORE_REMOTE_WAKEUP },

	/* INTEL VALUE SSD */
	{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },

+3 −2
Original line number Diff line number Diff line
@@ -4322,7 +4322,8 @@ static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
	if (hsotg->op_state == OTG_STATE_B_PERIPHERAL)
		goto unlock;

	if (hsotg->params.power_down > DWC2_POWER_DOWN_PARAM_PARTIAL)
	if (hsotg->params.power_down != DWC2_POWER_DOWN_PARAM_PARTIAL ||
	    hsotg->flags.b.port_connect_status == 0)
		goto skip_power_saving;

	/*
@@ -5398,7 +5399,7 @@ int dwc2_host_enter_hibernation(struct dwc2_hsotg *hsotg)
	dwc2_writel(hsotg, hprt0, HPRT0);

	/* Wait for the HPRT0.PrtSusp register field to be set */
	if (dwc2_hsotg_wait_bit_set(hsotg, HPRT0, HPRT0_SUSP, 3000))
	if (dwc2_hsotg_wait_bit_set(hsotg, HPRT0, HPRT0_SUSP, 5000))
		dev_warn(hsotg->dev, "Suspend wasn't generated\n");

	/*
+2 −0
Original line number Diff line number Diff line
@@ -120,6 +120,8 @@ static const struct property_entry dwc3_pci_intel_properties[] = {
static const struct property_entry dwc3_pci_mrfld_properties[] = {
	PROPERTY_ENTRY_STRING("dr_mode", "otg"),
	PROPERTY_ENTRY_STRING("linux,extcon-name", "mrfld_bcove_pwrsrc"),
	PROPERTY_ENTRY_BOOL("snps,dis_u3_susphy_quirk"),
	PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"),
	PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"),
	{}
};
+3 −0
Original line number Diff line number Diff line
@@ -244,6 +244,9 @@ static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
	struct device *dev = qcom->dev;
	int ret;

	if (has_acpi_companion(dev))
		return 0;

	qcom->icc_path_ddr = of_icc_get(dev, "usb-ddr");
	if (IS_ERR(qcom->icc_path_ddr)) {
		dev_err(dev, "failed to get usb-ddr path: %ld\n",
Loading