/* * Copyright (c) 2022 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #ifndef ZEPHYR_INCLUDE_IPC_ICMSG_H_ #define ZEPHYR_INCLUDE_IPC_ICMSG_H_ #include #include #include #include #include #include #include #ifdef __cplusplus extern "C" { #endif /** * @brief Icmsg IPC library API * @defgroup ipc_icmsg_api Icmsg IPC library API * @ingroup ipc * @{ */ enum icmsg_state { ICMSG_STATE_OFF, ICMSG_STATE_BUSY, ICMSG_STATE_READY, }; struct icmsg_config_t { uintptr_t tx_shm_addr; uintptr_t rx_shm_addr; size_t tx_shm_size; size_t rx_shm_size; struct mbox_channel mbox_tx; struct mbox_channel mbox_rx; }; struct icmsg_data_t { /* Tx/Rx buffers. */ struct spsc_pbuf *tx_ib; struct spsc_pbuf *rx_ib; atomic_t tx_buffer_state; #ifdef CONFIG_IPC_SERVICE_ICMSG_SHMEM_ACCESS_SYNC struct k_mutex tx_lock; #endif /* Callbacks for an endpoint. */ const struct ipc_service_cb *cb; void *ctx; /* General */ const struct icmsg_config_t *cfg; struct k_work_delayable notify_work; struct k_work mbox_work; atomic_t state; /* No-copy */ #ifdef CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX atomic_t rx_buffer_state; const void *rx_buffer; uint16_t rx_len; #endif }; /** @brief Open an icmsg instance * * Open an icmsg instance to be able to send and receive messages to a remote * instance. * This function is blocking until the handshake with the remote instance is * completed. * This function is intended to be called late in the initialization process, * possibly from a thread which can be safely blocked while handshake with the * remote instance is being pefromed. * * @param[in] conf Structure containing configuration parameters for the icmsg * instance. * @param[inout] dev_data Structure containing run-time data used by the icmsg * instance. * @param[in] cb Structure containing callback functions to be called on * events generated by this icmsg instance. The pointed memory * must be preserved while the icmsg instance is active. * @param[in] ctx Pointer to context passed as an argument to callbacks. * * * @retval 0 on success. * @retval -EALREADY when the instance is already opened. * @retval other errno codes from dependent modules. */ int icmsg_open(const struct icmsg_config_t *conf, struct icmsg_data_t *dev_data, const struct ipc_service_cb *cb, void *ctx); /** @brief Close an icmsg instance * * Closing an icmsg instance results in releasing all resources used by given * instance including the shared memory regions and mbox devices. * * @param[in] conf Structure containing configuration parameters for the icmsg * instance being closed. Its content must be the same as used * for creating this instance with @ref icmsg_open. * @param[inout] dev_data Structure containing run-time data used by the icmsg * instance. * * @retval 0 on success. * @retval other errno codes from dependent modules. */ int icmsg_close(const struct icmsg_config_t *conf, struct icmsg_data_t *dev_data); /** @brief Send a message to the remote icmsg instance. * * @param[in] conf Structure containing configuration parameters for the icmsg * instance. * @param[inout] dev_data Structure containing run-time data used by the icmsg * instance. * @param[in] msg Pointer to a buffer containing data to send. * @param[in] len Size of data in the @p msg buffer. * * * @retval 0 on success. * @retval -EBUSY when the instance has not finished handshake with the remote * instance. * @retval -ENODATA when the requested data to send is empty. * @retval -EBADMSG when the requested data to send is too big. * @retval -ENOBUFS when there are no TX buffers available. * @retval other errno codes from dependent modules. */ int icmsg_send(const struct icmsg_config_t *conf, struct icmsg_data_t *dev_data, const void *msg, size_t len); /** @brief Get an empty TX buffer to be sent using @ref icmsg_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 avoiding copy * performed by the icmsg library. * * It is the application responsibility to correctly fill the allocated TX * buffer with data and passing correct parameters to @ref * icmsg_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 one of two conditions: (1) when sending the buffer * using @ref icmsg_send_nocopy (and in this case the buffer is automatically * released by the backend), (2) when using @ref icmsg_drop_tx_buffer on a * buffer not sent. * * @param[in] conf Structure containing configuration parameters for the icmsg * instance. * @param[inout] dev_data Structure containing run-time data used by the icmsg * instance. * @param[out] data Pointer to the empty TX buffer. * @param[inout] size Pointer to store the requested TX buffer size. If the * function returns -ENOMEM, this parameter returns the * maximum allowed size. * * @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. */ int icmsg_get_tx_buffer(const struct icmsg_config_t *conf, struct icmsg_data_t *dev_data, void **data, size_t *size); /** @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 icmsg_get_tx_buffer. * * @param[in] conf Structure containing configuration parameters for the icmsg * instance. * @param[inout] dev_data Structure containing run-time data used by the icmsg * instance. * @param[in] data Pointer to the TX buffer. * * @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. */ int icmsg_drop_tx_buffer(const struct icmsg_config_t *conf, struct icmsg_data_t *dev_data, const void *data); /** @brief Send a message from a buffer obtained by @ref icmsg_get_tx_buffer * to the remote icmsg instance. * * This is equivalent to @ref icmsg_send but in this case the TX buffer must * have been obtained by using @ref icmsg_get_tx_buffer. * * The API user has to take the responsibility for getting the TX buffer using * @ref icmsg_get_tx_buffer and filling the TX buffer with the data. * * After the @ref icmsg_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 icmsg_drop_tx_buffer can be used * to drop the TX buffer. * * @param[in] conf Structure containing configuration parameters for the icmsg * instance. * @param[inout] dev_data Structure containing run-time data used by the icmsg * instance. * @param[in] msg Pointer to a buffer containing data to send. * @param[in] len Size of data in the @p msg buffer. * * * @return Size of sent data on success. * @retval -EBUSY when the instance has not finished handshake with the remote * instance. * @retval -ENODATA when the requested data to send is empty. * @retval -EBADMSG when the requested data to send is too big. * @retval -ENXIO when the buffer was not obtained using @ref * ipc_service_get_tx_buffer * @retval other errno codes from dependent modules. */ int icmsg_send_nocopy(const struct icmsg_config_t *conf, struct icmsg_data_t *dev_data, const void *msg, size_t len); #ifdef CONFIG_IPC_SERVICE_ICMSG_NOCOPY_RX /** @brief Hold RX buffer to be used outside of the received callback. * * @param[in] conf Structure containing configuration parameters for the icmsg * instance. * @param[inout] dev_data Structure containing run-time data used by the icmsg * instance. * @param[in] data Pointer to the buffer to be held. * * @retval 0 on success. * @retval -EBUSY when the instance has not finished handshake with the remote * instance. * @retval -EINVAL when the @p data argument does not point to a valid RX * buffer. * @retval -EALREADY when the buffer is already held. */ int icmsg_hold_rx_buffer(const struct icmsg_config_t *conf, struct icmsg_data_t *dev_data, const void *data); /** @brief Release RX buffer for future use. * * @param[in] conf Structure containing configuration parameters for the icmsg * instance. * @param[inout] dev_data Structure containing run-time data used by the icmsg * instance. * @param[in] data Pointer to the buffer to be released. * * @retval 0 on success. * @retval -EBUSY when the instance has not finished handshake with the remote * instance. * @retval -EINVAL when the @p data argument does not point to a valid RX * buffer. * @retval -EALREADY when the buffer is not held. */ int icmsg_release_rx_buffer(const struct icmsg_config_t *conf, struct icmsg_data_t *dev_data, const void *data); #endif /** * @} */ #ifdef __cplusplus } #endif #endif /* ZEPHYR_INCLUDE_IPC_ICMSG_H_ */