summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorShaun Ruffell <sruffell@digium.com>2011-02-18 16:23:51 -0600
committerShaun Ruffell <sruffell@digium.com>2011-04-15 14:19:01 -0500
commit206b5d94576722df68efa61f295fbd91b9d974a4 (patch)
tree9a75a97861c4557a0e03da39c7949157bb586bc7
parenta4d29961bef675ce27239c8f862ce696d7cd394d (diff)
wctdm24xxp: Introduce bg_create/bg_join.
Since there are several operations on the wctdm24xxp driver during initialization that can take a significant amount of time, but which can run in parallel with other operations, this adds a generic facility for creating those tasks and waiting for the results. This will be used to identify and configure the modules in parallel. Signed-off-by: Shaun Ruffell <sruffell@digium.com>
-rw-r--r--drivers/dahdi/wctdm24xxp/base.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/drivers/dahdi/wctdm24xxp/base.c b/drivers/dahdi/wctdm24xxp/base.c
index f89bf3b..134358c 100644
--- a/drivers/dahdi/wctdm24xxp/base.c
+++ b/drivers/dahdi/wctdm24xxp/base.c
@@ -297,6 +297,101 @@ static inline __attribute_const__ int VPM_CMD_BYTE(int timeslot, int bit)
return ((((timeslot) & 0x3) * 3 + (bit)) * 7) + ((timeslot) >> 2);
}
+typedef int (*bg_work_func_t)(struct wctdm *wc, unsigned long data);
+
+struct bg {
+ struct workqueue_struct *wq;
+ struct work_struct work;
+ struct completion complete;
+ struct wctdm *wc;
+ bg_work_func_t fn;
+ unsigned long param;
+ int ret;
+};
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+static void bg_work_func(void *data)
+{
+ struct bg *bg = data;
+#else
+static void bg_work_func(struct work_struct *work)
+{
+ struct bg *bg = container_of(work, struct bg, work);
+#endif
+ bg->ret = bg->fn(bg->wc, bg->param);
+ complete(&bg->complete);
+}
+
+/**
+ * bg_create - Call a function running in a background thread.
+ * @wc: The board structure passed to fn
+ * @fn: The function to run in it's own thread.
+ * @parma: An extra parameter to pass to the fn.
+ *
+ * Returns NULL if the thread could not be created, otherwise a pointer to be
+ * passed to bg_join in order to get the return value.
+ *
+ * The function 'fn' will be run in a new thread. The return value is the
+ * return from the bg_join function.
+ *
+ * This would probably be best served by concurrency managed workqueues before
+ * merging, but this will at least work on the older kernels tht DAHDI
+ * supports.
+ */
+static struct bg *
+bg_create(struct wctdm *wc, bg_work_func_t fn, unsigned long param)
+{
+ struct bg *bg;
+
+ bg = kzalloc(sizeof(*bg), GFP_KERNEL);
+ if (!bg)
+ return NULL;
+
+ bg->wq = create_singlethread_workqueue("wctdm_bg");
+ if (!bg->wq) {
+ kfree(bg);
+ return NULL;
+ }
+
+ init_completion(&bg->complete);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
+ INIT_WORK(&bg->work, bg_work_func, bg);
+#else
+ INIT_WORK(&bg->work, bg_work_func);
+#endif
+
+ bg->wc = wc;
+ bg->fn = fn;
+ bg->param = param;
+
+ queue_work(bg->wq, &bg->work);
+
+ return bg;
+}
+
+/**
+ * bg_join - Wait for a background function to complete and get the result.
+ * @bg: Pointer returned from the bg_create call.
+ *
+ * Returns the result of the function passed to bg_create.
+ */
+static int bg_join(struct bg *bg)
+{
+ int ret = -ERESTARTSYS;
+
+ if (unlikely(!bg))
+ return -EINVAL;
+
+ while (ret)
+ ret = wait_for_completion_interruptible(&bg->complete);
+
+ ret = bg->ret;
+ destroy_workqueue(bg->wq);
+ kfree(bg);
+
+ return ret;
+}
+
static void
setchanconfig_from_state(struct vpmadt032 *vpm, int channel,
GpakChannelConfig_t *chanconfig)