backports: cw1200 utilizes kthreads for <= 2.6.35
authorSolomon Peachy <pizza@shaftnet.org>
Sat, 17 Aug 2013 13:02:58 +0000 (09:02 -0400)
committerLuis R. Rodriguez <mcgrof@do-not-panic.com>
Tue, 27 Aug 2013 18:15:28 +0000 (11:15 -0700)
The new workqueue APIs in 2.6.36 allowed us to scrap the old kthread worker
that had been used; unfortunately the backported API isn't complete so
in order to support older kernels, resurrect this patch.

Signed-off-by: Solomon Peachy <pizza@shaftnet.org>
Signed-off-by: Luis R. Rodriguez <mcgrof@do-not-panic.com>
patches/collateral-evolutions/network/75-cw1200-workqueues/cw1200_workqueues.patch [new file with mode: 0644]

diff --git a/patches/collateral-evolutions/network/75-cw1200-workqueues/cw1200_workqueues.patch b/patches/collateral-evolutions/network/75-cw1200-workqueues/cw1200_workqueues.patch
new file mode 100644 (file)
index 0000000..3bf3197
--- /dev/null
@@ -0,0 +1,133 @@
+diff --git a/drivers/net/wireless/cw1200/bh.c b/drivers/net/wireless/cw1200/bh.c
+index c1ec2a4..5dcbb4e 100644
+--- 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_common *priv)
+               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_common *priv)
+       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;
+ }
+diff --git a/drivers/net/wireless/cw1200/cw1200.h b/drivers/net/wireless/cw1200/cw1200.h
+index 1ad7d36..300dbbb 100644
+--- 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;