Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: core: hcd: Convert from tasklet to BH workqueue

The only generic interface to execute asynchronously in the BH context is
tasklet; however, it's marked deprecated and has some design flaws. To
replace tasklets, BH workqueue support was recently added. A BH workqueue
behaves similarly to regular workqueues except that the queued work items
are executed in the BH context.

This patch converts usb hcd from tasklet to BH workqueue.

Signed-off-by: Tejun Heo <tj@kernel.org>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: linux-usb@vger.kernel.org

+13 -12
+12 -11
drivers/usb/core/hcd.c
··· 1664 1664 usb_put_urb(urb); 1665 1665 } 1666 1666 1667 - static void usb_giveback_urb_bh(struct tasklet_struct *t) 1667 + static void usb_giveback_urb_bh(struct work_struct *work) 1668 1668 { 1669 - struct giveback_urb_bh *bh = from_tasklet(bh, t, bh); 1669 + struct giveback_urb_bh *bh = 1670 + container_of(work, struct giveback_urb_bh, bh); 1670 1671 struct list_head local_list; 1671 1672 1672 1673 spin_lock_irq(&bh->lock); ··· 1692 1691 spin_lock_irq(&bh->lock); 1693 1692 if (!list_empty(&bh->head)) { 1694 1693 if (bh->high_prio) 1695 - tasklet_hi_schedule(&bh->bh); 1694 + queue_work(system_bh_highpri_wq, &bh->bh); 1696 1695 else 1697 - tasklet_schedule(&bh->bh); 1696 + queue_work(system_bh_wq, &bh->bh); 1698 1697 } 1699 1698 bh->running = false; 1700 1699 spin_unlock_irq(&bh->lock); ··· 1707 1706 * @status: completion status code for the URB. 1708 1707 * 1709 1708 * Context: atomic. The completion callback is invoked in caller's context. 1710 - * For HCDs with HCD_BH flag set, the completion callback is invoked in tasklet 1709 + * For HCDs with HCD_BH flag set, the completion callback is invoked in BH 1711 1710 * context (except for URBs submitted to the root hub which always complete in 1712 1711 * caller's context). 1713 1712 * ··· 1726 1725 struct giveback_urb_bh *bh; 1727 1726 bool running; 1728 1727 1729 - /* pass status to tasklet via unlinked */ 1728 + /* pass status to BH via unlinked */ 1730 1729 if (likely(!urb->unlinked)) 1731 1730 urb->unlinked = status; 1732 1731 ··· 1748 1747 if (running) 1749 1748 ; 1750 1749 else if (bh->high_prio) 1751 - tasklet_hi_schedule(&bh->bh); 1750 + queue_work(system_bh_highpri_wq, &bh->bh); 1752 1751 else 1753 - tasklet_schedule(&bh->bh); 1752 + queue_work(system_bh_wq, &bh->bh); 1754 1753 } 1755 1754 EXPORT_SYMBOL_GPL(usb_hcd_giveback_urb); 1756 1755 ··· 2541 2540 2542 2541 spin_lock_init(&bh->lock); 2543 2542 INIT_LIST_HEAD(&bh->head); 2544 - tasklet_setup(&bh->bh, usb_giveback_urb_bh); 2543 + INIT_WORK(&bh->bh, usb_giveback_urb_bh); 2545 2544 } 2546 2545 2547 2546 struct usb_hcd *__usb_create_hcd(const struct hc_driver *driver, ··· 2927 2926 && device_can_wakeup(&hcd->self.root_hub->dev)) 2928 2927 dev_dbg(hcd->self.controller, "supports USB remote wakeup\n"); 2929 2928 2930 - /* initialize tasklets */ 2929 + /* initialize BHs */ 2931 2930 init_giveback_urb_bh(&hcd->high_prio_bh); 2932 2931 hcd->high_prio_bh.high_prio = true; 2933 2932 init_giveback_urb_bh(&hcd->low_prio_bh); ··· 3037 3036 mutex_unlock(&usb_bus_idr_lock); 3038 3037 3039 3038 /* 3040 - * tasklet_kill() isn't needed here because: 3039 + * flush_work() isn't needed here because: 3041 3040 * - driver's disconnect() called from usb_disconnect() should 3042 3041 * make sure its URBs are completed during the disconnect() 3043 3042 * callback
+1 -1
include/linux/usb/hcd.h
··· 55 55 bool high_prio; 56 56 spinlock_t lock; 57 57 struct list_head head; 58 - struct tasklet_struct bh; 58 + struct work_struct bh; 59 59 struct usb_host_endpoint *completing_ep; 60 60 }; 61 61