arm64: dts: qcom: sm8550: add TRNG node
[linux-modified.git] / arch / powerpc / platforms / powernv / opal-async.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * PowerNV OPAL asynchronous completion interfaces
4  *
5  * Copyright 2013-2017 IBM Corp.
6  */
7
8 #undef DEBUG
9
10 #include <linux/kernel.h>
11 #include <linux/init.h>
12 #include <linux/slab.h>
13 #include <linux/sched.h>
14 #include <linux/semaphore.h>
15 #include <linux/spinlock.h>
16 #include <linux/wait.h>
17 #include <linux/gfp.h>
18 #include <linux/of.h>
19 #include <asm/machdep.h>
20 #include <asm/opal.h>
21
22 enum opal_async_token_state {
23         ASYNC_TOKEN_UNALLOCATED = 0,
24         ASYNC_TOKEN_ALLOCATED,
25         ASYNC_TOKEN_DISPATCHED,
26         ASYNC_TOKEN_ABANDONED,
27         ASYNC_TOKEN_COMPLETED
28 };
29
30 struct opal_async_token {
31         enum opal_async_token_state state;
32         struct opal_msg response;
33 };
34
35 static DECLARE_WAIT_QUEUE_HEAD(opal_async_wait);
36 static DEFINE_SPINLOCK(opal_async_comp_lock);
37 static struct semaphore opal_async_sem;
38 static unsigned int opal_max_async_tokens;
39 static struct opal_async_token *opal_async_tokens;
40
41 static int __opal_async_get_token(void)
42 {
43         unsigned long flags;
44         int i, token = -EBUSY;
45
46         spin_lock_irqsave(&opal_async_comp_lock, flags);
47
48         for (i = 0; i < opal_max_async_tokens; i++) {
49                 if (opal_async_tokens[i].state == ASYNC_TOKEN_UNALLOCATED) {
50                         opal_async_tokens[i].state = ASYNC_TOKEN_ALLOCATED;
51                         token = i;
52                         break;
53                 }
54         }
55
56         spin_unlock_irqrestore(&opal_async_comp_lock, flags);
57         return token;
58 }
59
60 /*
61  * Note: If the returned token is used in an opal call and opal returns
62  * OPAL_ASYNC_COMPLETION you MUST call one of opal_async_wait_response() or
63  * opal_async_wait_response_interruptible() at least once before calling another
64  * opal_async_* function
65  */
66 int opal_async_get_token_interruptible(void)
67 {
68         int token;
69
70         /* Wait until a token is available */
71         if (down_interruptible(&opal_async_sem))
72                 return -ERESTARTSYS;
73
74         token = __opal_async_get_token();
75         if (token < 0)
76                 up(&opal_async_sem);
77
78         return token;
79 }
80 EXPORT_SYMBOL_GPL(opal_async_get_token_interruptible);
81
82 static int __opal_async_release_token(int token)
83 {
84         unsigned long flags;
85         int rc;
86
87         if (token < 0 || token >= opal_max_async_tokens) {
88                 pr_err("%s: Passed token is out of range, token %d\n",
89                                 __func__, token);
90                 return -EINVAL;
91         }
92
93         spin_lock_irqsave(&opal_async_comp_lock, flags);
94         switch (opal_async_tokens[token].state) {
95         case ASYNC_TOKEN_COMPLETED:
96         case ASYNC_TOKEN_ALLOCATED:
97                 opal_async_tokens[token].state = ASYNC_TOKEN_UNALLOCATED;
98                 rc = 0;
99                 break;
100         /*
101          * DISPATCHED and ABANDONED tokens must wait for OPAL to respond.
102          * Mark a DISPATCHED token as ABANDONED so that the response handling
103          * code knows no one cares and that it can free it then.
104          */
105         case ASYNC_TOKEN_DISPATCHED:
106                 opal_async_tokens[token].state = ASYNC_TOKEN_ABANDONED;
107                 fallthrough;
108         default:
109                 rc = 1;
110         }
111         spin_unlock_irqrestore(&opal_async_comp_lock, flags);
112
113         return rc;
114 }
115
116 int opal_async_release_token(int token)
117 {
118         int ret;
119
120         ret = __opal_async_release_token(token);
121         if (!ret)
122                 up(&opal_async_sem);
123
124         return ret;
125 }
126 EXPORT_SYMBOL_GPL(opal_async_release_token);
127
128 int opal_async_wait_response(uint64_t token, struct opal_msg *msg)
129 {
130         if (token >= opal_max_async_tokens) {
131                 pr_err("%s: Invalid token passed\n", __func__);
132                 return -EINVAL;
133         }
134
135         if (!msg) {
136                 pr_err("%s: Invalid message pointer passed\n", __func__);
137                 return -EINVAL;
138         }
139
140         /*
141          * There is no need to mark the token as dispatched, wait_event()
142          * will block until the token completes.
143          *
144          * Wakeup the poller before we wait for events to speed things
145          * up on platforms or simulators where the interrupts aren't
146          * functional.
147          */
148         opal_wake_poller();
149         wait_event(opal_async_wait, opal_async_tokens[token].state
150                         == ASYNC_TOKEN_COMPLETED);
151         memcpy(msg, &opal_async_tokens[token].response, sizeof(*msg));
152
153         return 0;
154 }
155 EXPORT_SYMBOL_GPL(opal_async_wait_response);
156
157 int opal_async_wait_response_interruptible(uint64_t token, struct opal_msg *msg)
158 {
159         unsigned long flags;
160         int ret;
161
162         if (token >= opal_max_async_tokens) {
163                 pr_err("%s: Invalid token passed\n", __func__);
164                 return -EINVAL;
165         }
166
167         if (!msg) {
168                 pr_err("%s: Invalid message pointer passed\n", __func__);
169                 return -EINVAL;
170         }
171
172         /*
173          * The first time this gets called we mark the token as DISPATCHED
174          * so that if wait_event_interruptible() returns not zero and the
175          * caller frees the token, we know not to actually free the token
176          * until the response comes.
177          *
178          * Only change if the token is ALLOCATED - it may have been
179          * completed even before the caller gets around to calling this
180          * the first time.
181          *
182          * There is also a dirty great comment at the token allocation
183          * function that if the opal call returns OPAL_ASYNC_COMPLETION to
184          * the caller then the caller *must* call this or the not
185          * interruptible version before doing anything else with the
186          * token.
187          */
188         if (opal_async_tokens[token].state == ASYNC_TOKEN_ALLOCATED) {
189                 spin_lock_irqsave(&opal_async_comp_lock, flags);
190                 if (opal_async_tokens[token].state == ASYNC_TOKEN_ALLOCATED)
191                         opal_async_tokens[token].state = ASYNC_TOKEN_DISPATCHED;
192                 spin_unlock_irqrestore(&opal_async_comp_lock, flags);
193         }
194
195         /*
196          * Wakeup the poller before we wait for events to speed things
197          * up on platforms or simulators where the interrupts aren't
198          * functional.
199          */
200         opal_wake_poller();
201         ret = wait_event_interruptible(opal_async_wait,
202                         opal_async_tokens[token].state ==
203                         ASYNC_TOKEN_COMPLETED);
204         if (!ret)
205                 memcpy(msg, &opal_async_tokens[token].response, sizeof(*msg));
206
207         return ret;
208 }
209 EXPORT_SYMBOL_GPL(opal_async_wait_response_interruptible);
210
211 /* Called from interrupt context */
212 static int opal_async_comp_event(struct notifier_block *nb,
213                 unsigned long msg_type, void *msg)
214 {
215         struct opal_msg *comp_msg = msg;
216         enum opal_async_token_state state;
217         unsigned long flags;
218         uint64_t token;
219
220         if (msg_type != OPAL_MSG_ASYNC_COMP)
221                 return 0;
222
223         token = be64_to_cpu(comp_msg->params[0]);
224         spin_lock_irqsave(&opal_async_comp_lock, flags);
225         state = opal_async_tokens[token].state;
226         opal_async_tokens[token].state = ASYNC_TOKEN_COMPLETED;
227         spin_unlock_irqrestore(&opal_async_comp_lock, flags);
228
229         if (state == ASYNC_TOKEN_ABANDONED) {
230                 /* Free the token, no one else will */
231                 opal_async_release_token(token);
232                 return 0;
233         }
234         memcpy(&opal_async_tokens[token].response, comp_msg, sizeof(*comp_msg));
235         wake_up(&opal_async_wait);
236
237         return 0;
238 }
239
240 static struct notifier_block opal_async_comp_nb = {
241                 .notifier_call  = opal_async_comp_event,
242                 .next           = NULL,
243                 .priority       = 0,
244 };
245
246 int __init opal_async_comp_init(void)
247 {
248         struct device_node *opal_node;
249         const __be32 *async;
250         int err;
251
252         opal_node = of_find_node_by_path("/ibm,opal");
253         if (!opal_node) {
254                 pr_err("%s: Opal node not found\n", __func__);
255                 err = -ENOENT;
256                 goto out;
257         }
258
259         async = of_get_property(opal_node, "opal-msg-async-num", NULL);
260         if (!async) {
261                 pr_err("%s: %pOF has no opal-msg-async-num\n",
262                                 __func__, opal_node);
263                 err = -ENOENT;
264                 goto out_opal_node;
265         }
266
267         opal_max_async_tokens = be32_to_cpup(async);
268         opal_async_tokens = kcalloc(opal_max_async_tokens,
269                         sizeof(*opal_async_tokens), GFP_KERNEL);
270         if (!opal_async_tokens) {
271                 err = -ENOMEM;
272                 goto out_opal_node;
273         }
274
275         err = opal_message_notifier_register(OPAL_MSG_ASYNC_COMP,
276                         &opal_async_comp_nb);
277         if (err) {
278                 pr_err("%s: Can't register OPAL event notifier (%d)\n",
279                                 __func__, err);
280                 kfree(opal_async_tokens);
281                 goto out_opal_node;
282         }
283
284         sema_init(&opal_async_sem, opal_max_async_tokens);
285
286 out_opal_node:
287         of_node_put(opal_node);
288 out:
289         return err;
290 }