Add openamp messenger
Create an openamp messenger that will handle the setup and
communication to an outside PE using openamp and using mhu as a doorbell
mechanism.
Signed-off-by: Vishnu Banavath <vishnu.banavath@arm.com>
Signed-off-by: Rui Miguel Silva <rui.silva@linaro.org>
Change-Id: Iac4119faac3f98dc04e7edbc1f401db8c8c93537
diff --git a/components/messaging/openamp/sp/openamp_messenger.c b/components/messaging/openamp/sp/openamp_messenger.c
new file mode 100644
index 0000000..2b77ea4
--- /dev/null
+++ b/components/messaging/openamp/sp/openamp_messenger.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <errno.h>
+#include <stddef.h>
+#include <trace.h>
+#include "openamp_messenger.h"
+#include "openamp_messenger_api.h"
+#include "openamp_mhu.h"
+#include "openamp_virtio.h"
+#include <protocols/rpc/common/packed-c/status.h>
+
+#define OPENAMP_TRANSACTION_IDLE 0x0
+#define OPENAMP_TRANSACTION_INPROGRESS 0x1
+#define OPENAMP_TRANSACTION_INVOKED 0x2
+
+int openamp_messenger_call_begin(struct openamp_messenger *openamp,
+ uint8_t **req_buf, size_t req_len)
+{
+ const struct openamp_platform_ops *ops = openamp->platform_ops;
+ int ret;
+
+ if (!openamp)
+ return -EINVAL;
+
+ ops = openamp->platform_ops;
+ if (!req_buf) {
+ EMSG("openamp: call_begin: not req_buf");
+ return -EINVAL;
+ }
+
+ if (req_len > UINT32_MAX || req_len == 0) {
+ EMSG("openamp: call_begin: resp_len invalid: %lu", req_len);
+ return -EINVAL;
+ }
+
+ if (openamp->status != OPENAMP_TRANSACTION_IDLE) {
+ EMSG("openamp: call_begin: transaction not idle");
+ return -EINVAL;
+ }
+
+ ret = ops->platform_call_begin(openamp, req_buf, req_len);
+ if (ret < 0) {
+ EMSG("openamp: call_begin: platform begin failed: %d", ret);
+ return -EINVAL;
+ }
+
+ openamp->status = OPENAMP_TRANSACTION_INPROGRESS;
+
+ return 0;
+}
+
+int openamp_messenger_call_invoke(struct openamp_messenger *openamp,
+ uint8_t **resp_buf, size_t *resp_len)
+{
+ const struct openamp_platform_ops *ops;
+ int ret;
+
+ if (!openamp || !resp_buf || !resp_len) {
+ EMSG("openamp: call_invoke: invalid arguments");
+ return -EINVAL;
+ }
+
+ if (openamp->status != OPENAMP_TRANSACTION_INPROGRESS) {
+ EMSG("openamp: call_invoke: transaction needed to be started");
+ return -ENOTCONN;
+ }
+
+ ops = openamp->platform_ops;
+
+ ret = ops->platform_call_invoke(openamp, resp_buf, resp_len);
+ if (ret < 0)
+ return ret;
+
+ openamp->status = OPENAMP_TRANSACTION_INVOKED;
+
+ return 0;
+}
+
+void openamp_messenger_call_end(struct openamp_messenger *openamp)
+{
+ const struct openamp_platform_ops *ops;
+
+ if (!openamp)
+ return;
+
+ if (openamp->status == OPENAMP_TRANSACTION_IDLE) {
+ EMSG("openamp: call_end: transaction idle");
+ return;
+ }
+
+ ops = openamp->platform_ops;
+
+ ops->platform_call_end(openamp);
+
+ openamp->status = OPENAMP_TRANSACTION_IDLE;
+}
+
+void *openamp_messenger_phys_to_virt(struct openamp_messenger *openamp,
+ void *pa)
+{
+ const struct openamp_platform_ops *ops = openamp->platform_ops;
+
+ return ops->platform_phys_to_virt(openamp, pa);
+}
+
+void *openamp_messenger_virt_to_phys(struct openamp_messenger *openamp,
+ void *va)
+{
+ const struct openamp_platform_ops *ops = openamp->platform_ops;
+
+ return ops->platform_virt_to_phys(openamp, va);
+}
+
+static const struct openamp_platform_ops openamp_virtio_ops = {
+ .transport_init = openamp_mhu_init,
+ .transport_deinit = openamp_mhu_deinit,
+ .transport_notify = openamp_mhu_notify_peer,
+ .transport_receive = openamp_mhu_receive,
+ .platform_init = openamp_virtio_init,
+ .platform_call_begin = openamp_virtio_call_begin,
+ .platform_call_invoke = openamp_virtio_call_invoke,
+ .platform_call_end = openamp_virtio_call_end,
+ .platform_virt_to_phys = openamp_virtio_virt_to_phys,
+ .platform_phys_to_virt = openamp_virtio_phys_to_virt,
+};
+
+int openamp_messenger_init(struct openamp_messenger *openamp)
+{
+ const struct openamp_platform_ops *ops;
+ int ret;
+
+ if (openamp->ref_count)
+ return 0;
+
+ openamp->platform_ops = &openamp_virtio_ops;
+
+ ops = openamp->platform_ops;
+
+ ret = ops->transport_init(openamp);
+ if (ret < 0)
+ return ret;
+
+ ret = ops->platform_init(openamp);
+ if (ret < 0)
+ goto denit_transport;
+
+ openamp->ref_count++;
+
+ return 0;
+
+denit_transport:
+ ops->transport_deinit(openamp);
+
+ return ret;
+}
+
+void openamp_messenger_deinit(struct openamp_messenger *openamp)
+{
+ if (--openamp->ref_count)
+ return;
+}