1 /*
2  * Copyright (c) 2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_INCLUDE_IPC_ICMSG_H_
8 #define ZEPHYR_INCLUDE_IPC_ICMSG_H_
9 
10 #include <stddef.h>
11 #include <stdint.h>
12 #include <zephyr/kernel.h>
13 #include <zephyr/drivers/mbox.h>
14 #include <zephyr/ipc/ipc_service.h>
15 #include <zephyr/sys/atomic.h>
16 #include <zephyr/sys/spsc_pbuf.h>
17 
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21 
22 /**
23  * @brief Icmsg IPC library API
24  * @defgroup ipc_icmsg_api Icmsg IPC library API
25  * @ingroup ipc
26  * @{
27  */
28 
29 enum icmsg_state {
30 	ICMSG_STATE_OFF,
31 	ICMSG_STATE_BUSY,
32 	ICMSG_STATE_READY,
33 };
34 
35 struct icmsg_config_t {
36 	uintptr_t tx_shm_addr;
37 	uintptr_t rx_shm_addr;
38 	size_t tx_shm_size;
39 	size_t rx_shm_size;
40 	struct mbox_channel mbox_tx;
41 	struct mbox_channel mbox_rx;
42 };
43 
44 struct icmsg_data_t {
45 	/* Tx/Rx buffers. */
46 	struct spsc_pbuf *tx_ib;
47 	struct spsc_pbuf *rx_ib;
48 	atomic_t tx_buffer_state;
49 #ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC
50 	struct k_mutex tx_lock;
51 #endif
52 
53 	/* Callbacks for an endpoint. */
54 	const struct ipc_service_cb *cb;
55 	void *ctx;
56 
57 	/* General */
58 	const struct icmsg_config_t *cfg;
59 	struct k_work_delayable notify_work;
60 	struct k_work mbox_work;
61 	atomic_t state;
62 	/* No-copy */
63 #ifdef CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX
64 	atomic_t rx_buffer_state;
65 	const void *rx_buffer;
66 	uint16_t rx_len;
67 #endif
68 };
69 
70 /** @brief Open an icmsg instance
71  *
72  *  Open an icmsg instance to be able to send and receive messages to a remote
73  *  instance.
74  *  This function is blocking until the handshake with the remote instance is
75  *  completed.
76  *  This function is intended to be called late in the initialization process,
77  *  possibly from a thread which can be safely blocked while handshake with the
78  *  remote instance is being pefromed.
79  *
80  *  @param[in] conf Structure containing configuration parameters for the icmsg
81  *                  instance.
82  *  @param[inout] dev_data Structure containing run-time data used by the icmsg
83  *                         instance.
84  *  @param[in] cb Structure containing callback functions to be called on
85  *                events generated by this icmsg instance. The pointed memory
86  *                must be preserved while the icmsg instance is active.
87  *  @param[in] ctx Pointer to context passed as an argument to callbacks.
88  *
89  *
90  *  @retval 0 on success.
91  *  @retval -EALREADY when the instance is already opened.
92  *  @retval other errno codes from dependent modules.
93  */
94 int icmsg_open(const struct icmsg_config_t *conf,
95 	       struct icmsg_data_t *dev_data,
96 	       const struct ipc_service_cb *cb, void *ctx);
97 
98 /** @brief Close an icmsg instance
99  *
100  *  Closing an icmsg instance results in releasing all resources used by given
101  *  instance including the shared memory regions and mbox devices.
102  *
103  *  @param[in] conf Structure containing configuration parameters for the icmsg
104  *                  instance being closed. Its content must be the same as used
105  *                  for creating this instance with @ref icmsg_open.
106  *  @param[inout] dev_data Structure containing run-time data used by the icmsg
107  *                         instance.
108  *
109  *  @retval 0 on success.
110  *  @retval other errno codes from dependent modules.
111  */
112 int icmsg_close(const struct icmsg_config_t *conf,
113 		struct icmsg_data_t *dev_data);
114 
115 /** @brief Send a message to the remote icmsg instance.
116  *
117  *  @param[in] conf Structure containing configuration parameters for the icmsg
118  *                  instance.
119  *  @param[inout] dev_data Structure containing run-time data used by the icmsg
120  *                         instance.
121  *  @param[in] msg Pointer to a buffer containing data to send.
122  *  @param[in] len Size of data in the @p msg buffer.
123  *
124  *
125  *  @retval 0 on success.
126  *  @retval -EBUSY when the instance has not finished handshake with the remote
127  *                 instance.
128  *  @retval -ENODATA when the requested data to send is empty.
129  *  @retval -EBADMSG when the requested data to send is too big.
130  *  @retval -ENOBUFS when there are no TX buffers available.
131  *  @retval other errno codes from dependent modules.
132  */
133 int icmsg_send(const struct icmsg_config_t *conf,
134 	       struct icmsg_data_t *dev_data,
135 	       const void *msg, size_t len);
136 
137 /** @brief Get an empty TX buffer to be sent using @ref icmsg_send_nocopy
138  *
139  *  This function can be called to get an empty TX buffer so that the
140  *  application can directly put its data into the sending buffer avoiding copy
141  *  performed by the icmsg library.
142  *
143  *  It is the application responsibility to correctly fill the allocated TX
144  *  buffer with data and passing correct parameters to @ref
145  *  icmsg_send_nocopy function to perform data no-copy-send mechanism.
146  *
147  *  The size parameter can be used to request a buffer with a certain size:
148  *  - if the size can be accommodated the function returns no errors and the
149  *    buffer is allocated
150  *  - if the requested size is too big, the function returns -ENOMEM and the
151  *    the buffer is not allocated.
152  *  - if the requested size is '0' the buffer is allocated with the maximum
153  *    allowed size.
154  *
155  *  In all the cases on return the size parameter contains the maximum size for
156  *  the returned buffer.
157  *
158  *  When the function returns no errors, the buffer is intended as allocated
159  *  and it is released under one of two conditions: (1) when sending the buffer
160  *  using @ref icmsg_send_nocopy (and in this case the buffer is automatically
161  *  released by the backend), (2) when using @ref icmsg_drop_tx_buffer on a
162  *  buffer not sent.
163  *
164  *  @param[in] conf Structure containing configuration parameters for the icmsg
165  *                  instance.
166  *  @param[inout] dev_data Structure containing run-time data used by the icmsg
167  *                         instance.
168  *  @param[out] data Pointer to the empty TX buffer.
169  *  @param[inout] size Pointer to store the requested TX buffer size. If the
170  *		       function returns -ENOMEM, this parameter returns the
171  *		       maximum allowed size.
172  *
173  *  @retval -ENOBUFS when there are no TX buffers available.
174  *  @retval -EALREADY when a buffer was already claimed and not yet released.
175  *  @retval -ENOMEM when the requested size is too big (and the size parameter
176  *		    contains the maximum allowed size).
177  *
178  *  @retval 0 on success.
179  */
180 int icmsg_get_tx_buffer(const struct icmsg_config_t *conf,
181 			struct icmsg_data_t *dev_data,
182 			void **data, size_t *size);
183 
184 /** @brief Drop and release a TX buffer
185  *
186  *  Drop and release a TX buffer. It is possible to drop only TX buffers
187  *  obtained by using @ref icmsg_get_tx_buffer.
188  *
189  *  @param[in] conf Structure containing configuration parameters for the icmsg
190  *                  instance.
191  *  @param[inout] dev_data Structure containing run-time data used by the icmsg
192  *                         instance.
193  *  @param[in] data Pointer to the TX buffer.
194  *
195  *  @retval -EALREADY when the buffer was already dropped.
196  *  @retval -ENXIO when the buffer was not obtained using @ref
197  *		   ipc_service_get_tx_buffer
198  *
199  *  @retval 0 on success.
200  */
201 int icmsg_drop_tx_buffer(const struct icmsg_config_t *conf,
202 			 struct icmsg_data_t *dev_data,
203 			 const void *data);
204 
205 /** @brief Send a message from a buffer obtained by @ref icmsg_get_tx_buffer
206  *         to the remote icmsg instance.
207  *
208  *  This is equivalent to @ref icmsg_send but in this case the TX buffer must
209  *  have been obtained by using @ref icmsg_get_tx_buffer.
210  *
211  *  The API user has to take the responsibility for getting the TX buffer using
212  *  @ref icmsg_get_tx_buffer and filling the TX buffer with the data.
213  *
214  *  After the @ref icmsg_send_nocopy function is issued the TX buffer is no
215  *  more owned by the sending task and must not be touched anymore unless the
216  *  function fails and returns an error.
217  *
218  *  If this function returns an error, @ref icmsg_drop_tx_buffer can be used
219  *  to drop the TX buffer.
220  *
221  *  @param[in] conf Structure containing configuration parameters for the icmsg
222  *                  instance.
223  *  @param[inout] dev_data Structure containing run-time data used by the icmsg
224  *                         instance.
225  *  @param[in] msg Pointer to a buffer containing data to send.
226  *  @param[in] len Size of data in the @p msg buffer.
227  *
228  *
229  *  @return Size of sent data on success.
230  *  @retval -EBUSY when the instance has not finished handshake with the remote
231  *                 instance.
232  *  @retval -ENODATA when the requested data to send is empty.
233  *  @retval -EBADMSG when the requested data to send is too big.
234  *  @retval -ENXIO when the buffer was not obtained using @ref
235  *		   ipc_service_get_tx_buffer
236  *  @retval other errno codes from dependent modules.
237  */
238 int icmsg_send_nocopy(const struct icmsg_config_t *conf,
239 		      struct icmsg_data_t *dev_data,
240 		      const void *msg, size_t len);
241 
242 #ifdef CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX
243 /** @brief Hold RX buffer to be used outside of the received callback.
244  *
245  *  @param[in] conf Structure containing configuration parameters for the icmsg
246  *                  instance.
247  *  @param[inout] dev_data Structure containing run-time data used by the icmsg
248  *                         instance.
249  *  @param[in] data Pointer to the buffer to be held.
250  *
251  *  @retval 0 on success.
252  *  @retval -EBUSY when the instance has not finished handshake with the remote
253  *                 instance.
254  *  @retval -EINVAL when the @p data argument does not point to a valid RX
255  *                  buffer.
256  *  @retval -EALREADY when the buffer is already held.
257  */
258 int icmsg_hold_rx_buffer(const struct icmsg_config_t *conf,
259 			 struct icmsg_data_t *dev_data,
260 			 const void *data);
261 
262 /** @brief Release RX buffer for future use.
263  *
264  *  @param[in] conf Structure containing configuration parameters for the icmsg
265  *                  instance.
266  *  @param[inout] dev_data Structure containing run-time data used by the icmsg
267  *                         instance.
268  *  @param[in] data Pointer to the buffer to be released.
269  *
270  *  @retval 0 on success.
271  *  @retval -EBUSY when the instance has not finished handshake with the remote
272  *                 instance.
273  *  @retval -EINVAL when the @p data argument does not point to a valid RX
274  *                  buffer.
275  *  @retval -EALREADY when the buffer is not held.
276  */
277 int icmsg_release_rx_buffer(const struct icmsg_config_t *conf,
278 			    struct icmsg_data_t *dev_data,
279 			    const void *data);
280 #endif
281 
282 /**
283  * @}
284  */
285 
286 #ifdef __cplusplus
287 }
288 #endif
289 
290 #endif /* ZEPHYR_INCLUDE_IPC_ICMSG_H_ */
291