diff --git a/drivers/staging/greybus/connection.c b/drivers/staging/greybus/connection.c index 3765aa87ef2d..0ec5b0dcc145 100644 --- a/drivers/staging/greybus/connection.c +++ b/drivers/staging/greybus/connection.c @@ -11,6 +11,10 @@ #include "greybus.h" +#define GB_CONNECTION_TS_KFIFO_ELEMENTS 2 +#define GB_CONNECTION_TS_KFIFO_LEN \ + (GB_CONNECTION_TS_KFIFO_ELEMENTS * sizeof(struct timeval)) + static DEFINE_SPINLOCK(gb_connections_lock); /* This is only used at initialization time; no locking is required. */ @@ -63,6 +67,29 @@ void greybus_data_rcvd(struct greybus_host_device *hd, u16 cport_id, } EXPORT_SYMBOL_GPL(greybus_data_rcvd); +void gb_connection_push_timestamp(struct gb_connection *connection) +{ + struct timeval tv; + + do_gettimeofday(&tv); + kfifo_in_locked(&connection->ts_kfifo, (void *)&tv, + sizeof(struct timeval), &connection->lock); +} +EXPORT_SYMBOL_GPL(gb_connection_push_timestamp); + +int gb_connection_pop_timestamp(struct gb_connection *connection, + struct timeval *tv) +{ + int retval; + + if (!kfifo_len(&connection->ts_kfifo)) + return -ENOMEM; + retval = kfifo_out_locked(&connection->ts_kfifo, (void *)tv, + sizeof(*tv), &connection->lock); + return retval; +} +EXPORT_SYMBOL_GPL(gb_connection_pop_timestamp); + static ssize_t state_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -102,6 +129,7 @@ static void gb_connection_release(struct device *dev) struct gb_connection *connection = to_gb_connection(dev); destroy_workqueue(connection->wq); + kfifo_free(&connection->ts_kfifo); kfree(connection); } @@ -222,6 +250,10 @@ gb_connection_create_range(struct greybus_host_device *hd, if (!connection->wq) goto err_free_connection; + if (kfifo_alloc(&connection->ts_kfifo, GB_CONNECTION_TS_KFIFO_LEN, + GFP_KERNEL)) + goto err_free_connection; + connection->dev.parent = parent; connection->dev.bus = &greybus_bus_type; connection->dev.type = &greybus_connection_type; @@ -238,7 +270,7 @@ gb_connection_create_range(struct greybus_host_device *hd, pr_err("failed to add connection device for cport 0x%04hx\n", cport_id); - goto err_free_connection; + goto err_free_kfifo; } spin_lock_irq(&gb_connections_lock); @@ -259,6 +291,8 @@ gb_connection_create_range(struct greybus_host_device *hd, return connection; +err_free_kfifo: + kfifo_free(&connection->ts_kfifo); err_free_connection: kfree(connection); err_remove_ida: diff --git a/drivers/staging/greybus/connection.h b/drivers/staging/greybus/connection.h index 0dbbc202e953..a26a48033fc6 100644 --- a/drivers/staging/greybus/connection.h +++ b/drivers/staging/greybus/connection.h @@ -11,6 +11,7 @@ #define __CONNECTION_H #include +#include enum gb_connection_state { GB_CONNECTION_STATE_INVALID = 0, @@ -42,6 +43,7 @@ struct gb_connection { struct list_head operations; struct workqueue_struct *wq; + struct kfifo ts_kfifo; atomic_t op_cycle; @@ -65,6 +67,9 @@ void gb_hd_connections_exit(struct greybus_host_device *hd); void greybus_data_rcvd(struct greybus_host_device *hd, u16 cport_id, u8 *data, size_t length); +void gb_connection_push_timestamp(struct gb_connection *connection); +int gb_connection_pop_timestamp(struct gb_connection *connection, + struct timeval *tv); void gb_connection_bind_protocol(struct gb_connection *connection);