summaryrefslogtreecommitdiffstats
path: root/drivers/staging/greybus/connection.c
diff options
context:
space:
mode:
authorJohan Hovold2016-01-19 12:51:08 +0100
committerGreg Kroah-Hartman2016-01-19 21:12:40 +0100
commitbeb6b7fede005ae351619b30a8940a04e797b9b2 (patch)
treeb54e4842189220b612418df73f3bfb3c2decbfaa /drivers/staging/greybus/connection.c
parentgreybus: connection: add unidirectional enabled state (diff)
downloadkernel-qcow2-linux-beb6b7fede005ae351619b30a8940a04e797b9b2.tar.gz
kernel-qcow2-linux-beb6b7fede005ae351619b30a8940a04e797b9b2.tar.xz
kernel-qcow2-linux-beb6b7fede005ae351619b30a8940a04e797b9b2.zip
greybus: connection: add helper to disable incoming operations
Add helper to disable and flush incoming operations. This is intended to be used by core to flush any incoming requests before calling driver disconnect, but could potentially later be exported for driver use as well. Note that we currently flush all incoming operation and allow the request handlers to run, but cancel any responses sent. This may need to be refined later. Reviewed-by: Viresh Kumar <viresh.kumar@linaro.org> Signed-off-by: Johan Hovold <johan@hovoldconsulting.com> Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
Diffstat (limited to 'drivers/staging/greybus/connection.c')
-rw-r--r--drivers/staging/greybus/connection.c54
1 files changed, 54 insertions, 0 deletions
diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c
index 8ae099d20b48..c3207c828a45 100644
--- a/drivers/staging/greybus/connection.c
+++ b/drivers/staging/greybus/connection.c
@@ -386,6 +386,42 @@ static void gb_connection_cancel_operations(struct gb_connection *connection,
}
}
+/*
+ * Cancel all active incoming operations on a connection.
+ *
+ * Locking: Called with connection lock held and state set to ENABLED_TX.
+ */
+static void
+gb_connection_flush_incoming_operations(struct gb_connection *connection,
+ int errno)
+{
+ struct gb_operation *operation;
+ bool incoming;
+
+ while (!list_empty(&connection->operations)) {
+ incoming = false;
+ list_for_each_entry(operation, &connection->operations,
+ links) {
+ if (gb_operation_is_incoming(operation)) {
+ gb_operation_get(operation);
+ incoming = true;
+ break;
+ }
+ }
+
+ if (!incoming)
+ break;
+
+ spin_unlock_irq(&connection->lock);
+
+ /* FIXME: flush, not cancel? */
+ gb_operation_cancel_incoming(operation, errno);
+ gb_operation_put(operation);
+
+ spin_lock_irq(&connection->lock);
+ }
+}
+
int gb_connection_enable(struct gb_connection *connection,
gb_request_handler_t handler)
{
@@ -450,6 +486,24 @@ err_unlock:
}
EXPORT_SYMBOL_GPL(gb_connection_enable);
+void gb_connection_disable_rx(struct gb_connection *connection)
+{
+ mutex_lock(&connection->mutex);
+
+ spin_lock_irq(&connection->lock);
+ if (connection->state != GB_CONNECTION_STATE_ENABLED) {
+ spin_unlock_irq(&connection->lock);
+ goto out_unlock;
+ }
+ connection->state = GB_CONNECTION_STATE_ENABLED_TX;
+ gb_connection_flush_incoming_operations(connection, -ESHUTDOWN);
+ connection->handler = NULL;
+ spin_unlock_irq(&connection->lock);
+
+out_unlock:
+ mutex_unlock(&connection->mutex);
+}
+
void gb_connection_disable(struct gb_connection *connection)
{
mutex_lock(&connection->mutex);