blob: 184dab7fd7e3b84e965eec5dd1003f23305420cd [file] [log] [blame]
Ge Bian39c7f612022-04-14 12:32:03 -07001/*
2 * Google LWIS Fence
3 *
4 * Copyright (c) 2022 Google, LLC
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 */
10
11#include <linux/anon_inodes.h>
12#include <linux/file.h>
13#include <linux/mm.h>
14#include <linux/poll.h>
15
16#include "lwis_device_top.h"
17#include "lwis_commands.h"
18#include "lwis_fence.h"
Ge Bian988870a2022-04-27 21:13:32 -070019#include "lwis_transaction.h"
Ge Bian39c7f612022-04-14 12:32:03 -070020
Ge Bian988870a2022-04-27 21:13:32 -070021#define HASH_CLIENT(x) hash_ptr(x, LWIS_CLIENTS_HASH_BITS)
Ge Bian39c7f612022-04-14 12:32:03 -070022
Nick Chung399b2bc2022-08-17 14:36:26 +000023bool lwis_fence_debug;
24module_param(lwis_fence_debug, bool, 0644);
Holmes Chouff0f8c52023-04-06 14:27:14 +000025
Ge Bian39c7f612022-04-14 12:32:03 -070026static int lwis_fence_release(struct inode *node, struct file *fp);
27static ssize_t lwis_fence_get_status(struct file *fp, char __user *user_buffer, size_t len,
28 loff_t *offset);
Tommy Kardach1e4edd62022-06-09 18:20:37 +000029static ssize_t lwis_fence_write_status(struct file *fp, const char __user *user_buffer, size_t len,
30 loff_t *offset);
Ge Bian39c7f612022-04-14 12:32:03 -070031static unsigned int lwis_fence_poll(struct file *fp, poll_table *wait);
32
33static const struct file_operations fence_file_ops = {
34 .owner = THIS_MODULE,
35 .release = lwis_fence_release,
36 .read = lwis_fence_get_status,
Tommy Kardach1e4edd62022-06-09 18:20:37 +000037 .write = lwis_fence_write_status,
Ge Bian39c7f612022-04-14 12:32:03 -070038 .poll = lwis_fence_poll,
39};
40
Edmond Chung65800a62023-02-15 12:42:20 -080041static int get_fence_status(struct lwis_fence *lwis_fence)
42{
43 int status;
44 unsigned long flags;
45 spin_lock_irqsave(&lwis_fence->lock, flags);
46 status = lwis_fence->status;
47 spin_unlock_irqrestore(&lwis_fence->lock, flags);
48 return status;
49}
50
Ge Bian39c7f612022-04-14 12:32:03 -070051/*
52 * lwis_fence_release: Closing an instance of a LWIS fence
53 */
54static int lwis_fence_release(struct inode *node, struct file *fp)
55{
56 struct lwis_fence *lwis_fence = fp->private_data;
Ge Biana4e0b2d2022-05-24 23:31:51 -070057 struct lwis_fence_trigger_transaction_list *tx_list;
58 struct lwis_pending_transaction_id *transaction_id;
59 /* Temporary vars for traversal */
60 struct hlist_node *n;
61 struct list_head *it_tran, *it_tran_tmp;
62 int i;
63
Nick Chung399b2bc2022-08-17 14:36:26 +000064 if (lwis_fence_debug) {
65 dev_info(lwis_fence->lwis_top_dev->dev, "Releasing lwis_fence fd-%d",
66 lwis_fence->fd);
67 }
Nick Chung399b2bc2022-08-17 14:36:26 +000068
Ge Bian39c7f612022-04-14 12:32:03 -070069 if (lwis_fence->status == LWIS_FENCE_STATUS_NOT_SIGNALED) {
70 dev_err(lwis_fence->lwis_top_dev->dev,
71 "lwis_fence fd-%d release without being signaled", lwis_fence->fd);
72 }
Ge Biana4e0b2d2022-05-24 23:31:51 -070073
74 if (!hash_empty(lwis_fence->transaction_list)) {
75 hash_for_each_safe (lwis_fence->transaction_list, i, n, tx_list, node) {
76 if (!list_empty(&tx_list->list)) {
77 list_for_each_safe (it_tran, it_tran_tmp, &tx_list->list) {
78 transaction_id =
79 list_entry(it_tran,
80 struct lwis_pending_transaction_id,
81 list_node);
82 list_del(&transaction_id->list_node);
83 kfree(transaction_id);
84 }
85 }
86 hash_del(&tx_list->node);
87 kfree(tx_list);
88 }
89 }
90
Ge Bian39c7f612022-04-14 12:32:03 -070091 kfree(lwis_fence);
92 return 0;
93}
94
95/*
96 * lwis_fence_get_status: Read the LWIS fence's status
97 */
98static ssize_t lwis_fence_get_status(struct file *fp, char __user *user_buffer, size_t len,
99 loff_t *offset)
100{
Ge Bian988870a2022-04-27 21:13:32 -0700101 int status = 0;
Ge Bian39c7f612022-04-14 12:32:03 -0700102 struct lwis_fence *lwis_fence = fp->private_data;
103 int max_len, read_len;
104
105 if (!lwis_fence) {
106 dev_err(lwis_fence->lwis_top_dev->dev, "Cannot find lwis_fence instance\n");
107 return -EFAULT;
108 }
109
Ge Bian988870a2022-04-27 21:13:32 -0700110 max_len = sizeof(status) - *offset;
Ge Bian39c7f612022-04-14 12:32:03 -0700111 if (len > max_len) {
112 len = max_len;
113 }
114
Edmond Chung65800a62023-02-15 12:42:20 -0800115 status = get_fence_status(lwis_fence);
Ge Bian988870a2022-04-27 21:13:32 -0700116 read_len = len - copy_to_user((void __user *)user_buffer, (void *)&status + *offset, len);
Nick Chung399b2bc2022-08-17 14:36:26 +0000117
Ge Bian39c7f612022-04-14 12:32:03 -0700118 return read_len;
119}
120
121/*
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000122 * lwis_fence_write_status: Signal fence with the error code from user
Ge Bian39c7f612022-04-14 12:32:03 -0700123 */
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000124static ssize_t lwis_fence_write_status(struct file *fp, const char __user *user_buffer, size_t len,
125 loff_t *offset)
Ge Bian39c7f612022-04-14 12:32:03 -0700126{
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000127 int ret = 0;
Ge Bian988870a2022-04-27 21:13:32 -0700128 int status = 0;
Ge Bian39c7f612022-04-14 12:32:03 -0700129 struct lwis_fence *lwis_fence = fp->private_data;
Ge Bian988870a2022-04-27 21:13:32 -0700130
Ge Bian39c7f612022-04-14 12:32:03 -0700131 if (!lwis_fence) {
132 dev_err(lwis_fence->lwis_top_dev->dev, "Cannot find lwis_fence instance\n");
133 return -EFAULT;
134 }
135
136 if (len != sizeof(lwis_fence->status)) {
137 dev_err(lwis_fence->lwis_top_dev->dev,
Ge Bian988870a2022-04-27 21:13:32 -0700138 "Signal lwis_fence fd-%d with incorrect buffer length\n", lwis_fence->fd);
Ge Bian39c7f612022-04-14 12:32:03 -0700139 return -EINVAL;
140 }
141
Ge Bian988870a2022-04-27 21:13:32 -0700142 /* Set lwis_fence's status if not signaled */
143 len = len - copy_from_user(&status, (void __user *)user_buffer, len);
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000144 ret = lwis_fence_signal(lwis_fence, status);
145 if (ret) {
146 return ret;
147 }
148
149 return len;
150}
151
152int lwis_fence_signal(struct lwis_fence *lwis_fence, int status)
153{
154 unsigned long flags;
155 struct lwis_fence_trigger_transaction_list *tx_list;
156 /* Temporary vars for hash table traversal */
157 struct hlist_node *n;
158 int i;
159
160 spin_lock_irqsave(&lwis_fence->lock, flags);
161
Ge Bian988870a2022-04-27 21:13:32 -0700162 if (lwis_fence->status != LWIS_FENCE_STATUS_NOT_SIGNALED) {
163 /* Return error if fence is already signaled */
164 dev_err(lwis_fence->lwis_top_dev->dev,
165 "Cannot signal a lwis_fence fd-%d already signaled, status is %d\n",
166 lwis_fence->fd, lwis_fence->status);
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000167 spin_unlock_irqrestore(&lwis_fence->lock, flags);
Ge Bian988870a2022-04-27 21:13:32 -0700168 return -EINVAL;
169 }
170 lwis_fence->status = status;
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000171 spin_unlock_irqrestore(&lwis_fence->lock, flags);
Ge Bian988870a2022-04-27 21:13:32 -0700172
Ge Bian39c7f612022-04-14 12:32:03 -0700173 wake_up_interruptible(&lwis_fence->status_wait_queue);
Ge Bian988870a2022-04-27 21:13:32 -0700174
175 hash_for_each_safe (lwis_fence->transaction_list, i, n, tx_list, node) {
Ge Biana4e0b2d2022-05-24 23:31:51 -0700176 hash_del(&tx_list->node);
Ge Bian988870a2022-04-27 21:13:32 -0700177 lwis_transaction_fence_trigger(tx_list->owner, lwis_fence, &tx_list->list);
178 if (!list_empty(&tx_list->list)) {
179 dev_err(lwis_fence->lwis_top_dev->dev,
180 "Fail to trigger all transactions\n");
181 }
Ge Bian988870a2022-04-27 21:13:32 -0700182 kfree(tx_list);
183 }
184
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000185 return 0;
Ge Bian39c7f612022-04-14 12:32:03 -0700186}
187
188/*
189 * lwis_fence_poll: Poll status function of LWIS fence
190 */
191static unsigned int lwis_fence_poll(struct file *fp, poll_table *wait)
192{
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000193 unsigned long flags;
Ge Bian988870a2022-04-27 21:13:32 -0700194 int status = 0;
Ge Bian39c7f612022-04-14 12:32:03 -0700195 struct lwis_fence *lwis_fence = fp->private_data;
196 if (!lwis_fence) {
197 dev_err(lwis_fence->lwis_top_dev->dev, "Cannot find lwis_fence instance\n");
198 return POLLERR;
199 }
200
201 poll_wait(fp, &lwis_fence->status_wait_queue, wait);
Ge Bian988870a2022-04-27 21:13:32 -0700202
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000203 spin_lock_irqsave(&lwis_fence->lock, flags);
Ge Bian988870a2022-04-27 21:13:32 -0700204 status = lwis_fence->status;
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000205 spin_unlock_irqrestore(&lwis_fence->lock, flags);
Ge Bian988870a2022-04-27 21:13:32 -0700206
Ge Bian39c7f612022-04-14 12:32:03 -0700207 /* Check if the fence is already signaled */
Ge Bian988870a2022-04-27 21:13:32 -0700208 if (status != LWIS_FENCE_STATUS_NOT_SIGNALED) {
Ge Bian39c7f612022-04-14 12:32:03 -0700209 return POLLIN;
210 }
211
Ge Bian39c7f612022-04-14 12:32:03 -0700212 return 0;
213}
214
215int lwis_fence_create(struct lwis_device *lwis_dev)
216{
217 int fd_or_err;
218 struct lwis_fence *new_fence;
219
220 /* Allocate a new instance of lwis_fence struct */
221 new_fence = kmalloc(sizeof(struct lwis_fence), GFP_ATOMIC);
222 if (!new_fence) {
223 dev_err(lwis_dev->dev, "Failed to allocate lwis_fence at creating new fence\n");
224 return -ENOMEM;
225 }
226
227 /* Open a new fd for the new fence */
Edmond Chung10e32732023-02-22 14:03:31 -0800228 fd_or_err =
229 anon_inode_getfd("lwis_fence_file", &fence_file_ops, new_fence, O_RDWR | O_CLOEXEC);
Ge Bian39c7f612022-04-14 12:32:03 -0700230 if (fd_or_err < 0) {
231 kfree(new_fence);
232 dev_err(lwis_dev->dev, "Failed to create a new file instance for lwis_fence\n");
233 return fd_or_err;
234 }
235
236 new_fence->fd = fd_or_err;
237 new_fence->lwis_top_dev = lwis_dev->top_dev;
238 new_fence->status = LWIS_FENCE_STATUS_NOT_SIGNALED;
Tommy Kardachdec46b22023-03-13 13:15:45 -0700239 spin_lock_init(&new_fence->lock);
Ge Bian39c7f612022-04-14 12:32:03 -0700240 init_waitqueue_head(&new_fence->status_wait_queue);
Nick Chung399b2bc2022-08-17 14:36:26 +0000241 if (lwis_fence_debug) {
242 dev_info(lwis_dev->dev, "lwis_fence created new LWIS fence fd: %d", new_fence->fd);
243 }
Ge Bian39c7f612022-04-14 12:32:03 -0700244 return fd_or_err;
Ge Bian988870a2022-04-27 21:13:32 -0700245}
246
247static struct lwis_fence_trigger_transaction_list *transaction_list_find(struct lwis_fence *fence,
248 struct lwis_client *owner)
249{
250 int hash_key = HASH_CLIENT(owner);
251 struct lwis_fence_trigger_transaction_list *tx_list;
252 hash_for_each_possible (fence->transaction_list, tx_list, node, hash_key) {
253 if (tx_list->owner == owner) {
254 return tx_list;
255 }
256 }
257 return NULL;
258}
259
260static struct lwis_fence_trigger_transaction_list *
261transaction_list_create(struct lwis_fence *fence, struct lwis_client *owner)
262{
263 struct lwis_fence_trigger_transaction_list *tx_list =
264 kmalloc(sizeof(struct lwis_fence_trigger_transaction_list), GFP_ATOMIC);
265 if (!tx_list) {
266 dev_err(fence->lwis_top_dev->dev, "Cannot allocate new event list\n");
267 return NULL;
268 }
269 tx_list->owner = owner;
270 INIT_LIST_HEAD(&tx_list->list);
271 hash_add(fence->transaction_list, &tx_list->node, HASH_CLIENT(owner));
272 return tx_list;
273}
274
275static struct lwis_fence_trigger_transaction_list *
276transaction_list_find_or_create(struct lwis_fence *fence, struct lwis_client *owner)
277{
278 struct lwis_fence_trigger_transaction_list *list = transaction_list_find(fence, owner);
279 return (list == NULL) ? transaction_list_create(fence, owner) : list;
280}
281
Will McVicker675362d2022-05-26 12:39:44 -0700282static int lwis_trigger_fence_add_transaction(int fence_fd, struct lwis_client *client,
Tommy Kardachc1759a92022-09-01 20:57:34 +0000283 struct lwis_transaction *transaction)
Ge Bian988870a2022-04-27 21:13:32 -0700284{
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000285 unsigned long flags;
Ge Bian988870a2022-04-27 21:13:32 -0700286 struct file *fp;
287 struct lwis_fence *lwis_fence;
Ge Biana4e0b2d2022-05-24 23:31:51 -0700288 struct lwis_pending_transaction_id *pending_transaction_id;
Ge Bian988870a2022-04-27 21:13:32 -0700289 struct lwis_fence_trigger_transaction_list *tx_list;
290 int ret = 0;
291
Ge Bianf55393c2022-08-18 11:45:21 -0700292 if (transaction->num_trigger_fences >= LWIS_TRIGGER_NODES_MAX_NUM) {
293 dev_err(client->lwis_dev->dev,
294 "Invalid num_trigger_fences value in transaction %d\n", fence_fd);
295 return -EINVAL;
296 }
297
Ge Bian988870a2022-04-27 21:13:32 -0700298 fp = fget(fence_fd);
299 if (fp == NULL) {
300 dev_err(client->lwis_dev->dev, "Failed to find lwis_fence with fd %d\n", fence_fd);
301 return -EBADF;
302 }
303 lwis_fence = fp->private_data;
304 if (lwis_fence->fd != fence_fd) {
Ge Bianf55393c2022-08-18 11:45:21 -0700305 fput(fp);
Ge Bian988870a2022-04-27 21:13:32 -0700306 dev_err(client->lwis_dev->dev,
307 "Invalid lwis_fence with fd %d. Contains stale data \n", fence_fd);
308 return -EBADF;
309 }
310
Ge Biana4e0b2d2022-05-24 23:31:51 -0700311 pending_transaction_id = kmalloc(sizeof(struct lwis_pending_transaction_id), GFP_ATOMIC);
312 if (!pending_transaction_id) {
Ge Bianf55393c2022-08-18 11:45:21 -0700313 fput(fp);
Ge Biana4e0b2d2022-05-24 23:31:51 -0700314 dev_err(client->lwis_dev->dev,
315 "Failed to allocate lwis_pending_transaction_id at adding transactions to fence\n");
316 return -ENOMEM;
317 }
318 pending_transaction_id->id = transaction->info.id;
319
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000320 spin_lock_irqsave(&lwis_fence->lock, flags);
Tommy Kardachc1759a92022-09-01 20:57:34 +0000321 if (lwis_fence->status == LWIS_FENCE_STATUS_NOT_SIGNALED) {
Ge Bianf55393c2022-08-18 11:45:21 -0700322 transaction->trigger_fence_fps[transaction->num_trigger_fences++] = fp;
Ge Bian988870a2022-04-27 21:13:32 -0700323 tx_list = transaction_list_find_or_create(lwis_fence, client);
Ge Biana4e0b2d2022-05-24 23:31:51 -0700324 list_add(&pending_transaction_id->list_node, &tx_list->list);
Nick Chung399b2bc2022-08-17 14:36:26 +0000325 if (lwis_fence_debug) {
326 dev_info(client->lwis_dev->dev,
327 "lwis_fence transaction id %llu added to its trigger fence fd %d ",
328 transaction->info.id, lwis_fence->fd);
329 }
Ge Biana4e0b2d2022-05-24 23:31:51 -0700330 } else {
Ge Biana4e0b2d2022-05-24 23:31:51 -0700331 kfree(pending_transaction_id);
Holmes Chouff0f8c52023-04-06 14:27:14 +0000332 if (lwis_fence_debug) {
333 dev_info(
334 client->lwis_dev->dev,
335 "lwis_fence fd-%d not added to transaction id %llu, fence already signaled with error code %d \n",
336 fence_fd, transaction->info.id, lwis_fence->status);
337 }
Tommy Kardachb098b6b2022-08-11 21:54:20 +0000338 if (!transaction->info.is_level_triggered) {
Tommy Kardachc1759a92022-09-01 20:57:34 +0000339 /* If level triggering is disabled, return an error. */
Ge Bianf55393c2022-08-18 11:45:21 -0700340 fput(fp);
Tommy Kardach358aa4a2022-08-10 22:22:53 +0000341 ret = -EINVAL;
Tommy Kardachc1759a92022-09-01 20:57:34 +0000342 } else {
Ge Bianf55393c2022-08-18 11:45:21 -0700343 transaction->trigger_fence_fps[transaction->num_trigger_fences++] = fp;
Tommy Kardachc1759a92022-09-01 20:57:34 +0000344 /* If the transaction's trigger_condition evaluates to true, queue the
345 * transaction to be executed immediately.
346 */
Ge Bianf55393c2022-08-18 11:45:21 -0700347 if (lwis_fence_triggered_condition_ready(transaction, lwis_fence->status)) {
348 if (lwis_fence->status != 0) {
349 transaction->resp->error_code = -ECANCELED;
Tommy Kardachc1759a92022-09-01 20:57:34 +0000350 }
Ge Bianf55393c2022-08-18 11:45:21 -0700351 transaction->queue_immediately = true;
Tommy Kardachc1759a92022-09-01 20:57:34 +0000352 }
Tommy Kardach358aa4a2022-08-10 22:22:53 +0000353 }
Ge Bian988870a2022-04-27 21:13:32 -0700354 }
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000355 spin_unlock_irqrestore(&lwis_fence->lock, flags);
356
Ge Bian988870a2022-04-27 21:13:32 -0700357 return ret;
Will McVicker675362d2022-05-26 12:39:44 -0700358}
359
Will McVicker675362d2022-05-26 12:39:44 -0700360bool lwis_triggered_by_condition(struct lwis_transaction *transaction)
361{
362 return (transaction->info.trigger_condition.num_nodes > 0);
363}
364
365bool lwis_event_triggered_condition_ready(struct lwis_transaction *transaction,
366 struct lwis_transaction *weak_transaction,
367 int64_t event_id, int64_t event_counter)
368{
369 int32_t operator_type;
370 size_t all_signaled;
Holmes Chouff0f8c52023-04-06 14:27:14 +0000371 struct lwis_transaction_info_v2 *info = &transaction->info;
Will McVicker675362d2022-05-26 12:39:44 -0700372 int i;
Edmond Chung65800a62023-02-15 12:42:20 -0800373 struct lwis_fence *lwis_fence;
374 bool is_node_signaled = false;
Will McVicker675362d2022-05-26 12:39:44 -0700375
376 operator_type = info->trigger_condition.operator_type;
377 all_signaled = info->trigger_condition.num_nodes;
378
Edmond Chung65800a62023-02-15 12:42:20 -0800379 /*
380 * Three scenarios to consider a node signaled:
381 * 1) Event ID and event counter match,
382 * 2) Event ID match, event counter not specified but precondition fence signaled, or,
383 * 3) Event ID match, event counter and precondition fence not specified.
384 */
Will McVicker675362d2022-05-26 12:39:44 -0700385 for (i = 0; i < info->trigger_condition.num_nodes; i++) {
Edmond Chung65800a62023-02-15 12:42:20 -0800386 is_node_signaled = false;
Will McVicker675362d2022-05-26 12:39:44 -0700387 if (info->trigger_condition.trigger_nodes[i].type == LWIS_TRIGGER_EVENT &&
Edmond Chung65800a62023-02-15 12:42:20 -0800388 info->trigger_condition.trigger_nodes[i].event.id == event_id) {
389 if (info->trigger_condition.trigger_nodes[i].event.counter ==
390 event_counter ||
391 (info->trigger_condition.trigger_nodes[i].event.counter ==
392 LWIS_EVENT_COUNTER_ON_NEXT_OCCURRENCE &&
393 weak_transaction->precondition_fence_fp == NULL)) {
394 is_node_signaled = true;
395 } else if (info->trigger_condition.trigger_nodes[i].event.counter ==
396 LWIS_EVENT_COUNTER_ON_NEXT_OCCURRENCE) {
397 lwis_fence = weak_transaction->precondition_fence_fp->private_data;
398 if (lwis_fence != NULL && get_fence_status(lwis_fence) == 0) {
399 is_node_signaled = true;
400 if (lwis_fence_debug) {
401 pr_info("TransactionId %lld: event 0x%llx (%lld), precondition fence %d signaled",
402 info->id, event_id, event_counter,
403 info->trigger_condition.trigger_nodes[i]
404 .event.precondition_fence_fd);
405 }
406 } else {
407 if (lwis_fence_debug) {
408 pr_info("TransactionId %lld: event 0x%llx (%lld), precondition fence %d NOT signaled yet",
409 info->id, event_id, event_counter,
410 info->trigger_condition.trigger_nodes[i]
411 .event.precondition_fence_fd);
412 }
413 }
414 }
415
416 if (is_node_signaled) {
417 transaction->signaled_count++;
418 list_del(&weak_transaction->event_list_node);
419 if (weak_transaction->precondition_fence_fp) {
420 fput(weak_transaction->precondition_fence_fp);
421 }
422 kfree(weak_transaction);
423 /* The break here assumes that this event ID only appears once in
424 the trigger expression. Might need to revisit this. */
425 break;
426 }
Will McVicker675362d2022-05-26 12:39:44 -0700427 }
428 }
429
430 if (i >= info->trigger_condition.num_nodes) {
431 /* No event counter is matched */
432 return false;
433 }
434
435 if (operator_type == LWIS_TRIGGER_NODE_OPERATOR_AND &&
436 transaction->signaled_count == all_signaled) {
437 return true;
438 } else if (operator_type == LWIS_TRIGGER_NODE_OPERATOR_OR) {
439 return true;
440 } else if (operator_type == LWIS_TRIGGER_NODE_OPERATOR_NONE) {
441 return true;
442 }
443
444 return false;
445}
446
Edmond Chung65800a62023-02-15 12:42:20 -0800447bool lwis_fence_triggered_condition_ready(struct lwis_transaction *transaction, int fence_status)
Will McVicker675362d2022-05-26 12:39:44 -0700448{
449 int32_t operator_type;
450 size_t all_signaled;
451
452 operator_type = transaction->info.trigger_condition.operator_type;
453 all_signaled = transaction->info.trigger_condition.num_nodes;
454
455 transaction->signaled_count++;
456 if ((operator_type == LWIS_TRIGGER_NODE_OPERATOR_AND ||
457 operator_type == LWIS_TRIGGER_NODE_OPERATOR_OR) &&
458 transaction->signaled_count == all_signaled) {
459 return true;
Tommy Kardach358aa4a2022-08-10 22:22:53 +0000460 } else if (operator_type == LWIS_TRIGGER_NODE_OPERATOR_AND && fence_status != 0) {
Will McVicker675362d2022-05-26 12:39:44 -0700461 /*
462 This condition is ready to cancel transaction as long as there is
463 an error condition from fence with operator type "AND".
464 No matter whether all condition nodes are signaled.
465 */
466 return true;
Tommy Kardach358aa4a2022-08-10 22:22:53 +0000467 } else if (operator_type == LWIS_TRIGGER_NODE_OPERATOR_OR && fence_status == 0) {
Will McVicker675362d2022-05-26 12:39:44 -0700468 return true;
469 } else if (operator_type == LWIS_TRIGGER_NODE_OPERATOR_NONE) {
470 return true;
471 }
472
473 return false;
474}
475
Ge Bian2cd08542022-06-03 00:42:57 -0700476int lwis_parse_trigger_condition(struct lwis_client *client, struct lwis_transaction *transaction)
Will McVicker675362d2022-05-26 12:39:44 -0700477{
Holmes Chouff0f8c52023-04-06 14:27:14 +0000478 struct lwis_transaction_info_v2 *info;
Will McVicker675362d2022-05-26 12:39:44 -0700479 struct lwis_device *lwis_dev;
480 int i, ret;
Will McVicker675362d2022-05-26 12:39:44 -0700481
482 if (!transaction || !client) {
483 dev_err(client->lwis_dev->dev, "Invalid lwis transaction\n");
484 return -EINVAL;
485 }
486
487 info = &transaction->info;
488 lwis_dev = client->lwis_dev;
489
490 if (info->trigger_condition.num_nodes > LWIS_TRIGGER_NODES_MAX_NUM) {
491 dev_err(lwis_dev->dev,
492 "Trigger condition contains %lu node, more than the limit of %d\n",
Ge Bian2cd08542022-06-03 00:42:57 -0700493 info->trigger_condition.num_nodes, LWIS_TRIGGER_NODES_MAX_NUM);
Will McVicker675362d2022-05-26 12:39:44 -0700494 return -EINVAL;
495 }
496
497 for (i = 0; i < info->trigger_condition.num_nodes; i++) {
Will McVicker675362d2022-05-26 12:39:44 -0700498 if (info->trigger_condition.trigger_nodes[i].type == LWIS_TRIGGER_EVENT) {
499 ret = lwis_trigger_event_add_weak_transaction(
Edmond Chung65800a62023-02-15 12:42:20 -0800500 client, info->id, info->trigger_condition.trigger_nodes[i].event.id,
501 info->trigger_condition.trigger_nodes[i]
502 .event.precondition_fence_fd);
Will McVicker675362d2022-05-26 12:39:44 -0700503 } else {
504 ret = lwis_trigger_fence_add_transaction(
505 info->trigger_condition.trigger_nodes[i].fence_fd, client,
Tommy Kardachc1759a92022-09-01 20:57:34 +0000506 transaction);
Will McVicker675362d2022-05-26 12:39:44 -0700507 }
508 if (ret) {
509 return ret;
510 }
511 }
512
513 return 0;
514}
515
516int ioctl_lwis_fence_create(struct lwis_device *lwis_dev, int32_t __user *msg)
517{
518 int32_t fd_or_err;
519
520 fd_or_err = lwis_fence_create(lwis_dev);
521 if (fd_or_err < 0) {
522 return fd_or_err;
523 }
524
525 if (copy_to_user((void __user *)msg, &fd_or_err, sizeof(int32_t))) {
526 dev_err(lwis_dev->dev, "failed to copy to user\n");
527 return -EFAULT;
528 }
529
530 return 0;
531}
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000532
Tommy Kardach07b0a672022-09-20 17:09:57 +0000533int lwis_initialize_transaction_fences(struct lwis_client *client,
534 struct lwis_transaction *transaction)
535{
Holmes Chouff0f8c52023-04-06 14:27:14 +0000536 struct lwis_transaction_info_v2 *info = &transaction->info;
Tommy Kardach07b0a672022-09-20 17:09:57 +0000537 struct lwis_device *lwis_dev = client->lwis_dev;
538 int i;
539 int fd_or_err;
540
541 if (!transaction || !client) {
542 dev_err(client->lwis_dev->dev, "Invalid lwis transaction\n");
543 return -EINVAL;
544 }
545
546 /* If triggered by trigger_condition */
547 if (lwis_triggered_by_condition(transaction)) {
548 /* Initialize all placeholder fences in the trigger_condition */
549 for (i = 0; i < info->trigger_condition.num_nodes; i++) {
550 if (info->trigger_condition.trigger_nodes[i].type ==
551 LWIS_TRIGGER_FENCE_PLACEHOLDER) {
552 fd_or_err = lwis_fence_create(lwis_dev);
553 if (fd_or_err < 0) {
554 return fd_or_err;
555 }
556 info->trigger_condition.trigger_nodes[i].fence_fd = fd_or_err;
557 }
558 }
559 }
560
561 /* Initialize completion fence if one is requested */
562 if (info->completion_fence_fd == LWIS_CREATE_COMPLETION_FENCE) {
563 fd_or_err = lwis_fence_create(client->lwis_dev);
564 if (fd_or_err < 0) {
565 return fd_or_err;
566 }
567 info->completion_fence_fd = fd_or_err;
568 }
569
570 return 0;
571}
572
573int lwis_add_completion_fence(struct lwis_client *client, struct lwis_transaction *transaction)
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000574{
575 struct file *fp;
576 struct lwis_fence *lwis_fence;
577 struct lwis_fence_pending_signal *fence_pending_signal;
578 struct lwis_device *lwis_dev = client->lwis_dev;
Tommy Kardach07b0a672022-09-20 17:09:57 +0000579 int fence_fd = transaction->info.completion_fence_fd;
580
581 /* If completion fence is not requested, we can safely return */
582 if (fence_fd == LWIS_NO_COMPLETION_FENCE) {
583 return 0;
584 }
585
586 /* If completion fence is requested but not initialized, we cannot continue */
587 if (fence_fd == LWIS_CREATE_COMPLETION_FENCE) {
588 dev_err(lwis_dev->dev,
589 "Cannot add uninitialized completion fence to transaction\n");
590 return -EPERM;
591 }
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000592
593 fp = fget(fence_fd);
594 if (fp == NULL) {
595 dev_err(lwis_dev->dev, "Failed to find lwis_fence with fd %d\n", fence_fd);
596 return -EBADF;
597 }
Ge Bianf55393c2022-08-18 11:45:21 -0700598
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000599 lwis_fence = fp->private_data;
Ge Bianf55393c2022-08-18 11:45:21 -0700600 fence_pending_signal = lwis_fence_pending_signal_create(lwis_fence, fp);
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000601 if (fence_pending_signal == NULL) {
602 return -ENOMEM;
603 }
604 list_add(&fence_pending_signal->node, &transaction->completion_fence_list);
Nick Chung399b2bc2022-08-17 14:36:26 +0000605 if (lwis_fence_debug) {
Ge Biane07902a2022-07-12 17:30:34 -0700606 dev_info(client->lwis_dev->dev,
607 "lwis_fence transaction id %llu add completion fence fd %d ",
608 transaction->info.id, lwis_fence->fd);
Nick Chung399b2bc2022-08-17 14:36:26 +0000609 }
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000610 return 0;
611}
612
Ge Bianf55393c2022-08-18 11:45:21 -0700613struct lwis_fence_pending_signal *lwis_fence_pending_signal_create(struct lwis_fence *fence,
614 struct file *fp)
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000615{
616 struct lwis_fence_pending_signal *pending_fence_signal =
617 kmalloc(sizeof(struct lwis_fence_pending_signal), GFP_ATOMIC);
618 if (!pending_fence_signal) {
619 dev_err(fence->lwis_top_dev->dev,
620 "Cannot allocate new fence pending signal list\n");
621 return NULL;
622 }
Ge Bianf55393c2022-08-18 11:45:21 -0700623 pending_fence_signal->fp = fp;
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000624 pending_fence_signal->fence = fence;
625 pending_fence_signal->pending_status = LWIS_FENCE_STATUS_NOT_SIGNALED;
626 return pending_fence_signal;
627}
628
629void lwis_fences_pending_signal_emit(struct lwis_device *lwis_device,
630 struct list_head *pending_fences)
631{
632 int ret;
633 struct lwis_fence_pending_signal *pending_fence;
634 struct list_head *it_fence, *it_fence_tmp;
635
636 list_for_each_safe (it_fence, it_fence_tmp, pending_fences) {
637 pending_fence = list_entry(it_fence, struct lwis_fence_pending_signal, node);
638 ret = lwis_fence_signal(pending_fence->fence, pending_fence->pending_status);
639 if (ret) {
640 dev_err(lwis_device->dev, "Failed signaling fence with fd %d",
641 pending_fence->fence->fd);
642 }
643 list_del(&pending_fence->node);
Ge Bianf55393c2022-08-18 11:45:21 -0700644 fput(pending_fence->fp);
Tommy Kardach1e4edd62022-06-09 18:20:37 +0000645 kfree(pending_fence);
646 }
647}
648
649void lwis_pending_fences_move_all(struct lwis_device *lwis_device,
650 struct lwis_transaction *transaction,
651 struct list_head *pending_fences, int error_code)
652{
653 struct lwis_fence_pending_signal *pending_fence, *temp;
654
655 /* For each fence in transaction's signal list, move to pending_fences for signaling */
656 list_for_each_entry_safe (pending_fence, temp, &transaction->completion_fence_list, node) {
657 pending_fence->pending_status = error_code;
658 list_move_tail(&pending_fence->node, pending_fences);
659 }
660}