| --- a/drivers/net/wireless/cw1200/bh.c |
| +++ b/drivers/net/wireless/cw1200/bh.c |
| @@ -48,16 +48,22 @@ enum cw1200_bh_pm_state { |
| typedef int (*cw1200_wsm_handler)(struct cw1200_common *priv, |
| u8 *data, size_t size); |
| |
| +#ifndef CW1200_USE_COMPAT_KTHREAD |
| static void cw1200_bh_work(struct work_struct *work) |
| { |
| struct cw1200_common *priv = |
| container_of(work, struct cw1200_common, bh_work); |
| cw1200_bh(priv); |
| } |
| +#endif |
| |
| int cw1200_register_bh(struct cw1200_common *priv) |
| { |
| int err = 0; |
| +#ifdef CW1200_USE_COMPAT_KTHREAD |
| + struct sched_param param = { .sched_priority = 1 }; |
| + BUG_ON(priv->bh_thread); |
| +#else |
| /* Realtime workqueue */ |
| priv->bh_workqueue = alloc_workqueue("cw1200_bh", |
| WQ_MEM_RECLAIM | WQ_HIGHPRI |
| @@ -67,6 +73,7 @@ int cw1200_register_bh(struct cw1200_com |
| return -ENOMEM; |
| |
| INIT_WORK(&priv->bh_work, cw1200_bh_work); |
| +#endif |
| |
| pr_debug("[BH] register.\n"); |
| |
| @@ -81,20 +88,44 @@ int cw1200_register_bh(struct cw1200_com |
| init_waitqueue_head(&priv->bh_wq); |
| init_waitqueue_head(&priv->bh_evt_wq); |
| |
| +#ifdef CW1200_USE_COMPAT_KTHREAD |
| + priv->bh_thread = kthread_create(&cw1200_bh, priv, "cw1200_bh"); |
| + if (IS_ERR(priv->bh_thread)) { |
| + err = PTR_ERR(priv->bh_thread); |
| + priv->bh_thread = NULL; |
| + } else { |
| + WARN_ON(sched_setscheduler(priv->bh_thread, |
| + SCHED_FIFO, ¶m)); |
| + wake_up_process(priv->bh_thread); |
| + } |
| +#else |
| err = !queue_work(priv->bh_workqueue, &priv->bh_work); |
| WARN_ON(err); |
| +#endif |
| + |
| return err; |
| } |
| |
| void cw1200_unregister_bh(struct cw1200_common *priv) |
| { |
| +#ifdef CW1200_USE_COMPAT_KTHREAD |
| + struct task_struct *thread = priv->bh_thread; |
| + if (WARN_ON(!thread)) |
| + return; |
| +#endif |
| + |
| atomic_add(1, &priv->bh_term); |
| wake_up(&priv->bh_wq); |
| |
| +#ifdef CW1200_USE_COMPAT_KTHREAD |
| + kthread_stop(thread); |
| + priv->bh_thread = NULL; |
| +#else |
| flush_workqueue(priv->bh_workqueue); |
| |
| destroy_workqueue(priv->bh_workqueue); |
| priv->bh_workqueue = NULL; |
| +#endif |
| |
| pr_debug("[BH] unregistered.\n"); |
| } |
| @@ -614,6 +645,16 @@ static int cw1200_bh(void *arg) |
| pr_err("[BH] Fatal error, exiting.\n"); |
| priv->bh_error = 1; |
| /* TODO: schedule_work(recovery) */ |
| +#ifdef CW1200_USE_COMPAT_KTHREAD |
| + for (;;) { |
| + int status = wait_event_interruptible(priv->bh_wq, ({ |
| + term = atomic_xchg(&priv->bh_term, 0); |
| + (term); |
| + })); |
| + if (status || term) |
| + break; |
| + } |
| +#endif |
| } |
| return 0; |
| } |
| --- a/drivers/net/wireless/cw1200/cw1200.h |
| +++ b/drivers/net/wireless/cw1200/cw1200.h |
| @@ -23,12 +23,18 @@ |
| #include <linux/workqueue.h> |
| #include <net/mac80211.h> |
| |
| +#include <linux/version.h> |
| + |
| #include "queue.h" |
| #include "wsm.h" |
| #include "scan.h" |
| #include "txrx.h" |
| #include "pm.h" |
| |
| +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 36)) |
| +#define CW1200_USE_COMPAT_KTHREAD |
| +#endif |
| + |
| /* Forward declarations */ |
| struct hwbus_ops; |
| struct task_struct; |
| @@ -190,8 +196,12 @@ struct cw1200_common { |
| atomic_t bh_term; |
| atomic_t bh_suspend; |
| |
| +#ifdef CW1200_USE_COMPAT_KTHREAD |
| + struct task_struct *bh_thread; |
| +#else |
| struct workqueue_struct *bh_workqueue; |
| struct work_struct bh_work; |
| +#endif |
| |
| int bh_error; |
| wait_queue_head_t bh_wq; |