From e1158df0634ab771297fc7510dd78bcbe83e8c87 Mon Sep 17 00:00:00 2001 From: Alex Elder Date: Wed, 22 Oct 2014 02:04:29 -0500 Subject: [PATCH] greybus: define operation_cancel() Define a new function operation_cancel() that cancels an outstanding operation. Use it to clear out any operations that might be pending at the time a connection is torn down. Note: This code isn't really functional yet, partially because greybus_kill_gbuf() is not implemented. Signed-off-by: Alex Elder Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/connection.c | 7 +++++++ drivers/staging/greybus/operation.c | 18 ++++++++++++++++++ drivers/staging/greybus/operation.h | 2 ++ 3 files changed, 27 insertions(+) diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c index 368f05662e3d..9bcda993685a 100644 --- a/drivers/staging/greybus/connection.c +++ b/drivers/staging/greybus/connection.c @@ -162,12 +162,19 @@ struct gb_connection *gb_connection_create(struct gb_interface *interface, */ void gb_connection_destroy(struct gb_connection *connection) { + struct gb_operation *operation; + struct gb_operation *next; + if (WARN_ON(!connection)) return; /* XXX Need to wait for any outstanding requests to complete */ WARN_ON(!list_empty(&connection->operations)); + list_for_each_entry_safe(operation, next, &connection->operations, + links) { + gb_operation_cancel(operation); + } spin_lock_irq(&gb_connections_lock); list_del(&connection->interface_links); _gb_hd_connection_remove(connection); diff --git a/drivers/staging/greybus/operation.c b/drivers/staging/greybus/operation.c index e70e8a3faeae..afb42d5e1941 100644 --- a/drivers/staging/greybus/operation.c +++ b/drivers/staging/greybus/operation.c @@ -501,6 +501,24 @@ void gb_connection_operation_recv(struct gb_connection *connection, queue_work(gb_operation_recv_workqueue, &operation->recv_work); } +/* + * Cancel an operation. + */ +void gb_operation_cancel(struct gb_operation *operation) +{ + int ret; + + operation->canceled = true; + ret = greybus_kill_gbuf(operation->request); + if (ret) + pr_warn("error %d killing request gbuf\n", ret); + if (operation->response) { + ret = greybus_kill_gbuf(operation->response); + if (ret) + pr_warn("error %d killing response gbuf\n", ret); + } +} + int gb_operation_init(void) { gb_operation_cache = kmem_cache_create("gb_operation_cache", diff --git a/drivers/staging/greybus/operation.h b/drivers/staging/greybus/operation.h index 59aad3a38d17..1a8e6b94cb08 100644 --- a/drivers/staging/greybus/operation.h +++ b/drivers/staging/greybus/operation.h @@ -55,6 +55,7 @@ struct gb_operation { struct gbuf *request; struct gbuf *response; u16 id; + bool canceled; u8 result; struct work_struct recv_work; @@ -81,6 +82,7 @@ int gb_operation_request_send(struct gb_operation *operation, gb_operation_callback callback); 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);