Commit 708971e4 authored by Greg Kroah-Hartman's avatar Greg Kroah-Hartman

greybus: operation: make the timeout a per-operation thing, not per-connection

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: default avatarGreg Kroah-Hartman <greg@kroah.com>
parent 4afbba07
...@@ -102,15 +102,6 @@ static void gb_connection_hd_cport_id_free(struct gb_connection *connection) ...@@ -102,15 +102,6 @@ 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");
}
static ssize_t state_show(struct device *dev, struct device_attribute *attr, static ssize_t state_show(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
...@@ -207,7 +198,6 @@ struct gb_connection *gb_connection_create(struct gb_interface *interface, ...@@ -207,7 +198,6 @@ 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;
} }
......
...@@ -36,7 +36,6 @@ struct gb_connection { ...@@ -36,7 +36,6 @@ 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,7 +19,7 @@ ...@@ -19,7 +19,7 @@
*/ */
#define GB_OPERATION_TYPE_RESPONSE 0x80 #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 * XXX This needs to be coordinated with host driver parameters
...@@ -105,29 +105,25 @@ static void gb_operation_insert(struct gb_operation *operation) ...@@ -105,29 +105,25 @@ static void gb_operation_insert(struct gb_operation *operation)
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); timeout = msecs_to_jiffies(OPERATION_TIMEOUT_DEFAULT);
if (start_timer) if (start_timer)
schedule_delayed_work(&connection->timeout_work, timeout); schedule_delayed_work(&operation->timeout_work, timeout);
else 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) static void gb_operation_remove(struct gb_operation *operation)
{ {
struct gb_connection *connection = operation->connection; 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); spin_lock_irq(&gb_operations_lock);
rb_erase(&operation->node, &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 *
...@@ -159,7 +155,7 @@ gb_operation_find(struct gb_connection *connection, u16 id) ...@@ -159,7 +155,7 @@ gb_operation_find(struct gb_connection *connection, u16 id)
* any waiters. Otherwise we assume calling the completion is enough * any waiters. Otherwise we assume calling the completion is enough
* and nobody else will be waiting. * 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) if (operation->callback)
operation->callback(operation); operation->callback(operation);
...@@ -247,6 +243,24 @@ static void gb_operation_recv_work(struct work_struct *recv_work) ...@@ -247,6 +243,24 @@ static void gb_operation_recv_work(struct work_struct *recv_work)
greybus_gbuf_finished(operation->response); 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 * Buffer completion function. We get notified whenever any buffer
* completes. For outbound messages, this tells us that the message * completes. For outbound messages, this tells us that the message
...@@ -376,6 +390,7 @@ struct gb_operation *gb_operation_create(struct gb_connection *connection, ...@@ -376,6 +390,7 @@ struct gb_operation *gb_operation_create(struct gb_connection *connection,
INIT_WORK(&operation->recv_work, gb_operation_recv_work); INIT_WORK(&operation->recv_work, gb_operation_recv_work);
operation->callback = NULL; /* set at submit time */ operation->callback = NULL; /* set at submit time */
init_completion(&operation->completion); init_completion(&operation->completion);
INIT_DELAYED_WORK(&operation->timeout_work, operation_timeout);
spin_lock_irq(&gb_operations_lock); spin_lock_irq(&gb_operations_lock);
list_add_tail(&operation->links, &connection->operations); list_add_tail(&operation->links, &connection->operations);
......
...@@ -18,6 +18,7 @@ enum gb_operation_status { ...@@ -18,6 +18,7 @@ enum gb_operation_status {
GB_OP_INTERRUPTED = 3, GB_OP_INTERRUPTED = 3,
GB_OP_RETRY = 4, GB_OP_RETRY = 4,
GB_OP_PROTOCOL_BAD = 5, GB_OP_PROTOCOL_BAD = 5,
GB_OP_TIMEOUT = 0xff,
}; };
/* /*
...@@ -61,6 +62,7 @@ struct gb_operation { ...@@ -61,6 +62,7 @@ struct gb_operation {
struct work_struct recv_work; struct work_struct recv_work;
gb_operation_callback callback; /* If asynchronous */ gb_operation_callback callback; /* If asynchronous */
struct completion completion; /* Used if no callback */ struct completion completion; /* Used if no callback */
struct delayed_work timeout_work;
struct list_head links; /* connection->operations */ struct list_head links; /* connection->operations */
struct rb_node node; /* connection->pending */ struct rb_node node; /* connection->pending */
...@@ -84,7 +86,6 @@ int gb_operation_response_send(struct gb_operation *operation); ...@@ -84,7 +86,6 @@ int gb_operation_response_send(struct gb_operation *operation);
void gb_operation_cancel(struct gb_operation *operation); void gb_operation_cancel(struct gb_operation *operation);
int gb_operation_wait(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); int gb_operation_init(void);
void gb_operation_exit(void); void gb_operation_exit(void);
......
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