Merge branches 'clk-range', 'clk-uniphier', 'clk-apple' and 'clk-qcom' into clk-next
[linux-2.6-microblaze.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_drv.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)
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         wait_for_completion(&entry->c);
74         spin_lock_irqsave(&optee->notif.lock, flags);
75
76         list_del(&entry->link);
77 out:
78         spin_unlock_irqrestore(&optee->notif.lock, flags);
79
80         kfree(entry);
81
82         return rc;
83 }
84
85 int optee_notif_send(struct optee *optee, u_int key)
86 {
87         unsigned long flags;
88         struct notif_entry *entry;
89
90         if (key > optee->notif.max_key)
91                 return -EINVAL;
92
93         spin_lock_irqsave(&optee->notif.lock, flags);
94
95         list_for_each_entry(entry, &optee->notif.db, link)
96                 if (entry->key == key) {
97                         complete(&entry->c);
98                         goto out;
99                 }
100
101         /* Only set the bit in case there where nobody waiting */
102         set_bit(key, optee->notif.bitmap);
103 out:
104         spin_unlock_irqrestore(&optee->notif.lock, flags);
105
106         return 0;
107 }
108
109 int optee_notif_init(struct optee *optee, u_int max_key)
110 {
111         spin_lock_init(&optee->notif.lock);
112         INIT_LIST_HEAD(&optee->notif.db);
113         optee->notif.bitmap = bitmap_zalloc(max_key, GFP_KERNEL);
114         if (!optee->notif.bitmap)
115                 return -ENOMEM;
116
117         optee->notif.max_key = max_key;
118
119         return 0;
120 }
121
122 void optee_notif_uninit(struct optee *optee)
123 {
124         bitmap_free(optee->notif.bitmap);
125 }