• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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