zephyr/samples/subsys/ipc/rpmsg_multi_instance/src/main.c
Carlo Caione 0c2dabb4b9 ipc: rpmsg_multi_instance: Rework instance tracking
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>
2021-08-27 06:44:08 -04:00

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);
}