Commit e816e374 authored by Alex Elder's avatar Alex Elder Committed by Greg Kroah-Hartman

greybus: time out operation requests

Arrange for operation requests that takke too long to time out.
At the moment, nothing happens when that occurs (other than a silly
message getting printed).  When the connection and operation and
interface and module code are cleaned up properly, this event should
most likely cause the affected module to get torn down.
Signed-off-by: default avatarAlex Elder <elder@linaro.org>
Signed-off-by: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 63e4a8ee
...@@ -102,6 +102,15 @@ static void gb_connection_hd_cport_id_free(struct gb_connection *connection) ...@@ -102,6 +102,15 @@ static void gb_connection_hd_cport_id_free(struct gb_connection *connection)
connection->hd_cport_id = CPORT_ID_BAD; 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");
}
/* /*
* Set up a Greybus connection, representing the bidirectional link * Set up a Greybus connection, representing the bidirectional link
* between a CPort on a (local) Greybus host device and a CPort on * between a CPort on a (local) Greybus host device and a CPort on
...@@ -143,6 +152,7 @@ struct gb_connection *gb_connection_create(struct gb_interface *interface, ...@@ -143,6 +152,7 @@ struct gb_connection *gb_connection_create(struct gb_interface *interface,
INIT_LIST_HEAD(&connection->operations); INIT_LIST_HEAD(&connection->operations);
connection->pending = RB_ROOT; connection->pending = RB_ROOT;
atomic_set(&connection->op_cycle, 0); atomic_set(&connection->op_cycle, 0);
INIT_DELAYED_WORK(&connection->timeout_work, connection_timeout);
return connection; return connection;
} }
......
...@@ -26,6 +26,7 @@ struct gb_connection { ...@@ -26,6 +26,7 @@ struct gb_connection {
struct list_head operations; struct list_head operations;
struct rb_root pending; /* awaiting reponse */ struct rb_root pending; /* awaiting reponse */
atomic_t op_cycle; atomic_t op_cycle;
struct delayed_work timeout_work;
void *private; void *private;
}; };
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
*/ */
#define GB_OPERATION_TYPE_RESPONSE 0x80 #define GB_OPERATION_TYPE_RESPONSE 0x80
#define CONNECTION_TIMEOUT_DEFAULT 1000 /* milliseconds */
/* /*
* XXX This needs to be coordinated with host driver parameters * XXX This needs to be coordinated with host driver parameters
*/ */
...@@ -62,6 +64,8 @@ static void gb_operation_insert(struct gb_operation *operation) ...@@ -62,6 +64,8 @@ static void gb_operation_insert(struct gb_operation *operation)
struct rb_node **link = &root->rb_node; struct rb_node **link = &root->rb_node;
struct rb_node *above = NULL; struct rb_node *above = NULL;
struct gb_operation_msg_hdr *header; struct gb_operation_msg_hdr *header;
unsigned long timeout;
bool start_timer;
__le16 wire_id; __le16 wire_id;
/* /*
...@@ -76,6 +80,16 @@ static void gb_operation_insert(struct gb_operation *operation) ...@@ -76,6 +80,16 @@ static void gb_operation_insert(struct gb_operation *operation)
/* OK, insert the operation into its connection's tree */ /* OK, insert the operation into its connection's tree */
spin_lock_irq(&gb_operations_lock); spin_lock_irq(&gb_operations_lock);
/*
* We impose a time limit for requests to complete. If
* there are no requests pending there is no need for a
* timer. So if this will be the only one in flight we'll
* need to start the timer. Otherwise we just update the
* existing one to give this request a full timeout period
* to complete.
*/
start_timer = RB_EMPTY_ROOT(root);
while (*link) { while (*link) {
struct gb_operation *other; struct gb_operation *other;
...@@ -89,15 +103,31 @@ static void gb_operation_insert(struct gb_operation *operation) ...@@ -89,15 +103,31 @@ static void gb_operation_insert(struct gb_operation *operation)
} }
rb_link_node(node, above, link); rb_link_node(node, above, link);
rb_insert_color(node, root); rb_insert_color(node, root);
spin_unlock_irq(&gb_operations_lock); spin_unlock_irq(&gb_operations_lock);
timeout = msecs_to_jiffies(CONNECTION_TIMEOUT_DEFAULT);
if (start_timer)
schedule_delayed_work(&connection->timeout_work, timeout);
else
mod_delayed_work(system_wq, &connection->timeout_work, timeout);
} }
static void gb_operation_remove(struct gb_operation *operation) static void gb_operation_remove(struct gb_operation *operation)
{ {
struct gb_connection *connection = operation->connection;
bool last_pending;
spin_lock_irq(&gb_operations_lock); spin_lock_irq(&gb_operations_lock);
rb_erase(&operation->node, &operation->connection->pending); rb_erase(&operation->node, &connection->pending);
last_pending = RB_EMPTY_ROOT(&connection->pending);
spin_unlock_irq(&gb_operations_lock); 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 * static struct gb_operation *
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment