This patch is the first step to make the rpmsg_multi_instance usable in a multi-core scenario. The current driver is using a local driver variable (instance) to track the number of allocated instances. This counter is practically used to allocate to the instance the correct portion of the shared memory. This is fundamentally wrong because this is assuming that it does exist only one single shared memory region to split amongs all the allocated instances. When the platform has more than one core this is obviously not the case since each couple of cores are communicating using a different memory region. To solve this issue we introduce a new struct rpmsg_mi_ctx_shm_cfg that is doing two things: (1) it's carrying the information about the shared memory and (2) it's carrying an internal variable used to track the instances allocated in that region. The same struct should be used every time a new instance is allocated in the same shared memory region. We also fix a problem with the current code where there is a race between threads when accessing the instance variable, so this patch is adding a serializing mutex. Signed-off-by: Carlo Caione <ccaione@baylibre.com>
218 lines
5.3 KiB
C
218 lines
5.3 KiB
C
/*
|
|
* 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);
|
|
}
|