Commit 2c386316 authored by Hubert Miś's avatar Hubert Miś Committed by Carles Cufi
Browse files

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: default avatarHubert Miś <hubert.mis@nordicsemi.no>
parent 37a5158d
Loading
Loading
Loading
Loading
+32 −8
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
/*
 * 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_ */
+2 −4
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -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
+38 −180

File changed.

Preview size limit exceeded, changes collapsed.

Loading