blob: bf52a2382bd1eb0c0af427850e35a4988ee948c2 [file] [log] [blame]
Patrick Williams975a06f2022-10-21 14:42:47 -05001From e187510a814b48b7b2e477a9913ee35b68522d06 Mon Sep 17 00:00:00 2001
2From: Vishnu Banavath <vishnu.banavath@arm.com>
3Date: Fri, 3 Dec 2021 19:00:54 +0000
4Subject: [PATCH 03/19] Add openamp rpc caller
5
6Upstream-Status: Pending
7Signed-off-by: Vishnu Banavath <vishnu.banavath@arm.com>
8Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
9---
10 components/rpc/common/caller/rpc_caller.c | 10 +
11 components/rpc/common/interface/rpc_caller.h | 8 +
12 .../rpc/openamp/caller/sp/component.cmake | 15 +
13 .../rpc/openamp/caller/sp/openamp_caller.c | 203 +++++++
14 .../rpc/openamp/caller/sp/openamp_caller.h | 43 ++
15 .../rpc/openamp/caller/sp/openamp_mhu.c | 191 ++++++
16 .../rpc/openamp/caller/sp/openamp_mhu.h | 19 +
17 .../rpc/openamp/caller/sp/openamp_virtio.c | 555 ++++++++++++++++++
18 .../rpc/openamp/caller/sp/openamp_virtio.h | 24 +
19 .../se-proxy/opteesp/default_se-proxy.dts.in | 6 +
20 deployments/se-proxy/se-proxy.cmake | 1 +
21 11 files changed, 1075 insertions(+)
22 create mode 100644 components/rpc/openamp/caller/sp/component.cmake
23 create mode 100644 components/rpc/openamp/caller/sp/openamp_caller.c
24 create mode 100644 components/rpc/openamp/caller/sp/openamp_caller.h
25 create mode 100644 components/rpc/openamp/caller/sp/openamp_mhu.c
26 create mode 100644 components/rpc/openamp/caller/sp/openamp_mhu.h
27 create mode 100644 components/rpc/openamp/caller/sp/openamp_virtio.c
28 create mode 100644 components/rpc/openamp/caller/sp/openamp_virtio.h
29
30diff --git a/components/rpc/common/caller/rpc_caller.c b/components/rpc/common/caller/rpc_caller.c
31index 2dceabeb8967..20d889c162b0 100644
32--- a/components/rpc/common/caller/rpc_caller.c
33+++ b/components/rpc/common/caller/rpc_caller.c
34@@ -37,3 +37,13 @@ void rpc_caller_end(struct rpc_caller *s, rpc_call_handle handle)
35 {
36 s->call_end(s->context, handle);
37 }
38+
39+void *rpc_caller_virt_to_phys(struct rpc_caller *s, void *va)
40+{
41+ return s->virt_to_phys(s->context, va);
42+}
43+
44+void *rpc_caller_phys_to_virt(struct rpc_caller *s, void *pa)
45+{
46+ return s->phys_to_virt(s->context, pa);
47+}
48diff --git a/components/rpc/common/interface/rpc_caller.h b/components/rpc/common/interface/rpc_caller.h
49index 387489cdb1b2..ef9bb64905ed 100644
50--- a/components/rpc/common/interface/rpc_caller.h
51+++ b/components/rpc/common/interface/rpc_caller.h
52@@ -45,6 +45,10 @@ struct rpc_caller
53 rpc_opstatus_t *opstatus, uint8_t **resp_buf, size_t *resp_len);
54
55 void (*call_end)(void *context, rpc_call_handle handle);
56+
57+ void *(*virt_to_phys)(void *context, void *va);
58+
59+ void *(*phys_to_virt)(void *context, void *pa);
60 };
61
62 /*
63@@ -87,6 +91,10 @@ RPC_CALLER_EXPORTED rpc_status_t rpc_caller_invoke(struct rpc_caller *s, rpc_cal
64 */
65 RPC_CALLER_EXPORTED void rpc_caller_end(struct rpc_caller *s, rpc_call_handle handle);
66
67+RPC_CALLER_EXPORTED void *rpc_caller_virt_to_phys(struct rpc_caller *s, void *va);
68+
69+RPC_CALLER_EXPORTED void *rpc_caller_phys_to_virt(struct rpc_caller *s, void *pa);
70+
71 #ifdef __cplusplus
72 }
73 #endif
74diff --git a/components/rpc/openamp/caller/sp/component.cmake b/components/rpc/openamp/caller/sp/component.cmake
75new file mode 100644
76index 000000000000..fc919529d731
77--- /dev/null
78+++ b/components/rpc/openamp/caller/sp/component.cmake
79@@ -0,0 +1,15 @@
80+#-------------------------------------------------------------------------------
81+# Copyright (c) 2020, Arm Limited and Contributors. All rights reserved.
82+#
83+# SPDX-License-Identifier: BSD-3-Clause
84+#
85+#-------------------------------------------------------------------------------
86+if (NOT DEFINED TGT)
87+ message(FATAL_ERROR "mandatory parameter TGT is not defined.")
88+endif()
89+
90+target_sources(${TGT} PRIVATE
91+ "${CMAKE_CURRENT_LIST_DIR}/openamp_caller.c"
92+ "${CMAKE_CURRENT_LIST_DIR}/openamp_virtio.c"
93+ "${CMAKE_CURRENT_LIST_DIR}/openamp_mhu.c"
94+ )
95diff --git a/components/rpc/openamp/caller/sp/openamp_caller.c b/components/rpc/openamp/caller/sp/openamp_caller.c
96new file mode 100644
97index 000000000000..6cdfb756568f
98--- /dev/null
99+++ b/components/rpc/openamp/caller/sp/openamp_caller.c
100@@ -0,0 +1,203 @@
101+/*
102+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
103+ * Copyright (c) 2021, Linaro Limited. All rights reserved.
104+ *
105+ * SPDX-License-Identifier: BSD-3-Clause
106+ */
107+
108+#include <stddef.h>
109+#include <trace.h>
110+#include "openamp_caller.h"
111+#include "openamp_mhu.h"
112+#include "openamp_virtio.h"
113+#include <protocols/rpc/common/packed-c/status.h>
114+
115+#define OPENAMP_TRANSACTION_IDLE 0x0
116+#define OPENAMP_TRANSACTION_INPROGRESS 0x1
117+#define OPENAMP_TRANSACTION_INVOKED 0x2
118+
119+static rpc_call_handle openamp_call_begin(void *context, uint8_t **req_buf,
120+ size_t req_len)
121+{
122+ struct openamp_caller *openamp = context;
123+ const struct openamp_platform_ops *ops = openamp->platform_ops;
124+ rpc_call_handle handle;
125+ int ret;
126+
127+ if (!req_buf) {
128+ EMSG("openamp: call_begin: not req_buf");
129+ return NULL;
130+ }
131+
132+ if (req_len > UINT32_MAX || req_len == 0) {
133+ EMSG("openamp: call_begin: resp_len invalid: %lu", req_len);
134+ return NULL;
135+ }
136+
137+ if (openamp->status != OPENAMP_TRANSACTION_IDLE) {
138+ EMSG("openamp: call_begin: transaction not idle");
139+ return NULL;
140+ }
141+
142+ ret = ops->platform_call_begin(openamp, req_buf, req_len);
143+ if (ret < 0) {
144+ EMSG("openamp: call_begin: platform begin failed: %d", ret);
145+ return NULL;
146+ }
147+
148+ openamp->status = OPENAMP_TRANSACTION_INPROGRESS;
149+ handle = openamp;
150+
151+ return handle;
152+}
153+
154+static rpc_status_t openamp_call_invoke(void *context, rpc_call_handle handle,
155+ uint32_t opcode, int *opstatus,
156+ uint8_t **resp_buf, size_t *resp_len)
157+{
158+ struct openamp_caller *openamp = context;
159+ const struct openamp_platform_ops *ops = openamp->platform_ops;
160+ rpc_status_t status;
161+ int ret;
162+
163+ (void)opcode;
164+
165+ if ((handle != openamp) || !opstatus || !resp_buf || !resp_len) {
166+ EMSG("openamp: call_invoke: invalid arguments");
167+ return TS_RPC_ERROR_INVALID_PARAMETER;
168+ }
169+
170+ if (openamp->status != OPENAMP_TRANSACTION_INPROGRESS) {
171+ EMSG("openamp: call_invoke: transaction needed to be started");
172+ return TS_RPC_ERROR_NOT_READY;
173+ }
174+
175+ ret = ops->platform_call_invoke(openamp, opstatus, resp_buf, resp_len);
176+ if (ret < 0)
177+ return TS_RPC_ERROR_INTERNAL;
178+
179+ openamp->status = OPENAMP_TRANSACTION_INVOKED;
180+ *opstatus = 0;
181+
182+ return TS_RPC_CALL_ACCEPTED;
183+}
184+
185+static void openamp_call_end(void *context, rpc_call_handle handle)
186+{
187+ struct openamp_caller *openamp = context;
188+ const struct openamp_platform_ops *ops = openamp->platform_ops;
189+
190+ if (handle != openamp) {
191+ EMSG("openamp: call_end: invalid arguments");
192+ return;
193+ }
194+
195+ if (openamp->status == OPENAMP_TRANSACTION_IDLE) {
196+ EMSG("openamp: call_end: transaction idle");
197+ return;
198+ }
199+
200+ ops->platform_call_end(openamp);
201+
202+ openamp->status = OPENAMP_TRANSACTION_IDLE;
203+}
204+
205+static void *openamp_virt_to_phys(void *context, void *va)
206+{
207+ struct openamp_caller *openamp = context;
208+ const struct openamp_platform_ops *ops = openamp->platform_ops;
209+
210+ return ops->platform_virt_to_phys(openamp, va);
211+}
212+
213+static void *openamp_phys_to_virt(void *context, void *pa)
214+{
215+ struct openamp_caller *openamp = context;
216+ const struct openamp_platform_ops *ops = openamp->platform_ops;
217+
218+ return ops->platform_phys_to_virt(openamp, pa);
219+}
220+
221+static int openamp_init(struct openamp_caller *openamp)
222+{
223+ const struct openamp_platform_ops *ops = openamp->platform_ops;
224+ int ret;
225+
226+ ret = ops->transport_init(openamp);
227+ if (ret < 0)
228+ return ret;
229+
230+ ret = ops->platform_init(openamp);
231+ if (ret < 0)
232+ goto denit_transport;
233+
234+ return 0;
235+
236+denit_transport:
237+ ops->transport_deinit(openamp);
238+
239+ return ret;
240+}
241+
242+static const struct openamp_platform_ops openamp_virtio_ops = {
243+ .transport_init = openamp_mhu_init,
244+ .transport_deinit = openamp_mhu_deinit,
245+ .transport_notify = openamp_mhu_notify_peer,
246+ .transport_receive = openamp_mhu_receive,
247+ .platform_init = openamp_virtio_init,
248+ .platform_call_begin = openamp_virtio_call_begin,
249+ .platform_call_invoke = openamp_virtio_call_invoke,
250+ .platform_call_end = openamp_virtio_call_end,
251+ .platform_virt_to_phys = openamp_virtio_virt_to_phys,
252+ .platform_phys_to_virt = openamp_virtio_phys_to_virt,
253+};
254+
255+struct rpc_caller *openamp_caller_init(struct openamp_caller *openamp)
256+{
257+ struct rpc_caller *rpc = &openamp->rpc_caller;
258+ int ret;
259+
260+ if (openamp->ref_count)
261+ return rpc;
262+
263+ rpc_caller_init(rpc, openamp);
264+
265+ rpc->call_begin = openamp_call_begin;
266+ rpc->call_invoke = openamp_call_invoke;
267+ rpc->call_end = openamp_call_end;
268+ rpc->virt_to_phys = openamp_virt_to_phys;
269+ rpc->phys_to_virt = openamp_phys_to_virt;
270+ openamp->platform_ops = &openamp_virtio_ops;
271+
272+ ret = openamp_init(openamp);
273+ if (ret < 0) {
274+ EMSG("openamp_init: failed to start: %d", ret);
275+ return rpc;
276+ }
277+ openamp->ref_count++;
278+
279+ return rpc;
280+}
281+
282+void openamp_caller_deinit(struct openamp_caller *openamp)
283+{
284+ struct rpc_caller *rpc = &openamp->rpc_caller;
285+
286+ if (--openamp->ref_count)
287+ return;
288+
289+ rpc->context = NULL;
290+ rpc->call_begin = NULL;
291+ rpc->call_invoke = NULL;
292+ rpc->call_end = NULL;
293+}
294+
295+int openamp_caller_discover(struct openamp_caller *openamp)
296+{
297+ return openamp_init(openamp);
298+}
299+
300+int openamp_caller_open(struct openamp_caller *openamp)
301+{
302+
303+}
304diff --git a/components/rpc/openamp/caller/sp/openamp_caller.h b/components/rpc/openamp/caller/sp/openamp_caller.h
305new file mode 100644
306index 000000000000..3fb67c56cc53
307--- /dev/null
308+++ b/components/rpc/openamp/caller/sp/openamp_caller.h
309@@ -0,0 +1,43 @@
310+/*
311+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
312+ * Copyright (c) 2021, Linaro Limited. All rights reserved.
313+ *
314+ * SPDX-License-Identifier: BSD-3-Clause
315+ */
316+#ifndef OPENAMP_CALLER_H
317+#define OPENAMP_CALLER_H
318+
319+#include <stddef.h>
320+#include <rpc_caller.h>
321+
322+struct openamp_caller {
323+ struct rpc_caller rpc_caller;
324+ const struct openamp_platform_ops *platform_ops;
325+ uint32_t ref_count;
326+ uint8_t status;
327+
328+ void *transport;
329+ void *platform;
330+};
331+
332+struct openamp_platform_ops {
333+ int (*transport_init)(struct openamp_caller *openamp);
334+ int (*transport_deinit)(struct openamp_caller *openamp);
335+ int (*transport_notify)(struct openamp_caller *openamp);
336+ int (*transport_receive)(struct openamp_caller *openamp);
337+ int (*platform_init)(struct openamp_caller *openamp);
338+ int (*platform_deinit)(struct openamp_caller *openamp);
339+ int (*platform_call_begin)(struct openamp_caller *openamp,
340+ uint8_t **req_buf, size_t req_len);
341+ int (*platform_call_invoke)(struct openamp_caller *openamp,
342+ int *opstatus, uint8_t **resp_buf,
343+ size_t *resp_len);
344+ int (*platform_call_end)(struct openamp_caller *openamp);
345+ void *(*platform_virt_to_phys)(struct openamp_caller *openamp, void *va);
346+ void *(*platform_phys_to_virt)(struct openamp_caller *openamp, void *pa);
347+};
348+
349+struct rpc_caller *openamp_caller_init(struct openamp_caller *openamp);
350+void openamp_caller_deinit(struct openamp_caller *openamp);
351+
352+#endif
353diff --git a/components/rpc/openamp/caller/sp/openamp_mhu.c b/components/rpc/openamp/caller/sp/openamp_mhu.c
354new file mode 100644
355index 000000000000..ffdadaf870a3
356--- /dev/null
357+++ b/components/rpc/openamp/caller/sp/openamp_mhu.c
358@@ -0,0 +1,191 @@
359+/*
360+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
361+ * Copyright (c) 2021, Linaro Limited. All rights reserved.
362+ *
363+ * SPDX-License-Identifier: BSD-3-Clause
364+ */
365+
366+#include <config/interface/config_store.h>
367+#include <config/interface/config_blob.h>
368+#include <platform/interface/device_region.h>
369+#include <platform/drivers/arm/mhu_driver/mhu_v2.h>
370+#include <trace.h>
371+#include <errno.h>
372+#include <stdlib.h>
373+#include <stdint.h>
374+#include <stddef.h>
375+#include <limits.h>
376+
377+#include "openamp_caller.h"
378+
379+#define MHU_V_2_NOTIFY_CHANNEL 0
380+#define MHU_V_2_NOTIFY_VALUE 0xff
381+
382+struct openamp_mhu {
383+ struct device_region rx_region;
384+ struct device_region tx_region;
385+ struct mhu_v2_x_dev_t rx_dev;
386+ struct mhu_v2_x_dev_t tx_dev;
387+};
388+
389+static int openamp_mhu_device_get(const char *dev,
390+ struct device_region *dev_region)
391+{
392+ bool found;
393+
394+ found = config_store_query(CONFIG_CLASSIFIER_DEVICE_REGION, dev, 0,
395+ dev_region, sizeof(*dev_region));
396+ if (!found)
397+ return -EINVAL;
398+
399+ if (!dev_region->base_addr)
400+ return -EINVAL;
401+
402+ IMSG("mhu: device region found: %s addr: 0x%x size: %d", dev,
403+ dev_region->base_addr, dev_region->io_region_size);
404+
405+ return 0;
406+}
407+
408+int openamp_mhu_receive(struct openamp_caller *openamp)
409+{
410+ struct mhu_v2_x_dev_t *rx_dev;
411+ enum mhu_v2_x_error_t ret;
412+ struct openamp_mhu *mhu;
413+ uint32_t channel = 0;
414+ uint32_t irq_status;
415+
416+ if (!openamp->transport) {
417+ EMSG("openamp: mhu: receive transport not initialized");
418+ return -EINVAL;
419+ }
420+
421+ mhu = openamp->transport;
422+ rx_dev = &mhu->rx_dev;
423+
424+ irq_status = 0;
425+
426+ do {
427+ irq_status = mhu_v2_x_get_interrupt_status(rx_dev);
428+ } while(!irq_status);
429+
430+ ret = mhu_v2_1_get_ch_interrupt_num(rx_dev, &channel);
431+
432+ ret = mhu_v2_x_channel_clear(rx_dev, channel);
433+ if (ret != MHU_V_2_X_ERR_NONE) {
434+ EMSG("openamp: mhu: failed to clear channel: %d", channel);
435+ return -EPROTO;
436+ }
437+
438+ return 0;
439+}
440+
441+int openamp_mhu_notify_peer(struct openamp_caller *openamp)
442+{
443+ struct mhu_v2_x_dev_t *tx_dev;
444+ enum mhu_v2_x_error_t ret;
445+ struct openamp_mhu *mhu;
446+ uint32_t access_ready;
447+
448+ if (!openamp->transport) {
449+ EMSG("openamp: mhu: notify transport not initialized");
450+ return -EINVAL;
451+ }
452+
453+ mhu = openamp->transport;
454+ tx_dev = &mhu->tx_dev;
455+
456+ ret = mhu_v2_x_set_access_request(tx_dev);
457+ if (ret != MHU_V_2_X_ERR_NONE) {
458+ EMSG("openamp: mhu: set access request failed");
459+ return -EPROTO;
460+ }
461+
462+ do {
463+ ret = mhu_v2_x_get_access_ready(tx_dev, &access_ready);
464+ if (ret != MHU_V_2_X_ERR_NONE) {
465+ EMSG("openamp: mhu: failed to get access_ready");
466+ return -EPROTO;
467+ }
468+ } while (!access_ready);
469+
470+ ret = mhu_v2_x_channel_send(tx_dev, MHU_V_2_NOTIFY_CHANNEL,
471+ MHU_V_2_NOTIFY_VALUE);
472+ if (ret != MHU_V_2_X_ERR_NONE) {
473+ EMSG("openamp: mhu: failed send over channel");
474+ return -EPROTO;
475+ }
476+
477+ ret = mhu_v2_x_reset_access_request(tx_dev);
478+ if (ret != MHU_V_2_X_ERR_NONE) {
479+ EMSG("openamp: mhu: failed reset access request");
480+ return -EPROTO;
481+ }
482+
483+ return 0;
484+}
485+
486+int openamp_mhu_init(struct openamp_caller *openamp)
487+{
488+ struct mhu_v2_x_dev_t *rx_dev;
489+ struct mhu_v2_x_dev_t *tx_dev;
490+ struct openamp_mhu *mhu;
491+ int ret;
492+
493+ /* if we already have initialized skip this */
494+ if (openamp->transport)
495+ return 0;
496+
497+ mhu = malloc(sizeof(*mhu));
498+ if (!mhu)
499+ return -1;
500+
501+ ret = openamp_mhu_device_get("mhu-sender", &mhu->tx_region);
502+ if (ret < 0)
503+ goto free_mhu;
504+
505+ ret = openamp_mhu_device_get("mhu-receiver", &mhu->rx_region);
506+ if (ret < 0)
507+ goto free_mhu;
508+
509+ rx_dev = &mhu->rx_dev;
510+ tx_dev = &mhu->tx_dev;
511+
512+ rx_dev->base = (unsigned int)mhu->rx_region.base_addr;
513+ rx_dev->frame = MHU_V2_X_RECEIVER_FRAME;
514+
515+ tx_dev->base = (unsigned int)mhu->tx_region.base_addr;
516+ tx_dev->frame = MHU_V2_X_SENDER_FRAME;
517+
518+ ret = mhu_v2_x_driver_init(rx_dev, MHU_REV_READ_FROM_HW);
519+ if (ret < 0)
520+ goto free_mhu;
521+
522+ ret = mhu_v2_x_driver_init(tx_dev, MHU_REV_READ_FROM_HW);
523+ if (ret < 0)
524+ goto free_mhu;
525+
526+ openamp->transport = (void *)mhu;
527+
528+ return 0;
529+
530+free_mhu:
531+ free(mhu);
532+
533+ return ret;
534+}
535+
536+int openamp_mhu_deinit(struct openamp_caller *openamp)
537+{
538+ struct openamp_mhu *mhu;
539+
540+ if (!openamp->transport)
541+ return 0;
542+
543+ mhu = openamp->transport;
544+ free(mhu);
545+
546+ openamp->transport = NULL;
547+
548+ return 0;
549+}
550diff --git a/components/rpc/openamp/caller/sp/openamp_mhu.h b/components/rpc/openamp/caller/sp/openamp_mhu.h
551new file mode 100644
552index 000000000000..2ae5cb8ee1c6
553--- /dev/null
554+++ b/components/rpc/openamp/caller/sp/openamp_mhu.h
555@@ -0,0 +1,19 @@
556+/*
557+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
558+ * Copyright (c) 2021, Linaro Limited. All rights reserved.
559+ *
560+ * SPDX-License-Identifier: BSD-3-Clause
561+ */
562+#ifndef OPENAMP_MHU_H
563+#define OPENAMP_MHU_H
564+
565+#include <stddef.h>
566+#include "openamp_caller.h"
567+
568+int openamp_mhu_init(struct openamp_caller *openamp);
569+int openamp_mhu_deinit(struct openamp_caller *openamp);
570+
571+int openamp_mhu_notify_peer(struct openamp_caller *openamp);
572+int openamp_mhu_receive(struct openamp_caller *openamp);
573+
574+#endif
575diff --git a/components/rpc/openamp/caller/sp/openamp_virtio.c b/components/rpc/openamp/caller/sp/openamp_virtio.c
576new file mode 100644
577index 000000000000..b7c1aa929111
578--- /dev/null
579+++ b/components/rpc/openamp/caller/sp/openamp_virtio.c
580@@ -0,0 +1,555 @@
581+/*
582+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
583+ * Copyright (c) 2021, Linaro Limited. All rights reserved.
584+ *
585+ * SPDX-License-Identifier: BSD-3-Clause
586+ */
587+
588+#include <metal/device.h>
589+#include <metal/spinlock.h>
590+#include <openamp/open_amp.h>
591+#include <platform/interface/device_region.h>
592+#include <config/interface/config_store.h>
593+
594+#include <stddef.h>
595+#include <trace.h>
596+#include "openamp_caller.h"
597+
598+#define OPENAMP_SHEM_DEVICE_NAME "openamp-virtio"
599+#define OPENAMP_RPMSG_ENDPOINT_NAME OPENAMP_SHEM_DEVICE_NAME
600+#define OPENAMP_RPMSG_ENDPOINT_ADDR 1024
601+
602+#define OPENAMP_SHEM_PHYS 0x88000000
603+#define OPENAMP_SHEM_PHYS_PAGES 1
604+#define OPENAMP_SHEM_SE_PHYS 0xa8000000
605+
606+#define OPENAMP_SHEM_VDEV_SIZE (4 * 1024)
607+#define OPENAMP_SHEM_VRING_SIZE (4 * 1024)
608+
609+#define OPENAMP_BUFFER_NO_WAIT 0
610+#define OPENAMP_BUFFER_WAIT 1
611+
612+#define VIRTQUEUE_NR 2
613+#define VQ_TX 0
614+#define VQ_RX 1
615+
616+#define VRING_DESCRIPTORS 16
617+#define VRING_ALIGN 4
618+
619+#define container_of(ptr, type, member) \
620+ ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
621+
622+struct openamp_virtio_shm {
623+ uintptr_t base_addr;
624+ size_t size;
625+ uintptr_t vdev_status;
626+ size_t vdev_status_size;
627+ uintptr_t payload_addr;
628+ size_t payload_size;
629+ uintptr_t vring_tx;
630+ size_t vring_tx_size;
631+ uintptr_t vring_rx;
632+ size_t vring_rx_size;
633+
634+ metal_phys_addr_t shm_physmap[OPENAMP_SHEM_PHYS_PAGES];
635+};
636+
637+struct openamp_virtio_metal {
638+ struct metal_spinlock lock;
639+ struct metal_device shm_dev;
640+ struct metal_device *io_dev;
641+
642+ struct metal_io_region *io;
643+ struct openamp_virtio_shm shm;
644+};
645+
646+struct openamp_virtio_device {
647+ struct virtio_device virtio_dev;
648+ struct virtqueue *vq[VIRTQUEUE_NR];
649+ struct virtio_vring_info rvrings[VIRTQUEUE_NR];
650+};
651+
652+struct openamp_virtio_rpmsg {
653+ struct rpmsg_virtio_device rpmsg_vdev;
654+ struct rpmsg_endpoint ep;
655+ uint8_t *req_buf;
656+ uint32_t req_len;
657+ uint8_t *resp_buf;
658+ size_t resp_len;
659+};
660+
661+struct openamp_virtio {
662+ struct openamp_caller *openamp;
663+ struct openamp_virtio_rpmsg rpmsg;
664+ struct openamp_virtio_device vdev;
665+ struct openamp_virtio_metal metal;
666+};
667+
668+static struct openamp_virtio *openamp_virtio_from_dev(struct virtio_device *vdev)
669+{
670+ struct openamp_virtio_device *openamp_vdev;
671+
672+ openamp_vdev = container_of(vdev, struct openamp_virtio_device,
673+ virtio_dev);
674+
675+ return container_of(openamp_vdev, struct openamp_virtio, vdev);
676+}
677+
678+static struct openamp_virtio_rpmsg *openamp_virtio_rpmsg_from_dev(struct rpmsg_device *rdev)
679+{
680+ struct rpmsg_virtio_device *rvdev;
681+
682+ rvdev = container_of(rdev, struct rpmsg_virtio_device, rdev);
683+
684+ return container_of(rvdev, struct openamp_virtio_rpmsg, rpmsg_vdev);
685+
686+}
687+
688+static void openamp_virtio_metal_device_setup(struct metal_device *shm_dev,
689+ struct openamp_virtio_shm *shm)
690+{
691+ struct metal_io_region *shm_region;
692+
693+ shm_region = &shm_dev->regions[0];
694+
695+ shm_dev->name = OPENAMP_SHEM_DEVICE_NAME;
696+ shm_dev->num_regions = 1;
697+
698+ shm_region->virt = (void *)shm->payload_addr;
699+ shm_region->size = shm->payload_size;
700+
701+ shm_region->physmap = &shm->shm_physmap;
702+ shm_region->page_shift = (metal_phys_addr_t)(-1);
703+ shm_region->page_mask = (metal_phys_addr_t)(-1);
704+}
705+
706+static int openamp_virtio_metal_init(struct openamp_virtio_metal *metal)
707+{
708+ struct metal_init_params params = METAL_INIT_DEFAULTS;
709+ struct metal_device *shm_dev = &metal->shm_dev;
710+ int ret;
711+
712+ openamp_virtio_metal_device_setup(shm_dev, &metal->shm);
713+
714+ metal_spinlock_init(&metal->lock);
715+
716+ ret = metal_init(&params);
717+ if (ret < 0)
718+ return ret;
719+
720+ ret = metal_register_generic_device(shm_dev);
721+ if (ret < 0)
722+ goto metal_finish;
723+
724+ ret = metal_device_open("generic", OPENAMP_SHEM_DEVICE_NAME,
725+ &metal->io_dev);
726+ if (ret < 0)
727+ goto metal_finish;
728+
729+ metal->io = metal_device_io_region(metal->io_dev, 0);
730+ if (!metal->io) {
731+ EMSG("openamp: virtio: failed to init metal io");
732+ ret = -EPROTO;
733+ goto metal_finish;
734+ }
735+
736+ return 0;
737+
738+metal_finish:
739+ metal_finish();
740+ return ret;
741+}
742+
743+static unsigned char openamp_virtio_status_get(struct virtio_device *vdev)
744+{
745+ struct openamp_virtio *virtio = openamp_virtio_from_dev(vdev);
746+ struct openamp_virtio_shm *shm = &virtio->metal.shm;
747+
748+ uint32_t status = *(volatile uint32_t *)shm->vdev_status;
749+
750+ return status;
751+}
752+
753+static void openamp_virtio_status_set(struct virtio_device *vdev,
754+ unsigned char status)
755+{
756+ struct openamp_virtio *virtio = openamp_virtio_from_dev(vdev);
757+ struct openamp_virtio_shm *shm = &virtio->metal.shm;
758+
759+ *(volatile uint32_t *)shm->vdev_status = status;
760+}
761+
762+static int count;
763+
764+static uint32_t openamp_virtio_features_get(struct virtio_device *vdev)
765+{
766+ return 1 << VIRTIO_RPMSG_F_NS;
767+}
768+
769+static void openamp_virtio_notify(struct virtqueue *vq)
770+{
771+ struct openamp_virtio_device *openamp_vdev;
772+ struct openamp_caller *openamp;
773+ struct openamp_virtio *virtio;
774+ int ret;
775+
776+ openamp_vdev = container_of(vq->vq_dev, struct openamp_virtio_device, virtio_dev);
777+ virtio = container_of(openamp_vdev, struct openamp_virtio, vdev);
778+ openamp = virtio->openamp;
779+
780+ ret = openamp->platform_ops->transport_notify(openamp);
781+ if (ret < 0)
782+ EMSG("openamp: virtio: erro in transport_notify: %d", ret);
783+}
784+
785+const static struct virtio_dispatch openamp_virtio_dispatch = {
786+ .get_status = openamp_virtio_status_get,
787+ .set_status = openamp_virtio_status_set,
788+ .get_features = openamp_virtio_features_get,
789+ .notify = openamp_virtio_notify,
790+};
791+
792+static int openamp_virtio_device_setup(struct openamp_virtio *virtio)
793+{
794+ struct openamp_virtio_metal *metal = &virtio->metal;
795+ struct openamp_virtio_device *openamp_vdev = &virtio->vdev;
796+ struct virtio_device *vdev = &openamp_vdev->virtio_dev;
797+ struct openamp_virtio_shm *shm = &metal->shm;
798+ struct virtio_vring_info *rvring;
799+
800+ rvring = &openamp_vdev->rvrings[0];
801+
802+ vdev->role = RPMSG_REMOTE;
803+ vdev->vrings_num = VIRTQUEUE_NR;
804+ vdev->func = &openamp_virtio_dispatch;
805+
806+ openamp_vdev->vq[VQ_TX] = virtqueue_allocate(VRING_DESCRIPTORS);
807+ if (!openamp_vdev->vq[VQ_TX]) {
808+ EMSG("openamp: virtio: failed to allocate virtqueue 0");
809+ return -ENOMEM;
810+ }
811+ rvring->io = metal->io;
812+ rvring->info.vaddr = (void *)shm->vring_tx;
813+ rvring->info.num_descs = VRING_DESCRIPTORS;
814+ rvring->info.align = VRING_ALIGN;
815+ rvring->vq = openamp_vdev->vq[VQ_TX];
816+
817+ openamp_vdev->vq[VQ_RX] = virtqueue_allocate(VRING_DESCRIPTORS);
818+ if (!openamp_vdev->vq[VQ_RX]) {
819+ EMSG("openamp: virtio: failed to allocate virtqueue 1");
820+ goto free_vq;
821+ }
822+ rvring = &openamp_vdev->rvrings[VQ_RX];
823+ rvring->io = metal->io;
824+ rvring->info.vaddr = (void *)shm->vring_rx;
825+ rvring->info.num_descs = VRING_DESCRIPTORS;
826+ rvring->info.align = VRING_ALIGN;
827+ rvring->vq = openamp_vdev->vq[VQ_RX];
828+
829+ vdev->vrings_info = &openamp_vdev->rvrings[0];
830+
831+ return 0;
832+
833+free_vq:
834+ virtqueue_free(openamp_vdev->vq[VQ_TX]);
835+ virtqueue_free(openamp_vdev->vq[VQ_RX]);
836+
837+ return -ENOMEM;
838+}
839+
840+static int openamp_virtio_rpmsg_endpoint_callback(struct rpmsg_endpoint *ep,
841+ void *data, size_t len,
842+ uint32_t src, void *priv)
843+{
844+ struct openamp_virtio_rpmsg *vrpmsg;
845+ struct rpmsg_device *rdev;
846+ struct openamp_virtio *virtio;
847+
848+ rdev = ep->rdev;
849+ vrpmsg = openamp_virtio_rpmsg_from_dev(rdev);
850+ virtio = container_of(vrpmsg, struct openamp_virtio, rpmsg);
851+
852+ rpmsg_hold_rx_buffer(ep, data);
853+ vrpmsg->resp_buf = data;
854+ vrpmsg->resp_len = len;
855+
856+ return 0;
857+}
858+
859+static void openamp_virtio_rpmsg_service_unbind(struct rpmsg_endpoint *ep)
860+{
861+ struct openamp_virtio_rpmsg *vrpmsg;
862+ struct rpmsg_device *rdev;
863+
864+ rdev = container_of(ep, struct rpmsg_device, ns_ept);
865+ vrpmsg = openamp_virtio_rpmsg_from_dev(rdev);
866+
867+ rpmsg_destroy_ept(&vrpmsg->ep);
868+}
869+
870+static void openamp_virtio_rpmsg_endpoint_bind(struct rpmsg_device *rdev,
871+ const char *name,
872+ unsigned int dest)
873+{
874+ struct openamp_virtio_rpmsg *vrpmsg;
875+
876+ vrpmsg = openamp_virtio_rpmsg_from_dev(rdev);
877+
878+ rpmsg_create_ept(&vrpmsg->ep, rdev, name, RPMSG_ADDR_ANY, dest,
879+ openamp_virtio_rpmsg_endpoint_callback,
880+ openamp_virtio_rpmsg_service_unbind);
881+}
882+
883+static int openamp_virtio_rpmsg_device_setup(struct openamp_virtio *virtio,
884+ struct device_region *virtio_dev)
885+{
886+ struct openamp_virtio_rpmsg *vrpmsg = &virtio->rpmsg;
887+ struct rpmsg_virtio_device *rpmsg_vdev = &vrpmsg->rpmsg_vdev;
888+ struct openamp_virtio_device *openamp_vdev = &virtio->vdev;
889+ struct virtio_device *vdev = &openamp_vdev->virtio_dev;
890+ struct openamp_virtio_metal *metal = &virtio->metal;
891+ int ret;
892+
893+ /*
894+ * we assume here that we are the client side and do not need to
895+ * initialize the share memory poll (this is done at server side).
896+ */
897+ ret = rpmsg_init_vdev(rpmsg_vdev, vdev,
898+ openamp_virtio_rpmsg_endpoint_bind, metal->io,
899+ NULL);
900+ if (ret < 0) {
901+ EMSG("openamp: virtio: init vdev failed: %d", ret);
902+ return ret;
903+ }
904+
905+
906+ ret = rpmsg_create_ept(&vrpmsg->ep, &rpmsg_vdev->rdev,
907+ OPENAMP_RPMSG_ENDPOINT_NAME, RPMSG_ADDR_ANY,
908+ RPMSG_ADDR_ANY,
909+ openamp_virtio_rpmsg_endpoint_callback,
910+ openamp_virtio_rpmsg_service_unbind);
911+ if (ret < 0) {
912+ EMSG("openamp: virtio: failed to create endpoint: %d", ret);
913+ return ret;
914+ }
915+
916+ /* set default remote addr */
917+ vrpmsg->ep.dest_addr = OPENAMP_RPMSG_ENDPOINT_ADDR;
918+
919+ return 0;
920+}
921+
922+static void openamp_virtio_shm_set(struct openamp_virtio *virtio,
923+ struct device_region *virtio_region)
924+{
925+ struct openamp_virtio_shm *shm = &virtio->metal.shm;
926+
927+ shm->base_addr = virtio_region->base_addr;
928+ shm->size = virtio_region->io_region_size;
929+
930+ shm->vdev_status = shm->base_addr;
931+ shm->vdev_status_size = OPENAMP_SHEM_VDEV_SIZE;
932+
933+ shm->vring_rx = shm->base_addr + shm->size -
934+ (2 * OPENAMP_SHEM_VRING_SIZE);
935+ shm->vring_rx_size = OPENAMP_SHEM_VRING_SIZE;
936+
937+ shm->vring_tx = shm->vring_rx + shm->vring_rx_size;
938+ shm->vring_tx_size = OPENAMP_SHEM_VRING_SIZE;
939+
940+ shm->payload_addr = shm->vdev_status + shm->vdev_status_size;
941+ shm->payload_size = shm->size - shm->vdev_status_size -
942+ shm->vring_rx_size - shm->vring_tx_size;
943+
944+ shm->shm_physmap[0] = OPENAMP_SHEM_PHYS + shm->vdev_status_size;
945+
946+ IMSG("SHEM: base: 0x%0x size: 0x%0x size: %d",
947+ shm->base_addr, shm->size, shm->size);
948+ IMSG("VDEV: base: 0x%0x size: 0x%0x size: %d",
949+ shm->vdev_status, shm->vdev_status_size, shm->vdev_status_size);
950+ IMSG("PAYLOAD: base: 0x%0x size: 0x%0x size: %d",
951+ shm->payload_addr, shm->payload_size, shm->payload_size);
952+ IMSG("VRING_TX: base: 0x%0x size: 0x%0x size: %d",
953+ shm->vring_tx, shm->vring_tx_size, shm->vring_tx_size);
954+ IMSG("VRING_RX: base: 0x%0x size: 0x%0x size: %d",
955+ shm->vring_rx, shm->vring_rx_size, shm->vring_rx_size);
956+ IMSG("PHYMAP: base: 0x%0x", shm->shm_physmap[0]);
957+}
958+
959+static int openamp_virtio_device_get(const char *dev,
960+ struct device_region *dev_region)
961+{
962+ bool found;
963+
964+ found = config_store_query(CONFIG_CLASSIFIER_DEVICE_REGION, dev, 0,
965+ dev_region, sizeof(*dev_region));
966+ if (!found) {
967+ EMSG("openamp: virtio: device region not found: %s", dev);
968+ return -EINVAL;
969+ }
970+
971+ if (dev_region->base_addr == 0 || dev_region->io_region_size == 0) {
972+ EMSG("openamp: virtio: device region not valid");
973+ return -EINVAL;
974+ }
975+
976+ IMSG("openamp: virtio: device region found: %s addr: 0x%x size: %d",
977+ dev, dev_region->base_addr, dev_region->io_region_size);
978+
979+ return 0;
980+}
981+
982+int openamp_virtio_call_begin(struct openamp_caller *openamp, uint8_t **req_buf,
983+ size_t req_len)
984+{
985+ struct openamp_virtio *virtio = openamp->platform;
986+ struct openamp_virtio_rpmsg *vrpmsg = &virtio->rpmsg;
987+ struct rpmsg_endpoint *ep = &vrpmsg->ep;
988+
989+
990+ *req_buf = rpmsg_get_tx_payload_buffer(ep, &vrpmsg->req_len,
991+ OPENAMP_BUFFER_WAIT);
992+ if (*req_buf == NULL)
993+ return -EINVAL;
994+
995+ if (vrpmsg->req_len < req_len)
996+ return -E2BIG;
997+
998+ vrpmsg->req_buf = *req_buf;
999+
1000+ return 0;
1001+}
1002+
1003+int openamp_virtio_call_invoke(struct openamp_caller *openamp, int *opstatus,
1004+ uint8_t **resp_buf, size_t *resp_len)
1005+{
1006+ const struct openamp_platform_ops *ops = openamp->platform_ops;
1007+ struct openamp_virtio *virtio = openamp->platform;
1008+ struct openamp_virtio_device *openamp_vdev = &virtio->vdev;
1009+ struct openamp_virtio_rpmsg *vrpmsg = &virtio->rpmsg;
1010+ struct rpmsg_endpoint *ep = &vrpmsg->ep;
1011+ int ret;
1012+
1013+ ret = rpmsg_send_nocopy(ep, vrpmsg->req_buf, vrpmsg->req_len);
1014+ if (ret < 0) {
1015+ EMSG("openamp: virtio: send nocopy failed: %d", ret);
1016+ return -EIO;
1017+ }
1018+
1019+ if (ret != vrpmsg->req_len) {
1020+ EMSG("openamp: virtio: send less bytes %d than requested %d",
1021+ ret, vrpmsg->req_len);
1022+ return -EIO;
1023+ }
1024+
1025+ if (!ops->transport_receive)
1026+ return 0;
1027+
1028+ ret = ops->transport_receive(openamp);
1029+ if (ret < 0) {
1030+ EMSG("openamp: virtio: failed transport_receive");
1031+ return -EIO;
1032+ }
1033+
1034+ virtqueue_notification(openamp_vdev->vq[VQ_RX]);
1035+
1036+ *resp_buf = vrpmsg->resp_buf;
1037+ *resp_len = vrpmsg->resp_len;
1038+
1039+ return 0;
1040+}
1041+
1042+void openamp_virtio_call_end(struct openamp_caller *openamp)
1043+{
1044+ struct openamp_virtio *virtio = openamp->platform;
1045+ struct openamp_virtio_rpmsg *vrpmsg = &virtio->rpmsg;
1046+
1047+ rpmsg_release_rx_buffer(&vrpmsg->ep, vrpmsg->resp_buf);
1048+
1049+ vrpmsg->req_buf = NULL;
1050+ vrpmsg->req_len = 0;
1051+ vrpmsg->resp_buf = NULL;
1052+ vrpmsg->resp_len = 0;
1053+}
1054+
1055+void *openamp_virtio_virt_to_phys(struct openamp_caller *openamp, void *va)
1056+{
1057+ struct openamp_virtio *virtio = openamp->platform;
1058+ struct openamp_virtio_metal *metal = &virtio->metal;
1059+
1060+ return metal_io_virt_to_phys(metal->io, va);
1061+}
1062+
1063+void *openamp_virtio_phys_to_virt(struct openamp_caller *openamp, void *pa)
1064+{
1065+ struct openamp_virtio *virtio = openamp->platform;
1066+ struct openamp_virtio_metal *metal = &virtio->metal;
1067+
1068+ return metal_io_phys_to_virt(metal->io, pa);
1069+}
1070+
1071+int openamp_virtio_init(struct openamp_caller *openamp)
1072+{
1073+ struct device_region virtio_dev;
1074+ struct openamp_virtio *virtio;
1075+ int ret;
1076+
1077+ if (openamp->platform)
1078+ return 0;
1079+
1080+
1081+ virtio = malloc(sizeof(*virtio));
1082+ if (!virtio)
1083+ return -ENOMEM;
1084+
1085+ virtio->openamp = openamp;
1086+
1087+ ret = openamp_virtio_device_get(OPENAMP_SHEM_DEVICE_NAME, &virtio_dev);
1088+ if (ret < 0)
1089+ goto free_virtio;
1090+
1091+ openamp_virtio_shm_set(virtio, &virtio_dev);
1092+
1093+ ret = openamp_virtio_metal_init(&virtio->metal);
1094+ if (ret < 0)
1095+ goto free_virtio;
1096+
1097+ ret = openamp_virtio_device_setup(virtio);
1098+ if (ret < 0)
1099+ goto finish_metal;
1100+
1101+ ret = openamp_virtio_rpmsg_device_setup(virtio, &virtio_dev);
1102+ if (ret < 0) {
1103+ EMSG("openamp: virtio: rpmsg device setup failed: %d", ret);
1104+ goto finish_metal;
1105+ }
1106+
1107+ openamp->platform = virtio;
1108+
1109+ return 0;
1110+
1111+finish_metal:
1112+ metal_finish();
1113+
1114+free_virtio:
1115+ free(virtio);
1116+
1117+ return ret;
1118+}
1119+
1120+int openamp_virtio_deinit(struct openamp_caller *openamp)
1121+{
1122+ struct openamp_virtio *virtio;
1123+
1124+ if (!openamp->platform)
1125+ return 0;
1126+
1127+ virtio = openamp->platform;
1128+
1129+ metal_finish();
1130+ free(virtio);
1131+
1132+ openamp->platform = NULL;
1133+
1134+ return 0;
1135+}
1136diff --git a/components/rpc/openamp/caller/sp/openamp_virtio.h b/components/rpc/openamp/caller/sp/openamp_virtio.h
1137new file mode 100644
1138index 000000000000..915128ff65ce
1139--- /dev/null
1140+++ b/components/rpc/openamp/caller/sp/openamp_virtio.h
1141@@ -0,0 +1,24 @@
1142+/*
1143+ * Copyright (c) 2021, Arm Limited and Contributors. All rights reserved.
1144+ * Copyright (c) 2021, Linaro Limited. All rights reserved.
1145+ *
1146+ * SPDX-License-Identifier: BSD-3-Clause
1147+ */
1148+#ifndef OPENAMP_VIRTIO_H
1149+#define OPENAMP_VIRTIO_H
1150+
1151+#include <stddef.h>
1152+#include "openamp_caller.h"
1153+
1154+int openamp_virtio_call_begin(struct openamp_caller *openamp, uint8_t **req_buf,
1155+ size_t req_len);
1156+int openamp_virtio_call_invoke(struct openamp_caller *openamp, int *opstatus,
1157+ uint8_t **resp_buf, size_t *resp_len);
1158+int openamp_virtio_call_end(struct openamp_caller *openamp);
1159+void *openamp_virtio_virt_to_phys(struct openamp_caller *openamp, void *va);
1160+void *openamp_virtio_phys_to_virt(struct openamp_caller *openamp, void *pa);
1161+
1162+int openamp_virtio_init(struct openamp_caller *openamp);
1163+int openamp_virtio_deinit(struct openamp_caller *openamp);
1164+
1165+#endif
1166diff --git a/deployments/se-proxy/opteesp/default_se-proxy.dts.in b/deployments/se-proxy/opteesp/default_se-proxy.dts.in
1167index 267b4f923540..04c181586b06 100644
1168--- a/deployments/se-proxy/opteesp/default_se-proxy.dts.in
1169+++ b/deployments/se-proxy/opteesp/default_se-proxy.dts.in
1170@@ -32,5 +32,11 @@
1171 pages-count = <16>;
1172 attributes = <0x3>; /* read-write */
1173 };
1174+ openamp-virtio {
1175+ /* Armv8 A Foundation Platform values */
1176+ base-address = <0x00000000 0x88000000>;
1177+ pages-count = <256>;
1178+ attributes = <0x3>; /* read-write */
1179+ };
1180 };
1181 };
1182diff --git a/deployments/se-proxy/se-proxy.cmake b/deployments/se-proxy/se-proxy.cmake
1183index d39873a0fe81..34fe5ff1b925 100644
1184--- a/deployments/se-proxy/se-proxy.cmake
1185+++ b/deployments/se-proxy/se-proxy.cmake
1186@@ -47,6 +47,7 @@ add_components(TARGET "se-proxy"
1187 "components/service/attestation/include"
1188 "components/service/attestation/provider"
1189 "components/service/attestation/provider/serializer/packed-c"
1190+ "components/rpc/openamp/caller/sp"
1191
1192 # Stub service provider backends
1193 "components/rpc/dummy"
1194--
11952.38.0
1196