[PATCH v2 1/4] USB: HCD: support giveback of URB in tasklet context
Ming Lei
ming.lei at canonical.com
Tue Jun 25 07:30:43 EDT 2013
On Mon, Jun 24, 2013 at 11:17 PM, Alan Stern <stern at rowland.harvard.edu> wrote:
> On Mon, 24 Jun 2013, Ming Lei wrote:
>
>> This patch implements the mechanism of giveback of URB in
>> tasklet context, so that hardware interrupt handling time for
>> usb host controller can be saved much, and HCD interrupt handling
>> can be simplified.
>
> Changes from v1 to v2?
The change log is put in 0/4.
>
>
>> +static void usb_giveback_urb_bh(unsigned long param)
>> +{
>> + struct giveback_urb_bh *bh = (struct giveback_urb_bh *)param;
>> + unsigned long flags;
>> + struct list_head local_list;
>> +
>> + spin_lock_irqsave(&bh->lock, flags);
>> + bh->running = 1;
>> + restart:
>> + list_replace_init(&bh->head, &local_list);
>> + spin_unlock_irqrestore(&bh->lock, flags);
>
> Tasklet routines are always called with interrupts enabled, right?
> Therefore you don't need to use the "flags" argument here or below.
Good catch.
>
>> @@ -1667,25 +1721,40 @@ 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 sched, 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 = 1;
>> + } else {
>> + bh = &hcd->low_prio_bh;
>> + high_prio_bh = 0;
>> + }
>
> Bool values should be assigned "true" or "false", not "1" or "0".
Right.
>
>> +
>> + spin_lock(&bh->lock);
>> + list_add_tail(&urb->urb_list, &bh->head);
>> + if (bh->running)
>> + sched = 0;
>> + else
>> + sched = 1;
>> + spin_unlock(&bh->lock);
>
> How about calling this variable "running" instead of "sched"? Then you
> could just say:
>
> running = bh->running;
>
> with no "if" statement.
OK, even we can do this below without name change:
sched = !bh->running;
>
>> +
>> + if (!sched)
>> + ;
>> + else if (high_prio_bh)
>> + tasklet_hi_schedule(&bh->bh);
>> + else
>> + tasklet_schedule(&bh->bh);
>> }
>> EXPORT_SYMBOL_GPL(usb_hcd_giveback_urb);
>>
>> @@ -2307,6 +2376,42 @@ 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);
>> +}
>> +
>> +static void init_giveback_urb_bh(struct usb_hcd *hcd)
>> +{
>> + if (!hcd_giveback_urb_in_bh(hcd))
>> + return;
>
> As you mentioned, there's not much point in skipping this code when
> it's not needed. In fact, you could just put the two lines below
> directly into usb_create_shared_hcd(), and get rid of the "__" from the
> beginning of the name.
OK.
>
>> +
>> + __init_giveback_urb_bh(&hcd->high_prio_bh);
>> + __init_giveback_urb_bh(&hcd->low_prio_bh);
>> +}
>> +
>> +static void exit_giveback_urb_bh(struct usb_hcd *hcd)
>> +{
>> + if (!hcd_giveback_urb_in_bh(hcd))
>> + return;
>> +
>> + /*
>> + * tasklet_kill() isn't needed here because:
>> + * - driver's disconnec() called from usb_disconnect() should
>
> Misspelled "disconnect".
>
>> + * 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
>> + *
>> + * Using tasklet to run URB's complete() doesn't change this
>> + * behavior of usbcore.
>> + */
>> +}
>
> Why have a separate subroutine for doing nothing? Simply put this
> comment directly into usb_remove_hcd(). (And you can remove the last
> two lines of the comment; they don't make sense in this context.)
Looks it is a bit clean to put the comment in the function, but it is
OK to add them in usb_remove_hcd() too.
Thanks again for your review.
Thanks,
--
Ming Lei
More information about the linux-arm-kernel
mailing list