From 2e353685bf0e523505695f8339316b0536474ea4 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Tue, 23 Sep 2014 12:46:36 -0500 Subject: [PATCH] greybus: embed workqueue structure in struct gbuf 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 Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/gbuf.c | 51 +++++++++++---------------------------- drivers/staging/greybus/greybus.h | 1 + 2 files changed, 15 insertions(+), 37 deletions(-) diff --git a/drivers/staging/greybus/gbuf.c b/drivers/staging/greybus/gbuf.c index 5655721b..b51bd2a 100644 --- a/drivers/staging/greybus/gbuf.c +++ b/drivers/staging/greybus/gbuf.c @@ -19,9 +19,13 @@ #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); } diff --git a/drivers/staging/greybus/greybus.h b/drivers/staging/greybus/greybus.h index 59f9b98..692a5b9 100644 --- a/drivers/staging/greybus/greybus.h +++ b/drivers/staging/greybus/greybus.h @@ -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; }; -- 2.7.4