diff options
Diffstat (limited to 'drivers/usb/core')
| -rw-r--r-- | drivers/usb/core/devio.c | 46 | ||||
| -rw-r--r-- | drivers/usb/core/hcd-pci.c | 2 | ||||
| -rw-r--r-- | drivers/usb/core/hub.c | 21 | ||||
| -rw-r--r-- | drivers/usb/core/quirks.c | 6 | ||||
| -rw-r--r-- | drivers/usb/core/usb-acpi.c | 2 | ||||
| -rw-r--r-- | drivers/usb/core/usb.c | 8 |
6 files changed, 54 insertions, 31 deletions
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c index fa66e6e58792..b5b85bf80329 100644 --- a/drivers/usb/core/devio.c +++ b/drivers/usb/core/devio.c @@ -139,30 +139,42 @@ MODULE_PARM_DESC(usbfs_memory_mb, /* Hard limit, necessary to avoid arithmetic overflow */ #define USBFS_XFER_MAX (UINT_MAX / 2 - 1000000) -static atomic64_t usbfs_memory_usage; /* Total memory currently allocated */ +static DEFINE_SPINLOCK(usbfs_memory_usage_lock); +static u64 usbfs_memory_usage; /* Total memory currently allocated */ /* Check whether it's okay to allocate more memory for a transfer */ static int usbfs_increase_memory_usage(u64 amount) { - u64 lim; + u64 lim, total_mem; + unsigned long flags; + int ret; lim = READ_ONCE(usbfs_memory_mb); lim <<= 20; - atomic64_add(amount, &usbfs_memory_usage); - - if (lim > 0 && atomic64_read(&usbfs_memory_usage) > lim) { - atomic64_sub(amount, &usbfs_memory_usage); - return -ENOMEM; - } + ret = 0; + spin_lock_irqsave(&usbfs_memory_usage_lock, flags); + total_mem = usbfs_memory_usage + amount; + if (lim > 0 && total_mem > lim) + ret = -ENOMEM; + else + usbfs_memory_usage = total_mem; + spin_unlock_irqrestore(&usbfs_memory_usage_lock, flags); - return 0; + return ret; } /* Memory for a transfer is being deallocated */ static void usbfs_decrease_memory_usage(u64 amount) { - atomic64_sub(amount, &usbfs_memory_usage); + unsigned long flags; + + spin_lock_irqsave(&usbfs_memory_usage_lock, flags); + if (amount > usbfs_memory_usage) + usbfs_memory_usage = 0; + else + usbfs_memory_usage -= amount; + spin_unlock_irqrestore(&usbfs_memory_usage_lock, flags); } static int connected(struct usb_dev_state *ps) @@ -1197,12 +1209,16 @@ static int do_proc_control(struct usb_dev_state *ps, usb_unlock_device(dev); i = usbfs_start_wait_urb(urb, tmo, &actlen); + + /* Linger a bit, prior to the next control message. */ + if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG) + msleep(200); usb_lock_device(dev); snoop_urb(dev, NULL, pipe, actlen, i, COMPLETE, tbuf, actlen); if (!i && actlen) { if (copy_to_user(ctrl->data, tbuf, actlen)) { ret = -EFAULT; - goto recv_fault; + goto done; } } } else { @@ -1219,6 +1235,10 @@ static int do_proc_control(struct usb_dev_state *ps, usb_unlock_device(dev); i = usbfs_start_wait_urb(urb, tmo, &actlen); + + /* Linger a bit, prior to the next control message. */ + if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG) + msleep(200); usb_lock_device(dev); snoop_urb(dev, NULL, pipe, actlen, i, COMPLETE, NULL, 0); } @@ -1230,10 +1250,6 @@ static int do_proc_control(struct usb_dev_state *ps, } ret = (i < 0 ? i : actlen); - recv_fault: - /* Linger a bit, prior to the next control message. */ - if (dev->quirks & USB_QUIRK_DELAY_CTRL_MSG) - msleep(200); done: kfree(dr); usb_free_urb(urb); diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c index dd44e37a454a..8176bc81a635 100644 --- a/drivers/usb/core/hcd-pci.c +++ b/drivers/usb/core/hcd-pci.c @@ -248,7 +248,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id, hcd->rsrc_len, driver->description)) break; } - if (region == PCI_ROM_RESOURCE) { + if (region == PCI_STD_NUM_BARS) { dev_dbg(&dev->dev, "no i/o regions available\n"); retval = -EBUSY; goto put_hcd; diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 47a1c8bddf86..1460857026e0 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -2983,8 +2983,12 @@ static int hub_port_reset(struct usb_hub *hub, int port1, status); } - /* Check for disconnect or reset */ - if (status == 0 || status == -ENOTCONN || status == -ENODEV) { + /* + * Check for disconnect or reset, and bail out after several + * reset attempts to avoid warm reset loop. + */ + if (status == 0 || status == -ENOTCONN || status == -ENODEV || + (status == -EBUSY && i == PORT_RESET_TRIES - 1)) { usb_clear_port_feature(hub->hdev, port1, USB_PORT_FEAT_C_RESET); @@ -5005,6 +5009,7 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, retval = usb_get_bos_descriptor(udev); if (!retval) { udev->lpm_capable = usb_device_supports_lpm(udev); + udev->lpm_disable_count = 1; usb_set_lpm_parameters(udev); } } @@ -5928,16 +5933,6 @@ static int usb_reset_and_verify_device(struct usb_device *udev) */ usb_disable_usb2_hardware_lpm(udev); - /* Disable LPM while we reset the device and reinstall the alt settings. - * Device-initiated LPM, and system exit latency settings are cleared - * when the device is reset, so we have to set them up again. - */ - ret = usb_unlocked_disable_lpm(udev); - if (ret) { - dev_err(&udev->dev, "%s Failed to disable LPM\n", __func__); - goto re_enumerate_no_bos; - } - bos = udev->bos; udev->bos = NULL; @@ -6042,8 +6037,6 @@ done: re_enumerate: usb_release_bos_descriptor(udev); udev->bos = bos; -re_enumerate_no_bos: - /* LPM state doesn't matter when we're about to destroy the device. */ hub_port_logical_disconnect(parent_hub, port1); return -ENODEV; } diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c index d3c14b5ed4a1..97b44a68668a 100644 --- a/drivers/usb/core/quirks.c +++ b/drivers/usb/core/quirks.c @@ -404,6 +404,9 @@ static const struct usb_device_id usb_quirk_list[] = { { USB_DEVICE(0x0b05, 0x17e0), .driver_info = USB_QUIRK_IGNORE_REMOTE_WAKEUP }, + /* Realtek Semiconductor Corp. Mass Storage Device (Multicard Reader)*/ + { USB_DEVICE(0x0bda, 0x0151), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, + /* Realtek hub in Dell WD19 (Type-C) */ { USB_DEVICE(0x0bda, 0x0487), .driver_info = USB_QUIRK_NO_LPM }, @@ -507,6 +510,9 @@ static const struct usb_device_id usb_quirk_list[] = { /* DJI CineSSD */ { USB_DEVICE(0x2ca3, 0x0031), .driver_info = USB_QUIRK_NO_LPM }, + /* VCOM device */ + { USB_DEVICE(0x4296, 0x7570), .driver_info = USB_QUIRK_CONFIG_INTF_STRINGS }, + /* INTEL VALUE SSD */ { USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME }, diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 50b2fc7fcc0e..bb1da35eb891 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -166,7 +166,7 @@ usb_acpi_get_companion_for_port(struct usb_port *port_dev) if (!parent_handle) return NULL; - acpi_bus_get_device(parent_handle, &adev); + adev = acpi_fetch_acpi_dev(parent_handle); port1 = port_dev->portnum; } diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c index 2ce3667ec6fa..2f71636af6e1 100644 --- a/drivers/usb/core/usb.c +++ b/drivers/usb/core/usb.c @@ -688,6 +688,10 @@ EXPORT_SYMBOL_GPL(usb_alloc_dev); * Drivers for USB interfaces should normally record such references in * their probe() methods, when they bind to an interface, and release * them by calling usb_put_dev(), in their disconnect() methods. + * However, if a driver does not access the usb_device structure after + * its disconnect() method returns then refcounting is not necessary, + * because the USB core guarantees that a usb_device will not be + * deallocated until after all of its interface drivers have been unbound. * * Return: A pointer to the device with the incremented reference counter. */ @@ -722,6 +726,10 @@ EXPORT_SYMBOL_GPL(usb_put_dev); * Drivers for USB interfaces should normally record such references in * their probe() methods, when they bind to an interface, and release * them by calling usb_put_intf(), in their disconnect() methods. + * However, if a driver does not access the usb_interface structure after + * its disconnect() method returns then refcounting is not necessary, + * because the USB core guarantees that a usb_interface will not be + * deallocated until after its driver has been unbound. * * Return: A pointer to the interface with the incremented reference counter. */ |