Line data Source code
1 0 : /*
2 : * Copyright (c) 2021 Nordic Semiconductor ASA
3 : *
4 : * SPDX-License-Identifier: Apache-2.0
5 : */
6 :
7 : #ifndef ZEPHYR_INCLUDE_IPC_IPC_SERVICE_H_
8 : #define ZEPHYR_INCLUDE_IPC_IPC_SERVICE_H_
9 :
10 : #include <stdio.h>
11 : #include <zephyr/device.h>
12 : #include <zephyr/kernel.h>
13 :
14 : #ifdef __cplusplus
15 : extern "C" {
16 : #endif
17 :
18 : /**
19 : * @brief IPC
20 : * @defgroup ipc IPC
21 : * @ingroup os_services
22 : * @{
23 : * @}
24 : */
25 :
26 : /**
27 : * @brief IPC Service API
28 : * @defgroup ipc_service_api IPC service APIs
29 : * @ingroup ipc
30 : * @{
31 : */
32 :
33 : /**
34 : * @cond INTERNAL_HIDDEN
35 : *
36 : * These are for internal use only, so skip these in
37 : * public documentation.
38 : */
39 :
40 : /**
41 : * Some terminology:
42 : *
43 : * - INSTANCE: an instance is the external representation of a physical
44 : * communication channel between two domains / CPUs.
45 : *
46 : * The actual implementation and internal representation of the
47 : * instance is peculiar to each backend. For example for
48 : * OpenAMP-based backends, an instance is usually represented by a
49 : * shared memory region and a couple of IPM devices for RX/TX
50 : * signalling.
51 : *
52 : * It's important to note that an instance per se is not used to
53 : * send data between domains / CPUs. To send and receive data the
54 : * user have to create (register) an endpoint in the instance
55 : * connecting the two domains of interest.
56 : *
57 : * It's possible to have zero or multiple endpoints in one single
58 : * instance, each one used to exchange data, possibly with different
59 : * priorities.
60 : *
61 : * The creation of the instances is left to the backend (usually at
62 : * init time), while the registration of the endpoints is left to
63 : * the user (usually at run time).
64 : *
65 : * - ENDPOINT: an endpoint is the entity the user must use to send / receive
66 : * data between two domains (connected by the instance). An
67 : * endpoint is always associated to an instance.
68 : *
69 : * - BACKEND: the backend must take care of at least two different things:
70 : *
71 : * 1) creating the instances at init time
72 : * 2) creating / registering the endpoints onto an instance at run
73 : * time when requested by the user
74 : *
75 : * The API doesn't mandate a way for the backend to create the
76 : * instances but itis strongly recommended to use the DT to retrieve
77 : * the configuration parameters for the instance.
78 : *
79 : * Common API usage from the application prospective:
80 : *
81 : * HOST REMOTE
82 : * -----------------------------------------------------------------------------
83 : * # Open the (same) instance on host and remote
84 : * ipc_service_open() ipc_service_open()
85 : *
86 : * # Register the endpoints
87 : * ipc_service_register_endpoint() ipc_service_register_endpoint()
88 : * .bound() .bound()
89 : *
90 : * # After the .bound() callbacks are received the communication channel
91 : * # is ready to be used
92 : *
93 : * # Start sending and receiving data
94 : * ipc_service_send()
95 : * .receive()
96 : * ipc_service_send()
97 : * .receive()
98 : *
99 : *
100 : * Common API usage from the application prospective when using NOCOPY feature:
101 : *
102 : * HOST REMOTE
103 : * -----------------------------------------------------------------------------
104 : * ipc_service_open() ipc_service_open()
105 : *
106 : * ipc_service_register_endpoint() ipc_service_register_endpoint()
107 : * .bound() .bound()
108 : *
109 : * # Get a pointer to an available TX buffer
110 : * ipc_service_get_tx_buffer()
111 : *
112 : * # Fill the buffer with data
113 : *
114 : * # Send out the buffer
115 : * ipc_service_send_nocopy()
116 : * .receive()
117 : *
118 : * # Get hold of the received RX buffer
119 : * # in the .receive callback
120 : * ipc_service_hold_rx_buffer()
121 : *
122 : * # Copy the data out of the buffer at
123 : * # user convenience
124 : *
125 : * # Release the buffer when done
126 : * ipc_service_release_rx_buffer()
127 : *
128 : * # Get another TX buffer
129 : * ipc_service_get_tx_buffer()
130 : *
131 : * # We can also drop it if needed
132 : * ipc_service_drop_tx_buffer()
133 : *
134 : */
135 :
136 : /**
137 : * @endcond
138 : */
139 :
140 : /** @brief Event callback structure.
141 : *
142 : * It is registered during endpoint registration.
143 : * This structure is part of the endpoint configuration.
144 : */
145 1 : struct ipc_service_cb {
146 : /** @brief Bind was successful.
147 : *
148 : * This callback is called when the endpoint binding is successful.
149 : *
150 : * @param[in] priv Private user data.
151 : */
152 1 : void (*bound)(void *priv);
153 :
154 : /** @brief The endpoint unbound by the remote.
155 : *
156 : * This callback is called when the endpoint binding is removed. It may happen on
157 : * different reasons, e.g. when the remote deregistered the endpoint, connection was
158 : * lost, or remote CPU got reset.
159 : *
160 : * You may want to do some cleanup, resetting, e.t.c. and after that if you want to bound
161 : * again, you can register the endpoint. When the remote becomes available again and it
162 : * also registers the endpoint, the binding will be reestablished and the `bound()`
163 : * callback will be called.
164 : *
165 : * @param[in] priv Private user data.
166 : */
167 1 : void (*unbound)(void *priv);
168 :
169 : /** @brief New packet arrived.
170 : *
171 : * This callback is called when new data is received.
172 : *
173 : * @note When @ref ipc_service_hold_rx_buffer is not used, the data
174 : * buffer is to be considered released and available again only
175 : * when this callback returns.
176 : *
177 : * @param[in] data Pointer to data buffer.
178 : * @param[in] len Length of @a data.
179 : * @param[in] priv Private user data.
180 : */
181 1 : void (*received)(const void *data, size_t len, void *priv);
182 :
183 : /** @brief An error occurred.
184 : *
185 : * @param[in] message Error message.
186 : * @param[in] priv Private user data.
187 : */
188 1 : void (*error)(const char *message, void *priv);
189 : };
190 :
191 : /** @brief Endpoint instance.
192 : *
193 : * Token is not important for user of the API. It is implemented in a
194 : * specific backend.
195 : */
196 1 : struct ipc_ept {
197 :
198 : /** Instance this endpoint belongs to. */
199 1 : const struct device *instance;
200 :
201 : /** Backend-specific token used to identify an endpoint in an instance. */
202 1 : void *token;
203 : };
204 :
205 : /** @brief Endpoint configuration structure. */
206 1 : struct ipc_ept_cfg {
207 :
208 : /** Name of the endpoint. */
209 1 : const char *name;
210 :
211 : /** Endpoint priority. If the backend supports priorities. */
212 1 : int prio;
213 :
214 : /** Event callback structure. */
215 1 : struct ipc_service_cb cb;
216 :
217 : /** Private user data. */
218 1 : void *priv;
219 : };
220 :
221 : /** @brief Open an instance
222 : *
223 : * Function to be used to open an instance before being able to register a new
224 : * endpoint on it.
225 : *
226 : * @param[in] instance Instance to open.
227 : *
228 : * @retval -EINVAL when instance configuration is invalid.
229 : * @retval -EIO when no backend is registered.
230 : * @retval -EALREADY when the instance is already opened (or being opened).
231 : *
232 : * @retval 0 on success or when not implemented on the backend (not needed).
233 : * @retval other errno codes depending on the implementation of the backend.
234 : */
235 1 : int ipc_service_open_instance(const struct device *instance);
236 :
237 : /** @brief Close an instance
238 : *
239 : * Function to be used to close an instance. All bounded endpoints must be
240 : * deregistered using ipc_service_deregister_endpoint before this
241 : * is called.
242 : *
243 : * @param[in] instance Instance to close.
244 : *
245 : * @retval -EINVAL when instance configuration is invalid.
246 : * @retval -EIO when no backend is registered.
247 : * @retval -EALREADY when the instance is not already opened.
248 : * @retval -EBUSY when an endpoint exists that hasn't been
249 : * deregistered
250 : *
251 : * @retval 0 on success or when not implemented on the backend (not needed).
252 : * @retval other errno codes depending on the implementation of the backend.
253 : */
254 1 : int ipc_service_close_instance(const struct device *instance);
255 :
256 : /** @brief Register IPC endpoint onto an instance.
257 : *
258 : * Registers IPC endpoint onto an instance to enable communication with a
259 : * remote device.
260 : *
261 : * The same function registers endpoints for both host and remote devices.
262 : *
263 : * @param[in] instance Instance to register the endpoint onto.
264 : * @param[in] ept Endpoint object.
265 : * @param[in] cfg Endpoint configuration.
266 : *
267 : * @note Keep the variable pointed by @p cfg alive when endpoint is in use.
268 : *
269 : * @retval -EIO when no backend is registered.
270 : * @retval -EINVAL when instance, endpoint or configuration is invalid.
271 : * @retval -EBUSY when the instance is busy.
272 : *
273 : * @retval 0 on success.
274 : * @retval other errno codes depending on the implementation of the backend.
275 : */
276 1 : int ipc_service_register_endpoint(const struct device *instance,
277 : struct ipc_ept *ept,
278 : const struct ipc_ept_cfg *cfg);
279 :
280 : /** @brief Deregister an IPC endpoint from its instance.
281 : *
282 : * Deregisters an IPC endpoint from its instance.
283 : *
284 : * The same function deregisters endpoints for both host and remote devices.
285 : *
286 : * @param[in] ept Endpoint object.
287 : *
288 : * @retval -EIO when no backend is registered.
289 : * @retval -EINVAL when instance, endpoint or configuration is invalid.
290 : * @retval -ENOENT when the endpoint is not registered with the instance.
291 : * @retval -EBUSY when the instance is busy.
292 : *
293 : * @retval 0 on success.
294 : * @retval other errno codes depending on the implementation of the backend.
295 : */
296 1 : int ipc_service_deregister_endpoint(struct ipc_ept *ept);
297 :
298 : /** @brief Send data using given IPC endpoint.
299 : *
300 : * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint.
301 : * @param[in] data Pointer to the buffer to send.
302 : * @param[in] len Number of bytes to send.
303 : *
304 : * @retval -EIO when no backend is registered or send hook is missing from
305 : * backend.
306 : * @retval -EINVAL when instance or endpoint is invalid.
307 : * @retval -ENOENT when the endpoint is not registered with the instance.
308 : * @retval -EBADMSG when the data is invalid (i.e. invalid data format,
309 : * invalid length, ...)
310 : * @retval -EBUSY when the instance is busy.
311 : * @retval -ENOMEM when no memory / buffers are available.
312 : *
313 : * @retval bytes number of bytes sent.
314 : * @retval other errno codes depending on the implementation of the backend.
315 : */
316 1 : int ipc_service_send(struct ipc_ept *ept, const void *data, size_t len);
317 :
318 : /** @brief Get the TX buffer size
319 : *
320 : * Get the maximal size of a buffer which can be obtained by @ref
321 : * ipc_service_get_tx_buffer
322 : *
323 : * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint.
324 : *
325 : * @retval -EIO when no backend is registered or send hook is missing from
326 : * backend.
327 : * @retval -EINVAL when instance or endpoint is invalid.
328 : * @retval -ENOENT when the endpoint is not registered with the instance.
329 : * @retval -ENOTSUP when the operation is not supported by backend.
330 : *
331 : * @retval size TX buffer size on success.
332 : * @retval other errno codes depending on the implementation of the backend.
333 : */
334 1 : int ipc_service_get_tx_buffer_size(struct ipc_ept *ept);
335 :
336 : /** @brief Get an empty TX buffer to be sent using @ref ipc_service_send_nocopy
337 : *
338 : * This function can be called to get an empty TX buffer so that the
339 : * application can directly put its data into the sending buffer without copy
340 : * from an application buffer.
341 : *
342 : * It is the application responsibility to correctly fill the allocated TX
343 : * buffer with data and passing correct parameters to @ref
344 : * ipc_service_send_nocopy function to perform data no-copy-send mechanism.
345 : *
346 : * The size parameter can be used to request a buffer with a certain size:
347 : * - if the size can be accommodated the function returns no errors and the
348 : * buffer is allocated
349 : * - if the requested size is too big, the function returns -ENOMEM and the
350 : * the buffer is not allocated.
351 : * - if the requested size is '0' the buffer is allocated with the maximum
352 : * allowed size.
353 : *
354 : * In all the cases on return the size parameter contains the maximum size for
355 : * the returned buffer.
356 : *
357 : * When the function returns no errors, the buffer is intended as allocated
358 : * and it is released under two conditions: (1) when sending the buffer using
359 : * @ref ipc_service_send_nocopy (and in this case the buffer is automatically
360 : * released by the backend), (2) when using @ref ipc_service_drop_tx_buffer on
361 : * a buffer not sent.
362 : *
363 : * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint.
364 : * @param[out] data Pointer to the empty TX buffer.
365 : * @param[in,out] size Pointer to store the requested TX buffer size. If the
366 : * function returns -ENOMEM, this parameter returns the
367 : * maximum allowed size.
368 : * @param[in] wait Timeout waiting for an available TX buffer.
369 : *
370 : * @retval -EIO when no backend is registered or send hook is missing from
371 : * backend.
372 : * @retval -EINVAL when instance or endpoint is invalid.
373 : * @retval -ENOENT when the endpoint is not registered with the instance.
374 : * @retval -ENOTSUP when the operation or the timeout is not supported by backend.
375 : * @retval -ENOBUFS when there are no TX buffers available.
376 : * @retval -EALREADY when a buffer was already claimed and not yet released.
377 : * @retval -ENOMEM when the requested size is too big (and the size parameter
378 : * contains the maximum allowed size).
379 : *
380 : * @retval 0 on success.
381 : * @retval other errno codes depending on the implementation of the backend.
382 : */
383 1 : int ipc_service_get_tx_buffer(struct ipc_ept *ept, void **data, uint32_t *size, k_timeout_t wait);
384 :
385 : /** @brief Drop and release a TX buffer
386 : *
387 : * Drop and release a TX buffer. It is possible to drop only TX buffers
388 : * obtained by using @ref ipc_service_get_tx_buffer.
389 : *
390 : * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint.
391 : * @param[in] data Pointer to the TX buffer.
392 : *
393 : * @retval -EIO when no backend is registered or send hook is missing from
394 : * backend.
395 : * @retval -EINVAL when instance or endpoint is invalid.
396 : * @retval -ENOENT when the endpoint is not registered with the instance.
397 : * @retval -ENOTSUP when this is not supported by backend.
398 : * @retval -EALREADY when the buffer was already dropped.
399 : * @retval -ENXIO when the buffer was not obtained using @ref
400 : * ipc_service_get_tx_buffer
401 : *
402 : * @retval 0 on success.
403 : * @retval other errno codes depending on the implementation of the backend.
404 : */
405 1 : int ipc_service_drop_tx_buffer(struct ipc_ept *ept, const void *data);
406 :
407 : /** @brief Send data in a TX buffer reserved by @ref ipc_service_get_tx_buffer
408 : * using the given IPC endpoint.
409 : *
410 : * This is equivalent to @ref ipc_service_send but in this case the TX buffer
411 : * has been obtained by using @ref ipc_service_get_tx_buffer.
412 : *
413 : * The application has to take the responsibility for getting the TX buffer
414 : * using @ref ipc_service_get_tx_buffer and filling the TX buffer with the data.
415 : *
416 : * After the @ref ipc_service_send_nocopy function is issued the TX buffer is
417 : * no more owned by the sending task and must not be touched anymore unless
418 : * the function fails and returns an error.
419 : *
420 : * If this function returns an error, @ref ipc_service_drop_tx_buffer can be
421 : * used to drop the TX buffer.
422 : *
423 : * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint.
424 : * @param[in] data Pointer to the buffer to send obtained by @ref
425 : * ipc_service_get_tx_buffer.
426 : * @param[in] len Number of bytes to send.
427 : *
428 : * @retval -EIO when no backend is registered or send hook is missing from
429 : * backend.
430 : * @retval -EINVAL when instance or endpoint is invalid.
431 : * @retval -ENOENT when the endpoint is not registered with the instance.
432 : * @retval -EBADMSG when the data is invalid (i.e. invalid data format,
433 : * invalid length, ...)
434 : * @retval -EBUSY when the instance is busy.
435 : *
436 : * @retval bytes number of bytes sent.
437 : * @retval other errno codes depending on the implementation of the backend.
438 : */
439 1 : int ipc_service_send_nocopy(struct ipc_ept *ept, const void *data, size_t len);
440 :
441 : /** @brief Holds the RX buffer for usage outside the receive callback.
442 : *
443 : * Calling this function prevents the receive buffer from being released
444 : * back to the pool of shmem buffers. This function can be called in the
445 : * receive callback when the user does not want to copy the message out in
446 : * the callback itself.
447 : *
448 : * After the message is processed, the application must release the buffer
449 : * using the @ref ipc_service_release_rx_buffer function.
450 : *
451 : * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint.
452 : * @param[in] data Pointer to the RX buffer to hold.
453 : *
454 : * @retval -EIO when no backend is registered or release hook is missing from
455 : * backend.
456 : * @retval -EINVAL when instance or endpoint is invalid.
457 : * @retval -ENOENT when the endpoint is not registered with the instance.
458 : * @retval -EALREADY when the buffer data has been hold already.
459 : * @retval -ENOTSUP when this is not supported by backend.
460 : *
461 : * @retval 0 on success.
462 : * @retval other errno codes depending on the implementation of the backend.
463 : */
464 1 : int ipc_service_hold_rx_buffer(struct ipc_ept *ept, void *data);
465 :
466 : /** @brief Release the RX buffer for future reuse.
467 : *
468 : * When supported by the backend, this function can be called after the
469 : * received message has been processed and the buffer can be marked as
470 : * reusable again.
471 : *
472 : * It is possible to release only RX buffers on which @ref
473 : * ipc_service_hold_rx_buffer was previously used.
474 : *
475 : * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint.
476 : * @param[in] data Pointer to the RX buffer to release.
477 : *
478 : * @retval -EIO when no backend is registered or release hook is missing from
479 : * backend.
480 : * @retval -EINVAL when instance or endpoint is invalid.
481 : * @retval -ENOENT when the endpoint is not registered with the instance.
482 : * @retval -EALREADY when the buffer data has been already released.
483 : * @retval -ENOTSUP when this is not supported by backend.
484 : * @retval -ENXIO when the buffer was not hold before using @ref
485 : * ipc_service_hold_rx_buffer
486 : *
487 : * @retval 0 on success.
488 : * @retval other errno codes depending on the implementation of the backend.
489 : */
490 1 : int ipc_service_release_rx_buffer(struct ipc_ept *ept, void *data);
491 :
492 : /**
493 : * @}
494 : */
495 :
496 : #ifdef __cplusplus
497 : }
498 : #endif
499 :
500 : #endif /* ZEPHYR_INCLUDE_IPC_IPC_SERVICE_H_ */
|