summaryrefslogtreecommitdiff
path: root/lwis_fence.c
diff options
context:
space:
mode:
authorGe Bian <bian@google.com>2022-04-27 21:13:32 -0700
committerGe Bian <bian@google.com>2022-05-04 18:59:08 -0700
commit8184d61b777888730df8f6417408b4301ff61dca (patch)
tree77b7596c68b6daa918cacbef2b2b3e6a0521a3a7 /lwis_fence.c
parent590d3818f98cd42b3b2d4c67c3ca8a90fd89075e (diff)
downloadlwis-8184d61b777888730df8f6417408b4301ff61dca.tar.gz
LWIS: Support submitting transaction triggered by a lwis_fence.
Support transactions triggered by one fence, whcih can be either can existing lwis_fence or a placeholder fence. Bug: 229024993 Test: unit test Change-Id: I7536218c49b732061ed2dc85a425428fa7670c79
Diffstat (limited to 'lwis_fence.c')
-rw-r--r--lwis_fence.c134
1 files changed, 128 insertions, 6 deletions
diff --git a/lwis_fence.c b/lwis_fence.c
index 9cb0b8a..8c6e301 100644
--- a/lwis_fence.c
+++ b/lwis_fence.c
@@ -16,8 +16,10 @@
#include "lwis_device_top.h"
#include "lwis_commands.h"
#include "lwis_fence.h"
+#include "lwis_transaction.h"
#define LWIS_FENCE_DBG
+#define HASH_CLIENT(x) hash_ptr(x, LWIS_CLIENTS_HASH_BITS)
static int lwis_fence_release(struct inode *node, struct file *fp);
static ssize_t lwis_fence_get_status(struct file *fp, char __user *user_buffer, size_t len,
@@ -57,6 +59,7 @@ static int lwis_fence_release(struct inode *node, struct file *fp)
static ssize_t lwis_fence_get_status(struct file *fp, char __user *user_buffer, size_t len,
loff_t *offset)
{
+ int status = 0;
struct lwis_fence *lwis_fence = fp->private_data;
int max_len, read_len;
@@ -65,13 +68,16 @@ static ssize_t lwis_fence_get_status(struct file *fp, char __user *user_buffer,
return -EFAULT;
}
- max_len = sizeof(lwis_fence->status) - *offset;
+ max_len = sizeof(status) - *offset;
if (len > max_len) {
len = max_len;
}
- read_len = len - copy_to_user((void __user *)user_buffer,
- (void *)&lwis_fence->status + *offset, len);
+ mutex_lock(&lwis_fence->lock);
+ status = lwis_fence->status;
+ mutex_unlock(&lwis_fence->lock);
+
+ read_len = len - copy_to_user((void __user *)user_buffer, (void *)&status + *offset, len);
*offset += read_len;
#ifdef LWIS_FENCE_DBG
dev_info(lwis_fence->lwis_top_dev->dev, "lwis_fence fd-%d reading status = %d",
@@ -86,7 +92,13 @@ static ssize_t lwis_fence_get_status(struct file *fp, char __user *user_buffer,
static ssize_t lwis_fence_signal(struct file *fp, const char __user *user_buffer, size_t len,
loff_t *offset)
{
+ int status = 0;
struct lwis_fence *lwis_fence = fp->private_data;
+ struct lwis_fence_trigger_transaction_list *tx_list;
+ /* Temporary vars for hash table traversal */
+ struct hlist_node *n;
+ int i;
+
if (!lwis_fence) {
dev_err(lwis_fence->lwis_top_dev->dev, "Cannot find lwis_fence instance\n");
return -EFAULT;
@@ -94,16 +106,40 @@ static ssize_t lwis_fence_signal(struct file *fp, const char __user *user_buffer
if (len != sizeof(lwis_fence->status)) {
dev_err(lwis_fence->lwis_top_dev->dev,
- "Signal lwis_fence with incorrect buffer length\n");
+ "Signal lwis_fence fd-%d with incorrect buffer length\n", lwis_fence->fd);
return -EINVAL;
}
- len = len - copy_from_user(&lwis_fence->status, (void __user *)user_buffer, len);
+ /* Set lwis_fence's status if not signaled */
+ len = len - copy_from_user(&status, (void __user *)user_buffer, len);
+ mutex_lock(&lwis_fence->lock);
+ if (lwis_fence->status != LWIS_FENCE_STATUS_NOT_SIGNALED) {
+ /* Return error if fence is already signaled */
+ dev_err(lwis_fence->lwis_top_dev->dev,
+ "Cannot signal a lwis_fence fd-%d already signaled, status is %d\n",
+ lwis_fence->fd, lwis_fence->status);
+ mutex_unlock(&lwis_fence->lock);
+ return -EINVAL;
+ }
+ lwis_fence->status = status;
+ mutex_unlock(&lwis_fence->lock);
+
wake_up_interruptible(&lwis_fence->status_wait_queue);
#ifdef LWIS_FENCE_DBG
dev_info(lwis_fence->lwis_top_dev->dev, "lwis_fence fd-%d setting status to %d",
lwis_fence->fd, lwis_fence->status);
#endif
+
+ hash_for_each_safe (lwis_fence->transaction_list, i, n, tx_list, node) {
+ lwis_transaction_fence_trigger(tx_list->owner, lwis_fence, &tx_list->list);
+ if (!list_empty(&tx_list->list)) {
+ dev_err(lwis_fence->lwis_top_dev->dev,
+ "Fail to trigger all transactions\n");
+ }
+ hash_del(&tx_list->node);
+ kfree(tx_list);
+ }
+
return len;
}
@@ -112,6 +148,7 @@ static ssize_t lwis_fence_signal(struct file *fp, const char __user *user_buffer
*/
static unsigned int lwis_fence_poll(struct file *fp, poll_table *wait)
{
+ int status = 0;
struct lwis_fence *lwis_fence = fp->private_data;
if (!lwis_fence) {
dev_err(lwis_fence->lwis_top_dev->dev, "Cannot find lwis_fence instance\n");
@@ -119,8 +156,13 @@ static unsigned int lwis_fence_poll(struct file *fp, poll_table *wait)
}
poll_wait(fp, &lwis_fence->status_wait_queue, wait);
+
+ mutex_lock(&lwis_fence->lock);
+ status = lwis_fence->status;
+ mutex_unlock(&lwis_fence->lock);
+
/* Check if the fence is already signaled */
- if (lwis_fence->status != LWIS_FENCE_STATUS_NOT_SIGNALED) {
+ if (status != LWIS_FENCE_STATUS_NOT_SIGNALED) {
#ifdef LWIS_FENCE_DBG
dev_info(lwis_fence->lwis_top_dev->dev, "lwis_fence fd-%d poll return POLLIN",
lwis_fence->fd);
@@ -162,4 +204,84 @@ int lwis_fence_create(struct lwis_device *lwis_dev)
dev_info(lwis_dev->dev, "lwis_fence created new LWIS fence fd: %d", new_fence->fd);
#endif
return fd_or_err;
+}
+
+static struct lwis_fence_trigger_transaction_list *transaction_list_find(struct lwis_fence *fence,
+ struct lwis_client *owner)
+{
+ int hash_key = HASH_CLIENT(owner);
+ struct lwis_fence_trigger_transaction_list *tx_list;
+ hash_for_each_possible (fence->transaction_list, tx_list, node, hash_key) {
+ if (tx_list->owner == owner) {
+ return tx_list;
+ }
+ }
+ return NULL;
+}
+
+static struct lwis_fence_trigger_transaction_list *
+transaction_list_create(struct lwis_fence *fence, struct lwis_client *owner)
+{
+ struct lwis_fence_trigger_transaction_list *tx_list =
+ kmalloc(sizeof(struct lwis_fence_trigger_transaction_list), GFP_ATOMIC);
+ if (!tx_list) {
+ dev_err(fence->lwis_top_dev->dev, "Cannot allocate new event list\n");
+ return NULL;
+ }
+ tx_list->owner = owner;
+ INIT_LIST_HEAD(&tx_list->list);
+ hash_add(fence->transaction_list, &tx_list->node, HASH_CLIENT(owner));
+ return tx_list;
+}
+
+static struct lwis_fence_trigger_transaction_list *
+transaction_list_find_or_create(struct lwis_fence *fence, struct lwis_client *owner)
+{
+ struct lwis_fence_trigger_transaction_list *list = transaction_list_find(fence, owner);
+ return (list == NULL) ? transaction_list_create(fence, owner) : list;
+}
+
+int lwis_trigger_fence_add_transaction(int fence_fd, struct lwis_client *client,
+ struct lwis_transaction *transaction)
+{
+ struct file *fp;
+ struct lwis_fence *lwis_fence;
+ struct lwis_fence_trigger_transaction_list *tx_list;
+ int ret = 0;
+
+ fp = fget(fence_fd);
+ if (fp == NULL) {
+ dev_err(client->lwis_dev->dev, "Failed to find lwis_fence with fd %d\n", fence_fd);
+ return -EBADF;
+ }
+ lwis_fence = fp->private_data;
+ if (lwis_fence->fd != fence_fd) {
+ dev_err(client->lwis_dev->dev,
+ "Invalid lwis_fence with fd %d. Contains stale data \n", fence_fd);
+ return -EBADF;
+ }
+
+ mutex_lock(&lwis_fence->lock);
+ if (lwis_fence->status == LWIS_FENCE_STATUS_NOT_SIGNALED) {
+ lwis_fence->fp = fp;
+ tx_list = transaction_list_find_or_create(lwis_fence, client);
+ list_add(&transaction->event_list_node, &tx_list->list);
+#ifdef LWIS_FENCE_DBG
+ dev_info(client->lwis_dev->dev,
+ "lwis_fence transaction id %llu added to its trigger fence fd %d ",
+ transaction->info.id, lwis_fence->fd);
+#endif
+ } else if (lwis_fence->status == 0) {
+ fput(fp);
+ ret = -EALREADY;
+ } else if (lwis_fence->status) {
+ fput(fp);
+ dev_err(client->lwis_dev->dev,
+ "Bad lwis_fence fd-%d already signaled with error code %d \n", fence_fd,
+ lwis_fence->status);
+ ret = -EINVAL;
+ }
+ mutex_unlock(&lwis_fence->lock);
+
+ return ret;
} \ No newline at end of file