From: Luis R. Rodriguez Date: Fri, 17 Jul 2009 15:53:52 +0000 (-0700) Subject: We forgot to add usb_poison_urb() and usb_unpoison_urb() X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=899b22bb6a05d39ddfc7ceb59d7932d77ac62767;p=openwrt%2Fstaging%2Fblogic.git We forgot to add usb_poison_urb() and usb_unpoison_urb() Also correct the placement of USB backport files in consideration for 2.6.28. Signed-off-by: Luis R. Rodriguez --- diff --git a/compat/compat-2.6.27.c b/compat/compat-2.6.27.c index d072f646a579..a3ef74823fc9 100644 --- a/compat/compat-2.6.27.c +++ b/compat/compat-2.6.27.c @@ -18,7 +18,6 @@ #include #include - /* rfkill notification chain */ #define RFKILL_STATE_CHANGED 0x0001 /* state of a normal rfkill switch has changed */ diff --git a/compat/compat-2.6.28.c b/compat/compat-2.6.28.c index 7abd50d7795f..df06cbe08932 100644 --- a/compat/compat-2.6.28.c +++ b/compat/compat-2.6.28.c @@ -12,7 +12,188 @@ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)) -/* 2.6.27 compat code goes here */ +#include + +/* 2.6.28 compat code goes here */ + +/* + * Compat-wireless notes for USB backport stuff: + * + * urb->reject exists on 2.6.27, the poison/unpoison helpers + * did not though. The anchor poison does not exist so we cannot use them. + * + * USB anchor poising seems to exist to prevent future driver sumbissions + * of usb_anchor_urb() to an anchor marked as poisoned. For older kernels + * we cannot use that, so new usb_anchor_urb()s will be anchored. The down + * side to this should be submission of URBs will continue being anchored + * on an anchor instead of having them being rejected immediately when the + * driver realized we needed to stop. For ar9170 we poison URBs upon the + * ar9170 mac80211 stop callback(), don't think this should be so bad. + * It mean there is period of time in older kernels for which we continue + * to anchor new URBs to a known stopped anchor. We have two anchors + * (TX, and RX) + */ + +/** + * usb_poison_urb - reliably kill a transfer and prevent further use of an URB + * @urb: pointer to URB describing a previously submitted request, + * may be NULL + * + * This routine cancels an in-progress request. It is guaranteed that + * upon return all completion handlers will have finished and the URB + * will be totally idle and cannot be reused. These features make + * this an ideal way to stop I/O in a disconnect() callback. + * If the request has not already finished or been unlinked + * the completion handler will see urb->status == -ENOENT. + * + * After and while the routine runs, attempts to resubmit the URB will fail + * with error -EPERM. Thus even if the URB's completion handler always + * tries to resubmit, it will not succeed and the URB will become idle. + * + * This routine may not be used in an interrupt context (such as a bottom + * half or a completion handler), or when holding a spinlock, or in other + * situations where the caller can't schedule(). + * + * This routine should not be called by a driver after its disconnect + * method has returned. + */ +void usb_poison_urb(struct urb *urb) +{ + might_sleep(); + if (!(urb && urb->dev && urb->ep)) + return; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)) + spin_lock_irq(&usb_reject_lock); +#endif + ++urb->reject; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)) + spin_unlock_irq(&usb_reject_lock); +#endif + + usb_hcd_unlink_urb(urb, -ENOENT); + wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0); +} +EXPORT_SYMBOL_GPL(usb_poison_urb); + +void usb_unpoison_urb(struct urb *urb) +{ + unsigned long flags; + + if (!urb) + return; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)) + spin_lock_irqsave(&usb_reject_lock, flags); +#endif + --urb->reject; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)) + spin_unlock_irqrestore(&usb_reject_lock, flags); +#endif +} +EXPORT_SYMBOL_GPL(usb_unpoison_urb); + + +/** + * usb_poison_anchored_urbs - cease all traffic from an anchor + * @anchor: anchor the requests are bound to + * + * this allows all outstanding URBs to be poisoned starting + * from the back of the queue. Newly added URBs will also be + * poisoned + * + * This routine should not be called by a driver after its disconnect + * method has returned. + */ +void usb_poison_anchored_urbs(struct usb_anchor *anchor) +{ + struct urb *victim; + + spin_lock_irq(&anchor->lock); + // anchor->poisoned = 1; /* XXX: Cannot backport */ + while (!list_empty(&anchor->urb_list)) { + victim = list_entry(anchor->urb_list.prev, struct urb, + anchor_list); + /* we must make sure the URB isn't freed before we kill it*/ + usb_get_urb(victim); + spin_unlock_irq(&anchor->lock); + /* this will unanchor the URB */ + usb_poison_urb(victim); + usb_put_urb(victim); + spin_lock_irq(&anchor->lock); + } + spin_unlock_irq(&anchor->lock); +} +EXPORT_SYMBOL_GPL(usb_poison_anchored_urbs); + +/** + * usb_get_from_anchor - get an anchor's oldest urb + * @anchor: the anchor whose urb you want + * + * this will take the oldest urb from an anchor, + * unanchor and return it + */ +struct urb *usb_get_from_anchor(struct usb_anchor *anchor) +{ + struct urb *victim; + unsigned long flags; + + spin_lock_irqsave(&anchor->lock, flags); + if (!list_empty(&anchor->urb_list)) { + victim = list_entry(anchor->urb_list.next, struct urb, + anchor_list); + usb_get_urb(victim); + spin_unlock_irqrestore(&anchor->lock, flags); + usb_unanchor_urb(victim); + } else { + spin_unlock_irqrestore(&anchor->lock, flags); + victim = NULL; + } + + return victim; +} + +EXPORT_SYMBOL_GPL(usb_get_from_anchor); + +/** + * usb_scuttle_anchored_urbs - unanchor all an anchor's urbs + * @anchor: the anchor whose urbs you want to unanchor + * + * use this to get rid of all an anchor's urbs + */ +void usb_scuttle_anchored_urbs(struct usb_anchor *anchor) +{ + struct urb *victim; + unsigned long flags; + + spin_lock_irqsave(&anchor->lock, flags); + while (!list_empty(&anchor->urb_list)) { + victim = list_entry(anchor->urb_list.prev, struct urb, + anchor_list); + usb_get_urb(victim); + spin_unlock_irqrestore(&anchor->lock, flags); + /* this may free the URB */ + usb_unanchor_urb(victim); + usb_put_urb(victim); + spin_lock_irqsave(&anchor->lock, flags); + } + spin_unlock_irqrestore(&anchor->lock, flags); +} + +EXPORT_SYMBOL_GPL(usb_scuttle_anchored_urbs); + +/** + * usb_anchor_empty - is an anchor empty + * @anchor: the anchor you want to query + * + * returns 1 if the anchor has no urbs associated with it + */ +int usb_anchor_empty(struct usb_anchor *anchor) +{ + return list_empty(&anchor->urb_list); +} + +EXPORT_SYMBOL_GPL(usb_anchor_empty); + void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar) { diff --git a/compat/compat-2.6.28.h b/compat/compat-2.6.28.h index 6f7760eb2b04..945e9f2a8da8 100644 --- a/compat/compat-2.6.28.h +++ b/compat/compat-2.6.28.h @@ -9,6 +9,7 @@ #include #include +#include #ifndef ETH_P_PAE #define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */ @@ -28,6 +29,17 @@ }) #endif /* From include/asm-generic/bug.h */ +extern void usb_poison_urb(struct urb *urb); +extern void usb_unpoison_urb(struct urb *urb); + +extern void usb_poison_anchored_urbs(struct usb_anchor *anchor); +extern void usb_unpoison_anchored_urbs(struct usb_anchor *anchor); + +extern struct urb *usb_get_from_anchor(struct usb_anchor *anchor); +extern void usb_scuttle_anchored_urbs(struct usb_anchor *anchor); +extern int usb_anchor_empty(struct usb_anchor *anchor); + + void __iomem *pci_ioremap_bar(struct pci_dev *pdev, int bar); /** diff --git a/compat/compat-2.6.29.c b/compat/compat-2.6.29.c index 8c66d5237ea7..490edac3fc27 100644 --- a/compat/compat-2.6.29.c +++ b/compat/compat-2.6.29.c @@ -14,58 +14,6 @@ #include -/* 2.6.29 compat code goes here */ - -/* - * Compat-wireless notes for USB backport stuff: - * - * urb->reject exists on 2.6.27, the poison/unpoison helpers - * did not though. The anchor poison does not exist so we cannot use them. - * - * USB anchor poising seems to exist to prevent future driver sumbissions - * of usb_anchor_urb() to an anchor marked as poisoned. For older kernels - * we cannot use that, so new usb_anchor_urb()s will be anchored. The down - * side to this should be submission of URBs will continue being anchored - * on an anchor instead of having them being rejected immediately when the - * driver realized we needed to stop. For ar9170 we poison URBs upon the - * ar9170 mac80211 stop callback(), don't think this should be so bad. - * It mean there is period of time in older kernels for which we continue - * to anchor new URBs to a known stopped anchor. We have two anchors - * (TX, and RX) - */ - -/** - * usb_poison_anchored_urbs - cease all traffic from an anchor - * @anchor: anchor the requests are bound to - * - * this allows all outstanding URBs to be poisoned starting - * from the back of the queue. Newly added URBs will also be - * poisoned - * - * This routine should not be called by a driver after its disconnect - * method has returned. - */ -void usb_poison_anchored_urbs(struct usb_anchor *anchor) -{ - struct urb *victim; - - spin_lock_irq(&anchor->lock); - // anchor->poisoned = 1; /* XXX: Cannot backport */ - while (!list_empty(&anchor->urb_list)) { - victim = list_entry(anchor->urb_list.prev, struct urb, - anchor_list); - /* we must make sure the URB isn't freed before we kill it*/ - usb_get_urb(victim); - spin_unlock_irq(&anchor->lock); - /* this will unanchor the URB */ - usb_poison_urb(victim); - usb_put_urb(victim); - spin_lock_irq(&anchor->lock); - } - spin_unlock_irq(&anchor->lock); -} -EXPORT_SYMBOL_GPL(usb_poison_anchored_urbs); - /** * usb_unpoison_anchored_urbs - let an anchor be used successfully again * @anchor: anchor the requests are bound to @@ -87,75 +35,6 @@ void usb_unpoison_anchored_urbs(struct usb_anchor *anchor) } EXPORT_SYMBOL_GPL(usb_unpoison_anchored_urbs); -/** - * usb_get_from_anchor - get an anchor's oldest urb - * @anchor: the anchor whose urb you want - * - * this will take the oldest urb from an anchor, - * unanchor and return it - */ -struct urb *usb_get_from_anchor(struct usb_anchor *anchor) -{ - struct urb *victim; - unsigned long flags; - - spin_lock_irqsave(&anchor->lock, flags); - if (!list_empty(&anchor->urb_list)) { - victim = list_entry(anchor->urb_list.next, struct urb, - anchor_list); - usb_get_urb(victim); - spin_unlock_irqrestore(&anchor->lock, flags); - usb_unanchor_urb(victim); - } else { - spin_unlock_irqrestore(&anchor->lock, flags); - victim = NULL; - } - - return victim; -} - -EXPORT_SYMBOL_GPL(usb_get_from_anchor); - -/** - * usb_scuttle_anchored_urbs - unanchor all an anchor's urbs - * @anchor: the anchor whose urbs you want to unanchor - * - * use this to get rid of all an anchor's urbs - */ -void usb_scuttle_anchored_urbs(struct usb_anchor *anchor) -{ - struct urb *victim; - unsigned long flags; - - spin_lock_irqsave(&anchor->lock, flags); - while (!list_empty(&anchor->urb_list)) { - victim = list_entry(anchor->urb_list.prev, struct urb, - anchor_list); - usb_get_urb(victim); - spin_unlock_irqrestore(&anchor->lock, flags); - /* this may free the URB */ - usb_unanchor_urb(victim); - usb_put_urb(victim); - spin_lock_irqsave(&anchor->lock, flags); - } - spin_unlock_irqrestore(&anchor->lock, flags); -} - -EXPORT_SYMBOL_GPL(usb_scuttle_anchored_urbs); - -/** - * usb_anchor_empty - is an anchor empty - * @anchor: the anchor you want to query - * - * returns 1 if the anchor has no urbs associated with it - */ -int usb_anchor_empty(struct usb_anchor *anchor) -{ - return list_empty(&anchor->urb_list); -} - -EXPORT_SYMBOL_GPL(usb_anchor_empty); - #endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29) */ diff --git a/compat/compat-2.6.29.h b/compat/compat-2.6.29.h index ee8db16d735b..f4086e92e6a9 100644 --- a/compat/compat-2.6.29.h +++ b/compat/compat-2.6.29.h @@ -8,17 +8,6 @@ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,29)) #include -#include - -extern void usb_poison_urb(struct urb *urb); -extern void usb_unpoison_urb(struct urb *urb); - -extern void usb_poison_anchored_urbs(struct usb_anchor *anchor); -extern void usb_unpoison_anchored_urbs(struct usb_anchor *anchor); - -extern struct urb *usb_get_from_anchor(struct usb_anchor *anchor); -extern void usb_scuttle_anchored_urbs(struct usb_anchor *anchor); -extern int usb_anchor_empty(struct usb_anchor *anchor); /** * skb_queue_is_first - check if skb is the first entry in the queue