1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
4 */
5
6 #define pr_fmt(fmt) "gunyah: " fmt
7
8 #include <linux/completion.h>
9 #include <linux/gunyah.h>
10 #include <linux/module.h>
11 #include <linux/mutex.h>
12 #include <linux/notifier.h>
13 #include <linux/of.h>
14 #include <linux/of_irq.h>
15 #include <linux/platform_device.h>
16 #include <linux/miscdevice.h>
17 #include <linux/auxiliary_bus.h>
18
19 #include <asm/gunyah.h>
20
21 #include "rsc_mgr.h"
22 #include "vm_mgr.h"
23
24 /* clang-format off */
25 #define RM_RPC_API_VERSION_MASK GENMASK(3, 0)
26 #define RM_RPC_HEADER_WORDS_MASK GENMASK(7, 4)
27 #define RM_RPC_API_VERSION FIELD_PREP(RM_RPC_API_VERSION_MASK, 1)
28 #define RM_RPC_HEADER_WORDS FIELD_PREP(RM_RPC_HEADER_WORDS_MASK, \
29 (sizeof(struct gunyah_rm_rpc_hdr) / sizeof(u32)))
30 #define RM_RPC_API (RM_RPC_API_VERSION | RM_RPC_HEADER_WORDS)
31
32 #define RM_RPC_TYPE_CONTINUATION 0x0
33 #define RM_RPC_TYPE_REQUEST 0x1
34 #define RM_RPC_TYPE_REPLY 0x2
35 #define RM_RPC_TYPE_NOTIF 0x3
36 #define RM_RPC_TYPE_MASK GENMASK(1, 0)
37
38 #define GUNYAH_RM_MAX_NUM_FRAGMENTS 62
39 #define RM_RPC_FRAGMENTS_MASK GENMASK(7, 2)
40 /* clang-format on */
41
42 struct gunyah_rm_rpc_hdr {
43 u8 api;
44 u8 type;
45 __le16 seq;
46 __le32 msg_id;
47 } __packed;
48
49 struct gunyah_rm_rpc_reply_hdr {
50 struct gunyah_rm_rpc_hdr hdr;
51 __le32 err_code; /* GUNYAH_RM_ERROR_* */
52 } __packed;
53
54 #define GUNYAH_RM_MSGQ_MSG_SIZE 240
55 #define GUNYAH_RM_PAYLOAD_SIZE \
56 (GUNYAH_RM_MSGQ_MSG_SIZE - sizeof(struct gunyah_rm_rpc_hdr))
57
58 /* RM Error codes */
59 enum gunyah_rm_error {
60 /* clang-format off */
61 GUNYAH_RM_ERROR_OK = 0x0,
62 GUNYAH_RM_ERROR_UNIMPLEMENTED = 0xFFFFFFFF,
63 GUNYAH_RM_ERROR_NOMEM = 0x1,
64 GUNYAH_RM_ERROR_NORESOURCE = 0x2,
65 GUNYAH_RM_ERROR_DENIED = 0x3,
66 GUNYAH_RM_ERROR_INVALID = 0x4,
67 GUNYAH_RM_ERROR_BUSY = 0x5,
68 GUNYAH_RM_ERROR_ARGUMENT_INVALID = 0x6,
69 GUNYAH_RM_ERROR_HANDLE_INVALID = 0x7,
70 GUNYAH_RM_ERROR_VALIDATE_FAILED = 0x8,
71 GUNYAH_RM_ERROR_MAP_FAILED = 0x9,
72 GUNYAH_RM_ERROR_MEM_INVALID = 0xA,
73 GUNYAH_RM_ERROR_MEM_INUSE = 0xB,
74 GUNYAH_RM_ERROR_MEM_RELEASED = 0xC,
75 GUNYAH_RM_ERROR_VMID_INVALID = 0xD,
76 GUNYAH_RM_ERROR_LOOKUP_FAILED = 0xE,
77 GUNYAH_RM_ERROR_IRQ_INVALID = 0xF,
78 GUNYAH_RM_ERROR_IRQ_INUSE = 0x10,
79 GUNYAH_RM_ERROR_IRQ_RELEASED = 0x11,
80 /* clang-format on */
81 };
82
83 struct gunyah_rm_info {
84 __le64 tx_msgq_cap;
85 __le64 rx_msgq_cap;
86 __le32 tx_msgq_irq;
87 __le32 rx_msgq_irq;
88 __le32 tx_msgq_queue_depth;
89 __le32 tx_msgq_max_msg_size;
90 __le32 rx_msgq_queue_depth;
91 __le32 rx_msgq_max_msg_size;
92 };
93
94 /**
95 * struct gunyah_rm_message - Represents a complete message from resource manager
96 * @payload: Combined payload of all the fragments (msg headers stripped off).
97 * @size: Size of the payload received so far.
98 * @msg_id: Message ID from the header.
99 * @type: RM_RPC_TYPE_REPLY or RM_RPC_TYPE_NOTIF.
100 * @num_fragments: total number of fragments expected to be received.
101 * @fragments_received: fragments received so far.
102 * @reply: Fields used for request/reply sequences
103 */
104 struct gunyah_rm_message {
105 void *payload;
106 size_t size;
107 u32 msg_id;
108 u8 type;
109
110 u8 num_fragments;
111 u8 fragments_received;
112
113 /**
114 * @ret: Linux return code, there was an error processing message
115 * @seq: Sequence ID for the main message.
116 * @rm_error: For request/reply sequences with standard replies
117 * @seq_done: Signals caller that the RM reply has been received
118 */
119 struct {
120 int ret;
121 u16 seq;
122 enum gunyah_rm_error rm_error;
123 struct completion seq_done;
124 } reply;
125 };
126
127 /**
128 * struct gunyah_rm - private data for communicating w/Gunyah resource manager
129 * @tx_ghrsc: message queue resource to TX to RM
130 * @rx_ghrsc: message queue resource to RX from RM
131 * @active_rx_message: ongoing gunyah_rm_message for which we're receiving fragments
132 * @call_xarray: xarray to allocate & lookup sequence IDs for Request/Response flows
133 * @next_seq: next ID to allocate (for xa_alloc_cyclic)
134 * @recv_msg: cached allocation for Rx messages
135 * @send_msg: cached allocation for Tx messages. Must hold @send_lock to manipulate.
136 * @send_lock: synchronization to allow only one request to be sent at a time
137 * @send_ready: completed when we know Tx message queue can take more messages
138 * @nh: notifier chain for clients interested in RM notification messages
139 * @miscdev: /dev/gunyah
140 * @parent_fwnode: Parent IRQ fwnode to translate Gunyah hwirqs to Linux irqs
141 */
142 struct gunyah_rm {
143 struct gunyah_resource tx_ghrsc;
144 struct gunyah_resource rx_ghrsc;
145 struct gunyah_rm_message *active_rx_message;
146
147 struct xarray call_xarray;
148 u32 next_seq;
149
150 unsigned char recv_msg[GUNYAH_RM_MSGQ_MSG_SIZE];
151 unsigned char send_msg[GUNYAH_RM_MSGQ_MSG_SIZE];
152 struct mutex send_lock;
153 struct completion send_ready;
154 struct blocking_notifier_head nh;
155
156 struct auxiliary_device adev;
157 struct miscdevice miscdev;
158 struct fwnode_handle *parent_fwnode;
159 };
160
161 /**
162 * gunyah_rm_error_remap() - Remap Gunyah resource manager errors into a Linux error code
163 * @rm_error: "Standard" return value from Gunyah resource manager
164 */
gunyah_rm_error_remap(enum gunyah_rm_error rm_error)165 static inline int gunyah_rm_error_remap(enum gunyah_rm_error rm_error)
166 {
167 switch (rm_error) {
168 case GUNYAH_RM_ERROR_OK:
169 return 0;
170 case GUNYAH_RM_ERROR_UNIMPLEMENTED:
171 return -EOPNOTSUPP;
172 case GUNYAH_RM_ERROR_NOMEM:
173 return -ENOMEM;
174 case GUNYAH_RM_ERROR_NORESOURCE:
175 return -ENODEV;
176 case GUNYAH_RM_ERROR_DENIED:
177 return -EPERM;
178 case GUNYAH_RM_ERROR_BUSY:
179 return -EBUSY;
180 case GUNYAH_RM_ERROR_INVALID:
181 case GUNYAH_RM_ERROR_ARGUMENT_INVALID:
182 case GUNYAH_RM_ERROR_HANDLE_INVALID:
183 case GUNYAH_RM_ERROR_VALIDATE_FAILED:
184 case GUNYAH_RM_ERROR_MAP_FAILED:
185 case GUNYAH_RM_ERROR_MEM_INVALID:
186 case GUNYAH_RM_ERROR_MEM_INUSE:
187 case GUNYAH_RM_ERROR_MEM_RELEASED:
188 case GUNYAH_RM_ERROR_VMID_INVALID:
189 case GUNYAH_RM_ERROR_LOOKUP_FAILED:
190 case GUNYAH_RM_ERROR_IRQ_INVALID:
191 case GUNYAH_RM_ERROR_IRQ_INUSE:
192 case GUNYAH_RM_ERROR_IRQ_RELEASED:
193 return -EINVAL;
194 default:
195 return -EBADMSG;
196 }
197 }
198
gunyah_rm_alloc_irq(struct gunyah_rm * rm,u32 virq)199 static int gunyah_rm_alloc_irq(struct gunyah_rm *rm, u32 virq)
200 {
201 struct irq_fwspec fwspec;
202 int ret;
203
204 fwspec.fwnode = rm->parent_fwnode;
205 ret = arch_gunyah_fill_irq_fwspec_params(virq, &fwspec);
206 if (ret) {
207 pr_err("Failed to translate interrupt: %d\n", ret);
208 return ret;
209 }
210
211 ret = irq_create_fwspec_mapping(&fwspec);
212 if (ret < 0) {
213 pr_err("Failed to allocate irq mapping: %d\n", ret);
214 return ret;
215 }
216
217 return ret;
218 }
219
220
221 struct gunyah_resource *
gunyah_rm_alloc_resource(struct gunyah_rm * rm,struct gunyah_rm_hyp_resource * hyp_resource)222 gunyah_rm_alloc_resource(struct gunyah_rm *rm,
223 struct gunyah_rm_hyp_resource *hyp_resource)
224 {
225 struct gunyah_resource *ghrsc;
226 int ret;
227
228 ghrsc = kzalloc(sizeof(*ghrsc), GFP_KERNEL);
229 if (!ghrsc)
230 return NULL;
231
232 ghrsc->type = hyp_resource->type;
233 ghrsc->capid = le64_to_cpu(hyp_resource->cap_id);
234 ghrsc->irq = IRQ_NOTCONNECTED;
235 ghrsc->rm_label = le32_to_cpu(hyp_resource->resource_label);
236 if (hyp_resource->virq) {
237 ret = gunyah_rm_alloc_irq(rm, le32_to_cpu(hyp_resource->virq));
238 if (ret < 0) {
239 pr_err("Failed to allocate interrupt for resource %d label: %d: %d\n",
240 ghrsc->type, ghrsc->rm_label, ret);
241 kfree(ghrsc);
242 return NULL;
243 }
244 ghrsc->irq = ret;
245 }
246
247 return ghrsc;
248 }
249
gunyah_rm_free_resource(struct gunyah_resource * ghrsc)250 void gunyah_rm_free_resource(struct gunyah_resource *ghrsc)
251 {
252 irq_dispose_mapping(ghrsc->irq);
253 kfree(ghrsc);
254 }
255
gunyah_rm_init_message_payload(struct gunyah_rm_message * message,const void * msg,size_t hdr_size,size_t msg_size)256 static int gunyah_rm_init_message_payload(struct gunyah_rm_message *message,
257 const void *msg, size_t hdr_size,
258 size_t msg_size)
259 {
260 const struct gunyah_rm_rpc_hdr *hdr = msg;
261 size_t max_buf_size, payload_size;
262
263 if (msg_size < hdr_size)
264 return -EINVAL;
265
266 payload_size = msg_size - hdr_size;
267
268 message->num_fragments = FIELD_GET(RM_RPC_FRAGMENTS_MASK, hdr->type);
269 message->fragments_received = 0;
270
271 /* There's not going to be any payload, no need to allocate buffer. */
272 if (!payload_size && !message->num_fragments)
273 return 0;
274
275 if (message->num_fragments > GUNYAH_RM_MAX_NUM_FRAGMENTS)
276 return -EINVAL;
277
278 max_buf_size = payload_size +
279 (message->num_fragments * GUNYAH_RM_PAYLOAD_SIZE);
280
281 message->payload = kzalloc(max_buf_size, GFP_KERNEL);
282 if (!message->payload)
283 return -ENOMEM;
284
285 memcpy(message->payload, msg + hdr_size, payload_size);
286 message->size = payload_size;
287 return 0;
288 }
289
gunyah_rm_abort_message(struct gunyah_rm * rm)290 static void gunyah_rm_abort_message(struct gunyah_rm *rm)
291 {
292 kfree(rm->active_rx_message->payload);
293
294 switch (rm->active_rx_message->type) {
295 case RM_RPC_TYPE_REPLY:
296 rm->active_rx_message->reply.ret = -EIO;
297 complete(&rm->active_rx_message->reply.seq_done);
298 break;
299 case RM_RPC_TYPE_NOTIF:
300 fallthrough;
301 default:
302 kfree(rm->active_rx_message);
303 }
304
305 rm->active_rx_message = NULL;
306 }
307
gunyah_rm_try_complete_message(struct gunyah_rm * rm)308 static inline void gunyah_rm_try_complete_message(struct gunyah_rm *rm)
309 {
310 struct gunyah_rm_message *message = rm->active_rx_message;
311
312 if (!message || message->fragments_received != message->num_fragments)
313 return;
314
315 switch (message->type) {
316 case RM_RPC_TYPE_REPLY:
317 complete(&message->reply.seq_done);
318 break;
319 case RM_RPC_TYPE_NOTIF:
320 blocking_notifier_call_chain(&rm->nh, message->msg_id,
321 message->payload);
322
323 kfree(message->payload);
324 kfree(message);
325 break;
326 default:
327 pr_err_ratelimited("Invalid message type (%u) received\n",
328 message->type);
329 gunyah_rm_abort_message(rm);
330 break;
331 }
332
333 rm->active_rx_message = NULL;
334 }
335
gunyah_rm_process_notif(struct gunyah_rm * rm,const void * msg,size_t msg_size)336 static void gunyah_rm_process_notif(struct gunyah_rm *rm, const void *msg,
337 size_t msg_size)
338 {
339 const struct gunyah_rm_rpc_hdr *hdr = msg;
340 struct gunyah_rm_message *message;
341 int ret;
342
343 if (rm->active_rx_message) {
344 pr_err("Unexpected new notification, still processing an active message\n");
345 gunyah_rm_abort_message(rm);
346 }
347
348 message = kzalloc(sizeof(*message), GFP_KERNEL);
349 if (!message)
350 return;
351
352 message->type = RM_RPC_TYPE_NOTIF;
353 message->msg_id = le32_to_cpu(hdr->msg_id);
354
355 ret = gunyah_rm_init_message_payload(message, msg, sizeof(*hdr),
356 msg_size);
357 if (ret) {
358 pr_err("Failed to initialize message for notification: %d\n",
359 ret);
360 kfree(message);
361 return;
362 }
363
364 rm->active_rx_message = message;
365
366 gunyah_rm_try_complete_message(rm);
367 }
368
gunyah_rm_process_reply(struct gunyah_rm * rm,const void * msg,size_t msg_size)369 static void gunyah_rm_process_reply(struct gunyah_rm *rm, const void *msg,
370 size_t msg_size)
371 {
372 const struct gunyah_rm_rpc_reply_hdr *reply_hdr = msg;
373 struct gunyah_rm_message *message;
374 u16 seq_id;
375
376 seq_id = le16_to_cpu(reply_hdr->hdr.seq);
377 message = xa_load(&rm->call_xarray, seq_id);
378
379 if (!message || message->msg_id != le32_to_cpu(reply_hdr->hdr.msg_id))
380 return;
381
382 if (rm->active_rx_message) {
383 pr_err("Unexpected new reply, still processing an active message\n");
384 gunyah_rm_abort_message(rm);
385 }
386
387 if (gunyah_rm_init_message_payload(message, msg, sizeof(*reply_hdr),
388 msg_size)) {
389 pr_err("Failed to alloc message buffer for sequence %d\n",
390 seq_id);
391 /* Send message complete and error the client. */
392 message->reply.ret = -ENOMEM;
393 complete(&message->reply.seq_done);
394 return;
395 }
396
397 message->reply.rm_error = le32_to_cpu(reply_hdr->err_code);
398 rm->active_rx_message = message;
399
400 gunyah_rm_try_complete_message(rm);
401 }
402
gunyah_rm_process_cont(struct gunyah_rm * rm,struct gunyah_rm_message * message,const void * msg,size_t msg_size)403 static void gunyah_rm_process_cont(struct gunyah_rm *rm,
404 struct gunyah_rm_message *message,
405 const void *msg, size_t msg_size)
406 {
407 const struct gunyah_rm_rpc_hdr *hdr = msg;
408 size_t payload_size = msg_size - sizeof(*hdr);
409
410 if (!rm->active_rx_message)
411 return;
412
413 /*
414 * hdr->fragments and hdr->msg_id preserves the value from first reply
415 * or notif message. To detect mishandling, check it's still intact.
416 */
417 if (message->msg_id != le32_to_cpu(hdr->msg_id) ||
418 message->num_fragments !=
419 FIELD_GET(RM_RPC_FRAGMENTS_MASK, hdr->type)) {
420 gunyah_rm_abort_message(rm);
421 return;
422 }
423
424 memcpy(message->payload + message->size, msg + sizeof(*hdr),
425 payload_size);
426 message->size += payload_size;
427 message->fragments_received++;
428
429 gunyah_rm_try_complete_message(rm);
430 }
431
gunyah_rm_rx(int irq,void * data)432 static irqreturn_t gunyah_rm_rx(int irq, void *data)
433 {
434 enum gunyah_error gunyah_error;
435 struct gunyah_rm_rpc_hdr *hdr;
436 struct gunyah_rm *rm = data;
437 void *msg = &rm->recv_msg[0];
438 size_t len;
439 bool ready;
440
441 do {
442 gunyah_error = gunyah_hypercall_msgq_recv(rm->rx_ghrsc.capid,
443 msg,
444 sizeof(rm->recv_msg),
445 &len, &ready);
446 if (gunyah_error != GUNYAH_ERROR_OK) {
447 if (gunyah_error != GUNYAH_ERROR_MSGQUEUE_EMPTY)
448 pr_warn("Failed to receive data: %d\n",
449 gunyah_error);
450 return IRQ_HANDLED;
451 }
452
453 if (len < sizeof(*hdr)) {
454 pr_err_ratelimited("Too small message received. size=%ld\n", len);
455 continue;
456 }
457
458 hdr = msg;
459 if (hdr->api != RM_RPC_API) {
460 pr_err("Unknown RM RPC API version: %x\n",
461 hdr->api);
462 return IRQ_HANDLED;
463 }
464
465 switch (FIELD_GET(RM_RPC_TYPE_MASK, hdr->type)) {
466 case RM_RPC_TYPE_NOTIF:
467 gunyah_rm_process_notif(rm, msg, len);
468 break;
469 case RM_RPC_TYPE_REPLY:
470 gunyah_rm_process_reply(rm, msg, len);
471 break;
472 case RM_RPC_TYPE_CONTINUATION:
473 gunyah_rm_process_cont(rm, rm->active_rx_message, msg,
474 len);
475 break;
476 default:
477 pr_err("Invalid message type (%lu) received\n",
478 FIELD_GET(RM_RPC_TYPE_MASK, hdr->type));
479 return IRQ_HANDLED;
480 }
481 } while (ready);
482
483 return IRQ_HANDLED;
484 }
485
gunyah_rm_tx(int irq,void * data)486 static irqreturn_t gunyah_rm_tx(int irq, void *data)
487 {
488 struct gunyah_rm *rm = data;
489
490 complete(&rm->send_ready);
491
492 return IRQ_HANDLED;
493 }
494
gunyah_rm_msgq_send(struct gunyah_rm * rm,size_t size,bool push)495 static int gunyah_rm_msgq_send(struct gunyah_rm *rm, size_t size, bool push)
496 {
497 const u64 tx_flags = push ? GUNYAH_HYPERCALL_MSGQ_TX_FLAGS_PUSH : 0;
498 enum gunyah_error gunyah_error;
499 void *data = &rm->send_msg[0];
500 bool ready;
501
502 lockdep_assert_held(&rm->send_lock);
503
504 again:
505 wait_for_completion(&rm->send_ready);
506 gunyah_error = gunyah_hypercall_msgq_send(rm->tx_ghrsc.capid, size,
507 data, tx_flags, &ready);
508
509 /* Should never happen because Linux properly tracks the ready-state of the msgq */
510 if (WARN_ON(gunyah_error == GUNYAH_ERROR_MSGQUEUE_FULL))
511 goto again;
512
513 if (ready)
514 complete(&rm->send_ready);
515
516 return gunyah_error_remap(gunyah_error);
517 }
518
gunyah_rm_send_request(struct gunyah_rm * rm,u32 message_id,const void * req_buf,size_t req_buf_size,struct gunyah_rm_message * message)519 static int gunyah_rm_send_request(struct gunyah_rm *rm, u32 message_id,
520 const void *req_buf, size_t req_buf_size,
521 struct gunyah_rm_message *message)
522 {
523 size_t buf_size_remaining = req_buf_size;
524 const void *req_buf_curr = req_buf;
525 struct gunyah_rm_rpc_hdr *hdr =
526 (struct gunyah_rm_rpc_hdr *)&rm->send_msg[0];
527 struct gunyah_rm_rpc_hdr hdr_template;
528 void *payload = hdr + 1;
529 u32 cont_fragments = 0;
530 size_t payload_size;
531 bool push;
532 int ret;
533
534 if (req_buf_size >
535 GUNYAH_RM_MAX_NUM_FRAGMENTS * GUNYAH_RM_PAYLOAD_SIZE) {
536 pr_warn("Limit (%lu bytes) exceeded for the maximum message size: %lu\n",
537 GUNYAH_RM_MAX_NUM_FRAGMENTS * GUNYAH_RM_PAYLOAD_SIZE,
538 req_buf_size);
539 dump_stack();
540 return -E2BIG;
541 }
542
543 if (req_buf_size)
544 cont_fragments = (req_buf_size - 1) / GUNYAH_RM_PAYLOAD_SIZE;
545
546 hdr_template.api = RM_RPC_API;
547 hdr_template.type = FIELD_PREP(RM_RPC_TYPE_MASK, RM_RPC_TYPE_REQUEST) |
548 FIELD_PREP(RM_RPC_FRAGMENTS_MASK, cont_fragments);
549 hdr_template.seq = cpu_to_le16(message->reply.seq);
550 hdr_template.msg_id = cpu_to_le32(message_id);
551
552 do {
553 *hdr = hdr_template;
554
555 /* Copy payload */
556 payload_size = min(buf_size_remaining, GUNYAH_RM_PAYLOAD_SIZE);
557 memcpy(payload, req_buf_curr, payload_size);
558 req_buf_curr += payload_size;
559 buf_size_remaining -= payload_size;
560
561 /* Only the last message should have push flag set */
562 push = !buf_size_remaining;
563 ret = gunyah_rm_msgq_send(rm, sizeof(*hdr) + payload_size,
564 push);
565 if (ret)
566 break;
567
568 hdr_template.type =
569 FIELD_PREP(RM_RPC_TYPE_MASK, RM_RPC_TYPE_CONTINUATION) |
570 FIELD_PREP(RM_RPC_FRAGMENTS_MASK, cont_fragments);
571 } while (buf_size_remaining);
572
573 return ret;
574 }
575
576 /**
577 * gunyah_rm_call: Achieve request-response type communication with RPC
578 * @rm: Pointer to Gunyah resource manager internal data
579 * @message_id: The RM RPC message-id
580 * @req_buf: Request buffer that contains the payload
581 * @req_buf_size: Total size of the payload
582 * @resp_buf: Pointer to a response buffer
583 * @resp_buf_size: Size of the response buffer
584 *
585 * Make a request to the Resource Manager and wait for reply back. For a successful
586 * response, the function returns the payload. The size of the payload is set in
587 * resp_buf_size. The resp_buf must be freed by the caller when 0 is returned
588 * and resp_buf_size != 0.
589 *
590 * req_buf should be not NULL for req_buf_size >0. If req_buf_size == 0,
591 * req_buf *can* be NULL and no additional payload is sent.
592 *
593 * Context: Process context. Will sleep waiting for reply.
594 * Return: 0 on success. <0 if error.
595 */
gunyah_rm_call(struct gunyah_rm * rm,u32 message_id,const void * req_buf,size_t req_buf_size,void ** resp_buf,size_t * resp_buf_size)596 int gunyah_rm_call(struct gunyah_rm *rm, u32 message_id, const void *req_buf,
597 size_t req_buf_size, void **resp_buf, size_t *resp_buf_size)
598 {
599 struct gunyah_rm_message message = { 0 };
600 u32 seq_id;
601 int ret;
602
603 /* message_id 0 is reserved. req_buf_size implies req_buf is not NULL */
604 if (!rm || !message_id || (!req_buf && req_buf_size))
605 return -EINVAL;
606
607 message.type = RM_RPC_TYPE_REPLY;
608 message.msg_id = message_id;
609
610 message.reply.seq_done =
611 COMPLETION_INITIALIZER_ONSTACK(message.reply.seq_done);
612
613 /* Allocate a new seq number for this message */
614 ret = xa_alloc_cyclic(&rm->call_xarray, &seq_id, &message, xa_limit_16b,
615 &rm->next_seq, GFP_KERNEL);
616 if (ret < 0)
617 return ret;
618 message.reply.seq = lower_16_bits(seq_id);
619
620 mutex_lock(&rm->send_lock);
621 /* Send the request to the Resource Manager */
622 ret = gunyah_rm_send_request(rm, message_id, req_buf, req_buf_size,
623 &message);
624 if (ret < 0) {
625 pr_warn("Failed to send request. Error: %d\n", ret);
626 goto out;
627 }
628
629 /*
630 * Wait for response. Uninterruptible because rollback based on what RM did to VM
631 * requires us to know how RM handled the call.
632 */
633 wait_for_completion(&message.reply.seq_done);
634
635 /* Check for internal (kernel) error waiting for the response */
636 if (message.reply.ret) {
637 ret = message.reply.ret;
638 goto out;
639 }
640
641 /* Got a response, did resource manager give us an error? */
642 if (message.reply.rm_error != GUNYAH_RM_ERROR_OK) {
643 pr_warn("RM rejected message %08x. Error: %d\n",
644 message_id, message.reply.rm_error);
645 ret = gunyah_rm_error_remap(message.reply.rm_error);
646 kfree(message.payload);
647 goto out;
648 }
649
650 /* Everything looks good, return the payload */
651 if (resp_buf_size)
652 *resp_buf_size = message.size;
653
654 if (message.size && resp_buf) {
655 *resp_buf = message.payload;
656 } else {
657 /* kfree in case RM sent us multiple fragments but never any data in
658 * those fragments. We would've allocated memory for it, but message.size == 0
659 */
660 kfree(message.payload);
661 }
662
663 out:
664 mutex_unlock(&rm->send_lock);
665 xa_erase(&rm->call_xarray, message.reply.seq);
666 return ret;
667 }
668 EXPORT_SYMBOL_GPL(gunyah_rm_call);
669
gunyah_rm_notifier_register(struct gunyah_rm * rm,struct notifier_block * nb)670 int gunyah_rm_notifier_register(struct gunyah_rm *rm, struct notifier_block *nb)
671 {
672 return blocking_notifier_chain_register(&rm->nh, nb);
673 }
674 EXPORT_SYMBOL_GPL(gunyah_rm_notifier_register);
675
gunyah_rm_notifier_unregister(struct gunyah_rm * rm,struct notifier_block * nb)676 int gunyah_rm_notifier_unregister(struct gunyah_rm *rm,
677 struct notifier_block *nb)
678 {
679 return blocking_notifier_chain_unregister(&rm->nh, nb);
680 }
681 EXPORT_SYMBOL_GPL(gunyah_rm_notifier_unregister);
682
gunyah_rm_get(struct gunyah_rm * rm)683 struct device *gunyah_rm_get(struct gunyah_rm *rm)
684 {
685 return get_device(rm->miscdev.this_device);
686 }
687 EXPORT_SYMBOL_GPL(gunyah_rm_get);
688
gunyah_rm_put(struct gunyah_rm * rm)689 void gunyah_rm_put(struct gunyah_rm *rm)
690 {
691 put_device(rm->miscdev.this_device);
692 }
693 EXPORT_SYMBOL_GPL(gunyah_rm_put);
694
gunyah_dev_ioctl(struct file * filp,unsigned int cmd,unsigned long arg)695 static long gunyah_dev_ioctl(struct file *filp, unsigned int cmd,
696 unsigned long arg)
697 {
698 struct miscdevice *miscdev = filp->private_data;
699 struct gunyah_rm *rm = container_of(miscdev, struct gunyah_rm, miscdev);
700
701 return gunyah_dev_vm_mgr_ioctl(rm, cmd, arg);
702 }
703
704 static const struct file_operations gunyah_dev_fops = {
705 /* clang-format off */
706 .owner = THIS_MODULE,
707 .unlocked_ioctl = gunyah_dev_ioctl,
708 .compat_ioctl = compat_ptr_ioctl,
709 .llseek = noop_llseek,
710 /* clang-format on */
711 };
712
gunyah_rm_probe_info_area(struct gunyah_rm * rm)713 static int gunyah_rm_probe_info_area(struct gunyah_rm *rm)
714 {
715 struct gunyah_rm_info *info;
716 size_t info_size;
717 int ret;
718
719 info = gunyah_get_info(GUNYAH_INFO_OWNER_RM, 0, &info_size);
720 if (IS_ERR_OR_NULL(info))
721 return -ENOENT;
722 if (info_size != sizeof(*info))
723 return -EINVAL;
724
725 rm->tx_ghrsc.type = GUNYAH_RESOURCE_TYPE_MSGQ_TX;
726 rm->tx_ghrsc.capid = le64_to_cpu(info->tx_msgq_cap);
727 ret = gunyah_rm_alloc_irq(rm, le32_to_cpu(info->tx_msgq_irq));
728 if (ret <= 0)
729 return -EINVAL;
730 rm->tx_ghrsc.irq = ret;
731
732 rm->rx_ghrsc.type = GUNYAH_RESOURCE_TYPE_MSGQ_RX;
733 rm->rx_ghrsc.capid = le64_to_cpu(info->rx_msgq_cap);
734 ret = gunyah_rm_alloc_irq(rm, le32_to_cpu(info->rx_msgq_irq));
735 if (ret <= 0)
736 return -EINVAL;
737 rm->rx_ghrsc.irq = ret;
738
739 return 0;
740 }
741
gunyah_rm_get_of_info(struct gunyah_rm * rm)742 static int gunyah_rm_get_of_info(struct gunyah_rm *rm)
743 {
744 struct device_node *gunyah_np __free(device_node) = NULL;
745 struct device_node *rm_np __free(device_node) = NULL;
746 int ret;
747
748 if (!arch_is_gunyah_guest())
749 return -ENODEV;
750
751 gunyah_np = of_find_node_by_path("/hypervisor");
752 if (!gunyah_np)
753 return -ENODEV;
754
755 rm_np = of_get_compatible_child(gunyah_np, "gunyah-resource-manager");
756 if (!rm_np)
757 return -ENODEV;
758
759 rm->tx_ghrsc.type = GUNYAH_RESOURCE_TYPE_MSGQ_TX;
760 ret = of_property_read_u64_index(rm_np, "reg", 0, &rm->tx_ghrsc.capid);
761 if (ret)
762 return -EINVAL;
763
764 ret = of_irq_get(rm_np, 0);
765 if (ret <= 0)
766 return -EINVAL;
767 rm->tx_ghrsc.irq = ret;
768
769 rm->rx_ghrsc.type = GUNYAH_RESOURCE_TYPE_MSGQ_RX;
770 ret = of_property_read_u64_index(rm_np, "reg", 1, &rm->rx_ghrsc.capid);
771 if (ret)
772 return -EINVAL;
773
774 ret = of_irq_get(rm_np, 1);
775 if (ret <= 0)
776 return -EINVAL;
777 rm->rx_ghrsc.irq = ret;
778
779 of_node_put(rm_np);
780 return 0;
781 }
782
gunyah_adev_release(struct device * dev)783 static void gunyah_adev_release(struct device *dev)
784 {
785 /* no-op */
786 }
787
gunyah_adev_init(struct gunyah_rm * rm,const char * name)788 static int gunyah_adev_init(struct gunyah_rm *rm, const char *name)
789 {
790 struct auxiliary_device *adev = &rm->adev;
791 int ret = 0;
792
793 adev->name = name;
794 adev->dev.platform_data = rm;
795 adev->dev.parent = rm->miscdev.this_device;
796 adev->dev.release = gunyah_adev_release;
797 ret = auxiliary_device_init(adev);
798 if (ret)
799 return ret;
800
801 ret = auxiliary_device_add(adev);
802 if (ret) {
803 auxiliary_device_uninit(adev);
804 return ret;
805 }
806
807 return ret;
808 }
809
810 static struct gunyah_rm *__rm;
811
gunyah_rm_init(void)812 static int __init gunyah_rm_init(void)
813 {
814 struct device_node *parent_irq_node;
815 struct gunyah_rm *rm __free(kfree) = NULL;
816 int ret;
817
818 rm = kzalloc(sizeof(*rm), GFP_KERNEL);
819 if (!rm)
820 return -ENOMEM;
821
822 of_node_get(of_root);
823 parent_irq_node = of_irq_find_parent(of_root);
824 if (!parent_irq_node) {
825 pr_err("Failed to find interrupt parent of resource manager\n");
826 return -ENODEV;
827 }
828 of_node_put(of_root);
829
830 rm->parent_fwnode = of_node_to_fwnode(parent_irq_node);
831 if (!rm->parent_fwnode) {
832 pr_err("Failed to find interrupt parent domain of resource manager\n");
833 return -ENODEV;
834 }
835
836 mutex_init(&rm->send_lock);
837 init_completion(&rm->send_ready);
838 BLOCKING_INIT_NOTIFIER_HEAD(&rm->nh);
839 xa_init_flags(&rm->call_xarray, XA_FLAGS_ALLOC);
840
841 ret = gunyah_rm_probe_info_area(rm);
842 if (ret == -ENOENT)
843 ret = gunyah_rm_get_of_info(rm);
844 if (ret)
845 return ret;
846
847 enable_irq_wake(rm->tx_ghrsc.irq);
848 ret = request_threaded_irq(rm->tx_ghrsc.irq, NULL,
849 gunyah_rm_tx, IRQF_ONESHOT,
850 "gunyah_rm_tx", rm);
851 if (ret)
852 return ret;
853 /* assume RM is ready to receive messages from us */
854 complete(&rm->send_ready);
855
856 enable_irq_wake(rm->rx_ghrsc.irq);
857 ret = request_threaded_irq(rm->rx_ghrsc.irq, NULL,
858 gunyah_rm_rx, IRQF_ONESHOT,
859 "gunyah_rm_rx", rm);
860 if (ret)
861 goto free_tx_irq;
862
863 rm->miscdev.name = "gunyah";
864 rm->miscdev.minor = MISC_DYNAMIC_MINOR;
865 rm->miscdev.fops = &gunyah_dev_fops;
866
867 ret = misc_register(&rm->miscdev);
868 if (ret) {
869 pr_err("Failed to register gunyah misc device\n");
870 goto free_rx_irq;
871 }
872
873 ret = gunyah_adev_init(rm, "gh_rm_core");
874 if (ret) {
875 pr_err("Failed to add gh_rm_core device\n");
876 goto deregister_misc;
877 }
878
879 ret = gunyah_cma_mem_init();
880 if (ret)
881 pr_err("Failed to register gunyah CMA device\n");
882
883 __rm = no_free_ptr(rm);
884 return 0;
885 deregister_misc:
886 misc_deregister(&rm->miscdev);
887 free_rx_irq:
888 free_irq(rm->rx_ghrsc.irq, rm);
889 free_tx_irq:
890 free_irq(rm->tx_ghrsc.irq, rm);
891 return ret;
892 }
893 module_init(gunyah_rm_init);
894
gunyah_rm_exit(void)895 static void __exit gunyah_rm_exit(void)
896 {
897 struct gunyah_rm *rm = __rm;
898
899 __rm = NULL;
900
901 if (!rm)
902 return;
903
904 gunyah_cma_mem_exit();
905 auxiliary_device_delete(&rm->adev);
906 misc_deregister(&rm->miscdev);
907 free_irq(rm->rx_ghrsc.irq, rm);
908 free_irq(rm->tx_ghrsc.irq, rm);
909 }
910 module_exit(gunyah_rm_exit);
911
912 MODULE_LICENSE("GPL");
913 MODULE_DESCRIPTION("Gunyah Resource Manager Driver");
914