greybus: connection: add unidirectional enabled state
authorJohan Hovold <johan@hovoldconsulting.com>
Tue, 19 Jan 2016 11:51:07 +0000 (12:51 +0100)
committerGreg Kroah-Hartman <gregkh@google.com>
Tue, 19 Jan 2016 20:12:40 +0000 (12:12 -0800)
Add a new connection state ENABLED_TX in which only outgoing operations
are allowed.

This allows drivers to query the device during probe before allocating
their state containers without having to worry about racing incoming
requests.

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
drivers/staging/greybus/operation.c

index 56588f357b208658ab0d747a9c8b855b89e021ff..8ae099d20b48e46bd2e3540671cb5d6cf35bc6dc 100644 (file)
@@ -396,6 +396,18 @@ int gb_connection_enable(struct gb_connection *connection,
        if (connection->state == GB_CONNECTION_STATE_ENABLED)
                goto out_unlock;
 
+       if (connection->state == GB_CONNECTION_STATE_ENABLED_TX) {
+               if (!handler)
+                       goto out_unlock;
+
+               spin_lock_irq(&connection->lock);
+               connection->handler = handler;
+               connection->state = GB_CONNECTION_STATE_ENABLED;
+               spin_unlock_irq(&connection->lock);
+
+               goto out_unlock;
+       }
+
        ret = gb_connection_hd_cport_enable(connection);
        if (ret)
                goto err_unlock;
@@ -406,7 +418,10 @@ int gb_connection_enable(struct gb_connection *connection,
 
        spin_lock_irq(&connection->lock);
        connection->handler = handler;
-       connection->state = GB_CONNECTION_STATE_ENABLED;
+       if (handler)
+               connection->state = GB_CONNECTION_STATE_ENABLED;
+       else
+               connection->state = GB_CONNECTION_STATE_ENABLED_TX;
        spin_unlock_irq(&connection->lock);
 
        ret = gb_connection_control_connected(connection);
@@ -422,6 +437,7 @@ err_svc_destroy:
        spin_lock_irq(&connection->lock);
        connection->state = GB_CONNECTION_STATE_DISABLED;
        gb_connection_cancel_operations(connection, -ESHUTDOWN);
+       connection->handler = NULL;
        spin_unlock_irq(&connection->lock);
 
        gb_connection_svc_connection_destroy(connection);
@@ -446,6 +462,7 @@ void gb_connection_disable(struct gb_connection *connection)
        spin_lock_irq(&connection->lock);
        connection->state = GB_CONNECTION_STATE_DISABLED;
        gb_connection_cancel_operations(connection, -ESHUTDOWN);
+       connection->handler = NULL;
        spin_unlock_irq(&connection->lock);
 
        gb_connection_svc_connection_destroy(connection);
index e7c6feb76e805d75b286a132960a358c1ebe4695..ab2556d812731f9bc01e93755f9b9b752c87b447 100644 (file)
@@ -16,7 +16,8 @@
 enum gb_connection_state {
        GB_CONNECTION_STATE_INVALID     = 0,
        GB_CONNECTION_STATE_DISABLED    = 1,
-       GB_CONNECTION_STATE_ENABLED     = 2,
+       GB_CONNECTION_STATE_ENABLED_TX  = 2,
+       GB_CONNECTION_STATE_ENABLED     = 3,
 };
 
 struct gb_operation;
@@ -70,6 +71,10 @@ static inline bool gb_connection_is_static(struct gb_connection *connection)
 
 int gb_connection_enable(struct gb_connection *connection,
                                        gb_request_handler_t handler);
+static inline int gb_connection_enable_tx(struct gb_connection *connection)
+{
+       return gb_connection_enable(connection, NULL);
+}
 void gb_connection_disable(struct gb_connection *connection);
 
 int gb_connection_legacy_init(struct gb_connection *connection);
index 4dc79cb12397a5b65aaf791fe7ce60be6a9dd5d7..d6b3d1f22b281a17e81f32796889a6fdf0e57cd7 100644 (file)
@@ -47,7 +47,9 @@ static int gb_operation_get_active(struct gb_operation *operation)
 
        spin_lock_irqsave(&connection->lock, flags);
 
-       if (connection->state != GB_CONNECTION_STATE_ENABLED) {
+       if (connection->state != GB_CONNECTION_STATE_ENABLED &&
+                       connection->state != GB_CONNECTION_STATE_ENABLED_TX &&
+                       !gb_operation_is_incoming(operation)) {
                spin_unlock_irqrestore(&connection->lock, flags);
                return -ENOTCONN;
        }
@@ -906,7 +908,8 @@ void gb_connection_recv(struct gb_connection *connection,
        size_t msg_size;
        u16 operation_id;
 
-       if (connection->state != GB_CONNECTION_STATE_ENABLED) {
+       if (connection->state != GB_CONNECTION_STATE_ENABLED &&
+               connection->state != GB_CONNECTION_STATE_ENABLED_TX) {
                dev_warn(dev, "%s: dropping %zu received bytes\n",
                                connection->name, size);
                return;