blob: eee33ddd619d42227722c3724f0c0e5b44d8ce17 [file] [log] [blame]
--- 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, &param));
+ 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;