]> git.karo-electronics.de Git - linux-beck.git/commitdiff
greybus: connection: add helper to disable incoming operations
authorJohan Hovold <johan@hovoldconsulting.com>
Tue, 19 Jan 2016 11:51:08 +0000 (12:51 +0100)
committerGreg Kroah-Hartman <gregkh@google.com>
Tue, 19 Jan 2016 20:12:40 +0000 (12:12 -0800)
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>
drivers/staging/greybus/connection.c
drivers/staging/greybus/connection.h

index 8ae099d20b48e46bd2e3540671cb5d6cf35bc6dc..c3207c828a450ce1acf4ce4b38da712e59e54299 100644 (file)
@@ -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);
index ab2556d812731f9bc01e93755f9b9b752c87b447..8813f54eab9209001c93d5f5013586e9c551f276 100644 (file)
@@ -75,6 +75,7 @@ static inline int gb_connection_enable_tx(struct gb_connection *connection)
 {
        return gb_connection_enable(connection, NULL);
 }
+void gb_connection_disable_rx(struct gb_connection *connection);
 void gb_connection_disable(struct gb_connection *connection);
 
 int gb_connection_legacy_init(struct gb_connection *connection);