--- 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 #include +#include + #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;