1 /*
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 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 	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 	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 	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 	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 struct ipc_ept {
197 
198 	/** Instance this endpoint belongs to. */
199 	const struct device *instance;
200 
201 	/** Backend-specific token used to identify an endpoint in an instance. */
202 	void *token;
203 };
204 
205 /** @brief Endpoint configuration structure. */
206 struct ipc_ept_cfg {
207 
208 	/** Name of the endpoint. */
209 	const char *name;
210 
211 	/** Endpoint priority. If the backend supports priorities. */
212 	int prio;
213 
214 	/** Event callback structure. */
215 	struct ipc_service_cb cb;
216 
217 	/** Private user data. */
218 	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 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 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 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 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 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 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 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 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 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 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 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_ */
501