greybus: operation: make the timeout a per-operation thing, not per-connection
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 27 Oct 2014 07:40:09 +0000 (15:40 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 27 Oct 2014 07:40:09 +0000 (15:40 +0800)
An operation is what can timeout, not a connection itself.  So notify
the operation timedout, and the connection can then do with it as it
sees fit, if necessary.

Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
drivers/staging/greybus/connection.c
drivers/staging/greybus/connection.h
drivers/staging/greybus/operation.c
drivers/staging/greybus/operation.h

index 2d71679ff66cb66038c40e04ff9deadc952d6614..bbae1634605064929fba4d1618da39597a9b1526 100644 (file)
@@ -102,15 +102,6 @@ static void gb_connection_hd_cport_id_free(struct gb_connection *connection)
        connection->hd_cport_id = CPORT_ID_BAD;
 }
 
-static void connection_timeout(struct work_struct *work)
-{
-       struct gb_connection *connection;
-
-       connection =
-               container_of(work, struct gb_connection, timeout_work.work);
-       printk("timeout!\n");
-}
-
 static ssize_t state_show(struct device *dev, struct device_attribute *attr,
                          char *buf)
 {
@@ -207,7 +198,6 @@ struct gb_connection *gb_connection_create(struct gb_interface *interface,
        INIT_LIST_HEAD(&connection->operations);
        connection->pending = RB_ROOT;
        atomic_set(&connection->op_cycle, 0);
-       INIT_DELAYED_WORK(&connection->timeout_work, connection_timeout);
 
        return connection;
 }
index 19dd91dae0624137414e2d383040876c7b2d8cc4..17fde8fa285d48427b87a6c43587738ac457f012 100644 (file)
@@ -36,7 +36,6 @@ struct gb_connection {
        struct list_head                operations;
        struct rb_root                  pending;        /* awaiting reponse */
        atomic_t                        op_cycle;
-       struct delayed_work             timeout_work;
 
        void                            *private;
 };
index 9b889b169bf50a6915d5aafdf20fec0261f30305..736c2c167f855ef8b965036379bb58111e25040e 100644 (file)
@@ -19,7 +19,7 @@
  */
 #define GB_OPERATION_TYPE_RESPONSE     0x80
 
-#define CONNECTION_TIMEOUT_DEFAULT     1000    /* milliseconds */
+#define OPERATION_TIMEOUT_DEFAULT      1000    /* milliseconds */
 
 /*
  * XXX This needs to be coordinated with host driver parameters
@@ -105,29 +105,25 @@ static void gb_operation_insert(struct gb_operation *operation)
        rb_insert_color(node, root);
        spin_unlock_irq(&gb_operations_lock);
 
-       timeout = msecs_to_jiffies(CONNECTION_TIMEOUT_DEFAULT);
+       timeout = msecs_to_jiffies(OPERATION_TIMEOUT_DEFAULT);
        if (start_timer)
-               schedule_delayed_work(&connection->timeout_work, timeout);
+               schedule_delayed_work(&operation->timeout_work, timeout);
        else
-               mod_delayed_work(system_wq, &connection->timeout_work, timeout);
+               mod_delayed_work(system_wq, &operation->timeout_work, timeout);
 }
 
 static void gb_operation_remove(struct gb_operation *operation)
 {
        struct gb_connection *connection = operation->connection;
-       bool last_pending;
 
+       /* Shut down our timeout timer */
+       cancel_delayed_work(&operation->timeout_work);
+
+       /* Take us off of the list of pending operations */
        spin_lock_irq(&gb_operations_lock);
        rb_erase(&operation->node, &connection->pending);
-       last_pending = RB_EMPTY_ROOT(&connection->pending);
        spin_unlock_irq(&gb_operations_lock);
 
-       /*
-        * If there are no more pending requests, we can stop the
-        * timeout timer.
-        */
-       if (last_pending)
-               cancel_delayed_work(&connection->timeout_work);
 }
 
 static struct gb_operation *
@@ -159,7 +155,7 @@ gb_operation_find(struct gb_connection *connection, u16 id)
  * any waiters.  Otherwise we assume calling the completion is enough
  * and nobody else will be waiting.
  */
-void gb_operation_complete(struct gb_operation *operation)
+static void gb_operation_complete(struct gb_operation *operation)
 {
        if (operation->callback)
                operation->callback(operation);
@@ -247,6 +243,24 @@ static void gb_operation_recv_work(struct work_struct *recv_work)
                greybus_gbuf_finished(operation->response);
 }
 
+/*
+ * Timeout call for the operation.
+ *
+ * If this fires, something went wrong, so mark the result as timed out, and
+ * run the completion handler, which (hopefully) should clean up the operation
+ * properly.
+ */
+static void operation_timeout(struct work_struct *work)
+{
+       struct gb_operation *operation;
+
+       operation = container_of(work, struct gb_operation, timeout_work.work);
+       printk("timeout!\n");
+
+       operation->result = GB_OP_TIMEOUT;
+       gb_operation_complete(operation);
+}
+
 /*
  * Buffer completion function.  We get notified whenever any buffer
  * completes.  For outbound messages, this tells us that the message
@@ -376,6 +390,7 @@ struct gb_operation *gb_operation_create(struct gb_connection *connection,
        INIT_WORK(&operation->recv_work, gb_operation_recv_work);
        operation->callback = NULL;     /* set at submit time */
        init_completion(&operation->completion);
+       INIT_DELAYED_WORK(&operation->timeout_work, operation_timeout);
 
        spin_lock_irq(&gb_operations_lock);
        list_add_tail(&operation->links, &connection->operations);
index 1a8e6b94cb08dcfcc000d8999c75379df5744fc2..965ad9c1aa8c23b5c55ba073e16e1366ab2a9856 100644 (file)
@@ -18,6 +18,7 @@ enum gb_operation_status {
        GB_OP_INTERRUPTED       = 3,
        GB_OP_RETRY             = 4,
        GB_OP_PROTOCOL_BAD      = 5,
+       GB_OP_TIMEOUT           = 0xff,
 };
 
 /*
@@ -61,6 +62,7 @@ struct gb_operation {
        struct work_struct      recv_work;
        gb_operation_callback   callback;       /* If asynchronous */
        struct completion       completion;     /* Used if no callback */
+       struct delayed_work     timeout_work;
 
        struct list_head        links;          /* connection->operations */
        struct rb_node          node;           /* connection->pending */
@@ -84,7 +86,6 @@ 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);
 
 int gb_operation_init(void);
 void gb_operation_exit(void);