From 708971e43c29d103c22409cf66b6213033518da3 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Mon, 27 Oct 2014 15:40:09 +0800 Subject: [PATCH] greybus: operation: make the timeout a per-operation thing, not per-connection An operation is what can timeout, not a connection itself. So notify the operation timedout, and the connection can then do with it as it sees fit, if necessary. Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/connection.c | 10 ------- drivers/staging/greybus/connection.h | 1 - drivers/staging/greybus/operation.c | 41 +++++++++++++++++++--------- drivers/staging/greybus/operation.h | 3 +- 4 files changed, 30 insertions(+), 25 deletions(-) diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c index 2d71679ff66c..bbae16346050 100644 --- a/drivers/staging/greybus/connection.c +++ b/drivers/staging/greybus/connection.c @@ -102,15 +102,6 @@ static void gb_connection_hd_cport_id_free(struct gb_connection *connection) connection->hd_cport_id = CPORT_ID_BAD; } -static void connection_timeout(struct work_struct *work) -{ - struct gb_connection *connection; - - connection = - container_of(work, struct gb_connection, timeout_work.work); - printk("timeout!\n"); -} - static ssize_t state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -207,7 +198,6 @@ struct gb_connection *gb_connection_create(struct gb_interface *interface, INIT_LIST_HEAD(&connection->operations); connection->pending = RB_ROOT; atomic_set(&connection->op_cycle, 0); - INIT_DELAYED_WORK(&connection->timeout_work, connection_timeout); return connection; } diff --git a/drivers/staging/greybus/connection.h b/drivers/staging/greybus/connection.h index 19dd91dae062..17fde8fa285d 100644 --- a/drivers/staging/greybus/connection.h +++ b/drivers/staging/greybus/connection.h @@ -36,7 +36,6 @@ struct gb_connection { struct list_head operations; struct rb_root pending; /* awaiting reponse */ atomic_t op_cycle; - struct delayed_work timeout_work; void *private; }; diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c index 9b889b169bf5..736c2c167f85 100644 --- a/drivers/staging/greybus/operation.c +++ b/drivers/staging/greybus/operation.c @@ -19,7 +19,7 @@ */ #define GB_OPERATION_TYPE_RESPONSE 0x80 -#define CONNECTION_TIMEOUT_DEFAULT 1000 /* milliseconds */ +#define OPERATION_TIMEOUT_DEFAULT 1000 /* milliseconds */ /* * XXX This needs to be coordinated with host driver parameters @@ -105,29 +105,25 @@ static void gb_operation_insert(struct gb_operation *operation) rb_insert_color(node, root); spin_unlock_irq(&gb_operations_lock); - timeout = msecs_to_jiffies(CONNECTION_TIMEOUT_DEFAULT); + timeout = msecs_to_jiffies(OPERATION_TIMEOUT_DEFAULT); if (start_timer) - schedule_delayed_work(&connection->timeout_work, timeout); + schedule_delayed_work(&operation->timeout_work, timeout); else - mod_delayed_work(system_wq, &connection->timeout_work, timeout); + mod_delayed_work(system_wq, &operation->timeout_work, timeout); } static void gb_operation_remove(struct gb_operation *operation) { struct gb_connection *connection = operation->connection; - bool last_pending; + /* Shut down our timeout timer */ + cancel_delayed_work(&operation->timeout_work); + + /* Take us off of the list of pending operations */ spin_lock_irq(&gb_operations_lock); rb_erase(&operation->node, &connection->pending); - last_pending = RB_EMPTY_ROOT(&connection->pending); spin_unlock_irq(&gb_operations_lock); - /* - * If there are no more pending requests, we can stop the - * timeout timer. - */ - if (last_pending) - cancel_delayed_work(&connection->timeout_work); } static struct gb_operation * @@ -159,7 +155,7 @@ gb_operation_find(struct gb_connection *connection, u16 id) * any waiters. Otherwise we assume calling the completion is enough * and nobody else will be waiting. */ -void gb_operation_complete(struct gb_operation *operation) +static void gb_operation_complete(struct gb_operation *operation) { if (operation->callback) operation->callback(operation); @@ -247,6 +243,24 @@ static void gb_operation_recv_work(struct work_struct *recv_work) greybus_gbuf_finished(operation->response); } +/* + * Timeout call for the operation. + * + * If this fires, something went wrong, so mark the result as timed out, and + * run the completion handler, which (hopefully) should clean up the operation + * properly. + */ +static void operation_timeout(struct work_struct *work) +{ + struct gb_operation *operation; + + operation = container_of(work, struct gb_operation, timeout_work.work); + printk("timeout!\n"); + + operation->result = GB_OP_TIMEOUT; + gb_operation_complete(operation); +} + /* * Buffer completion function. We get notified whenever any buffer * completes. For outbound messages, this tells us that the message @@ -376,6 +390,7 @@ struct gb_operation *gb_operation_create(struct gb_connection *connection, INIT_WORK(&operation->recv_work, gb_operation_recv_work); operation->callback = NULL; /* set at submit time */ init_completion(&operation->completion); + INIT_DELAYED_WORK(&operation->timeout_work, operation_timeout); spin_lock_irq(&gb_operations_lock); list_add_tail(&operation->links, &connection->operations); diff --git a/drivers/staging/greybus/operation.h b/drivers/staging/greybus/operation.h index 1a8e6b94cb08..965ad9c1aa8c 100644 --- a/drivers/staging/greybus/operation.h +++ b/drivers/staging/greybus/operation.h @@ -18,6 +18,7 @@ enum gb_operation_status { GB_OP_INTERRUPTED = 3, GB_OP_RETRY = 4, GB_OP_PROTOCOL_BAD = 5, + GB_OP_TIMEOUT = 0xff, }; /* @@ -61,6 +62,7 @@ struct gb_operation { struct work_struct recv_work; gb_operation_callback callback; /* If asynchronous */ struct completion completion; /* Used if no callback */ + struct delayed_work timeout_work; struct list_head links; /* connection->operations */ struct rb_node node; /* connection->pending */ @@ -84,7 +86,6 @@ int gb_operation_response_send(struct gb_operation *operation); void gb_operation_cancel(struct gb_operation *operation); int gb_operation_wait(struct gb_operation *operation); -void gb_operation_complete(struct gb_operation *operation); int gb_operation_init(void); void gb_operation_exit(void); -- 2.20.1