]> Git Repo - J-linux.git/blob - drivers/tee/optee/notif.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / drivers / tee / optee / notif.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2015-2021, Linaro Limited
4  */
5
6 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7
8 #include <linux/arm-smccc.h>
9 #include <linux/errno.h>
10 #include <linux/slab.h>
11 #include <linux/spinlock.h>
12 #include <linux/tee_core.h>
13 #include "optee_private.h"
14
15 struct notif_entry {
16         struct list_head link;
17         struct completion c;
18         u_int key;
19 };
20
21 static bool have_key(struct optee *optee, u_int key)
22 {
23         struct notif_entry *entry;
24
25         list_for_each_entry(entry, &optee->notif.db, link)
26                 if (entry->key == key)
27                         return true;
28
29         return false;
30 }
31
32 int optee_notif_wait(struct optee *optee, u_int key, u32 timeout)
33 {
34         unsigned long flags;
35         struct notif_entry *entry;
36         int rc = 0;
37
38         if (key > optee->notif.max_key)
39                 return -EINVAL;
40
41         entry = kmalloc(sizeof(*entry), GFP_KERNEL);
42         if (!entry)
43                 return -ENOMEM;
44         init_completion(&entry->c);
45         entry->key = key;
46
47         spin_lock_irqsave(&optee->notif.lock, flags);
48
49         /*
50          * If the bit is already set it means that the key has already
51          * been posted and we must not wait.
52          */
53         if (test_bit(key, optee->notif.bitmap)) {
54                 clear_bit(key, optee->notif.bitmap);
55                 goto out;
56         }
57
58         /*
59          * Check if someone is already waiting for this key. If there is
60          * it's a programming error.
61          */
62         if (have_key(optee, key)) {
63                 rc = -EBUSY;
64                 goto out;
65         }
66
67         list_add_tail(&entry->link, &optee->notif.db);
68
69         /*
70          * Unlock temporarily and wait for completion.
71          */
72         spin_unlock_irqrestore(&optee->notif.lock, flags);
73         if (timeout != 0) {
74                 if (!wait_for_completion_timeout(&entry->c, timeout))
75                         rc = -ETIMEDOUT;
76         } else {
77                 wait_for_completion(&entry->c);
78         }
79         spin_lock_irqsave(&optee->notif.lock, flags);
80
81         list_del(&entry->link);
82 out:
83         spin_unlock_irqrestore(&optee->notif.lock, flags);
84
85         kfree(entry);
86
87         return rc;
88 }
89
90 int optee_notif_send(struct optee *optee, u_int key)
91 {
92         unsigned long flags;
93         struct notif_entry *entry;
94
95         if (key > optee->notif.max_key)
96                 return -EINVAL;
97
98         spin_lock_irqsave(&optee->notif.lock, flags);
99
100         list_for_each_entry(entry, &optee->notif.db, link)
101                 if (entry->key == key) {
102                         complete(&entry->c);
103                         goto out;
104                 }
105
106         /* Only set the bit in case there where nobody waiting */
107         set_bit(key, optee->notif.bitmap);
108 out:
109         spin_unlock_irqrestore(&optee->notif.lock, flags);
110
111         return 0;
112 }
113
114 int optee_notif_init(struct optee *optee, u_int max_key)
115 {
116         spin_lock_init(&optee->notif.lock);
117         INIT_LIST_HEAD(&optee->notif.db);
118         optee->notif.bitmap = bitmap_zalloc(max_key, GFP_KERNEL);
119         if (!optee->notif.bitmap)
120                 return -ENOMEM;
121
122         optee->notif.max_key = max_key;
123
124         return 0;
125 }
126
127 void optee_notif_uninit(struct optee *optee)
128 {
129         bitmap_free(optee->notif.bitmap);
130 }
This page took 0.034366 seconds and 4 git commands to generate.