ipc: multi-endpoint icmsg cleanup
The multi-endpoint backend of the ipc_service subsystem contains two roles with separated implementations: initiator and follower. There was many code duplications for both roles. This patch introduces a new IPC library: icmsg_me containing common code extracted from both roles and encapsulating access to common data fields. Signed-off-by: Hubert Miś <hubert.mis@nordicsemi.no>
This commit is contained in:
parent
37a5158dc4
commit
2c3863160d
9 changed files with 847 additions and 386 deletions
|
|
@ -4,6 +4,9 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_IPC_ICMSG_H_
|
||||
#define ZEPHYR_INCLUDE_IPC_ICMSG_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <zephyr/kernel.h>
|
||||
|
|
@ -12,6 +15,17 @@
|
|||
#include <zephyr/sys/atomic.h>
|
||||
#include <zephyr/sys/spsc_pbuf.h>
|
||||
|
||||
#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,
|
||||
|
|
@ -80,7 +94,7 @@ int icmsg_init(const struct icmsg_config_t *conf,
|
|||
* remote instance is being pefromed.
|
||||
*
|
||||
* @param[in] conf Structure containing configuration parameters for the icmsg
|
||||
* instance being created.
|
||||
* instance.
|
||||
* @param[inout] dev_data Structure containing run-time data used by the icmsg
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_init and its content must be preserved
|
||||
|
|
@ -121,7 +135,7 @@ int icmsg_close(const struct icmsg_config_t *conf,
|
|||
/** @brief Send a message to the remote icmsg instance.
|
||||
*
|
||||
* @param[in] conf Structure containing configuration parameters for the icmsg
|
||||
* instance being created.
|
||||
* instance.
|
||||
* @param[inout] dev_data Structure containing run-time data used by the icmsg
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_init and its content must be preserved
|
||||
|
|
@ -170,7 +184,7 @@ int icmsg_send(const struct icmsg_config_t *conf,
|
|||
* buffer not sent.
|
||||
*
|
||||
* @param[in] conf Structure containing configuration parameters for the icmsg
|
||||
* instance being created.
|
||||
* instance.
|
||||
* @param[inout] dev_data Structure containing run-time data used by the icmsg
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_init and its content must be preserved
|
||||
|
|
@ -197,7 +211,7 @@ int icmsg_get_tx_buffer(const struct icmsg_config_t *conf,
|
|||
* obtained by using @ref icmsg_get_tx_buffer.
|
||||
*
|
||||
* @param[in] conf Structure containing configuration parameters for the icmsg
|
||||
* instance being created.
|
||||
* instance.
|
||||
* @param[inout] dev_data Structure containing run-time data used by the icmsg
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_init and its content must be preserved
|
||||
|
|
@ -231,7 +245,7 @@ int icmsg_drop_tx_buffer(const struct icmsg_config_t *conf,
|
|||
* to drop the TX buffer.
|
||||
*
|
||||
* @param[in] conf Structure containing configuration parameters for the icmsg
|
||||
* instance being created.
|
||||
* instance.
|
||||
* @param[inout] dev_data Structure containing run-time data used by the icmsg
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_init and its content must be preserved
|
||||
|
|
@ -240,7 +254,7 @@ int icmsg_drop_tx_buffer(const struct icmsg_config_t *conf,
|
|||
* @param[in] len Size of data in the @p msg buffer.
|
||||
*
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @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.
|
||||
|
|
@ -257,7 +271,7 @@ int icmsg_send_nocopy(const struct icmsg_config_t *conf,
|
|||
/** @brief Hold RX buffer to be used outside of the received callback.
|
||||
*
|
||||
* @param[in] conf Structure containing configuration parameters for the icmsg
|
||||
* instance being created.
|
||||
* instance.
|
||||
* @param[inout] dev_data Structure containing run-time data used by the icmsg
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_init and its content must be preserved
|
||||
|
|
@ -278,7 +292,7 @@ int icmsg_hold_rx_buffer(const struct icmsg_config_t *conf,
|
|||
/** @brief Release RX buffer for future use.
|
||||
*
|
||||
* @param[in] conf Structure containing configuration parameters for the icmsg
|
||||
* instance being created.
|
||||
* instance.
|
||||
* @param[inout] dev_data Structure containing run-time data used by the icmsg
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_init and its content must be preserved
|
||||
|
|
@ -320,3 +334,13 @@ int icmsg_clear_tx_memory(const struct icmsg_config_t *conf);
|
|||
* @retval 0 on success.
|
||||
*/
|
||||
int icmsg_clear_rx_memory(const struct icmsg_config_t *conf);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_IPC_ICMSG_H_ */
|
||||
|
|
|
|||
370
include/zephyr/ipc/icmsg_me.h
Normal file
370
include/zephyr/ipc/icmsg_me.h
Normal file
|
|
@ -0,0 +1,370 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_IPC_ICMSG_ME_H_
|
||||
#define ZEPHYR_INCLUDE_IPC_ICMSG_ME_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/ipc/icmsg.h>
|
||||
#include <zephyr/ipc/ipc_service.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Multi-endpoint extension of icmsg IPC library
|
||||
* @defgroup ipc_icmsg_me_api Icmsg multi-endpoint IPC library API
|
||||
* @ingroup ipc
|
||||
* @{
|
||||
*/
|
||||
|
||||
|
||||
/* If more bytes than 1 was used for endpoint id, endianness should be
|
||||
* considered.
|
||||
*/
|
||||
typedef uint8_t icmsg_me_ept_id_t;
|
||||
|
||||
struct icmsg_me_data_t {
|
||||
struct icmsg_data_t icmsg_data;
|
||||
struct ipc_ept_cfg ept_cfg;
|
||||
|
||||
struct k_event event;
|
||||
|
||||
struct k_mutex send_mutex;
|
||||
const struct ipc_ept_cfg *epts[CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NUM_EP];
|
||||
|
||||
uint8_t send_buffer[CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_SEND_BUF_SIZE] __aligned(4);
|
||||
};
|
||||
|
||||
|
||||
/** @brief Initialize an icmsg_me instance
|
||||
*
|
||||
* This function is intended to be called during system initialization.
|
||||
* It initializes the underlying icmsg instace as one of the initialization
|
||||
* steps.
|
||||
*
|
||||
* @param[in] conf Structure containing configuration parameters for the
|
||||
* underlying icmsg instance being created.
|
||||
* @param[inout] data Structure containing run-time data used by the icmsg_me
|
||||
* instance. The structure shall be filled with zeros
|
||||
* when calling this function. The content of this
|
||||
* structure must be preserved while the icmsg_me instance
|
||||
* is active.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval other errno codes from dependent modules.
|
||||
*/
|
||||
int icmsg_me_init(const struct icmsg_config_t *conf,
|
||||
struct icmsg_me_data_t *data);
|
||||
|
||||
/** @brief Open an icmsg_me instance
|
||||
*
|
||||
* Open an icmsg_me 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
|
||||
* underlying icmsg instance.
|
||||
* @param[inout] data Structure containing run-time data used by the icmsg_me
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_me_init and its content must be preserved
|
||||
* while the icmsg_me instance is active.
|
||||
* @param[in] cb Structure containing callback functions to be called on
|
||||
* events generated by this icmsg_me instance. The pointed memory
|
||||
* must be preserved while the icmsg_me instance is active.
|
||||
* @param[in] ctx Pointer to context passed as an argument to callbacks.
|
||||
*
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval other errno codes from dependent modules.
|
||||
*/
|
||||
int icmsg_me_open(const struct icmsg_config_t *conf,
|
||||
struct icmsg_me_data_t *data,
|
||||
const struct ipc_service_cb *cb,
|
||||
void *ctx);
|
||||
|
||||
/** @brief Wait until the underlying icmsg instance calls bound callback
|
||||
*
|
||||
* This function blocks calling thread until the underlying icmsg connection
|
||||
* is bound. If the connection was bound before this function is called, the
|
||||
* function ends immediately without any delay.
|
||||
*
|
||||
* This function is intended to be used in the endpoints handshake procedure
|
||||
* to make sure that handshake is not performed until the icmsg channel is
|
||||
* ready to pass handshake messages.
|
||||
*
|
||||
* @param[inout] data Structure containing run-time data used by the icmsg_me
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_me_init and its content must be preserved
|
||||
* while the icmsg_me instance is active.
|
||||
*/
|
||||
void icmsg_me_wait_for_icmsg_bind(struct icmsg_me_data_t *data);
|
||||
|
||||
/** @brief Notify the icmsg_me instance that the underlying icmsg was bound
|
||||
*
|
||||
* The icmsg_me API users are responsible to implement the callback functions
|
||||
* called by the underlying icmsg instance. One of the actions of the bound
|
||||
* callback must be calling this function.
|
||||
*
|
||||
* @param[inout] data Structure containing run-time data used by the icmsg_me
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_me_init and its content must be preserved
|
||||
* while the icmsg_me instance is active.
|
||||
*/
|
||||
void icmsg_me_icmsg_bound(struct icmsg_me_data_t *data);
|
||||
|
||||
/** @brief Notify the icmsg_me instance that data for an endpoint was received
|
||||
*
|
||||
* The icmsg_me API users are responsible to implement the callback functions
|
||||
* called by the underlying icmsg instance. If the data received by the icmsg
|
||||
* instance contains data frame destined to one of the endpoints, this
|
||||
* function must be called.
|
||||
*
|
||||
* @param[inout] data Structure containing run-time data used by the icmsg_me
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_me_init and its content must be preserved
|
||||
* while the icmsg_me instance is active.
|
||||
* @param[in] id The value identifyig the endpoint.
|
||||
* @param[in] msg Data frame received from the peer, stripped of the
|
||||
* multi-endpoint header.
|
||||
* @param[in] len Size of the data pointed by @p msg.
|
||||
*/
|
||||
void icmsg_me_received_data(struct icmsg_me_data_t *data, icmsg_me_ept_id_t id,
|
||||
const void *msg, size_t len);
|
||||
|
||||
/** @brief Set endpoint configuration in an empty endpoint slot
|
||||
*
|
||||
* During endpoint handshake the handshake initiator must select an id number
|
||||
* and store endpoint metadata required to finalize handshake and maintain
|
||||
* the connection. This function is a helper which stores the configuration
|
||||
* in an empty configuration slot and provides the unique id value associated
|
||||
* with the selected slot.
|
||||
*
|
||||
* @note This function is not reentrant for a single icmsg_me instance.
|
||||
* It must be protected by the caller using mutex, critical section,
|
||||
* spinlock, or similar solution.
|
||||
* This function is reentrant for different icmsg_me instances. The
|
||||
* protection scope might be limited to a single instance.
|
||||
*
|
||||
* @param[inout] data Structure containing run-time data used by the icmsg_me
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_me_init and its content must be preserved
|
||||
* while the icmsg_me instance is active.
|
||||
* @param[in] ept_cfg Configuration data of the endpoint for which the
|
||||
* handshake procedure is being initiated.
|
||||
* @param[out] id The value uniquely identifyig this endpoint.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -ENOMEM when there are no more empty endpoint configuration slots.
|
||||
*/
|
||||
int icmsg_me_set_empty_ept_cfg_slot(struct icmsg_me_data_t *data,
|
||||
const struct ipc_ept_cfg *ept_cfg,
|
||||
icmsg_me_ept_id_t *id);
|
||||
|
||||
/** @brief Set endpoint configuration in a selected endpoint slot
|
||||
*
|
||||
* During endpoint handshake the handshake follower must store endpoint id and
|
||||
* metadata required to finalize handshake and maintain the connection. This
|
||||
* function is a helper which stores the configuration in a configuration slot
|
||||
* associated with the id of the endpoint.
|
||||
*
|
||||
* @param[inout] data Structure containing run-time data used by the icmsg_me
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_me_init and its content must be preserved
|
||||
* while the icmsg_me instance is active.
|
||||
* @param[in] id The value uniquely identifyig this endpoint.
|
||||
* @param[in] ept_cfg Configuration data of the endpoint for which the
|
||||
* handshake procedure is ongoing.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -ENOENT when @p id is out of range of available slots.
|
||||
*/
|
||||
int icmsg_me_set_ept_cfg(struct icmsg_me_data_t *data, icmsg_me_ept_id_t id,
|
||||
const struct ipc_ept_cfg *ept_cfg);
|
||||
|
||||
/** @brief Get endpoint configuration from a selected endpoint slot
|
||||
*
|
||||
* When the icmsg_me instance receives data from a remote endpoint, it must
|
||||
* get the endpoint configuration based on the id of the endpoint. This
|
||||
* function is designed for this purpose.
|
||||
*
|
||||
* If retrieved endpoint configuration is not set, @p ept_cfg points to NULL.
|
||||
*
|
||||
* @param[inout] data Structure containing run-time data used by the icmsg_me
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_me_init and its content must be preserved
|
||||
* while the icmsg_me instance is active.
|
||||
* @param[in] id The value uniquely identifyig endpoint.
|
||||
* @param[in] ept_cfg Configuration data of the endpoint with given id.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -ENOENT when @p id is out of range of available slots.
|
||||
*/
|
||||
int icmsg_me_get_ept_cfg(struct icmsg_me_data_t *data, icmsg_me_ept_id_t id,
|
||||
const struct ipc_ept_cfg **ept_cfg);
|
||||
|
||||
/** @brief Reset endpoint configuration in a selected endpoint slot.
|
||||
*
|
||||
* If handshake fails or an endpoint is disconnected, then configuration
|
||||
* slot for given endpoint should be vacated. This function is intended to
|
||||
* be used for this purpose.
|
||||
*
|
||||
* @param[inout] data Structure containing run-time data used by the icmsg_me
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_me_init and its content must be preserved
|
||||
* while the icmsg_me instance is active.
|
||||
* @param[in] id The value uniquely identifyig endpoint.
|
||||
*/
|
||||
void icmsg_me_reset_ept_cfg(struct icmsg_me_data_t *data, icmsg_me_ept_id_t id);
|
||||
|
||||
/** @brief Send a message to the remote icmsg_me endpoint.
|
||||
*
|
||||
* @param[in] conf Structure containing configuration parameters for the
|
||||
* underlying icmsg instance.
|
||||
* @param[inout] data Structure containing run-time data used by the icmsg_me
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_me_init and its content must be preserved
|
||||
* while the icmsg_me instance is active.
|
||||
* @param[in] id Id of the endpoint to use.
|
||||
* @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 -EBADMSG when the requested data to send is too big.
|
||||
* @retval other errno codes from dependent modules.
|
||||
*/
|
||||
int icmsg_me_send(const struct icmsg_config_t *conf,
|
||||
struct icmsg_me_data_t *data, icmsg_me_ept_id_t id,
|
||||
const void *msg, size_t len);
|
||||
|
||||
/** @brief Get an empty TX buffer to be sent using @ref icmsg_me_send_nocopy
|
||||
*
|
||||
* This function is a wrapper around @ref icmsg_get_tx_buffer aligning buffer
|
||||
* size and pointers to fit header required by the multi-endpoint feature.
|
||||
* It shares all properites and usage scenarios with @ref icmsg_get_tx_buffer.
|
||||
*
|
||||
* @param[in] conf Structure containing configuration parameters for the
|
||||
& underlying icmsg instance.
|
||||
* @param[inout] data Structure containing run-time data used by the icmsg_me
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_me_init and its content must be preserved
|
||||
* while the icmsg_me instance is active.
|
||||
* @param[out] buffer 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.
|
||||
* @param[in] wait Timeout value to wait for a free buffer acceptable by
|
||||
* the function caller. Only K_NO_WAIT is supported by icmsg.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval -ENOTSUP when requested unsupported @p wait timeout.
|
||||
* @retval -ENOBUFS when there are no TX buffers available.
|
||||
* @retval -ENOMEM when the requested size is too big (and the size parameter
|
||||
* contains the maximum allowed size).
|
||||
* @retval other errno codes from dependent modules.
|
||||
*/
|
||||
int icmsg_me_get_tx_buffer(const struct icmsg_config_t *conf,
|
||||
struct icmsg_me_data_t *data,
|
||||
void **buffer, uint32_t *size, k_timeout_t wait);
|
||||
|
||||
/** @brief Drop and release a TX buffer
|
||||
*
|
||||
* This function is a wrapper around @ref icmsg_drop_tx_buffer aligning buffer
|
||||
* pointer to fit header required by the multi-endpoint feature. This function
|
||||
* shares all properties and usage scenarios with @ref icmsg_drop_tx_buffer.
|
||||
*
|
||||
* @param[in] conf Structure containing configuration parameters for the
|
||||
* underlying icmsg instance.
|
||||
* @param[inout] data Structure containing run-time data used by the icmsg_me
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_me_init and its content must be preserved
|
||||
* while the icmsg_me instance is active.
|
||||
* @param[in] buffer Pointer to the TX buffer obtained with
|
||||
* @ref icmsg_me_get_tx_buffer.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval other errno codes from dependent modules.
|
||||
*/
|
||||
int icmsg_me_drop_tx_buffer(const struct icmsg_config_t *conf,
|
||||
struct icmsg_me_data_t *data,
|
||||
const void *buffer);
|
||||
|
||||
/** @brief Send a message from a buffer obtained by @ref icmsg_me_get_tx_buffer
|
||||
* to the remote icmsg_me instance.
|
||||
*
|
||||
* This function is a wrapper around @ref icmsg_send_nocopy aligning buffer
|
||||
* size and pointer to fit header required by the multi-endpoint feature. This
|
||||
* function shares all properties and usage scenarios with
|
||||
* @ref icmsg_send_nocopy.
|
||||
*
|
||||
* @param[in] conf Structure containing configuration parameters for the
|
||||
* underlying icmsg instance.
|
||||
* @param[inout] data Structure containing run-time data used by the icmsg_me
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_me_init and its content must be preserved
|
||||
* while the icmsg_me instance is active.
|
||||
* @param[in] id Id of the endpoint to use.
|
||||
* @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 other errno codes from dependent modules.
|
||||
*/
|
||||
int icmsg_me_send_nocopy(const struct icmsg_config_t *conf,
|
||||
struct icmsg_me_data_t *data, icmsg_me_ept_id_t id,
|
||||
const void *msg, size_t len);
|
||||
|
||||
#ifdef CONFIG_IPC_SERVICE_ICMSG_ME_NOCOPY_RX
|
||||
/** @brief Hold RX buffer to be used outside of the received callback.
|
||||
*
|
||||
* @param[in] conf Structure containing configuration parameters for the
|
||||
* underlying icmsg instance.
|
||||
* @param[inout] data Structure containing run-time data used by the icmsg_me
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_me_init and its content must be preserved
|
||||
* while the icmsg_me instance is active.
|
||||
* @param[in] buffer Pointer to the buffer to be held.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval other errno codes from dependent modules.
|
||||
*/
|
||||
int icmsg_me_hold_rx_buffer(const struct icmsg_config_t *conf,
|
||||
struct icmsg_me_data_t *data, void *buffer);
|
||||
|
||||
/** @brief Release RX buffer for future use.
|
||||
*
|
||||
* @param[in] conf Structure containing configuration parameters for the
|
||||
* underlying icmsg instance.
|
||||
* @param[inout] data Structure containing run-time data used by the icmsg_me
|
||||
* instance. The structure is initialized with
|
||||
* @ref icmsg_me_init and its content must be preserved
|
||||
* while the icmsg_me instance is active.
|
||||
* @param[in] buffer Pointer to the buffer to be released.
|
||||
*
|
||||
* @retval 0 on success.
|
||||
* @retval other errno codes from dependent modules.
|
||||
*/
|
||||
int icmsg_me_release_rx_buffer(const struct icmsg_config_t *conf,
|
||||
struct icmsg_me_data_t *data, void *buffer);
|
||||
#endif /* CONFIG_IPC_SERVICE_ICMSG_ME_NOCOPY_RX */
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_IPC_ICMSG_ME_H_ */
|
||||
|
|
@ -31,8 +31,7 @@ config IPC_SERVICE_BACKEND_ICMSG_ME_INITIATOR
|
|||
default y
|
||||
depends on MBOX
|
||||
depends on DT_HAS_ZEPHYR_IPC_ICMSG_ME_INITIATOR_ENABLED
|
||||
select IPC_SERVICE_ICMSG
|
||||
select EVENTS
|
||||
select IPC_SERVICE_ICMSG_ME
|
||||
help
|
||||
Chosing this backend results in multi endpoint implementation based
|
||||
on circular packet buffer. This enables enpoint discovery initiator
|
||||
|
|
@ -43,8 +42,7 @@ config IPC_SERVICE_BACKEND_ICMSG_ME_FOLLOWER
|
|||
default y
|
||||
depends on MBOX
|
||||
depends on DT_HAS_ZEPHYR_IPC_ICMSG_ME_FOLLOWER_ENABLED
|
||||
select IPC_SERVICE_ICMSG
|
||||
select EVENTS
|
||||
select IPC_SERVICE_ICMSG_ME
|
||||
help
|
||||
Chosing this backend results in multi endpoint implementation based
|
||||
on circular packet buffer. This enables enpoint discovery follower
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ config IPC_SERVICE_BACKEND_ICMSG_ME_SHMEM_RESET
|
|||
|
||||
config IPC_SERVICE_BACKEND_ICMSG_ME_NOCOPY_RX
|
||||
bool "Nocopy feature for receive path"
|
||||
select IPC_SERVICE_ICMSG_NOCOPY_RX
|
||||
select IPC_SERVICE_ICMSG_ME_NOCOPY_RX
|
||||
help
|
||||
Enable nocopy feature for receive path of multiendpoint icmsg
|
||||
ipc_service backend. This features enables functions to hold and
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/ipc/icmsg.h>
|
||||
#include <zephyr/ipc/icmsg_me.h>
|
||||
#include <zephyr/ipc/ipc_service_backend.h>
|
||||
|
||||
#define DT_DRV_COMPAT zephyr_ipc_icmsg_me_follower
|
||||
|
|
@ -19,30 +20,17 @@
|
|||
|
||||
#define EVENT_BOUND 0x01
|
||||
|
||||
/* If more bytes than 1 was used for endpoint id, endianness should be
|
||||
* considered.
|
||||
*/
|
||||
typedef uint8_t ept_id_t;
|
||||
|
||||
struct ept_disc_rmt_cache_t {
|
||||
ept_id_t id;
|
||||
icmsg_me_ept_id_t id;
|
||||
char name[EP_NAME_LEN];
|
||||
};
|
||||
|
||||
struct backend_data_t {
|
||||
struct icmsg_data_t icmsg_data;
|
||||
struct ipc_ept_cfg ept_cfg;
|
||||
|
||||
struct k_event event;
|
||||
|
||||
struct k_mutex epts_mutex;
|
||||
struct k_mutex send_mutex;
|
||||
const struct ipc_ept_cfg *epts[NUM_EP];
|
||||
struct icmsg_me_data_t icmsg_me_data;
|
||||
|
||||
struct k_mutex cache_mutex;
|
||||
const struct ipc_ept_cfg *ept_disc_loc_cache[NUM_EP];
|
||||
struct ept_disc_rmt_cache_t ept_disc_rmt_cache[NUM_EP];
|
||||
|
||||
uint8_t send_buffer[SEND_BUF_SIZE] __aligned(4);
|
||||
};
|
||||
|
||||
static const struct ipc_ept_cfg *get_ept_cached_loc(
|
||||
|
|
@ -90,7 +78,7 @@ static int cache_ept_loc(struct backend_data_t *data, const struct ipc_ept_cfg *
|
|||
}
|
||||
|
||||
static int cache_ept_rmt(struct backend_data_t *data, const char *name,
|
||||
size_t len, ept_id_t id)
|
||||
size_t len, icmsg_me_ept_id_t id)
|
||||
{
|
||||
for (int i = 0; i < NUM_EP; i++) {
|
||||
if (!strlen(data->ept_disc_rmt_cache[i].name)) {
|
||||
|
|
@ -107,48 +95,25 @@ static int cache_ept_rmt(struct backend_data_t *data, const char *name,
|
|||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static void *icmsg_buffer_to_user_buffer(const void *icmsg_buffer)
|
||||
{
|
||||
return (void *)(((char *)icmsg_buffer) + sizeof(ept_id_t));
|
||||
}
|
||||
|
||||
static void *user_buffer_to_icmsg_buffer(const void *user_buffer)
|
||||
{
|
||||
return (void *)(((char *)user_buffer) - sizeof(ept_id_t));
|
||||
}
|
||||
|
||||
static size_t icmsg_buffer_len_to_user_buffer_len(size_t icmsg_buffer_len)
|
||||
{
|
||||
return icmsg_buffer_len - sizeof(ept_id_t);
|
||||
}
|
||||
|
||||
static size_t user_buffer_len_to_icmsg_buffer_len(size_t user_buffer_len)
|
||||
{
|
||||
return user_buffer_len + sizeof(ept_id_t);
|
||||
}
|
||||
|
||||
static void set_ept_id_in_send_buffer(uint8_t *send_buffer, ept_id_t ept_id)
|
||||
{
|
||||
send_buffer[0] = ept_id;
|
||||
}
|
||||
|
||||
static int bind_ept(const struct icmsg_config_t *conf,
|
||||
struct backend_data_t *data, const struct ipc_ept_cfg *ept,
|
||||
ept_id_t id)
|
||||
icmsg_me_ept_id_t id)
|
||||
{
|
||||
__ASSERT_NO_MSG(id <= NUM_EP);
|
||||
|
||||
int r;
|
||||
int i = id - 1;
|
||||
const uint8_t confirmation[] = {
|
||||
0, /* EP discovery endpoint id */
|
||||
id, /* Bound endpoint id */
|
||||
};
|
||||
|
||||
data->epts[i] = ept;
|
||||
r = icmsg_me_set_ept_cfg(&data->icmsg_me_data, id, ept);
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
k_event_wait(&data->event, EVENT_BOUND, false, K_FOREVER);
|
||||
r = icmsg_send(conf, &data->icmsg_data, confirmation,
|
||||
icmsg_me_wait_for_icmsg_bind(&data->icmsg_me_data);
|
||||
r = icmsg_send(conf, &data->icmsg_me_data.icmsg_data, confirmation,
|
||||
sizeof(confirmation));
|
||||
if (r < 0) {
|
||||
return r;
|
||||
|
|
@ -166,7 +131,7 @@ static void bound(void *priv)
|
|||
const struct device *instance = priv;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
|
||||
k_event_post(&dev_data->event, EVENT_BOUND);
|
||||
icmsg_me_icmsg_bound(&dev_data->icmsg_me_data);
|
||||
}
|
||||
|
||||
static void received(const void *data, size_t len, void *priv)
|
||||
|
|
@ -175,7 +140,7 @@ static void received(const void *data, size_t len, void *priv)
|
|||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
|
||||
const ept_id_t *id = data;
|
||||
const icmsg_me_ept_id_t *id = data;
|
||||
|
||||
__ASSERT_NO_MSG(len > 0);
|
||||
|
||||
|
|
@ -183,11 +148,11 @@ static void received(const void *data, size_t len, void *priv)
|
|||
__ASSERT_NO_MSG(len > 1);
|
||||
|
||||
id++;
|
||||
ept_id_t ept_id = *id;
|
||||
icmsg_me_ept_id_t ept_id = *id;
|
||||
const char *name = id + 1;
|
||||
size_t name_len = len - 2 * sizeof(ept_id_t);
|
||||
size_t name_len = len - 2 * sizeof(icmsg_me_ept_id_t);
|
||||
|
||||
k_mutex_lock(&dev_data->epts_mutex, K_FOREVER);
|
||||
k_mutex_lock(&dev_data->cache_mutex, K_FOREVER);
|
||||
|
||||
const struct ipc_ept_cfg *ept =
|
||||
get_ept_cached_loc(dev_data, name, name_len);
|
||||
|
|
@ -210,22 +175,10 @@ static void received(const void *data, size_t len, void *priv)
|
|||
bind_ept(conf, dev_data, ept, ept_id);
|
||||
}
|
||||
|
||||
k_mutex_unlock(&dev_data->epts_mutex);
|
||||
k_mutex_unlock(&dev_data->cache_mutex);
|
||||
} else {
|
||||
int i = *id - 1;
|
||||
|
||||
if (i >= NUM_EP) {
|
||||
return;
|
||||
}
|
||||
if (dev_data->epts[i] == NULL) {
|
||||
return;
|
||||
}
|
||||
if (dev_data->epts[i]->cb.received) {
|
||||
dev_data->epts[i]->cb.received(
|
||||
icmsg_buffer_to_user_buffer(data),
|
||||
icmsg_buffer_len_to_user_buffer_len(len),
|
||||
dev_data->epts[i]->priv);
|
||||
}
|
||||
icmsg_me_received_data(&dev_data->icmsg_me_data, *id,
|
||||
data, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -240,11 +193,8 @@ static int open(const struct device *instance)
|
|||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
|
||||
dev_data->ept_cfg.cb = cb;
|
||||
dev_data->ept_cfg.priv = (void *)instance;
|
||||
|
||||
return icmsg_open(conf, &dev_data->icmsg_data, &dev_data->ept_cfg.cb,
|
||||
dev_data->ept_cfg.priv);
|
||||
return icmsg_me_open(conf, &dev_data->icmsg_me_data, &cb,
|
||||
(void *)instance);
|
||||
}
|
||||
|
||||
static int register_ept(const struct device *instance, void **token,
|
||||
|
|
@ -255,7 +205,7 @@ static int register_ept(const struct device *instance, void **token,
|
|||
struct ept_disc_rmt_cache_t *rmt_cache_entry;
|
||||
int r;
|
||||
|
||||
k_mutex_lock(&data->epts_mutex, K_FOREVER);
|
||||
k_mutex_lock(&data->cache_mutex, K_FOREVER);
|
||||
|
||||
rmt_cache_entry = get_ept_cached_rmt(data, cfg->name,
|
||||
strlen(cfg->name));
|
||||
|
|
@ -279,7 +229,7 @@ static int register_ept(const struct device *instance, void **token,
|
|||
__ASSERT_NO_MSG(rmt_cache_entry != NULL);
|
||||
*token = &rmt_cache_entry->id;
|
||||
} else {
|
||||
ept_id_t ept_id = rmt_cache_entry->id;
|
||||
icmsg_me_ept_id_t ept_id = rmt_cache_entry->id;
|
||||
|
||||
if (ept_id == INVALID_EPT_ID) {
|
||||
r = -EAGAIN;
|
||||
|
|
@ -291,7 +241,7 @@ static int register_ept(const struct device *instance, void **token,
|
|||
}
|
||||
|
||||
exit:
|
||||
k_mutex_unlock(&data->epts_mutex);
|
||||
k_mutex_unlock(&data->cache_mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
@ -300,50 +250,14 @@ static int send(const struct device *instance, void *token,
|
|||
{
|
||||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
ept_id_t *id = token;
|
||||
int r;
|
||||
int sent_bytes;
|
||||
icmsg_me_ept_id_t *id = token;
|
||||
|
||||
if (*id == INVALID_EPT_ID) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
if (user_len >= SEND_BUF_SIZE - sizeof(ept_id_t)) {
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
k_mutex_lock(&dev_data->send_mutex, K_FOREVER);
|
||||
|
||||
/* TODO: Optimization: How to avoid this copying? */
|
||||
/* Scatter list supported by icmsg? */
|
||||
set_ept_id_in_send_buffer(dev_data->send_buffer, *id);
|
||||
memcpy(icmsg_buffer_to_user_buffer(dev_data->send_buffer), msg,
|
||||
user_len);
|
||||
|
||||
r = icmsg_send(conf, &dev_data->icmsg_data, dev_data->send_buffer,
|
||||
user_buffer_len_to_icmsg_buffer_len(user_len));
|
||||
|
||||
if (r > 0) {
|
||||
sent_bytes = r - 1;
|
||||
}
|
||||
|
||||
k_mutex_unlock(&dev_data->send_mutex);
|
||||
|
||||
if (r > 0) {
|
||||
return sent_bytes;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t get_buffer_length_to_pass(size_t allocated_buffer_length)
|
||||
{
|
||||
if (allocated_buffer_length >= sizeof(ept_id_t)) {
|
||||
return icmsg_buffer_len_to_user_buffer_len(
|
||||
allocated_buffer_length);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return icmsg_me_send(conf, &dev_data->icmsg_me_data, *id, msg,
|
||||
user_len);
|
||||
}
|
||||
|
||||
static int get_tx_buffer(const struct device *instance, void *token,
|
||||
|
|
@ -351,46 +265,9 @@ static int get_tx_buffer(const struct device *instance, void *token,
|
|||
{
|
||||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
void *icmsg_buffer;
|
||||
int r;
|
||||
size_t icmsg_len;
|
||||
|
||||
if (!K_TIMEOUT_EQ(wait, K_NO_WAIT)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (*user_len) {
|
||||
icmsg_len = user_buffer_len_to_icmsg_buffer_len(*user_len);
|
||||
} else {
|
||||
icmsg_len = 0;
|
||||
}
|
||||
|
||||
r = icmsg_get_tx_buffer(conf, &dev_data->icmsg_data, &icmsg_buffer,
|
||||
&icmsg_len);
|
||||
if (r == -ENOMEM) {
|
||||
*user_len = get_buffer_length_to_pass(icmsg_len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
*user_len = get_buffer_length_to_pass(icmsg_len);
|
||||
/* If requested max buffer length (*user_len == 0) allocated buffer
|
||||
* might be shorter than sizeof(ept_id_t). In such circumstances drop
|
||||
* the buffer and return error.
|
||||
*/
|
||||
|
||||
if (*user_len) {
|
||||
*data = icmsg_buffer_to_user_buffer(icmsg_buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = icmsg_drop_tx_buffer(conf, &dev_data->icmsg_data,
|
||||
icmsg_buffer);
|
||||
__ASSERT_NO_MSG(!r);
|
||||
return -ENOBUFS;
|
||||
return icmsg_me_get_tx_buffer(conf, &dev_data->icmsg_me_data, data,
|
||||
user_len, wait);
|
||||
}
|
||||
|
||||
static int drop_tx_buffer(const struct device *instance, void *token,
|
||||
|
|
@ -398,9 +275,8 @@ static int drop_tx_buffer(const struct device *instance, void *token,
|
|||
{
|
||||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
const void *buffer_to_drop = user_buffer_to_icmsg_buffer(data);
|
||||
|
||||
return icmsg_drop_tx_buffer(conf, &dev_data->icmsg_data, buffer_to_drop);
|
||||
return icmsg_me_drop_tx_buffer(conf, &dev_data->icmsg_me_data, data);
|
||||
}
|
||||
|
||||
static int send_nocopy(const struct device *instance, void *token,
|
||||
|
|
@ -408,27 +284,14 @@ static int send_nocopy(const struct device *instance, void *token,
|
|||
{
|
||||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
ept_id_t *id = token;
|
||||
void *buffer_to_send;
|
||||
size_t len_to_send;
|
||||
int r;
|
||||
icmsg_me_ept_id_t *id = token;
|
||||
|
||||
if (*id == INVALID_EPT_ID) {
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
buffer_to_send = user_buffer_to_icmsg_buffer(data);
|
||||
len_to_send = user_buffer_len_to_icmsg_buffer_len(len);
|
||||
|
||||
set_ept_id_in_send_buffer(buffer_to_send, *id);
|
||||
|
||||
r = icmsg_send_nocopy(conf, &dev_data->icmsg_data, buffer_to_send,
|
||||
len_to_send);
|
||||
if (r > 0) {
|
||||
return icmsg_buffer_len_to_user_buffer_len(r);
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
return icmsg_me_send_nocopy(conf, &dev_data->icmsg_me_data, *id,
|
||||
data, len);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NOCOPY_RX
|
||||
|
|
@ -436,19 +299,16 @@ int hold_rx_buffer(const struct device *instance, void *token, void *data)
|
|||
{
|
||||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
void *icmsg_buffer = user_buffer_to_icmsg_buffer(data);
|
||||
|
||||
return icmsg_hold_rx_buffer(conf, &dev_data->icmsg_data, icmsg_buffer);
|
||||
return icmsg_me_hold_rx_buffer(conf, &dev_data->icmsg_me_data, data);
|
||||
}
|
||||
|
||||
int release_rx_buffer(const struct device *instance, void *token, void *data)
|
||||
{
|
||||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
void *icmsg_buffer = user_buffer_to_icmsg_buffer(data);
|
||||
|
||||
return icmsg_release_rx_buffer(conf, &dev_data->icmsg_data,
|
||||
icmsg_buffer);
|
||||
return icmsg_me_release_rx_buffer(conf, &dev_data->icmsg_me_data, data);
|
||||
}
|
||||
#endif /* CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NOCOPY_RX */
|
||||
|
||||
|
|
@ -472,11 +332,9 @@ static int backend_init(const struct device *instance)
|
|||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
|
||||
k_event_init(&dev_data->event);
|
||||
k_mutex_init(&dev_data->epts_mutex);
|
||||
k_mutex_init(&dev_data->send_mutex);
|
||||
k_mutex_init(&dev_data->cache_mutex);
|
||||
|
||||
return icmsg_init(conf, &dev_data->icmsg_data);
|
||||
return icmsg_me_init(conf, &dev_data->icmsg_me_data);
|
||||
}
|
||||
|
||||
#define BACKEND_CONFIG_POPULATE(i) \
|
||||
|
|
|
|||
|
|
@ -8,33 +8,19 @@
|
|||
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/ipc/icmsg.h>
|
||||
#include <zephyr/ipc/icmsg_me.h>
|
||||
#include <zephyr/ipc/ipc_service_backend.h>
|
||||
|
||||
#define DT_DRV_COMPAT zephyr_ipc_icmsg_me_initiator
|
||||
|
||||
#define SEND_BUF_SIZE CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_SEND_BUF_SIZE
|
||||
#define NUM_EP CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NUM_EP
|
||||
#define EP_NAME_LEN CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_EP_NAME_LEN
|
||||
|
||||
#define EVENT_BOUND 0x01
|
||||
|
||||
/* If more bytes than 1 was used for endpoint id, endianness should be
|
||||
* considered.
|
||||
*/
|
||||
typedef uint8_t ept_id_t;
|
||||
|
||||
struct backend_data_t {
|
||||
struct icmsg_data_t icmsg_data;
|
||||
struct ipc_ept_cfg ept_cfg;
|
||||
|
||||
struct k_event event;
|
||||
struct icmsg_me_data_t icmsg_me_data;
|
||||
|
||||
struct k_mutex epts_mutex;
|
||||
struct k_mutex send_mutex;
|
||||
const struct ipc_ept_cfg *epts[NUM_EP];
|
||||
ept_id_t ids[NUM_EP];
|
||||
|
||||
uint8_t send_buffer[SEND_BUF_SIZE] __aligned(4);
|
||||
icmsg_me_ept_id_t ids[NUM_EP];
|
||||
};
|
||||
|
||||
static void bound(void *priv)
|
||||
|
|
@ -42,32 +28,7 @@ static void bound(void *priv)
|
|||
const struct device *instance = priv;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
|
||||
k_event_post(&dev_data->event, EVENT_BOUND);
|
||||
}
|
||||
|
||||
static void *icmsg_buffer_to_user_buffer(const void *icmsg_buffer)
|
||||
{
|
||||
return (void *)(((char *)icmsg_buffer) + sizeof(ept_id_t));
|
||||
}
|
||||
|
||||
static void *user_buffer_to_icmsg_buffer(const void *user_buffer)
|
||||
{
|
||||
return (void *)(((char *)user_buffer) - sizeof(ept_id_t));
|
||||
}
|
||||
|
||||
static size_t icmsg_buffer_len_to_user_buffer_len(size_t icmsg_buffer_len)
|
||||
{
|
||||
return icmsg_buffer_len - sizeof(ept_id_t);
|
||||
}
|
||||
|
||||
static size_t user_buffer_len_to_icmsg_buffer_len(size_t user_buffer_len)
|
||||
{
|
||||
return user_buffer_len + sizeof(ept_id_t);
|
||||
}
|
||||
|
||||
static void set_ept_id_in_send_buffer(uint8_t *send_buffer, ept_id_t ept_id)
|
||||
{
|
||||
send_buffer[0] = ept_id;
|
||||
icmsg_me_icmsg_bound(&dev_data->icmsg_me_data);
|
||||
}
|
||||
|
||||
static void received(const void *data, size_t len, void *priv)
|
||||
|
|
@ -75,42 +36,31 @@ static void received(const void *data, size_t len, void *priv)
|
|||
const struct device *instance = priv;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
|
||||
const ept_id_t *id = data;
|
||||
const icmsg_me_ept_id_t *id = data;
|
||||
|
||||
__ASSERT_NO_MSG(len > 0);
|
||||
|
||||
if (*id == 0) {
|
||||
const struct ipc_ept_cfg *ept;
|
||||
int r;
|
||||
|
||||
__ASSERT_NO_MSG(len > 1);
|
||||
|
||||
id++;
|
||||
ept_id_t ept_id = *id;
|
||||
icmsg_me_ept_id_t ept_id = *id;
|
||||
|
||||
int i = ept_id - 1;
|
||||
|
||||
if (ept_id > NUM_EP) {
|
||||
r = icmsg_me_get_ept_cfg(&dev_data->icmsg_me_data, ept_id,
|
||||
&ept);
|
||||
if (r < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const struct ipc_ept_cfg *ept = dev_data->epts[i];
|
||||
|
||||
if (ept->cb.bound) {
|
||||
if (ept && ept->cb.bound) {
|
||||
ept->cb.bound(ept->priv);
|
||||
}
|
||||
} else {
|
||||
int i = *id - 1;
|
||||
|
||||
if (i >= NUM_EP) {
|
||||
return;
|
||||
}
|
||||
if (dev_data->epts[i] == NULL) {
|
||||
return;
|
||||
}
|
||||
if (dev_data->epts[i]->cb.received) {
|
||||
dev_data->epts[i]->cb.received(
|
||||
icmsg_buffer_to_user_buffer(data),
|
||||
icmsg_buffer_len_to_user_buffer_len(len),
|
||||
dev_data->epts[i]->priv);
|
||||
}
|
||||
icmsg_me_received_data(&dev_data->icmsg_me_data, *id,
|
||||
data, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -125,11 +75,29 @@ static int open(const struct device *instance)
|
|||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
|
||||
dev_data->ept_cfg.cb = cb;
|
||||
dev_data->ept_cfg.priv = (void *)instance;
|
||||
return icmsg_me_open(conf, &dev_data->icmsg_me_data, &cb,
|
||||
(void *)instance);
|
||||
}
|
||||
|
||||
return icmsg_open(conf, &dev_data->icmsg_data, &dev_data->ept_cfg.cb,
|
||||
dev_data->ept_cfg.priv);
|
||||
static int store_id_for_token(struct backend_data_t *data, icmsg_me_ept_id_t id,
|
||||
void **token)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_EP; i++) {
|
||||
if (data->ids[i] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
__ASSERT_NO_MSG(i < NUM_EP);
|
||||
if (i >= NUM_EP) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
data->ids[i] = id;
|
||||
*token = &data->ids[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int register_ept(const struct device *instance, void **token,
|
||||
|
|
@ -138,8 +106,7 @@ static int register_ept(const struct device *instance, void **token,
|
|||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *data = instance->data;
|
||||
int r = 0;
|
||||
int i;
|
||||
ept_id_t id;
|
||||
icmsg_me_ept_id_t id;
|
||||
size_t name_len = strlen(cfg->name);
|
||||
|
||||
if (name_len > EP_NAME_LEN) {
|
||||
|
|
@ -148,40 +115,42 @@ static int register_ept(const struct device *instance, void **token,
|
|||
|
||||
k_mutex_lock(&data->epts_mutex, K_FOREVER);
|
||||
|
||||
for (i = 0; i < NUM_EP; i++) {
|
||||
if (data->epts[i] == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= NUM_EP) {
|
||||
r = -ENOMEM;
|
||||
r = icmsg_me_set_empty_ept_cfg_slot(&data->icmsg_me_data, cfg, &id);
|
||||
if (r < 0) {
|
||||
goto exit;
|
||||
}
|
||||
__ASSERT_NO_MSG(id > 0);
|
||||
if (id <= 0) {
|
||||
r = -ENOENT;
|
||||
goto reset_slot;
|
||||
}
|
||||
|
||||
id = i + 1;
|
||||
r = store_id_for_token(data, id, token);
|
||||
if (r < 0) {
|
||||
goto reset_slot;
|
||||
}
|
||||
|
||||
uint8_t ep_disc_req[EP_NAME_LEN + 2 * sizeof(ept_id_t)] = {
|
||||
uint8_t ep_disc_req[EP_NAME_LEN + 2 * sizeof(icmsg_me_ept_id_t)] = {
|
||||
0, /* EP discovery endpoint id */
|
||||
id, /* Bound endpoint id */
|
||||
};
|
||||
memcpy(&ep_disc_req[2], cfg->name, name_len);
|
||||
|
||||
data->epts[i] = cfg;
|
||||
data->ids[i] = id;
|
||||
*token = &data->ids[i];
|
||||
icmsg_me_wait_for_icmsg_bind(&data->icmsg_me_data);
|
||||
|
||||
k_event_wait(&data->event, EVENT_BOUND, false, K_FOREVER);
|
||||
|
||||
r = icmsg_send(conf, &data->icmsg_data, ep_disc_req,
|
||||
2 * sizeof(ept_id_t) + name_len);
|
||||
r = icmsg_send(conf, &data->icmsg_me_data.icmsg_data, ep_disc_req,
|
||||
2 * sizeof(icmsg_me_ept_id_t) + name_len);
|
||||
if (r < 0) {
|
||||
data->epts[i] = NULL;
|
||||
goto exit;
|
||||
goto reset_slot;
|
||||
} else {
|
||||
r = 0;
|
||||
}
|
||||
|
||||
reset_slot:
|
||||
if (r < 0) {
|
||||
icmsg_me_reset_ept_cfg(&data->icmsg_me_data, id);
|
||||
}
|
||||
|
||||
exit:
|
||||
k_mutex_unlock(&data->epts_mutex);
|
||||
return r;
|
||||
|
|
@ -192,45 +161,9 @@ static int send(const struct device *instance, void *token,
|
|||
{
|
||||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
ept_id_t *id = token;
|
||||
int r;
|
||||
int sent_bytes;
|
||||
icmsg_me_ept_id_t *id = token;
|
||||
|
||||
if (len >= SEND_BUF_SIZE - sizeof(ept_id_t)) {
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
k_mutex_lock(&dev_data->send_mutex, K_FOREVER);
|
||||
|
||||
/* TODO: Optimization: How to avoid this copying? */
|
||||
/* We could implement scatter list for icmsg_send, but it would require
|
||||
* scatter list also for SPSC buffer implementation.
|
||||
*/
|
||||
set_ept_id_in_send_buffer(dev_data->send_buffer, *id);
|
||||
memcpy(icmsg_buffer_to_user_buffer(dev_data->send_buffer), msg, len);
|
||||
|
||||
r = icmsg_send(conf, &dev_data->icmsg_data, dev_data->send_buffer,
|
||||
user_buffer_len_to_icmsg_buffer_len(len));
|
||||
if (r > 0) {
|
||||
sent_bytes = icmsg_buffer_len_to_user_buffer_len(r);
|
||||
}
|
||||
|
||||
k_mutex_unlock(&dev_data->send_mutex);
|
||||
|
||||
if (r > 0) {
|
||||
return sent_bytes;
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t get_buffer_length_to_pass(size_t icmsg_buffer_len)
|
||||
{
|
||||
if (icmsg_buffer_len >= sizeof(ept_id_t)) {
|
||||
return icmsg_buffer_len_to_user_buffer_len(icmsg_buffer_len);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
return icmsg_me_send(conf, &dev_data->icmsg_me_data, *id, msg, len);
|
||||
}
|
||||
|
||||
static int get_tx_buffer(const struct device *instance, void *token,
|
||||
|
|
@ -238,46 +171,9 @@ static int get_tx_buffer(const struct device *instance, void *token,
|
|||
{
|
||||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
void *icmsg_buffer;
|
||||
int r;
|
||||
size_t icmsg_len;
|
||||
|
||||
if (!K_TIMEOUT_EQ(wait, K_NO_WAIT)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (*user_len) {
|
||||
icmsg_len = user_buffer_len_to_icmsg_buffer_len(*user_len);
|
||||
} else {
|
||||
icmsg_len = 0;
|
||||
}
|
||||
|
||||
r = icmsg_get_tx_buffer(conf, &dev_data->icmsg_data, &icmsg_buffer,
|
||||
&icmsg_len);
|
||||
if (r == -ENOMEM) {
|
||||
*user_len = get_buffer_length_to_pass(icmsg_len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
*user_len = get_buffer_length_to_pass(icmsg_len);
|
||||
/* If requested max buffer length (*len == 0) allocated buffer might be
|
||||
* shorter than sizeof(ept_id_t). In such circumstances drop the buffer
|
||||
* and return error.
|
||||
*/
|
||||
|
||||
if (*user_len) {
|
||||
*data = icmsg_buffer_to_user_buffer(icmsg_buffer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = icmsg_drop_tx_buffer(conf, &dev_data->icmsg_data,
|
||||
icmsg_buffer);
|
||||
__ASSERT_NO_MSG(!r);
|
||||
return -ENOBUFS;
|
||||
return icmsg_me_get_tx_buffer(conf, &dev_data->icmsg_me_data, data,
|
||||
user_len, wait);
|
||||
}
|
||||
|
||||
static int drop_tx_buffer(const struct device *instance, void *token,
|
||||
|
|
@ -285,9 +181,8 @@ static int drop_tx_buffer(const struct device *instance, void *token,
|
|||
{
|
||||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
const void *buffer_to_drop = user_buffer_to_icmsg_buffer(data);
|
||||
|
||||
return icmsg_drop_tx_buffer(conf, &dev_data->icmsg_data, buffer_to_drop);
|
||||
return icmsg_me_drop_tx_buffer(conf, &dev_data->icmsg_me_data, data);
|
||||
}
|
||||
|
||||
static int send_nocopy(const struct device *instance, void *token,
|
||||
|
|
@ -295,23 +190,10 @@ static int send_nocopy(const struct device *instance, void *token,
|
|||
{
|
||||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
ept_id_t *id = token;
|
||||
void *buffer_to_send;
|
||||
size_t len_to_send;
|
||||
int r;
|
||||
icmsg_me_ept_id_t *id = token;
|
||||
|
||||
buffer_to_send = user_buffer_to_icmsg_buffer(data);
|
||||
len_to_send = user_buffer_len_to_icmsg_buffer_len(len);
|
||||
|
||||
set_ept_id_in_send_buffer(buffer_to_send, *id);
|
||||
|
||||
r = icmsg_send_nocopy(conf, &dev_data->icmsg_data, buffer_to_send,
|
||||
len_to_send);
|
||||
if (r > 0) {
|
||||
return icmsg_buffer_len_to_user_buffer_len(r);
|
||||
} else {
|
||||
return r;
|
||||
}
|
||||
return icmsg_me_send_nocopy(conf, &dev_data->icmsg_me_data, *id,
|
||||
data, len);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NOCOPY_RX
|
||||
|
|
@ -319,19 +201,16 @@ int hold_rx_buffer(const struct device *instance, void *token, void *data)
|
|||
{
|
||||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
void *icmsg_buffer = user_buffer_to_icmsg_buffer(data);
|
||||
|
||||
return icmsg_hold_rx_buffer(conf, &dev_data->icmsg_data, icmsg_buffer);
|
||||
return icmsg_me_hold_rx_buffer(conf, &dev_data->icmsg_me_data, data);
|
||||
}
|
||||
|
||||
int release_rx_buffer(const struct device *instance, void *token, void *data)
|
||||
{
|
||||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
void *icmsg_buffer = user_buffer_to_icmsg_buffer(data);
|
||||
|
||||
return icmsg_release_rx_buffer(conf, &dev_data->icmsg_data,
|
||||
icmsg_buffer);
|
||||
return icmsg_me_release_rx_buffer(conf, &dev_data->icmsg_me_data, data);
|
||||
}
|
||||
#endif /* CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NOCOPY_RX */
|
||||
|
||||
|
|
@ -355,11 +234,9 @@ static int backend_init(const struct device *instance)
|
|||
const struct icmsg_config_t *conf = instance->config;
|
||||
struct backend_data_t *dev_data = instance->data;
|
||||
|
||||
k_event_init(&dev_data->event);
|
||||
k_mutex_init(&dev_data->epts_mutex);
|
||||
k_mutex_init(&dev_data->send_mutex);
|
||||
|
||||
return icmsg_init(conf, &dev_data->icmsg_data);
|
||||
return icmsg_me_init(conf, &dev_data->icmsg_me_data);
|
||||
}
|
||||
|
||||
#define BACKEND_CONFIG_POPULATE(i) \
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_sources_ifdef(CONFIG_IPC_SERVICE_ICMSG icmsg.c)
|
||||
zephyr_sources_ifdef(CONFIG_IPC_SERVICE_ICMSG_ME icmsg_me.c)
|
||||
zephyr_sources_ifdef(CONFIG_IPC_SERVICE_RPMSG ipc_rpmsg.c)
|
||||
zephyr_sources_ifdef(CONFIG_IPC_SERVICE_STATIC_VRINGS ipc_static_vrings.c)
|
||||
|
|
|
|||
|
|
@ -28,3 +28,19 @@ menuconfig IPC_SERVICE_ICMSG
|
|||
if IPC_SERVICE_ICMSG
|
||||
rsource "Kconfig.icmsg"
|
||||
endif
|
||||
|
||||
config IPC_SERVICE_ICMSG_ME
|
||||
bool "icmsg IPC library with multi-endpoint functionality"
|
||||
select IPC_SERVICE_ICMSG
|
||||
select EVENTS
|
||||
help
|
||||
Multi-endpoint functionality for the icmsg library
|
||||
|
||||
config IPC_SERVICE_ICMSG_ME_NOCOPY_RX
|
||||
bool
|
||||
depends on IPC_SERVICE_ICMSG_ME
|
||||
select IPC_SERVICE_ICMSG_NOCOPY_RX
|
||||
help
|
||||
Enable nocopy feature for receiving path of the multi-endpoint
|
||||
feature of the icmsg library. This features might be used by backends
|
||||
based on multi-endpoint icmsg.
|
||||
|
|
|
|||
317
subsys/ipc/ipc_service/lib/icmsg_me.c
Normal file
317
subsys/ipc/ipc_service/lib/icmsg_me.c
Normal file
|
|
@ -0,0 +1,317 @@
|
|||
/*
|
||||
* Copyright (c) 2023 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr/ipc/icmsg_me.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define SEND_BUF_SIZE CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_SEND_BUF_SIZE
|
||||
#define NUM_EP CONFIG_IPC_SERVICE_BACKEND_ICMSG_ME_NUM_EP
|
||||
|
||||
#define EVENT_BOUND 0x01
|
||||
|
||||
#define HEADER_SIZE (sizeof(icmsg_me_ept_id_t))
|
||||
|
||||
static void *icmsg_buffer_to_user_buffer(const void *icmsg_buffer)
|
||||
{
|
||||
return (void *)(((char *)icmsg_buffer) + HEADER_SIZE);
|
||||
}
|
||||
|
||||
static void *user_buffer_to_icmsg_buffer(const void *user_buffer)
|
||||
{
|
||||
return (void *)(((char *)user_buffer) - HEADER_SIZE);
|
||||
}
|
||||
|
||||
static size_t icmsg_buffer_len_to_user_buffer_len(size_t icmsg_buffer_len)
|
||||
{
|
||||
return icmsg_buffer_len - HEADER_SIZE;
|
||||
}
|
||||
|
||||
static size_t user_buffer_len_to_icmsg_buffer_len(size_t user_buffer_len)
|
||||
{
|
||||
return user_buffer_len + HEADER_SIZE;
|
||||
}
|
||||
|
||||
static void set_ept_id_in_send_buffer(uint8_t *send_buffer,
|
||||
icmsg_me_ept_id_t ept_id)
|
||||
{
|
||||
send_buffer[0] = ept_id;
|
||||
}
|
||||
|
||||
int icmsg_me_init(const struct icmsg_config_t *conf,
|
||||
struct icmsg_me_data_t *data)
|
||||
{
|
||||
k_event_init(&data->event);
|
||||
k_mutex_init(&data->send_mutex);
|
||||
|
||||
return icmsg_init(conf, &data->icmsg_data);
|
||||
}
|
||||
|
||||
int icmsg_me_open(const struct icmsg_config_t *conf,
|
||||
struct icmsg_me_data_t *data,
|
||||
const struct ipc_service_cb *cb,
|
||||
void *ctx)
|
||||
{
|
||||
data->ept_cfg.cb = *cb;
|
||||
data->ept_cfg.priv = ctx;
|
||||
|
||||
return icmsg_open(conf, &data->icmsg_data, &data->ept_cfg.cb,
|
||||
data->ept_cfg.priv);
|
||||
}
|
||||
|
||||
void icmsg_me_icmsg_bound(struct icmsg_me_data_t *data)
|
||||
{
|
||||
k_event_post(&data->event, EVENT_BOUND);
|
||||
}
|
||||
|
||||
void icmsg_me_wait_for_icmsg_bind(struct icmsg_me_data_t *data)
|
||||
{
|
||||
k_event_wait(&data->event, EVENT_BOUND, false, K_FOREVER);
|
||||
}
|
||||
|
||||
int icmsg_me_set_empty_ept_cfg_slot(struct icmsg_me_data_t *data,
|
||||
const struct ipc_ept_cfg *ept_cfg,
|
||||
icmsg_me_ept_id_t *id)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < NUM_EP; i++) {
|
||||
if (data->epts[i] == NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= NUM_EP) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
data->epts[i] = ept_cfg;
|
||||
*id = i + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_ept_cfg_index(icmsg_me_ept_id_t id)
|
||||
{
|
||||
int i = id - 1;
|
||||
|
||||
if (i >= NUM_EP || i < 0) {
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int icmsg_me_set_ept_cfg(struct icmsg_me_data_t *data, icmsg_me_ept_id_t id,
|
||||
const struct ipc_ept_cfg *ept_cfg)
|
||||
{
|
||||
int i = get_ept_cfg_index(id);
|
||||
|
||||
if (i < 0) {
|
||||
return i;
|
||||
}
|
||||
|
||||
data->epts[i] = ept_cfg;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int icmsg_me_get_ept_cfg(struct icmsg_me_data_t *data, icmsg_me_ept_id_t id,
|
||||
const struct ipc_ept_cfg **ept_cfg)
|
||||
{
|
||||
int i = get_ept_cfg_index(id);
|
||||
|
||||
if (i < 0) {
|
||||
return i;
|
||||
}
|
||||
|
||||
*ept_cfg = data->epts[i];
|
||||
return 0;
|
||||
}
|
||||
|
||||
void icmsg_me_reset_ept_cfg(struct icmsg_me_data_t *data, icmsg_me_ept_id_t id)
|
||||
{
|
||||
int i = get_ept_cfg_index(id);
|
||||
|
||||
if (i < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
data->epts[i] = NULL;
|
||||
}
|
||||
|
||||
void icmsg_me_received_data(struct icmsg_me_data_t *data, icmsg_me_ept_id_t id,
|
||||
const void *msg, size_t len)
|
||||
{
|
||||
int r;
|
||||
const struct ipc_ept_cfg *ept;
|
||||
|
||||
r = icmsg_me_get_ept_cfg(data, id, &ept);
|
||||
if (r < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ept == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ept->cb.received) {
|
||||
ept->cb.received(icmsg_buffer_to_user_buffer(msg),
|
||||
icmsg_buffer_len_to_user_buffer_len(len),
|
||||
ept->priv);
|
||||
}
|
||||
}
|
||||
|
||||
int icmsg_me_send(const struct icmsg_config_t *conf,
|
||||
struct icmsg_me_data_t *data, icmsg_me_ept_id_t id,
|
||||
const void *msg, size_t len)
|
||||
{
|
||||
int r;
|
||||
int sent_bytes;
|
||||
|
||||
if (user_buffer_len_to_icmsg_buffer_len(len) >= SEND_BUF_SIZE) {
|
||||
return -EBADMSG;
|
||||
}
|
||||
|
||||
k_mutex_lock(&data->send_mutex, K_FOREVER);
|
||||
|
||||
/* TODO: Optimization: How to avoid this copying? */
|
||||
/* We could implement scatter list for icmsg_send, but it would require
|
||||
* scatter list also for SPSC buffer implementation.
|
||||
*/
|
||||
set_ept_id_in_send_buffer(data->send_buffer, id);
|
||||
memcpy(icmsg_buffer_to_user_buffer(data->send_buffer), msg, len);
|
||||
|
||||
r = icmsg_send(conf, &data->icmsg_data, data->send_buffer,
|
||||
user_buffer_len_to_icmsg_buffer_len(len));
|
||||
if (r > 0) {
|
||||
sent_bytes = icmsg_buffer_len_to_user_buffer_len(r);
|
||||
}
|
||||
|
||||
k_mutex_unlock(&data->send_mutex);
|
||||
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
__ASSERT_NO_MSG(r >= HEADER_SIZE);
|
||||
if (r < HEADER_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return sent_bytes;
|
||||
}
|
||||
|
||||
static size_t get_buffer_length_to_pass(size_t icmsg_buffer_len)
|
||||
{
|
||||
if (icmsg_buffer_len >= HEADER_SIZE) {
|
||||
return icmsg_buffer_len_to_user_buffer_len(icmsg_buffer_len);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int icmsg_me_get_tx_buffer(const struct icmsg_config_t *conf,
|
||||
struct icmsg_me_data_t *data,
|
||||
void **buffer, uint32_t *user_len, k_timeout_t wait)
|
||||
{
|
||||
void *icmsg_buffer;
|
||||
int r;
|
||||
size_t icmsg_len;
|
||||
|
||||
if (!K_TIMEOUT_EQ(wait, K_NO_WAIT)) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
if (*user_len) {
|
||||
icmsg_len = user_buffer_len_to_icmsg_buffer_len(*user_len);
|
||||
} else {
|
||||
icmsg_len = 0;
|
||||
}
|
||||
|
||||
r = icmsg_get_tx_buffer(conf, &data->icmsg_data,
|
||||
&icmsg_buffer, &icmsg_len);
|
||||
if (r == -ENOMEM) {
|
||||
*user_len = get_buffer_length_to_pass(icmsg_len);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
/* If requested max buffer length (*len == 0) allocated buffer might be
|
||||
* shorter than HEADER_SIZE. In such circumstances drop the buffer
|
||||
* and return error.
|
||||
*/
|
||||
*user_len = get_buffer_length_to_pass(icmsg_len);
|
||||
|
||||
if (!(*user_len)) {
|
||||
r = icmsg_drop_tx_buffer(conf, &data->icmsg_data, icmsg_buffer);
|
||||
__ASSERT_NO_MSG(!r);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
*buffer = icmsg_buffer_to_user_buffer(icmsg_buffer);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
int icmsg_me_drop_tx_buffer(const struct icmsg_config_t *conf,
|
||||
struct icmsg_me_data_t *data,
|
||||
const void *buffer)
|
||||
{
|
||||
const void *buffer_to_drop = user_buffer_to_icmsg_buffer(buffer);
|
||||
|
||||
return icmsg_drop_tx_buffer(conf, &data->icmsg_data, buffer_to_drop);
|
||||
}
|
||||
|
||||
int icmsg_me_send_nocopy(const struct icmsg_config_t *conf,
|
||||
struct icmsg_me_data_t *data, icmsg_me_ept_id_t id,
|
||||
const void *msg, size_t len)
|
||||
{
|
||||
void *buffer_to_send;
|
||||
size_t len_to_send;
|
||||
int r;
|
||||
int sent_bytes;
|
||||
|
||||
buffer_to_send = user_buffer_to_icmsg_buffer(msg);
|
||||
len_to_send = user_buffer_len_to_icmsg_buffer_len(len);
|
||||
|
||||
set_ept_id_in_send_buffer(buffer_to_send, id);
|
||||
|
||||
r = icmsg_send_nocopy(conf, &data->icmsg_data,
|
||||
buffer_to_send, len_to_send);
|
||||
|
||||
if (r < 0) {
|
||||
return r;
|
||||
}
|
||||
|
||||
__ASSERT_NO_MSG(r >= HEADER_SIZE);
|
||||
if (r < HEADER_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
sent_bytes = icmsg_buffer_len_to_user_buffer_len(r);
|
||||
|
||||
return sent_bytes;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IPC_SERVICE_ICMSG_ME_NOCOPY_RX
|
||||
int icmsg_me_hold_rx_buffer(const struct icmsg_config_t *conf,
|
||||
struct icmsg_me_data_t *data, void *buffer)
|
||||
{
|
||||
void *icmsg_buffer = user_buffer_to_icmsg_buffer(buffer);
|
||||
|
||||
return icmsg_hold_rx_buffer(conf, &data->icmsg_data, icmsg_buffer);
|
||||
}
|
||||
|
||||
int icmsg_me_release_rx_buffer(const struct icmsg_config_t *conf,
|
||||
struct icmsg_me_data_t *data, void *buffer)
|
||||
{
|
||||
void *icmsg_buffer = user_buffer_to_icmsg_buffer(buffer);
|
||||
|
||||
return icmsg_release_rx_buffer(conf, &data->icmsg_data, icmsg_buffer);
|
||||
}
|
||||
#endif /* CONFIG_IPC_SERVICE_ICMSG_ME_NOCOPY_RX */
|
||||
Loading…
Reference in a new issue