]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
greybus: embed workqueue structure in struct gbuf
authorAlex Elder <elder@linaro.org>
Tue, 23 Sep 2014 17:46:36 +0000 (12:46 -0500)
committerGreg Kroah-Hartman <greg@kroah.com>
Wed, 24 Sep 2014 03:58:00 +0000 (20:58 -0700)
A Greybus buffer containing outbound data is submitted to to the
underlying driver to be sent over a CPort.  Sending that data could
be deferred, so the submit operation completes asynchronously.  When
the send is done, a callback occurs, and the buffer is "completed",
and the buffer's completion routine is called.  The buffer is then
freed.

If data arrives on the CPort, greybus_cport_in_data() is called
to allocate a Greybus buffer and copy the received data into it.
Once that's done the buffer is completed, again allowing the
buffer's completion routine to finish any final tasks before
freeing the buffer.

We use a workqueue to schedule calling the buffer's completion
function.  This patch does two things related to the work queue:
    - Renames the work queue "gbuf_workqueue" so its name more
      directly describes its purpose
    - Moves the work_struct needed for scheduling completions
      into the struct greybuf.  Previously a separate type
      was used, and dynamically allocated *at interrupt time*
      to hold this work_struct.  We can now do away with that.

Signed-off-by: Alex Elder <elder@linaro.org>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
drivers/staging/greybus/gbuf.c
drivers/staging/greybus/greybus.h

index 5655721bb397d9e635e65bf2b403cb99c66cead9..b51bd2ad66ec7ee5f98eff8f5aa82b31643142b0 100644 (file)
 
 #include "greybus.h"
 
+static void cport_process_event(struct work_struct *work);
 
 static struct kmem_cache *gbuf_head_cache;
 
+/* Workqueue to handle Greybus buffer completions. */
+static struct workqueue_struct *gbuf_workqueue;
+
 static struct gbuf *__alloc_gbuf(struct greybus_module *gmod,
                                struct gmod_cport *cport,
                                gbuf_complete_t complete,
@@ -37,6 +41,7 @@ static struct gbuf *__alloc_gbuf(struct greybus_module *gmod,
        kref_init(&gbuf->kref);
        gbuf->gmod = gmod;
        gbuf->cport = cport;
+       INIT_WORK(&gbuf->event, cport_process_event);
        gbuf->complete = complete;
        gbuf->context = context;
 
@@ -129,41 +134,13 @@ int greybus_kill_gbuf(struct gbuf *gbuf)
        return -ENOMEM;
 }
 
-struct cport_msg {
-       struct gbuf *gbuf;
-       struct work_struct event;
-};
-
-static struct workqueue_struct *cport_workqueue;
-
 static void cport_process_event(struct work_struct *work)
 {
-       struct cport_msg *cm;
-       struct gbuf *gbuf;
-
-       cm = container_of(work, struct cport_msg, event);
-
-       gbuf = cm->gbuf;
-
-       /* call the gbuf handler */
-       gbuf->complete(gbuf);
-
-       /* free all the memory */
-       greybus_free_gbuf(gbuf);
-       kfree(cm);
-}
-
-static void cport_create_event(struct gbuf *gbuf)
-{
-       struct cport_msg *cm;
-
-       /* Slow alloc, does it matter??? */
-       cm = kmalloc(sizeof(*cm), GFP_ATOMIC);
+       struct gbuf *gbuf = container_of(work, struct gbuf, event);
 
-       /* Queue up the cport message to be handled in user context */
-       cm->gbuf = gbuf;
-       INIT_WORK(&cm->event, cport_process_event);
-       queue_work(cport_workqueue, &cm->event);
+       /* Call the completion handler, then drop our reference */
+       gbuf->complete(gbuf);
+       greybus_put_gbuf(gbuf);
 }
 
 #define MAX_CPORTS     1024
@@ -237,21 +214,21 @@ void greybus_cport_in_data(struct greybus_host_device *hd, int cport, u8 *data,
        gbuf->transfer_buffer_length = length;
        gbuf->actual_length = length;
 
-       cport_create_event(gbuf);
+       queue_work(gbuf_workqueue, &gbuf->event);
 }
 EXPORT_SYMBOL_GPL(greybus_cport_in_data);
 
 /* Can be called in interrupt context, do the work and get out of here */
 void greybus_gbuf_finished(struct gbuf *gbuf)
 {
-       cport_create_event(gbuf);
+       queue_work(gbuf_workqueue, &gbuf->event);
 }
 EXPORT_SYMBOL_GPL(greybus_gbuf_finished);
 
 int gb_gbuf_init(void)
 {
-       cport_workqueue = alloc_workqueue("greybus_gbuf", 0, 1);
-       if (!cport_workqueue)
+       gbuf_workqueue = alloc_workqueue("greybus_gbuf", 0, 1);
+       if (!gbuf_workqueue)
                return -ENOMEM;
 
        gbuf_head_cache = kmem_cache_create("gbuf_head_cache",
@@ -261,6 +238,6 @@ int gb_gbuf_init(void)
 
 void gb_gbuf_exit(void)
 {
-       destroy_workqueue(cport_workqueue);
+       destroy_workqueue(gbuf_workqueue);
        kmem_cache_destroy(gbuf_head_cache);
 }
index 59f9b980c6fc0bf86ec0c872c312070128e48ad0..692a5b9bf797350e7f75153c10ffe0f7675d411a 100644 (file)
@@ -133,6 +133,7 @@ struct gbuf {
        unsigned int    direction : 1;  /* 0 is out, 1 is in */
 
        void *context;
+       struct work_struct event;
        gbuf_complete_t complete;
 };