[PATCH v2 1/4] USB: HCD: support giveback of URB in tasklet context

Alan Stern stern at rowland.harvard.edu
Mon Jun 24 11:17:36 EDT 2013


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?


> +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.

> @@ -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".

> +
> +	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.

> +
> +	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.

> +
> +	__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.)

Alan Stern




More information about the linux-arm-kernel mailing list