diff options
author | Johan Hovold <johan@kernel.org> | 2017-01-23 13:04:14 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2017-02-09 11:58:56 +0100 |
commit | dbec27298b0df86eaa6bc02e5df0ce55ec7d97f2 (patch) | |
tree | aaeae8679724ce4bdbe08e94e24b4660d0545ec9 /drivers/staging/greybus/operation.c | |
parent | a769f30c7bd7cf917eea05a2b448f3588a87d767 (diff) | |
download | linux-dbec27298b0df86eaa6bc02e5df0ce55ec7d97f2.tar.bz2 |
staging: greybus: operation: add generic timeout support
Add a struct timer_list to struct gb_operation and use that to implement
generic operation timeouts.
This simplifies the synchronous operation handling somewhat while also
providing a generic timeout mechanism that drivers can use for
asynchronous operations.
Signed-off-by: Johan Hovold <johan@kernel.org>
Acked-by: Bryan O'Donoghue <pure.logic@nexus-software.ie>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/greybus/operation.c')
-rw-r--r-- | drivers/staging/greybus/operation.c | 50 |
1 files changed, 36 insertions, 14 deletions
diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c index 0123109a1070..3023012808d9 100644 --- a/drivers/staging/greybus/operation.c +++ b/drivers/staging/greybus/operation.c @@ -273,18 +273,40 @@ static void gb_operation_request_handle(struct gb_operation *operation) static void gb_operation_work(struct work_struct *work) { struct gb_operation *operation; + int ret; operation = container_of(work, struct gb_operation, work); - if (gb_operation_is_incoming(operation)) + if (gb_operation_is_incoming(operation)) { gb_operation_request_handle(operation); - else + } else { + ret = del_timer_sync(&operation->timer); + if (!ret) { + /* Cancel request message if scheduled by timeout. */ + if (gb_operation_result(operation) == -ETIMEDOUT) + gb_message_cancel(operation->request); + } + operation->callback(operation); + } gb_operation_put_active(operation); gb_operation_put(operation); } +static void gb_operation_timeout(unsigned long arg) +{ + struct gb_operation *operation = (void *)arg; + + if (gb_operation_result_set(operation, -ETIMEDOUT)) { + /* + * A stuck request message will be cancelled from the + * workqueue. + */ + queue_work(gb_operation_completion_wq, &operation->work); + } +} + static void gb_operation_message_init(struct gb_host_device *hd, struct gb_message *message, u16 operation_id, size_t payload_size, u8 type) @@ -518,6 +540,9 @@ gb_operation_create_common(struct gb_connection *connection, u8 type, gfp_flags)) { goto err_request; } + + setup_timer(&operation->timer, gb_operation_timeout, + (unsigned long)operation); } operation->flags = op_flags; @@ -679,6 +704,7 @@ static void gb_operation_sync_callback(struct gb_operation *operation) * gb_operation_request_send() - send an operation request message * @operation: the operation to initiate * @callback: the operation completion callback + * @timeout: operation timeout in milliseconds, or zero for no timeout * @gfp: the memory flags to use for any allocations * * The caller has filled in any payload so the request message is ready to go. @@ -693,6 +719,7 @@ static void gb_operation_sync_callback(struct gb_operation *operation) */ int gb_operation_request_send(struct gb_operation *operation, gb_operation_callback callback, + unsigned int timeout, gfp_t gfp) { struct gb_connection *connection = operation->connection; @@ -742,6 +769,11 @@ int gb_operation_request_send(struct gb_operation *operation, if (ret) goto err_put_active; + if (timeout) { + operation->timer.expires = jiffies + msecs_to_jiffies(timeout); + add_timer(&operation->timer); + } + return 0; err_put_active: @@ -763,26 +795,16 @@ int gb_operation_request_send_sync_timeout(struct gb_operation *operation, unsigned int timeout) { int ret; - unsigned long timeout_jiffies; ret = gb_operation_request_send(operation, gb_operation_sync_callback, - GFP_KERNEL); + timeout, GFP_KERNEL); if (ret) return ret; - if (timeout) - timeout_jiffies = msecs_to_jiffies(timeout); - else - timeout_jiffies = MAX_SCHEDULE_TIMEOUT; - - ret = wait_for_completion_interruptible_timeout(&operation->completion, - timeout_jiffies); + ret = wait_for_completion_interruptible(&operation->completion); if (ret < 0) { /* Cancel the operation if interrupted */ gb_operation_cancel(operation, -ECANCELED); - } else if (ret == 0) { - /* Cancel the operation if op timed out */ - gb_operation_cancel(operation, -ETIMEDOUT); } return gb_operation_result(operation); |