summaryrefslogtreecommitdiff
path: root/drivers/usb/core/hcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/core/hcd.c')
-rw-r--r--drivers/usb/core/hcd.c227
1 files changed, 168 insertions, 59 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 014dc996b4f6..d6a8d23f047b 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -378,9 +378,10 @@ MODULE_PARM_DESC(authorized_default,
* @buf: Buffer for USB string descriptor (header + UTF-16LE)
* @len: Length (in bytes; may be odd) of descriptor buffer.
*
- * The return value is the number of bytes filled in: 2 + 2*strlen(s) or
- * buflen, whichever is less.
+ * Return: The number of bytes filled in: 2 + 2*strlen(s) or @len,
+ * whichever is less.
*
+ * Note:
* USB String descriptors can contain at most 126 characters; input
* strings longer than that are truncated.
*/
@@ -416,7 +417,8 @@ ascii2desc(char const *s, u8 *buf, unsigned len)
*
* Produces either a manufacturer, product or serial number string for the
* virtual root hub device.
- * Returns the number of bytes filled in: the length of the descriptor or
+ *
+ * Return: The number of bytes filled in: the length of the descriptor or
* of the provided buffer, whichever is less.
*/
static unsigned
@@ -464,17 +466,13 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
struct usb_ctrlrequest *cmd;
u16 typeReq, wValue, wIndex, wLength;
u8 *ubuf = urb->transfer_buffer;
- /*
- * tbuf should be as big as the BOS descriptor and
- * the USB hub descriptor.
- */
- u8 tbuf[USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE]
- __attribute__((aligned(4)));
- const u8 *bufp = tbuf;
unsigned len = 0;
int status;
u8 patch_wakeup = 0;
u8 patch_protocol = 0;
+ u16 tbuf_size;
+ u8 *tbuf = NULL;
+ const u8 *bufp;
might_sleep();
@@ -494,6 +492,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
if (wLength > urb->transfer_buffer_length)
goto error;
+ /*
+ * tbuf should be at least as big as the
+ * USB hub descriptor.
+ */
+ tbuf_size = max_t(u16, sizeof(struct usb_hub_descriptor), wLength);
+ tbuf = kzalloc(tbuf_size, GFP_KERNEL);
+ if (!tbuf)
+ return -ENOMEM;
+
+ bufp = tbuf;
+
+
urb->actual_length = 0;
switch (typeReq) {
@@ -691,18 +701,12 @@ error:
bDeviceProtocol = USB_HUB_PR_HS_SINGLE_TT;
}
+ kfree(tbuf);
+
/* any errors get returned through the urb completion */
spin_lock_irq(&hcd_root_hub_lock);
usb_hcd_unlink_urb_from_ep(hcd, urb);
-
- /* This peculiar use of spinlocks echoes what real HC drivers do.
- * Avoiding calls to local_irq_disable/enable makes the code
- * RT-friendly.
- */
- spin_unlock(&hcd_root_hub_lock);
usb_hcd_giveback_urb(hcd, urb, status);
- spin_lock(&hcd_root_hub_lock);
-
spin_unlock_irq(&hcd_root_hub_lock);
return 0;
}
@@ -742,9 +746,7 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
memcpy(urb->transfer_buffer, buffer, length);
usb_hcd_unlink_urb_from_ep(hcd, urb);
- spin_unlock(&hcd_root_hub_lock);
usb_hcd_giveback_urb(hcd, urb, 0);
- spin_lock(&hcd_root_hub_lock);
} else {
length = 0;
set_bit(HCD_FLAG_POLL_PENDING, &hcd->flags);
@@ -834,10 +836,7 @@ static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
if (urb == hcd->status_urb) {
hcd->status_urb = NULL;
usb_hcd_unlink_urb_from_ep(hcd, urb);
-
- spin_unlock(&hcd_root_hub_lock);
usb_hcd_giveback_urb(hcd, urb, status);
- spin_lock(&hcd_root_hub_lock);
}
}
done:
@@ -850,9 +849,8 @@ static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
/*
* Show & store the current value of authorized_default
*/
-static ssize_t usb_host_authorized_default_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t authorized_default_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct usb_device *rh_usb_dev = to_usb_device(dev);
struct usb_bus *usb_bus = rh_usb_dev->bus;
@@ -864,9 +862,9 @@ static ssize_t usb_host_authorized_default_show(struct device *dev,
return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default);
}
-static ssize_t usb_host_authorized_default_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t size)
+static ssize_t authorized_default_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t size)
{
ssize_t result;
unsigned val;
@@ -886,11 +884,7 @@ static ssize_t usb_host_authorized_default_store(struct device *dev,
result = -EINVAL;
return result;
}
-
-static DEVICE_ATTR(authorized_default, 0644,
- usb_host_authorized_default_show,
- usb_host_authorized_default_store);
-
+static DEVICE_ATTR_RW(authorized_default);
/* Group all the USB bus attributes */
static struct attribute *usb_bus_attrs[] = {
@@ -938,6 +932,8 @@ static void usb_bus_init (struct usb_bus *bus)
*
* Assigns a bus number, and links the controller into usbcore data
* structures so that it can be seen by scanning the bus list.
+ *
+ * Return: 0 if successful. A negative error code otherwise.
*/
static int usb_register_bus(struct usb_bus *bus)
{
@@ -1002,6 +998,8 @@ static void usb_deregister_bus (struct usb_bus *bus)
* the device properly in the device tree and then calls usb_new_device()
* to register the usb device. It also assigns the root hub's USB address
* (always 1).
+ *
+ * Return: 0 if successful. A negative error code otherwise.
*/
static int register_root_hub(struct usb_hcd *hcd)
{
@@ -1108,7 +1106,9 @@ EXPORT_SYMBOL_GPL(usb_hcd_end_port_resume);
* @isoc: true for isochronous transactions, false for interrupt ones
* @bytecount: how many bytes in the transaction.
*
- * Returns approximate bus time in nanoseconds for a periodic transaction.
+ * Return: Approximate bus time in nanoseconds for a periodic transaction.
+ *
+ * Note:
* See USB 2.0 spec section 5.11.3; only periodic transfers need to be
* scheduled in software, this function is only used for such scheduling.
*/
@@ -1166,7 +1166,7 @@ EXPORT_SYMBOL_GPL(usb_calc_bus_time);
* be disabled. The actions carried out here are required for URB
* submission, as well as for endpoint shutdown and for usb_kill_urb.
*
- * Returns 0 for no error, otherwise a negative error code (in which case
+ * Return: 0 for no error, otherwise a negative error code (in which case
* the enqueue() method must fail). If no error occurs but enqueue() fails
* anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing
* the private spinlock and returning.
@@ -1221,7 +1221,7 @@ EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep);
* be disabled. The actions carried out here are required for making
* sure than an unlink is valid.
*
- * Returns 0 for no error, otherwise a negative error code (in which case
+ * Return: 0 for no error, otherwise a negative error code (in which case
* the dequeue() method must fail). The possible error codes are:
*
* -EIDRM: @urb was not submitted or has already completed.
@@ -1648,6 +1648,72 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
/*-------------------------------------------------------------------------*/
+static void __usb_hcd_giveback_urb(struct urb *urb)
+{
+ struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
+ int status = urb->unlinked;
+ unsigned long flags;
+
+ urb->hcpriv = NULL;
+ if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+ urb->actual_length < urb->transfer_buffer_length &&
+ !status))
+ status = -EREMOTEIO;
+
+ unmap_urb_for_dma(hcd, urb);
+ usbmon_urb_complete(&hcd->self, urb, status);
+ usb_unanchor_urb(urb);
+
+ /* pass ownership to the completion handler */
+ urb->status = status;
+
+ /*
+ * We disable local IRQs here avoid possible deadlock because
+ * drivers may call spin_lock() to hold lock which might be
+ * acquired in one hard interrupt handler.
+ *
+ * The local_irq_save()/local_irq_restore() around complete()
+ * will be removed if current USB drivers have been cleaned up
+ * and no one may trigger the above deadlock situation when
+ * running complete() in tasklet.
+ */
+ local_irq_save(flags);
+ urb->complete(urb);
+ local_irq_restore(flags);
+
+ atomic_dec(&urb->use_count);
+ if (unlikely(atomic_read(&urb->reject)))
+ wake_up(&usb_kill_urb_queue);
+ usb_put_urb(urb);
+}
+
+static void usb_giveback_urb_bh(unsigned long param)
+{
+ struct giveback_urb_bh *bh = (struct giveback_urb_bh *)param;
+ struct list_head local_list;
+
+ spin_lock_irq(&bh->lock);
+ bh->running = true;
+ restart:
+ list_replace_init(&bh->head, &local_list);
+ spin_unlock_irq(&bh->lock);
+
+ while (!list_empty(&local_list)) {
+ struct urb *urb;
+
+ urb = list_entry(local_list.next, struct urb, urb_list);
+ list_del_init(&urb->urb_list);
+ __usb_hcd_giveback_urb(urb);
+ }
+
+ /* check if there are new URBs to giveback */
+ spin_lock_irq(&bh->lock);
+ if (!list_empty(&bh->head))
+ goto restart;
+ bh->running = false;
+ spin_unlock_irq(&bh->lock);
+}
+
/**
* usb_hcd_giveback_urb - return URB from HCD to device driver
* @hcd: host controller returning the URB
@@ -1667,25 +1733,37 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
*/
void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status)
{
- urb->hcpriv = NULL;
- if (unlikely(urb->unlinked))
- status = urb->unlinked;
- else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
- urb->actual_length < urb->transfer_buffer_length &&
- !status))
- status = -EREMOTEIO;
+ struct giveback_urb_bh *bh;
+ bool running, high_prio_bh;
- unmap_urb_for_dma(hcd, urb);
- usbmon_urb_complete(&hcd->self, urb, status);
- usb_unanchor_urb(urb);
+ /* pass status to tasklet via unlinked */
+ if (likely(!urb->unlinked))
+ urb->unlinked = status;
- /* pass ownership to the completion handler */
- urb->status = status;
- urb->complete (urb);
- atomic_dec (&urb->use_count);
- if (unlikely(atomic_read(&urb->reject)))
- wake_up (&usb_kill_urb_queue);
- usb_put_urb (urb);
+ if (!hcd_giveback_urb_in_bh(hcd) && !is_root_hub(urb->dev)) {
+ __usb_hcd_giveback_urb(urb);
+ return;
+ }
+
+ if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) {
+ bh = &hcd->high_prio_bh;
+ high_prio_bh = true;
+ } else {
+ bh = &hcd->low_prio_bh;
+ high_prio_bh = false;
+ }
+
+ spin_lock(&bh->lock);
+ list_add_tail(&urb->urb_list, &bh->head);
+ running = bh->running;
+ spin_unlock(&bh->lock);
+
+ if (running)
+ ;
+ else if (high_prio_bh)
+ tasklet_hi_schedule(&bh->bh);
+ else
+ tasklet_schedule(&bh->bh);
}
EXPORT_SYMBOL_GPL(usb_hcd_giveback_urb);
@@ -1784,7 +1862,7 @@ rescan:
* pass in the current alternate interface setting in cur_alt,
* and pass in the new alternate interface setting in new_alt.
*
- * Returns an error if the requested bandwidth change exceeds the
+ * Return: An error if the requested bandwidth change exceeds the
* bus bandwidth or host controller internal resources.
*/
int usb_hcd_alloc_bandwidth(struct usb_device *udev,
@@ -1954,9 +2032,12 @@ void usb_hcd_reset_endpoint(struct usb_device *udev,
* @num_streams: number of streams to allocate.
* @mem_flags: flags hcd should use to allocate memory.
*
- * Sets up a group of bulk endpoints to have num_streams stream IDs available.
+ * Sets up a group of bulk endpoints to have @num_streams stream IDs available.
* Drivers may queue multiple transfers to different stream IDs, which may
* complete in a different order than they were queued.
+ *
+ * Return: On success, the number of allocated streams. On failure, a negative
+ * error code.
*/
int usb_alloc_streams(struct usb_interface *interface,
struct usb_host_endpoint **eps, unsigned int num_eps,
@@ -2201,6 +2282,8 @@ EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
* khubd identifying and possibly configuring the device.
* This is needed by OTG controller drivers, where it helps meet
* HNP protocol timing requirements for starting a port reset.
+ *
+ * Return: 0 if successful.
*/
int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num)
{
@@ -2235,6 +2318,8 @@ EXPORT_SYMBOL_GPL(usb_bus_start_enum);
*
* If the controller isn't HALTed, calls the driver's irq handler.
* Checks whether the controller is now dead.
+ *
+ * Return: %IRQ_HANDLED if the IRQ was handled. %IRQ_NONE otherwise.
*/
irqreturn_t usb_hcd_irq (int irq, void *__hcd)
{
@@ -2307,6 +2392,14 @@ EXPORT_SYMBOL_GPL (usb_hc_died);
/*-------------------------------------------------------------------------*/
+static void init_giveback_urb_bh(struct giveback_urb_bh *bh)
+{
+
+ spin_lock_init(&bh->lock);
+ INIT_LIST_HEAD(&bh->head);
+ tasklet_init(&bh->bh, usb_giveback_urb_bh, (unsigned long)bh);
+}
+
/**
* usb_create_shared_hcd - create and initialize an HCD structure
* @driver: HC driver that will use this hcd
@@ -2320,7 +2413,8 @@ EXPORT_SYMBOL_GPL (usb_hc_died);
* HC driver's private data. Initialize the generic members of the
* hcd structure.
*
- * If memory is unavailable, returns NULL.
+ * Return: On success, a pointer to the created and initialized HCD structure.
+ * On failure (e.g. if memory is unavailable), %NULL.
*/
struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
struct device *dev, const char *bus_name,
@@ -2384,7 +2478,8 @@ EXPORT_SYMBOL_GPL(usb_create_shared_hcd);
* HC driver's private data. Initialize the generic members of the
* hcd structure.
*
- * If memory is unavailable, returns NULL.
+ * Return: On success, a pointer to the created and initialized HCD
+ * structure. On failure (e.g. if memory is unavailable), %NULL.
*/
struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
struct device *dev, const char *bus_name)
@@ -2563,7 +2658,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
* should already have been reset (and boot firmware kicked off etc).
*/
if (hcd->driver->reset && (retval = hcd->driver->reset(hcd)) < 0) {
- dev_err(hcd->self.controller, "can't setup\n");
+ dev_err(hcd->self.controller, "can't setup: %d\n", retval);
goto err_hcd_driver_setup;
}
hcd->rh_pollable = 1;
@@ -2573,6 +2668,10 @@ int usb_add_hcd(struct usb_hcd *hcd,
&& device_can_wakeup(&hcd->self.root_hub->dev))
dev_dbg(hcd->self.controller, "supports USB remote wakeup\n");
+ /* initialize tasklets */
+ init_giveback_urb_bh(&hcd->high_prio_bh);
+ init_giveback_urb_bh(&hcd->low_prio_bh);
+
/* enable irqs just before we start the controller,
* if the BIOS provides legacy PCI irqs.
*/
@@ -2681,6 +2780,16 @@ void usb_remove_hcd(struct usb_hcd *hcd)
usb_disconnect(&rhdev); /* Sets rhdev to NULL */
mutex_unlock(&usb_bus_list_lock);
+ /*
+ * tasklet_kill() isn't needed here because:
+ * - driver's disconnect() called from usb_disconnect() should
+ * make sure its URBs are completed during the disconnect()
+ * callback
+ *
+ * - it is too late to run complete() here since driver may have
+ * been removed already now
+ */
+
/* Prevent any more root-hub status calls from the timer.
* The HCD might still restart the timer (if a port status change
* interrupt occurs), but usb_hcd_poll_rh_status() won't invoke