diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index ac347f9d5ef0..bf5e37667697 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c @@ -1692,6 +1692,7 @@ static void usb_giveback_urb_bh(struct tasklet_struct *t) spin_lock_irq(&bh->lock); bh->running = true; + restart: list_replace_init(&bh->head, &local_list); spin_unlock_irq(&bh->lock); @@ -1705,17 +1706,10 @@ static void usb_giveback_urb_bh(struct tasklet_struct *t) bh->completing_ep = NULL; } - /* - * giveback new URBs next time to prevent this function - * from not exiting for a long time. - */ + /* check if there are new URBs to giveback */ spin_lock_irq(&bh->lock); - if (!list_empty(&bh->head)) { - if (bh->high_prio) - tasklet_hi_schedule(&bh->bh); - else - tasklet_schedule(&bh->bh); - } + if (!list_empty(&bh->head)) + goto restart; bh->running = false; spin_unlock_irq(&bh->lock); } @@ -1740,7 +1734,7 @@ static void usb_giveback_urb_bh(struct tasklet_struct *t) void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) { struct giveback_urb_bh *bh; - bool running; + bool running, high_prio_bh; /* pass status to tasklet via unlinked */ if (likely(!urb->unlinked)) @@ -1751,10 +1745,13 @@ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) return; } - if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) + if (usb_pipeisoc(urb->pipe) || usb_pipeint(urb->pipe)) { bh = &hcd->high_prio_bh; - else + 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); @@ -1763,7 +1760,7 @@ void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb, int status) if (running) ; - else if (bh->high_prio) + else if (high_prio_bh) tasklet_hi_schedule(&bh->bh); else tasklet_schedule(&bh->bh); @@ -2803,7 +2800,6 @@ int usb_add_hcd(struct usb_hcd *hcd, /* initialize tasklets */ init_giveback_urb_bh(&hcd->high_prio_bh); - hcd->high_prio_bh.high_prio = true; init_giveback_urb_bh(&hcd->low_prio_bh); /* enable irqs just before we start the controller, diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h index 70106b34785a..d14b39d1418e 100644 --- a/include/linux/usb/hcd.h +++ b/include/linux/usb/hcd.h @@ -67,7 +67,6 @@ struct giveback_urb_bh { bool running; - bool high_prio; spinlock_t lock; struct list_head head; struct tasklet_struct bh;