ipc: ipc_service: Rework multi-instance backend.
Only one single IPC service backend is currently present: multi_instance backend. This backend is heavily relying on the RPMsg multi_instance code to instanciate and manage instances and endpoints. Samples exist for both in the samples/subsys/ipc/ directory. With this patch we are "unpacking" the RPMsg multi_service code to make it more modular and reusable by different backends. In particular we are re-organizing the code into two helper libraries: an RPMsg library and a VRING / virtqueues static allocation library. At the same time we rewrite the multi_instance backend to make fully use of those new libraries and remove the old multi_instance sample. Signed-off-by: Carlo Caione <ccaione@baylibre.com>
This commit is contained in:
parent
6a3593f4af
commit
6c00e980b2
128
include/ipc/ipc_rpmsg.h
Normal file
128
include/ipc/ipc_rpmsg.h
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_IPC_SERVICE_IPC_RPMSG_H_
|
||||
#define ZEPHYR_INCLUDE_IPC_SERVICE_IPC_RPMSG_H_
|
||||
|
||||
#include <ipc/ipc_service.h>
|
||||
#include <openamp/open_amp.h>
|
||||
#include <metal/device.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief IPC service RPMsg API
|
||||
* @defgroup ipc_service_rpmsg_api IPC service RPMsg API
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Number of endpoints. */
|
||||
#define NUM_ENDPOINTS CONFIG_IPC_SERVICE_NUM_ENDPOINTS_PER_INSTANCE
|
||||
|
||||
/**
|
||||
* @typedef rpmsg_ept_bound_cb
|
||||
* @brief Define the bound callback.
|
||||
*
|
||||
* This callback is defined at instance level and it is called when an endpoint
|
||||
* of the instance is bound.
|
||||
*
|
||||
* @param ept Endpoint of the instance just bound.
|
||||
*/
|
||||
typedef void (*rpmsg_ept_bound_cb)(struct ipc_ept *ept);
|
||||
|
||||
/** @brief Endpoint structure.
|
||||
*
|
||||
* Used to define an endpoint to be encapsulated in an RPMsg instance.
|
||||
*/
|
||||
struct ipc_ept {
|
||||
/** RPMsg endpoint. */
|
||||
struct rpmsg_endpoint ep;
|
||||
|
||||
/** Name of the endpoint. */
|
||||
const char *name;
|
||||
|
||||
/** Bound flag. */
|
||||
volatile bool bound;
|
||||
|
||||
/** Callbacks. */
|
||||
const struct ipc_service_cb *cb;
|
||||
|
||||
/** Private data to be passed to the endpoint callbacks. */
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/** @brief RPMsg instance structure.
|
||||
*
|
||||
* Struct representation of an RPMsg instance.
|
||||
*/
|
||||
struct ipc_rpmsg_instance {
|
||||
/** Endpoints in the instance. */
|
||||
struct ipc_ept endpoint[NUM_ENDPOINTS];
|
||||
|
||||
/** RPMsg virtIO device. */
|
||||
struct rpmsg_virtio_device rvdev;
|
||||
|
||||
/** SHM pool. */
|
||||
struct rpmsg_virtio_shm_pool shm_pool;
|
||||
|
||||
/** EPT (instance) bound callback. */
|
||||
rpmsg_ept_bound_cb bound_cb;
|
||||
|
||||
/** EPT (instance) callback. */
|
||||
rpmsg_ept_cb cb;
|
||||
};
|
||||
|
||||
/** @brief Init an RPMsg instance.
|
||||
*
|
||||
* Init an RPMsg instance.
|
||||
*
|
||||
* @param instance Pointer to the RPMsg instance struct.
|
||||
* @param role Master / Remote role.
|
||||
* @param shm_io SHM IO region pointer.
|
||||
* @param vdev VirtIO device pointer.
|
||||
* @param shb Shared memory region pointer.
|
||||
* @param size Size of the shared memory region.
|
||||
* @param ns_bind_cb callback handler for name service announcement without
|
||||
* local endpoints waiting to bind. If NULL the
|
||||
* implementation falls back to the internal implementation.
|
||||
*
|
||||
* @retval -EINVAL When some parameter is missing.
|
||||
* @retval 0 If successful.
|
||||
* @retval Other errno codes depending on the OpenAMP implementation.
|
||||
*/
|
||||
int ipc_rpmsg_init(struct ipc_rpmsg_instance *instance,
|
||||
unsigned int role,
|
||||
struct metal_io_region *shm_io,
|
||||
struct virtio_device *vdev,
|
||||
void *shb, size_t size,
|
||||
rpmsg_ns_bind_cb ns_bind_cb);
|
||||
|
||||
/** @brief Register an endpoint.
|
||||
*
|
||||
* Register an endpoint to a provided RPMsg instance.
|
||||
*
|
||||
* @param instance Pointer to the RPMsg instance struct.
|
||||
* @param role Master / Remote role.
|
||||
* @param ept Endpoint to register.
|
||||
*
|
||||
* @retval -EINVAL When some parameter is missing.
|
||||
* @retval 0 If successful.
|
||||
* @retval Other errno codes depending on the OpenAMP implementation.
|
||||
*/
|
||||
int ipc_rpmsg_register_ept(struct ipc_rpmsg_instance *instance, unsigned int role,
|
||||
struct ipc_ept *ept);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_IPC_SERVICE_IPC_RPMSG_H_ */
|
108
include/ipc/ipc_static_vrings.h
Normal file
108
include/ipc/ipc_static_vrings.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_IPC_SERVICE_IPC_STATIC_VRINGS_H_
|
||||
#define ZEPHYR_INCLUDE_IPC_SERVICE_IPC_STATIC_VRINGS_H_
|
||||
|
||||
#include <ipc/ipc_service.h>
|
||||
#include <openamp/open_amp.h>
|
||||
#include <metal/device.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief IPC service static VRINGs API
|
||||
* @defgroup ipc_service_static_vrings_api IPC service static VRINGs API
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** Number of used VRING buffers. */
|
||||
#define VRING_COUNT (2)
|
||||
|
||||
/**
|
||||
* @typedef ipc_notify_cb
|
||||
* @brief Define the notify callback.
|
||||
*
|
||||
* This callback is defined at instance level and it is called on virtqueue notify.
|
||||
*
|
||||
* @param vq Virtqueue.
|
||||
* @param priv Priv data.
|
||||
*/
|
||||
typedef void (*ipc_notify_cb)(struct virtqueue *vq, void *priv);
|
||||
|
||||
/** @brief Static VRINGs structure.
|
||||
*
|
||||
* Struct used to represent and carry information about static allocation of VRINGs.
|
||||
*/
|
||||
struct ipc_static_vrings {
|
||||
/** virtIO device. */
|
||||
struct virtio_device vdev;
|
||||
|
||||
/** SHM physmap. */
|
||||
metal_phys_addr_t shm_physmap[1];
|
||||
|
||||
/** SHM device. */
|
||||
struct metal_device shm_device;
|
||||
|
||||
/** SHM and addresses. */
|
||||
uintptr_t status_reg_addr;
|
||||
|
||||
/** TX VRING address. */
|
||||
uintptr_t tx_addr;
|
||||
|
||||
/** RX VRING address. */
|
||||
uintptr_t rx_addr;
|
||||
|
||||
/** VRING size. */
|
||||
size_t vring_size;
|
||||
|
||||
/** Shared memory region address. */
|
||||
uintptr_t shm_addr;
|
||||
|
||||
/** Share memory region size. */
|
||||
size_t shm_size;
|
||||
|
||||
/** SHM IO region. */
|
||||
struct metal_io_region *shm_io;
|
||||
|
||||
/** VRINGs */
|
||||
struct virtio_vring_info rvrings[VRING_COUNT];
|
||||
|
||||
/** Virtqueues. */
|
||||
struct virtqueue *vq[VRING_COUNT];
|
||||
|
||||
/** Private data to be passed to the notify callback. */
|
||||
void *priv;
|
||||
|
||||
/** Notify callback. */
|
||||
ipc_notify_cb notify_cb;
|
||||
};
|
||||
|
||||
/** @brief Init the static VRINGs.
|
||||
*
|
||||
* Init VRINGs and Virtqueues of an OpenAMP / RPMsg instance.
|
||||
*
|
||||
* @param vr Pointer to the VRINGs instance struct.
|
||||
* @param role Master / Remote role.
|
||||
*
|
||||
* @retval -EINVAL When some parameter is missing.
|
||||
* @retval -ENOMEM When memory is not enough for VQs allocation.
|
||||
* @retval 0 If successful.
|
||||
* @retval Other errno codes depending on the OpenAMP implementation.
|
||||
*/
|
||||
int ipc_static_vrings_init(struct ipc_static_vrings *vr, unsigned int role);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_IPC_SERVICE_IPC_STATIC_VRINGS_H_ */
|
|
@ -1,212 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#ifndef ZEPHYR_INCLUDE_RPMSG_MULTIPLE_INSTANCE_H_
|
||||
#define ZEPHYR_INCLUDE_RPMSG_MULTIPLE_INSTANCE_H_
|
||||
|
||||
#include <openamp/open_amp.h>
|
||||
#include <metal/sys.h>
|
||||
#include <metal/device.h>
|
||||
#include <metal/alloc.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief RPMsg multiple instance API
|
||||
* @defgroup rpmsg_multiple_instance_api RPMsg multiple instance APIs
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define VDEV_START_ADDR CONFIG_RPMSG_MULTI_INSTANCE_SHM_BASE_ADDRESS
|
||||
#define VDEV_SIZE CONFIG_RPMSG_MULTI_INSTANCE_SHM_SIZE
|
||||
|
||||
#define SHM_START_ADDR VDEV_START_ADDR
|
||||
#define SHM_SIZE VDEV_SIZE
|
||||
|
||||
#define VRING_ALIGNMENT (4) /**< Alignment of vring buffer. */
|
||||
#define VDEV_STATUS_SIZE (0x4) /**< Size of status region. */
|
||||
|
||||
/** @brief Event callback structure.
|
||||
*
|
||||
* It is registered during endpoint registration.
|
||||
* This structure is packed into the endpoint configuration.
|
||||
*/
|
||||
struct rpmsg_mi_cb {
|
||||
/** @brief Bind was successful.
|
||||
*
|
||||
* @param priv Private user data.
|
||||
*/
|
||||
void (*bound)(void *priv);
|
||||
|
||||
/** @brief New packet arrived.
|
||||
*
|
||||
* @param data Pointer to data buffer.
|
||||
* @param len Length of @a data.
|
||||
* @param priv Private user data.
|
||||
*/
|
||||
void (*received)(const void *data, size_t len, void *priv);
|
||||
};
|
||||
|
||||
/** @brief Endpoint instance. */
|
||||
struct rpmsg_mi_ept {
|
||||
|
||||
/** Name of endpoint. */
|
||||
const char *name;
|
||||
|
||||
/** RPMsg endpoint. */
|
||||
struct rpmsg_endpoint ep;
|
||||
|
||||
/** Event callback structure. */
|
||||
struct rpmsg_mi_cb *cb;
|
||||
|
||||
/** Private user data. */
|
||||
void *priv;
|
||||
|
||||
/** Endpoint was bound. */
|
||||
volatile bool bound;
|
||||
|
||||
/** Linked list node. */
|
||||
sys_snode_t node;
|
||||
};
|
||||
|
||||
/** @brief Endpoint configuration. */
|
||||
struct rpmsg_mi_ept_cfg {
|
||||
|
||||
/** Name of endpoint. */
|
||||
const char *name;
|
||||
|
||||
/** Event callback structure. */
|
||||
struct rpmsg_mi_cb *cb;
|
||||
|
||||
/** Private user data. */
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/** @brief Struct describing the context of the RPMsg instance. */
|
||||
struct rpmsg_mi_ctx {
|
||||
const char *name;
|
||||
struct k_work_q ipm_work_q;
|
||||
struct k_work ipm_work;
|
||||
|
||||
const struct device *ipm_tx_handle;
|
||||
const struct device *ipm_rx_handle;
|
||||
|
||||
unsigned int ipm_tx_id;
|
||||
|
||||
uintptr_t shm_status_reg_addr;
|
||||
struct metal_io_region *shm_io;
|
||||
struct metal_device shm_device;
|
||||
metal_phys_addr_t shm_physmap[1];
|
||||
|
||||
struct rpmsg_virtio_device rvdev;
|
||||
struct rpmsg_virtio_shm_pool shpool;
|
||||
struct rpmsg_device *rdev;
|
||||
|
||||
struct virtqueue *vq[2];
|
||||
struct virtio_vring_info rvrings[2];
|
||||
struct virtio_device vdev;
|
||||
|
||||
uintptr_t vring_tx_addr;
|
||||
uintptr_t vring_rx_addr;
|
||||
|
||||
sys_slist_t endpoints;
|
||||
};
|
||||
|
||||
struct rpmsg_mi_ctx_shm_cfg {
|
||||
/** Physical address shared memory region. */
|
||||
uintptr_t addr;
|
||||
|
||||
/** Size shared memory region. */
|
||||
size_t size;
|
||||
|
||||
/** Internal counter. */
|
||||
unsigned int instance;
|
||||
};
|
||||
|
||||
/** @brief Configuration of the RPMsg instance. */
|
||||
struct rpmsg_mi_ctx_cfg {
|
||||
|
||||
/** Name of instance. */
|
||||
const char *name;
|
||||
|
||||
/** Stack area for k_work_q. */
|
||||
k_thread_stack_t *ipm_stack_area;
|
||||
|
||||
/** Size of stack area. */
|
||||
size_t ipm_stack_size;
|
||||
|
||||
/** Priority of work_q. */
|
||||
int ipm_work_q_prio;
|
||||
|
||||
/** Name of work_q thread. */
|
||||
const char *ipm_thread_name;
|
||||
|
||||
/** Name of the TX IPM channel. */
|
||||
const char *ipm_tx_name;
|
||||
|
||||
/** Name of the RX IPM channel. */
|
||||
const char *ipm_rx_name;
|
||||
|
||||
/** IPM message identifier. */
|
||||
unsigned int ipm_tx_id;
|
||||
|
||||
/** SHM struct. */
|
||||
struct rpmsg_mi_ctx_shm_cfg *shm;
|
||||
};
|
||||
|
||||
/** @brief Initialization of RPMsg instance.
|
||||
*
|
||||
* Each instance has an automatically allocated area of shared memory.
|
||||
*
|
||||
* @param ctx Pointer to the RPMsg instance.
|
||||
* @param cfg Pointer to the configuration structure.
|
||||
* @retval 0 if the operation was successful.
|
||||
* -EINVAL when the incorrect parameters have been passed.
|
||||
* -EIO when the configuration is not correct.
|
||||
* -ENODEV failed to get TX or RX IPM handle.
|
||||
* -ENOMEM when there is not enough memory to register virqueue.
|
||||
* < 0 on other negative errno code, reported by rpmsg.
|
||||
*/
|
||||
int rpmsg_mi_ctx_init(struct rpmsg_mi_ctx *ctx, const struct rpmsg_mi_ctx_cfg *cfg);
|
||||
|
||||
/** @brief Register IPC endpoint.
|
||||
*
|
||||
* Registers IPC endpoint to enable communication with a remote device.
|
||||
*
|
||||
* @param ctx Pointer to the RPMsg instance.
|
||||
* @param ept Pointer to endpoint object.
|
||||
* @param cfg Pointer to the endpoint configuration.
|
||||
*
|
||||
* @retval -EINVAL One of the parameters is incorrect.
|
||||
* @retval other errno code reported by rpmsg.
|
||||
*/
|
||||
int rpmsg_mi_ept_register(struct rpmsg_mi_ctx *ctx,
|
||||
struct rpmsg_mi_ept *ept,
|
||||
struct rpmsg_mi_ept_cfg *cfg);
|
||||
|
||||
/** @brief Send data using given IPC endpoint.
|
||||
*
|
||||
* Note: It is not possible to send a message of zero length.
|
||||
*
|
||||
* @param ept Endpoint object.
|
||||
* @param data Pointer to the buffer to send through RPMsg.
|
||||
* @param len Number of bytes to send.
|
||||
*
|
||||
* @retval Number of bytes it has sent or negative error value on failure.
|
||||
*/
|
||||
int rpmsg_mi_send(struct rpmsg_mi_ept *ept, const void *data, size_t len);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* ZEPHYR_INCLUDE_RPMSG_MULTIPLE_INNSTANCE_H_ */
|
|
@ -18,7 +18,7 @@ CONFIG_IPM_MSG_CH_2_RX=y
|
|||
CONFIG_IPM_MSG_CH_1_TX=y
|
||||
CONFIG_IPM_MSG_CH_3_TX=y
|
||||
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_TX_NAME="IPM_1"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_RX_NAME="IPM_0"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_TX_NAME="IPM_3"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_RX_NAME="IPM_2"
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_0_IPM_TX_NAME="IPM_1"
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_0_IPM_RX_NAME="IPM_0"
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_1_IPM_TX_NAME="IPM_3"
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_1_IPM_RX_NAME="IPM_2"
|
||||
|
|
|
@ -18,7 +18,7 @@ CONFIG_IPM_MSG_CH_2_RX=y
|
|||
CONFIG_IPM_MSG_CH_1_TX=y
|
||||
CONFIG_IPM_MSG_CH_3_TX=y
|
||||
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_TX_NAME="IPM_1"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_RX_NAME="IPM_0"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_TX_NAME="IPM_3"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_RX_NAME="IPM_2"
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_0_IPM_TX_NAME="IPM_1"
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_0_IPM_RX_NAME="IPM_0"
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_1_IPM_TX_NAME="IPM_3"
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_1_IPM_RX_NAME="IPM_2"
|
||||
|
|
|
@ -6,14 +6,14 @@ CONFIG_HEAP_MEM_POOL_SIZE=4096
|
|||
|
||||
# Configuration IPC Service
|
||||
CONFIG_IPC_SERVICE=y
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MULTI_INSTANCE=y
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_MASTER=y
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI=y
|
||||
|
||||
# Configuration backend for IPC Service
|
||||
CONFIG_OPENAMP=y
|
||||
CONFIG_OPENAMP_SLAVE=n
|
||||
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_MASTER=y
|
||||
CONFIG_RPMSG_MULTI_INSTANCES_NO=2
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_NUM_INSTANCES=2
|
||||
|
||||
CONFIG_LOG=y
|
||||
CONFIG_IPC_SERVICE_LOG_LEVEL_INF=y
|
||||
|
|
|
@ -16,7 +16,7 @@ CONFIG_IPM_MSG_CH_3_RX=y
|
|||
CONFIG_IPM_MSG_CH_0_TX=y
|
||||
CONFIG_IPM_MSG_CH_2_TX=y
|
||||
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_TX_NAME="IPM_0"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_RX_NAME="IPM_1"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_TX_NAME="IPM_2"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_RX_NAME="IPM_3"
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_0_IPM_TX_NAME="IPM_0"
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_0_IPM_RX_NAME="IPM_1"
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_1_IPM_TX_NAME="IPM_2"
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_1_IPM_RX_NAME="IPM_3"
|
||||
|
|
|
@ -16,7 +16,7 @@ CONFIG_IPM_MSG_CH_3_RX=y
|
|||
CONFIG_IPM_MSG_CH_0_TX=y
|
||||
CONFIG_IPM_MSG_CH_2_TX=y
|
||||
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_TX_NAME="IPM_0"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_RX_NAME="IPM_1"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_TX_NAME="IPM_2"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_RX_NAME="IPM_3"
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_0_IPM_TX_NAME="IPM_0"
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_0_IPM_RX_NAME="IPM_1"
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_1_IPM_TX_NAME="IPM_2"
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_1_IPM_RX_NAME="IPM_3"
|
||||
|
|
|
@ -6,14 +6,14 @@ CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=4096
|
|||
|
||||
# Configuration IPC Service
|
||||
CONFIG_IPC_SERVICE=y
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MULTI_INSTANCE=y
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_REMOTE=y
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI=y
|
||||
|
||||
# Configuration backend for IPC Service
|
||||
CONFIG_OPENAMP=y
|
||||
CONFIG_OPENAMP_MASTER=n
|
||||
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_REMOTE=y
|
||||
CONFIG_RPMSG_MULTI_INSTANCES_NO=2
|
||||
CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_NUM_INSTANCES=2
|
||||
|
||||
CONFIG_LOG=y
|
||||
CONFIG_IPC_SERVICE_LOG_LEVEL_INF=y
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
# Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
set(REMOTE_ZEPHYR_DIR ${CMAKE_CURRENT_BINARY_DIR}/rpmsg_multi_instance_remote-prefix/src/rpmsg_multi_instance_remote-build/zephyr)
|
||||
|
||||
if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpuapp")
|
||||
set(BOARD_REMOTE "nrf5340dk_nrf5340_cpunet")
|
||||
elseif("${BOARD}" STREQUAL "bl5340_dvk_cpuapp")
|
||||
set(BOARD_REMOTE "bl5340_dvk_cpunet")
|
||||
else()
|
||||
message(FATAL_ERROR "${BOARD} is not supported for this sample")
|
||||
endif()
|
||||
|
||||
message(INFO " ${BOARD} compile as Master in this sample")
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(rpmsg_multi_instance)
|
||||
|
||||
enable_language(C ASM)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
||||
|
||||
include(ExternalProject)
|
||||
|
||||
ExternalProject_Add(
|
||||
rpmsg_multi_instance_remote
|
||||
SOURCE_DIR ${APPLICATION_SOURCE_DIR}/remote
|
||||
INSTALL_COMMAND "" # This particular build system has no install command
|
||||
CMAKE_CACHE_ARGS -DBOARD:STRING=${BOARD_REMOTE}
|
||||
CMAKE_CACHE_ARGS -DDTC_OVERLAY_FILE:STRING=${DTC_OVERLAY_FILE}
|
||||
BUILD_BYPRODUCTS "${REMOTE_ZEPHYR_DIR}/${KERNEL_BIN_NAME}"
|
||||
# NB: Do we need to pass on more CMake variables?
|
||||
BUILD_ALWAYS True
|
||||
)
|
|
@ -1,135 +0,0 @@
|
|||
.. _Multiple_instance_RPMsg_sample:
|
||||
|
||||
Multiple instance of RPMsg
|
||||
##########################
|
||||
|
||||
Overview
|
||||
********
|
||||
|
||||
Multiple instance of RPMsg is an abstraction created over OpenAMP.
|
||||
It simplifies the initialization and endpoint creation process.
|
||||
This sample demonstrates how to use multi-instance RPMsg in Zephyr.
|
||||
|
||||
Building the application for nrf5340dk_nrf5340_cpuapp
|
||||
*****************************************************
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/subsys/ipc/rpmsg_multi_instance
|
||||
:board: nrf5340dk_nrf5340_cpuapp
|
||||
:goals: debug
|
||||
|
||||
Open a serial terminal (for example Minicom or PuTTY) and connect the board with the following settings:
|
||||
|
||||
- Speed: 115200
|
||||
- Data: 8 bits
|
||||
- Parity: None
|
||||
- Stop bits: 1
|
||||
|
||||
When you reset the development kit, the following messages (one for master and one for remote) will appear on the corresponding serial ports:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
*** Booting Zephyr OS build zephyr-v2.5.0-3564-gf89886d69a8c ***
|
||||
Starting application thread!
|
||||
|
||||
RPMsg Multiple instance [master no 1] demo started
|
||||
|
||||
RPMsg Multiple instance [master no 2] demo started
|
||||
Master [no 1] core received a message: 1
|
||||
Master [no 2] core received a message: 1
|
||||
Master [no 1] core received a message: 3
|
||||
Master [no 2] core received a message: 3
|
||||
Master [no 1] core received a message: 5
|
||||
Master [no 2] core received a message: 5
|
||||
...
|
||||
Master [no 1] core received a message: 99
|
||||
RPMsg Multiple instance [no 1] demo ended.
|
||||
Master [no 2] core received a message: 99
|
||||
RPMsg Multiple instance [no 2] demo ended.
|
||||
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
*** Booting Zephyr OS build zephyr-v2.5.0-3564-gf89886d69a8c ***
|
||||
Starting application thread!
|
||||
|
||||
RPMsg Multiple instance [remote no 1] demo started
|
||||
|
||||
RPMsg Multiple instance [remote no 2] demo started
|
||||
Remote [no 1] core received a message: 0
|
||||
Remote [no 2] core received a message: 0
|
||||
Remote [no 1] core received a message: 2
|
||||
Remote [no 2] core received a message: 2
|
||||
Remote [no 1] core received a message: 4
|
||||
Remote [no 2] core received a message: 4
|
||||
...
|
||||
Remote [no 1] core received a message: 98
|
||||
RPMsg Multiple instance [no 1] demo ended.
|
||||
Remote [no 2] core received a message: 98
|
||||
RPMsg Multiple instance [no 2] demo ended.
|
||||
|
||||
Building the application for bl5340_dvk_cpuapp
|
||||
**********************************************
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/subsys/ipc/rpmsg_multi_instance
|
||||
:board: bl5340_dvk_cpuapp
|
||||
:goals: debug
|
||||
|
||||
.. zephyr-app-commands::
|
||||
:zephyr-app: samples/subsys/ipc/rpmsg_multi_instance/remote
|
||||
:board: bl5340_dvk_cpunet
|
||||
:goals: debug
|
||||
|
||||
Open a serial terminal (for example Minicom or PuTTY) and connect to the board
|
||||
with the following settings on both serial ports:
|
||||
|
||||
- Speed: 115200
|
||||
- Data: 8 bits
|
||||
- Parity: None
|
||||
- Stop bits: 1
|
||||
|
||||
When you reset the development kit after having flashed both the application
|
||||
and network core images, the following messages (one for master and one for
|
||||
remote) will appear on the corresponding serial ports:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
*** Booting Zephyr OS build v2.7.0-rc1-103-ge19875c88916 ***
|
||||
Starting application thread!
|
||||
|
||||
RPMsg Multiple instance [master no 1] demo started
|
||||
|
||||
RPMsg Multiple instance [master no 2] demo started
|
||||
Master [no 1] core received a message: 1
|
||||
Master [no 2] core received a message: 1
|
||||
Master [no 1] core received a message: 3
|
||||
Master [no 2] core received a message: 3
|
||||
Master [no 1] core received a message: 5
|
||||
Master [no 2] core received a message: 5
|
||||
...
|
||||
Master [no 1] core received a message: 99
|
||||
RPMsg Multiple instance [no 1] demo ended.
|
||||
Master [no 2] core received a message: 99
|
||||
RPMsg Multiple instance [no 2] demo ended.
|
||||
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
*** Booting Zephyr OS build v2.7.0-rc1-103-ge19875c88916 ***
|
||||
Starting application thread!
|
||||
|
||||
RPMsg Multiple instance [remote no 1] demo started
|
||||
|
||||
RPMsg Multiple instance [remote no 2] demo started
|
||||
Remote [no 1] core received a message: 0
|
||||
Remote [no 2] core received a message: 0
|
||||
Remote [no 1] core received a message: 2
|
||||
Remote [no 2] core received a message: 2
|
||||
Remote [no 1] core received a message: 4
|
||||
Remote [no 2] core received a message: 4
|
||||
...
|
||||
Remote [no 1] core received a message: 98
|
||||
RPMsg Multiple instance [no 1] demo ended.
|
||||
Remote [no 2] core received a message: 98
|
||||
RPMsg Multiple instance [no 2] demo ended.
|
|
@ -1,24 +0,0 @@
|
|||
CONFIG_BOARD_ENABLE_CPUNET=y
|
||||
|
||||
#IPM Configuration
|
||||
CONFIG_IPM=y
|
||||
CONFIG_IPM_NRFX=y
|
||||
|
||||
# Enable all needed IPM channels
|
||||
CONFIG_IPM_MSG_CH_0_ENABLE=y
|
||||
CONFIG_IPM_MSG_CH_1_ENABLE=y
|
||||
CONFIG_IPM_MSG_CH_2_ENABLE=y
|
||||
CONFIG_IPM_MSG_CH_3_ENABLE=y
|
||||
|
||||
# Configure all RX channels
|
||||
CONFIG_IPM_MSG_CH_0_RX=y
|
||||
CONFIG_IPM_MSG_CH_2_RX=y
|
||||
|
||||
# Configure all TX channels
|
||||
CONFIG_IPM_MSG_CH_1_TX=y
|
||||
CONFIG_IPM_MSG_CH_3_TX=y
|
||||
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_TX_NAME="IPM_1"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_RX_NAME="IPM_0"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_TX_NAME="IPM_3"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_RX_NAME="IPM_2"
|
|
@ -1,24 +0,0 @@
|
|||
CONFIG_BOARD_ENABLE_CPUNET=y
|
||||
|
||||
#IPM Configuration
|
||||
CONFIG_IPM=y
|
||||
CONFIG_IPM_NRFX=y
|
||||
|
||||
# Enable all needed IPM channels
|
||||
CONFIG_IPM_MSG_CH_0_ENABLE=y
|
||||
CONFIG_IPM_MSG_CH_1_ENABLE=y
|
||||
CONFIG_IPM_MSG_CH_2_ENABLE=y
|
||||
CONFIG_IPM_MSG_CH_3_ENABLE=y
|
||||
|
||||
# Configure all RX channels
|
||||
CONFIG_IPM_MSG_CH_0_RX=y
|
||||
CONFIG_IPM_MSG_CH_2_RX=y
|
||||
|
||||
# Configure all TX channels
|
||||
CONFIG_IPM_MSG_CH_1_TX=y
|
||||
CONFIG_IPM_MSG_CH_3_TX=y
|
||||
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_TX_NAME="IPM_1"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_RX_NAME="IPM_0"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_TX_NAME="IPM_3"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_RX_NAME="IPM_2"
|
|
@ -1,16 +0,0 @@
|
|||
CONFIG_PRINTK=y
|
||||
CONFIG_IPM=y
|
||||
CONFIG_TIMESLICE_SIZE=1
|
||||
CONFIG_MAIN_STACK_SIZE=2048
|
||||
CONFIG_HEAP_MEM_POOL_SIZE=4096
|
||||
|
||||
# Enable RPMsg multiple instance
|
||||
CONFIG_RPMSG_MULTI_INSTANCE=y
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_MASTER=y
|
||||
CONFIG_RPMSG_MULTI_INSTANCES_NO=2
|
||||
|
||||
CONFIG_OPENAMP=y
|
||||
CONFIG_OPENAMP_SLAVE=n
|
||||
|
||||
CONFIG_LOG=y
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_LOG_LEVEL_INF=y
|
|
@ -1,18 +0,0 @@
|
|||
# Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 3.20.0)
|
||||
|
||||
if("${BOARD}" STREQUAL "nrf5340dk_nrf5340_cpunet"
|
||||
OR "${BOARD}" STREQUAL "bl5340_dvk_cpunet")
|
||||
message(INFO " ${BOARD} compile as slave in this sample")
|
||||
else()
|
||||
message(FATAL_ERROR "${BOARD} is not supported for this sample")
|
||||
endif()
|
||||
|
||||
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||
project(rpmsg_multi_instance_remote)
|
||||
|
||||
target_sources(app PRIVATE src/main.c)
|
|
@ -1,22 +0,0 @@
|
|||
#IPM Configuration
|
||||
CONFIG_IPM=y
|
||||
CONFIG_IPM_NRFX=y
|
||||
|
||||
# Enable all needed IPM channels
|
||||
CONFIG_IPM_MSG_CH_0_ENABLE=y
|
||||
CONFIG_IPM_MSG_CH_1_ENABLE=y
|
||||
CONFIG_IPM_MSG_CH_2_ENABLE=y
|
||||
CONFIG_IPM_MSG_CH_3_ENABLE=y
|
||||
|
||||
# Configure all RX channels
|
||||
CONFIG_IPM_MSG_CH_1_RX=y
|
||||
CONFIG_IPM_MSG_CH_3_RX=y
|
||||
|
||||
# Configure all TX channels
|
||||
CONFIG_IPM_MSG_CH_0_TX=y
|
||||
CONFIG_IPM_MSG_CH_2_TX=y
|
||||
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_TX_NAME="IPM_0"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_RX_NAME="IPM_1"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_TX_NAME="IPM_2"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_RX_NAME="IPM_3"
|
|
@ -1,22 +0,0 @@
|
|||
#IPM Configuration
|
||||
CONFIG_IPM=y
|
||||
CONFIG_IPM_NRFX=y
|
||||
|
||||
# Enable all needed IPM channels
|
||||
CONFIG_IPM_MSG_CH_0_ENABLE=y
|
||||
CONFIG_IPM_MSG_CH_1_ENABLE=y
|
||||
CONFIG_IPM_MSG_CH_2_ENABLE=y
|
||||
CONFIG_IPM_MSG_CH_3_ENABLE=y
|
||||
|
||||
# Configure all RX channels
|
||||
CONFIG_IPM_MSG_CH_1_RX=y
|
||||
CONFIG_IPM_MSG_CH_3_RX=y
|
||||
|
||||
# Configure all TX channels
|
||||
CONFIG_IPM_MSG_CH_0_TX=y
|
||||
CONFIG_IPM_MSG_CH_2_TX=y
|
||||
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_TX_NAME="IPM_0"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_RX_NAME="IPM_1"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_TX_NAME="IPM_2"
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_RX_NAME="IPM_3"
|
|
@ -1,16 +0,0 @@
|
|||
CONFIG_STDOUT_CONSOLE=n
|
||||
CONFIG_PRINTK=n
|
||||
CONFIG_IPM=y
|
||||
CONFIG_HEAP_MEM_POOL_SIZE=4096
|
||||
CONFIG_SEGGER_RTT_BUFFER_SIZE_UP=4096
|
||||
|
||||
# Enable Rpmsg multiple instance
|
||||
CONFIG_RPMSG_MULTI_INSTANCE=y
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_REMOTE=y
|
||||
CONFIG_RPMSG_MULTI_INSTANCES_NO=2
|
||||
|
||||
CONFIG_OPENAMP=y
|
||||
CONFIG_OPENAMP_MASTER=n
|
||||
|
||||
CONFIG_LOG=y
|
||||
CONFIG_RPMSG_MULTI_INSTANCE_LOG_LEVEL_INF=y
|
|
@ -1,216 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <drivers/ipm.h>
|
||||
#include <sys/printk.h>
|
||||
#include <device.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <init.h>
|
||||
|
||||
#include <ipc/rpmsg_multi_instance.h>
|
||||
|
||||
#define IPM_WORK_QUEUE_STACK_SIZE 1024
|
||||
#define APP_TASK_STACK_SIZE 1024
|
||||
|
||||
#define IPM_MSG_ID 0
|
||||
|
||||
K_THREAD_STACK_DEFINE(ipm_stack_area_1, IPM_WORK_QUEUE_STACK_SIZE);
|
||||
K_THREAD_STACK_DEFINE(ipm_stack_area_2, IPM_WORK_QUEUE_STACK_SIZE);
|
||||
|
||||
K_THREAD_STACK_DEFINE(thread_stack_1, APP_TASK_STACK_SIZE);
|
||||
K_THREAD_STACK_DEFINE(thread_stack_2, APP_TASK_STACK_SIZE);
|
||||
|
||||
static struct k_thread thread_data_1;
|
||||
static struct k_thread thread_data_2;
|
||||
|
||||
static K_SEM_DEFINE(bound_ept1_sem, 0, 1);
|
||||
static K_SEM_DEFINE(bound_ept2_sem, 0, 1);
|
||||
|
||||
static K_SEM_DEFINE(data_rx1_sem, 0, 1);
|
||||
static K_SEM_DEFINE(data_rx2_sem, 0, 1);
|
||||
|
||||
static volatile uint8_t received_data_1;
|
||||
static volatile uint8_t received_data_2;
|
||||
|
||||
static struct rpmsg_mi_ctx ctx_1;
|
||||
static struct rpmsg_mi_ctx ctx_2;
|
||||
|
||||
static struct rpmsg_mi_ept ept_1;
|
||||
static struct rpmsg_mi_ept ept_2;
|
||||
|
||||
static void boud1_cb(void *priv)
|
||||
{
|
||||
k_sem_give(&bound_ept1_sem);
|
||||
}
|
||||
|
||||
static void received1_cb(const void *data, size_t len, void *priv)
|
||||
{
|
||||
received_data_1 = *((uint8_t *)data);
|
||||
k_sem_give(&data_rx1_sem);
|
||||
}
|
||||
|
||||
static void boud2_cb(void *priv)
|
||||
{
|
||||
k_sem_give(&bound_ept2_sem);
|
||||
}
|
||||
|
||||
static void received2_cb(const void *data, size_t len, void *priv)
|
||||
{
|
||||
received_data_2 = *((uint8_t *)data);
|
||||
k_sem_give(&data_rx2_sem);
|
||||
}
|
||||
|
||||
static struct rpmsg_mi_ctx_shm_cfg shm = {
|
||||
.addr = SHM_START_ADDR,
|
||||
.size = SHM_SIZE,
|
||||
};
|
||||
|
||||
static const struct rpmsg_mi_ctx_cfg cfg_1 = {
|
||||
.name = "instance 1",
|
||||
.ipm_stack_area = ipm_stack_area_1,
|
||||
.ipm_stack_size = K_THREAD_STACK_SIZEOF(ipm_stack_area_1),
|
||||
.ipm_thread_name = "ipm_work_q_1",
|
||||
.ipm_work_q_prio = 0,
|
||||
.ipm_tx_name = CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_TX_NAME,
|
||||
.ipm_rx_name = CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_RX_NAME,
|
||||
.ipm_tx_id = IPM_MSG_ID,
|
||||
.shm = &shm,
|
||||
};
|
||||
|
||||
static const struct rpmsg_mi_ctx_cfg cfg_2 = {
|
||||
.name = "instance 2",
|
||||
.ipm_stack_area = ipm_stack_area_2,
|
||||
.ipm_stack_size = K_THREAD_STACK_SIZEOF(ipm_stack_area_2),
|
||||
.ipm_thread_name = "ipm_work_q_2",
|
||||
.ipm_work_q_prio = 0,
|
||||
.ipm_tx_name = CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_TX_NAME,
|
||||
.ipm_rx_name = CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_RX_NAME,
|
||||
.ipm_tx_id = IPM_MSG_ID,
|
||||
.shm = &shm,
|
||||
};
|
||||
|
||||
static struct rpmsg_mi_cb cb_1 = {
|
||||
.bound = boud1_cb,
|
||||
.received = received1_cb,
|
||||
};
|
||||
|
||||
static struct rpmsg_mi_cb cb_2 = {
|
||||
.bound = boud2_cb,
|
||||
.received = received2_cb,
|
||||
};
|
||||
static struct rpmsg_mi_ept_cfg ept_cfg_1 = {
|
||||
.name = "ept1",
|
||||
.cb = &cb_1,
|
||||
.priv = &ept_1,
|
||||
};
|
||||
|
||||
static struct rpmsg_mi_ept_cfg ept_cfg_2 = {
|
||||
.name = "ept2",
|
||||
.cb = &cb_2,
|
||||
.priv = &ept_2,
|
||||
};
|
||||
|
||||
void app_task_1(void *arg1, void *arg2, void *arg3)
|
||||
{
|
||||
ARG_UNUSED(arg1);
|
||||
ARG_UNUSED(arg2);
|
||||
ARG_UNUSED(arg3);
|
||||
int status = 0;
|
||||
uint8_t message = 0U;
|
||||
|
||||
printk("\r\nRPMsg Multiple instance [remote no 1] demo started\r\n");
|
||||
|
||||
/* Initialization of 1 instance */
|
||||
status = rpmsg_mi_ctx_init(&ctx_1, &cfg_1);
|
||||
if (status < 0) {
|
||||
printk("rpmsg_mi_init [no 1] failed with status %d\n", status);
|
||||
}
|
||||
|
||||
status = rpmsg_mi_ept_register(&ctx_1, &ept_1, &ept_cfg_1);
|
||||
if (status < 0) {
|
||||
printk("rpmsg_mi_ept_register [no 1] failed with status %d\n",
|
||||
status);
|
||||
}
|
||||
|
||||
/* Waiting to be bound. */
|
||||
k_sem_take(&bound_ept1_sem, K_FOREVER);
|
||||
|
||||
|
||||
while (message < 99) {
|
||||
k_sem_take(&data_rx1_sem, K_FOREVER);
|
||||
message = received_data_1;
|
||||
printk("Remote [no 1] core received a message: %d\n", message);
|
||||
|
||||
message++;
|
||||
status = rpmsg_mi_send(&ept_1, &message, sizeof(message));
|
||||
if (status < 0) {
|
||||
printk("send_message(%d) failed with status %d\n",
|
||||
message, status);
|
||||
}
|
||||
}
|
||||
|
||||
printk("RPMsg Multiple instance [no 1] demo ended.\n");
|
||||
}
|
||||
|
||||
void app_task_2(void *arg1, void *arg2, void *arg3)
|
||||
{
|
||||
ARG_UNUSED(arg1);
|
||||
ARG_UNUSED(arg2);
|
||||
ARG_UNUSED(arg3);
|
||||
int status = 0;
|
||||
uint8_t message = 0U;
|
||||
|
||||
printk("\r\nRPMsg Multiple instance [remote no 2] demo started\r\n");
|
||||
|
||||
/* Initialization of 2 instance */
|
||||
status = rpmsg_mi_ctx_init(&ctx_2, &cfg_2);
|
||||
if (status < 0) {
|
||||
printk("rpmsg_mi_init [no 2] failed with status %d\n", status);
|
||||
}
|
||||
|
||||
status = rpmsg_mi_ept_register(&ctx_2, &ept_2, &ept_cfg_2);
|
||||
if (status < 0) {
|
||||
printk("rpmsg_mi_ept_register [no 2] failed with status %d\n",
|
||||
status);
|
||||
}
|
||||
|
||||
/* Waiting to be bound. */
|
||||
k_sem_take(&bound_ept2_sem, K_FOREVER);
|
||||
|
||||
|
||||
while (message < 99) {
|
||||
k_sem_take(&data_rx2_sem, K_FOREVER);
|
||||
message = received_data_2;
|
||||
printk("Remote [no 2] core received a message: %d\n", message);
|
||||
|
||||
/* k_sleep(K_MSEC(1));*/ /* for testing*/
|
||||
|
||||
message++;
|
||||
status = rpmsg_mi_send(&ept_2, &message, sizeof(message));
|
||||
if (status < 0) {
|
||||
printk("send_message(%d) failed with status %d\n",
|
||||
message, status);
|
||||
}
|
||||
}
|
||||
|
||||
printk("RPMsg Multiple instance [no 2] demo ended.\n");
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
printk("Starting application thread!\n");
|
||||
|
||||
k_thread_create(&thread_data_1, thread_stack_1, APP_TASK_STACK_SIZE,
|
||||
(k_thread_entry_t)app_task_1,
|
||||
NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
|
||||
|
||||
k_thread_create(&thread_data_2, thread_stack_2, APP_TASK_STACK_SIZE,
|
||||
(k_thread_entry_t)app_task_2,
|
||||
NULL, NULL, NULL, K_PRIO_COOP(8), 0, K_NO_WAIT);
|
||||
}
|
|
@ -1,11 +0,0 @@
|
|||
sample:
|
||||
description: This app provides an example of how to integrate
|
||||
RPMsg Multiple Instance with Zephyr.
|
||||
name: RPMsg Multiple Instance example integration
|
||||
tests:
|
||||
sample.ipc.rpmsg_multiple_instance.nrf:
|
||||
platform_allow: nrf5340dk_nrf5340_cpuapp bl5340_dvk_cpuapp
|
||||
integration_platforms:
|
||||
- nrf5340dk_nrf5340_cpuapp bl5340_dvk_cpuapp
|
||||
tags: ipm
|
||||
build_only: true
|
|
@ -1,217 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <drivers/ipm.h>
|
||||
#include <sys/printk.h>
|
||||
#include <device.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <init.h>
|
||||
|
||||
#include <ipc/rpmsg_multi_instance.h>
|
||||
|
||||
#define IPM_WORK_QUEUE_STACK_SIZE 1024
|
||||
#define APP_TASK_STACK_SIZE 1024
|
||||
|
||||
#define IPM_MSG_ID 0
|
||||
|
||||
K_THREAD_STACK_DEFINE(ipm_stack_area_1, IPM_WORK_QUEUE_STACK_SIZE);
|
||||
K_THREAD_STACK_DEFINE(ipm_stack_area_2, IPM_WORK_QUEUE_STACK_SIZE);
|
||||
|
||||
K_THREAD_STACK_DEFINE(thread_stack_1, APP_TASK_STACK_SIZE);
|
||||
K_THREAD_STACK_DEFINE(thread_stack_2, APP_TASK_STACK_SIZE);
|
||||
|
||||
static struct k_thread thread_data_1;
|
||||
static struct k_thread thread_data_2;
|
||||
|
||||
static K_SEM_DEFINE(bound_ept1_sem, 0, 1);
|
||||
static K_SEM_DEFINE(bound_ept2_sem, 0, 1);
|
||||
|
||||
static K_SEM_DEFINE(data_rx1_sem, 0, 1);
|
||||
static K_SEM_DEFINE(data_rx2_sem, 0, 1);
|
||||
|
||||
static volatile uint8_t received_data_1;
|
||||
static volatile uint8_t received_data_2;
|
||||
|
||||
static struct rpmsg_mi_ctx ctx_1;
|
||||
static struct rpmsg_mi_ctx ctx_2;
|
||||
|
||||
static struct rpmsg_mi_ept ept_1;
|
||||
static struct rpmsg_mi_ept ept_2;
|
||||
|
||||
static void boud1_cb(void *priv)
|
||||
{
|
||||
k_sem_give(&bound_ept1_sem);
|
||||
}
|
||||
|
||||
static void received1_cb(const void *data, size_t len, void *priv)
|
||||
{
|
||||
received_data_1 = *((uint8_t *)data);
|
||||
k_sem_give(&data_rx1_sem);
|
||||
}
|
||||
|
||||
static void boud2_cb(void *priv)
|
||||
{
|
||||
k_sem_give(&bound_ept2_sem);
|
||||
}
|
||||
|
||||
static void received2_cb(const void *data, size_t len, void *priv)
|
||||
{
|
||||
received_data_2 = *((uint8_t *)data);
|
||||
k_sem_give(&data_rx2_sem);
|
||||
}
|
||||
|
||||
static struct rpmsg_mi_ctx_shm_cfg shm = {
|
||||
.addr = SHM_START_ADDR,
|
||||
.size = SHM_SIZE,
|
||||
};
|
||||
|
||||
static const struct rpmsg_mi_ctx_cfg cfg_1 = {
|
||||
.name = "instance 1",
|
||||
.ipm_stack_area = ipm_stack_area_1,
|
||||
.ipm_stack_size = K_THREAD_STACK_SIZEOF(ipm_stack_area_1),
|
||||
.ipm_thread_name = "ipm_work_q_1",
|
||||
.ipm_work_q_prio = 0,
|
||||
.ipm_tx_name = CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_TX_NAME,
|
||||
.ipm_rx_name = CONFIG_RPMSG_MULTI_INSTANCE_0_IPM_RX_NAME,
|
||||
.ipm_tx_id = IPM_MSG_ID,
|
||||
.shm = &shm,
|
||||
};
|
||||
|
||||
static const struct rpmsg_mi_ctx_cfg cfg_2 = {
|
||||
.name = "instance 2",
|
||||
.ipm_stack_area = ipm_stack_area_2,
|
||||
.ipm_stack_size = K_THREAD_STACK_SIZEOF(ipm_stack_area_2),
|
||||
.ipm_thread_name = "ipm_work_q_2",
|
||||
.ipm_work_q_prio = 0,
|
||||
.ipm_tx_name = CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_TX_NAME,
|
||||
.ipm_rx_name = CONFIG_RPMSG_MULTI_INSTANCE_1_IPM_RX_NAME,
|
||||
.ipm_tx_id = IPM_MSG_ID,
|
||||
.shm = &shm,
|
||||
};
|
||||
|
||||
static struct rpmsg_mi_cb cb_1 = {
|
||||
.bound = boud1_cb,
|
||||
.received = received1_cb,
|
||||
};
|
||||
|
||||
static struct rpmsg_mi_cb cb_2 = {
|
||||
.bound = boud2_cb,
|
||||
.received = received2_cb,
|
||||
};
|
||||
|
||||
static struct rpmsg_mi_ept_cfg ept_cfg_1 = {
|
||||
.name = "ept1",
|
||||
.cb = &cb_1,
|
||||
.priv = &ept_1,
|
||||
};
|
||||
|
||||
static struct rpmsg_mi_ept_cfg ept_cfg_2 = {
|
||||
.name = "ept2",
|
||||
.cb = &cb_2,
|
||||
.priv = &ept_2,
|
||||
};
|
||||
|
||||
void app_task_1(void *arg1, void *arg2, void *arg3)
|
||||
{
|
||||
ARG_UNUSED(arg1);
|
||||
ARG_UNUSED(arg2);
|
||||
ARG_UNUSED(arg3);
|
||||
int status = 0;
|
||||
uint8_t message = 0U;
|
||||
|
||||
printk("\r\nRPMsg Multiple instance [master no 1] demo started\r\n");
|
||||
|
||||
/* Initialization of 1 instance */
|
||||
status = rpmsg_mi_ctx_init(&ctx_1, &cfg_1);
|
||||
if (status < 0) {
|
||||
printk("rpmsg_mi_init for [no 1] failed with status %d\n",
|
||||
status);
|
||||
}
|
||||
|
||||
status = rpmsg_mi_ept_register(&ctx_1, &ept_1, &ept_cfg_1);
|
||||
if (status < 0) {
|
||||
printk("rpmsg_mi_ept_register [no 1] failed with status %d\n",
|
||||
status);
|
||||
}
|
||||
|
||||
/* Waiting to be bound. */
|
||||
k_sem_take(&bound_ept1_sem, K_FOREVER);
|
||||
|
||||
while (message < 100) {
|
||||
status = rpmsg_mi_send(&ept_1, &message, sizeof(message));
|
||||
if (status < 0) {
|
||||
printk("send_message(%d) failed with status %d\n",
|
||||
message, status);
|
||||
}
|
||||
|
||||
k_sem_take(&data_rx1_sem, K_FOREVER);
|
||||
message = received_data_1;
|
||||
|
||||
printk("Master [no 1] core received a message: %d\n", message);
|
||||
message++;
|
||||
}
|
||||
|
||||
printk("RPMsg Multiple instance [no 1] demo ended.\n");
|
||||
}
|
||||
|
||||
void app_task_2(void *arg1, void *arg2, void *arg3)
|
||||
{
|
||||
ARG_UNUSED(arg1);
|
||||
ARG_UNUSED(arg2);
|
||||
ARG_UNUSED(arg3);
|
||||
int status = 0;
|
||||
uint8_t message = 0U;
|
||||
|
||||
printk("\r\nRPMsg Multiple instance [master no 2] demo started\r\n");
|
||||
|
||||
/* Initialization of 2 instance */
|
||||
status = rpmsg_mi_ctx_init(&ctx_2, &cfg_2);
|
||||
if (status < 0) {
|
||||
printk("rpmsg_mi_init [no 2] failed with status %d\n", status);
|
||||
}
|
||||
|
||||
status = rpmsg_mi_ept_register(&ctx_2, &ept_2, &ept_cfg_2);
|
||||
if (status < 0) {
|
||||
printk("rpmsg_mi_ept_register [no 2] failed with status %d\n",
|
||||
status);
|
||||
}
|
||||
|
||||
/* Waiting to be bound. */
|
||||
k_sem_take(&bound_ept2_sem, K_FOREVER);
|
||||
|
||||
while (message < 100) {
|
||||
status = rpmsg_mi_send(&ept_2, &message, sizeof(message));
|
||||
if (status < 0) {
|
||||
printk("send_message(%d) failed with status %d\n",
|
||||
message, status);
|
||||
}
|
||||
|
||||
k_sem_take(&data_rx2_sem, K_FOREVER);
|
||||
message = received_data_2;
|
||||
|
||||
printk("Master [no 2] core received a message: %d\n", message);
|
||||
|
||||
message++;
|
||||
}
|
||||
|
||||
printk("RPMsg Multiple instance [no 2] demo ended.\n");
|
||||
}
|
||||
|
||||
void main(void)
|
||||
{
|
||||
printk("Starting application thread!\n");
|
||||
|
||||
k_thread_create(&thread_data_1, thread_stack_1, APP_TASK_STACK_SIZE,
|
||||
(k_thread_entry_t)app_task_1,
|
||||
NULL, NULL, NULL, K_PRIO_COOP(7), 0, K_NO_WAIT);
|
||||
|
||||
k_thread_create(&thread_data_2, thread_stack_2, APP_TASK_STACK_SIZE,
|
||||
(k_thread_entry_t)app_task_2,
|
||||
NULL, NULL, NULL, K_PRIO_COOP(8), 0, K_NO_WAIT);
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
add_subdirectory_ifdef(CONFIG_RPMSG_SERVICE rpmsg_service)
|
||||
add_subdirectory_ifdef(CONFIG_RPMSG_MULTI_INSTANCE rpmsg_multi_instance)
|
||||
add_subdirectory_ifdef(CONFIG_IPC_SERVICE ipc_service)
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
menu "Inter Processor Communication"
|
||||
|
||||
source "subsys/ipc/rpmsg_service/Kconfig"
|
||||
source "subsys/ipc/rpmsg_multi_instance/Kconfig"
|
||||
source "subsys/ipc/ipc_service/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -11,23 +11,15 @@ menuconfig IPC_SERVICE
|
|||
|
||||
if IPC_SERVICE
|
||||
|
||||
choice IPC_SERVICE_BACKEND
|
||||
prompt "IPC Service backend"
|
||||
rsource "backends/Kconfig"
|
||||
|
||||
config IPC_SERVICE_BACKEND_RPMSG_MULTI_INSTANCE
|
||||
bool "RPMsg multiple instance backend"
|
||||
select RPMSG_MULTI_INSTANCE
|
||||
config IPC_SERVICE_NUM_ENDPOINTS_PER_INSTANCE
|
||||
int "Max number of registered endpoints per instance"
|
||||
default 2
|
||||
help
|
||||
Maximal number of endpoints that can be registered for one instance.
|
||||
|
||||
endchoice
|
||||
|
||||
if IPC_SERVICE_BACKEND_RPMSG_MULTI_INSTANCE
|
||||
|
||||
rsource "backends/Kconfig.rpmsg_mi"
|
||||
|
||||
endif # IPC_SERVICE_BACKEND_RPMSG_MULTI_INSTANCE
|
||||
|
||||
|
||||
config IPC_SERVICE_BACKEND_REG_PRIORITY
|
||||
config IPC_SERVICE_REG_BACKEND_PRIORITY
|
||||
int "Initialization priority of modules registering IPC backend"
|
||||
default 46
|
||||
help
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_sources_ifdef(CONFIG_IPC_SERVICE_BACKEND_RPMSG_MULTI_INSTANCE ipc_rpmsg_multi_instance.c)
|
||||
# libraries
|
||||
zephyr_sources_ifdef(CONFIG_IPC_SERVICE_RPMSG ipc_rpmsg.c)
|
||||
zephyr_sources_ifdef(CONFIG_IPC_SERVICE_STATIC_VRINGS ipc_static_vrings.c)
|
||||
|
||||
# backends
|
||||
zephyr_sources_ifdef(CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI ipc_rpmsg_static_vrings_mi.c)
|
||||
|
|
30
subsys/ipc/ipc_service/backends/Kconfig
Normal file
30
subsys/ipc/ipc_service/backends/Kconfig
Normal file
|
@ -0,0 +1,30 @@
|
|||
# Copyright (c) 2021 Nordic Semiconductor (ASA)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
choice IPC_SERVICE_BACKEND
|
||||
prompt "IPC service backend"
|
||||
|
||||
config IPC_SERVICE_BACKEND_RPMSG_MI
|
||||
bool "RPMSG backend - static VRINGs (multi-instance)"
|
||||
select IPC_SERVICE_RPMSG
|
||||
select IPC_SERVICE_STATIC_VRINGS
|
||||
select OPENAMP
|
||||
select IPM
|
||||
|
||||
endchoice
|
||||
|
||||
if IPC_SERVICE_BACKEND_RPMSG_MI
|
||||
|
||||
rsource "Kconfig.rpmsg_mi"
|
||||
|
||||
endif # IP_SERVICE_BACKEND_RPMSG_MI
|
||||
|
||||
config IPC_SERVICE_RPMSG
|
||||
bool "RPMsg support library"
|
||||
help
|
||||
"RPMsg library"
|
||||
|
||||
config IPC_SERVICE_STATIC_VRINGS
|
||||
bool "Static VRINGs support library"
|
||||
help
|
||||
"Static VRINGs library"
|
|
@ -1,13 +1,13 @@
|
|||
# Copyright (c) 2021 Nordic Semiconductor (ASA)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config RPMSG_MULTI_INSTANCE_$(ipm_name_instance_num)_IPM_TX_NAME
|
||||
config IPC_SERVICE_BACKEND_RPMSG_MI_$(ipm_name_instance_num)_IPM_TX_NAME
|
||||
string "TX IPM channel name for instance $(ipm_name_instance_num)"
|
||||
help
|
||||
This option specifies the IPM device name to be used for
|
||||
TX communication.
|
||||
|
||||
config RPMSG_MULTI_INSTANCE_$(ipm_name_instance_num)_IPM_RX_NAME
|
||||
config IPC_SERVICE_BACKEND_RPMSG_MI_$(ipm_name_instance_num)_IPM_RX_NAME
|
||||
string "RX IPM channel name for instance $(ipm_name_instance_num)"
|
||||
help
|
||||
This option specifies the IPM device name to be used for
|
|
@ -1,17 +1,60 @@
|
|||
# Copyright (c) 2020-2021 Nordic Semiconductor (ASA)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config IPC_BACKEND_RPMSG_MI_WORK_QUEUE_STACK_SIZE
|
||||
int "Size of RX work queue stack"
|
||||
choice IPC_SERVICE_BACKEND_RPMSG_MI_ROLE
|
||||
prompt "IPC service device role"
|
||||
|
||||
config IPC_SERVICE_BACKEND_RPMSG_MI_REMOTE
|
||||
bool "Remote"
|
||||
|
||||
config IPC_SERVICE_BACKEND_RPMSG_MI_MASTER
|
||||
bool "Master"
|
||||
|
||||
endchoice
|
||||
|
||||
config IPC_SERVICE_BACKEND_RPMSG_MI_WQ_STACK_SIZE
|
||||
int "Size of RX work queue stack"
|
||||
default 1024
|
||||
help
|
||||
Size of stack used by work queue RX thread. This work queue is
|
||||
created in the multi-instance RPMsg backend module to prevent notifying
|
||||
service users about received data from the system work queue.
|
||||
Size is the same for all instances.
|
||||
created in the multi-instance / multi-core RPMsg backend module to
|
||||
prevent notifying service users about received data from the system
|
||||
work queue. Size is the same for all instances.
|
||||
|
||||
config IPC_BACKEND_RPMSG_MI_NUM_ENDPOINTS_PER_INSTANCE
|
||||
int "Max number of registered endpoints per instance"
|
||||
default 2
|
||||
config IPC_SERVICE_BACKEND_RPMSG_MI_SHM_BASE_ADDRESS
|
||||
hex
|
||||
default "$(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_IPC_SHM))"
|
||||
help
|
||||
Maximal number of endpoints that can be registered for one instance.
|
||||
This option specifies base address of the memory region to
|
||||
be used for the OpenAMP IPC shared memory.
|
||||
|
||||
config IPC_SERVICE_BACKEND_RPMSG_MI_SHM_SIZE
|
||||
hex
|
||||
default "$(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_IPC_SHM))"
|
||||
help
|
||||
This option specifies size of the memory region to be used
|
||||
for the OpenAMP IPC shared memory.
|
||||
|
||||
config IPC_SERVICE_BACKEND_RPMSG_MI_NUM_INSTANCES
|
||||
int "Number of RPMsg instances"
|
||||
default 2
|
||||
range 1 8
|
||||
help
|
||||
How many instances are to be used.
|
||||
|
||||
ipm_name_instance_num = 0
|
||||
rsource "Kconfig.ipm_name_instance"
|
||||
ipm_name_instance_num = 1
|
||||
rsource "Kconfig.ipm_name_instance"
|
||||
ipm_name_instance_num = 2
|
||||
rsource "Kconfig.ipm_name_instance"
|
||||
ipm_name_instance_num = 3
|
||||
rsource "Kconfig.ipm_name_instance"
|
||||
ipm_name_instance_num = 4
|
||||
rsource "Kconfig.ipm_name_instance"
|
||||
ipm_name_instance_num = 5
|
||||
rsource "Kconfig.ipm_name_instance"
|
||||
ipm_name_instance_num = 6
|
||||
rsource "Kconfig.ipm_name_instance"
|
||||
ipm_name_instance_num = 7
|
||||
rsource "Kconfig.ipm_name_instance"
|
||||
|
|
86
subsys/ipc/ipc_service/backends/ipc_rpmsg.c
Normal file
86
subsys/ipc/ipc_service/backends/ipc_rpmsg.c
Normal file
|
@ -0,0 +1,86 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <zephyr.h>
|
||||
#include <ipc/ipc_rpmsg.h>
|
||||
|
||||
static void rpmsg_service_unbind(struct rpmsg_endpoint *ep)
|
||||
{
|
||||
rpmsg_destroy_ept(ep);
|
||||
}
|
||||
|
||||
static void ns_bind_cb(struct rpmsg_device *rdev, const char *name, uint32_t dest)
|
||||
{
|
||||
struct rpmsg_virtio_device *p_rvdev;
|
||||
struct ipc_rpmsg_instance *instance;
|
||||
struct ipc_ept *ept;
|
||||
int err;
|
||||
|
||||
p_rvdev = CONTAINER_OF(rdev, struct rpmsg_virtio_device, rdev);
|
||||
instance = CONTAINER_OF(p_rvdev->shpool, struct ipc_rpmsg_instance, shm_pool);
|
||||
|
||||
for (size_t i = 0; i < NUM_ENDPOINTS; i++) {
|
||||
ept = &instance->endpoint[i];
|
||||
|
||||
if (strcmp(name, ept->name) == 0) {
|
||||
err = rpmsg_create_ept(&ept->ep, rdev, name, RPMSG_ADDR_ANY,
|
||||
dest, instance->cb, rpmsg_service_unbind);
|
||||
if (err != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ept->bound = true;
|
||||
if (instance->bound_cb) {
|
||||
instance->bound_cb(ept);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ipc_rpmsg_register_ept(struct ipc_rpmsg_instance *instance, unsigned int role,
|
||||
struct ipc_ept *ept)
|
||||
{
|
||||
struct rpmsg_device *rdev;
|
||||
|
||||
if (!instance || !ept) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rdev = rpmsg_virtio_get_rpmsg_device(&instance->rvdev);
|
||||
|
||||
if (role == RPMSG_REMOTE) {
|
||||
return rpmsg_create_ept(&ept->ep, rdev, ept->name, RPMSG_ADDR_ANY,
|
||||
RPMSG_ADDR_ANY, instance->cb, rpmsg_service_unbind);
|
||||
}
|
||||
|
||||
return RPMSG_SUCCESS;
|
||||
}
|
||||
|
||||
int ipc_rpmsg_init(struct ipc_rpmsg_instance *instance,
|
||||
unsigned int role,
|
||||
struct metal_io_region *shm_io,
|
||||
struct virtio_device *vdev,
|
||||
void *shb, size_t size,
|
||||
rpmsg_ns_bind_cb p_bind_cb)
|
||||
{
|
||||
rpmsg_ns_bind_cb bind_cb = p_bind_cb;
|
||||
|
||||
if (!instance || !shb) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (p_bind_cb == NULL) {
|
||||
bind_cb = ns_bind_cb;
|
||||
}
|
||||
|
||||
if (role == RPMSG_MASTER) {
|
||||
rpmsg_virtio_init_shm_pool(&instance->shm_pool, shb, size);
|
||||
return rpmsg_init_vdev(&instance->rvdev, vdev, bind_cb,
|
||||
shm_io, &instance->shm_pool);
|
||||
} else {
|
||||
return rpmsg_init_vdev(&instance->rvdev, vdev, bind_cb, shm_io, NULL);
|
||||
}
|
||||
}
|
|
@ -1,201 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021, Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
#include <ipc/ipc_service_backend.h>
|
||||
#include <ipc/rpmsg_multi_instance.h>
|
||||
|
||||
#include <logging/log.h>
|
||||
#include <sys/util_macro.h>
|
||||
#include <zephyr.h>
|
||||
#include <device.h>
|
||||
|
||||
LOG_MODULE_REGISTER(ipc_rpmsg_multi_instance, CONFIG_IPC_SERVICE_LOG_LEVEL);
|
||||
|
||||
#define NUM_INSTANCES CONFIG_RPMSG_MULTI_INSTANCES_NO
|
||||
#define NUM_ENDPOINTS CONFIG_IPC_BACKEND_RPMSG_MI_NUM_ENDPOINTS_PER_INSTANCE
|
||||
|
||||
#define WORK_QUEUE_STACK_SIZE CONFIG_IPC_BACKEND_RPMSG_MI_WORK_QUEUE_STACK_SIZE
|
||||
|
||||
#define PRIO_INIT_VAL INT_MAX
|
||||
#define INSTANCE_NAME_SIZE 16
|
||||
#define IPM_MSG_ID 0
|
||||
|
||||
#define CH_NAME(idx, sub) (CONFIG_RPMSG_MULTI_INSTANCE_ ## idx ## _IPM_ ## sub ## _NAME)
|
||||
|
||||
static char *ipm_rx_name[] = {
|
||||
FOR_EACH_FIXED_ARG(CH_NAME, (,), RX, 0, 1, 2, 3, 4, 5, 6, 7),
|
||||
};
|
||||
|
||||
static char *ipm_tx_name[] = {
|
||||
FOR_EACH_FIXED_ARG(CH_NAME, (,), TX, 0, 1, 2, 3, 4, 5, 6, 7),
|
||||
};
|
||||
|
||||
BUILD_ASSERT(ARRAY_SIZE(ipm_rx_name) >= NUM_INSTANCES, "Invalid configuration");
|
||||
BUILD_ASSERT(ARRAY_SIZE(ipm_tx_name) >= NUM_INSTANCES, "Invalid configuration");
|
||||
|
||||
K_THREAD_STACK_ARRAY_DEFINE(ipm_stack, NUM_INSTANCES, WORK_QUEUE_STACK_SIZE);
|
||||
|
||||
struct ipc_ept {
|
||||
struct rpmsg_mi_ept rpmsg_ep;
|
||||
struct ipc_service_cb cb;
|
||||
const char *name;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
struct ipc_rpmsg_mi_instances {
|
||||
struct ipc_ept endpoints[NUM_ENDPOINTS];
|
||||
char name[INSTANCE_NAME_SIZE];
|
||||
struct rpmsg_mi_ctx ctx;
|
||||
bool is_initialized;
|
||||
int prio;
|
||||
};
|
||||
|
||||
static struct ipc_rpmsg_mi_instances instances[NUM_INSTANCES];
|
||||
|
||||
static struct rpmsg_mi_ctx_shm_cfg shm = {
|
||||
.addr = SHM_START_ADDR,
|
||||
.size = SHM_SIZE,
|
||||
};
|
||||
|
||||
static void common_bound_cb(void *priv)
|
||||
{
|
||||
struct ipc_ept *ept = (struct ipc_ept *)priv;
|
||||
|
||||
if (ept->cb.bound) {
|
||||
ept->cb.bound(ept->priv);
|
||||
}
|
||||
}
|
||||
|
||||
static void common_recv_cb(const void *data, size_t len, void *priv)
|
||||
{
|
||||
struct ipc_ept *ept = (struct ipc_ept *)priv;
|
||||
|
||||
if (ept->cb.received) {
|
||||
ept->cb.received(data, len, ept->priv);
|
||||
}
|
||||
}
|
||||
|
||||
static struct rpmsg_mi_cb cb = {
|
||||
.bound = common_bound_cb,
|
||||
.received = common_recv_cb,
|
||||
};
|
||||
|
||||
static int send(struct ipc_ept *ept, const void *data, size_t len)
|
||||
{
|
||||
return rpmsg_mi_send(&ept->rpmsg_ep, data, len);
|
||||
}
|
||||
|
||||
static int get_available_instance(const struct ipc_ept_cfg *cfg)
|
||||
{
|
||||
/* Endpoints with the same priority are
|
||||
* registered to the same instance.
|
||||
*/
|
||||
for (size_t i = 0; i < NUM_INSTANCES; i++) {
|
||||
if (instances[i].prio == cfg->prio || instances[i].prio == PRIO_INIT_VAL) {
|
||||
return (int)i;
|
||||
}
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int get_available_ept_slot(struct ipc_rpmsg_mi_instances *instance)
|
||||
{
|
||||
for (size_t i = 0; i < NUM_ENDPOINTS; i++) {
|
||||
if (!(instance->endpoints[i].name)) {
|
||||
return (int)i;
|
||||
}
|
||||
}
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static int register_ept(struct ipc_ept **ept, const struct ipc_ept_cfg *cfg)
|
||||
{
|
||||
struct rpmsg_mi_ept_cfg ept_cfg = { 0 };
|
||||
int i_idx, e_idx;
|
||||
|
||||
if (!cfg || !ept) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
i_idx = get_available_instance(cfg);
|
||||
if (i_idx < 0) {
|
||||
LOG_ERR("Available instance not found");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* Initialization of the instance context is performed only once.
|
||||
* When registering the first endpoint for the instance.
|
||||
*/
|
||||
if (!instances[i_idx].is_initialized) {
|
||||
struct rpmsg_mi_ctx_cfg ctx_cfg = { 0 };
|
||||
|
||||
snprintf(instances[i_idx].name, INSTANCE_NAME_SIZE, "rpmsg_mi_%d", i_idx);
|
||||
|
||||
ctx_cfg.name = instances[i_idx].name;
|
||||
ctx_cfg.ipm_stack_area = ipm_stack[i_idx];
|
||||
ctx_cfg.ipm_stack_size = K_THREAD_STACK_SIZEOF(ipm_stack[i_idx]);
|
||||
ctx_cfg.ipm_work_q_prio = cfg->prio;
|
||||
ctx_cfg.ipm_thread_name = instances[i_idx].name;
|
||||
ctx_cfg.ipm_rx_name = ipm_rx_name[i_idx];
|
||||
ctx_cfg.ipm_tx_name = ipm_tx_name[i_idx];
|
||||
ctx_cfg.ipm_tx_id = IPM_MSG_ID;
|
||||
|
||||
ctx_cfg.shm = &shm;
|
||||
|
||||
if (rpmsg_mi_ctx_init(&instances[i_idx].ctx, &ctx_cfg) < 0) {
|
||||
LOG_ERR("Instance initialization failed");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
instances[i_idx].is_initialized = true;
|
||||
}
|
||||
|
||||
e_idx = get_available_ept_slot(&instances[i_idx]);
|
||||
if (e_idx < 0) {
|
||||
LOG_ERR("No free slots to register endpoint %s", log_strdup(cfg->name));
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
instances[i_idx].endpoints[e_idx].priv = cfg->priv;
|
||||
instances[i_idx].endpoints[e_idx].cb = cfg->cb;
|
||||
|
||||
ept_cfg.cb = &cb;
|
||||
ept_cfg.priv = &instances[i_idx].endpoints[e_idx];
|
||||
ept_cfg.name = cfg->name;
|
||||
|
||||
if (rpmsg_mi_ept_register(&instances[i_idx].ctx,
|
||||
&instances[i_idx].endpoints[e_idx].rpmsg_ep, &ept_cfg) < 0) {
|
||||
LOG_ERR("Register endpoint failed");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
instances[i_idx].endpoints[e_idx].name = cfg->name;
|
||||
instances[i_idx].prio = cfg->prio;
|
||||
|
||||
*ept = &instances[i_idx].endpoints[e_idx];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const static struct ipc_service_backend backend = {
|
||||
.name = "RPMsg multi-instace backend",
|
||||
.send = send,
|
||||
.register_endpoint = register_ept,
|
||||
};
|
||||
|
||||
static int backend_init(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
for (size_t i = 0; i < NUM_INSTANCES; i++) {
|
||||
instances[i].prio = PRIO_INIT_VAL;
|
||||
}
|
||||
|
||||
return ipc_service_register_backend(&backend);
|
||||
}
|
||||
|
||||
SYS_INIT(backend_init, POST_KERNEL, CONFIG_IPC_SERVICE_BACKEND_REG_PRIORITY);
|
326
subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings_mi.c
Normal file
326
subsys/ipc/ipc_service/backends/ipc_rpmsg_static_vrings_mi.c
Normal file
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
* Copyright (c) 2020-2021, Nordic Semiconductor ASA
|
||||
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <ipc/ipc_service_backend.h>
|
||||
#include <ipc/ipc_rpmsg.h>
|
||||
#include <ipc/ipc_static_vrings.h>
|
||||
|
||||
#include <logging/log.h>
|
||||
#include <zephyr.h>
|
||||
#include <cache.h>
|
||||
#include <device.h>
|
||||
#include <drivers/ipm.h>
|
||||
|
||||
#include "ipc_rpmsg_static_vrings_mi.h"
|
||||
|
||||
LOG_MODULE_REGISTER(ipc_rpmsg_multi_instance, CONFIG_IPC_SERVICE_LOG_LEVEL);
|
||||
|
||||
#define WQ_STACK_SIZE CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_WQ_STACK_SIZE
|
||||
|
||||
#define PRIO_INIT_VAL INT_MAX
|
||||
#define INST_NAME_SIZE 16
|
||||
#define IPM_MSG_ID 0
|
||||
|
||||
#define CH_NAME(idx, sub) (CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_ ## idx ## _IPM_ ## sub ## _NAME)
|
||||
|
||||
static char *ipm_rx_name[] = {
|
||||
FOR_EACH_FIXED_ARG(CH_NAME, (,), RX, 0, 1, 2, 3, 4, 5, 6, 7),
|
||||
};
|
||||
|
||||
static char *ipm_tx_name[] = {
|
||||
FOR_EACH_FIXED_ARG(CH_NAME, (,), TX, 0, 1, 2, 3, 4, 5, 6, 7),
|
||||
};
|
||||
|
||||
BUILD_ASSERT(ARRAY_SIZE(ipm_rx_name) >= NUM_INSTANCES, "Invalid configuration");
|
||||
BUILD_ASSERT(ARRAY_SIZE(ipm_tx_name) >= NUM_INSTANCES, "Invalid configuration");
|
||||
|
||||
K_THREAD_STACK_ARRAY_DEFINE(ipm_stack, NUM_INSTANCES, WQ_STACK_SIZE);
|
||||
|
||||
struct rpmsg_mi_instance {
|
||||
/* RPMsg */
|
||||
struct ipc_rpmsg_instance rpmsg_inst;
|
||||
|
||||
/* Static VRINGs */
|
||||
struct ipc_static_vrings vr;
|
||||
|
||||
/* General */
|
||||
char name[INST_NAME_SIZE];
|
||||
bool is_initialized;
|
||||
unsigned int id;
|
||||
|
||||
/* IPM */
|
||||
const struct device *ipm_tx_handle;
|
||||
const struct device *ipm_rx_handle;
|
||||
struct k_work_q ipm_wq;
|
||||
struct k_work ipm_work;
|
||||
int priority;
|
||||
|
||||
/* Role */
|
||||
unsigned int role;
|
||||
};
|
||||
|
||||
struct {
|
||||
uintptr_t addr;
|
||||
size_t size;
|
||||
size_t instance;
|
||||
} shm = {
|
||||
.addr = SHM_START_ADDR,
|
||||
.size = SHM_SIZE,
|
||||
};
|
||||
|
||||
static struct rpmsg_mi_instance instance[NUM_INSTANCES];
|
||||
|
||||
static int send(struct ipc_ept *ept, const void *data, size_t len)
|
||||
{
|
||||
return rpmsg_send(&ept->ep, data, len);
|
||||
}
|
||||
|
||||
static struct rpmsg_mi_instance *get_available_instance(const struct ipc_ept_cfg *cfg)
|
||||
{
|
||||
/* Endpoints with the same priority are registered to the same instance. */
|
||||
for (size_t i = 0; i < NUM_INSTANCES; i++) {
|
||||
if (instance[i].priority == cfg->prio || instance[i].priority == PRIO_INIT_VAL) {
|
||||
return &instance[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct ipc_ept *get_available_ept_slot(struct ipc_rpmsg_instance *rpmsg_instance)
|
||||
{
|
||||
for (size_t i = 0; i < NUM_ENDPOINTS; i++) {
|
||||
if (rpmsg_instance->endpoint[i].name == NULL) {
|
||||
return &rpmsg_instance->endpoint[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void ipm_callback_process(struct k_work *item)
|
||||
{
|
||||
struct rpmsg_mi_instance *instance;
|
||||
unsigned int id;
|
||||
|
||||
instance = CONTAINER_OF(item, struct rpmsg_mi_instance, ipm_work);
|
||||
id = (instance->role == VIRTIO_DEV_MASTER) ?
|
||||
VIRTQUEUE_ID_MASTER : VIRTQUEUE_ID_REMOTE;
|
||||
|
||||
virtqueue_notification(instance->vr.vq[id]);
|
||||
}
|
||||
|
||||
static void ipm_callback(const struct device *dev, void *context, uint32_t id, volatile void *data)
|
||||
{
|
||||
struct rpmsg_mi_instance *instance = (struct rpmsg_mi_instance *) context;
|
||||
|
||||
k_work_submit_to_queue(&instance->ipm_wq, &instance->ipm_work);
|
||||
}
|
||||
|
||||
static int ipm_setup(struct rpmsg_mi_instance *instance)
|
||||
{
|
||||
instance->ipm_tx_handle = device_get_binding(ipm_tx_name[instance->id]);
|
||||
if (instance->ipm_tx_handle == NULL) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
instance->ipm_rx_handle = device_get_binding(ipm_rx_name[instance->id]);
|
||||
if (instance->ipm_rx_handle == NULL) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
k_work_queue_start(&instance->ipm_wq, ipm_stack[instance->id],
|
||||
K_THREAD_STACK_SIZEOF(ipm_stack[instance->id]),
|
||||
instance->priority, NULL);
|
||||
|
||||
k_thread_name_set(&instance->ipm_wq.thread, instance->name);
|
||||
|
||||
k_work_init(&instance->ipm_work, ipm_callback_process);
|
||||
|
||||
ipm_register_callback(instance->ipm_rx_handle, ipm_callback, instance);
|
||||
|
||||
return ipm_set_enabled(instance->ipm_rx_handle, 1);
|
||||
}
|
||||
|
||||
static void shm_configure(struct rpmsg_mi_instance *instance)
|
||||
{
|
||||
size_t vring_size, shm_size, shm_local_size;
|
||||
size_t rpmsg_reg_size, vring_reg_size;
|
||||
uintptr_t shm_addr, shm_local_addr;
|
||||
|
||||
vring_size = VRING_SIZE_GET(shm.size);
|
||||
shm_addr = SHMEM_INST_ADDR_AUTOALLOC_GET(shm.addr, shm.size, shm.instance);
|
||||
shm_size = SHMEM_INST_SIZE_AUTOALLOC_GET(shm.size);
|
||||
|
||||
shm_local_addr = shm_addr + VDEV_STATUS_SIZE;
|
||||
shm_local_size = shm_size - VDEV_STATUS_SIZE;
|
||||
|
||||
rpmsg_reg_size = VRING_COUNT * VIRTQUEUE_SIZE_GET(vring_size);
|
||||
vring_reg_size = VRING_SIZE_COMPUTE(vring_size, VRING_ALIGNMENT);
|
||||
|
||||
instance->vr.status_reg_addr = shm_addr;
|
||||
instance->vr.vring_size = vring_size;
|
||||
instance->vr.rx_addr = shm_local_addr + rpmsg_reg_size;
|
||||
instance->vr.tx_addr = instance->vr.rx_addr + vring_reg_size;
|
||||
instance->vr.shm_addr = shm_local_addr;
|
||||
instance->vr.shm_size = shm_local_size;
|
||||
}
|
||||
|
||||
static void bound_cb(struct ipc_ept *ept)
|
||||
{
|
||||
/* Notify the remote site that binding has occurred */
|
||||
rpmsg_send(&ept->ep, (uint8_t *)"", 0);
|
||||
|
||||
if (ept->cb->bound) {
|
||||
ept->cb->bound(ept->priv);
|
||||
}
|
||||
}
|
||||
|
||||
static int ept_cb(struct rpmsg_endpoint *ep, void *data, size_t len, uint32_t src, void *priv)
|
||||
{
|
||||
struct ipc_ept *ept;
|
||||
|
||||
ept = (struct ipc_ept *) priv;
|
||||
|
||||
if (len == 0) {
|
||||
if (!ept->bound) {
|
||||
ept->bound = true;
|
||||
bound_cb(ept);
|
||||
}
|
||||
return RPMSG_SUCCESS;
|
||||
}
|
||||
|
||||
if (ept->cb->received) {
|
||||
ept->cb->received(data, len, ept->priv);
|
||||
}
|
||||
|
||||
return RPMSG_SUCCESS;
|
||||
}
|
||||
|
||||
static void virtio_notify_cb(struct virtqueue *vq, void *priv)
|
||||
{
|
||||
struct rpmsg_mi_instance *instance;
|
||||
|
||||
instance = (struct rpmsg_mi_instance *) priv;
|
||||
|
||||
if (instance) {
|
||||
ipm_send(instance->ipm_tx_handle, 0, IPM_MSG_ID, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int init_instance(struct rpmsg_mi_instance *instance)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
/* Check if there is enough space in the SHM */
|
||||
if (SHMEM_INST_SIZE_AUTOALLOC_GET(shm.size) * NUM_INSTANCES > shm.size) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
shm_configure(instance);
|
||||
|
||||
instance->vr.notify_cb = virtio_notify_cb;
|
||||
instance->vr.priv = instance;
|
||||
|
||||
ipc_static_vrings_init(&instance->vr, instance->role);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ipm_setup(instance);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
shm.instance++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int register_ept(struct ipc_ept **r_ept, const struct ipc_ept_cfg *cfg)
|
||||
{
|
||||
struct ipc_rpmsg_instance *rpmsg_instance;
|
||||
struct rpmsg_mi_instance *instance;
|
||||
struct ipc_ept *ept;
|
||||
int err;
|
||||
|
||||
if (!cfg || !r_ept) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
instance = get_available_instance(cfg);
|
||||
if (instance == NULL) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
rpmsg_instance = &instance->rpmsg_inst;
|
||||
|
||||
if (!instance->is_initialized) {
|
||||
snprintf(instance->name, INST_NAME_SIZE, "rpmsg_mi_%d", instance->id);
|
||||
|
||||
instance->priority = cfg->prio;
|
||||
|
||||
err = init_instance(instance);
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
rpmsg_instance->bound_cb = bound_cb;
|
||||
rpmsg_instance->cb = ept_cb;
|
||||
|
||||
err = ipc_rpmsg_init(rpmsg_instance,
|
||||
instance->role,
|
||||
instance->vr.shm_io,
|
||||
&instance->vr.vdev,
|
||||
(void *) instance->vr.shm_device.regions->virt,
|
||||
instance->vr.shm_device.regions->size, NULL);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
instance->is_initialized = true;
|
||||
}
|
||||
|
||||
ept = get_available_ept_slot(rpmsg_instance);
|
||||
if (ept == NULL) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ept->name = cfg->name;
|
||||
ept->cb = &cfg->cb;
|
||||
ept->priv = cfg->priv;
|
||||
ept->bound = false;
|
||||
ept->ep.priv = ept;
|
||||
|
||||
err = ipc_rpmsg_register_ept(rpmsg_instance, instance->role, ept);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
*r_ept = ept;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const static struct ipc_service_backend backend = {
|
||||
.name = "RPMSG backend - static VRINGs (multi-instance)",
|
||||
.send = send,
|
||||
.register_endpoint = register_ept,
|
||||
};
|
||||
|
||||
static int backend_init(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
for (size_t i = 0; i < NUM_INSTANCES; i++) {
|
||||
instance[i].priority = PRIO_INIT_VAL;
|
||||
instance[i].id = i;
|
||||
instance[i].role = IS_ENABLED(CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_MASTER) ?
|
||||
VIRTIO_DEV_MASTER : VIRTIO_DEV_SLAVE;
|
||||
}
|
||||
|
||||
return ipc_service_register_backend(&backend);
|
||||
}
|
||||
SYS_INIT(backend_init, POST_KERNEL, CONFIG_IPC_SERVICE_REG_BACKEND_PRIORITY);
|
|
@ -4,13 +4,15 @@
|
|||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define SHM_DEVICE_NAME "sram0.shm"
|
||||
#define SHM_START_ADDR CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_SHM_BASE_ADDRESS
|
||||
#define SHM_SIZE CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_SHM_SIZE
|
||||
|
||||
#define VRING_ALIGNMENT (4) /* Alignment of vring buffer */
|
||||
#define VDEV_STATUS_SIZE (0x4) /* Size of status region */
|
||||
|
||||
#define RPMSG_VQ_0 (0) /* TX virtqueue queue index */
|
||||
#define RPMSG_VQ_1 (1) /* RX virtqueue queue index */
|
||||
#define VRING_COUNT (2) /* Number of used vring buffers. */
|
||||
|
||||
#define IPC_INSTANCE_COUNT (CONFIG_RPMSG_MULTI_INSTANCES_NO) /* Number of IPC instances.*/
|
||||
#define NUM_INSTANCES (CONFIG_IPC_SERVICE_BACKEND_RPMSG_MI_NUM_INSTANCES)
|
||||
|
||||
/* Private macros. */
|
||||
#define VRING_DESC_SIZEOF(num) ((num) * (sizeof(struct vring_desc)))
|
||||
|
@ -37,7 +39,7 @@
|
|||
(VRING_ALIGNMENT))))
|
||||
|
||||
/* Returns size of used shared memory consumed by all IPC instances*/
|
||||
#define SHMEM_CONSUMED_SIZE_GET(vring_size) (IPC_INSTANCE_COUNT * \
|
||||
#define SHMEM_CONSUMED_SIZE_GET(vring_size) (NUM_INSTANCES * \
|
||||
SHMEM_INST_SIZE_GET((vring_size)))
|
||||
|
||||
/* Returns maximum allowable size of vring buffers to fit memory requirements. */
|
||||
|
@ -60,8 +62,5 @@
|
|||
((shmem_addr) + \
|
||||
((id) * (SHMEM_INST_SIZE_AUTOALLOC_GET(shmem_size))))
|
||||
|
||||
#ifdef CONFIG_RPMSG_MULTI_INSTANCE_MASTER
|
||||
#define VIRTQUEUE_ID (0)
|
||||
#else
|
||||
#define VIRTQUEUE_ID (1)
|
||||
#endif
|
||||
#define VIRTQUEUE_ID_MASTER (0)
|
||||
#define VIRTQUEUE_ID_REMOTE (1)
|
162
subsys/ipc/ipc_service/backends/ipc_static_vrings.c
Normal file
162
subsys/ipc/ipc_service/backends/ipc_static_vrings.c
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Carlo Caione <ccaione@baylibre.com>
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <ipc/ipc_static_vrings.h>
|
||||
#include <cache.h>
|
||||
|
||||
#define SHM_DEVICE_NAME "sram0.shm"
|
||||
|
||||
#define VRING_ALIGNMENT (4) /* Alignment of vring buffer */
|
||||
|
||||
#define RPMSG_VQ_0 (0) /* TX virtqueue queue index */
|
||||
#define RPMSG_VQ_1 (1) /* RX virtqueue queue index */
|
||||
|
||||
static void virtio_notify(struct virtqueue *vq)
|
||||
{
|
||||
struct ipc_static_vrings *vr;
|
||||
|
||||
vr = CONTAINER_OF(vq->vq_dev, struct ipc_static_vrings, vdev);
|
||||
|
||||
if (vr->notify_cb) {
|
||||
vr->notify_cb(vq, vr->priv);
|
||||
}
|
||||
}
|
||||
|
||||
static void virtio_set_features(struct virtio_device *vdev, uint32_t features)
|
||||
{
|
||||
/* No need for implementation */
|
||||
}
|
||||
|
||||
static void virtio_set_status(struct virtio_device *p_vdev, unsigned char status)
|
||||
{
|
||||
struct ipc_static_vrings *vr;
|
||||
|
||||
if (p_vdev->role != VIRTIO_DEV_MASTER) {
|
||||
return;
|
||||
}
|
||||
|
||||
vr = CONTAINER_OF(p_vdev, struct ipc_static_vrings, vdev);
|
||||
|
||||
sys_write8(status, vr->status_reg_addr);
|
||||
sys_cache_data_range((void *) vr->status_reg_addr,
|
||||
sizeof(status), K_CACHE_WB);
|
||||
}
|
||||
|
||||
static uint32_t virtio_get_features(struct virtio_device *vdev)
|
||||
{
|
||||
return BIT(VIRTIO_RPMSG_F_NS);
|
||||
}
|
||||
|
||||
static unsigned char virtio_get_status(struct virtio_device *p_vdev)
|
||||
{
|
||||
struct ipc_static_vrings *vr;
|
||||
uint8_t ret;
|
||||
|
||||
vr = CONTAINER_OF(p_vdev, struct ipc_static_vrings, vdev);
|
||||
|
||||
ret = VIRTIO_CONFIG_STATUS_DRIVER_OK;
|
||||
|
||||
if (p_vdev->role == VIRTIO_DEV_SLAVE) {
|
||||
sys_cache_data_range((void *) vr->status_reg_addr,
|
||||
sizeof(ret), K_CACHE_INVD);
|
||||
ret = sys_read8(vr->status_reg_addr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const static struct virtio_dispatch dispatch = {
|
||||
.get_status = virtio_get_status,
|
||||
.get_features = virtio_get_features,
|
||||
.set_status = virtio_set_status,
|
||||
.set_features = virtio_set_features,
|
||||
.notify = virtio_notify,
|
||||
};
|
||||
|
||||
static int libmetal_setup(struct ipc_static_vrings *vr)
|
||||
{
|
||||
struct metal_init_params metal_params = METAL_INIT_DEFAULTS;
|
||||
struct metal_device *device;
|
||||
int err;
|
||||
|
||||
err = metal_init(&metal_params);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = metal_register_generic_device(&vr->shm_device);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
err = metal_device_open("generic", SHM_DEVICE_NAME, &device);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
vr->shm_io = metal_device_io_region(device, 0);
|
||||
if (vr->shm_io == NULL) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vq_setup(struct ipc_static_vrings *vr, unsigned int role)
|
||||
{
|
||||
vr->vq[RPMSG_VQ_0] = virtqueue_allocate(vr->vring_size);
|
||||
if (vr->vq[RPMSG_VQ_0] == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
vr->vq[RPMSG_VQ_1] = virtqueue_allocate(vr->vring_size);
|
||||
if (vr->vq[RPMSG_VQ_1] == NULL) {
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
vr->rvrings[RPMSG_VQ_0].io = vr->shm_io;
|
||||
vr->rvrings[RPMSG_VQ_0].info.vaddr = (void *) vr->tx_addr;
|
||||
vr->rvrings[RPMSG_VQ_0].info.num_descs = vr->vring_size;
|
||||
vr->rvrings[RPMSG_VQ_0].info.align = VRING_ALIGNMENT;
|
||||
vr->rvrings[RPMSG_VQ_0].vq = vr->vq[RPMSG_VQ_0];
|
||||
|
||||
vr->rvrings[RPMSG_VQ_1].io = vr->shm_io;
|
||||
vr->rvrings[RPMSG_VQ_1].info.vaddr = (void *) vr->rx_addr;
|
||||
vr->rvrings[RPMSG_VQ_1].info.num_descs = vr->vring_size;
|
||||
vr->rvrings[RPMSG_VQ_1].info.align = VRING_ALIGNMENT;
|
||||
vr->rvrings[RPMSG_VQ_1].vq = vr->vq[RPMSG_VQ_1];
|
||||
|
||||
vr->vdev.role = role;
|
||||
|
||||
vr->vdev.vrings_num = VRING_COUNT;
|
||||
vr->vdev.func = &dispatch;
|
||||
vr->vdev.vrings_info = &vr->rvrings[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ipc_static_vrings_init(struct ipc_static_vrings *vr, unsigned int role)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (!vr) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
vr->shm_device.name = SHM_DEVICE_NAME;
|
||||
vr->shm_device.num_regions = 1;
|
||||
vr->shm_physmap[0] = vr->shm_addr;
|
||||
|
||||
metal_io_init(vr->shm_device.regions, (void *) vr->shm_addr,
|
||||
vr->shm_physmap, vr->shm_size, -1, 0, NULL);
|
||||
|
||||
err = libmetal_setup(vr);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return vq_setup(vr, role);
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
zephyr_sources(rpmsg_multi_instance.c)
|
|
@ -1,75 +0,0 @@
|
|||
# Copyright (c) 2021 Nordic Semiconductor (ASA)
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
# Workaround for not being able to have commas in macro arguments
|
||||
DT_CHOSEN_Z_IPC_SHM := zephyr,ipc_shm
|
||||
|
||||
menuconfig RPMSG_MULTI_INSTANCE
|
||||
bool "RPMsg multiple instance"
|
||||
select IPM
|
||||
select OPENAMP
|
||||
help
|
||||
Enables support for RPMsg multiple instance.
|
||||
|
||||
if RPMSG_MULTI_INSTANCE
|
||||
|
||||
choice RPMSG_ROLE
|
||||
prompt "RPMSG device role"
|
||||
default RPMSG_MULTI_INSTANCE_REMOTE
|
||||
|
||||
config RPMSG_MULTI_INSTANCE_REMOTE
|
||||
bool "Remote"
|
||||
|
||||
config RPMSG_MULTI_INSTANCE_MASTER
|
||||
bool "Master"
|
||||
endchoice
|
||||
|
||||
config RPMSG_MULTI_INSTANCES_NO
|
||||
int "Number of RPMSG instances."
|
||||
default 2
|
||||
range 1 8
|
||||
help
|
||||
How many instances are to be used.
|
||||
|
||||
ipm_name_instance_num = 0
|
||||
rsource "Kconfig.ipm_name_instance"
|
||||
ipm_name_instance_num = 1
|
||||
rsource "Kconfig.ipm_name_instance"
|
||||
ipm_name_instance_num = 2
|
||||
rsource "Kconfig.ipm_name_instance"
|
||||
ipm_name_instance_num = 3
|
||||
rsource "Kconfig.ipm_name_instance"
|
||||
ipm_name_instance_num = 4
|
||||
rsource "Kconfig.ipm_name_instance"
|
||||
ipm_name_instance_num = 5
|
||||
rsource "Kconfig.ipm_name_instance"
|
||||
ipm_name_instance_num = 6
|
||||
rsource "Kconfig.ipm_name_instance"
|
||||
ipm_name_instance_num = 7
|
||||
rsource "Kconfig.ipm_name_instance"
|
||||
|
||||
config RPMSG_MULTI_INSTANCE_SHM_BASE_ADDRESS
|
||||
hex
|
||||
default "$(dt_chosen_reg_addr_hex,$(DT_CHOSEN_Z_IPC_SHM))"
|
||||
help
|
||||
This option specifies base address of the memory region to
|
||||
be used for the OpenAMP IPC shared memory.
|
||||
|
||||
config RPMSG_MULTI_INSTANCE_SHM_SIZE
|
||||
hex
|
||||
default "$(dt_chosen_reg_size_hex,$(DT_CHOSEN_Z_IPC_SHM))"
|
||||
help
|
||||
This option specifies size of the memory region to be used
|
||||
for the OpenAMP IPC shared memory.
|
||||
|
||||
config RPMSG_MULTI_INSTANCE_INIT_PRIORITY
|
||||
int "Initialization priority of RPMsg muliple instances"
|
||||
default 46
|
||||
help
|
||||
If in doubt, do not modify this value.
|
||||
|
||||
module = RPMSG_MULTI_INSTANCE
|
||||
module-str = RPMsg multi instance
|
||||
source "${ZEPHYR_BASE}/subsys/logging/Kconfig.template.log_config"
|
||||
|
||||
endif # RPMSG_MULTI_INSTANCE
|
|
@ -1,415 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Nordic Semiconductor ASA
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <ipc/rpmsg_multi_instance.h>
|
||||
#include <zephyr.h>
|
||||
#include <device.h>
|
||||
#include <logging/log.h>
|
||||
|
||||
#include <drivers/ipm.h>
|
||||
#include <openamp/open_amp.h>
|
||||
#include <cache.h>
|
||||
|
||||
#include "rpmsg_multi_instance.h"
|
||||
|
||||
LOG_MODULE_REGISTER(rpmsg_multi_instance, CONFIG_RPMSG_MULTI_INSTANCE_LOG_LEVEL);
|
||||
|
||||
K_MUTEX_DEFINE(shm_mutex);
|
||||
|
||||
static void rpmsg_service_unbind(struct rpmsg_endpoint *p_ep)
|
||||
{
|
||||
rpmsg_destroy_ept(p_ep);
|
||||
}
|
||||
|
||||
static unsigned char virtio_get_status(struct virtio_device *p_vdev)
|
||||
{
|
||||
struct rpmsg_mi_ctx *ctx = metal_container_of(p_vdev, struct rpmsg_mi_ctx, vdev);
|
||||
uint8_t ret = VIRTIO_CONFIG_STATUS_DRIVER_OK;
|
||||
|
||||
if (!IS_ENABLED(CONFIG_RPMSG_MULTI_INSTANCE_MASTER)) {
|
||||
sys_cache_data_range(&ctx->shm_status_reg_addr,
|
||||
sizeof(ctx->shm_status_reg_addr), K_CACHE_INVD);
|
||||
ret = sys_read8(ctx->shm_status_reg_addr);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static uint32_t virtio_get_features(struct virtio_device *vdev)
|
||||
{
|
||||
return BIT(VIRTIO_RPMSG_F_NS);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_RPMSG_MULTI_INSTANCE_MASTER
|
||||
|
||||
static void virtio_set_status(struct virtio_device *p_vdev, unsigned char status)
|
||||
{
|
||||
struct rpmsg_mi_ctx *ctx = metal_container_of(p_vdev, struct rpmsg_mi_ctx, vdev);
|
||||
|
||||
sys_write8(status, ctx->shm_status_reg_addr);
|
||||
sys_cache_data_range(&ctx->shm_status_reg_addr,
|
||||
sizeof(ctx->shm_status_reg_addr), K_CACHE_WB);
|
||||
}
|
||||
|
||||
static void virtio_set_features(struct virtio_device *vdev, uint32_t features)
|
||||
{
|
||||
/* No need for implementation */
|
||||
}
|
||||
#endif /* CONFIG_RPMSG_MULTI_INSTANCE_MASTER */
|
||||
|
||||
static void virtio_notify(struct virtqueue *vq)
|
||||
{
|
||||
struct rpmsg_mi_ctx *ctx = metal_container_of(vq->vq_dev, struct rpmsg_mi_ctx, vdev);
|
||||
int status;
|
||||
|
||||
if (ctx) {
|
||||
status = ipm_send(ctx->ipm_tx_handle, 0, ctx->ipm_tx_id, NULL, 0);
|
||||
if (status != 0) {
|
||||
LOG_WRN("Failed to notify: %d", status);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const static struct virtio_dispatch dispatch = {
|
||||
.get_status = virtio_get_status,
|
||||
.get_features = virtio_get_features,
|
||||
#ifdef CONFIG_RPMSG_MULTI_INSTANCE_MASTER
|
||||
.set_status = virtio_set_status,
|
||||
.set_features = virtio_set_features,
|
||||
#endif /* CONFIG_RPMSG_MULTI_INSTANCE_MASTER */
|
||||
.notify = virtio_notify,
|
||||
};
|
||||
|
||||
static void ipm_callback_process(struct k_work *item)
|
||||
{
|
||||
struct rpmsg_mi_ctx *ctx = CONTAINER_OF(item, struct rpmsg_mi_ctx, ipm_work);
|
||||
|
||||
LOG_DBG("Process callback. Instance name: %s", ctx->name);
|
||||
virtqueue_notification(ctx->vq[VIRTQUEUE_ID]);
|
||||
}
|
||||
|
||||
static void ipm_callback(const struct device *dev, void *context, uint32_t id, volatile void *data)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
struct rpmsg_mi_ctx *ctx = (struct rpmsg_mi_ctx *)context;
|
||||
|
||||
k_work_submit_to_queue(&ctx->ipm_work_q, &ctx->ipm_work);
|
||||
}
|
||||
|
||||
static void rpmsg_mi_configure_shm(struct rpmsg_mi_ctx *ctx, const struct rpmsg_mi_ctx_cfg *cfg)
|
||||
{
|
||||
size_t vring_size = VRING_SIZE_GET(cfg->shm->size);
|
||||
uintptr_t shm_addr = SHMEM_INST_ADDR_AUTOALLOC_GET(cfg->shm->addr,
|
||||
cfg->shm->size,
|
||||
cfg->shm->instance);
|
||||
size_t shm_size = SHMEM_INST_SIZE_AUTOALLOC_GET(cfg->shm->size);
|
||||
|
||||
uintptr_t shm_local_start_addr = shm_addr + VDEV_STATUS_SIZE;
|
||||
size_t shm_local_size = shm_size - VDEV_STATUS_SIZE;
|
||||
|
||||
size_t rpmsg_reg_size = VRING_COUNT * VIRTQUEUE_SIZE_GET(vring_size);
|
||||
size_t vring_region_size = VRING_SIZE_COMPUTE(vring_size, VRING_ALIGNMENT);
|
||||
|
||||
ctx->shm_status_reg_addr = shm_addr;
|
||||
ctx->shm_physmap[0] = shm_local_start_addr;
|
||||
|
||||
ctx->shm_device.name = SHM_DEVICE_NAME;
|
||||
ctx->shm_device.bus = NULL;
|
||||
ctx->shm_device.num_regions = 1;
|
||||
|
||||
ctx->shm_device.regions->virt = (void *)shm_local_start_addr;
|
||||
ctx->shm_device.regions->physmap = ctx->shm_physmap;
|
||||
|
||||
ctx->shm_device.regions->size = shm_local_size;
|
||||
ctx->shm_device.regions->page_shift = 0xffffffff;
|
||||
ctx->shm_device.regions->page_mask = 0xffffffff;
|
||||
ctx->shm_device.regions->mem_flags = 0;
|
||||
|
||||
ctx->shm_device.irq_num = 0;
|
||||
ctx->shm_device.irq_info = NULL;
|
||||
|
||||
ctx->vring_rx_addr = shm_local_start_addr + rpmsg_reg_size;
|
||||
ctx->vring_tx_addr = ctx->vring_rx_addr + vring_region_size;
|
||||
}
|
||||
|
||||
static int ept_cb(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv)
|
||||
{
|
||||
struct rpmsg_mi_ept *mi_ep = (struct rpmsg_mi_ept *)priv;
|
||||
|
||||
if (len == 0) {
|
||||
if (!mi_ep->bound) {
|
||||
LOG_DBG("Handshake done");
|
||||
rpmsg_send(ept, (uint8_t *) "", 0);
|
||||
mi_ep->bound = true;
|
||||
if (mi_ep->cb->bound) {
|
||||
mi_ep->cb->bound(mi_ep->priv);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mi_ep->cb->received) {
|
||||
mi_ep->cb->received(data, len, mi_ep->priv);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ns_bind_cb(struct rpmsg_device *rdev, const char *name, uint32_t dest)
|
||||
{
|
||||
sys_snode_t *node;
|
||||
struct rpmsg_virtio_device *p_rvdev = metal_container_of(rdev,
|
||||
struct rpmsg_virtio_device, rdev);
|
||||
struct rpmsg_mi_ctx *ctx = metal_container_of(p_rvdev, struct rpmsg_mi_ctx, rvdev);
|
||||
|
||||
LOG_DBG("bind_cb endpoint: %s, for instance: %s", name ? log_strdup(name) : "", ctx->name);
|
||||
|
||||
SYS_SLIST_FOR_EACH_NODE(&ctx->endpoints, node) {
|
||||
struct rpmsg_mi_ept *ept = CONTAINER_OF(node, struct rpmsg_mi_ept, node);
|
||||
|
||||
if (strcmp(name, ept->name) == 0) {
|
||||
LOG_DBG("Master - Create endpoint: %s", ept->name);
|
||||
|
||||
int err = rpmsg_create_ept(&ept->ep, rdev, name, RPMSG_ADDR_ANY,
|
||||
dest, ept_cb, rpmsg_service_unbind);
|
||||
if (err != 0) {
|
||||
LOG_ERR("Creating remote endpoint %s"
|
||||
" failed wirh error %d", name, err);
|
||||
} else {
|
||||
/* Notify the remote site that binding has occurred */
|
||||
rpmsg_send(&ept->ep, (uint8_t *)"", 0);
|
||||
|
||||
ept->bound = true;
|
||||
ept->cb->bound(ept->priv);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool rpmsg_mi_config_verify(const struct rpmsg_mi_ctx_cfg *cfg)
|
||||
{
|
||||
if (SHMEM_INST_SIZE_AUTOALLOC_GET(cfg->shm->size) * IPC_INSTANCE_COUNT > cfg->shm->size) {
|
||||
LOG_ERR("Not enough memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int libmetal_setup(struct rpmsg_mi_ctx *ctx)
|
||||
{
|
||||
struct metal_init_params metal_params = METAL_INIT_DEFAULTS;
|
||||
struct metal_device *device;
|
||||
int err;
|
||||
|
||||
err = metal_init(&metal_params);
|
||||
if (err) {
|
||||
LOG_ERR("metal_init: failed - error code %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = metal_register_generic_device(&ctx->shm_device);
|
||||
if (err) {
|
||||
LOG_ERR("Could not register shared memory device: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = metal_device_open("generic", SHM_DEVICE_NAME, &device);
|
||||
if (err) {
|
||||
LOG_ERR("metal_device_open failed: %d", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
ctx->shm_io = metal_device_io_region(device, 0);
|
||||
if (!ctx->shm_io) {
|
||||
LOG_ERR("metal_device_io_region failed to get region");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ipm_setup(struct rpmsg_mi_ctx *ctx, const struct rpmsg_mi_ctx_cfg *cfg)
|
||||
{
|
||||
int err;
|
||||
|
||||
ctx->ipm_tx_handle = device_get_binding(cfg->ipm_tx_name);
|
||||
if (!ctx->ipm_tx_handle) {
|
||||
LOG_ERR("Could not get TX IPM device handle");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
ctx->ipm_tx_id = cfg->ipm_tx_id;
|
||||
|
||||
ctx->ipm_rx_handle = device_get_binding(cfg->ipm_rx_name);
|
||||
if (!ctx->ipm_rx_handle) {
|
||||
LOG_ERR("Could not get RX IPM device handle");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
k_work_queue_start(&ctx->ipm_work_q, cfg->ipm_stack_area,
|
||||
cfg->ipm_stack_size, cfg->ipm_work_q_prio, NULL);
|
||||
k_thread_name_set(&ctx->ipm_work_q.thread, cfg->ipm_thread_name);
|
||||
|
||||
k_work_init(&ctx->ipm_work, ipm_callback_process);
|
||||
|
||||
ipm_register_callback(ctx->ipm_rx_handle, ipm_callback, ctx);
|
||||
|
||||
err = ipm_set_enabled(ctx->ipm_rx_handle, 1);
|
||||
if (err != 0) {
|
||||
LOG_ERR("Could not enable IPM interrupts and callbacks for RX");
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vq_setup(struct rpmsg_mi_ctx *ctx, size_t vring_size)
|
||||
{
|
||||
ctx->vq[RPMSG_VQ_0] = virtqueue_allocate(vring_size);
|
||||
if (!ctx->vq[RPMSG_VQ_0]) {
|
||||
LOG_ERR("virtqueue_allocate failed to alloc vq[RPMSG_VQ_0]");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ctx->vq[RPMSG_VQ_1] = virtqueue_allocate(vring_size);
|
||||
if (!ctx->vq[RPMSG_VQ_1]) {
|
||||
LOG_ERR("virtqueue_allocate failed to alloc vq[RPMSG_VQ_1]");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ctx->rvrings[RPMSG_VQ_0].io = ctx->shm_io;
|
||||
ctx->rvrings[RPMSG_VQ_0].info.vaddr = (void *)ctx->vring_tx_addr;
|
||||
ctx->rvrings[RPMSG_VQ_0].info.num_descs = vring_size;
|
||||
ctx->rvrings[RPMSG_VQ_0].info.align = VRING_ALIGNMENT;
|
||||
ctx->rvrings[RPMSG_VQ_0].vq = ctx->vq[RPMSG_VQ_0];
|
||||
|
||||
ctx->rvrings[RPMSG_VQ_1].io = ctx->shm_io;
|
||||
ctx->rvrings[RPMSG_VQ_1].info.vaddr = (void *)ctx->vring_rx_addr;
|
||||
ctx->rvrings[RPMSG_VQ_1].info.num_descs = vring_size;
|
||||
ctx->rvrings[RPMSG_VQ_1].info.align = VRING_ALIGNMENT;
|
||||
ctx->rvrings[RPMSG_VQ_1].vq = ctx->vq[RPMSG_VQ_1];
|
||||
|
||||
ctx->vdev.role = IS_ENABLED(CONFIG_RPMSG_MULTI_INSTANCE_MASTER) ?
|
||||
RPMSG_MASTER : RPMSG_REMOTE;
|
||||
|
||||
ctx->vdev.vrings_num = VRING_COUNT;
|
||||
ctx->vdev.func = &dispatch;
|
||||
ctx->vdev.vrings_info = &ctx->rvrings[0];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rpmsg_mi_ctx_init(struct rpmsg_mi_ctx *ctx, const struct rpmsg_mi_ctx_cfg *cfg)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (!ctx || !cfg) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
LOG_DBG("RPMsg multiple instance initialization");
|
||||
|
||||
if (!rpmsg_mi_config_verify(cfg)) {
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
k_mutex_lock(&shm_mutex, K_FOREVER);
|
||||
|
||||
/* Configure shared memory */
|
||||
rpmsg_mi_configure_shm(ctx, cfg);
|
||||
|
||||
/* Setup libmetal */
|
||||
err = libmetal_setup(ctx);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to setup libmetal");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Setup IPM */
|
||||
err = ipm_setup(ctx, cfg);
|
||||
if (err) {
|
||||
LOG_ERR("Failed to setup IPM");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Setup VQs / VRINGs */
|
||||
err = vq_setup(ctx, VRING_SIZE_GET(cfg->shm->size));
|
||||
if (err) {
|
||||
LOG_ERR("Failed to setup VQs / VRINGs");
|
||||
goto out;
|
||||
}
|
||||
|
||||
ctx->name = cfg->name;
|
||||
sys_slist_init(&ctx->endpoints);
|
||||
|
||||
if (IS_ENABLED(CONFIG_RPMSG_MULTI_INSTANCE_MASTER)) {
|
||||
/* This step is only required if you are VirtIO device master.
|
||||
* Initialize the shared buffers pool.
|
||||
*/
|
||||
rpmsg_virtio_init_shm_pool(&ctx->shpool, (void *) ctx->shm_device.regions->virt,
|
||||
ctx->shm_device.regions->size);
|
||||
|
||||
err = rpmsg_init_vdev(&ctx->rvdev, &ctx->vdev, ns_bind_cb,
|
||||
ctx->shm_io, &ctx->shpool);
|
||||
} else {
|
||||
err = rpmsg_init_vdev(&ctx->rvdev, &ctx->vdev, NULL, ctx->shm_io, NULL);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
LOG_ERR("RPMSG vdev initialization failed %d", err);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get RPMsg device from RPMsg VirtIO device. */
|
||||
ctx->rdev = rpmsg_virtio_get_rpmsg_device(&ctx->rvdev);
|
||||
|
||||
cfg->shm->instance++;
|
||||
|
||||
LOG_DBG("RPMsg multiple instance initialization done");
|
||||
|
||||
out:
|
||||
k_mutex_unlock(&shm_mutex);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int rpmsg_mi_ept_register(struct rpmsg_mi_ctx *ctx, struct rpmsg_mi_ept *ept,
|
||||
struct rpmsg_mi_ept_cfg *cfg)
|
||||
{
|
||||
if (!ctx || !ept || !cfg) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ept->cb = cfg->cb;
|
||||
ept->priv = cfg->priv;
|
||||
ept->ep.priv = ept;
|
||||
ept->bound = false;
|
||||
ept->name = cfg->name;
|
||||
|
||||
sys_slist_append(&ctx->endpoints, &ept->node);
|
||||
|
||||
if (!IS_ENABLED(CONFIG_RPMSG_MULTI_INSTANCE_MASTER)) {
|
||||
LOG_DBG("Remote - Create endpoint: %s", ept->name);
|
||||
|
||||
int err = rpmsg_create_ept(&ept->ep, ctx->rdev, ept->name, RPMSG_ADDR_ANY,
|
||||
RPMSG_ADDR_ANY, ept_cb, rpmsg_service_unbind);
|
||||
|
||||
if (err != 0) {
|
||||
LOG_ERR("RPMSG endpoint create failed %d", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rpmsg_mi_send(struct rpmsg_mi_ept *ept, const void *data, size_t len)
|
||||
{
|
||||
return rpmsg_send(&ept->ep, data, len);
|
||||
}
|
Loading…
Reference in a new issue