1 /*
2  * Copyright (c) 2021 Nordic Semiconductor ASA
3  * Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 #include <zephyr/ipc/ipc_service.h>
9 #include <zephyr/ipc/ipc_service_backend.h>
10 
11 #include <zephyr/logging/log.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/device.h>
14 
15 LOG_MODULE_REGISTER(ipc_service, CONFIG_IPC_SERVICE_LOG_LEVEL);
16 
ipc_service_open_instance(const struct device * instance)17 int ipc_service_open_instance(const struct device *instance)
18 {
19 	const struct ipc_service_backend *backend;
20 
21 	if (!instance) {
22 		LOG_ERR("Invalid instance");
23 		return -EINVAL;
24 	}
25 
26 	backend = (const struct ipc_service_backend *) instance->api;
27 
28 	if (!backend) {
29 		LOG_ERR("Invalid backend configuration");
30 		return -EIO;
31 	}
32 
33 	if (!backend->open_instance) {
34 		/* maybe not needed on backend */
35 		return 0;
36 	}
37 
38 	return backend->open_instance(instance);
39 }
40 
ipc_service_close_instance(const struct device * instance)41 int ipc_service_close_instance(const struct device *instance)
42 {
43 	const struct ipc_service_backend *backend;
44 
45 	if (!instance) {
46 		LOG_ERR("Invalid instance");
47 		return -EINVAL;
48 	}
49 
50 	backend = (const struct ipc_service_backend *) instance->api;
51 
52 	if (!backend) {
53 		LOG_ERR("Invalid backend configuration");
54 		return -EIO;
55 	}
56 
57 	if (!backend->close_instance) {
58 		/* maybe not needed on backend */
59 		return 0;
60 	}
61 
62 	return backend->close_instance(instance);
63 }
64 
ipc_service_register_endpoint(const struct device * instance,struct ipc_ept * ept,const struct ipc_ept_cfg * cfg)65 int ipc_service_register_endpoint(const struct device *instance,
66 				  struct ipc_ept *ept,
67 				  const struct ipc_ept_cfg *cfg)
68 {
69 	const struct ipc_service_backend *backend;
70 
71 	if (!instance || !ept || !cfg) {
72 		LOG_ERR("Invalid instance, endpoint or configuration");
73 		return -EINVAL;
74 	}
75 
76 	backend = (const struct ipc_service_backend *) instance->api;
77 
78 	if (!backend || !backend->register_endpoint) {
79 		LOG_ERR("Invalid backend configuration");
80 		return -EIO;
81 	}
82 
83 	LOG_DBG("Register endpoint %s", cfg->name ? cfg->name : "");
84 
85 	ept->instance = instance;
86 
87 	return backend->register_endpoint(instance, &ept->token, cfg);
88 }
89 
ipc_service_deregister_endpoint(struct ipc_ept * ept)90 int ipc_service_deregister_endpoint(struct ipc_ept *ept)
91 {
92 	const struct ipc_service_backend *backend;
93 	int err;
94 
95 	if (!ept) {
96 		LOG_ERR("Invalid endpoint");
97 		return -EINVAL;
98 	}
99 
100 	if (!ept->instance) {
101 		LOG_ERR("Endpoint not registered\n");
102 		return -ENOENT;
103 	}
104 
105 	backend = ept->instance->api;
106 
107 	if (!backend || !backend->deregister_endpoint) {
108 		LOG_ERR("Invalid backend configuration");
109 		return -EIO;
110 	}
111 
112 	err = backend->deregister_endpoint(ept->instance, ept->token);
113 	if (err != 0) {
114 		return err;
115 	}
116 
117 	ept->instance = 0;
118 
119 	return 0;
120 }
121 
122 
ipc_service_send(struct ipc_ept * ept,const void * data,size_t len)123 int ipc_service_send(struct ipc_ept *ept, const void *data, size_t len)
124 {
125 	const struct ipc_service_backend *backend;
126 
127 	if (!ept) {
128 		LOG_ERR("Invalid endpoint");
129 		return -EINVAL;
130 	}
131 
132 	if (!ept->instance) {
133 		LOG_ERR("Endpoint not registered\n");
134 		return -ENOENT;
135 	}
136 
137 	backend = ept->instance->api;
138 
139 	if (!backend || !backend->send) {
140 		LOG_ERR("Invalid backend configuration");
141 		return -EIO;
142 	}
143 
144 	return backend->send(ept->instance, ept->token, data, len);
145 }
146 
ipc_service_get_tx_buffer_size(struct ipc_ept * ept)147 int ipc_service_get_tx_buffer_size(struct ipc_ept *ept)
148 {
149 	const struct ipc_service_backend *backend;
150 
151 	if (!ept) {
152 		LOG_ERR("Invalid endpoint");
153 		return -EINVAL;
154 	}
155 
156 	if (!ept->instance) {
157 		LOG_ERR("Endpoint not registered\n");
158 		return -ENOENT;
159 	}
160 
161 	backend = ept->instance->api;
162 
163 	if (!backend) {
164 		LOG_ERR("Invalid backend configuration");
165 		return -EIO;
166 	}
167 
168 	if (!backend->get_tx_buffer_size) {
169 		LOG_ERR("No-copy feature not available");
170 		return -EIO;
171 	}
172 
173 	return backend->get_tx_buffer_size(ept->instance, ept->token);
174 }
175 
ipc_service_get_tx_buffer(struct ipc_ept * ept,void ** data,uint32_t * len,k_timeout_t wait)176 int ipc_service_get_tx_buffer(struct ipc_ept *ept, void **data, uint32_t *len, k_timeout_t wait)
177 {
178 	const struct ipc_service_backend *backend;
179 
180 	if (!ept || !data || !len) {
181 		LOG_ERR("Invalid endpoint, data or len pointer");
182 		return -EINVAL;
183 	}
184 
185 	if (!ept->instance) {
186 		LOG_ERR("Endpoint not registered\n");
187 		return -ENOENT;
188 	}
189 
190 	backend = ept->instance->api;
191 
192 	if (!backend) {
193 		LOG_ERR("Invalid backend configuration");
194 		return -EIO;
195 	}
196 
197 	if (!backend->send_nocopy || !backend->get_tx_buffer) {
198 		LOG_ERR("No-copy feature not available");
199 		return -EIO;
200 	}
201 
202 	return backend->get_tx_buffer(ept->instance, ept->token, data, len, wait);
203 }
204 
ipc_service_drop_tx_buffer(struct ipc_ept * ept,const void * data)205 int ipc_service_drop_tx_buffer(struct ipc_ept *ept, const void *data)
206 {
207 	const struct ipc_service_backend *backend;
208 
209 	if (!ept || !data) {
210 		LOG_ERR("Invalid endpoint or data pointer");
211 		return -EINVAL;
212 	}
213 
214 	if (!ept->instance) {
215 		LOG_ERR("Endpoint not registered\n");
216 		return -ENOENT;
217 	}
218 
219 	backend = ept->instance->api;
220 
221 	if (!backend) {
222 		LOG_ERR("Invalid backend configuration");
223 		return -EIO;
224 	}
225 
226 	if (!backend->drop_tx_buffer) {
227 		LOG_ERR("No-copy feature not available");
228 		return -EIO;
229 	}
230 
231 	return backend->drop_tx_buffer(ept->instance, ept->token, data);
232 }
233 
ipc_service_send_nocopy(struct ipc_ept * ept,const void * data,size_t len)234 int ipc_service_send_nocopy(struct ipc_ept *ept, const void *data, size_t len)
235 {
236 	const struct ipc_service_backend *backend;
237 
238 	if (!ept) {
239 		LOG_ERR("Invalid endpoint");
240 		return -EINVAL;
241 	}
242 
243 	if (!ept->instance) {
244 		LOG_ERR("Endpoint not registered\n");
245 		return -ENOENT;
246 	}
247 
248 	backend = ept->instance->api;
249 
250 	if (!backend) {
251 		LOG_ERR("Invalid backend configuration");
252 		return -EIO;
253 	}
254 
255 	if (!backend->get_tx_buffer || !backend->send_nocopy) {
256 		LOG_ERR("No-copy feature not available");
257 		return -EIO;
258 	}
259 
260 	return backend->send_nocopy(ept->instance, ept->token, data, len);
261 }
262 
ipc_service_hold_rx_buffer(struct ipc_ept * ept,void * data)263 int ipc_service_hold_rx_buffer(struct ipc_ept *ept, void *data)
264 {
265 	const struct ipc_service_backend *backend;
266 
267 	if (!ept) {
268 		LOG_ERR("Invalid endpoint");
269 		return -EINVAL;
270 	}
271 
272 	if (!ept->instance) {
273 		LOG_ERR("Endpoint not registered\n");
274 		return -ENOENT;
275 	}
276 
277 	backend = ept->instance->api;
278 
279 	if (!backend) {
280 		LOG_ERR("Invalid backend configuration");
281 		return -EIO;
282 	}
283 
284 	/* We also need the release function */
285 	if (!backend->release_rx_buffer || !backend->hold_rx_buffer) {
286 		LOG_ERR("No-copy feature not available");
287 		return -EIO;
288 	}
289 
290 	return backend->hold_rx_buffer(ept->instance, ept->token, data);
291 }
ipc_service_release_rx_buffer(struct ipc_ept * ept,void * data)292 int ipc_service_release_rx_buffer(struct ipc_ept *ept, void *data)
293 {
294 	const struct ipc_service_backend *backend;
295 
296 	if (!ept) {
297 		LOG_ERR("Invalid endpoint");
298 		return -EINVAL;
299 	}
300 
301 	if (!ept->instance) {
302 		LOG_ERR("Endpoint not registered\n");
303 		return -ENOENT;
304 	}
305 
306 	backend = ept->instance->api;
307 
308 	if (!backend) {
309 		LOG_ERR("Invalid backend configuration");
310 		return -EIO;
311 	}
312 
313 	/* We also need the hold function */
314 	if (!backend->hold_rx_buffer || !backend->release_rx_buffer) {
315 		LOG_ERR("No-copy feature not available");
316 		return -EIO;
317 	}
318 
319 	return backend->release_rx_buffer(ept->instance, ept->token, data);
320 }
321