USB: see if URB comes from a completion handler
authorAlan Stern <stern@rowland.harvard.edu>
Tue, 3 Sep 2013 17:58:43 +0000 (13:58 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 17 Sep 2013 16:49:24 +0000 (09:49 -0700)
Now that URBs can be completed inside tasklets, we need a way of
determining whether a completion handler for a given endpoint is
currently running.  Otherwise it's not possible to maintain the API
guarantee about keeping isochronous streams synchronous when an
underrun occurs.

This patch adds a field and a routine to check whether a completion
handler for a periodic endpoint is running.  At the moment no
analogous routine appears to be necessary for async endpoints, but one
can always be added.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
CC: Ming Lei <tom.leiming@gmail.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/core/hcd.c
include/linux/usb/hcd.h

index d6a8d23f047ba69c33d836adb8adc9e0741a85c5..3a2e82a9c115a413fa90f1eb85c9a2d39218d08e 100644 (file)
@@ -1703,7 +1703,9 @@ static void usb_giveback_urb_bh(unsigned long param)
 
                urb = list_entry(local_list.next, struct urb, urb_list);
                list_del_init(&urb->urb_list);
+               bh->completing_ep = urb->ep;
                __usb_hcd_giveback_urb(urb);
+               bh->completing_ep = NULL;
        }
 
        /* check if there are new URBs to giveback */
index 75efc45eaa2ff361d4cb92fa4c325eb8d5d50461..8c865134c881228462273a2c619b22b8968e229d 100644 (file)
@@ -73,6 +73,7 @@ struct giveback_urb_bh {
        spinlock_t lock;
        struct list_head  head;
        struct tasklet_struct bh;
+       struct usb_host_endpoint *completing_ep;
 };
 
 struct usb_hcd {
@@ -378,6 +379,12 @@ static inline int hcd_giveback_urb_in_bh(struct usb_hcd *hcd)
        return hcd->driver->flags & HCD_BH;
 }
 
+static inline bool hcd_periodic_completion_in_progress(struct usb_hcd *hcd,
+               struct usb_host_endpoint *ep)
+{
+       return hcd->high_prio_bh.completing_ep == ep;
+}
+
 extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
 extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
                int status);