| /* |
| * Copyright (c) 2021 Nordic Semiconductor ASA |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #ifndef ZEPHYR_INCLUDE_IPC_IPC_SERVICE_H_ |
| #define ZEPHYR_INCLUDE_IPC_IPC_SERVICE_H_ |
| |
| #include <stdio.h> |
| #include <device.h> |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /** |
| * @brief IPC Service API |
| * @defgroup ipc_service_api IPC service APIs |
| * @{ |
| * |
| * Some terminology: |
| * |
| * - INSTANCE: an instance is the external representation of a physical |
| * communication channel between two domains / CPUs. |
| * |
| * The actual implementation and internal representation of the |
| * instance is peculiar to each backend. For example for |
| * OpenAMP-based backends, an instance is usually represented by a |
| * shared memory region and a couple of IPM devices for RX/TX |
| * signalling. |
| * |
| * It's important to note that an instance per se is not used to |
| * send data between domains / CPUs. To send and receive data the |
| * user have to create (register) an endpoint in the instance |
| * connecting the two domains of interest. |
| * |
| * It's possible to have zero or multiple endpoints in one single |
| * instance, each one used to exchange data, possibly with different |
| * priorities. |
| * |
| * The creation of the instances is left to the backend (usually at |
| * init time), while the registration of the endpoints is left to |
| * the user (usually at run time). |
| * |
| * - ENDPOINT: an endpoint is the entity the user must use to send / receive |
| * data between two domains (connected by the instance). An |
| * endpoint is always associated to an instance. |
| * |
| * - BACKEND: the backend must take care of at least two different things: |
| * |
| * 1) creating the instances at init time |
| * 2) creating / registering the endpoints onto an instance at run |
| * time when requested by the user |
| * |
| * The API doesn't mandate a way for the backend to create the |
| * instances but itis strongly recommended to use the DT to retrieve |
| * the configuration parameters for the instance. |
| * |
| * Common API usage from the application prospective: |
| * |
| * HOST REMOTE |
| * ----------------------------------------------------------------------------- |
| * # Open the (same) instance on host and remote |
| * ipc_service_open() ipc_service_open() |
| * |
| * # Register the endpoints |
| * ipc_service_register_endpoint() ipc_service_register_endpoint() |
| * .bound() .bound() |
| * |
| * # After the .bound() callbacks are received the communication channel |
| * # is ready to be used |
| * |
| * # Start sending and receiving data |
| * ipc_service_send() |
| * .receive() |
| * ipc_service_send() |
| * .receive() |
| * |
| * |
| * Common API usage from the application prospective when using NOCOPY feature: |
| * |
| * HOST REMOTE |
| * ----------------------------------------------------------------------------- |
| * ipc_service_open() ipc_service_open() |
| * |
| * ipc_service_register_endpoint() ipc_service_register_endpoint() |
| * .bound() .bound() |
| * |
| * # Get a pointer to an available TX buffer |
| * ipc_service_get_tx_buffer() |
| * |
| * # Fill the buffer with data |
| * |
| * # Send out the buffer |
| * ipc_service_send_nocopy() |
| * .receive() |
| * |
| * # Get hold of the received RX buffer |
| * # in the .receive callback |
| * ipc_service_hold_rx_buffer() |
| * |
| * # Copy the data out of the buffer at |
| * # user convenience |
| * |
| * # Release the buffer when done |
| * ipc_service_release_rx_buffer() |
| * |
| * # Get another TX buffer |
| * ipc_service_get_tx_buffer() |
| * |
| * # We can also drop it if needed |
| * ipc_service_drop_tx_buffer() |
| * |
| */ |
| |
| /** @brief Event callback structure. |
| * |
| * It is registered during endpoint registration. |
| * This structure is part of the endpoint configuration. |
| */ |
| struct ipc_service_cb { |
| /** @brief Bind was successful. |
| * |
| * This callback is called when the endpoint binding is successful. |
| * |
| * @param[in] priv Private user data. |
| */ |
| void (*bound)(void *priv); |
| |
| /** @brief New packet arrived. |
| * |
| * This callback is called when new data is received. |
| * |
| * @note When @ref ipc_service_hold_rx_buffer is not used, the data |
| * buffer is to be considered released and available again only |
| * when this callback returns. |
| * |
| * @param[in] data Pointer to data buffer. |
| * @param[in] len Length of @a data. |
| * @param[in] priv Private user data. |
| */ |
| void (*received)(const void *data, size_t len, void *priv); |
| |
| /** @brief An error occurred. |
| * |
| * @param[in] message Error message. |
| * @param[in] priv Private user data. |
| */ |
| void (*error)(const char *message, void *priv); |
| }; |
| |
| /** @brief Endpoint instance. |
| * |
| * Token is not important for user of the API. It is implemented in a |
| * specific backend. |
| */ |
| struct ipc_ept { |
| |
| /** Instance this endpoint belongs to. */ |
| const struct device *instance; |
| |
| /** Backend-specific token used to identify an endpoint in an instance. */ |
| void *token; |
| }; |
| |
| /** @brief Endpoint configuration structure. */ |
| struct ipc_ept_cfg { |
| |
| /** Name of the endpoint. */ |
| const char *name; |
| |
| /** Endpoint priority. If the backend supports priorities. */ |
| int prio; |
| |
| /** Event callback structure. */ |
| struct ipc_service_cb cb; |
| |
| /** Private user data. */ |
| void *priv; |
| }; |
| |
| /** @brief Open an instance |
| * |
| * Function to be used to open an instance before being able to register a new |
| * endpoint on it. |
| * |
| * @param[in] instance Instance to open. |
| * |
| * @retval -EINVAL when instance configuration is invalid. |
| * @retval -EIO when no backend is registered. |
| * @retval -EALREADY when the instance is already opened (or being opened). |
| * |
| * @retval 0 on success or when not implemented on the backend (not needed). |
| * @retval other errno codes depending on the implementation of the backend. |
| */ |
| int ipc_service_open_instance(const struct device *instance); |
| |
| |
| /** @brief Register IPC endpoint onto an instance. |
| * |
| * Registers IPC endpoint onto an instance to enable communication with a |
| * remote device. |
| * |
| * The same function registers endpoints for both host and remote devices. |
| * |
| * @param[in] instance Instance to register the endpoint onto. |
| * @param[in] ept Endpoint object. |
| * @param[in] cfg Endpoint configuration. |
| * |
| * @note Keep the variable pointed by @p cfg alive when endpoint is in use. |
| * |
| * @retval -EIO when no backend is registered. |
| * @retval -EINVAL when instance, endpoint or configuration is invalid. |
| * @retval -EBUSY when the instance is busy. |
| * |
| * @retval 0 on success. |
| * @retval other errno codes depending on the implementation of the backend. |
| */ |
| int ipc_service_register_endpoint(const struct device *instance, |
| struct ipc_ept *ept, |
| const struct ipc_ept_cfg *cfg); |
| |
| /** @brief Send data using given IPC endpoint. |
| * |
| * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint. |
| * @param[in] data Pointer to the buffer to send. |
| * @param[in] len Number of bytes to send. |
| * |
| * @retval -EIO when no backend is registered or send hook is missing from |
| * backend. |
| * @retval -EINVAL when instance or endpoint is invalid. |
| * @retval -EBADMSG when the data is invalid (i.e. invalid data format, |
| * invalid length, ...) |
| * @retval -EBUSY when the instance is busy. |
| * |
| * @retval bytes number of bytes sent. |
| * @retval other errno codes depending on the implementation of the backend. |
| */ |
| int ipc_service_send(struct ipc_ept *ept, const void *data, size_t len); |
| |
| /** @brief Get the TX buffer size |
| * |
| * Get the maximal size of a buffer which can be obtained by @ref |
| * ipc_service_get_tx_buffer |
| * |
| * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint. |
| * |
| * @retval -EIO when no backend is registered or send hook is missing from |
| * backend. |
| * @retval -EINVAL when instance or endpoint is invalid. |
| * @retval -ENOTSUP when the operation is not supported by backend. |
| * |
| * @retval size TX buffer size on success. |
| * @retval other errno codes depending on the implementation of the backend. |
| */ |
| int ipc_service_get_tx_buffer_size(struct ipc_ept *ept); |
| |
| /** @brief Get an empty TX buffer to be sent using @ref ipc_service_send_nocopy |
| * |
| * This function can be called to get an empty TX buffer so that the |
| * application can directly put its data into the sending buffer without copy |
| * from an application buffer. |
| * |
| * It is the application responsibility to correctly fill the allocated TX |
| * buffer with data and passing correct parameters to @ref |
| * ipc_service_send_nocopy function to perform data no-copy-send mechanism. |
| * |
| * The size parameter can be used to request a buffer with a certain size: |
| * - if the size can be accommodated the function returns no errors and the |
| * buffer is allocated |
| * - if the requested size is too big, the function returns -ENOMEM and the |
| * the buffer is not allocated. |
| * - if the requested size is '0' the buffer is allocated with the maximum |
| * allowed size. |
| * |
| * In all the cases on return the size parameter contains the maximum size for |
| * the returned buffer. |
| * |
| * When the function returns no errors, the buffer is intended as allocated |
| * and it is released under two conditions: (1) when sending the buffer using |
| * @ref ipc_service_send_nocopy (and in this case the buffer is automatically |
| * released by the backend), (2) when using @ref ipc_service_drop_tx_buffer on |
| * a buffer not sent. |
| * |
| * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint. |
| * @param[out] data Pointer to the empty TX buffer. |
| * @param[in,out] size Pointer to store the requested TX buffer size. If the |
| * function returns -ENOMEM, this parameter returns the |
| * maximum allowed size. |
| * @param[in] wait Timeout waiting for an available TX buffer. |
| * |
| * @retval -EIO when no backend is registered or send hook is missing from |
| * backend. |
| * @retval -EINVAL when instance or endpoint is invalid. |
| * @retval -ENOTSUP when the operation or the timeout is not supported by backend. |
| * @retval -ENOBUFS when there are no TX buffers available. |
| * @retval -EALREADY when a buffer was already claimed and not yet released. |
| * @retval -ENOMEM when the requested size is too big (and the size parameter |
| * contains the maximum allowed size). |
| * |
| * @retval 0 on success. |
| * @retval other errno codes depending on the implementation of the backend. |
| */ |
| int ipc_service_get_tx_buffer(struct ipc_ept *ept, void **data, uint32_t *size, k_timeout_t wait); |
| |
| /** @brief Drop and release a TX buffer |
| * |
| * Drop and release a TX buffer. It is possible to drop only TX buffers |
| * obtained by using @ref ipc_service_get_tx_buffer. |
| * |
| * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint. |
| * @param[in] data Pointer to the TX buffer. |
| * |
| * @retval -EIO when no backend is registered or send hook is missing from |
| * backend. |
| * @retval -EINVAL when instance or endpoint is invalid. |
| * @retval -ENOTSUP when this is not supported by backend. |
| * @retval -EALREADY when the buffer was already dropped. |
| * @retval -ENXIO when the buffer was not obtained using @ref |
| * ipc_service_get_tx_buffer |
| * |
| * @retval 0 on success. |
| * @retval other errno codes depending on the implementation of the backend. |
| */ |
| int ipc_service_drop_tx_buffer(struct ipc_ept *ept, const void *data); |
| |
| /** @brief Send data in a TX buffer reserved by @ref ipc_service_get_tx_buffer |
| * using the given IPC endpoint. |
| * |
| * This is equivalent to @ref ipc_service_send but in this case the TX buffer |
| * has been obtained by using @ref ipc_service_get_tx_buffer. |
| * |
| * The application has to take the responsibility for getting the TX buffer |
| * using @ref ipc_service_get_tx_buffer and filling the TX buffer with the data. |
| * |
| * After the @ref ipc_service_send_nocopy function is issued the TX buffer is |
| * no more owned by the sending task and must not be touched anymore unless |
| * the function fails and returns an error. |
| * |
| * If this function returns an error, @ref ipc_service_drop_tx_buffer can be |
| * used to drop the TX buffer. |
| * |
| * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint. |
| * @param[in] data Pointer to the buffer to send obtained by @ref |
| * ipc_service_get_tx_buffer. |
| * @param[in] len Number of bytes to send. |
| * |
| * @retval -EIO when no backend is registered or send hook is missing from |
| * backend. |
| * @retval -EINVAL when instance or endpoint is invalid. |
| * @retval -EBADMSG when the data is invalid (i.e. invalid data format, |
| * invalid length, ...) |
| * @retval -EBUSY when the instance is busy. |
| * |
| * @retval bytes number of bytes sent. |
| * @retval other errno codes depending on the implementation of the backend. |
| */ |
| int ipc_service_send_nocopy(struct ipc_ept *ept, const void *data, size_t len); |
| |
| /** @brief Holds the RX buffer for usage outside the receive callback. |
| * |
| * Calling this function prevents the receive buffer from being released |
| * back to the pool of shmem buffers. This function can be called in the |
| * receive callback when the user does not want to copy the message out in |
| * the callback itself. |
| * |
| * After the message is processed, the application must release the buffer |
| * using the @ref ipc_service_release_rx_buffer function. |
| * |
| * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint. |
| * @param[in] data Pointer to the RX buffer to release. |
| * |
| * @retval -EIO when no backend is registered or release hook is missing from |
| * backend. |
| * @retval -EINVAL when instance or endpoint is invalid. |
| * @retval -EALREADY when the buffer data has been hold already. |
| * @retval -ENOTSUP when this is not supported by backend. |
| * |
| * @retval 0 on success. |
| * @retval other errno codes depending on the implementation of the backend. |
| */ |
| int ipc_service_hold_rx_buffer(struct ipc_ept *ept, void *data); |
| |
| /** @brief Release the RX buffer for future reuse. |
| * |
| * When supported by the backend, this function can be called after the |
| * received message has been processed and the buffer can be marked as |
| * reusable again. |
| * |
| * It is possible to release only RX buffers on which @ref |
| * ipc_service_hold_rx_buffer was previously used. |
| * |
| * @param[in] ept Registered endpoint by @ref ipc_service_register_endpoint. |
| * @param[in] data Pointer to the RX buffer to release. |
| * |
| * @retval -EIO when no backend is registered or release hook is missing from |
| * backend. |
| * @retval -EINVAL when instance or endpoint is invalid. |
| * @retval -EALREADY when the buffer data has been already released. |
| * @retval -ENOTSUP when this is not supported by backend. |
| * @retval -ENXIO when the buffer was not hold before using @ref |
| * ipc_service_hold_rx_buffer |
| * |
| * @retval 0 on success. |
| * @retval other errno codes depending on the implementation of the backend. |
| */ |
| int ipc_service_release_rx_buffer(struct ipc_ept *ept, void *data); |
| |
| /** |
| * @} |
| */ |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |
| #endif /* ZEPHYR_INCLUDE_IPC_IPC_SERVICE_H_ */ |