From b24bc8a94e7c159ac76c8b6493ce71a2f3e4b1b7 Mon Sep 17 00:00:00 2001 From: "Luis R. Rodriguez" Date: Wed, 23 Sep 2009 10:26:47 -0700 Subject: [PATCH] Backport threaded IRQ support using workqueues b43 makes use this. Signed-off-by: Michael Buesch Signed-off-by: Luis R. Rodriguez --- compat/compat-2.6.31.h | 87 ++++++++++++++++++++++++++++ compat/patches/09-threaded-irq.patch | 63 ++++++++++++++++++++ 2 files changed, 150 insertions(+) create mode 100644 compat/patches/09-threaded-irq.patch diff --git a/compat/compat-2.6.31.h b/compat/compat-2.6.31.h index 95a649cda5ac..154209c96f77 100644 --- a/compat/compat-2.6.31.h +++ b/compat/compat-2.6.31.h @@ -8,6 +8,8 @@ #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)) #include +#include +#include #include #include @@ -57,6 +59,16 @@ #define SDIO_DEVICE_ID_MARVELL_8688WLAN 0x9104 #endif +struct compat_threaded_irq { + unsigned int irq; + irq_handler_t handler; + irq_handler_t thread_fn; + void *dev_id; + char wq_name[64]; + struct workqueue_struct *wq; + struct work_struct work; +}; + /* * kmemleak was introduced on 2.6.31, since older kernels do not have * we simply ignore its tuning. @@ -91,6 +103,81 @@ static inline void skb_dst_drop(struct sk_buff *skb) extern int genl_register_family_with_ops(struct genl_family *family, struct genl_ops *ops, size_t n_ops); + +/* Backport threaded IRQ support */ + +static inline +void compat_irq_work(struct work_struct *work) +{ + struct compat_threaded_irq *comp = container_of(work, struct compat_threaded_irq, work); + comp->thread_fn(comp->irq, comp->dev_id); +} + +static inline +irqreturn_t compat_irq_dispatcher(int irq, void *dev_id) +{ + struct compat_threaded_irq *comp = dev_id; + irqreturn_t res; + + res = comp->handler(irq, comp->dev_id); + if (res == IRQ_WAKE_THREAD) { + queue_work(comp->wq, &comp->work); + res = IRQ_HANDLED; + } + + return res; +} + +static inline +int compat_request_threaded_irq(struct compat_threaded_irq *comp, + unsigned int irq, + irq_handler_t handler, + irq_handler_t thread_fn, + unsigned long flags, + const char *name, + void *dev_id) +{ + comp->irq = irq; + comp->handler = handler; + comp->thread_fn = thread_fn; + comp->dev_id = dev_id; + INIT_WORK(&comp->work, compat_irq_work); + + if (!comp->wq) { + snprintf(comp->wq_name, sizeof(comp->wq_name), + "compirq/%u-%s", irq, name); + comp->wq = create_singlethread_workqueue(comp->wq_name); + if (!comp->wq) { + printk(KERN_ERR "Failed to create compat-threaded-IRQ workqueue %s\n", + comp->wq_name); + return -ENOMEM; + } + } + return request_irq(irq, compat_irq_dispatcher, flags, name, comp); +} + +static inline +void compat_free_threaded_irq(struct compat_threaded_irq *comp) +{ + free_irq(comp->irq, comp); +} + +static inline +void compat_destroy_threaded_irq(struct compat_threaded_irq *comp) +{ + if (comp->wq) + destroy_workqueue(comp->wq); + comp->wq = NULL; +} + +static inline +void compat_synchronize_threaded_irq(struct compat_threaded_irq *comp) +{ + synchronize_irq(comp->irq); + cancel_work_sync(&comp->work); +} + + #endif /* (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)) */ #endif /* LINUX_26_31_COMPAT_H */ diff --git a/compat/patches/09-threaded-irq.patch b/compat/patches/09-threaded-irq.patch new file mode 100644 index 000000000000..e6daa151a14b --- /dev/null +++ b/compat/patches/09-threaded-irq.patch @@ -0,0 +1,63 @@ +The 2.6.31 kernel has threaded IRQ support and b43 is the first +wireless driver that makes use of it. To support threaded IRSs +on older kernels we built our own struct compat_threaded_irq +to queue_work() onto it as the kernel thread be running the +thread in process context as well. + +--- a/drivers/net/wireless/b43/main.c 2009-09-23 10:17:44.852134031 -0700 ++++ b/drivers/net/wireless/b43/main.c 2009-09-23 10:21:45.887734082 -0700 +@@ -3908,8 +3908,13 @@ redo: + if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) { + b43_sdio_free_irq(dev); + } else { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) ++ compat_synchronize_threaded_irq(&dev->irq_compat); ++ compat_free_threaded_irq(&dev->irq_compat); ++#else + synchronize_irq(dev->dev->irq); + free_irq(dev->dev->irq, dev); ++#endif + } + mutex_lock(&wl->mutex); + dev = wl->current_dev; +@@ -3948,9 +3953,17 @@ static int b43_wireless_core_start(struc + goto out; + } + } else { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) + err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler, + b43_interrupt_thread_handler, + IRQF_SHARED, KBUILD_MODNAME, dev); ++#else ++ err = compat_request_threaded_irq(&dev->irq_compat, ++ dev->dev->irq, ++ b43_interrupt_handler, ++ b43_interrupt_thread_handler, ++ IRQF_SHARED, KBUILD_MODNAME, dev); ++#endif + if (err) { + b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq); + goto out; +@@ -4656,6 +4669,10 @@ static int b43_setup_bands(struct b43_wl + + static void b43_wireless_core_detach(struct b43_wldev *dev) + { ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) ++ if (dev->dev->bus->bustype != SSB_BUSTYPE_SDIO) ++ compat_destroy_threaded_irq(&dev->irq_compat); ++#endif + /* We release firmware that late to not be required to re-request + * is all the time when we reinit the core. */ + b43_release_firmware(dev); +--- a/drivers/net/wireless/b43/b43.h 2009-09-23 10:17:59.383718279 -0700 ++++ b/drivers/net/wireless/b43/b43.h 2009-09-23 10:22:17.127771634 -0700 +@@ -822,6 +822,9 @@ struct b43_wldev { + unsigned int tx_count; + unsigned int rx_count; + #endif ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31) ++ struct compat_threaded_irq irq_compat; ++#endif + }; + + static inline struct b43_wl *hw_to_b43_wl(struct ieee80211_hw *hw) -- 2.30.2