aboutsummaryrefslogtreecommitdiff
path: root/drivers/usb/core
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core')
-rw-r--r--drivers/usb/core/devio.c46
-rw-r--r--drivers/usb/core/hcd-pci.c2
-rw-r--r--drivers/usb/core/hub.c21
-rw-r--r--drivers/usb/core/quirks.c6
-rw-r--r--drivers/usb/core/usb-acpi.c2
-rw-r--r--drivers/usb/core/usb.c8
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.
*/