blob: 2b77ea45a39a60009be3886ca1e1884d41d78440 [file] [log] [blame]
Rui Miguel Silva909ff4d2021-12-03 19:00:54 +00001/*
2 * Copyright (c) 2021-2023, Arm Limited and Contributors. All rights reserved.
3 * Copyright (c) 2021-2023, Linaro Limited. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8#include <errno.h>
9#include <stddef.h>
10#include <trace.h>
11#include "openamp_messenger.h"
12#include "openamp_messenger_api.h"
13#include "openamp_mhu.h"
14#include "openamp_virtio.h"
15#include <protocols/rpc/common/packed-c/status.h>
16
17#define OPENAMP_TRANSACTION_IDLE 0x0
18#define OPENAMP_TRANSACTION_INPROGRESS 0x1
19#define OPENAMP_TRANSACTION_INVOKED 0x2
20
21int openamp_messenger_call_begin(struct openamp_messenger *openamp,
22 uint8_t **req_buf, size_t req_len)
23{
24 const struct openamp_platform_ops *ops = openamp->platform_ops;
25 int ret;
26
27 if (!openamp)
28 return -EINVAL;
29
30 ops = openamp->platform_ops;
31 if (!req_buf) {
32 EMSG("openamp: call_begin: not req_buf");
33 return -EINVAL;
34 }
35
36 if (req_len > UINT32_MAX || req_len == 0) {
37 EMSG("openamp: call_begin: resp_len invalid: %lu", req_len);
38 return -EINVAL;
39 }
40
41 if (openamp->status != OPENAMP_TRANSACTION_IDLE) {
42 EMSG("openamp: call_begin: transaction not idle");
43 return -EINVAL;
44 }
45
46 ret = ops->platform_call_begin(openamp, req_buf, req_len);
47 if (ret < 0) {
48 EMSG("openamp: call_begin: platform begin failed: %d", ret);
49 return -EINVAL;
50 }
51
52 openamp->status = OPENAMP_TRANSACTION_INPROGRESS;
53
54 return 0;
55}
56
57int openamp_messenger_call_invoke(struct openamp_messenger *openamp,
58 uint8_t **resp_buf, size_t *resp_len)
59{
60 const struct openamp_platform_ops *ops;
61 int ret;
62
63 if (!openamp || !resp_buf || !resp_len) {
64 EMSG("openamp: call_invoke: invalid arguments");
65 return -EINVAL;
66 }
67
68 if (openamp->status != OPENAMP_TRANSACTION_INPROGRESS) {
69 EMSG("openamp: call_invoke: transaction needed to be started");
70 return -ENOTCONN;
71 }
72
73 ops = openamp->platform_ops;
74
75 ret = ops->platform_call_invoke(openamp, resp_buf, resp_len);
76 if (ret < 0)
77 return ret;
78
79 openamp->status = OPENAMP_TRANSACTION_INVOKED;
80
81 return 0;
82}
83
84void openamp_messenger_call_end(struct openamp_messenger *openamp)
85{
86 const struct openamp_platform_ops *ops;
87
88 if (!openamp)
89 return;
90
91 if (openamp->status == OPENAMP_TRANSACTION_IDLE) {
92 EMSG("openamp: call_end: transaction idle");
93 return;
94 }
95
96 ops = openamp->platform_ops;
97
98 ops->platform_call_end(openamp);
99
100 openamp->status = OPENAMP_TRANSACTION_IDLE;
101}
102
103void *openamp_messenger_phys_to_virt(struct openamp_messenger *openamp,
104 void *pa)
105{
106 const struct openamp_platform_ops *ops = openamp->platform_ops;
107
108 return ops->platform_phys_to_virt(openamp, pa);
109}
110
111void *openamp_messenger_virt_to_phys(struct openamp_messenger *openamp,
112 void *va)
113{
114 const struct openamp_platform_ops *ops = openamp->platform_ops;
115
116 return ops->platform_virt_to_phys(openamp, va);
117}
118
119static const struct openamp_platform_ops openamp_virtio_ops = {
120 .transport_init = openamp_mhu_init,
121 .transport_deinit = openamp_mhu_deinit,
122 .transport_notify = openamp_mhu_notify_peer,
123 .transport_receive = openamp_mhu_receive,
124 .platform_init = openamp_virtio_init,
125 .platform_call_begin = openamp_virtio_call_begin,
126 .platform_call_invoke = openamp_virtio_call_invoke,
127 .platform_call_end = openamp_virtio_call_end,
128 .platform_virt_to_phys = openamp_virtio_virt_to_phys,
129 .platform_phys_to_virt = openamp_virtio_phys_to_virt,
130};
131
132int openamp_messenger_init(struct openamp_messenger *openamp)
133{
134 const struct openamp_platform_ops *ops;
135 int ret;
136
137 if (openamp->ref_count)
138 return 0;
139
140 openamp->platform_ops = &openamp_virtio_ops;
141
142 ops = openamp->platform_ops;
143
144 ret = ops->transport_init(openamp);
145 if (ret < 0)
146 return ret;
147
148 ret = ops->platform_init(openamp);
149 if (ret < 0)
150 goto denit_transport;
151
152 openamp->ref_count++;
153
154 return 0;
155
156denit_transport:
157 ops->transport_deinit(openamp);
158
159 return ret;
160}
161
162void openamp_messenger_deinit(struct openamp_messenger *openamp)
163{
164 if (--openamp->ref_count)
165 return;
166}