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 New packet arrived. 155 * 156 * This callback is called when new data is received. 157 * 158 * @note When @ref ipc_service_hold_rx_buffer is not used, the data 159 * buffer is to be considered released and available again only 160 * when this callback returns. 161 * 162 * @param[in] data Pointer to data buffer. 163 * @param[in] len Length of @a data. 164 * @param[in] priv Private user data. 165 */ 166 void (*received)(const void *data, size_t len, void *priv); 167 168 /** @brief An error occurred. 169 * 170 * @param[in] message Error message. 171 * @param[in] priv Private user data. 172 */ 173 void (*error)(const char *message, void *priv); 174 }; 175 176 /** @brief Endpoint instance. 177 * 178 * Token is not important for user of the API. It is implemented in a 179 * specific backend. 180 */ 181 struct ipc_ept { 182 183 /** Instance this endpoint belongs to. */ 184 const struct device *instance; 185 186 /** Backend-specific token used to identify an endpoint in an instance. */ 187 void *token; 188 }; 189 190 /** @brief Endpoint configuration structure. */ 191 struct ipc_ept_cfg { 192 193 /** Name of the endpoint. */ 194 const char *name; 195 196 /** Endpoint priority. If the backend supports priorities. */ 197 int prio; 198 199 /** Event callback structure. */ 200 struct ipc_service_cb cb; 201 202 /** Private user data. */ 203 void *priv; 204 }; 205 206 /** @brief Open an instance 207 * 208 * Function to be used to open an instance before being able to register a new 209 * endpoint on it. 210 * 211 * @param[in] instance Instance to open. 212 * 213 * @retval -EINVAL when instance configuration is invalid. 214 * @retval -EIO when no backend is registered. 215 * @retval -EALREADY when the instance is already opened (or being opened). 216 * 217 * @retval 0 on success or when not implemented on the backend (not needed). 218 * @retval other errno codes depending on the implementation of the backend. 219 */ 220 int ipc_service_open_instance(const struct device *instance); 221 222 /** @brief Close an instance 223 * 224 * Function to be used to close an instance. All bounded endpoints must be 225 * deregistered using ipc_service_deregister_endpoint before this 226 * is called. 227 * 228 * @param[in] instance Instance to close. 229 * 230 * @retval -EINVAL when instance configuration is invalid. 231 * @retval -EIO when no backend is registered. 232 * @retval -EALREADY when the instance is not already opened. 233 * @retval -EBUSY when an endpoint exists that hasn't been 234 * deregistered 235 * 236 * @retval 0 on success or when not implemented on the backend (not needed). 237 * @retval other errno codes depending on the implementation of the backend. 238 */ 239 int ipc_service_close_instance(const struct device *instance); 240 241 /** @brief Register IPC endpoint onto an instance. 242 * 243 * Registers IPC endpoint onto an instance to enable communication with a 244 * remote device. 245 * 246 * The same function registers endpoints for both host and remote devices. 247 * 248 * @param[in] instance Instance to register the endpoint onto. 249 * @param[in] ept Endpoint object. 250 * @param[in] cfg Endpoint configuration. 251 * 252 * @note Keep the variable pointed by @p cfg alive when endpoint is in use. 253 * 254 * @retval -EIO when no backend is registered. 255 * @retval -EINVAL when instance, endpoint or configuration is invalid. 256 * @retval -EBUSY when the instance is busy. 257 * 258 * @retval 0 on success. 259 * @retval other errno codes depending on the implementation of the backend. 260 */ 261 int ipc_service_register_endpoint(const struct device *instance, 262 struct ipc_ept *ept, 263 const struct ipc_ept_cfg *cfg); 264 265 /** @brief Deregister an IPC endpoint from its instance. 266 * 267 * Deregisters an IPC endpoint from its instance. 268 * 269 * The same function deregisters endpoints for both host and remote devices. 270 * 271 * @param[in] ept Endpoint object. 272 * 273 * @retval -EIO when no backend is registered. 274 * @retval -EINVAL when instance, endpoint or configuration is invalid. 275 * @retval -ENOENT when the endpoint is not registered with the instance. 276 * @retval -EBUSY when the instance is busy. 277 * 278 * @retval 0 on success. 279 * @retval other errno codes depending on the implementation of the backend. 280 */ 281 int ipc_service_deregister_endpoint(struct ipc_ept *ept); 282 283 /** @brief Send data using given IPC endpoint. 284 * 285 * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint. 286 * @param[in] data Pointer to the buffer to send. 287 * @param[in] len Number of bytes to send. 288 * 289 * @retval -EIO when no backend is registered or send hook is missing from 290 * backend. 291 * @retval -EINVAL when instance or endpoint is invalid. 292 * @retval -ENOENT when the endpoint is not registered with the instance. 293 * @retval -EBADMSG when the data is invalid (i.e. invalid data format, 294 * invalid length, ...) 295 * @retval -EBUSY when the instance is busy. 296 * @retval -ENOMEM when no memory / buffers are available. 297 * 298 * @retval bytes number of bytes sent. 299 * @retval other errno codes depending on the implementation of the backend. 300 */ 301 int ipc_service_send(struct ipc_ept *ept, const void *data, size_t len); 302 303 /** @brief Get the TX buffer size 304 * 305 * Get the maximal size of a buffer which can be obtained by @ref 306 * ipc_service_get_tx_buffer 307 * 308 * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint. 309 * 310 * @retval -EIO when no backend is registered or send hook is missing from 311 * backend. 312 * @retval -EINVAL when instance or endpoint is invalid. 313 * @retval -ENOENT when the endpoint is not registered with the instance. 314 * @retval -ENOTSUP when the operation is not supported by backend. 315 * 316 * @retval size TX buffer size on success. 317 * @retval other errno codes depending on the implementation of the backend. 318 */ 319 int ipc_service_get_tx_buffer_size(struct ipc_ept *ept); 320 321 /** @brief Get an empty TX buffer to be sent using @ref ipc_service_send_nocopy 322 * 323 * This function can be called to get an empty TX buffer so that the 324 * application can directly put its data into the sending buffer without copy 325 * from an application buffer. 326 * 327 * It is the application responsibility to correctly fill the allocated TX 328 * buffer with data and passing correct parameters to @ref 329 * ipc_service_send_nocopy function to perform data no-copy-send mechanism. 330 * 331 * The size parameter can be used to request a buffer with a certain size: 332 * - if the size can be accommodated the function returns no errors and the 333 * buffer is allocated 334 * - if the requested size is too big, the function returns -ENOMEM and the 335 * the buffer is not allocated. 336 * - if the requested size is '0' the buffer is allocated with the maximum 337 * allowed size. 338 * 339 * In all the cases on return the size parameter contains the maximum size for 340 * the returned buffer. 341 * 342 * When the function returns no errors, the buffer is intended as allocated 343 * and it is released under two conditions: (1) when sending the buffer using 344 * @ref ipc_service_send_nocopy (and in this case the buffer is automatically 345 * released by the backend), (2) when using @ref ipc_service_drop_tx_buffer on 346 * a buffer not sent. 347 * 348 * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint. 349 * @param[out] data Pointer to the empty TX buffer. 350 * @param[in,out] size Pointer to store the requested TX buffer size. If the 351 * function returns -ENOMEM, this parameter returns the 352 * maximum allowed size. 353 * @param[in] wait Timeout waiting for an available TX buffer. 354 * 355 * @retval -EIO when no backend is registered or send hook is missing from 356 * backend. 357 * @retval -EINVAL when instance or endpoint is invalid. 358 * @retval -ENOENT when the endpoint is not registered with the instance. 359 * @retval -ENOTSUP when the operation or the timeout is not supported by backend. 360 * @retval -ENOBUFS when there are no TX buffers available. 361 * @retval -EALREADY when a buffer was already claimed and not yet released. 362 * @retval -ENOMEM when the requested size is too big (and the size parameter 363 * contains the maximum allowed size). 364 * 365 * @retval 0 on success. 366 * @retval other errno codes depending on the implementation of the backend. 367 */ 368 int ipc_service_get_tx_buffer(struct ipc_ept *ept, void **data, uint32_t *size, k_timeout_t wait); 369 370 /** @brief Drop and release a TX buffer 371 * 372 * Drop and release a TX buffer. It is possible to drop only TX buffers 373 * obtained by using @ref ipc_service_get_tx_buffer. 374 * 375 * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint. 376 * @param[in] data Pointer to the TX buffer. 377 * 378 * @retval -EIO when no backend is registered or send hook is missing from 379 * backend. 380 * @retval -EINVAL when instance or endpoint is invalid. 381 * @retval -ENOENT when the endpoint is not registered with the instance. 382 * @retval -ENOTSUP when this is not supported by backend. 383 * @retval -EALREADY when the buffer was already dropped. 384 * @retval -ENXIO when the buffer was not obtained using @ref 385 * ipc_service_get_tx_buffer 386 * 387 * @retval 0 on success. 388 * @retval other errno codes depending on the implementation of the backend. 389 */ 390 int ipc_service_drop_tx_buffer(struct ipc_ept *ept, const void *data); 391 392 /** @brief Send data in a TX buffer reserved by @ref ipc_service_get_tx_buffer 393 * using the given IPC endpoint. 394 * 395 * This is equivalent to @ref ipc_service_send but in this case the TX buffer 396 * has been obtained by using @ref ipc_service_get_tx_buffer. 397 * 398 * The application has to take the responsibility for getting the TX buffer 399 * using @ref ipc_service_get_tx_buffer and filling the TX buffer with the data. 400 * 401 * After the @ref ipc_service_send_nocopy function is issued the TX buffer is 402 * no more owned by the sending task and must not be touched anymore unless 403 * the function fails and returns an error. 404 * 405 * If this function returns an error, @ref ipc_service_drop_tx_buffer can be 406 * used to drop the TX buffer. 407 * 408 * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint. 409 * @param[in] data Pointer to the buffer to send obtained by @ref 410 * ipc_service_get_tx_buffer. 411 * @param[in] len Number of bytes to send. 412 * 413 * @retval -EIO when no backend is registered or send hook is missing from 414 * backend. 415 * @retval -EINVAL when instance or endpoint is invalid. 416 * @retval -ENOENT when the endpoint is not registered with the instance. 417 * @retval -EBADMSG when the data is invalid (i.e. invalid data format, 418 * invalid length, ...) 419 * @retval -EBUSY when the instance is busy. 420 * 421 * @retval bytes number of bytes sent. 422 * @retval other errno codes depending on the implementation of the backend. 423 */ 424 int ipc_service_send_nocopy(struct ipc_ept *ept, const void *data, size_t len); 425 426 /** @brief Holds the RX buffer for usage outside the receive callback. 427 * 428 * Calling this function prevents the receive buffer from being released 429 * back to the pool of shmem buffers. This function can be called in the 430 * receive callback when the user does not want to copy the message out in 431 * the callback itself. 432 * 433 * After the message is processed, the application must release the buffer 434 * using the @ref ipc_service_release_rx_buffer function. 435 * 436 * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint. 437 * @param[in] data Pointer to the RX buffer to hold. 438 * 439 * @retval -EIO when no backend is registered or release hook is missing from 440 * backend. 441 * @retval -EINVAL when instance or endpoint is invalid. 442 * @retval -ENOENT when the endpoint is not registered with the instance. 443 * @retval -EALREADY when the buffer data has been hold already. 444 * @retval -ENOTSUP when this is not supported by backend. 445 * 446 * @retval 0 on success. 447 * @retval other errno codes depending on the implementation of the backend. 448 */ 449 int ipc_service_hold_rx_buffer(struct ipc_ept *ept, void *data); 450 451 /** @brief Release the RX buffer for future reuse. 452 * 453 * When supported by the backend, this function can be called after the 454 * received message has been processed and the buffer can be marked as 455 * reusable again. 456 * 457 * It is possible to release only RX buffers on which @ref 458 * ipc_service_hold_rx_buffer was previously used. 459 * 460 * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint. 461 * @param[in] data Pointer to the RX buffer to release. 462 * 463 * @retval -EIO when no backend is registered or release hook is missing from 464 * backend. 465 * @retval -EINVAL when instance or endpoint is invalid. 466 * @retval -ENOENT when the endpoint is not registered with the instance. 467 * @retval -EALREADY when the buffer data has been already released. 468 * @retval -ENOTSUP when this is not supported by backend. 469 * @retval -ENXIO when the buffer was not hold before using @ref 470 * ipc_service_hold_rx_buffer 471 * 472 * @retval 0 on success. 473 * @retval other errno codes depending on the implementation of the backend. 474 */ 475 int ipc_service_release_rx_buffer(struct ipc_ept *ept, void *data); 476 477 /** 478 * @} 479 */ 480 481 #ifdef __cplusplus 482 } 483 #endif 484 485 #endif /* ZEPHYR_INCLUDE_IPC_IPC_SERVICE_H_ */ 486