mirror of
https://github.com/Fishwaldo/OBLFR.git
synced 2025-03-15 11:21:23 +00:00
RPMsg, Mailbox updates (#10)
* Update Readme * Port the IRQ_Forward Code to a component So it can be used in any M0 firmware * update d0_lowload to use new IRQ forwarding code * Enable Ethernet, USB, and GPIO forwarding as well * add RPMSG component * Fix crash if there are no timers registered. * Update rpmsg and mailbox code for latest kernel updates
This commit is contained in:
parent
e36316fa13
commit
53ceb5fd82
37 changed files with 7208 additions and 28 deletions
20
apps/examples/rpmsg/CMakeLists.txt
Normal file
20
apps/examples/rpmsg/CMakeLists.txt
Normal file
|
@ -0,0 +1,20 @@
|
|||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
# Get SDK path
|
||||
if(NOT SDK_PATH)
|
||||
get_filename_component(SDK_PATH ../../../ ABSOLUTE)
|
||||
if(EXISTS $ENV{OBLFR_SDK_PATH})
|
||||
set(SDK_PATH $ENV{OBLFR_SDK_PATH})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Check SDK Path
|
||||
if(NOT EXISTS ${SDK_PATH})
|
||||
message(FATAL_ERROR "SDK path Error, Please set OBLFR_SDK_PATH variable")
|
||||
endif()
|
||||
|
||||
include(${SDK_PATH}/cmake/bflbsdk.cmake)
|
||||
|
||||
target_compile_options(app PRIVATE -ggdb -Os)
|
||||
sdk_set_main_file(src/main.c)
|
||||
project(rpmsgdemo)
|
7
apps/examples/rpmsg/Makefile
Normal file
7
apps/examples/rpmsg/Makefile
Normal file
|
@ -0,0 +1,7 @@
|
|||
OBLFR_SDK_PATH := $(realpath $(dir $(realpath $(lastword $(MAKEFILE_LIST))))../../../)
|
||||
|
||||
-include sdkconfig
|
||||
|
||||
CPU_ID = m0
|
||||
|
||||
include $(OBLFR_SDK_PATH)/cmake/project.build
|
9
apps/examples/rpmsg/README.md
Normal file
9
apps/examples/rpmsg/README.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
## RPMSG demo
|
||||
|
||||
This is a demo application that emulates a TTY and RAW channel between M0 and Linux running
|
||||
on the D0 core.
|
||||
|
||||
Once running, the application will create a TTY device and a RAW device. The TTY device will
|
||||
be available at /dev/ttyRPMSG0 and the RAW device will be available at /dev/rpmsg0. on linux
|
||||
|
||||
This requires the remoteproc driver to be enabled in the linux kernel.
|
4
apps/examples/rpmsg/sdkconfig.default
Normal file
4
apps/examples/rpmsg/sdkconfig.default
Normal file
|
@ -0,0 +1,4 @@
|
|||
CONFIG_COMPONENT_MAILBOX=y
|
||||
CONFIG_COMPONENT_MAILBOX_IRQFWD_SDH=y
|
||||
CONFIG_COMPONENT_MAILBOX_IRQFWD_GPIO=y
|
||||
CONFIG_COMPONENT_RPMSG=y
|
112
apps/examples/rpmsg/src/main.c
Executable file
112
apps/examples/rpmsg/src/main.c
Executable file
|
@ -0,0 +1,112 @@
|
|||
/**
|
||||
* @file main.c
|
||||
* @brief
|
||||
*
|
||||
* Copyright (c) 2023 Justin Hammond
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership. The
|
||||
* ASF licenses this file to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the
|
||||
* License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <board.h>
|
||||
#include <bflb_mtimer.h>
|
||||
#include "oblfr_mailbox.h"
|
||||
#include "oblfr_rpmsg.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define DBG_TAG "MAIN"
|
||||
#include <log.h>
|
||||
|
||||
void tty_cb(void *data, size_t len, void *priv)
|
||||
{
|
||||
LOG_I("tty_cb: %s\r\n", data);
|
||||
}
|
||||
|
||||
void raw_cb(void *data, size_t len, void *priv)
|
||||
{
|
||||
LOG_I("raw_cb: %s\r\n", data);
|
||||
}
|
||||
|
||||
void haha_cb(void *data, size_t len, void *priv)
|
||||
{
|
||||
LOG_I("haha_cb: %s\r\n", data);
|
||||
}
|
||||
|
||||
int app_main(void)
|
||||
{
|
||||
// board_init();
|
||||
|
||||
LOG_I("Starting Mailbox Handlers\r\n");
|
||||
|
||||
if (oblfr_mailbox_init() != OBLFR_OK)
|
||||
{
|
||||
LOG_E("oblfr_mailbox_init failed\r\n");
|
||||
while (1)
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
LOG_I("Running...\r\n");
|
||||
if (init_rpmsg(NULL) != OBLFR_OK)
|
||||
{
|
||||
LOG_E("init_rpmsg failed\r\n");
|
||||
while (1)
|
||||
{
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
oblfr_device_cfg_t endpoint = {
|
||||
.name = "rpmsg-tty",
|
||||
.cb = tty_cb,
|
||||
.priv = NULL,
|
||||
};
|
||||
oblfr_queue_entry_t *ttyhandle = oblfr_rpmsg_device_add(&endpoint);
|
||||
|
||||
oblfr_device_cfg_t endpoint2 = {
|
||||
.name = "rpmsg-raw",
|
||||
.cb = raw_cb,
|
||||
.priv = NULL,
|
||||
};
|
||||
oblfr_rpmsg_device_add(&endpoint2);
|
||||
|
||||
oblfr_device_cfg_t endpoint3 = {
|
||||
.name = "haha",
|
||||
.cb = haha_cb,
|
||||
.priv = NULL,
|
||||
};
|
||||
oblfr_queue_entry_t *handle = oblfr_rpmsg_device_add(&endpoint3);
|
||||
char txdata[] = "Hello from M0";
|
||||
LOG_I("You can now open and send messages from linux on /dev/ttyRPMSG0\r\n");
|
||||
while (1)
|
||||
{
|
||||
bflb_mtimer_delay_ms(6000);
|
||||
if (handle && (oblfr_rpmsg_device_remove(handle) != OBLFR_OK))
|
||||
{
|
||||
LOG_E("oblfr_rpmsg_remove_endpoint failed\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
handle = NULL;
|
||||
}
|
||||
if (oblfr_rpmsg_device_send(ttyhandle, txdata, sizeof(txdata), OBLFR_NO_BLOCK) != OBLFR_OK)
|
||||
{
|
||||
LOG_E("oblfr_rpmsg_device_send failed\r\n");
|
||||
}
|
||||
oblfr_rpmsg_dump();
|
||||
}
|
||||
}
|
|
@ -6,4 +6,5 @@ sdk_add_subdirectory_ifdef(CONFIG_COMPONENT_BUTTON button)
|
|||
sdk_add_subdirectory_ifdef(CONFIG_COMPONENT_STATUS_LED indicator)
|
||||
sdk_add_subdirectory_ifdef(CONFIG_COMPONENT_TIMER timer)
|
||||
sdk_add_subdirectory_ifdef(CONFIG_COMPONENT_NVKVS nvkvs)
|
||||
sdk_add_subdirectory_ifdef(CONFIG_COMPONENT_MAILBOX mailbox)
|
||||
sdk_add_subdirectory_ifdef(CONFIG_COMPONENT_RPMSG rpmsg)
|
||||
sdk_add_subdirectory_ifdef(CONFIG_COMPONENT_MAILBOX mailbox)
|
||||
|
|
|
@ -13,11 +13,24 @@
|
|||
#define BLFB_IPC_DEVICE_USB 2
|
||||
#define BFLB_IPC_DEVICE_EMAC 3
|
||||
#define BFLB_IPC_DEVICE_GPIO 4
|
||||
#define BFLB_IPC_DEVICE_MAILBOX 5
|
||||
#define BFLB_IPC_DEVICE_MBOX_TX 5
|
||||
#define BFLB_IPC_DEVICE_MBOX_RX 6
|
||||
|
||||
/* MailBox Service */
|
||||
#define BFLB_IPC_MBOX_VIRTIO 1
|
||||
|
||||
/* Operations for MBOX_VIRTIO */
|
||||
#define BFLB_IPC_MBOX_VIRTIO_OP_KICK 1
|
||||
|
||||
typedef void (*mbox_signal_handler_t)(uint16_t service, uint16_t op, uint32_t param, void *arg);
|
||||
|
||||
oblfr_err_t oblfr_mailbox_init(void);
|
||||
|
||||
oblfr_err_t oblfr_mailbox_dump();
|
||||
|
||||
oblfr_err_t oblfr_mailbox_add_signal_handler(uint16_t service, uint16_t op, mbox_signal_handler_t handler, void *arg);
|
||||
oblfr_err_t oblfr_mailbox_del_signal_handler(uint16_t service, uint16_t op );
|
||||
oblfr_err_t oblfr_mailbox_send_signal(uint16_t service, uint16_t op, uint32_t data);
|
||||
oblfr_err_t oblfr_mailbox_mask_signal(uint16_t service, uint16_t op);
|
||||
oblfr_err_t oblfr_mailbox_unmask_signal(uint16_t service, uint16_t op);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
// Copyright 2020-2021 Espressif Systems (Shanghai) CO LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <sys/queue.h>
|
||||
#include <board.h>
|
||||
#include <bl808.h>
|
||||
#include <bl808_common.h>
|
||||
|
@ -21,6 +8,11 @@
|
|||
#include <ipc_reg.h>
|
||||
#include <bflb_clock.h>
|
||||
#include <bflb_gpio.h>
|
||||
#ifdef CONFIG_FREERTOS
|
||||
#include <FreeRTOS.h>
|
||||
#include <semphr.h>
|
||||
#endif
|
||||
|
||||
#include "oblfr_mailbox.h"
|
||||
#define DBG_TAG "MBOX"
|
||||
#include "log.h"
|
||||
|
@ -37,6 +29,67 @@ typedef struct {
|
|||
void (*handler)(int irq, void *arg);
|
||||
} mbox_irq_t;
|
||||
|
||||
typedef struct mbox_signal_s {
|
||||
uint16_t service;
|
||||
uint16_t op;
|
||||
mbox_signal_handler_t handler;
|
||||
void *arg;
|
||||
uint32_t count;
|
||||
bool masked;
|
||||
LIST_ENTRY(mbox_signal_s) list_entry;
|
||||
} mbox_signal_t;
|
||||
|
||||
static LIST_HEAD(oblfr_mbox_signals, mbox_signal_s) oblfr_mbox_signals = LIST_HEAD_INITIALIZER(oblfr_mbox_signals);
|
||||
|
||||
typedef struct mbox_stats_s {
|
||||
uint32_t unhandled_irq;
|
||||
uint32_t unhandled_signals;
|
||||
} mbox_stats_t;
|
||||
|
||||
static mbox_stats_t mbox_stats = {0};
|
||||
|
||||
#ifdef CONFIG_FREERTOS
|
||||
static SemaphoreHandle_t oblfr_mbox_signals_lock = NULL;
|
||||
#endif
|
||||
|
||||
static bool oblfr_mailbox_signal_lock(bool inisr) {
|
||||
#ifdef CONFIG_FREERTOS
|
||||
if (inisr) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
if (xSemaphoreTakeFromISR(oblfr_mbox_signals_lock, &xHigherPriorityTaskWoken) != pdPASS) {
|
||||
LOG_E("Failed to take mbox signals list lock\r\n");
|
||||
return false;
|
||||
}
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
} else {
|
||||
if (xSemaphoreTake(oblfr_mbox_signals_lock, pdMS_TO_TICKS(2000)) != pdPASS) {
|
||||
LOG_E("Failed to take mbox signals list lock\r\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool oblfr_mailbox_signal_unlock(bool inisr) {
|
||||
#ifdef CONFIG_FREERTOS
|
||||
if (inisr) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
if (xSemaphoreGiveFromISR(oblfr_mbox_signals_lock, &xHigherPriorityTaskWoken) != pdPASS) {
|
||||
LOG_E("Failed to give mbox signals list lock\r\n");
|
||||
return false;
|
||||
}
|
||||
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
|
||||
} else {
|
||||
if (xSemaphoreGive(oblfr_mbox_signals_lock) != pdPASS) {
|
||||
LOG_E("Failed to give mbox signals list lock\r\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
static void Send_IPC_IRQ(int device);
|
||||
|
||||
#ifdef CONFIG_COMPONENT_MAILBOX_IRQFWD_SDH
|
||||
|
@ -79,7 +132,7 @@ static void GPIO_IRQHandler(int irq, void *arg)
|
|||
}
|
||||
#endif
|
||||
|
||||
static mbox_irq_t ipc_irqs[32] = {
|
||||
mbox_irq_t ipc_irqs[32] = {
|
||||
#ifdef CONFIG_COMPONENT_MAILBOX_IRQFWD_SDH
|
||||
[BFLB_IPC_DEVICE_SDHCI] = { "SDH", SDH_IRQn, 0, SDHCI_IRQHandler},
|
||||
#endif
|
||||
|
@ -97,7 +150,6 @@ static mbox_irq_t ipc_irqs[32] = {
|
|||
#endif
|
||||
};
|
||||
|
||||
|
||||
static void Send_IPC_IRQ(int device)
|
||||
{
|
||||
if (ipc_irqs[device].irq == 0) {
|
||||
|
@ -109,6 +161,51 @@ static void Send_IPC_IRQ(int device)
|
|||
ipc_irqs[device].count++;
|
||||
}
|
||||
|
||||
static void oblfr_mailbox_signal_handler(int irq, void *arg)
|
||||
{
|
||||
struct mbox_signal_s *s;
|
||||
|
||||
uint32_t signal = BL_RD_REG(IPC0_BASE, IPC_CPU1_IPC_ILSHR);
|
||||
uint32_t data = BL_RD_REG(IPC0_BASE, IPC_CPU1_IPC_ILSLR);
|
||||
|
||||
uint16_t service = (signal >> 16);
|
||||
uint16_t op = (signal & 0xFFFF);
|
||||
|
||||
LOG_D("Got IPC Mailbox Service: %d, Operation: %d Data: %d\r\n", service, op, data);
|
||||
|
||||
bool handled = false;
|
||||
if (!oblfr_mailbox_signal_lock(true)) {
|
||||
LOG_W("%s Can't Take Signal Lock\r\n", __FUNCTION__);
|
||||
goto err;
|
||||
}
|
||||
LIST_FOREACH(s, &oblfr_mbox_signals, list_entry) {
|
||||
if ((s->service == service) & (s->op = op)) {
|
||||
handled = true;
|
||||
if (s->masked) {
|
||||
LOG_D("Signal %d masked\r\n", signal);
|
||||
break;
|
||||
}
|
||||
__asm volatile ("fence":::"memory");
|
||||
s->handler(service, op, data, s->arg);
|
||||
s->count++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
oblfr_mailbox_signal_unlock(true);
|
||||
|
||||
if (!handled) {
|
||||
LOG_W("Got IPC MBOX for unknown service %d, op %d\r\n", service, op);
|
||||
mbox_stats.unhandled_signals++;
|
||||
}
|
||||
|
||||
err:
|
||||
/* send a EOI */
|
||||
BL_WR_REG(IPC2_BASE, IPC_CPU1_IPC_ISWR, (1 << BFLB_IPC_DEVICE_MBOX_RX));
|
||||
LOG_D("Signal Handler Done\r\n");
|
||||
|
||||
|
||||
}
|
||||
|
||||
void IPC_M0_IRQHandler(int irq, void *arg)
|
||||
{
|
||||
int i;
|
||||
|
@ -116,15 +213,20 @@ void IPC_M0_IRQHandler(int irq, void *arg)
|
|||
for (i = 0; i < sizeof(irqStatus) * 8; i++)
|
||||
{
|
||||
if (irqStatus & (1 << i)) {
|
||||
if (i == BFLB_IPC_DEVICE_MAILBOX) {
|
||||
LOG_I("Got Mailbox IRQ\r\n");
|
||||
if (i == BFLB_IPC_DEVICE_MBOX_RX) {
|
||||
oblfr_mailbox_signal_handler(irq, arg);
|
||||
break;
|
||||
} else if (i == BFLB_IPC_DEVICE_MBOX_TX) {
|
||||
LOG_D("Got IPC MBOX TX EOI\r");
|
||||
break;
|
||||
} else {
|
||||
if (ipc_irqs[i].irq == 0) {
|
||||
LOG_W("Got IPC IRQ for unknown peripheral %d\r\n", i);
|
||||
mbox_stats.unhandled_irq++;
|
||||
} else {
|
||||
LOG_T("Got IPC EOI for Peripheral %s (%d - %d)\r\n", ipc_irqs[i].name, irqStatus, ipc_irqs[i].irq);
|
||||
//assert(irqStatus == ipc_irqs[irqStatus].irq);
|
||||
bflb_irq_enable(ipc_irqs[i].irq);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -168,10 +270,122 @@ static oblfr_err_t setup_emac_peripheral(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
oblfr_err_t oblfr_mailbox_add_signal_handler(uint16_t service, uint16_t op, mbox_signal_handler_t handler, void *arg)
|
||||
{
|
||||
struct mbox_signal_s *s;
|
||||
if (!oblfr_mailbox_signal_lock(false)) {
|
||||
LOG_W("%s Can't Take Signal Lock\r\n", __FUNCTION__);
|
||||
return OBLFR_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
LIST_FOREACH(s, &oblfr_mbox_signals, list_entry) {
|
||||
if ((s->service == service) & (s->op = op)) {
|
||||
LOG_W("Service %d Op %d already registered\r\n", service, op);
|
||||
oblfr_mailbox_signal_unlock(false);
|
||||
return OBLFR_ERR_INVALID;
|
||||
}
|
||||
}
|
||||
|
||||
mbox_signal_t *newsig = malloc(sizeof(mbox_signal_t));
|
||||
if (!newsig) {
|
||||
LOG_W("Can't allocate signal\r\n");
|
||||
oblfr_mailbox_signal_unlock(false);
|
||||
return OBLFR_ERR_NOMEM;
|
||||
}
|
||||
|
||||
newsig->service = service;
|
||||
newsig->op = op;
|
||||
newsig->handler = handler;
|
||||
newsig->arg = arg;
|
||||
newsig->count = 0;
|
||||
newsig->masked = false;
|
||||
newsig->list_entry.le_next = NULL;
|
||||
|
||||
LIST_INSERT_HEAD(&oblfr_mbox_signals, newsig, list_entry);
|
||||
LOG_D("Added Signal Handler for Service %d, Op %d\r\n", service, op);
|
||||
oblfr_mailbox_signal_unlock(false);
|
||||
return OBLFR_OK;
|
||||
}
|
||||
|
||||
oblfr_err_t oblfr_mailbox_del_signal_handler(uint16_t service, uint16_t op) {
|
||||
struct mbox_signal_s *s;
|
||||
if (!oblfr_mailbox_signal_lock(false)) {
|
||||
LOG_W("Can't Take Signal Lock\r\n");
|
||||
return OBLFR_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
LIST_FOREACH(s, &oblfr_mbox_signals, list_entry) {
|
||||
if ((s->service == service) & (s->op == op)) {
|
||||
LOG_D("Deleting Signal Handler for Service %d, op %d \r\n", service, op);
|
||||
LIST_REMOVE(s, list_entry);
|
||||
break;
|
||||
}
|
||||
}
|
||||
oblfr_mailbox_signal_unlock(false);
|
||||
return OBLFR_OK;
|
||||
}
|
||||
|
||||
oblfr_err_t oblfr_mailbox_send_signal(uint16_t service, uint16_t op, uint32_t arg)
|
||||
{
|
||||
uint32_t tmpVal = (service << 16) | op;
|
||||
BL_WR_REG(IPC2_BASE, IPC_CPU0_IPC_ILSHR, tmpVal);
|
||||
BL_WR_REG(IPC2_BASE, IPC_CPU0_IPC_ILSLR, arg);
|
||||
|
||||
LOG_D("Sent IPC Mailbox Singal: service %d op: %d, arg %d\r\n", service, op, arg);
|
||||
|
||||
/* trigger a IPC */
|
||||
BL_WR_REG(IPC2_BASE, IPC_CPU1_IPC_ISWR, (1 << BFLB_IPC_DEVICE_MBOX_TX));
|
||||
|
||||
return OBLFR_OK;
|
||||
}
|
||||
|
||||
oblfr_err_t oblfr_mailbox_mask_signal(uint16_t service, uint16_t op)
|
||||
{
|
||||
struct mbox_signal_s *s;
|
||||
if (!oblfr_mailbox_signal_lock(false)) {
|
||||
LOG_W("Can't Take Signal Lock\r\n");
|
||||
return OBLFR_ERR_TIMEOUT;
|
||||
}
|
||||
|
||||
LIST_FOREACH(s, &oblfr_mbox_signals, list_entry) {
|
||||
if ((s->service == service) & (s->op == op)) {
|
||||
// s->masked = true;
|
||||
LOG_D("Masked Signal Service %d, Op %d\r\n", service, op);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
oblfr_mailbox_signal_unlock(false);
|
||||
return OBLFR_OK;
|
||||
}
|
||||
|
||||
oblfr_err_t oblfr_mailbox_unmask_signal(uint16_t service, uint16_t op)
|
||||
{
|
||||
struct mbox_signal_s *s;
|
||||
if (!oblfr_mailbox_signal_lock(false)) {
|
||||
LOG_W("Can't Take Signal Lock\r\n");
|
||||
return OBLFR_ERR_TIMEOUT;
|
||||
}
|
||||
LIST_FOREACH(s, &oblfr_mbox_signals, list_entry) {
|
||||
if ((s->service == service) & (s->op == op)) {
|
||||
// s->masked = false;
|
||||
LOG_D("Unmasked Signal Service %d, Op %d\r\n", service, op);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
oblfr_mailbox_signal_unlock(false);
|
||||
return OBLFR_OK;
|
||||
}
|
||||
|
||||
oblfr_err_t oblfr_mailbox_init()
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_FREERTOS
|
||||
oblfr_mbox_signals_lock = xSemaphoreCreateMutex();
|
||||
#endif
|
||||
|
||||
/* setup the IPC Interupt */
|
||||
bflb_irq_attach(IPC_M0_IRQn, IPC_M0_IRQHandler, NULL);
|
||||
BL_WR_REG(IPC0_BASE, IPC_CPU0_IPC_IUSR, 0xffffffff);
|
||||
|
@ -206,12 +420,27 @@ oblfr_err_t oblfr_mailbox_init()
|
|||
|
||||
oblfr_err_t oblfr_mailbox_dump()
|
||||
{
|
||||
struct mbox_signal_s *s;
|
||||
LOG_I("Mailbox IRQ Stats:\r\n");
|
||||
for (uint8_t i = 0; i < sizeof(ipc_irqs) / sizeof(ipc_irqs[0]); i++) {
|
||||
if (ipc_irqs[i].irq != 0) {
|
||||
LOG_I("Peripheral %s (%d): %d\r\n", ipc_irqs[i].name, ipc_irqs[i].irq, ipc_irqs[i].count);
|
||||
LOG_I("\tPeripheral %s (%d): %d\r\n", ipc_irqs[i].name, ipc_irqs[i].irq, ipc_irqs[i].count);
|
||||
}
|
||||
}
|
||||
if (!oblfr_mailbox_signal_lock(false)) {
|
||||
LOG_W("%s Can't Take Signal Lock\r\n", __FUNCTION__);
|
||||
return OBLFR_ERR_TIMEOUT;
|
||||
}
|
||||
if (LIST_FIRST(&oblfr_mbox_signals)) {
|
||||
LOG_I("Mailbox Signal Stats:\r\n");
|
||||
LIST_FOREACH(s, &oblfr_mbox_signals, list_entry) {
|
||||
LOG_I("Service %d, Op %d: %d\r\n", s->service, s->op, s->count);
|
||||
}
|
||||
}
|
||||
LOG_I("Unhandled Interupts: %d Unhandled Signals %d\r\n", mbox_stats.unhandled_irq, mbox_stats.unhandled_signals);
|
||||
LOG_I("====================================\r\n");
|
||||
|
||||
oblfr_mailbox_signal_unlock(false);
|
||||
return OBLFR_OK;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,6 +66,7 @@
|
|||
#define configIDLE_SHOULD_YIELD 0
|
||||
#define configUSE_MUTEXES 1
|
||||
#define configQUEUE_REGISTRY_SIZE 8
|
||||
#define configUSE_QUEUE_SETS 1
|
||||
#define configCHECK_FOR_STACK_OVERFLOW CONFIG_COMPONENT_SYSTEM_CHECK_STACK_OVERFLOW
|
||||
#define configUSE_RECURSIVE_MUTEXES 1
|
||||
#define configUSE_MALLOC_FAILED_HOOK 1
|
||||
|
|
|
@ -31,6 +31,9 @@ typedef enum {
|
|||
|
||||
typedef int oblfr_err_t;
|
||||
|
||||
|
||||
typedef enum {
|
||||
OBLFR_NO_BLOCK = 0,
|
||||
OBLFR_BLOCK = 0xFFFFFFFFU,
|
||||
} OBLFR_Timeout;
|
||||
|
||||
#endif
|
5
components/rpmsg/CMakeLists.txt
Normal file
5
components/rpmsg/CMakeLists.txt
Normal file
|
@ -0,0 +1,5 @@
|
|||
add_subdirectory(rpmsg-lite)
|
||||
sdk_generate_library(oblfr_rpmsg)
|
||||
sdk_add_include_directories(include)
|
||||
sdk_library_add_sources(${CMAKE_CURRENT_SOURCE_DIR}/src/oblfr_rpmsg.c)
|
||||
|
11
components/rpmsg/Kconfig
Normal file
11
components/rpmsg/Kconfig
Normal file
|
@ -0,0 +1,11 @@
|
|||
config COMPONENT_RPMSG
|
||||
bool "RPmsg Component"
|
||||
default n
|
||||
select COMPONENT_SYSTEM
|
||||
help
|
||||
RPmsg Component to allow inter core communication
|
||||
works with bare metal and linux
|
||||
|
||||
menu "RPMsg Configuration"
|
||||
visible if COMPONENT_RPMSG
|
||||
endmenu
|
9
components/rpmsg/README.md
Normal file
9
components/rpmsg/README.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
## RPMsg - Remote Processor Messaging
|
||||
|
||||
A implmentation of the RPMsg protocol for bare-metal systems.
|
||||
|
||||
This component allows firmware running on different cores to exchagne messages with each other.
|
||||
It is compatible with the Linux kernel implementation of RPMsg, and can be used to communicate with Linux applications/drivers.
|
||||
|
||||
It can also be used to communicate with bare metal firmware running on different cores.
|
||||
|
130
components/rpmsg/include/oblfr_rpmsg.h
Normal file
130
components/rpmsg/include/oblfr_rpmsg.h
Normal file
|
@ -0,0 +1,130 @@
|
|||
#ifndef IPC_H
|
||||
#define IPC_H
|
||||
#include "oblfr_mailbox.h"
|
||||
/**
|
||||
* @brief Device Status Enum
|
||||
*/
|
||||
typedef enum device_status_e {
|
||||
DEVICE_DOWN, /*<- Device is Down */
|
||||
DEVICE_UP, /*<- Device is up and ready to transmit/recieve */
|
||||
} device_status_t;
|
||||
|
||||
/**
|
||||
* @brief Opaque handle to RPMSG endpoint
|
||||
*/
|
||||
typedef struct oblfr_queue_entry_s oblfr_queue_entry_t;
|
||||
|
||||
/**
|
||||
* @brief RPMSG callback function
|
||||
*/
|
||||
typedef void (*oblfr_rpmsg_cb_t)(void* data, size_t len, void* priv);
|
||||
|
||||
/* forward declaration */
|
||||
typedef struct oblfr_device_cfg_s oblfr_device_cfg_t;
|
||||
|
||||
/**
|
||||
* @brief RPMSG Device Status Change Callback
|
||||
*/
|
||||
typedef void (*oblfr_rpmsg_device_status_cb_t)(oblfr_device_cfg_t *device, device_status_t status);
|
||||
|
||||
/**
|
||||
* @brief RPMSG endpoint configuration
|
||||
*
|
||||
* Configuresa rpmsg endpoint for communication with the remote processor
|
||||
*
|
||||
* @param name Name of the endpoint
|
||||
* @param cb Callback function to be called when data is received
|
||||
* @param priv Private data to be passed to the callback function
|
||||
*/
|
||||
typedef struct oblfr_device_cfg_s
|
||||
{
|
||||
char name[16];
|
||||
oblfr_rpmsg_cb_t cb;
|
||||
oblfr_rpmsg_device_status_cb_t status_cb;
|
||||
void *priv;
|
||||
} oblfr_device_cfg_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize a rpmsg device endpoint
|
||||
*
|
||||
* @param cfg Endpoint configuration
|
||||
* @return Opaque handle to the endpoint
|
||||
*/
|
||||
oblfr_queue_entry_t *oblfr_rpmsg_device_add(oblfr_device_cfg_t *cfg);
|
||||
|
||||
/**
|
||||
* @brief Remove a rpmsg device endpoint
|
||||
*
|
||||
* @param device Opaque handle to the endpoint
|
||||
* @return OBLFR_OK on success
|
||||
* OBLFR_ERROR on failure
|
||||
*/
|
||||
oblfr_err_t oblfr_rpmsg_device_remove(oblfr_queue_entry_t *device);
|
||||
|
||||
/**
|
||||
* @brief Send data to a rpmsg device endpoint
|
||||
*
|
||||
* This uses a user allocated buffer and copies the data to shared memory for
|
||||
* transmission to the remote processor
|
||||
*
|
||||
* @param device Opaque handle to the endpoint
|
||||
* @param data Data to send
|
||||
* @param len Length of the data
|
||||
* @param timeout Timeout in milliseconds to wait for the data to be sent
|
||||
* @return OBLFR_OK on success
|
||||
* OBLFR_ERROR on failure
|
||||
*/
|
||||
oblfr_err_t oblfr_rpmsg_device_send(oblfr_queue_entry_t *device, void *data, size_t len, OBLFR_Timeout timeout);
|
||||
|
||||
/**
|
||||
* @brief Allocate a buffer for sending data to a rpmsg device endpoint for zerocopy sends
|
||||
*
|
||||
* @param device Opaque handle to the endpoint
|
||||
* @param out size the total size of the buffer returned
|
||||
* @param timeout Timeout in milliseconds to wait for the buffer to be allocated
|
||||
* @return Pointer to the buffer or NULL on error
|
||||
*/
|
||||
void *oblfr_rpmsg_device_send_buffer_alloc(oblfr_queue_entry_t *device, uint32_t *size, OBLFR_Timeout timeout);
|
||||
|
||||
/**
|
||||
* @brief Send a zerocopy buffer to a rpmsg device endpoint
|
||||
*
|
||||
* @param device Opaque handle to the endpoint
|
||||
* @param buffer Buffer to send (must be allocated with oblfr_rpmsg_device_send_buffer_alloc)
|
||||
* @param len Length of the message in the buffer
|
||||
* @return OBLFR_OK on success
|
||||
* OBLFR_ERROR on failure
|
||||
*/
|
||||
oblfr_err_t oblfr_rpmsg_device_send_buffer(oblfr_queue_entry_t *device, void *buffer, size_t len);
|
||||
|
||||
/**
|
||||
* @brief get the maximum size of a message that can be sent to a rpmsg device endpoint
|
||||
*/
|
||||
uint32_t oblfr_rpmsg_get_mtu(void);
|
||||
|
||||
/**
|
||||
* @brief Check if communication with the remote processor is ready
|
||||
*
|
||||
* @return true if communication is ready
|
||||
* false if communication is not ready
|
||||
*/
|
||||
bool oblfr_rpmsg_is_ready(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize the RPMSG communication
|
||||
*
|
||||
* Starts a background task that handles communication with the remote processor
|
||||
*
|
||||
* @return OBLFR_OK on success
|
||||
* OBLFR_ERROR on failure
|
||||
*/
|
||||
oblfr_err_t init_rpmsg();
|
||||
|
||||
/**
|
||||
* @brief dump the internal state of the rpmsg communication
|
||||
*
|
||||
* @return OBLFR_OK on success
|
||||
*/
|
||||
oblfr_err_t oblfr_rpmsg_dump(void);
|
||||
|
||||
#endif
|
29
components/rpmsg/rpmsg-lite/CMakeLists.txt
Normal file
29
components/rpmsg/rpmsg-lite/CMakeLists.txt
Normal file
|
@ -0,0 +1,29 @@
|
|||
sdk_generate_library(librpmsg-lite)
|
||||
sdk_library_add_sources(
|
||||
rpmsg_lite/rpmsg_lite.c
|
||||
rpmsg_lite/rpmsg_queue.c
|
||||
rpmsg_lite/rpmsg_ns.c
|
||||
common/llist.c
|
||||
virtio/virtqueue.c
|
||||
rpmsg_lite/porting/platform/bl808/rpmsg_platform.c
|
||||
)
|
||||
if(CONFIG_FREERTOS)
|
||||
sdk_library_add_sources(
|
||||
rpmsg_lite/porting/environment/rpmsg_env_freertos.c
|
||||
)
|
||||
sdk_add_include_directories(
|
||||
include/environment/freertos
|
||||
)
|
||||
else()
|
||||
sdk_library_add_sources(
|
||||
rpmsg_lite/porting/environment/rpmsg_env_bm.c
|
||||
)
|
||||
sdk_add_include_directories(
|
||||
include/environment/bm
|
||||
)
|
||||
endif()
|
||||
sdk_add_include_directories(
|
||||
include
|
||||
include/platform/bl808
|
||||
)
|
||||
#sdk_add_compile_definitions(-DVQUEUE_DEBUG)
|
29
components/rpmsg/rpmsg-lite/LICENSE
Normal file
29
components/rpmsg/rpmsg-lite/LICENSE
Normal file
|
@ -0,0 +1,29 @@
|
|||
Copyright (c) 2016-2022 NXP
|
||||
Copyright (c) 2014-2016 Freescale Semiconductor, Inc.
|
||||
Copyright (c) 2014, Mentor Graphics Corporation
|
||||
Copyright (c) 2015 Xilinx, Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
o Redistributions of source code must retain the above copyright notice, this list
|
||||
of conditions and the following disclaimer.
|
||||
|
||||
o Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
o Neither the name of Freescale Semiconductor, Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
112
components/rpmsg/rpmsg-lite/README.md
Normal file
112
components/rpmsg/rpmsg-lite/README.md
Normal file
|
@ -0,0 +1,112 @@
|
|||
RPMsg Component
|
||||
===============
|
||||
This has been ported to the bouffalo lab bl_mcu_sdk platform from the original.
|
||||
|
||||
This documentation describes the RPMsg-Lite component, which is a lightweight implementation of the Remote Processor Messaging (RPMsg) protocol. The RPMsg protocol defines a standardized binary interface used to communicate between multiple cores in a heterogeneous multicore system.
|
||||
|
||||
Compared to the RPMsg implementation of the Open Asymmetric Multi Processing (OpenAMP) framework (https://github.com/OpenAMP/open-amp), the RPMsg-Lite offers a code size reduction, API simplification, and improved modularity. On smaller Cortex-M0+ based systems, it is recommended to use RPMsg-Lite.
|
||||
|
||||
The RPMsg-Lite is an open-source component developed by NXP Semiconductors and released under the BSD-compatible license.
|
||||
|
||||
For Further documentation, please look at doxygen documentation at: https://nxp-mcuxpresso.github.io/rpmsg-lite/
|
||||
|
||||
# Motivation to create RPMsg-Lite
|
||||
|
||||
There are multiple reasons why RPMsg-Lite was developed. One reason is the need for the small footprint of the RPMsg protocol-compatible communication component, another reason is the simplification of extensive API of OpenAMP RPMsg implementation.
|
||||
|
||||
RPMsg protocol was not documented, and its only definition was given by the Linux Kernel and legacy OpenAMP implementations. This has changed with [1] which is a standardization protocol allowing multiple different implementations to coexist and still be mutually compatible.
|
||||
|
||||
Small MCU-based systems often do not implement dynamic memory allocation. The creation of static API in RPMsg-Lite enables another reduction of resource usage. Not only does the dynamic allocation adds another 5 KB of code size, but also communication is slower and less deterministic, which is a property introduced by dynamic memory. The following table shows some rough comparison data between the OpenAMP RPMsg implementation and new RPMsg-Lite implementation:
|
||||
|
||||
|Component / Configuration | Flash [B] |RAM [B] |
|
||||
|---------------------------------------------|-----------|---------------|
|
||||
|OpenAMP RPMsg / Release (reference) | 5547 | 456 + dynamic |
|
||||
|RPMsg-Lite / Dynamic API, Release | 3462 | 56 + dynamic |
|
||||
|Relative Difference [%] | ~62.4% | ~12.3% |
|
||||
|RPMsg-Lite / Static API (no malloc), Release | 2926 | 352 |
|
||||
|Relative Difference [%] | ~52.7% | ~77.2% |
|
||||
|
||||
# Implementation
|
||||
|
||||
The implementation of RPMsg-Lite can be divided into three sub-components, from which two are optional. The core component is situated in <i>rpmsg_lite.c</i>. Two optional components are used to implement a blocking receive API (in <i>rpmsg_queue.c</i>) and dynamic "named" endpoint creation and deletion announcement service (in <i>rpmsg_ns.c</i>).
|
||||
|
||||
The actual "media access" layer is implemented in <i>virtqueue.c</i>, which is one of the few files shared with the OpenAMP implementation. This layer mainly defines the shared memory model, and internally defines used components such as vring or virtqueue.
|
||||
|
||||
The porting layer is split into two sub-layers: the environment layer and the platform layer. The first sublayer is to be implemented separately for each environment. (The bare metal environment already exists and is implemented in <i>rpmsg_env_bm.c</i>, and the FreeRTOS environment is implemented in <i>rpmsg_env_freertos.c</i> etc.) Only the source file, which matches the used environment, is included in the target application project. The second sublayer is implemented in <i>rpmsg_platform.c</i> and defines low-level functions for interrupt enabling, disabling, and triggering mainly. The situation is described in the following figure:
|
||||
|
||||

|
||||
|
||||
## RPMsg-Lite core sub-component
|
||||
|
||||
This subcomponent implements a blocking send API and callback-based receive API. The RPMsg protocol is part of the transport layer. This is realized by using so-called endpoints. Each endpoint can be assigned a different receive callback function. However, it is important to notice that the callback is executed in an interrupt environment in current design. Therefore, certain actions like memory allocation are discouraged to execute in the callback. The following figure shows the role of RPMsg in an ISO/OSI-like layered model:
|
||||
|
||||

|
||||
|
||||
## Queue sub-component (optional)
|
||||
|
||||
This subcomponent is optional and requires implementation of the env_*_queue() functions in the environment porting layer. It uses a blocking receive API, which is common in RTOS-environments. It supports both copy and nocopy blocking receive functions.
|
||||
|
||||
## Name Service sub-component (optional)
|
||||
|
||||
This subcomponent is a minimum implementation of the name service which is present in the Linux Kernel implementation of RPMsg. It allows the communicating node both to send announcements about "named" endpoint (in other words, channel) creation or deletion and to receive these announcement taking any user-defined action in an application callback. The endpoint address used to receive name service announcements is arbitrarily fixed to be 53 (0x35).
|
||||
|
||||
# Usage
|
||||
|
||||
The application should put the /rpmsg_lite/lib/include directory to the include path and in the application, include either the rpmsg_lite.h header file, or optionally also include the rpmsg_queue.h and/or rpmsg_ns.h files. Both porting sublayers should be provided for you by NXP, but if you plan to use your own RTOS, all you need to do is to implement your own environment layer (in other words, rpmsg_env_myrtos.c) and to include it in the project build.
|
||||
|
||||
The initialization of the stack is done by calling the rpmsg_lite_master_init() on the master side and the rpmsg_lite_remote_init() on the remote side. This initialization function must be called prior to any RPMsg-Lite API call. After the init, it is wise to create a communication endpoint, otherwise communication is not possible. This can be done by calling the rpmsg_lite_create_ept() function. It optionally accepts a last argument, where an internal context of the endpoint is created, just in case the RL_USE_STATIC_API option is set to 1. If not, the stack internally calls env_alloc() to allocate dynamic memory for it. In case a callback-based receiving is to be used, an ISR-callback is registered to each new endpoint with user-defined callback data pointer. If a blocking receive is desired (in case of RTOS environment), the rpmsg_queue_create() function must be called before calling rpmsg_lite_create_ept(). The queue handle is passed to the endpoint creation function as a callback data argument and the callback function is set to rpmsg_queue_rx_cb(). Then, it is possible to use rpmsg_queue_receive() function to listen on a queue object for incoming messages. The rpmsg_lite_send() function is used to send messages to the other side.
|
||||
|
||||
The RPMsg-Lite also implements no-copy mechanisms for both sending and receiving operations. These methods require
|
||||
specifics that have to be considered when used in an application.
|
||||
|
||||
<b>no-copy-send mechanism:</b> This mechanism allows sending messages without the cost for copying data from the application
|
||||
buffer to the RPMsg/virtio buffer in the shared memory. The sequence of no-copy sending steps to be performed is as follows:
|
||||
- Call the rpmsg_lite_alloc_tx_buffer() function to get the virtio buffer and provide the buffer pointer to the application.
|
||||
- Fill the data to be sent into the pre-allocated virtio buffer. Ensure that the filled data does not exceed the buffer size
|
||||
(provided as the rpmsg_lite_alloc_tx_buffer() <i>size</i> output parameter).
|
||||
- Call the rpmsg_lite_send_nocopy() function to send the message to the destination endpoint. Consider the cache
|
||||
functionality and the virtio buffer alignment. See the rpmsg_lite_send_nocopy() function description below.
|
||||
|
||||
<b>no-copy-receive mechanism:</b> This mechanism allows reading messages without the cost for copying data from the virtio
|
||||
buffer in the shared memory to the application buffer. The sequence of no-copy receiving steps to be performed is as follows:
|
||||
- Call the rpmsg_queue_recv_nocopy() function to get the virtio buffer pointer to the received data.
|
||||
- Read received data directly from the shared memory.
|
||||
- Call the rpmsg_queue_nocopy_free() function to release the virtio buffer and to make it available for the next data transfer.
|
||||
|
||||
The user is responsible for destroying any RPMsg-Lite objects he has created in case of deinitialization. In order to do this, the function rpmsg_queue_destroy() is used to destroy a queue, rpmsg_lite_destroy_ept() is used to destroy an endpoint and finally, rpmsg_lite_deinit() is used to deinitialize the RPMsg-Lite intercore communication stack. Deinitialize all endpoints using a queue before deinitializing the queue. Otherwise, you are actively invalidating the used queue handle, which is not allowed. RPMsg-Lite does not check this internally, since its main aim is to be lightweight.
|
||||
|
||||

|
||||
|
||||
# Configuration options
|
||||
|
||||
The RPMsg-Lite can be configured at the compile time. The default configuration is defined in the rpmsg_default_config.h header file. This configuration can be customized by the user by including rpmsg_config.h file with custom settings. The following table summarizes all possible RPMsg-Lite configuration options.
|
||||
|
||||
| Configuration option | Default value | Usage |
|
||||
|------------------------------|---------------|-----------|
|
||||
|RL_MS_PER_INTERVAL | (1) | Delay in milliseconds used in non-blocking API functions for polling. |
|
||||
|RL_BUFFER_PAYLOAD_SIZE | (496) | Size of the buffer payload, it must be equal to (240, 496, 1008, ...) [2^n - 16] |
|
||||
|RL_BUFFER_COUNT | (2) | Number of the buffers, it must be power of two (2, 4, ...) |
|
||||
|RL_API_HAS_ZEROCOPY | (1) | Zero-copy API functions enabled/disabled. |
|
||||
|RL_USE_STATIC_API | (0) | Static API functions (no dynamic allocation) enabled/disabled. |
|
||||
|RL_CLEAR_USED_BUFFERS | (0) | Clearing used buffers before returning back to the pool of free buffers enabled/disabled. |
|
||||
|RL_USE_MCMGR_IPC_ISR_HANDLER | (0) | When enabled IPC interrupts are managed by the Multicore Manager (IPC interrupts router), when disabled RPMsg-Lite manages IPC interrupts by itself. |
|
||||
|RL_USE_ENVIRONMENT_CONTEXT | (0) | When enabled the environment layer uses its own context. Required for some environments (QNX). The default value is 0 (no context, saves some RAM). |
|
||||
|RL_DEBUG_CHECK_BUFFERS | (0) | When enabled buffer debug checks in rpmsg_lite_send_nocopy() and rpmsg_lite_release_rx_buffer() functions are disabled. Do not use in RPMsg-Lite to Linux configuration. |
|
||||
|RL_ALLOW_CONSUMED_BUFFERS_NOTIFICATION | (0) | When enabled the opposite side is notified each time received buffers are consumed and put into the queue of available buffers. Enable this option in RPMsg-Lite to Linux configuration to allow unblocking of the Linux blocking send. The default value is 0 (RPMsg-Lite to RPMsg-Lite communication). |
|
||||
|RL_ALLOW_CUSTOM_SHMEM_CONFIG | (0) | It allows to define custom shared memory configuration and replacing the shared memory related global settings from rpmsg_config.h This is useful when multiple instances are running in parallel but different shared memory arrangement (vring size & alignment, buffers size & count) is required. The default value is 0 (all RPMsg_Lite instances use the same shared memory arrangement as defined by common config macros). |
|
||||
|RL_ASSERT | see rpmsg_default_config.h | Assert implementation. |
|
||||
|
||||
# Contributing to the rpmsg-lite project
|
||||
We welcome and encourage the community to submit patches directly to the rpmsg-lite project placed on github. Contributing can be managed via pull-requests. Before a pull-request is created the code should be tested and properly formatted.
|
||||
|
||||
## How to format rpmsg-lite code
|
||||
To format code, use the application developed by Google, named *clang-format*. This tool is part of the [llvm](http://llvm.org/) project. Currently, the clang-format 10.0.0 version is used for rpmsg-lite.
|
||||
The set of style settings used for clang-format is defined in the `.clang-format` file, placed in a root of the rpmsg-lite directory where Python script ``run_clang_format.py`` can be executed.
|
||||
This script executes the application named *clang-format.exe*. You need to have the path of this application in the OS's environment path, or you need to change the script.
|
||||
|
||||
# References
|
||||
[1] M. Novak, M. Cingel, Lockless Shared Memory Based Multicore Communication Protocol
|
||||
|
||||
---
|
||||
Copyright © 2016 Freescale Semiconductor, Inc.
|
||||
Copyright © 2016-2022 NXP
|
113
components/rpmsg/rpmsg-lite/common/llist.c
Normal file
113
components/rpmsg/rpmsg-lite/common/llist.c
Normal file
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Mentor Graphics Corporation
|
||||
* Copyright 2019 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Mentor Graphics Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**************************************************************************
|
||||
* FILE NAME
|
||||
*
|
||||
* llist.c
|
||||
*
|
||||
* COMPONENT
|
||||
*
|
||||
* OpenAMP stack.
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Source file for basic linked list service.
|
||||
*
|
||||
**************************************************************************/
|
||||
#include "llist.h"
|
||||
|
||||
#define LIST_NULL ((void *)0)
|
||||
/*!
|
||||
* add_to_list
|
||||
*
|
||||
* Places new element at the start of the list.
|
||||
*
|
||||
* @param head - list head
|
||||
* @param node - new element to add
|
||||
*
|
||||
*/
|
||||
void add_to_list(struct llist **head, struct llist *node)
|
||||
{
|
||||
if (node == LIST_NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (*head != LIST_NULL)
|
||||
{
|
||||
/* Place the new element at the start of list. */
|
||||
node->next = *head;
|
||||
node->prev = LIST_NULL;
|
||||
(*head)->prev = node;
|
||||
*head = node;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* List is empty - assign new element to list head. */
|
||||
*head = node;
|
||||
(*head)->next = LIST_NULL;
|
||||
(*head)->prev = LIST_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* remove_from_list
|
||||
*
|
||||
* Removes the given element from the list.
|
||||
*
|
||||
* @param head - list head
|
||||
* @param element - element to remove from list
|
||||
*
|
||||
*/
|
||||
void remove_from_list(struct llist **head, struct llist *node)
|
||||
{
|
||||
if ((*head == LIST_NULL) || (node == LIST_NULL))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (node == *head)
|
||||
{
|
||||
/* First element has to be removed. */
|
||||
*head = (*head)->next;
|
||||
}
|
||||
else if (node->next == LIST_NULL)
|
||||
{
|
||||
/* Last element has to be removed. */
|
||||
node->prev->next = node->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Intermediate element has to be removed. */
|
||||
node->prev->next = node->next;
|
||||
node->next->prev = node->prev;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2021 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/**************************************************************************
|
||||
* FILE NAME
|
||||
*
|
||||
* rpmsg_env_specific.h
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* This file contains FreeRTOS specific constructions.
|
||||
*
|
||||
**************************************************************************/
|
||||
#ifndef RPMSG_ENV_SPECIFIC_H_
|
||||
#define RPMSG_ENV_SPECIFIC_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "rpmsg_default_config.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t src;
|
||||
void *data;
|
||||
uint32_t len;
|
||||
} rpmsg_queue_rx_cb_data_t;
|
||||
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
#include "FreeRTOS.h"
|
||||
|
||||
#if (configSUPPORT_STATIC_ALLOCATION == 0)
|
||||
#warning You have configured RPMsg_Lite to use static API but FreeRTOS is not configured for static allocations! Please switch the configSUPPORT_STATIC_ALLOCATION to 1 in your FreeRTOSConfig.h file.
|
||||
#endif
|
||||
typedef StaticSemaphore_t LOCK_STATIC_CONTEXT;
|
||||
typedef StaticQueue_t rpmsg_static_queue_ctxt;
|
||||
|
||||
/* Queue object static storage size in bytes, should be defined as (RL_BUFFER_COUNT*sizeof(rpmsg_queue_rx_cb_data_t))
|
||||
This macro helps the application to statically allocate the queue object static storage memory. Note, the
|
||||
RL_BUFFER_COUNT is not applied for all instances when RL_ALLOW_CUSTOM_SHMEM_CONFIG is set to 1 ! */
|
||||
#define RL_ENV_QUEUE_STATIC_STORAGE_SIZE (RL_BUFFER_COUNT * sizeof(rpmsg_queue_rx_cb_data_t))
|
||||
#endif
|
||||
|
||||
#endif /* RPMSG_ENV_SPECIFIC_H_ */
|
62
components/rpmsg/rpmsg-lite/include/llist.h
Normal file
62
components/rpmsg/rpmsg-lite/include/llist.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Mentor Graphics Corporation
|
||||
* Copyright 2019 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of Mentor Graphics Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**************************************************************************
|
||||
* FILE NAME
|
||||
*
|
||||
* llist.h
|
||||
*
|
||||
* COMPONENT
|
||||
*
|
||||
* OpenAMP stack.
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* Header file for linked list service.
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#ifndef LLIST_H_
|
||||
#define LLIST_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct llist
|
||||
{
|
||||
void *data;
|
||||
uint32_t attr;
|
||||
struct llist *next;
|
||||
struct llist *prev;
|
||||
};
|
||||
|
||||
void add_to_list(struct llist **head, struct llist *node);
|
||||
void remove_from_list(struct llist **head, struct llist *node);
|
||||
|
||||
#endif /* LLIST_H_ */
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2019 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#ifndef RPMSG_PLATFORM_H_
|
||||
#define RPMSG_PLATFORM_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* No need to align the VRING as defined in Linux because k32l3a6 is not intended
|
||||
* to run the Linux
|
||||
*/
|
||||
#ifndef VRING_ALIGN
|
||||
#define VRING_ALIGN (0x1000U)
|
||||
//#define VRING_ALIGN (0x10U)
|
||||
#endif
|
||||
|
||||
/* contains pool of descriptos and two circular buffers */
|
||||
#if 1
|
||||
#ifndef VRING_SIZE
|
||||
#define VRING_SIZE (0x4000UL)
|
||||
#endif
|
||||
#else
|
||||
#define VRING_SIZE1 (RL_BUFFER_COUNT * sizeof(struct vring_desc))
|
||||
#define VRING_SIZE2 (VRING_SIZE1 + sizeof(struct vring_avail) + (RL_BUFFER_COUNT * sizeof(uint16_t)) + sizeof(uint16_t))
|
||||
#define VRING_SIZE3 ((VRING_SIZE2 + VRING_ALIGN - 1UL) & ~(VRING_ALIGN - 1UL))
|
||||
#define VRING_SIZE4 (VRING_SIZE3 + sizeof(struct vring_used) + (RL_BUFFER_COUNT * sizeof(struct vring_used_elem)) + sizeof(uint16_t))
|
||||
#define VRING_SIZE (((int32_t)VRING_SIZE4))
|
||||
#endif
|
||||
|
||||
/* size of shared memory + 2*VRING size */
|
||||
#define RL_VRING_OVERHEAD (2UL * VRING_SIZE)
|
||||
|
||||
#define RL_GET_VQ_ID(link_id, queue_id) (((queue_id)&0x1U) | (((link_id) << 1U) & 0xFFFFFFFEU))
|
||||
#define RL_GET_LINK_ID(id) (((id)&0xFFFFFFFEU) >> 1U)
|
||||
#define RL_GET_Q_ID(id) ((id)&0x1U)
|
||||
|
||||
#define RL_PLATFORM_BL808_M0_LINK_ID (0U)
|
||||
#define RL_PLATFORM_HIGHEST_LINK_ID (0U)
|
||||
|
||||
|
||||
/* platform interrupt related functions */
|
||||
int32_t platform_init_interrupt(uint32_t vector_id, void *isr_data);
|
||||
int32_t platform_deinit_interrupt(uint32_t vector_id);
|
||||
int32_t platform_interrupt_enable(uint32_t vector_id);
|
||||
int32_t platform_interrupt_disable(uint32_t vector_id);
|
||||
int32_t platform_in_isr(void);
|
||||
void platform_notify(uint32_t vector_id);
|
||||
|
||||
/* platform low-level time-delay (busy loop) */
|
||||
void platform_time_delay(uint32_t num_msec);
|
||||
|
||||
/* platform memory functions */
|
||||
void platform_map_mem_region(uint32_t vrt_addr, uint32_t phy_addr, uint32_t size, uint32_t flags);
|
||||
void platform_cache_all_flush_invalidate(void);
|
||||
void platform_cache_disable(void);
|
||||
uint32_t platform_vatopa(void *addr);
|
||||
void *platform_patova(uintptr_t addr);
|
||||
|
||||
/* platform init/deinit */
|
||||
int32_t platform_init(void);
|
||||
int32_t platform_deinit(void);
|
||||
|
||||
#endif /* RPMSG_PLATFORM_H_ */
|
123
components/rpmsg/rpmsg-lite/include/rpmsg_compiler.h
Normal file
123
components/rpmsg/rpmsg-lite/include/rpmsg_compiler.h
Normal file
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Mentor Graphics Corporation
|
||||
* Copyright (c) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2016 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**************************************************************************
|
||||
* FILE NAME
|
||||
*
|
||||
* rpmsg_compiler.h
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* This file defines compiler-specific macros.
|
||||
*
|
||||
***************************************************************************/
|
||||
#ifndef RPMSG_COMPILER_H_
|
||||
#define RPMSG_COMPILER_H_
|
||||
|
||||
/* IAR ARM build tools */
|
||||
#if defined(__ICCARM__)
|
||||
|
||||
#include <intrinsics.h>
|
||||
|
||||
#define MEM_BARRIER() __DSB()
|
||||
|
||||
#ifndef RL_PACKED_BEGIN
|
||||
#define RL_PACKED_BEGIN __packed
|
||||
#endif
|
||||
|
||||
#ifndef RL_PACKED_END
|
||||
#define RL_PACKED_END
|
||||
#endif
|
||||
|
||||
/* ARM GCC */
|
||||
#elif defined(__CC_ARM) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
|
||||
|
||||
#if (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))
|
||||
#include <arm_compat.h>
|
||||
#endif
|
||||
|
||||
#define MEM_BARRIER() __schedule_barrier()
|
||||
|
||||
#ifndef RL_PACKED_BEGIN
|
||||
#define RL_PACKED_BEGIN _Pragma("pack(1U)")
|
||||
#endif
|
||||
|
||||
#ifndef RL_PACKED_END
|
||||
#define RL_PACKED_END _Pragma("pack()")
|
||||
#endif
|
||||
|
||||
/* XCC HiFi4 */
|
||||
#elif defined(__XCC__)
|
||||
|
||||
/*
|
||||
* The XCC HiFi4 compiler is compatible with GNU compiler, with restrictions.
|
||||
* For ARM __schedule_barrier, there's no identical intrinsic in HiFi4.
|
||||
* A complete synchronization barrier would require initialize and wait ops.
|
||||
* Here use NOP instead, similar to ARM __nop.
|
||||
*/
|
||||
#define MEM_BARRIER() __asm__ __volatile__("nop" : : : "memory")
|
||||
|
||||
#ifndef RL_PACKED_BEGIN
|
||||
#define RL_PACKED_BEGIN
|
||||
#endif
|
||||
|
||||
#ifndef RL_PACKED_END
|
||||
#define RL_PACKED_END __attribute__((__packed__))
|
||||
#endif
|
||||
|
||||
/* GNUC */
|
||||
#elif defined(__GNUC__)
|
||||
|
||||
#if defined(__riscv)
|
||||
#include <csi_core.h>
|
||||
#define MEM_BARRIER() __DMB()
|
||||
#define MEM_BARRIER_R() __DMB()
|
||||
#define MEM_BARRIER_W() __DMB()
|
||||
#else
|
||||
#define MEM_BARRIER() __asm__ volatile("dsb" : : : "memory")
|
||||
#define MEM_BARRIER_R() __asm__ volatile("dsb" : : : "memory")
|
||||
#define MEM_BARRIER_W() __asm__ volatile("dsb" : : : "memory")
|
||||
#endif
|
||||
|
||||
#ifndef RL_PACKED_BEGIN
|
||||
#define RL_PACKED_BEGIN
|
||||
#endif
|
||||
|
||||
#ifndef RL_PACKED_END
|
||||
#define RL_PACKED_END __attribute__((__packed__))
|
||||
#endif
|
||||
|
||||
#else
|
||||
/* There is no default definition here to avoid wrong structures packing in case of not supported compiler */
|
||||
#error Please implement the structure packing macros for your compiler here!
|
||||
#endif
|
||||
|
||||
#endif /* RPMSG_COMPILER_H_ */
|
198
components/rpmsg/rpmsg-lite/include/rpmsg_default_config.h
Normal file
198
components/rpmsg/rpmsg-lite/include/rpmsg_default_config.h
Normal file
|
@ -0,0 +1,198 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Mentor Graphics Corporation
|
||||
* Copyright (c) 2015 Xilinx, Inc.
|
||||
* Copyright (c) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2021 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef RPMSG_DEFAULT_CONFIG_H_
|
||||
#define RPMSG_DEFAULT_CONFIG_H_
|
||||
|
||||
#define RL_USE_CUSTOM_CONFIG (0)
|
||||
|
||||
#if RL_USE_CUSTOM_CONFIG
|
||||
#include "rpmsg_config.h"
|
||||
#error "Custom Configuration is not supported"
|
||||
#endif
|
||||
|
||||
#define DBG_TAG "RPMSG"
|
||||
#include "log.h"
|
||||
|
||||
/*!
|
||||
* @addtogroup config
|
||||
* @{
|
||||
* @file
|
||||
*/
|
||||
|
||||
//! @name Configuration options
|
||||
//@{
|
||||
|
||||
//! @def RL_MS_PER_INTERVAL
|
||||
//!
|
||||
//! Delay in milliseconds used in non-blocking API functions for polling.
|
||||
//! The default value is 1.
|
||||
#ifndef RL_MS_PER_INTERVAL
|
||||
#define RL_MS_PER_INTERVAL (10)
|
||||
#endif
|
||||
|
||||
//! @def RL_ALLOW_CUSTOM_SHMEM_CONFIG
|
||||
//!
|
||||
//! This option allows to define custom shared memory configuration and replacing
|
||||
//! the shared memory related global settings from rpmsg_config.h This is useful
|
||||
//! when multiple instances are running in parallel but different shared memory
|
||||
//! arrangement (vring size & alignment, buffers size & count) is required. Note,
|
||||
//! that once enabled the platform_get_custom_shmem_config() function needs
|
||||
//! to be implemented in platform layer. The default value is 0 (all RPMsg_Lite
|
||||
//! instances use the same shared memory arrangement as defined by common config macros).
|
||||
#ifndef RL_ALLOW_CUSTOM_SHMEM_CONFIG
|
||||
#define RL_ALLOW_CUSTOM_SHMEM_CONFIG (0)
|
||||
#endif
|
||||
|
||||
#if !(defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1))
|
||||
//! @def RL_BUFFER_PAYLOAD_SIZE
|
||||
//!
|
||||
//! Size of the buffer payload, it must be equal to (240, 496, 1008, ...)
|
||||
//! [2^n - 16]. Ensure the same value is defined on both sides of rpmsg
|
||||
//! communication. The default value is 496U.
|
||||
#ifndef RL_BUFFER_PAYLOAD_SIZE
|
||||
#define RL_BUFFER_PAYLOAD_SIZE (2032U)
|
||||
#endif
|
||||
|
||||
//! @def RL_BUFFER_COUNT
|
||||
//!
|
||||
//! Number of the buffers, it must be power of two (2, 4, ...).
|
||||
//! The default value is 2U.
|
||||
//! Note this value defines the buffer count for one direction of the rpmsg
|
||||
//! communication only, i.e. if the default value of 2 is used
|
||||
//! in rpmsg_config.h files for the master and the remote side, 4 buffers
|
||||
//! in total are created in the shared memory.
|
||||
|
||||
/* for bl808, based on 32K buffer size, and 2048 message size: */
|
||||
|
||||
|
||||
#ifndef RL_BUFFER_COUNT
|
||||
#define RL_BUFFER_COUNT (8U)
|
||||
#endif
|
||||
|
||||
#else
|
||||
//! Define the buffer payload and count per different link IDs (rpmsg_lite instance) when RL_ALLOW_CUSTOM_SHMEM_CONFIG
|
||||
//! is set.
|
||||
//! Refer to the rpmsg_plaform.h for the used link IDs.
|
||||
#ifndef RL_BUFFER_PAYLOAD_SIZE
|
||||
#define RL_BUFFER_PAYLOAD_SIZE(link_id) (496U)
|
||||
#endif
|
||||
|
||||
#ifndef RL_BUFFER_COUNT
|
||||
#define RL_BUFFER_COUNT(link_id) (((link_id) == 0U) ? 256U : 2U)
|
||||
#endif
|
||||
#endif /* !(defined(RL_ALLOW_CUSTOM_SHMEM_CONFIG) && (RL_ALLOW_CUSTOM_SHMEM_CONFIG == 1))*/
|
||||
|
||||
//! @def RL_API_HAS_ZEROCOPY
|
||||
//!
|
||||
//! Zero-copy API functions enabled/disabled.
|
||||
//! The default value is 1 (enabled).
|
||||
#ifndef RL_API_HAS_ZEROCOPY
|
||||
#define RL_API_HAS_ZEROCOPY (1)
|
||||
#endif
|
||||
|
||||
//! @def RL_USE_STATIC_API
|
||||
//!
|
||||
//! Static API functions (no dynamic allocation) enabled/disabled.
|
||||
//! The default value is 0 (static API disabled).
|
||||
#ifndef RL_USE_STATIC_API
|
||||
#define RL_USE_STATIC_API (0)
|
||||
#endif
|
||||
|
||||
//! @def RL_CLEAR_USED_BUFFERS
|
||||
//!
|
||||
//! Clearing used buffers before returning back to the pool of free buffers
|
||||
//! enabled/disabled.
|
||||
//! The default value is 0 (disabled).
|
||||
#ifndef RL_CLEAR_USED_BUFFERS
|
||||
#define RL_CLEAR_USED_BUFFERS (1)
|
||||
#endif
|
||||
|
||||
//! @def RL_USE_MCMGR_IPC_ISR_HANDLER
|
||||
//!
|
||||
//! When enabled IPC interrupts are managed by the Multicore Manager (IPC
|
||||
//! interrupts router), when disabled RPMsg-Lite manages IPC interrupts
|
||||
//! by itself.
|
||||
//! The default value is 0 (no MCMGR IPC ISR handler used).
|
||||
#ifndef RL_USE_MCMGR_IPC_ISR_HANDLER
|
||||
#define RL_USE_MCMGR_IPC_ISR_HANDLER (0)
|
||||
#endif
|
||||
|
||||
//! @def RL_USE_ENVIRONMENT_CONTEXT
|
||||
//!
|
||||
//! When enabled the environment layer uses its own context.
|
||||
//! Added for QNX port mainly, but can be used if required.
|
||||
//! The default value is 0 (no context, saves some RAM).
|
||||
#ifndef RL_USE_ENVIRONMENT_CONTEXT
|
||||
#define RL_USE_ENVIRONMENT_CONTEXT (0)
|
||||
#endif
|
||||
|
||||
//! @def RL_DEBUG_CHECK_BUFFERS
|
||||
//!
|
||||
//! Do not use in RPMsg-Lite to Linux configuration
|
||||
#ifndef RL_DEBUG_CHECK_BUFFERS
|
||||
#define RL_DEBUG_CHECK_BUFFERS (0)
|
||||
#endif
|
||||
|
||||
//! @def RL_ALLOW_CONSUMED_BUFFERS_NOTIFICATION
|
||||
//!
|
||||
//! When enabled the opposite side is notified each time received buffers
|
||||
//! are consumed and put into the queue of available buffers.
|
||||
//! Enable this option in RPMsg-Lite to Linux configuration to allow unblocking
|
||||
//! of the Linux blocking send.
|
||||
//! The default value is 0 (RPMsg-Lite to RPMsg-Lite communication).
|
||||
#ifndef RL_ALLOW_CONSUMED_BUFFERS_NOTIFICATION
|
||||
#define RL_ALLOW_CONSUMED_BUFFERS_NOTIFICATION (1)
|
||||
#endif
|
||||
|
||||
|
||||
//! @def RL_ASSERT
|
||||
//!
|
||||
//! Assert implementation.
|
||||
#ifndef RL_ASSERT
|
||||
#define RL_ASSERT_BOOL(b) \
|
||||
do \
|
||||
{ \
|
||||
if (!(b)) \
|
||||
{ \
|
||||
LOG_E("RPMsg-Lite hang %s:%d\r\n", __FILE__, __LINE__); \
|
||||
for (;;) \
|
||||
{ \
|
||||
} \
|
||||
} \
|
||||
} while (0 == 1);
|
||||
#define RL_ASSERT(x) RL_ASSERT_BOOL((int32_t)(x) != 0)
|
||||
|
||||
#endif
|
||||
//@}
|
||||
|
||||
#endif /* RPMSG_DEFAULT_CONFIG_H_ */
|
628
components/rpmsg/rpmsg-lite/include/rpmsg_env.h
Normal file
628
components/rpmsg/rpmsg-lite/include/rpmsg_env.h
Normal file
|
@ -0,0 +1,628 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Mentor Graphics Corporation
|
||||
* Copyright (c) 2015 Xilinx, Inc.
|
||||
* Copyright (c) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2022 NXP
|
||||
* Copyright 2021 ACRIOS Systems s.r.o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**************************************************************************
|
||||
* FILE NAME
|
||||
*
|
||||
* rpmsg_env.h
|
||||
*
|
||||
* COMPONENT
|
||||
*
|
||||
* OpenAMP stack.
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* This file defines abstraction layer for OpenAMP stack. The implementor
|
||||
* must provide definition of all the functions.
|
||||
*
|
||||
* DATA STRUCTURES
|
||||
*
|
||||
* none
|
||||
*
|
||||
* FUNCTIONS
|
||||
*
|
||||
* env_allocate_memory
|
||||
* env_free_memory
|
||||
* env_memset
|
||||
* env_memcpy
|
||||
* env_strncpy
|
||||
* env_print
|
||||
* env_map_vatopa
|
||||
* env_map_patova
|
||||
* env_mb
|
||||
* env_rmb
|
||||
* env_wmb
|
||||
* env_create_mutex
|
||||
* env_delete_mutex
|
||||
* env_lock_mutex
|
||||
* env_unlock_mutex
|
||||
* env_sleep_msec
|
||||
* env_disable_interrupt
|
||||
* env_enable_interrupt
|
||||
* env_create_queue
|
||||
* env_delete_queue
|
||||
* env_put_queue
|
||||
* env_get_queue
|
||||
* env_wait_for_link_up
|
||||
* env_tx_callback
|
||||
*
|
||||
**************************************************************************/
|
||||
#ifndef RPMSG_ENV_H_
|
||||
#define RPMSG_ENV_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "rpmsg_default_config.h"
|
||||
#include "rpmsg_env_specific.h"
|
||||
#include "rpmsg_platform.h"
|
||||
|
||||
/*!
|
||||
* env_init
|
||||
*
|
||||
* Initializes OS/BM environment.
|
||||
*
|
||||
* @param env_context Pointer to preallocated environment context data
|
||||
* @param env_init_data Initialization data for the environment layer
|
||||
*
|
||||
* @returns - execution status
|
||||
*/
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
int32_t env_init(void **env_context, void *env_init_data);
|
||||
#else
|
||||
int32_t env_init(void);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* env_deinit
|
||||
*
|
||||
* Uninitializes OS/BM environment.
|
||||
*
|
||||
* @param env_context Pointer to environment context data
|
||||
*
|
||||
* @returns - execution status
|
||||
*/
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
int32_t env_deinit(void *env_context);
|
||||
#else
|
||||
int32_t env_deinit(void);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* -------------------------------------------------------------------------
|
||||
*
|
||||
* Dynamic memory management functions. The parameters
|
||||
* are similar to standard c functions.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
**/
|
||||
|
||||
/*!
|
||||
* env_allocate_memory
|
||||
*
|
||||
* Allocates memory with the given size.
|
||||
*
|
||||
* @param size - size of memory to allocate
|
||||
*
|
||||
* @return - pointer to allocated memory
|
||||
*/
|
||||
void *env_allocate_memory(uint32_t size);
|
||||
|
||||
/*!
|
||||
* env_free_memory
|
||||
*
|
||||
* Frees memory pointed by the given parameter.
|
||||
*
|
||||
* @param ptr - pointer to memory to free
|
||||
*/
|
||||
void env_free_memory(void *ptr);
|
||||
|
||||
/*!
|
||||
* -------------------------------------------------------------------------
|
||||
*
|
||||
* RTL Functions
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
void env_memset(void *ptr, int32_t value, uint32_t size);
|
||||
void env_memcpy(void *dst, void const *src, uint32_t len);
|
||||
int32_t env_strcmp(const char *dst, const char *src);
|
||||
void env_strncpy(char *dest, const char *src, uint32_t len);
|
||||
int32_t env_strncmp(char *dest, const char *src, uint32_t len);
|
||||
#ifdef MCUXPRESSO_SDK
|
||||
/* MCUXpresso_SDK's PRINTF used in SDK examples */
|
||||
#include "fsl_debug_console.h"
|
||||
#if defined SDK_DEBUGCONSOLE && (SDK_DEBUGCONSOLE != DEBUGCONSOLE_DISABLE)
|
||||
#define env_print(...) (void)PRINTF(__VA_ARGS__)
|
||||
#else
|
||||
#define env_print(...)
|
||||
#endif
|
||||
#else
|
||||
/* When RPMsg_Lite being used outside of MCUXpresso_SDK use your own env_print
|
||||
implemenetation to avoid conflict with Misra 21.6 rule */
|
||||
#include <stdio.h>
|
||||
#include <log.h>
|
||||
#define env_print(...) (void)printf(__VA_ARGS__)
|
||||
#endif /* MCUXPRESSO_SDK */
|
||||
|
||||
/*!
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* Functions to convert physical address to virtual address and vice versa.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*!
|
||||
* env_map_vatopa
|
||||
*
|
||||
* Converts logical address to physical address
|
||||
*
|
||||
* @param env Pointer to environment context data
|
||||
* @param address Pointer to logical address
|
||||
*
|
||||
* @return - physical address
|
||||
*/
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
uint32_t env_map_vatopa(void *env, void *address);
|
||||
#else
|
||||
uint32_t env_map_vatopa(void *address);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* env_map_patova
|
||||
*
|
||||
* Converts physical address to logical address
|
||||
*
|
||||
* @param env_context Pointer to environment context data
|
||||
* @param address Pointer to physical address
|
||||
*
|
||||
* @return - logical address
|
||||
*
|
||||
*/
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
void *env_map_patova(void *env, uint32_t address);
|
||||
#else
|
||||
void *env_map_patova(uint32_t address);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* Abstractions for memory barrier instructions.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*!
|
||||
* env_mb
|
||||
*
|
||||
* Inserts memory barrier.
|
||||
*/
|
||||
|
||||
void env_mb(void);
|
||||
|
||||
/*!
|
||||
* env_rmb
|
||||
*
|
||||
* Inserts read memory barrier
|
||||
*/
|
||||
|
||||
void env_rmb(void);
|
||||
|
||||
/*!
|
||||
* env_wmb
|
||||
*
|
||||
* Inserts write memory barrier
|
||||
*/
|
||||
|
||||
void env_wmb(void);
|
||||
|
||||
/*!
|
||||
*-----------------------------------------------------------------------------
|
||||
*
|
||||
* Abstractions for OS lock primitives.
|
||||
*
|
||||
*-----------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*!
|
||||
* env_create_mutex
|
||||
*
|
||||
* Creates a mutex with given initial count.
|
||||
*
|
||||
* @param lock - pointer to created mutex
|
||||
* @param count - initial count 0 or 1
|
||||
* @param context - context for mutex
|
||||
*
|
||||
* @return - status of function execution
|
||||
*/
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
int32_t env_create_mutex(void **lock, int32_t count, void *context);
|
||||
#else
|
||||
int32_t env_create_mutex(void **lock, int32_t count);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* env_delete_mutex
|
||||
*
|
||||
* Deletes the given lock.
|
||||
*
|
||||
* @param lock - mutex to delete
|
||||
*/
|
||||
|
||||
void env_delete_mutex(void *lock);
|
||||
|
||||
/*!
|
||||
* env_lock_mutex
|
||||
*
|
||||
* Tries to acquire the lock, if lock is not available then call to
|
||||
* this function will suspend.
|
||||
*
|
||||
* @param lock - mutex to lock
|
||||
*
|
||||
*/
|
||||
|
||||
void env_lock_mutex(void *lock);
|
||||
|
||||
/*!
|
||||
* env_unlock_mutex
|
||||
*
|
||||
* Releases the given lock.
|
||||
*
|
||||
* @param lock - mutex to unlock
|
||||
*/
|
||||
|
||||
void env_unlock_mutex(void *lock);
|
||||
|
||||
/*!
|
||||
* env_create_sync_lock
|
||||
*
|
||||
* Creates a synchronization lock primitive. It is used
|
||||
* when signal has to be sent from the interrupt context to main
|
||||
* thread context.
|
||||
*
|
||||
* @param lock - pointer to created sync lock object
|
||||
* @param state - initial state , lock or unlocked
|
||||
* @param context - context for lock
|
||||
*
|
||||
* @returns - status of function execution
|
||||
*/
|
||||
#define LOCKED 0
|
||||
#define UNLOCKED 1
|
||||
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
int32_t env_create_sync_lock(void **lock, int32_t state, void *context);
|
||||
#else
|
||||
int32_t env_create_sync_lock(void **lock, int32_t state);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* env_create_sync_lock
|
||||
*
|
||||
* Deletes given sync lock object.
|
||||
*
|
||||
* @param lock - sync lock to delete.
|
||||
*
|
||||
*/
|
||||
|
||||
void env_delete_sync_lock(void *lock);
|
||||
|
||||
/*!
|
||||
* env_acquire_sync_lock
|
||||
*
|
||||
* Tries to acquire the sync lock.
|
||||
*
|
||||
* @param lock - sync lock to acquire.
|
||||
*/
|
||||
void env_acquire_sync_lock(void *lock);
|
||||
|
||||
/*!
|
||||
* env_release_sync_lock
|
||||
*
|
||||
* Releases synchronization lock.
|
||||
*
|
||||
* @param lock - sync lock to release.
|
||||
*/
|
||||
void env_release_sync_lock(void *lock);
|
||||
|
||||
/*!
|
||||
* env_sleep_msec
|
||||
*
|
||||
* Suspends the calling thread for given time in msecs.
|
||||
*
|
||||
* @param num_msec - delay in msecs
|
||||
*/
|
||||
void env_sleep_msec(uint32_t num_msec);
|
||||
|
||||
/*!
|
||||
* env_register_isr
|
||||
*
|
||||
* Registers interrupt handler data for the given interrupt vector.
|
||||
*
|
||||
* @param env Pointer to environment context data
|
||||
* @param vector_id Virtual interrupt vector number
|
||||
* @param data Interrupt handler data (virtqueue)
|
||||
*/
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
void env_register_isr(void *env, uint32_t vector_id, void *data);
|
||||
#else
|
||||
void env_register_isr(uint32_t vector_id, void *data);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* env_unregister_isr
|
||||
*
|
||||
* Unregisters interrupt handler data for the given interrupt vector.
|
||||
*
|
||||
* @param env Pointer to environment context data
|
||||
* @param vector_id Virtual interrupt vector number
|
||||
*/
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
void env_unregister_isr(void *env, uint32_t vector_id);
|
||||
#else
|
||||
void env_unregister_isr(uint32_t vector_id);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* env_enable_interrupt
|
||||
*
|
||||
* Enables the given interrupt
|
||||
*
|
||||
* @param env Pointer to environment context data
|
||||
* @param vector_id Virtual interrupt vector number
|
||||
*/
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
void env_enable_interrupt(void *env, uint32_t vector_id);
|
||||
#else
|
||||
void env_enable_interrupt(uint32_t vector_id);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* env_disable_interrupt
|
||||
*
|
||||
* Disables the given interrupt.
|
||||
*
|
||||
* @param env Pointer to environment context data
|
||||
* @param vector_id Virtual interrupt vector number
|
||||
*/
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
void env_disable_interrupt(void *env, uint32_t vector_id);
|
||||
#else
|
||||
void env_disable_interrupt(uint32_t vector_id);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* env_map_memory
|
||||
*
|
||||
* Enables memory mapping for given memory region.
|
||||
*
|
||||
* @param pa - physical address of memory
|
||||
* @param va - logical address of memory
|
||||
* @param size - memory size
|
||||
* param flags - flags for cache/uncached and access type
|
||||
*
|
||||
* Currently only first byte of flag parameter is used and bits mapping is defined as follow;
|
||||
*
|
||||
* Cache bits
|
||||
* 0x0000_0001 = No cache
|
||||
* 0x0000_0010 = Write back
|
||||
* 0x0000_0100 = Write through
|
||||
* 0x0000_x000 = Not used
|
||||
*
|
||||
* Memory types
|
||||
*
|
||||
* 0x0001_xxxx = Memory Mapped
|
||||
* 0x0010_xxxx = IO Mapped
|
||||
* 0x0100_xxxx = Shared
|
||||
* 0x1000_xxxx = TLB
|
||||
*/
|
||||
|
||||
/* Macros for caching scheme used by the shared memory */
|
||||
#define UNCACHED (1 << 0)
|
||||
#define WB_CACHE (1 << 1)
|
||||
#define WT_CACHE (1 << 2)
|
||||
|
||||
/* Memory Types */
|
||||
#define MEM_MAPPED (1 << 4)
|
||||
#define IO_MAPPED (1 << 5)
|
||||
#define SHARED_MEM (1 << 6)
|
||||
#define TLB_MEM (1 << 7)
|
||||
|
||||
void env_map_memory(uint32_t pa, uint32_t va, uint32_t size, uint32_t flags);
|
||||
|
||||
/*!
|
||||
* env_get_timestamp
|
||||
*
|
||||
* Returns a 64 bit time stamp.
|
||||
*
|
||||
*
|
||||
*/
|
||||
uint64_t env_get_timestamp(void);
|
||||
|
||||
/*!
|
||||
* env_disable_cache
|
||||
*
|
||||
* Disables system caches.
|
||||
*
|
||||
*/
|
||||
|
||||
void env_disable_cache(void);
|
||||
|
||||
typedef void LOCK;
|
||||
|
||||
/*!
|
||||
* env_create_queue
|
||||
*
|
||||
* Creates a message queue.
|
||||
*
|
||||
* @param queue Pointer to created queue
|
||||
* @param length Maximum number of elements in the queue
|
||||
* @param item_size Queue element size in bytes
|
||||
* @param queue_static_storage Pointer to queue static storage buffer
|
||||
* @param queue_static_context Pointer to queue static context
|
||||
*
|
||||
* @return - status of function execution
|
||||
*/
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
int32_t env_create_queue(void **queue,
|
||||
int32_t length,
|
||||
int32_t element_size,
|
||||
uint8_t *queue_static_storage,
|
||||
rpmsg_static_queue_ctxt *queue_static_context);
|
||||
#else
|
||||
int32_t env_create_queue(void **queue, int32_t length, int32_t element_size);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* env_delete_queue
|
||||
*
|
||||
* Deletes the message queue.
|
||||
*
|
||||
* @param queue Queue to delete
|
||||
*/
|
||||
|
||||
void env_delete_queue(void *queue);
|
||||
|
||||
/*!
|
||||
* env_put_queue
|
||||
*
|
||||
* Put an element in a queue.
|
||||
*
|
||||
* @param queue Queue to put element in
|
||||
* @param msg Pointer to the message to be put into the queue
|
||||
* @param timeout_ms Timeout in ms
|
||||
*
|
||||
* @return - status of function execution
|
||||
*/
|
||||
|
||||
int32_t env_put_queue(void *queue, void *msg, uint32_t timeout_ms);
|
||||
|
||||
/*!
|
||||
* env_get_queue
|
||||
*
|
||||
* Get an element out of a queue.
|
||||
*
|
||||
* @param queue Queue to get element from
|
||||
* @param msg Pointer to a memory to save the message
|
||||
* @param timeout_ms Timeout in ms
|
||||
*
|
||||
* @return - status of function execution
|
||||
*/
|
||||
|
||||
int32_t env_get_queue(void *queue, void *msg, uint32_t timeout_ms);
|
||||
|
||||
/*!
|
||||
* env_get_current_queue_size
|
||||
*
|
||||
* Get current queue size.
|
||||
*
|
||||
* @param queue Queue pointer
|
||||
*
|
||||
* @return - Number of queued items in the queue
|
||||
*/
|
||||
|
||||
int32_t env_get_current_queue_size(void *queue);
|
||||
|
||||
/*!
|
||||
* env_isr
|
||||
*
|
||||
* Invoke RPMSG/IRQ callback
|
||||
*
|
||||
* @param env Pointer to environment context data
|
||||
* @param vector RPMSG IRQ vector ID.
|
||||
*/
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
void env_isr(void *env, uint32_t vector);
|
||||
#else
|
||||
void env_isr(uint32_t vector);
|
||||
#endif
|
||||
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
/*!
|
||||
* env_get_platform_context
|
||||
*
|
||||
* Get the platform layer context from the environment platform context
|
||||
*
|
||||
* @param env Pointer to environment context data
|
||||
*
|
||||
* @return Pointer to platform context data
|
||||
*/
|
||||
void *env_get_platform_context(void *env_context);
|
||||
|
||||
/*!
|
||||
* env_init_interrupt
|
||||
*
|
||||
* Initialize the ISR data for given virtqueue interrupt
|
||||
*
|
||||
* @param env Pointer to environment context data
|
||||
* @param vq_id Virtqueue ID
|
||||
* @param isr_data Pointer to initial ISR data
|
||||
*
|
||||
* @return Execution status, 0 on success
|
||||
*/
|
||||
int32_t env_init_interrupt(void *env, int32_t vq_id, void *isr_data);
|
||||
|
||||
/*!
|
||||
* env_deinit_interrupt
|
||||
*
|
||||
* Deinitialize the ISR data for given virtqueue interrupt
|
||||
*
|
||||
* @param env Pointer to environment context data
|
||||
* @param vq_id Virtqueue ID
|
||||
*
|
||||
* @return Execution status, 0 on success
|
||||
*/
|
||||
int32_t env_deinit_interrupt(void *env, int32_t vq_id);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* env_wait_for_link_up
|
||||
*
|
||||
* Env. specific implementation of rpmsg_lite_wait_for_link_up function with the usage
|
||||
* of RTOS sync. primitives to avoid busy loop. Returns once the link is up.
|
||||
*
|
||||
* @param link_state Pointer to the link_state parameter of the rpmsg_lite_instance structure
|
||||
* @param link_id Link ID used to define the rpmsg-lite instance, see rpmsg_platform.h
|
||||
*/
|
||||
void env_wait_for_link_up(volatile uint32_t *link_state, uint32_t link_id);
|
||||
|
||||
/*!
|
||||
* env_tx_callback
|
||||
*
|
||||
* Called from rpmsg_lite_tx_callback() to allow unblocking of env_wait_for_link_up()
|
||||
*
|
||||
* @param link_id Link ID used to define the rpmsg-lite instance, see rpmsg_platform.h
|
||||
*/
|
||||
void env_tx_callback(uint32_t link_id);
|
||||
|
||||
#endif /* RPMSG_ENV_H_ */
|
375
components/rpmsg/rpmsg-lite/include/rpmsg_lite.h
Normal file
375
components/rpmsg/rpmsg-lite/include/rpmsg_lite.h
Normal file
|
@ -0,0 +1,375 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Mentor Graphics Corporation
|
||||
* Copyright (c) 2015 Xilinx, Inc.
|
||||
* Copyright (c) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2022 NXP
|
||||
* Copyright 2021 ACRIOS Systems s.r.o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef RPMSG_LITE_H_
|
||||
#define RPMSG_LITE_H_
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h>
|
||||
#include "rpmsg_compiler.h"
|
||||
#include "virtqueue.h"
|
||||
#include "rpmsg_env.h"
|
||||
#include "llist.h"
|
||||
#include "rpmsg_default_config.h"
|
||||
|
||||
//! @addtogroup rpmsg_lite
|
||||
//! @{
|
||||
|
||||
/*******************************************************************************
|
||||
* Definitions
|
||||
******************************************************************************/
|
||||
|
||||
#define RL_VERSION "4.0.0" /*!< Current RPMsg Lite version */
|
||||
|
||||
/* Shared memory "allocator" parameters */
|
||||
#define RL_WORD_SIZE (sizeof(uint32_t))
|
||||
#define RL_WORD_ALIGN_UP(a) \
|
||||
(((((uint32_t)(a)) & (RL_WORD_SIZE - 1U)) != 0U) ? ((((uint32_t)(a)) & (~(RL_WORD_SIZE - 1U))) + 4U) : \
|
||||
((uint32_t)(a)))
|
||||
#define RL_WORD_ALIGN_DOWN(a) \
|
||||
(((((uint32_t)(a)) & (RL_WORD_SIZE - 1U)) != 0U) ? (((uint32_t)(a)) & (~(RL_WORD_SIZE - 1U))) : ((uint32_t)(a)))
|
||||
|
||||
/* Definitions for device types , null pointer, etc.*/
|
||||
#define RL_SUCCESS (0)
|
||||
#define RL_NULL ((void *)0)
|
||||
#define RL_REMOTE (0)
|
||||
#define RL_MASTER (1)
|
||||
#define RL_TRUE (1UL)
|
||||
#define RL_FALSE (0UL)
|
||||
#define RL_ADDR_ANY (0xFFFFFFFFU)
|
||||
#define RL_RELEASE (0)
|
||||
#define RL_HOLD (1)
|
||||
#define RL_DONT_BLOCK (0)
|
||||
#define RL_BLOCK (0xFFFFFFFFU)
|
||||
|
||||
/* Error macros. */
|
||||
#define RL_ERRORS_BASE (-5000)
|
||||
#define RL_ERR_NO_MEM (RL_ERRORS_BASE - 1)
|
||||
#define RL_ERR_BUFF_SIZE (RL_ERRORS_BASE - 2)
|
||||
#define RL_ERR_PARAM (RL_ERRORS_BASE - 3)
|
||||
#define RL_ERR_DEV_ID (RL_ERRORS_BASE - 4)
|
||||
#define RL_ERR_MAX_VQ (RL_ERRORS_BASE - 5)
|
||||
#define RL_ERR_NO_BUFF (RL_ERRORS_BASE - 6)
|
||||
#define RL_NOT_READY (RL_ERRORS_BASE - 7)
|
||||
#define RL_ALREADY_DONE (RL_ERRORS_BASE - 8)
|
||||
|
||||
/* Init flags */
|
||||
#define RL_NO_FLAGS (0)
|
||||
|
||||
/*! \typedef rl_ept_rx_cb_t
|
||||
\brief Receive callback function type.
|
||||
*/
|
||||
typedef int32_t (*rl_ept_rx_cb_t)(void *payload, uint32_t payload_len, uint32_t src, void *priv);
|
||||
|
||||
/*!
|
||||
* RPMsg Lite Endpoint structure
|
||||
*/
|
||||
struct rpmsg_lite_endpoint
|
||||
{
|
||||
uint32_t addr; /*!< endpoint address */
|
||||
rl_ept_rx_cb_t rx_cb; /*!< ISR callback function */
|
||||
void *rx_cb_data; /*!< ISR callback data */
|
||||
void *rfu; /*!< reserved for future usage */
|
||||
/* 16 bytes aligned on 32bit architecture */
|
||||
};
|
||||
|
||||
/*!
|
||||
* RPMsg Lite Endpoint static context
|
||||
*/
|
||||
struct rpmsg_lite_ept_static_context
|
||||
{
|
||||
struct rpmsg_lite_endpoint ept; /*!< memory for endpoint structure */
|
||||
struct llist node; /*!< memory for linked list node structure */
|
||||
};
|
||||
|
||||
/*!
|
||||
* Structure describing the local instance
|
||||
* of RPMSG lite communication stack and
|
||||
* holds all runtime variables needed internally
|
||||
* by the stack.
|
||||
*/
|
||||
struct rpmsg_lite_instance
|
||||
{
|
||||
struct virtqueue *rvq; /*!< receive virtqueue */
|
||||
struct virtqueue *tvq; /*!< transmit virtqueue */
|
||||
struct llist *rl_endpoints; /*!< linked list of endpoints */
|
||||
LOCK *lock; /*!< local RPMsg Lite mutex lock */
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
LOCK_STATIC_CONTEXT lock_static_ctxt; /*!< Static context for lock object creation */
|
||||
#endif
|
||||
uint32_t link_state; /*!< state of the link, up/down*/
|
||||
char *sh_mem_base; /*!< base address of the shared memory */
|
||||
uint32_t sh_mem_remaining; /*!< amount of remaining unused buffers in shared memory */
|
||||
uint32_t sh_mem_total; /*!< total amount of buffers in shared memory */
|
||||
struct virtqueue_ops const *vq_ops; /*!< ops functions table pointer */
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
void *env; /*!< pointer to the environment layer context */
|
||||
#endif
|
||||
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
struct vq_static_context vq_ctxt[2];
|
||||
#endif
|
||||
uint32_t link_id; /*!< linkID of this rpmsg_lite instance */
|
||||
};
|
||||
|
||||
/*******************************************************************************
|
||||
* API
|
||||
******************************************************************************/
|
||||
|
||||
/* Exported API functions */
|
||||
|
||||
/*!
|
||||
* @brief Initializes the RPMsg-Lite communication stack.
|
||||
* Must be called prior to any other RPMSG lite API.
|
||||
* To be called by the master side.
|
||||
*
|
||||
* @param shmem_addr Shared memory base used for this instance of RPMsg-Lite
|
||||
* @param shmem_length Length of memory area given by previous parameter
|
||||
* @param link_id Link ID used to define the rpmsg-lite instance, see rpmsg_platform.h
|
||||
* @param init_flags Initialization flags
|
||||
* @param env_cfg Initialization data for the environement RPMsg-Lite layer, used when
|
||||
* the environment layer uses its own context (RL_USE_ENVIRONMENT_CONTEXT)
|
||||
* @param static_context RPMsg-Lite preallocated context pointer, used in case of static api (RL_USE_STATIC_API)
|
||||
*
|
||||
* @return New RPMsg-Lite instance pointer or RL_NULL.
|
||||
*
|
||||
*/
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
struct rpmsg_lite_instance *rpmsg_lite_master_init(void *shmem_addr,
|
||||
size_t shmem_length,
|
||||
uint32_t link_id,
|
||||
uint32_t init_flags,
|
||||
struct rpmsg_lite_instance *static_context);
|
||||
#elif defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
struct rpmsg_lite_instance *rpmsg_lite_master_init(
|
||||
void *shmem_addr, size_t shmem_length, uint32_t link_id, uint32_t init_flags, void *env_cfg);
|
||||
#else
|
||||
struct rpmsg_lite_instance *rpmsg_lite_master_init(void *shmem_addr,
|
||||
size_t shmem_length,
|
||||
uint32_t link_id,
|
||||
uint32_t init_flags);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initializes the RPMsg-Lite communication stack.
|
||||
* Must be called prior to any other RPMsg-Lite API.
|
||||
* To be called by the remote side.
|
||||
*
|
||||
* @param shmem_addr Shared memory base used for this instance of RPMsg-Lite
|
||||
* @param link_id Link ID used to define the rpmsg-lite instance, see rpmsg_platform.h
|
||||
* @param init_flags Initialization flags
|
||||
* @param env_cfg Initialization data for the environement RPMsg-Lite layer, used when
|
||||
* the environment layer uses its own context (RL_USE_ENVIRONMENT_CONTEXT)
|
||||
* @param static_context RPMsg-Lite preallocated context pointer, used in case of static api (RL_USE_STATIC_API)
|
||||
*
|
||||
* @return New RPMsg-Lite instance pointer or RL_NULL.
|
||||
*
|
||||
*/
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
struct rpmsg_lite_instance *rpmsg_lite_remote_init(void *shmem_addr,
|
||||
uint32_t link_id,
|
||||
uint32_t init_flags,
|
||||
struct rpmsg_lite_instance *static_context);
|
||||
#elif defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
struct rpmsg_lite_instance *rpmsg_lite_remote_init(void *shmem_addr,
|
||||
uint32_t link_id,
|
||||
uint32_t init_flags,
|
||||
void *env_cfg);
|
||||
#else
|
||||
struct rpmsg_lite_instance *rpmsg_lite_remote_init(void *shmem_addr, uint32_t link_id, uint32_t init_flags);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
*
|
||||
* @brief Deinitialized the RPMsg-Lite communication stack
|
||||
* This function always succeeds.
|
||||
* rpmsg_lite_init() can be called again after this
|
||||
* function has been called.
|
||||
*
|
||||
* @param rpmsg_lite_dev RPMsg-Lite instance
|
||||
*
|
||||
* @return Status of function execution, RL_SUCCESS on success.
|
||||
*/
|
||||
int32_t rpmsg_lite_deinit(struct rpmsg_lite_instance *rpmsg_lite_dev);
|
||||
|
||||
/*!
|
||||
* @brief Create a new rpmsg endpoint, which can be used
|
||||
* for communication.
|
||||
*
|
||||
* @param rpmsg_lite_dev RPMsg-Lite instance
|
||||
* @param addr Desired address, RL_ADDR_ANY for automatic selection
|
||||
* @param rx_cb Callback function called on receive
|
||||
* @param rx_cb_data Callback data pointer, passed to rx_cb
|
||||
* @param ept_context Endpoint preallocated context pointer, used in case of static api (RL_USE_STATIC_API)
|
||||
*
|
||||
* @return RL_NULL on error, new endpoint pointer on success.
|
||||
*
|
||||
*/
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
struct rpmsg_lite_endpoint *rpmsg_lite_create_ept(struct rpmsg_lite_instance *rpmsg_lite_dev,
|
||||
uint32_t addr,
|
||||
rl_ept_rx_cb_t rx_cb,
|
||||
void *rx_cb_data,
|
||||
struct rpmsg_lite_ept_static_context *ept_context);
|
||||
#else
|
||||
struct rpmsg_lite_endpoint *rpmsg_lite_create_ept(struct rpmsg_lite_instance *rpmsg_lite_dev,
|
||||
uint32_t addr,
|
||||
rl_ept_rx_cb_t rx_cb,
|
||||
void *rx_cb_data);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* @brief This function deletes rpmsg endpoint and performs cleanup.
|
||||
*
|
||||
* @param rpmsg_lite_dev RPMsg-Lite instance
|
||||
* @param rl_ept Pointer to endpoint to destroy
|
||||
*
|
||||
*/
|
||||
int32_t rpmsg_lite_destroy_ept(struct rpmsg_lite_instance *rpmsg_lite_dev, struct rpmsg_lite_endpoint *rl_ept);
|
||||
|
||||
/*!
|
||||
*
|
||||
* @brief Sends a message contained in data field of length size
|
||||
* to the remote endpoint with address dst.
|
||||
* ept->addr is used as source address in the rpmsg header
|
||||
* of the message being sent.
|
||||
*
|
||||
* @param rpmsg_lite_dev RPMsg-Lite instance
|
||||
* @param ept Sender endpoint
|
||||
* @param dst Remote endpoint address
|
||||
* @param data Payload buffer
|
||||
* @param size Size of payload, in bytes
|
||||
* @param timeout Timeout in ms, 0 if nonblocking
|
||||
*
|
||||
* @return Status of function execution, RL_SUCCESS on success.
|
||||
*
|
||||
*/
|
||||
int32_t rpmsg_lite_send(struct rpmsg_lite_instance *rpmsg_lite_dev,
|
||||
struct rpmsg_lite_endpoint *ept,
|
||||
uint32_t dst,
|
||||
char *data,
|
||||
uint32_t size,
|
||||
uint32_t timeout);
|
||||
|
||||
/*!
|
||||
* @brief Function to get the link state
|
||||
*
|
||||
* @param rpmsg_lite_dev RPMsg-Lite instance pointer
|
||||
*
|
||||
* @return RL_TRUE when link up, RL_FALSE when down.
|
||||
*
|
||||
*/
|
||||
uint32_t rpmsg_lite_is_link_up(struct rpmsg_lite_instance *rpmsg_lite_dev);
|
||||
|
||||
/*!
|
||||
* @brief Function to wait until the link is up. Returns
|
||||
* once the link_state is set.
|
||||
*
|
||||
* @param rpmsg_lite_dev RPMsg-Lite instance pointer
|
||||
*/
|
||||
void rpmsg_lite_wait_for_link_up(struct rpmsg_lite_instance *rpmsg_lite_dev);
|
||||
|
||||
#if defined(RL_API_HAS_ZEROCOPY) && (RL_API_HAS_ZEROCOPY == 1)
|
||||
|
||||
/*!
|
||||
* @brief Releases the rx buffer for future reuse in vring.
|
||||
* This API can be called at process context when the
|
||||
* message in rx buffer is processed.
|
||||
*
|
||||
* @param rpmsg_lite_dev RPMsg-Lite instance
|
||||
* @param rxbuf Rx buffer with message payload
|
||||
*
|
||||
* @return Status of function execution, RL_SUCCESS on success.
|
||||
*/
|
||||
int32_t rpmsg_lite_release_rx_buffer(struct rpmsg_lite_instance *rpmsg_lite_dev, void *rxbuf);
|
||||
|
||||
/*!
|
||||
* @brief Allocates the tx buffer for message payload.
|
||||
*
|
||||
* This API can only be called at process context to get the tx buffer in vring. By this way, the
|
||||
* application can directly put its message into the vring tx buffer without copy from an application buffer.
|
||||
* It is the application responsibility to correctly fill the allocated tx buffer by data and passing correct
|
||||
* parameters to the rpmsg_lite_send_nocopy() function to perform data no-copy-send mechanism.
|
||||
*
|
||||
* @param rpmsg_lite_dev RPMsg-Lite instance
|
||||
* @param[in] size Pointer to store maximum payload size available
|
||||
* @param[in] timeout Integer, wait upto timeout ms or not for buffer to become available
|
||||
*
|
||||
* @return The tx buffer address on success and RL_NULL on failure.
|
||||
*
|
||||
* @see rpmsg_lite_send_nocopy
|
||||
*/
|
||||
void *rpmsg_lite_alloc_tx_buffer(struct rpmsg_lite_instance *rpmsg_lite_dev, uint32_t *size, uint32_t timeout);
|
||||
|
||||
/*!
|
||||
* @brief Sends a message in tx buffer allocated by rpmsg_lite_alloc_tx_buffer()
|
||||
*
|
||||
* This function sends txbuf of length len to the remote dst address,
|
||||
* and uses ept->addr as the source address.
|
||||
* The application has to take the responsibility for:
|
||||
* 1. tx buffer allocation (rpmsg_lite_alloc_tx_buffer())
|
||||
* 2. filling the data to be sent into the pre-allocated tx buffer
|
||||
* 3. not exceeding the buffer size when filling the data
|
||||
* 4. data cache coherency
|
||||
*
|
||||
* After the rpmsg_lite_send_nocopy() function is issued the tx buffer is no more owned
|
||||
* by the sending task and must not be touched anymore unless the rpmsg_lite_send_nocopy()
|
||||
* function fails and returns an error.
|
||||
*
|
||||
* @param rpmsg_lite_dev RPMsg-Lite instance
|
||||
* @param[in] ept Sender endpoint pointer
|
||||
* @param[in] dst Destination address
|
||||
* @param[in] data TX buffer with message filled
|
||||
* @param[in] size Length of payload
|
||||
*
|
||||
* @return 0 on success and an appropriate error value on failure.
|
||||
*
|
||||
* @see rpmsg_lite_alloc_tx_buffer
|
||||
*/
|
||||
int32_t rpmsg_lite_send_nocopy(struct rpmsg_lite_instance *rpmsg_lite_dev,
|
||||
struct rpmsg_lite_endpoint *ept,
|
||||
uint32_t dst,
|
||||
void *data,
|
||||
uint32_t size);
|
||||
#endif /* RL_API_HAS_ZEROCOPY */
|
||||
|
||||
//! @}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RPMSG_LITE_H_ */
|
140
components/rpmsg/rpmsg-lite/include/rpmsg_ns.h
Normal file
140
components/rpmsg/rpmsg-lite/include/rpmsg_ns.h
Normal file
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Mentor Graphics Corporation
|
||||
* Copyright (c) 2015 Xilinx, Inc.
|
||||
* Copyright (c) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2016 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef RPMSG_NS_H_
|
||||
#define RPMSG_NS_H_
|
||||
|
||||
#include "rpmsg_lite.h"
|
||||
|
||||
//! @addtogroup rpmsg_ns
|
||||
//! @{
|
||||
|
||||
#define RL_NS_EPT_ADDR (0x35u)
|
||||
|
||||
/* Up to 32 flags available */
|
||||
enum rpmsg_ns_flags
|
||||
{
|
||||
RL_NS_CREATE = 0,
|
||||
RL_NS_DESTROY = 1,
|
||||
};
|
||||
|
||||
/*! \typedef rpmsg_ns_new_ept_cb
|
||||
\brief New endpoint NS callback function type.
|
||||
*/
|
||||
typedef void (*rpmsg_ns_new_ept_cb)(uint32_t new_ept, const char *new_ept_name, uint32_t flags, void *user_data);
|
||||
|
||||
struct rpmsg_ns_callback_data
|
||||
{
|
||||
rpmsg_ns_new_ept_cb cb;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct rpmsg_ns_context
|
||||
{
|
||||
struct rpmsg_lite_endpoint *ept;
|
||||
struct rpmsg_ns_callback_data *cb_ctxt;
|
||||
};
|
||||
|
||||
typedef struct rpmsg_ns_context *rpmsg_ns_handle;
|
||||
|
||||
struct rpmsg_ns_static_context_container
|
||||
{
|
||||
struct rpmsg_lite_ept_static_context ept_ctxt;
|
||||
struct rpmsg_ns_callback_data cb_ctxt;
|
||||
struct rpmsg_ns_context ns_ctxt;
|
||||
};
|
||||
|
||||
typedef struct rpmsg_ns_static_context_container rpmsg_ns_static_context;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*******************************************************************************
|
||||
* API
|
||||
******************************************************************************/
|
||||
|
||||
/* Exported API functions */
|
||||
|
||||
/*!
|
||||
* @brief Registers application nameservice callback
|
||||
*
|
||||
* @param rpmsg_lite_dev RPMsg-Lite instance
|
||||
* @param app_cb Application nameservice callback
|
||||
* @param user_data Application nameservice callback data
|
||||
*
|
||||
* @return RL_NULL on error, NameService handle on success.
|
||||
*
|
||||
*/
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
rpmsg_ns_handle rpmsg_ns_bind(struct rpmsg_lite_instance *rpmsg_lite_dev,
|
||||
rpmsg_ns_new_ept_cb app_cb,
|
||||
void *user_data,
|
||||
rpmsg_ns_static_context *ns_ept_ctxt);
|
||||
#else
|
||||
rpmsg_ns_handle rpmsg_ns_bind(struct rpmsg_lite_instance *rpmsg_lite_dev, rpmsg_ns_new_ept_cb app_cb, void *user_data);
|
||||
#endif /* RL_USE_STATIC_API */
|
||||
|
||||
/*!
|
||||
* @brief Unregisters application nameservice callback and cleans up
|
||||
*
|
||||
* @param rpmsg_lite_dev RPMsg-Lite instance
|
||||
* @param handle NameService handle
|
||||
*
|
||||
* @return Status of function execution, RL_SUCCESS on success.
|
||||
*
|
||||
*/
|
||||
int32_t rpmsg_ns_unbind(struct rpmsg_lite_instance *rpmsg_lite_dev, rpmsg_ns_handle handle);
|
||||
|
||||
/*!
|
||||
* @brief Sends name service announcement to remote device
|
||||
*
|
||||
* @param rpmsg_lite_dev RPMsg-Lite instance
|
||||
* @param new_ept New endpoint to announce
|
||||
* @param ept_name Name for the announced endpoint
|
||||
* @param flags Channel creation/deletion flags
|
||||
*
|
||||
* @return Status of function execution, RL_SUCCESS on success
|
||||
*
|
||||
*/
|
||||
int32_t rpmsg_ns_announce(struct rpmsg_lite_instance *rpmsg_lite_dev,
|
||||
struct rpmsg_lite_endpoint *new_ept,
|
||||
const char *ept_name,
|
||||
uint32_t flags);
|
||||
|
||||
//! @}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RPMSG_NS_H_ */
|
203
components/rpmsg/rpmsg-lite/include/rpmsg_queue.h
Normal file
203
components/rpmsg/rpmsg-lite/include/rpmsg_queue.h
Normal file
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Mentor Graphics Corporation
|
||||
* Copyright (c) 2015 Xilinx, Inc.
|
||||
* Copyright (c) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2021 NXP
|
||||
* Copyright 2021 ACRIOS Systems s.r.o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef RPMSG_QUEUE_H_
|
||||
#define RPMSG_QUEUE_H_
|
||||
|
||||
#include "rpmsg_lite.h"
|
||||
|
||||
//! @addtogroup rpmsg_queue
|
||||
//! @{
|
||||
|
||||
/*! \typedef rpmsg_queue_handle
|
||||
\brief Rpmsg queue handle type.
|
||||
*/
|
||||
typedef void *rpmsg_queue_handle;
|
||||
|
||||
/* RL_API_HAS_ZEROCOPY has to be enabled for RPMsg Queue to work */
|
||||
#if defined(RL_API_HAS_ZEROCOPY) && (RL_API_HAS_ZEROCOPY == 1)
|
||||
|
||||
/*******************************************************************************
|
||||
* API
|
||||
******************************************************************************/
|
||||
|
||||
/* Exported API functions */
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* @brief
|
||||
* This callback needs to be registered with an endpoint
|
||||
*
|
||||
* @param payload Pointer to the buffer containing received data
|
||||
* @param payload_len Size of data received, in bytes
|
||||
* @param src Pointer to address of the endpoint from which data is received
|
||||
* @param priv Private data provided during endpoint creation
|
||||
*
|
||||
* @return RL_HOLD or RL_RELEASE to release or hold the buffer in payload
|
||||
*/
|
||||
int32_t rpmsg_queue_rx_cb(void *payload, uint32_t payload_len, uint32_t src, void *priv);
|
||||
|
||||
/*!
|
||||
* @brief
|
||||
* Create a RPMsg queue which can be used
|
||||
* for blocking reception.
|
||||
*
|
||||
* @param rpmsg_lite_dev RPMsg Lite instance
|
||||
* @param queue_storage RPMsg Lite queue static storage pointer
|
||||
* @param queue_ctxt RPMsg Lite queue static context holder
|
||||
*
|
||||
* @return RPMsg queue handle or RL_NULL
|
||||
*
|
||||
*/
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
rpmsg_queue_handle rpmsg_queue_create(struct rpmsg_lite_instance *rpmsg_lite_dev,
|
||||
uint8_t *queue_storage,
|
||||
rpmsg_static_queue_ctxt *queue_ctxt);
|
||||
#else
|
||||
rpmsg_queue_handle rpmsg_queue_create(struct rpmsg_lite_instance *rpmsg_lite_dev);
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* @brief
|
||||
* Destroy a queue and clean up.
|
||||
* Do not destroy a queue which is registered with an active endpoint!
|
||||
*
|
||||
* @param rpmsg_lite_dev RPMsg-Lite instance
|
||||
* @param[in] q RPMsg queue handle to destroy
|
||||
*
|
||||
* @return Status of function execution
|
||||
*
|
||||
*/
|
||||
int32_t rpmsg_queue_destroy(struct rpmsg_lite_instance *rpmsg_lite_dev, rpmsg_queue_handle q);
|
||||
|
||||
/*!
|
||||
* @brief
|
||||
* blocking receive function - blocking version of the received function that can be called from an RTOS task.
|
||||
* The data is copied from the receive buffer into the user supplied buffer.
|
||||
*
|
||||
* This is the "receive with copy" version of the RPMsg receive function. This version is simple
|
||||
* to use but it requires copying data from shared memory into the user space buffer.
|
||||
* The user has no obligation or burden to manage the shared memory buffers.
|
||||
*
|
||||
* @param rpmsg_lite_dev RPMsg-Lite instance
|
||||
* @param[in] q RPMsg queue handle to listen on
|
||||
* @param[in] data Pointer to the user buffer the received data are copied to
|
||||
* @param[out] len Pointer to an int variable that will contain the number of bytes actually copied into the
|
||||
* buffer
|
||||
* @param[in] maxlen Maximum number of bytes to copy (received buffer size)
|
||||
* @param[out] src Pointer to address of the endpoint from which data is received
|
||||
* @param[in] timeout Timeout, in milliseconds, to wait for a message. A value of 0 means don't wait (non-blocking
|
||||
* call).
|
||||
* A value of 0xffffffff means wait forever (blocking call).
|
||||
*
|
||||
* @return Status of function execution
|
||||
*
|
||||
* @see rpmsg_queue_recv_nocopy
|
||||
*/
|
||||
int32_t rpmsg_queue_recv(struct rpmsg_lite_instance *rpmsg_lite_dev,
|
||||
rpmsg_queue_handle q,
|
||||
uint32_t *src,
|
||||
char *data,
|
||||
uint32_t maxlen,
|
||||
uint32_t *len,
|
||||
uint32_t timeout);
|
||||
|
||||
/*!
|
||||
* @brief
|
||||
* blocking receive function - blocking version of the received function that can be called from an RTOS task.
|
||||
* The data is NOT copied into the user-app. buffer.
|
||||
*
|
||||
* This is the "zero-copy receive" version of the RPMsg receive function. No data is copied.
|
||||
* Only the pointer to the data is returned. This version is fast, but it requires the user to manage
|
||||
* buffer allocation. Specifically, the user must decide when a buffer is no longer in use and
|
||||
* make the appropriate API call to free it, see rpmsg_queue_nocopy_free().
|
||||
*
|
||||
* @param rpmsg_lite_dev RPMsg Lite instance
|
||||
* @param[in] q RPMsg queue handle to listen on
|
||||
* @param[out] data Pointer to the RPMsg buffer of the shared memory where the received data is stored
|
||||
* @param[out] len Pointer to an int variable that that will contain the number of valid bytes in the RPMsg
|
||||
* buffer
|
||||
* @param[out] src Pointer to address of the endpoint from which data is received
|
||||
* @param[in] timeout Timeout, in milliseconds, to wait for a message. A value of 0 means don't wait (non-blocking
|
||||
* call).
|
||||
* A value of 0xffffffff means wait forever (blocking call).
|
||||
*
|
||||
* @return Status of function execution.
|
||||
*
|
||||
* @see rpmsg_queue_nocopy_free
|
||||
* @see rpmsg_queue_recv
|
||||
*/
|
||||
int32_t rpmsg_queue_recv_nocopy(struct rpmsg_lite_instance *rpmsg_lite_dev,
|
||||
rpmsg_queue_handle q,
|
||||
uint32_t *src,
|
||||
char **data,
|
||||
uint32_t *len,
|
||||
uint32_t timeout);
|
||||
|
||||
/*!
|
||||
* @brief This function frees a buffer previously returned by rpmsg_queue_recv_nocopy().
|
||||
*
|
||||
* Once the zero-copy mechanism of receiving data is used, this function
|
||||
* has to be called to free a buffer and to make it available for the next data
|
||||
* transfer.
|
||||
*
|
||||
* @param rpmsg_lite_dev RPMsg-Lite instance
|
||||
* @param[in] data Pointer to the RPMsg buffer of the shared memory that has to be freed
|
||||
*
|
||||
* @return Status of function execution.
|
||||
*
|
||||
* @see rpmsg_queue_recv_nocopy
|
||||
*/
|
||||
int32_t rpmsg_queue_nocopy_free(struct rpmsg_lite_instance *rpmsg_lite_dev, void *data);
|
||||
|
||||
/*!
|
||||
* @brief This function returns the number of pending messages in the queue.
|
||||
*
|
||||
* @param[in] q RPMsg queue handle
|
||||
*
|
||||
* @return Number of pending messages in the queue.
|
||||
*/
|
||||
int32_t rpmsg_queue_get_current_size(rpmsg_queue_handle q);
|
||||
|
||||
//! @}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* RL_API_HAS_ZEROCOPY */
|
||||
|
||||
#endif /* RPMSG_QUEUE_H_ */
|
168
components/rpmsg/rpmsg-lite/include/virtio_ring.h
Normal file
168
components/rpmsg/rpmsg-lite/include/virtio_ring.h
Normal file
|
@ -0,0 +1,168 @@
|
|||
/*-
|
||||
* Copyright Rusty Russell IBM Corporation 2007.
|
||||
* Copyright 2019 NXP
|
||||
* This header is BSD licensed so anyone can use the definitions to implement
|
||||
* compatible drivers/servers.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of IBM nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef VIRTIO_RING_H
|
||||
#define VIRTIO_RING_H
|
||||
|
||||
/* This marks a buffer as continuing via the next field. */
|
||||
#define VRING_DESC_F_NEXT 1U
|
||||
/* This marks a buffer as write-only (otherwise read-only). */
|
||||
#define VRING_DESC_F_WRITE 2U
|
||||
/* This means the buffer contains a list of buffer descriptors. */
|
||||
#define VRING_DESC_F_INDIRECT 4U
|
||||
|
||||
/* The Host uses this in used->flags to advise the Guest: don't kick me
|
||||
* when you add a buffer. It's unreliable, so it's simply an
|
||||
* optimization. Guest will still kick if it's out of buffers. */
|
||||
#define VRING_USED_F_NO_NOTIFY 1U
|
||||
/* The Guest uses this in avail->flags to advise the Host: don't
|
||||
* interrupt me when you consume a buffer. It's unreliable, so it's
|
||||
* simply an optimization. */
|
||||
#define VRING_AVAIL_F_NO_INTERRUPT 1U
|
||||
|
||||
/* VirtIO ring descriptors: 16 bytes.
|
||||
* These can chain together via "next". */
|
||||
struct vring_desc
|
||||
{
|
||||
/* Address (guest-physical). */
|
||||
uint64_t addr;
|
||||
/* Length. */
|
||||
uint32_t len;
|
||||
/* The flags as indicated above. */
|
||||
uint16_t flags;
|
||||
/* We chain unused descriptors via this, too. */
|
||||
uint16_t next;
|
||||
};
|
||||
|
||||
struct vring_avail
|
||||
{
|
||||
uint16_t flags;
|
||||
uint16_t idx;
|
||||
uint16_t ring[1];
|
||||
};
|
||||
|
||||
/* uint32_t is used here for ids for padding reasons. */
|
||||
struct vring_used_elem
|
||||
{
|
||||
/* Index of start of used descriptor chain. */
|
||||
uint32_t id;
|
||||
/* Total length of the descriptor chain which was written to. */
|
||||
uint32_t len;
|
||||
};
|
||||
|
||||
struct vring_used
|
||||
{
|
||||
uint16_t flags;
|
||||
uint16_t idx;
|
||||
struct vring_used_elem ring[1];
|
||||
};
|
||||
|
||||
struct vring
|
||||
{
|
||||
uint32_t num;
|
||||
|
||||
struct vring_desc *desc;
|
||||
struct vring_avail *avail;
|
||||
struct vring_used *used;
|
||||
};
|
||||
|
||||
/* The standard layout for the ring is a continuous chunk of memory which
|
||||
* looks like this. We assume num is a power of 2.
|
||||
*
|
||||
* struct vring {
|
||||
* # The actual descriptors (16 bytes each)
|
||||
* struct vring_desc desc[num];
|
||||
*
|
||||
* # A ring of available descriptor heads with free-running index.
|
||||
* __u16 avail_flags;
|
||||
* __u16 avail_idx;
|
||||
* __u16 available[num];
|
||||
* __u16 used_event_idx;
|
||||
*
|
||||
* # Padding to the next align boundary.
|
||||
* char pad[];
|
||||
*
|
||||
* # A ring of used descriptor heads with free-running index.
|
||||
* __u16 used_flags;
|
||||
* __u16 used_idx;
|
||||
* struct vring_used_elem used[num];
|
||||
* __u16 avail_event_idx;
|
||||
* };
|
||||
*
|
||||
* NOTE: for VirtIO PCI, align is 4096.
|
||||
*/
|
||||
|
||||
/*
|
||||
* We publish the used event index at the end of the available ring, and vice
|
||||
* versa. They are at the end for backwards compatibility.
|
||||
*/
|
||||
#define vring_used_event(vr) ((vr)->avail->ring[(vr)->num])
|
||||
#define vring_avail_event(vr) ((vr)->used->ring[(vr)->num].id)
|
||||
|
||||
static inline int32_t vring_size(uint32_t num, uint32_t align)
|
||||
{
|
||||
uint32_t size;
|
||||
|
||||
size = num * sizeof(struct vring_desc);
|
||||
size += sizeof(struct vring_avail) + (num * sizeof(uint16_t)) + sizeof(uint16_t);
|
||||
size = (size + align - 1UL) & ~(align - 1UL);
|
||||
size += sizeof(struct vring_used) + (num * sizeof(struct vring_used_elem)) + sizeof(uint16_t);
|
||||
return ((int32_t)size);
|
||||
}
|
||||
|
||||
static inline void vring_init(struct vring *vr, uint32_t num, uint8_t *p, uint32_t align)
|
||||
{
|
||||
vr->num = num;
|
||||
vr->desc = (struct vring_desc *)(void *)p;
|
||||
vr->avail = (struct vring_avail *)(void *)(p + num * sizeof(struct vring_desc));
|
||||
vr->used = (struct vring_used *)(((uintptr_t)&vr->avail->ring[num] + align - 1UL) & ~(align - 1UL));
|
||||
}
|
||||
|
||||
/*
|
||||
* The following is used with VIRTIO_RING_F_EVENT_IDX.
|
||||
*
|
||||
* Assuming a given event_idx value from the other size, if we have
|
||||
* just incremented index from old to new_idx, should we trigger an
|
||||
* event?
|
||||
*/
|
||||
static inline int32_t vring_need_event(uint16_t event_idx, uint16_t new_idx, uint16_t old)
|
||||
{
|
||||
if ((uint16_t)(new_idx - event_idx - 1U) < (uint16_t)(new_idx - old))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif /* VIRTIO_RING_H */
|
252
components/rpmsg/rpmsg-lite/include/virtqueue.h
Normal file
252
components/rpmsg/rpmsg-lite/include/virtqueue.h
Normal file
|
@ -0,0 +1,252 @@
|
|||
#ifndef VIRTQUEUE_H_
|
||||
#define VIRTQUEUE_H_
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org>
|
||||
* Copyright (c) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2019 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice unmodified, this list of conditions, and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "rpmsg_default_config.h"
|
||||
typedef uint8_t boolean;
|
||||
|
||||
#include "virtio_ring.h"
|
||||
#include "llist.h"
|
||||
|
||||
/*Error Codes*/
|
||||
#define VQ_ERROR_BASE (-3000)
|
||||
#define ERROR_VRING_FULL (VQ_ERROR_BASE - 1)
|
||||
#define ERROR_INVLD_DESC_IDX (VQ_ERROR_BASE - 2)
|
||||
#define ERROR_EMPTY_RING (VQ_ERROR_BASE - 3)
|
||||
#define ERROR_NO_MEM (VQ_ERROR_BASE - 4)
|
||||
#define ERROR_VRING_MAX_DESC (VQ_ERROR_BASE - 5)
|
||||
#define ERROR_VRING_ALIGN (VQ_ERROR_BASE - 6)
|
||||
#define ERROR_VRING_NO_BUFF (VQ_ERROR_BASE - 7)
|
||||
#define ERROR_VQUEUE_INVLD_PARAM (VQ_ERROR_BASE - 8)
|
||||
|
||||
#define VQUEUE_SUCCESS (0)
|
||||
#define VQUEUE_DEBUG (false)
|
||||
|
||||
/* This is temporary macro to replace C NULL support.
|
||||
* At the moment all the RTL specific functions are present in env.
|
||||
* */
|
||||
#define VQ_NULL ((void *)0)
|
||||
|
||||
/* The maximum virtqueue size is 2^15. Use that value as the end of
|
||||
* descriptor chain terminator since it will never be a valid index
|
||||
* in the descriptor table. This is used to verify we are correctly
|
||||
* handling vq_free_cnt.
|
||||
*/
|
||||
#define VQ_RING_DESC_CHAIN_END (32768)
|
||||
#define VIRTQUEUE_FLAG_INDIRECT (0x0001U)
|
||||
#define VIRTQUEUE_FLAG_EVENT_IDX (0x0002U)
|
||||
#define VIRTQUEUE_MAX_NAME_SZ (32) /* mind the alignment */
|
||||
|
||||
/* Support for indirect buffer descriptors. */
|
||||
#define VIRTIO_RING_F_INDIRECT_DESC (1 << 28)
|
||||
|
||||
/* Support to suppress interrupt until specific index is reached. */
|
||||
#define VIRTIO_RING_F_EVENT_IDX (1 << 29)
|
||||
|
||||
/*
|
||||
* Hint on how long the next interrupt should be postponed. This is
|
||||
* only used when the EVENT_IDX feature is negotiated.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
VQ_POSTPONE_SHORT,
|
||||
VQ_POSTPONE_LONG,
|
||||
VQ_POSTPONE_EMPTIED /* Until all available desc are used. */
|
||||
} vq_postpone_t;
|
||||
|
||||
/* local virtqueue representation, not in shared memory */
|
||||
struct virtqueue
|
||||
{
|
||||
/* 32bit aligned { */
|
||||
char vq_name[VIRTQUEUE_MAX_NAME_SZ];
|
||||
uint32_t vq_flags;
|
||||
int32_t vq_alignment;
|
||||
int32_t vq_ring_size;
|
||||
void *vq_ring_mem;
|
||||
void (*callback_fc)(struct virtqueue *vq);
|
||||
void (*notify_fc)(struct virtqueue *vq);
|
||||
int32_t vq_max_indirect_size;
|
||||
int32_t vq_indirect_mem_size;
|
||||
struct vring vq_ring;
|
||||
/* } 32bit aligned */
|
||||
|
||||
/* 16bit aligned { */
|
||||
uint16_t vq_queue_index;
|
||||
uint16_t vq_nentries;
|
||||
uint16_t vq_free_cnt;
|
||||
uint16_t vq_queued_cnt;
|
||||
|
||||
/*
|
||||
* Head of the free chain in the descriptor table. If
|
||||
* there are no free descriptors, this will be set to
|
||||
* VQ_RING_DESC_CHAIN_END.
|
||||
*/
|
||||
uint16_t vq_desc_head_idx;
|
||||
|
||||
/*
|
||||
* Last consumed descriptor in the used table,
|
||||
* trails vq_ring.used->idx.
|
||||
*/
|
||||
uint16_t vq_used_cons_idx;
|
||||
|
||||
/*
|
||||
* Last consumed descriptor in the available table -
|
||||
* used by the consumer side.
|
||||
*/
|
||||
uint16_t vq_available_idx;
|
||||
/* } 16bit aligned */
|
||||
|
||||
boolean avail_read; /* 8bit wide */
|
||||
boolean avail_write; /* 8bit wide */
|
||||
boolean used_read; /* 8bit wide */
|
||||
boolean used_write; /* 8bit wide */
|
||||
|
||||
uint16_t padd; /* aligned to 32bits after this: */
|
||||
|
||||
void *priv; /* private pointer, upper layer instance pointer */
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
void *env; /* private pointer to environment layer internal context */
|
||||
#endif
|
||||
};
|
||||
|
||||
/* struct to hold vring specific information */
|
||||
struct vring_alloc_info
|
||||
{
|
||||
void *phy_addr;
|
||||
uint32_t align;
|
||||
uint16_t num_descs;
|
||||
uint16_t pad;
|
||||
};
|
||||
|
||||
struct vq_static_context
|
||||
{
|
||||
struct virtqueue vq;
|
||||
};
|
||||
|
||||
typedef void vq_callback(struct virtqueue *vq);
|
||||
typedef void vq_notify(struct virtqueue *vq);
|
||||
|
||||
#if (VQUEUE_DEBUG == true)
|
||||
#define VQASSERT_BOOL(_vq, _exp, _msg) \
|
||||
do \
|
||||
{ \
|
||||
if (!(_exp)) \
|
||||
{ \
|
||||
env_print("%s: %s - "(_msg), __func__, (_vq)->vq_name); \
|
||||
while (1) \
|
||||
{ \
|
||||
}; \
|
||||
} \
|
||||
} while (0)
|
||||
#define VQASSERT(_vq, _exp, _msg) VQASSERT_BOOL(_vq, (_exp) != 0, _msg)
|
||||
|
||||
#define VQ_RING_ASSERT_VALID_IDX(_vq, _idx) VQASSERT((_vq), (_idx) < (_vq)->vq_nentries, "invalid ring index")
|
||||
|
||||
#define VQ_PARAM_CHK(condition, status_var, status_err) \
|
||||
if ((status_var == 0) && (condition)) \
|
||||
{ \
|
||||
status_var = status_err; \
|
||||
}
|
||||
|
||||
#define VQUEUE_BUSY(vq, dir) \
|
||||
if ((vq)->dir == false) \
|
||||
{ \
|
||||
(vq)->dir = true; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
VQASSERT(vq, (vq)->dir == false, "VirtQueue already in use") \
|
||||
}
|
||||
|
||||
#define VQUEUE_IDLE(vq, dir) ((vq)->dir = false)
|
||||
|
||||
#else
|
||||
|
||||
#define KASSERT(cond, str)
|
||||
#define VQASSERT(_vq, _exp, _msg)
|
||||
#define VQ_RING_ASSERT_VALID_IDX(_vq, _idx)
|
||||
#define VQ_PARAM_CHK(condition, status_var, status_err)
|
||||
#define VQUEUE_BUSY(vq, dir)
|
||||
#define VQUEUE_IDLE(vq, dir)
|
||||
|
||||
#endif
|
||||
|
||||
int32_t virtqueue_create(uint16_t id,
|
||||
const char *name,
|
||||
struct vring_alloc_info *ring,
|
||||
void (*callback_fc)(struct virtqueue *vq),
|
||||
void (*notify_fc)(struct virtqueue *vq),
|
||||
struct virtqueue **v_queue);
|
||||
|
||||
int32_t virtqueue_create_static(uint16_t id,
|
||||
const char *name,
|
||||
struct vring_alloc_info *ring,
|
||||
void (*callback_fc)(struct virtqueue *vq),
|
||||
void (*notify_fc)(struct virtqueue *vq),
|
||||
struct virtqueue **v_queue,
|
||||
struct vq_static_context *vq_ctxt);
|
||||
|
||||
int32_t virtqueue_add_buffer(struct virtqueue *vq, uint16_t head_idx);
|
||||
|
||||
int32_t virtqueue_fill_used_buffers(struct virtqueue *vq, void *buffer, uint32_t len);
|
||||
|
||||
int32_t virtqueue_fill_avail_buffers(struct virtqueue *vq, void *buffer, uint32_t len);
|
||||
|
||||
void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx);
|
||||
|
||||
void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx, uint32_t *len);
|
||||
|
||||
int32_t virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx, uint32_t len);
|
||||
|
||||
void virtqueue_disable_cb(struct virtqueue *vq);
|
||||
|
||||
int32_t virtqueue_enable_cb(struct virtqueue *vq);
|
||||
|
||||
void virtqueue_kick(struct virtqueue *vq);
|
||||
|
||||
void virtqueue_free(struct virtqueue *vq);
|
||||
|
||||
void virtqueue_free_static(struct virtqueue *vq);
|
||||
|
||||
void virtqueue_dump(const char *func, struct virtqueue *vq);
|
||||
|
||||
void virtqueue_notification(struct virtqueue *vq);
|
||||
|
||||
uint32_t virtqueue_get_desc_size(struct virtqueue *vq);
|
||||
|
||||
uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx);
|
||||
|
||||
void vq_ring_init(struct virtqueue *vq);
|
||||
|
||||
#endif /* VIRTQUEUE_H_ */
|
|
@ -0,0 +1,794 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Mentor Graphics Corporation
|
||||
* Copyright (c) 2015 Xilinx, Inc.
|
||||
* Copyright (c) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2022 NXP
|
||||
* Copyright 2021 ACRIOS Systems s.r.o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/**************************************************************************
|
||||
* FILE NAME
|
||||
*
|
||||
* rpmsg_env_freertos.c
|
||||
*
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* This file is FreeRTOS Implementation of env layer for OpenAMP.
|
||||
*
|
||||
*
|
||||
**************************************************************************/
|
||||
|
||||
#include "rpmsg_compiler.h"
|
||||
#include "rpmsg_env.h"
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "semphr.h"
|
||||
#include "rpmsg_platform.h"
|
||||
#include "virtqueue.h"
|
||||
#include "event_groups.h"
|
||||
#include "rpmsg_lite.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static int32_t env_init_counter = 0;
|
||||
static SemaphoreHandle_t env_sema = ((void *)0);
|
||||
static EventGroupHandle_t event_group = ((void *)0);
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
LOCK_STATIC_CONTEXT env_sem_static_context;
|
||||
StaticEventGroup_t event_group_static_context;
|
||||
#endif
|
||||
|
||||
/* RL_ENV_MAX_MUTEX_COUNT is an arbitrary count greater than 'count'
|
||||
if the inital count is 1, this function behaves as a mutex
|
||||
if it is greater than 1, it acts as a "resource allocator" with
|
||||
the maximum of 'count' resources available.
|
||||
Currently, only the first use-case is applicable/applied in RPMsg-Lite.
|
||||
*/
|
||||
#define RL_ENV_MAX_MUTEX_COUNT (10)
|
||||
|
||||
/* Max supported ISR counts */
|
||||
#define ISR_COUNT (16U)
|
||||
/*!
|
||||
* Structure to keep track of registered ISR's.
|
||||
*/
|
||||
struct isr_info
|
||||
{
|
||||
void *data;
|
||||
};
|
||||
static struct isr_info isr_table[ISR_COUNT];
|
||||
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
#error "This RPMsg-Lite port requires RL_USE_ENVIRONMENT_CONTEXT set to 0"
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* env_in_isr
|
||||
*
|
||||
* @returns - true, if currently in ISR
|
||||
*
|
||||
*/
|
||||
static int32_t env_in_isr(void)
|
||||
{
|
||||
return platform_in_isr();
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_wait_for_link_up
|
||||
*
|
||||
* Wait until the link_state parameter of the rpmsg_lite_instance is set.
|
||||
* Utilize events to avoid busy loop implementation.
|
||||
*
|
||||
*/
|
||||
void env_wait_for_link_up(volatile uint32_t *link_state, uint32_t link_id)
|
||||
{
|
||||
(void)xEventGroupClearBits(event_group, (EventBits_t)(1UL << link_id));
|
||||
if (*link_state != 1U)
|
||||
{
|
||||
(void)xEventGroupWaitBits(event_group, (EventBits_t)(1UL << link_id), pdFALSE, pdTRUE, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_tx_callback
|
||||
*
|
||||
* Set event to notify task waiting in env_wait_for_link_up().
|
||||
*
|
||||
*/
|
||||
void env_tx_callback(uint32_t link_id)
|
||||
{
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
if (env_in_isr() != 0)
|
||||
{
|
||||
(void)xEventGroupSetBitsFromISR(event_group, (EventBits_t)(1UL << link_id), &xHigherPriorityTaskWoken);
|
||||
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)xEventGroupSetBits(event_group, (EventBits_t)(1UL << link_id));
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_init
|
||||
*
|
||||
* Initializes OS/BM environment.
|
||||
*
|
||||
*/
|
||||
int32_t env_init(void)
|
||||
{
|
||||
int32_t retval;
|
||||
vTaskSuspendAll(); /* stop scheduler */
|
||||
/* verify 'env_init_counter' */
|
||||
RL_ASSERT(env_init_counter >= 0);
|
||||
if (env_init_counter < 0)
|
||||
{
|
||||
(void)xTaskResumeAll(); /* re-enable scheduler */
|
||||
return -1;
|
||||
}
|
||||
env_init_counter++;
|
||||
/* multiple call of 'env_init' - return ok */
|
||||
if (env_init_counter == 1)
|
||||
{
|
||||
/* first call */
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
env_sema = xSemaphoreCreateBinaryStatic(&env_sem_static_context);
|
||||
event_group = xEventGroupCreateStatic(&event_group_static_context);
|
||||
#else
|
||||
env_sema = xSemaphoreCreateBinary();
|
||||
event_group = xEventGroupCreate();
|
||||
#endif
|
||||
#if (configUSE_16_BIT_TICKS == 1)
|
||||
(void)xEventGroupClearBits(event_group, 0xFFu);
|
||||
#else
|
||||
(void)xEventGroupClearBits(event_group, 0xFFFFFFu);
|
||||
#endif
|
||||
(void)memset(isr_table, 0, sizeof(isr_table));
|
||||
(void)xTaskResumeAll();
|
||||
retval = platform_init();
|
||||
(void)xSemaphoreGive(env_sema);
|
||||
|
||||
return retval;
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)xTaskResumeAll();
|
||||
/* Get the semaphore and then return it,
|
||||
* this allows for platform_init() to block
|
||||
* if needed and other tasks to wait for the
|
||||
* blocking to be done.
|
||||
* This is in ENV layer as this is ENV specific.*/
|
||||
if (pdTRUE == xSemaphoreTake(env_sema, portMAX_DELAY))
|
||||
{
|
||||
(void)xSemaphoreGive(env_sema);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_deinit
|
||||
*
|
||||
* Uninitializes OS/BM environment.
|
||||
*
|
||||
* @returns - execution status
|
||||
*/
|
||||
int32_t env_deinit(void)
|
||||
{
|
||||
int32_t retval;
|
||||
|
||||
vTaskSuspendAll(); /* stop scheduler */
|
||||
/* verify 'env_init_counter' */
|
||||
RL_ASSERT(env_init_counter > 0);
|
||||
if (env_init_counter <= 0)
|
||||
{
|
||||
(void)xTaskResumeAll(); /* re-enable scheduler */
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* counter on zero - call platform deinit */
|
||||
env_init_counter--;
|
||||
/* multiple call of 'env_deinit' - return ok */
|
||||
if (env_init_counter <= 0)
|
||||
{
|
||||
/* last call */
|
||||
(void)memset(isr_table, 0, sizeof(isr_table));
|
||||
retval = platform_deinit();
|
||||
vEventGroupDelete(event_group);
|
||||
event_group = ((void *)0);
|
||||
vSemaphoreDelete(env_sema);
|
||||
env_sema = ((void *)0);
|
||||
(void)xTaskResumeAll();
|
||||
|
||||
return retval;
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)xTaskResumeAll();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_allocate_memory - implementation
|
||||
*
|
||||
* @param size
|
||||
*/
|
||||
void *env_allocate_memory(uint32_t size)
|
||||
{
|
||||
return (pvPortMalloc(size));
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_free_memory - implementation
|
||||
*
|
||||
* @param ptr
|
||||
*/
|
||||
void env_free_memory(void *ptr)
|
||||
{
|
||||
if (ptr != ((void *)0))
|
||||
{
|
||||
vPortFree(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
*
|
||||
* env_memset - implementation
|
||||
*
|
||||
* @param ptr
|
||||
* @param value
|
||||
* @param size
|
||||
*/
|
||||
void env_memset(void *ptr, int32_t value, uint32_t size)
|
||||
{
|
||||
(void)memset(ptr, value, size);
|
||||
}
|
||||
|
||||
/*!
|
||||
*
|
||||
* env_memcpy - implementation
|
||||
*
|
||||
* @param dst
|
||||
* @param src
|
||||
* @param len
|
||||
*/
|
||||
void env_memcpy(void *dst, void const *src, uint32_t len)
|
||||
{
|
||||
(void)memcpy(dst, src, len);
|
||||
}
|
||||
|
||||
/*!
|
||||
*
|
||||
* env_strcmp - implementation
|
||||
*
|
||||
* @param dst
|
||||
* @param src
|
||||
*/
|
||||
|
||||
int32_t env_strcmp(const char *dst, const char *src)
|
||||
{
|
||||
return (strcmp(dst, src));
|
||||
}
|
||||
|
||||
/*!
|
||||
*
|
||||
* env_strncpy - implementation
|
||||
*
|
||||
* @param dest
|
||||
* @param src
|
||||
* @param len
|
||||
*/
|
||||
void env_strncpy(char *dest, const char *src, uint32_t len)
|
||||
{
|
||||
(void)strncpy(dest, src, len);
|
||||
}
|
||||
|
||||
/*!
|
||||
*
|
||||
* env_strncmp - implementation
|
||||
*
|
||||
* @param dest
|
||||
* @param src
|
||||
* @param len
|
||||
*/
|
||||
int32_t env_strncmp(char *dest, const char *src, uint32_t len)
|
||||
{
|
||||
return (strncmp(dest, src, len));
|
||||
}
|
||||
|
||||
/*!
|
||||
*
|
||||
* env_mb - implementation
|
||||
*
|
||||
*/
|
||||
void env_mb(void)
|
||||
{
|
||||
MEM_BARRIER();
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_rmb - implementation
|
||||
*/
|
||||
void env_rmb(void)
|
||||
{
|
||||
MEM_BARRIER_R();
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_wmb - implementation
|
||||
*/
|
||||
void env_wmb(void)
|
||||
{
|
||||
MEM_BARRIER_W();
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_map_vatopa - implementation
|
||||
*
|
||||
* @param address
|
||||
*/
|
||||
uint32_t env_map_vatopa(void *address)
|
||||
{
|
||||
return platform_vatopa(address);
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_map_patova - implementation
|
||||
*
|
||||
* @param address
|
||||
*/
|
||||
void *env_map_patova(uint32_t address)
|
||||
{
|
||||
return platform_patova(address);
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_create_mutex
|
||||
*
|
||||
* Creates a mutex with the given initial count.
|
||||
*
|
||||
*/
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
int32_t env_create_mutex(void **lock, int32_t count, void *context)
|
||||
#else
|
||||
int32_t env_create_mutex(void **lock, int32_t count)
|
||||
#endif
|
||||
{
|
||||
if (count > RL_ENV_MAX_MUTEX_COUNT)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
*lock = xSemaphoreCreateCountingStatic((UBaseType_t)RL_ENV_MAX_MUTEX_COUNT, (UBaseType_t)count,
|
||||
(StaticSemaphore_t *)context);
|
||||
#else
|
||||
*lock = xSemaphoreCreateCounting((UBaseType_t)RL_ENV_MAX_MUTEX_COUNT, (UBaseType_t)count);
|
||||
#endif
|
||||
if (*lock != ((void *)0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_delete_mutex
|
||||
*
|
||||
* Deletes the given lock
|
||||
*
|
||||
*/
|
||||
void env_delete_mutex(void *lock)
|
||||
{
|
||||
vSemaphoreDelete(lock);
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_lock_mutex
|
||||
*
|
||||
* Tries to acquire the lock, if lock is not available then call to
|
||||
* this function will suspend.
|
||||
*/
|
||||
void env_lock_mutex(void *lock)
|
||||
{
|
||||
SemaphoreHandle_t xSemaphore = (SemaphoreHandle_t)lock;
|
||||
if (env_in_isr() == 0)
|
||||
{
|
||||
(void)xSemaphoreTake(xSemaphore, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_unlock_mutex
|
||||
*
|
||||
* Releases the given lock.
|
||||
*/
|
||||
void env_unlock_mutex(void *lock)
|
||||
{
|
||||
SemaphoreHandle_t xSemaphore = (SemaphoreHandle_t)lock;
|
||||
if (env_in_isr() == 0)
|
||||
{
|
||||
(void)xSemaphoreGive(xSemaphore);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_create_sync_lock
|
||||
*
|
||||
* Creates a synchronization lock primitive. It is used
|
||||
* when signal has to be sent from the interrupt context to main
|
||||
* thread context.
|
||||
*/
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
int32_t env_create_sync_lock(void **lock, int32_t state, void *context)
|
||||
{
|
||||
return env_create_mutex(lock, state, context); /* state=1 .. initially free */
|
||||
}
|
||||
#else
|
||||
int32_t env_create_sync_lock(void **lock, int32_t state)
|
||||
{
|
||||
return env_create_mutex(lock, state); /* state=1 .. initially free */
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
* env_delete_sync_lock
|
||||
*
|
||||
* Deletes the given lock
|
||||
*
|
||||
*/
|
||||
void env_delete_sync_lock(void *lock)
|
||||
{
|
||||
if (lock != ((void *)0))
|
||||
{
|
||||
env_delete_mutex(lock);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_acquire_sync_lock
|
||||
*
|
||||
* Tries to acquire the lock, if lock is not available then call to
|
||||
* this function waits for lock to become available.
|
||||
*/
|
||||
void env_acquire_sync_lock(void *lock)
|
||||
{
|
||||
BaseType_t xTaskWokenByReceive = pdFALSE;
|
||||
SemaphoreHandle_t xSemaphore = (SemaphoreHandle_t)lock;
|
||||
if (env_in_isr() != 0)
|
||||
{
|
||||
(void)xSemaphoreTakeFromISR(xSemaphore, &xTaskWokenByReceive);
|
||||
portEND_SWITCHING_ISR(xTaskWokenByReceive);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)xSemaphoreTake(xSemaphore, portMAX_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_release_sync_lock
|
||||
*
|
||||
* Releases the given lock.
|
||||
*/
|
||||
void env_release_sync_lock(void *lock)
|
||||
{
|
||||
BaseType_t xTaskWokenByReceive = pdFALSE;
|
||||
SemaphoreHandle_t xSemaphore = (SemaphoreHandle_t)lock;
|
||||
if (env_in_isr() != 0)
|
||||
{
|
||||
(void)xSemaphoreGiveFromISR(xSemaphore, &xTaskWokenByReceive);
|
||||
portEND_SWITCHING_ISR(xTaskWokenByReceive);
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)xSemaphoreGive(xSemaphore);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_sleep_msec
|
||||
*
|
||||
* Suspends the calling thread for given time , in msecs.
|
||||
*/
|
||||
void env_sleep_msec(uint32_t num_msec)
|
||||
{
|
||||
vTaskDelay(num_msec / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_register_isr
|
||||
*
|
||||
* Registers interrupt handler data for the given interrupt vector.
|
||||
*
|
||||
* @param vector_id - virtual interrupt vector number
|
||||
* @param data - interrupt handler data (virtqueue)
|
||||
*/
|
||||
void env_register_isr(uint32_t vector_id, void *data)
|
||||
{
|
||||
RL_ASSERT(vector_id < ISR_COUNT);
|
||||
if (vector_id < ISR_COUNT)
|
||||
{
|
||||
isr_table[vector_id].data = data;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_unregister_isr
|
||||
*
|
||||
* Unregisters interrupt handler data for the given interrupt vector.
|
||||
*
|
||||
* @param vector_id - virtual interrupt vector number
|
||||
*/
|
||||
void env_unregister_isr(uint32_t vector_id)
|
||||
{
|
||||
RL_ASSERT(vector_id < ISR_COUNT);
|
||||
if (vector_id < ISR_COUNT)
|
||||
{
|
||||
isr_table[vector_id].data = ((void *)0);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_enable_interrupt
|
||||
*
|
||||
* Enables the given interrupt
|
||||
*
|
||||
* @param vector_id - virtual interrupt vector number
|
||||
*/
|
||||
|
||||
void env_enable_interrupt(uint32_t vector_id)
|
||||
{
|
||||
(void)platform_interrupt_enable(vector_id);
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_disable_interrupt
|
||||
*
|
||||
* Disables the given interrupt
|
||||
*
|
||||
* @param vector_id - virtual interrupt vector number
|
||||
*/
|
||||
|
||||
void env_disable_interrupt(uint32_t vector_id)
|
||||
{
|
||||
(void)platform_interrupt_disable(vector_id);
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_map_memory
|
||||
*
|
||||
* Enables memory mapping for given memory region.
|
||||
*
|
||||
* @param pa - physical address of memory
|
||||
* @param va - logical address of memory
|
||||
* @param size - memory size
|
||||
* param flags - flags for cache/uncached and access type
|
||||
*/
|
||||
|
||||
void env_map_memory(uint32_t pa, uint32_t va, uint32_t size, uint32_t flags)
|
||||
{
|
||||
platform_map_mem_region(va, pa, size, flags);
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_disable_cache
|
||||
*
|
||||
* Disables system caches.
|
||||
*
|
||||
*/
|
||||
|
||||
void env_disable_cache(void)
|
||||
{
|
||||
platform_cache_all_flush_invalidate();
|
||||
platform_cache_disable();
|
||||
}
|
||||
|
||||
/*!
|
||||
*
|
||||
* env_get_timestamp
|
||||
*
|
||||
* Returns a 64 bit time stamp.
|
||||
*
|
||||
*
|
||||
*/
|
||||
uint64_t env_get_timestamp(void)
|
||||
{
|
||||
if (env_in_isr() != 0)
|
||||
{
|
||||
return (uint64_t)xTaskGetTickCountFromISR();
|
||||
}
|
||||
else
|
||||
{
|
||||
return (uint64_t)xTaskGetTickCount();
|
||||
}
|
||||
}
|
||||
|
||||
/*========================================================= */
|
||||
/* Util data / functions */
|
||||
|
||||
void env_isr(uint32_t vector)
|
||||
{
|
||||
platform_inisr(true);
|
||||
struct isr_info *info;
|
||||
RL_ASSERT(vector < ISR_COUNT);
|
||||
if (vector < ISR_COUNT)
|
||||
{
|
||||
info = &isr_table[vector];
|
||||
virtqueue_notification((struct virtqueue *)info->data);
|
||||
}
|
||||
platform_inisr(false);
|
||||
}
|
||||
|
||||
/*
|
||||
* env_create_queue
|
||||
*
|
||||
* Creates a message queue.
|
||||
*
|
||||
* @param queue - pointer to created queue
|
||||
* @param length - maximum number of elements in the queue
|
||||
* @param element_size - queue element size in bytes
|
||||
* @param queue_static_storage - pointer to queue static storage buffer
|
||||
* @param queue_static_context - pointer to queue static context
|
||||
*
|
||||
* @return - status of function execution
|
||||
*/
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
int32_t env_create_queue(void **queue,
|
||||
int32_t length,
|
||||
int32_t element_size,
|
||||
uint8_t *queue_static_storage,
|
||||
rpmsg_static_queue_ctxt *queue_static_context)
|
||||
{
|
||||
*queue =
|
||||
xQueueCreateStatic((UBaseType_t)length, (UBaseType_t)element_size, queue_static_storage, queue_static_context);
|
||||
#else
|
||||
int32_t env_create_queue(void **queue, int32_t length, int32_t element_size)
|
||||
{
|
||||
*queue = xQueueCreate((UBaseType_t)length, (UBaseType_t)element_size);
|
||||
#endif
|
||||
if (*queue != ((void *)0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_delete_queue
|
||||
*
|
||||
* Deletes the message queue.
|
||||
*
|
||||
* @param queue - queue to delete
|
||||
*/
|
||||
|
||||
void env_delete_queue(void *queue)
|
||||
{
|
||||
vQueueDelete(queue);
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_put_queue
|
||||
*
|
||||
* Put an element in a queue.
|
||||
*
|
||||
* @param queue - queue to put element in
|
||||
* @param msg - pointer to the message to be put into the queue
|
||||
* @param timeout_ms - timeout in ms
|
||||
*
|
||||
* @return - status of function execution
|
||||
*/
|
||||
|
||||
int32_t env_put_queue(void *queue, void *msg, uint32_t timeout_ms)
|
||||
{
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
if (env_in_isr() != 0)
|
||||
{
|
||||
if (xQueueSendFromISR(queue, msg, &xHigherPriorityTaskWoken) == pdPASS)
|
||||
{
|
||||
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
|
||||
return 1;
|
||||
}
|
||||
LOG_E("Failed to send from ISR\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (xQueueSend(queue, msg, ((portMAX_DELAY == timeout_ms) ? portMAX_DELAY : timeout_ms / portTICK_PERIOD_MS)) ==
|
||||
pdPASS)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
LOG_E("Failed to send\r\n");
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_get_queue
|
||||
*
|
||||
* Get an element out of a queue.
|
||||
*
|
||||
* @param queue - queue to get element from
|
||||
* @param msg - pointer to a memory to save the message
|
||||
* @param timeout_ms - timeout in ms
|
||||
*
|
||||
* @return - status of function execution
|
||||
*/
|
||||
|
||||
int32_t env_get_queue(void *queue, void *msg, uint32_t timeout_ms)
|
||||
{
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
if (env_in_isr() != 0)
|
||||
{
|
||||
if (xQueueReceiveFromISR(queue, msg, &xHigherPriorityTaskWoken) == pdPASS)
|
||||
{
|
||||
portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (xQueueReceive(queue, msg,
|
||||
((portMAX_DELAY == timeout_ms) ? portMAX_DELAY : timeout_ms / portTICK_PERIOD_MS)) == pdPASS)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* env_get_current_queue_size
|
||||
*
|
||||
* Get current queue size.
|
||||
*
|
||||
* @param queue - queue pointer
|
||||
*
|
||||
* @return - Number of queued items in the queue
|
||||
*/
|
||||
|
||||
int32_t env_get_current_queue_size(void *queue)
|
||||
{
|
||||
if (env_in_isr() != 0)
|
||||
{
|
||||
return ((int32_t)uxQueueMessagesWaitingFromISR(queue));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ((int32_t)uxQueueMessagesWaiting(queue));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
*
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <bflb_mtimer.h>
|
||||
|
||||
#include "rpmsg_platform.h"
|
||||
#include "rpmsg_env.h"
|
||||
#include "oblfr_mailbox.h"
|
||||
|
||||
#define DBG_TAG "RPMSG"
|
||||
#include <log.h>
|
||||
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
#error "This RPMsg-Lite port requires RL_USE_ENVIRONMENT_CONTEXT set to 0"
|
||||
#endif
|
||||
|
||||
|
||||
static int32_t isr_counter = 0;
|
||||
static int32_t disable_counter = 0;
|
||||
static void *platform_lock;
|
||||
static int32_t in_isr_counter = 0;
|
||||
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
static LOCK_STATIC_CONTEXT platform_lock_static_ctxt;
|
||||
#endif
|
||||
|
||||
static void platform_isr_handle(uint16_t service, uint16_t op, uint32_t param, void *arg) {
|
||||
LOG_D("RP: Service %d, Op %d Param %d\r\n", service, op, param);
|
||||
env_isr(param);
|
||||
}
|
||||
|
||||
static void platform_global_isr_disable(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void platform_global_isr_enable(void)
|
||||
{
|
||||
}
|
||||
|
||||
int32_t platform_init_interrupt(uint32_t vector_id, void *isr_data)
|
||||
{
|
||||
/* Register ISR to environment layer */
|
||||
env_register_isr(vector_id, isr_data);
|
||||
|
||||
/* Prepare the MU Hardware, enable channel 1 interrupt */
|
||||
env_lock_mutex(platform_lock);
|
||||
|
||||
RL_ASSERT(0 <= isr_counter);
|
||||
if (isr_counter == 0)
|
||||
{
|
||||
LOG_D("RP: init irq vector %ld\r\n", vector_id);
|
||||
oblfr_mailbox_add_signal_handler(BFLB_IPC_MBOX_VIRTIO, BFLB_IPC_MBOX_VIRTIO_OP_KICK, platform_isr_handle, NULL);
|
||||
}
|
||||
isr_counter++;
|
||||
|
||||
env_unlock_mutex(platform_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t platform_deinit_interrupt(uint32_t vector_id)
|
||||
{
|
||||
/* Prepare the MU Hardware */
|
||||
env_lock_mutex(platform_lock);
|
||||
|
||||
RL_ASSERT(0 < isr_counter);
|
||||
isr_counter--;
|
||||
if (isr_counter == 0)
|
||||
{
|
||||
LOG_D("RP: deinit irq vector %ld\r\n", vector_id);
|
||||
oblfr_mailbox_del_signal_handler(BFLB_IPC_MBOX_VIRTIO, BFLB_IPC_MBOX_VIRTIO_OP_KICK);
|
||||
}
|
||||
|
||||
/* Unregister ISR from environment layer */
|
||||
env_unregister_isr(vector_id);
|
||||
|
||||
env_unlock_mutex(platform_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void platform_notify(uint32_t vector_id)
|
||||
{
|
||||
|
||||
env_lock_mutex(platform_lock);
|
||||
oblfr_mailbox_send_signal(BFLB_IPC_MBOX_VIRTIO, BFLB_IPC_MBOX_VIRTIO_OP_KICK, vector_id);
|
||||
env_unlock_mutex(platform_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* platform_time_delay
|
||||
*
|
||||
* @param num_msec Delay time in ms.
|
||||
*
|
||||
* This is not an accurate delay, it ensures at least num_msec passed when return.
|
||||
*/
|
||||
void platform_time_delay(uint32_t num_msec)
|
||||
{
|
||||
bflb_mtimer_get_time_ms(num_msec);
|
||||
}
|
||||
|
||||
/**
|
||||
* platform_in_isr
|
||||
*
|
||||
* Return whether CPU is processing IRQ
|
||||
*
|
||||
* @return True for IRQ, false otherwise.
|
||||
*
|
||||
*/
|
||||
int32_t platform_in_isr(void)
|
||||
{
|
||||
return in_isr_counter > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* platform_interrupt_enable
|
||||
*
|
||||
* Enable peripheral-related interrupt
|
||||
*
|
||||
* @param vector_id Virtual vector ID that needs to be converted to IRQ number
|
||||
*
|
||||
* @return vector_id Return value is never checked.
|
||||
*
|
||||
*/
|
||||
int32_t platform_interrupt_enable(uint32_t vector_id)
|
||||
{
|
||||
RL_ASSERT(0 < disable_counter);
|
||||
|
||||
platform_global_isr_disable();
|
||||
disable_counter--;
|
||||
|
||||
if (disable_counter == 0)
|
||||
{
|
||||
LOG_D("RP: enable irq vector %ld\r\n", vector_id);
|
||||
oblfr_mailbox_unmask_signal(BFLB_IPC_MBOX_VIRTIO, BFLB_IPC_MBOX_VIRTIO_OP_KICK);
|
||||
}
|
||||
platform_global_isr_enable();
|
||||
return ((int32_t)vector_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* platform_interrupt_disable
|
||||
*
|
||||
* Disable peripheral-related interrupt.
|
||||
*
|
||||
* @param vector_id Virtual vector ID that needs to be converted to IRQ number
|
||||
*
|
||||
* @return vector_id Return value is never checked.
|
||||
*
|
||||
*/
|
||||
int32_t platform_interrupt_disable(uint32_t vector_id)
|
||||
{
|
||||
RL_ASSERT(0 <= disable_counter);
|
||||
|
||||
platform_global_isr_disable();
|
||||
/* virtqueues use the same NVIC vector
|
||||
if counter is set - the interrupts are disabled */
|
||||
if (disable_counter == 0)
|
||||
{
|
||||
LOG_D("RP: disable irq vector %ld\r\n", vector_id);
|
||||
oblfr_mailbox_mask_signal(BFLB_IPC_MBOX_VIRTIO, BFLB_IPC_MBOX_VIRTIO_OP_KICK);
|
||||
}
|
||||
disable_counter++;
|
||||
platform_global_isr_enable();
|
||||
return ((int32_t)vector_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* platform_map_mem_region
|
||||
*
|
||||
* Dummy implementation
|
||||
*
|
||||
*/
|
||||
void platform_map_mem_region(uint32_t vrt_addr, uint32_t phy_addr, uint32_t size, uint32_t flags)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* platform_cache_all_flush_invalidate
|
||||
*
|
||||
* Dummy implementation
|
||||
*
|
||||
*/
|
||||
void platform_cache_all_flush_invalidate(void)
|
||||
{
|
||||
/* we might need to flush the xram address? */
|
||||
LOG_W("Invalidate cache\r\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* platform_cache_disable
|
||||
*
|
||||
* Dummy implementation
|
||||
*
|
||||
*/
|
||||
void platform_cache_disable(void)
|
||||
{
|
||||
LOG_W("Disable cache\r\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* platform_vatopa
|
||||
*
|
||||
* Dummy implementation
|
||||
*
|
||||
*/
|
||||
uint32_t platform_vatopa(void *addr)
|
||||
{
|
||||
return ((uintptr_t)(char *)addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* platform_patova
|
||||
*
|
||||
* Dummy implementation
|
||||
*
|
||||
*/
|
||||
void *platform_patova(uintptr_t addr)
|
||||
{
|
||||
return ((void *)(char *)addr);
|
||||
}
|
||||
|
||||
/**
|
||||
* platform_init
|
||||
*
|
||||
* platform/environment init
|
||||
*/
|
||||
int32_t platform_init(void)
|
||||
{
|
||||
/* Create lock used in multi-instanced RPMsg */
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
if (0 != env_create_mutex(&platform_lock, 1, &platform_lock_static_ctxt))
|
||||
#else
|
||||
if (0 != env_create_mutex(&platform_lock, 1))
|
||||
#endif
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* platform_deinit
|
||||
*
|
||||
* platform/environment deinit process
|
||||
*/
|
||||
int32_t platform_deinit(void)
|
||||
{
|
||||
/* Delete lock used in multi-instanced RPMsg */
|
||||
env_delete_mutex(platform_lock);
|
||||
platform_lock = ((void *)0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void platform_inisr(bool in_isr)
|
||||
{
|
||||
if (in_isr)
|
||||
{
|
||||
in_isr_counter++;
|
||||
}
|
||||
else
|
||||
{
|
||||
in_isr_counter--;
|
||||
}
|
||||
}
|
1429
components/rpmsg/rpmsg-lite/rpmsg_lite/rpmsg_lite.c
Normal file
1429
components/rpmsg/rpmsg-lite/rpmsg_lite/rpmsg_lite.c
Normal file
File diff suppressed because it is too large
Load diff
189
components/rpmsg/rpmsg-lite/rpmsg_lite/rpmsg_ns.c
Normal file
189
components/rpmsg/rpmsg-lite/rpmsg_lite/rpmsg_ns.c
Normal file
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Mentor Graphics Corporation
|
||||
* Copyright (c) 2015 Xilinx, Inc.
|
||||
* Copyright (c) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2019 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "rpmsg_lite.h"
|
||||
#include "rpmsg_ns.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#define RL_NS_NAME_SIZE (32)
|
||||
|
||||
/*!
|
||||
* struct rpmsg_ns_msg - dynamic name service announcement message
|
||||
* @name: name of remote service that is published
|
||||
* @addr: address of remote service that is published
|
||||
* @flags: indicates whether service is created or destroyed
|
||||
*
|
||||
* This message is sent across to publish a new service, or announce
|
||||
* about its removal. When we receive these messages, an appropriate
|
||||
* rpmsg channel (i.e device) is created/destroyed. In turn, the ->probe()
|
||||
* or ->remove() handler of the appropriate rpmsg driver will be invoked
|
||||
* (if/as-soon-as one is registered).
|
||||
*/
|
||||
RL_PACKED_BEGIN
|
||||
struct rpmsg_ns_msg
|
||||
{
|
||||
char name[RL_NS_NAME_SIZE];
|
||||
uint32_t addr;
|
||||
uint32_t flags;
|
||||
} RL_PACKED_END;
|
||||
|
||||
/*!
|
||||
* @brief
|
||||
* Nameservice callback, called in interrupt context
|
||||
*
|
||||
* @param payload Pointer to the buffer containing received data
|
||||
* @param payload_len Size of data received, in bytes
|
||||
* @param src Pointer to address of the endpoint from which data is received
|
||||
* @param priv Private data provided during endpoint creation
|
||||
*
|
||||
* @return RL_RELEASE, message is always freed
|
||||
*
|
||||
*/
|
||||
static int32_t rpmsg_ns_rx_cb(void *payload, uint32_t payload_len, uint32_t src, void *priv)
|
||||
{
|
||||
struct rpmsg_ns_msg *ns_msg_ptr = payload;
|
||||
struct rpmsg_ns_callback_data *cb_ctxt = priv;
|
||||
RL_ASSERT(priv != RL_NULL);
|
||||
RL_ASSERT(cb_ctxt->cb != RL_NULL);
|
||||
|
||||
/* Drop likely bad messages received at nameservice address */
|
||||
if (payload_len == sizeof(struct rpmsg_ns_msg))
|
||||
{
|
||||
cb_ctxt->cb(ns_msg_ptr->addr, ns_msg_ptr->name, ns_msg_ptr->flags, cb_ctxt->user_data);
|
||||
}
|
||||
|
||||
return RL_RELEASE;
|
||||
}
|
||||
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
rpmsg_ns_handle rpmsg_ns_bind(struct rpmsg_lite_instance *rpmsg_lite_dev,
|
||||
rpmsg_ns_new_ept_cb app_cb,
|
||||
void *user_data,
|
||||
rpmsg_ns_static_context *ns_ept_ctxt)
|
||||
#else
|
||||
rpmsg_ns_handle rpmsg_ns_bind(struct rpmsg_lite_instance *rpmsg_lite_dev, rpmsg_ns_new_ept_cb app_cb, void *user_data)
|
||||
#endif /* RL_USE_STATIC_API */
|
||||
{
|
||||
struct rpmsg_ns_context *ns_ctxt;
|
||||
|
||||
if (app_cb == RL_NULL)
|
||||
{
|
||||
return RL_NULL;
|
||||
}
|
||||
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
if (ns_ept_ctxt == RL_NULL)
|
||||
{
|
||||
return RL_NULL;
|
||||
}
|
||||
|
||||
ns_ctxt = &ns_ept_ctxt->ns_ctxt;
|
||||
|
||||
/* Set-up the nameservice callback context */
|
||||
ns_ept_ctxt->cb_ctxt.user_data = user_data;
|
||||
ns_ept_ctxt->cb_ctxt.cb = app_cb;
|
||||
|
||||
ns_ctxt->cb_ctxt = &ns_ept_ctxt->cb_ctxt;
|
||||
|
||||
ns_ctxt->ept = rpmsg_lite_create_ept(rpmsg_lite_dev, RL_NS_EPT_ADDR, rpmsg_ns_rx_cb, (void *)ns_ctxt->cb_ctxt,
|
||||
&ns_ept_ctxt->ept_ctxt);
|
||||
#else
|
||||
{
|
||||
struct rpmsg_ns_callback_data *cb_ctxt;
|
||||
|
||||
cb_ctxt = env_allocate_memory(sizeof(struct rpmsg_ns_callback_data));
|
||||
if (cb_ctxt == RL_NULL)
|
||||
{
|
||||
return RL_NULL;
|
||||
}
|
||||
ns_ctxt = env_allocate_memory(sizeof(struct rpmsg_ns_context));
|
||||
if (ns_ctxt == RL_NULL)
|
||||
{
|
||||
env_free_memory(cb_ctxt);
|
||||
return RL_NULL;
|
||||
}
|
||||
|
||||
/* Set-up the nameservice callback context */
|
||||
cb_ctxt->user_data = user_data;
|
||||
cb_ctxt->cb = app_cb;
|
||||
|
||||
ns_ctxt->cb_ctxt = cb_ctxt;
|
||||
|
||||
ns_ctxt->ept = rpmsg_lite_create_ept(rpmsg_lite_dev, RL_NS_EPT_ADDR, rpmsg_ns_rx_cb, (void *)ns_ctxt->cb_ctxt);
|
||||
}
|
||||
#endif /* RL_USE_STATIC_API */
|
||||
|
||||
return (rpmsg_ns_handle)ns_ctxt;
|
||||
}
|
||||
|
||||
int32_t rpmsg_ns_unbind(struct rpmsg_lite_instance *rpmsg_lite_dev, rpmsg_ns_handle handle)
|
||||
{
|
||||
struct rpmsg_ns_context *ns_ctxt = (struct rpmsg_ns_context *)handle;
|
||||
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
return rpmsg_lite_destroy_ept(rpmsg_lite_dev, ns_ctxt->ept);
|
||||
#else
|
||||
{
|
||||
int32_t retval;
|
||||
|
||||
retval = rpmsg_lite_destroy_ept(rpmsg_lite_dev, ns_ctxt->ept);
|
||||
env_free_memory(ns_ctxt->cb_ctxt);
|
||||
env_free_memory(ns_ctxt);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int32_t rpmsg_ns_announce(struct rpmsg_lite_instance *rpmsg_lite_dev,
|
||||
struct rpmsg_lite_endpoint *new_ept,
|
||||
const char *ept_name,
|
||||
uint32_t flags)
|
||||
{
|
||||
struct rpmsg_ns_msg ns_msg;
|
||||
|
||||
if (ept_name == RL_NULL)
|
||||
{
|
||||
return RL_ERR_PARAM;
|
||||
}
|
||||
|
||||
if (new_ept == RL_NULL)
|
||||
{
|
||||
return RL_ERR_PARAM;
|
||||
}
|
||||
|
||||
env_strncpy(ns_msg.name, ept_name, RL_NS_NAME_SIZE);
|
||||
ns_msg.flags = flags;
|
||||
ns_msg.addr = new_ept->addr;
|
||||
|
||||
return rpmsg_lite_send(rpmsg_lite_dev, new_ept, RL_NS_EPT_ADDR, (char *)&ns_msg, sizeof(struct rpmsg_ns_msg),
|
||||
RL_BLOCK);
|
||||
}
|
220
components/rpmsg/rpmsg-lite/rpmsg_lite/rpmsg_queue.c
Normal file
220
components/rpmsg/rpmsg-lite/rpmsg_lite/rpmsg_queue.c
Normal file
|
@ -0,0 +1,220 @@
|
|||
/*
|
||||
* Copyright (c) 2014, Mentor Graphics Corporation
|
||||
* Copyright (c) 2015 Xilinx, Inc.
|
||||
* Copyright (c) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2021 NXP
|
||||
* Copyright 2021 ACRIOS Systems s.r.o.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holder nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from this
|
||||
* software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "rpmsg_lite.h"
|
||||
#include "rpmsg_queue.h"
|
||||
|
||||
int32_t rpmsg_queue_rx_cb(void *payload, uint32_t payload_len, uint32_t src, void *priv)
|
||||
{
|
||||
rpmsg_queue_rx_cb_data_t msg;
|
||||
|
||||
RL_ASSERT(priv != RL_NULL);
|
||||
|
||||
msg.data = payload;
|
||||
msg.len = payload_len;
|
||||
msg.src = src;
|
||||
/* if message is successfully added into queue then hold rpmsg buffer */
|
||||
if (0 != env_put_queue(priv, &msg, 0))
|
||||
{
|
||||
/* hold the rx buffer */
|
||||
return RL_HOLD;
|
||||
}
|
||||
return RL_RELEASE;
|
||||
}
|
||||
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
rpmsg_queue_handle rpmsg_queue_create(struct rpmsg_lite_instance *rpmsg_lite_dev,
|
||||
uint8_t *queue_storage,
|
||||
rpmsg_static_queue_ctxt *queue_ctxt)
|
||||
#else
|
||||
rpmsg_queue_handle rpmsg_queue_create(struct rpmsg_lite_instance *rpmsg_lite_dev)
|
||||
#endif
|
||||
{
|
||||
int32_t status;
|
||||
void *q = RL_NULL;
|
||||
|
||||
if (rpmsg_lite_dev == RL_NULL)
|
||||
{
|
||||
return RL_NULL;
|
||||
}
|
||||
|
||||
/* create message queue for channel default endpoint */
|
||||
#if defined(RL_USE_STATIC_API) && (RL_USE_STATIC_API == 1)
|
||||
status = env_create_queue(&q, (int32_t)rpmsg_lite_dev->rvq->vq_nentries, (int32_t)sizeof(rpmsg_queue_rx_cb_data_t),
|
||||
queue_storage, queue_ctxt);
|
||||
#else
|
||||
status = env_create_queue(&q, (int32_t)rpmsg_lite_dev->rvq->vq_nentries, (int32_t)sizeof(rpmsg_queue_rx_cb_data_t));
|
||||
#endif
|
||||
if ((status != 0) || (q == RL_NULL))
|
||||
{
|
||||
return RL_NULL;
|
||||
}
|
||||
|
||||
return ((rpmsg_queue_handle)q);
|
||||
}
|
||||
|
||||
int32_t rpmsg_queue_destroy(struct rpmsg_lite_instance *rpmsg_lite_dev, rpmsg_queue_handle q)
|
||||
{
|
||||
if (rpmsg_lite_dev == RL_NULL)
|
||||
{
|
||||
return RL_ERR_PARAM;
|
||||
}
|
||||
|
||||
if (q == RL_NULL)
|
||||
{
|
||||
return RL_ERR_PARAM;
|
||||
}
|
||||
env_delete_queue((void *)q);
|
||||
return RL_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t rpmsg_queue_recv(struct rpmsg_lite_instance *rpmsg_lite_dev,
|
||||
rpmsg_queue_handle q,
|
||||
uint32_t *src,
|
||||
char *data,
|
||||
uint32_t maxlen,
|
||||
uint32_t *len,
|
||||
uint32_t timeout)
|
||||
{
|
||||
rpmsg_queue_rx_cb_data_t msg = {0};
|
||||
int32_t retval = RL_SUCCESS;
|
||||
|
||||
if (rpmsg_lite_dev == RL_NULL)
|
||||
{
|
||||
return RL_ERR_PARAM;
|
||||
}
|
||||
if (q == RL_NULL)
|
||||
{
|
||||
return RL_ERR_PARAM;
|
||||
}
|
||||
if (data == RL_NULL)
|
||||
{
|
||||
return RL_ERR_PARAM;
|
||||
}
|
||||
|
||||
/* Get an element out of the message queue for the selected endpoint */
|
||||
if (0 != env_get_queue((void *)q, &msg, timeout))
|
||||
{
|
||||
if (src != RL_NULL)
|
||||
{
|
||||
*src = msg.src;
|
||||
}
|
||||
if (len != RL_NULL)
|
||||
{
|
||||
*len = msg.len;
|
||||
}
|
||||
|
||||
if (maxlen >= msg.len)
|
||||
{
|
||||
env_memcpy(data, msg.data, msg.len);
|
||||
}
|
||||
else
|
||||
{
|
||||
retval = RL_ERR_BUFF_SIZE;
|
||||
}
|
||||
|
||||
/* Release used buffer. */
|
||||
return ((RL_SUCCESS == rpmsg_lite_release_rx_buffer(rpmsg_lite_dev, msg.data)) ? retval : RL_ERR_PARAM);
|
||||
}
|
||||
else
|
||||
{
|
||||
return RL_ERR_NO_BUFF; /* failed */
|
||||
}
|
||||
}
|
||||
|
||||
int32_t rpmsg_queue_recv_nocopy(struct rpmsg_lite_instance *rpmsg_lite_dev,
|
||||
rpmsg_queue_handle q,
|
||||
uint32_t *src,
|
||||
char **data,
|
||||
uint32_t *len,
|
||||
uint32_t timeout)
|
||||
{
|
||||
rpmsg_queue_rx_cb_data_t msg = {0};
|
||||
|
||||
if (rpmsg_lite_dev == RL_NULL)
|
||||
{
|
||||
return RL_ERR_PARAM;
|
||||
}
|
||||
if (data == RL_NULL)
|
||||
{
|
||||
return RL_ERR_PARAM;
|
||||
}
|
||||
if (q == RL_NULL)
|
||||
{
|
||||
return RL_ERR_PARAM;
|
||||
}
|
||||
|
||||
/* Get an element out of the message queue for the selected endpoint */
|
||||
if (0 != env_get_queue((void *)q, &msg, timeout))
|
||||
{
|
||||
if (src != RL_NULL)
|
||||
{
|
||||
*src = msg.src;
|
||||
}
|
||||
if (len != RL_NULL)
|
||||
{
|
||||
*len = msg.len;
|
||||
}
|
||||
|
||||
*data = msg.data;
|
||||
|
||||
return RL_SUCCESS; /* success */
|
||||
}
|
||||
|
||||
return RL_ERR_NO_BUFF; /* failed */
|
||||
}
|
||||
|
||||
int32_t rpmsg_queue_nocopy_free(struct rpmsg_lite_instance *rpmsg_lite_dev, void *data)
|
||||
{
|
||||
if (rpmsg_lite_dev == RL_NULL)
|
||||
{
|
||||
return RL_ERR_PARAM;
|
||||
}
|
||||
if (data == RL_NULL)
|
||||
{
|
||||
return RL_ERR_PARAM;
|
||||
}
|
||||
|
||||
/* Release used buffer. */
|
||||
return ((RL_SUCCESS == rpmsg_lite_release_rx_buffer(rpmsg_lite_dev, data)) ? RL_SUCCESS : RL_ERR_PARAM);
|
||||
}
|
||||
|
||||
int32_t rpmsg_queue_get_current_size(rpmsg_queue_handle q)
|
||||
{
|
||||
if (q == RL_NULL)
|
||||
{
|
||||
return RL_ERR_PARAM;
|
||||
}
|
||||
|
||||
/* Return actual queue size. */
|
||||
return env_get_current_queue_size((void *)q);
|
||||
}
|
749
components/rpmsg/rpmsg-lite/virtio/virtqueue.c
Normal file
749
components/rpmsg/rpmsg-lite/virtio/virtqueue.c
Normal file
|
@ -0,0 +1,749 @@
|
|||
/*-
|
||||
* Copyright (c) 2011, Bryan Venteicher <bryanv@FreeBSD.org>
|
||||
* Copyright (c) 2016 Freescale Semiconductor, Inc.
|
||||
* Copyright 2016-2019 NXP
|
||||
* All rights reserved.
|
||||
*
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice unmodified, this list of conditions, and the following
|
||||
* disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "rpmsg_env.h"
|
||||
#include "virtqueue.h"
|
||||
|
||||
/* Prototype for internal functions. */
|
||||
static void vq_ring_update_avail(struct virtqueue *vq, uint16_t desc_idx);
|
||||
static void vq_ring_update_used(struct virtqueue *vq, uint16_t head_idx, uint32_t len);
|
||||
static uint16_t vq_ring_add_buffer(
|
||||
struct virtqueue *vq, struct vring_desc *desc, uint16_t head_idx, void *buffer, uint32_t length);
|
||||
static int32_t vq_ring_enable_interrupt(struct virtqueue *vq, uint16_t ndesc);
|
||||
static int32_t vq_ring_must_notify_host(struct virtqueue *vq);
|
||||
static void vq_ring_notify_host(struct virtqueue *vq);
|
||||
static uint16_t virtqueue_nused(struct virtqueue *vq);
|
||||
|
||||
/*!
|
||||
* virtqueue_create - Creates new VirtIO queue
|
||||
*
|
||||
* @param id - VirtIO queue ID , must be unique
|
||||
* @param name - Name of VirtIO queue
|
||||
* @param ring - Pointer to vring_alloc_info control block
|
||||
* @param callback - Pointer to callback function, invoked
|
||||
* when message is available on VirtIO queue
|
||||
* @param notify - Pointer to notify function, used to notify
|
||||
* other side that there is job available for it
|
||||
* @param v_queue - Created VirtIO queue.
|
||||
*
|
||||
* @return - Function status
|
||||
*/
|
||||
int32_t virtqueue_create(uint16_t id,
|
||||
const char *name,
|
||||
struct vring_alloc_info *ring,
|
||||
void (*callback_fc)(struct virtqueue *vq),
|
||||
void (*notify_fc)(struct virtqueue *vq),
|
||||
struct virtqueue **v_queue)
|
||||
{
|
||||
struct virtqueue *vq = VQ_NULL;
|
||||
volatile int32_t status = VQUEUE_SUCCESS;
|
||||
uint32_t vq_size = 0U;
|
||||
|
||||
VQ_PARAM_CHK(ring == VQ_NULL, status, ERROR_VQUEUE_INVLD_PARAM);
|
||||
VQ_PARAM_CHK(ring->num_descs == 0U, status, ERROR_VQUEUE_INVLD_PARAM);
|
||||
VQ_PARAM_CHK(ring->num_descs & (ring->num_descs - 1U), status, ERROR_VRING_ALIGN);
|
||||
|
||||
if (status == VQUEUE_SUCCESS)
|
||||
{
|
||||
vq_size = sizeof(struct virtqueue);
|
||||
vq = (struct virtqueue *)env_allocate_memory(vq_size);
|
||||
|
||||
if (vq == VQ_NULL)
|
||||
{
|
||||
return (ERROR_NO_MEM);
|
||||
}
|
||||
|
||||
env_memset(vq, 0x00, vq_size);
|
||||
|
||||
env_strncpy(vq->vq_name, name, VIRTQUEUE_MAX_NAME_SZ);
|
||||
vq->vq_queue_index = id;
|
||||
vq->vq_alignment = (int32_t)(ring->align);
|
||||
vq->vq_nentries = ring->num_descs;
|
||||
vq->callback_fc = callback_fc;
|
||||
vq->notify_fc = notify_fc;
|
||||
|
||||
// indirect addition is not supported
|
||||
vq->vq_ring_size = vring_size(ring->num_descs, ring->align);
|
||||
vq->vq_ring_mem = (void *)ring->phy_addr;
|
||||
|
||||
vring_init(&vq->vq_ring, vq->vq_nentries, vq->vq_ring_mem, (uint32_t)vq->vq_alignment);
|
||||
|
||||
*v_queue = vq;
|
||||
}
|
||||
virtqueue_dump(__FUNCTION__, vq);
|
||||
return (status);
|
||||
}
|
||||
|
||||
/*!
|
||||
* virtqueue_create_static - Creates new VirtIO queue - static version
|
||||
*
|
||||
* @param id - VirtIO queue ID , must be unique
|
||||
* @param name - Name of VirtIO queue
|
||||
* @param ring - Pointer to vring_alloc_info control block
|
||||
* @param callback - Pointer to callback function, invoked
|
||||
* when message is available on VirtIO queue
|
||||
* @param notify - Pointer to notify function, used to notify
|
||||
* other side that there is job available for it
|
||||
* @param v_queue - Created VirtIO queue.
|
||||
* @param vq_ctxt - Statically allocated virtqueue context
|
||||
*
|
||||
* @return - Function status
|
||||
*/
|
||||
int32_t virtqueue_create_static(uint16_t id,
|
||||
const char *name,
|
||||
struct vring_alloc_info *ring,
|
||||
void (*callback_fc)(struct virtqueue *vq),
|
||||
void (*notify_fc)(struct virtqueue *vq),
|
||||
struct virtqueue **v_queue,
|
||||
struct vq_static_context *vq_ctxt)
|
||||
{
|
||||
struct virtqueue *vq = VQ_NULL;
|
||||
volatile int32_t status = VQUEUE_SUCCESS;
|
||||
uint32_t vq_size = 0U;
|
||||
|
||||
VQ_PARAM_CHK(vq_ctxt == VQ_NULL, status, ERROR_VQUEUE_INVLD_PARAM);
|
||||
VQ_PARAM_CHK(ring == VQ_NULL, status, ERROR_VQUEUE_INVLD_PARAM);
|
||||
VQ_PARAM_CHK(ring->num_descs == 0U, status, ERROR_VQUEUE_INVLD_PARAM);
|
||||
VQ_PARAM_CHK(ring->num_descs & (ring->num_descs - 1U), status, ERROR_VRING_ALIGN);
|
||||
|
||||
if (status == VQUEUE_SUCCESS)
|
||||
{
|
||||
vq_size = sizeof(struct virtqueue);
|
||||
vq = &vq_ctxt->vq;
|
||||
|
||||
env_memset(vq, 0x00, vq_size);
|
||||
|
||||
env_strncpy(vq->vq_name, name, VIRTQUEUE_MAX_NAME_SZ);
|
||||
vq->vq_queue_index = id;
|
||||
vq->vq_alignment = (int32_t)(ring->align);
|
||||
vq->vq_nentries = ring->num_descs;
|
||||
vq->callback_fc = callback_fc;
|
||||
vq->notify_fc = notify_fc;
|
||||
|
||||
// indirect addition is not supported
|
||||
vq->vq_ring_size = vring_size(ring->num_descs, ring->align);
|
||||
vq->vq_ring_mem = (void *)ring->phy_addr;
|
||||
|
||||
vring_init(&vq->vq_ring, vq->vq_nentries, vq->vq_ring_mem, (uint32_t)vq->vq_alignment);
|
||||
|
||||
*v_queue = vq;
|
||||
}
|
||||
virtqueue_dump(__FUNCTION__, vq);
|
||||
return (status);
|
||||
}
|
||||
|
||||
/*!
|
||||
* virtqueue_add_buffer() - Enqueues new buffer in vring for consumption
|
||||
* by other side.
|
||||
*
|
||||
* @param vq - Pointer to VirtIO queue control block.
|
||||
* @param head_idx - Index of buffer to be added to the avail ring
|
||||
*
|
||||
* @return - Function status
|
||||
*/
|
||||
int32_t virtqueue_add_buffer(struct virtqueue *vq, uint16_t head_idx)
|
||||
{
|
||||
volatile int32_t status = VQUEUE_SUCCESS;
|
||||
|
||||
VQ_PARAM_CHK(vq == VQ_NULL, status, ERROR_VQUEUE_INVLD_PARAM);
|
||||
|
||||
VQUEUE_BUSY(vq, avail_write);
|
||||
|
||||
if (status == VQUEUE_SUCCESS)
|
||||
{
|
||||
VQ_RING_ASSERT_VALID_IDX(vq, head_idx);
|
||||
|
||||
/*
|
||||
* Update vring_avail control block fields so that other
|
||||
* side can get buffer using it.
|
||||
*/
|
||||
vq_ring_update_avail(vq, head_idx);
|
||||
}
|
||||
|
||||
VQUEUE_IDLE(vq, avail_write);
|
||||
virtqueue_dump(__FUNCTION__, vq);
|
||||
return (status);
|
||||
}
|
||||
|
||||
/*!
|
||||
* virtqueue_fill_avail_buffers - Enqueues single buffer in vring, updates avail
|
||||
*
|
||||
* @param vq - Pointer to VirtIO queue control block
|
||||
* @param buffer - Address of buffer
|
||||
* @param len - Length of buffer
|
||||
*
|
||||
* @return - Function status
|
||||
*/
|
||||
int32_t virtqueue_fill_avail_buffers(struct virtqueue *vq, void *buffer, uint32_t len)
|
||||
{
|
||||
struct vring_desc *dp;
|
||||
uint16_t head_idx;
|
||||
|
||||
volatile int32_t status = VQUEUE_SUCCESS;
|
||||
|
||||
VQ_PARAM_CHK(vq == VQ_NULL, status, ERROR_VQUEUE_INVLD_PARAM);
|
||||
|
||||
VQUEUE_BUSY(vq, avail_write);
|
||||
|
||||
if (status == VQUEUE_SUCCESS)
|
||||
{
|
||||
head_idx = vq->vq_desc_head_idx;
|
||||
|
||||
dp = &vq->vq_ring.desc[head_idx];
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
dp->addr = env_map_vatopa(vq->env, buffer);
|
||||
#else
|
||||
dp->addr = env_map_vatopa(buffer);
|
||||
#endif
|
||||
dp->len = len;
|
||||
dp->flags = VRING_DESC_F_WRITE;
|
||||
|
||||
vq->vq_desc_head_idx++;
|
||||
|
||||
vq_ring_update_avail(vq, head_idx);
|
||||
}
|
||||
|
||||
VQUEUE_IDLE(vq, avail_write);
|
||||
virtqueue_dump(__FUNCTION__, vq);
|
||||
return (status);
|
||||
}
|
||||
|
||||
/*!
|
||||
* virtqueue_get_buffer - Returns used buffers from VirtIO queue
|
||||
*
|
||||
* @param vq - Pointer to VirtIO queue control block
|
||||
* @param len - Length of consumed buffer
|
||||
* @param idx - Index to buffer descriptor pool
|
||||
*
|
||||
* @return - Pointer to used buffer
|
||||
*/
|
||||
void *virtqueue_get_buffer(struct virtqueue *vq, uint32_t *len, uint16_t *idx)
|
||||
{
|
||||
struct vring_used_elem *uep;
|
||||
uint16_t used_idx, desc_idx;
|
||||
env_mb();
|
||||
virtqueue_dump(__FUNCTION__, vq);
|
||||
if ((vq == VQ_NULL) || (vq->vq_used_cons_idx == vq->vq_ring.used->idx))
|
||||
{
|
||||
return (VQ_NULL);
|
||||
}
|
||||
VQUEUE_BUSY(vq, used_read);
|
||||
|
||||
used_idx = (uint16_t)(vq->vq_used_cons_idx & ((uint16_t)(vq->vq_nentries - 1U)));
|
||||
uep = &vq->vq_ring.used->ring[used_idx];
|
||||
|
||||
|
||||
desc_idx = (uint16_t)uep->id;
|
||||
if (len != VQ_NULL)
|
||||
{
|
||||
*len = uep->len;
|
||||
}
|
||||
|
||||
if (idx != VQ_NULL)
|
||||
{
|
||||
*idx = desc_idx;
|
||||
}
|
||||
|
||||
vq->vq_used_cons_idx++;
|
||||
|
||||
VQUEUE_IDLE(vq, used_read);
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
return env_map_patova(vq->env, ((uint32_t)(vq->vq_ring.desc[desc_idx].addr)));
|
||||
#else
|
||||
return env_map_patova((uint32_t)(vq->vq_ring.desc[desc_idx].addr));
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* virtqueue_get_buffer_length - Returns size of a buffer
|
||||
*
|
||||
* @param vq - Pointer to VirtIO queue control block
|
||||
* @param idx - Index to buffer descriptor pool
|
||||
*
|
||||
* @return - Buffer length
|
||||
*/
|
||||
uint32_t virtqueue_get_buffer_length(struct virtqueue *vq, uint16_t idx)
|
||||
{
|
||||
return vq->vq_ring.desc[idx].len;
|
||||
}
|
||||
|
||||
/*!
|
||||
* virtqueue_free - Frees VirtIO queue resources
|
||||
*
|
||||
* @param vq - Pointer to VirtIO queue control block
|
||||
*
|
||||
*/
|
||||
void virtqueue_free(struct virtqueue *vq)
|
||||
{
|
||||
if (vq != VQ_NULL)
|
||||
{
|
||||
if (vq->vq_ring_mem != VQ_NULL)
|
||||
{
|
||||
vq->vq_ring_size = 0;
|
||||
vq->vq_ring_mem = VQ_NULL;
|
||||
}
|
||||
|
||||
env_free_memory(vq);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* virtqueue_free - Frees VirtIO queue resources - static version
|
||||
*
|
||||
* @param vq - Pointer to VirtIO queue control block
|
||||
*
|
||||
*/
|
||||
void virtqueue_free_static(struct virtqueue *vq)
|
||||
{
|
||||
if (vq != VQ_NULL)
|
||||
{
|
||||
if (vq->vq_ring_mem != VQ_NULL)
|
||||
{
|
||||
vq->vq_ring_size = 0;
|
||||
vq->vq_ring_mem = VQ_NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* virtqueue_get_available_buffer - Returns buffer available for use in the
|
||||
* VirtIO queue
|
||||
*
|
||||
* @param vq - Pointer to VirtIO queue control block
|
||||
* @param avail_idx - Pointer to index used in vring desc table
|
||||
* @param len - Length of buffer
|
||||
*
|
||||
* @return - Pointer to available buffer
|
||||
*/
|
||||
void *virtqueue_get_available_buffer(struct virtqueue *vq, uint16_t *avail_idx, uint32_t *len)
|
||||
{
|
||||
uint16_t head_idx = 0;
|
||||
void *buffer;
|
||||
|
||||
env_rmb();
|
||||
|
||||
if (vq->vq_available_idx == vq->vq_ring.avail->idx)
|
||||
{
|
||||
return (VQ_NULL);
|
||||
}
|
||||
|
||||
VQUEUE_BUSY(vq, avail_read);
|
||||
|
||||
head_idx = (uint16_t)(vq->vq_available_idx++ & ((uint16_t)(vq->vq_nentries - 1U)));
|
||||
*avail_idx = vq->vq_ring.avail->ring[head_idx];
|
||||
|
||||
|
||||
env_rmb();
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
buffer = env_map_patova(vq->env, ((uint32_t)(vq->vq_ring.desc[*avail_idx].addr)));
|
||||
#else
|
||||
buffer = env_map_patova((uint32_t)(vq->vq_ring.desc[*avail_idx].addr));
|
||||
#endif
|
||||
*len = vq->vq_ring.desc[*avail_idx].len;
|
||||
|
||||
VQUEUE_IDLE(vq, avail_read);
|
||||
virtqueue_dump(__FUNCTION__, vq);
|
||||
return (buffer);
|
||||
}
|
||||
|
||||
/*!
|
||||
* virtqueue_add_consumed_buffer - Returns consumed buffer back to VirtIO queue
|
||||
*
|
||||
* @param vq - Pointer to VirtIO queue control block
|
||||
* @param head_idx - Index of vring desc containing used buffer
|
||||
* @param len - Length of buffer
|
||||
*
|
||||
* @return - Function status
|
||||
*/
|
||||
int32_t virtqueue_add_consumed_buffer(struct virtqueue *vq, uint16_t head_idx, uint32_t len)
|
||||
{
|
||||
if (head_idx > vq->vq_nentries)
|
||||
{
|
||||
return (ERROR_VRING_NO_BUFF);
|
||||
}
|
||||
|
||||
VQUEUE_BUSY(vq, used_write);
|
||||
vq_ring_update_used(vq, head_idx, len);
|
||||
VQUEUE_IDLE(vq, used_write);
|
||||
virtqueue_dump(__FUNCTION__, vq);
|
||||
return (VQUEUE_SUCCESS);
|
||||
}
|
||||
|
||||
/*!
|
||||
* virtqueue_fill_used_buffers - Fill used buffer ring
|
||||
*
|
||||
* @param vq - Pointer to VirtIO queue control block
|
||||
* @param buffer - Buffer to add
|
||||
* @param len - Length of buffer
|
||||
*
|
||||
* @return - Function status
|
||||
*/
|
||||
int32_t virtqueue_fill_used_buffers(struct virtqueue *vq, void *buffer, uint32_t len)
|
||||
{
|
||||
uint16_t head_idx;
|
||||
uint16_t idx;
|
||||
|
||||
VQUEUE_BUSY(vq, used_write);
|
||||
|
||||
head_idx = vq->vq_desc_head_idx;
|
||||
VQ_RING_ASSERT_VALID_IDX(vq, head_idx);
|
||||
|
||||
/* Enqueue buffer onto the ring. */
|
||||
idx = vq_ring_add_buffer(vq, vq->vq_ring.desc, head_idx, buffer, len);
|
||||
|
||||
vq->vq_desc_head_idx = idx;
|
||||
|
||||
vq_ring_update_used(vq, head_idx, len);
|
||||
|
||||
VQUEUE_IDLE(vq, used_write);
|
||||
virtqueue_dump(__FUNCTION__, vq);
|
||||
return (VQUEUE_SUCCESS);
|
||||
}
|
||||
|
||||
/*!
|
||||
* virtqueue_enable_cb - Enables callback generation
|
||||
*
|
||||
* @param vq - Pointer to VirtIO queue control block
|
||||
*
|
||||
* @return - Function status
|
||||
*/
|
||||
int32_t virtqueue_enable_cb(struct virtqueue *vq)
|
||||
{
|
||||
return (vq_ring_enable_interrupt(vq, 0));
|
||||
}
|
||||
|
||||
/*!
|
||||
* virtqueue_enable_cb - Disables callback generation
|
||||
*
|
||||
* @param vq - Pointer to VirtIO queue control block
|
||||
*
|
||||
*/
|
||||
void virtqueue_disable_cb(struct virtqueue *vq)
|
||||
{
|
||||
VQUEUE_BUSY(vq, avail_write);
|
||||
|
||||
if ((vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) != 0UL)
|
||||
{
|
||||
vring_used_event(&vq->vq_ring) = vq->vq_used_cons_idx - vq->vq_nentries - 1U;
|
||||
}
|
||||
else
|
||||
{
|
||||
vq->vq_ring.avail->flags |= (uint16_t)VRING_AVAIL_F_NO_INTERRUPT;
|
||||
}
|
||||
|
||||
VQUEUE_IDLE(vq, avail_write);
|
||||
}
|
||||
|
||||
/*!
|
||||
* virtqueue_kick - Notifies other side that there is buffer available for it.
|
||||
*
|
||||
* @param vq - Pointer to VirtIO queue control block
|
||||
*/
|
||||
void virtqueue_kick(struct virtqueue *vq)
|
||||
{
|
||||
VQUEUE_BUSY(vq, avail_write);
|
||||
|
||||
/* Ensure updated avail->idx is visible to host. */
|
||||
env_mb();
|
||||
|
||||
if (0 != vq_ring_must_notify_host(vq))
|
||||
{
|
||||
vq_ring_notify_host(vq);
|
||||
}
|
||||
vq->vq_queued_cnt = 0;
|
||||
virtqueue_dump(__FUNCTION__, vq);
|
||||
VQUEUE_IDLE(vq, avail_write);
|
||||
}
|
||||
|
||||
/*!
|
||||
* virtqueue_dump Dumps important virtqueue fields , use for debugging purposes
|
||||
*
|
||||
* @param vq - Pointer to VirtIO queue control block
|
||||
*/
|
||||
void virtqueue_dump(const char *func, struct virtqueue *vq)
|
||||
{
|
||||
return;
|
||||
if (vq == VQ_NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
env_print(
|
||||
"VQ: %s - %s - size=%d; used=%d; queued=%d; "
|
||||
"desc_head_idx=%d; avail.idx=%d; used_cons_idx=%d; "
|
||||
"used.idx=%d; avail.flags=0x%x; used.flags=0x%x address: %p\r\n",
|
||||
func, vq->vq_name, vq->vq_nentries, virtqueue_nused(vq), vq->vq_queued_cnt, vq->vq_desc_head_idx,
|
||||
vq->vq_ring.avail->idx, vq->vq_used_cons_idx, vq->vq_ring.used->idx, vq->vq_ring.avail->flags,
|
||||
vq->vq_ring.used->flags, vq->vq_ring_mem);
|
||||
}
|
||||
|
||||
/*!
|
||||
* virtqueue_get_desc_size - Returns vring descriptor size
|
||||
*
|
||||
* @param vq - Pointer to VirtIO queue control block
|
||||
*
|
||||
* @return - Descriptor length
|
||||
*/
|
||||
uint32_t virtqueue_get_desc_size(struct virtqueue *vq)
|
||||
{
|
||||
uint16_t head_idx;
|
||||
uint16_t avail_idx;
|
||||
uint32_t len;
|
||||
|
||||
if (vq->vq_available_idx == vq->vq_ring.avail->idx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
head_idx = (uint16_t)(vq->vq_available_idx & ((uint16_t)(vq->vq_nentries - 1U)));
|
||||
avail_idx = vq->vq_ring.avail->ring[head_idx];
|
||||
len = vq->vq_ring.desc[avail_idx].len;
|
||||
virtqueue_dump(__FUNCTION__, vq);
|
||||
return (len);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Helper Functions *
|
||||
**************************************************************************/
|
||||
|
||||
/*!
|
||||
*
|
||||
* vq_ring_add_buffer
|
||||
*
|
||||
*/
|
||||
static uint16_t vq_ring_add_buffer(
|
||||
struct virtqueue *vq, struct vring_desc *desc, uint16_t head_idx, void *buffer, uint32_t length)
|
||||
{
|
||||
struct vring_desc *dp;
|
||||
|
||||
if (buffer == VQ_NULL)
|
||||
{
|
||||
return head_idx;
|
||||
}
|
||||
|
||||
VQASSERT(vq, head_idx != VQ_RING_DESC_CHAIN_END, "premature end of free desc chain");
|
||||
|
||||
virtqueue_dump(__FUNCTION__, vq);
|
||||
|
||||
dp = &desc[head_idx];
|
||||
#if defined(RL_USE_ENVIRONMENT_CONTEXT) && (RL_USE_ENVIRONMENT_CONTEXT == 1)
|
||||
dp->addr = env_map_vatopa(vq->env, buffer);
|
||||
#else
|
||||
dp->addr = env_map_vatopa(buffer);
|
||||
#endif
|
||||
dp->len = length;
|
||||
dp->flags = VRING_DESC_F_WRITE;
|
||||
|
||||
|
||||
return (head_idx + 1U);
|
||||
}
|
||||
|
||||
/*!
|
||||
*
|
||||
* vq_ring_init
|
||||
*
|
||||
*/
|
||||
void vq_ring_init(struct virtqueue *vq)
|
||||
{
|
||||
struct vring *vr;
|
||||
uint32_t i, size;
|
||||
|
||||
size = (uint32_t)(vq->vq_nentries);
|
||||
vr = &vq->vq_ring;
|
||||
|
||||
for (i = 0U; i < size - 1U; i++)
|
||||
{
|
||||
vr->desc[i].next = (uint16_t)(i + 1U);
|
||||
}
|
||||
vr->desc[i].next = (uint16_t)VQ_RING_DESC_CHAIN_END;
|
||||
virtqueue_dump(__FUNCTION__, vq);
|
||||
}
|
||||
|
||||
/*!
|
||||
*
|
||||
* vq_ring_update_avail
|
||||
*
|
||||
*/
|
||||
static void vq_ring_update_avail(struct virtqueue *vq, uint16_t desc_idx)
|
||||
{
|
||||
uint16_t avail_idx;
|
||||
|
||||
/*
|
||||
* Place the head of the descriptor chain into the next slot and make
|
||||
* it usable to the host. The chain is made available now rather than
|
||||
* deferring to virtqueue_notify() in the hopes that if the host is
|
||||
* currently running on another CPU, we can keep it processing the new
|
||||
* descriptor.
|
||||
*/
|
||||
avail_idx = (uint16_t)(vq->vq_ring.avail->idx & ((uint16_t)(vq->vq_nentries - 1U)));
|
||||
vq->vq_ring.avail->ring[avail_idx] = desc_idx;
|
||||
|
||||
env_wmb();
|
||||
|
||||
vq->vq_ring.avail->idx++;
|
||||
|
||||
/* Keep pending count until virtqueue_notify(). */
|
||||
vq->vq_queued_cnt++;
|
||||
virtqueue_dump(__FUNCTION__, vq);
|
||||
}
|
||||
|
||||
/*!
|
||||
*
|
||||
* vq_ring_update_used
|
||||
*
|
||||
*/
|
||||
static void vq_ring_update_used(struct virtqueue *vq, uint16_t head_idx, uint32_t len)
|
||||
{
|
||||
uint16_t used_idx;
|
||||
struct vring_used_elem *used_desc = VQ_NULL;
|
||||
|
||||
/*
|
||||
* Place the head of the descriptor chain into the next slot and make
|
||||
* it usable to the host. The chain is made available now rather than
|
||||
* deferring to virtqueue_notify() in the hopes that if the host is
|
||||
* currently running on another CPU, we can keep it processing the new
|
||||
* descriptor.
|
||||
*/
|
||||
used_idx = vq->vq_ring.used->idx & (vq->vq_nentries - 1U);
|
||||
used_desc = &(vq->vq_ring.used->ring[used_idx]);
|
||||
used_desc->id = head_idx;
|
||||
used_desc->len = len;
|
||||
|
||||
env_wmb();
|
||||
|
||||
vq->vq_ring.used->idx++;
|
||||
virtqueue_dump(__FUNCTION__, vq);
|
||||
}
|
||||
|
||||
/*!
|
||||
*
|
||||
* vq_ring_enable_interrupt
|
||||
*
|
||||
*/
|
||||
static int32_t vq_ring_enable_interrupt(struct virtqueue *vq, uint16_t ndesc)
|
||||
{
|
||||
/*
|
||||
* Enable interrupts, making sure we get the latest index of
|
||||
* what's already been consumed.
|
||||
*/
|
||||
if ((vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) != 0UL)
|
||||
{
|
||||
vring_used_event(&vq->vq_ring) = vq->vq_used_cons_idx + ndesc;
|
||||
}
|
||||
else
|
||||
{
|
||||
vq->vq_ring.avail->flags &= ~(uint16_t)VRING_AVAIL_F_NO_INTERRUPT;
|
||||
}
|
||||
|
||||
env_mb();
|
||||
|
||||
/*
|
||||
* Enough items may have already been consumed to meet our threshold
|
||||
* since we last checked. Let our caller know so it processes the new
|
||||
* entries.
|
||||
*/
|
||||
virtqueue_dump(__FUNCTION__, vq);
|
||||
if (virtqueue_nused(vq) > ndesc)
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*!
|
||||
*
|
||||
* virtqueue_interrupt
|
||||
*
|
||||
*/
|
||||
void virtqueue_notification(struct virtqueue *vq)
|
||||
{
|
||||
if (vq != VQ_NULL)
|
||||
{
|
||||
if (vq->callback_fc != VQ_NULL)
|
||||
{
|
||||
env_mb();
|
||||
vq->callback_fc(vq);
|
||||
virtqueue_dump(__FUNCTION__, vq);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
*
|
||||
* vq_ring_must_notify_host
|
||||
*
|
||||
*/
|
||||
static int32_t vq_ring_must_notify_host(struct virtqueue *vq)
|
||||
{
|
||||
uint16_t new_idx, prev_idx;
|
||||
uint16_t event_idx;
|
||||
|
||||
if ((vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) != 0UL)
|
||||
{
|
||||
new_idx = vq->vq_ring.avail->idx;
|
||||
prev_idx = new_idx - vq->vq_queued_cnt;
|
||||
event_idx = (uint16_t)vring_avail_event(&vq->vq_ring);
|
||||
|
||||
return ((vring_need_event(event_idx, new_idx, prev_idx) != 0) ? 1 : 0);
|
||||
}
|
||||
virtqueue_dump(__FUNCTION__, vq);
|
||||
return (((vq->vq_ring.used->flags & ((uint16_t)VRING_USED_F_NO_NOTIFY)) == 0U) ? 1 : 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
*
|
||||
* vq_ring_notify_host
|
||||
*
|
||||
*/
|
||||
static void vq_ring_notify_host(struct virtqueue *vq)
|
||||
{
|
||||
if (vq->notify_fc != VQ_NULL)
|
||||
{
|
||||
vq->notify_fc(vq);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
*
|
||||
* virtqueue_nused
|
||||
*
|
||||
*/
|
||||
static uint16_t virtqueue_nused(struct virtqueue *vq)
|
||||
{
|
||||
uint16_t used_idx, nused;
|
||||
|
||||
used_idx = vq->vq_ring.used->idx;
|
||||
|
||||
nused = (uint16_t)(used_idx - vq->vq_used_cons_idx);
|
||||
VQASSERT(vq, nused <= vq->vq_nentries, "used more than available");
|
||||
|
||||
return (nused);
|
||||
}
|
422
components/rpmsg/src/oblfr_rpmsg.c
Normal file
422
components/rpmsg/src/oblfr_rpmsg.c
Normal file
|
@ -0,0 +1,422 @@
|
|||
|
||||
#include <bflb_l1c.h>
|
||||
#include <sys/queue.h>
|
||||
#include <FreeRTOS.h>
|
||||
#include <task.h>
|
||||
#include <queue.h>
|
||||
|
||||
#include "rpmsg_lite.h"
|
||||
#include "rpmsg_ns.h"
|
||||
#include "rpmsg_queue.h"
|
||||
#include "oblfr_mailbox.h"
|
||||
#include "oblfr_rpmsg.h"
|
||||
|
||||
#define DBG_TAG "RPMSG"
|
||||
#include <log.h>
|
||||
|
||||
#define MAX_NUMBER_OF_ENDPOINTS 4
|
||||
#define MAX_NUMBER_OF_QUEUED_MESSAGES RL_BUFFER_COUNT
|
||||
#define MAX_QUEUESET_SIZE (MAX_NUMBER_OF_ENDPOINTS * MAX_NUMBER_OF_QUEUED_MESSAGES)
|
||||
|
||||
static struct rpmsg_lite_instance *ipc_rpmsg;
|
||||
static rpmsg_ns_handle ipc_rpmsg_ns;
|
||||
|
||||
typedef struct oblfr_queue_entry_s
|
||||
{
|
||||
rpmsg_queue_handle queue;
|
||||
oblfr_device_cfg_t *cfg;
|
||||
struct rpmsg_lite_endpoint *ept;
|
||||
uint32_t dst;
|
||||
bool valid;
|
||||
uint32_t sent;
|
||||
uint32_t received;
|
||||
LIST_ENTRY(oblfr_queue_entry_s)
|
||||
list_entry;
|
||||
} oblfr_queue_entry_t;
|
||||
|
||||
static LIST_HEAD(oblfr_rpmsg_queues, oblfr_queue_entry_s) oblfr_rpmsg_queues = LIST_HEAD_INITIALIZER(oblfr_rpmsg_queues);
|
||||
|
||||
static QueueSetHandle_t xQueueSet;
|
||||
|
||||
#define XRAM_RINGBUF_ADDR 0x22048000
|
||||
|
||||
// WRAM - 0x22030000 - 160KB (0x28000) - 0x22058000
|
||||
// vring1 - 0x22048000 - 16K (0x4000) - 0x2204C000
|
||||
// vring2 - 0x2204C000 - 16K (0x4000) - 0x22050000
|
||||
// buffer - 0x22050000 - 32K (0x8000) - 0x22058000
|
||||
|
||||
void oblfr_rpmsg_task(void *arg);
|
||||
|
||||
/* we shouldn't actually get any NS calls from Linux */
|
||||
static void ipc_rpmsg_ns_callback(uint32_t new_ept, const char *new_ept_name, uint32_t flags, void *user_data)
|
||||
{
|
||||
oblfr_queue_entry_t *rpmsgqueue;
|
||||
LOG_D("NS Announcement: Endpoint: %s - endpoint %d - flags %d\r", new_ept_name, new_ept, flags);
|
||||
LIST_FOREACH(rpmsgqueue, &oblfr_rpmsg_queues, list_entry)
|
||||
{
|
||||
if (strncasecmp(rpmsgqueue->cfg->name, new_ept_name, strlen(new_ept_name)) == 0)
|
||||
{
|
||||
if (rpmsgqueue->dst == RL_ADDR_ANY)
|
||||
{
|
||||
if (flags == RL_NS_CREATE) {
|
||||
rpmsgqueue->dst = new_ept;
|
||||
LOG_D("Updated Device %s with endpoint %d - flags %d\r", new_ept_name, new_ept, flags);
|
||||
} else if (flags == RL_NS_DESTROY) {
|
||||
rpmsgqueue->dst = 0;
|
||||
LOG_D("Device %s is Down - flags %d\r", new_ept_name, new_ept, flags);
|
||||
}
|
||||
if (rpmsgqueue->cfg->status_cb != NULL)
|
||||
rpmsgqueue->cfg->status_cb(rpmsgqueue->cfg, flags == RL_NS_CREATE ? DEVICE_UP : DEVICE_DOWN);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
oblfr_err_t init_rpmsg()
|
||||
{
|
||||
|
||||
LOG_I("Initilizing RPMsg\r\n");
|
||||
|
||||
bflb_l1c_dcache_disable();
|
||||
|
||||
ipc_rpmsg = rpmsg_lite_remote_init((uintptr_t *)XRAM_RINGBUF_ADDR, RL_PLATFORM_BL808_M0_LINK_ID, RL_NO_FLAGS);
|
||||
LOG_I("rpmsg addr %lx, remaining %lx, total: %lx\r\n", ipc_rpmsg->sh_mem_base, ipc_rpmsg->sh_mem_remaining, ipc_rpmsg->sh_mem_total);
|
||||
if (ipc_rpmsg == NULL)
|
||||
{
|
||||
LOG_E("RPMSG init failed\r\n");
|
||||
return OBLFR_ERR_ERROR;
|
||||
}
|
||||
xQueueSet = xQueueCreateSet(MAX_QUEUESET_SIZE);
|
||||
if (xQueueSet == NULL)
|
||||
{
|
||||
LOG_E("Failed to create QueueSet\r\n");
|
||||
rpmsg_lite_deinit(ipc_rpmsg);
|
||||
ipc_rpmsg = NULL;
|
||||
return OBLFR_ERR_ERROR;
|
||||
}
|
||||
|
||||
if (xTaskCreate(oblfr_rpmsg_task, "rpmsg", 1024, NULL, 5, NULL) != pdPASS)
|
||||
{
|
||||
LOG_E("Failed to create RPMSG task\r\n");
|
||||
rpmsg_lite_deinit(ipc_rpmsg);
|
||||
ipc_rpmsg = NULL;
|
||||
return OBLFR_ERR_ERROR;
|
||||
}
|
||||
return OBLFR_OK;
|
||||
}
|
||||
|
||||
oblfr_queue_entry_t *oblfr_rpmsg_device_add(oblfr_device_cfg_t *cfg)
|
||||
{
|
||||
oblfr_queue_entry_t *queue_entry = malloc(sizeof(oblfr_queue_entry_t));
|
||||
if (queue_entry == NULL)
|
||||
{
|
||||
LOG_E("Failed to allocate queue entry\r\n");
|
||||
return NULL;
|
||||
}
|
||||
queue_entry->cfg = cfg;
|
||||
|
||||
queue_entry->queue = rpmsg_queue_create(ipc_rpmsg);
|
||||
if (queue_entry->queue == RL_NULL)
|
||||
{
|
||||
LOG_W("Failed to create RPMSG queue\r\n");
|
||||
rpmsg_queue_destroy(ipc_rpmsg, queue_entry->queue);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* first endpoint addr will be 0x1*/
|
||||
queue_entry->ept = rpmsg_lite_create_ept(ipc_rpmsg, RL_ADDR_ANY, rpmsg_queue_rx_cb, queue_entry->queue);
|
||||
if (queue_entry->ept == RL_NULL)
|
||||
{
|
||||
LOG_W("Failed to create RPMSG endpoint\r\n");
|
||||
rpmsg_queue_destroy(ipc_rpmsg, queue_entry->queue);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LIST_INSERT_HEAD(&oblfr_rpmsg_queues, queue_entry, list_entry);
|
||||
if (xQueueAddToSet(queue_entry->queue, xQueueSet) != pdPASS)
|
||||
{
|
||||
LOG_W("Failed to add queue to set\r\n");
|
||||
rpmsg_lite_destroy_ept(ipc_rpmsg, queue_entry->ept);
|
||||
rpmsg_queue_destroy(ipc_rpmsg, queue_entry->queue);
|
||||
LIST_REMOVE(queue_entry, list_entry);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LOG_D("New RPMsg Driver %s\r\n", queue_entry->cfg->name);
|
||||
|
||||
/* only announce if the link is up */
|
||||
if (rpmsg_lite_is_link_up(ipc_rpmsg) == RL_TRUE)
|
||||
{
|
||||
if (rpmsg_ns_announce(ipc_rpmsg, queue_entry->ept, queue_entry->cfg->name, RL_NS_CREATE) != RL_SUCCESS)
|
||||
{
|
||||
LOG_W("Failed to announce RPMSG NS\r\n");
|
||||
rpmsg_lite_destroy_ept(ipc_rpmsg, queue_entry->ept);
|
||||
rpmsg_queue_destroy(ipc_rpmsg, queue_entry->queue);
|
||||
return NULL;
|
||||
}
|
||||
LOG_D("New Endpoint %s Announced\r\n", queue_entry->cfg->name);
|
||||
}
|
||||
queue_entry->dst = RL_ADDR_ANY;
|
||||
queue_entry->valid = true;
|
||||
queue_entry->sent = queue_entry->received = 0;
|
||||
return queue_entry;
|
||||
}
|
||||
|
||||
oblfr_err_t oblfr_rpmsg_device_remove(oblfr_queue_entry_t *device)
|
||||
{
|
||||
if (device == NULL)
|
||||
{
|
||||
LOG_W("Invalid Handle\r\n");
|
||||
return OBLFR_ERR_INVALID;
|
||||
}
|
||||
if (device->valid == false)
|
||||
{
|
||||
LOG_W("Invalid Handle\r\n");
|
||||
return OBLFR_ERR_INVALID;
|
||||
}
|
||||
|
||||
oblfr_err_t ret = OBLFR_OK;
|
||||
if (rpmsg_lite_is_link_up(ipc_rpmsg) == RL_TRUE)
|
||||
{
|
||||
if (rpmsg_ns_announce(ipc_rpmsg, device->ept, device->cfg->name, RL_NS_DESTROY) != RL_SUCCESS)
|
||||
{
|
||||
LOG_W("Failed to Destroy RPMSG Nameservice for %s\r\n", device->cfg->name);
|
||||
ret = OBLFR_ERR_ERROR;
|
||||
}
|
||||
}
|
||||
LIST_REMOVE(device, list_entry);
|
||||
if (xQueueRemoveFromSet(device->queue, xQueueSet) != pdPASS)
|
||||
{
|
||||
LOG_W("Failed to remove queue from set\r\n");
|
||||
ret = OBLFR_ERR_ERROR;
|
||||
}
|
||||
if (rpmsg_lite_destroy_ept(ipc_rpmsg, device->ept) != RL_SUCCESS)
|
||||
{
|
||||
LOG_W("Failed to destroy RPMSG endpoint\r\n");
|
||||
ret = OBLFR_ERR_ERROR;
|
||||
}
|
||||
|
||||
if (rpmsg_queue_destroy(ipc_rpmsg, device->queue) != RL_SUCCESS)
|
||||
{
|
||||
LOG_W("Failed to destroy RPMSG queue\r\n");
|
||||
ret = OBLFR_ERR_ERROR;
|
||||
}
|
||||
LOG_D("RPMSG Driver %s removed: %d\r\n", device->cfg->name, ret);
|
||||
device->valid = false;
|
||||
free(device);
|
||||
device = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
oblfr_err_t oblfr_rpmsg_device_send(oblfr_queue_entry_t *device, void *data, size_t len, OBLFR_Timeout timeout)
|
||||
{
|
||||
if (device == NULL)
|
||||
{
|
||||
LOG_W("Invalid Handle\r\n");
|
||||
return OBLFR_ERR_INVALID;
|
||||
}
|
||||
if (device->valid == false)
|
||||
{
|
||||
LOG_W("Invalid Handle\r\n");
|
||||
return OBLFR_ERR_INVALID;
|
||||
}
|
||||
if (len > RL_BUFFER_PAYLOAD_SIZE)
|
||||
{
|
||||
LOG_W("Message too large\r\n");
|
||||
return OBLFR_ERR_INVALID;
|
||||
}
|
||||
if (device->dst == RL_ADDR_ANY)
|
||||
{
|
||||
LOG_W("No destination address\r\n");
|
||||
return OBLFR_ERR_INVALID;
|
||||
}
|
||||
if (rpmsg_lite_is_link_up(ipc_rpmsg) == RL_FALSE)
|
||||
{
|
||||
LOG_W("Link is down\r\n");
|
||||
return OBLFR_ERR_ERROR;
|
||||
}
|
||||
if (rpmsg_lite_send(ipc_rpmsg, device->ept, device->dst, data, len, (uint32_t)timeout) != RL_SUCCESS)
|
||||
{
|
||||
LOG_W("Failed to send message\r\n");
|
||||
return OBLFR_ERR_ERROR;
|
||||
}
|
||||
device->sent++;
|
||||
LOG_D("Sent message to %s\r\n", device->cfg->name);
|
||||
return OBLFR_OK;
|
||||
}
|
||||
|
||||
void *oblfr_rpmsg_device_send_buffer_alloc(oblfr_queue_entry_t *device, uint32_t *size, OBLFR_Timeout timeout)
|
||||
{
|
||||
if (device == NULL)
|
||||
{
|
||||
LOG_W("Invalid Handle\r\n");
|
||||
return NULL;
|
||||
}
|
||||
if (device->valid == false)
|
||||
{
|
||||
LOG_W("Invalid Handle\r\n");
|
||||
return NULL;
|
||||
}
|
||||
if (device->dst == RL_ADDR_ANY)
|
||||
{
|
||||
LOG_W("No destination address\r\n");
|
||||
return NULL;
|
||||
}
|
||||
if (rpmsg_lite_is_link_up(ipc_rpmsg) == RL_FALSE)
|
||||
{
|
||||
LOG_W("Link is down\r\n");
|
||||
return NULL;
|
||||
}
|
||||
LOG_D("Allocating buffer for %s\r\n", device->cfg->name);
|
||||
return rpmsg_lite_alloc_tx_buffer(ipc_rpmsg, size, (uint32_t)timeout);
|
||||
}
|
||||
oblfr_err_t oblfr_rpmsg_device_send_buffer(oblfr_queue_entry_t *device, void *buffer, size_t len)
|
||||
{
|
||||
if (device == NULL)
|
||||
{
|
||||
LOG_W("Invalid Handle\r\n");
|
||||
return OBLFR_ERR_INVALID;
|
||||
}
|
||||
if (device->valid == false)
|
||||
{
|
||||
LOG_W("Invalid Handle\r\n");
|
||||
return OBLFR_ERR_INVALID;
|
||||
}
|
||||
if (len > RL_BUFFER_PAYLOAD_SIZE)
|
||||
{
|
||||
LOG_W("Message too large\r\n");
|
||||
return OBLFR_ERR_INVALID;
|
||||
}
|
||||
if (device->dst == RL_ADDR_ANY)
|
||||
{
|
||||
LOG_W("No destination address\r\n");
|
||||
return OBLFR_ERR_INVALID;
|
||||
}
|
||||
if (rpmsg_lite_is_link_up(ipc_rpmsg) == RL_FALSE)
|
||||
{
|
||||
LOG_W("Link is down\r\n");
|
||||
return OBLFR_ERR_INVALID;
|
||||
}
|
||||
if (rpmsg_lite_send_nocopy(ipc_rpmsg, device->ept, device->dst, buffer, len) != RL_SUCCESS)
|
||||
{
|
||||
LOG_W("Failed to send message\r\n");
|
||||
return OBLFR_ERR_ERROR;
|
||||
}
|
||||
device->sent++;
|
||||
LOG_D("Sent message to %s\r\n", device->cfg->name);
|
||||
return OBLFR_OK;
|
||||
}
|
||||
|
||||
uint32_t oblfr_rpmsg_get_mtu(void)
|
||||
{
|
||||
return RL_BUFFER_PAYLOAD_SIZE;
|
||||
}
|
||||
|
||||
bool oblfr_rpmsg_is_ready(void)
|
||||
{
|
||||
return rpmsg_lite_is_link_up(ipc_rpmsg);
|
||||
}
|
||||
|
||||
oblfr_err_t oblfr_rpmsg_dump(void)
|
||||
{
|
||||
oblfr_queue_entry_t *rpmsgqueue;
|
||||
if (rpmsg_lite_is_link_up(ipc_rpmsg) == RL_FALSE)
|
||||
{
|
||||
LOG_W("Link is down\r\n");
|
||||
return OBLFR_ERR_INVALID;
|
||||
}
|
||||
|
||||
LOG_I("RPMSG Driver Dump\r\n");
|
||||
LOG_I("State: %s\r\n", rpmsg_lite_is_link_up(ipc_rpmsg) == RL_TRUE ? "UP" : "DOWN");
|
||||
LOG_I("Shared Memory Total: %ld Free: %ld\r\n", ipc_rpmsg->sh_mem_total, ipc_rpmsg->sh_mem_remaining);
|
||||
LOG_I("RPMSG MTU %ld\r\n", oblfr_rpmsg_get_mtu());
|
||||
LIST_FOREACH(rpmsgqueue, &oblfr_rpmsg_queues, list_entry)
|
||||
{
|
||||
LOG_I("Endpoint: %s - Addr: %ld Sent: %ld Recv: %ld\r\n", rpmsgqueue->cfg->name, rpmsgqueue->dst, rpmsgqueue->sent, rpmsgqueue->received);
|
||||
}
|
||||
LOG_I("========================================\r\n");
|
||||
return OBLFR_OK;
|
||||
}
|
||||
|
||||
void oblfr_process_queue(oblfr_queue_entry_t *rpmsgqueue)
|
||||
{
|
||||
char *rx_msg;
|
||||
uint32_t len;
|
||||
if (rpmsg_queue_recv_nocopy(ipc_rpmsg, rpmsgqueue->queue, &rpmsgqueue->dst, &rx_msg, &len, RL_DONT_BLOCK) == RL_SUCCESS)
|
||||
{
|
||||
rpmsgqueue->cfg->cb(rx_msg, len, rpmsgqueue->cfg->priv);
|
||||
if (rpmsg_queue_nocopy_free(ipc_rpmsg, rx_msg) != RL_SUCCESS)
|
||||
{
|
||||
LOG_W("Failed to free rpmsg buffer\r\n");
|
||||
}
|
||||
rpmsgqueue->received++;
|
||||
}
|
||||
}
|
||||
|
||||
void oblfr_rpmsg_task(void *arg)
|
||||
{
|
||||
oblfr_queue_entry_t *rpmsgqueue;
|
||||
|
||||
LOG_I("Waiting for RPMSG link up\r\n");
|
||||
while (0 == rpmsg_lite_is_link_up(ipc_rpmsg))
|
||||
{
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
}
|
||||
LOG_I("RPMSG link up: MTU Size: %d\r\n", oblfr_rpmsg_get_mtu());
|
||||
|
||||
ipc_rpmsg_ns = rpmsg_ns_bind(ipc_rpmsg, ipc_rpmsg_ns_callback, NULL);
|
||||
if (ipc_rpmsg_ns == RL_NULL)
|
||||
{
|
||||
LOG_W("Failed to bind RPMSG NS\r\n");
|
||||
rpmsg_lite_deinit(ipc_rpmsg);
|
||||
ipc_rpmsg = NULL;
|
||||
vTaskDelete(NULL);
|
||||
return;
|
||||
}
|
||||
LOG_D("RPMSG NS binded\r\n");
|
||||
|
||||
/* go through any registered endpoints and annouce them again */
|
||||
LIST_FOREACH(rpmsgqueue, &oblfr_rpmsg_queues, list_entry)
|
||||
{
|
||||
/* ignore errors */
|
||||
if (rpmsg_ns_announce(ipc_rpmsg, rpmsgqueue->ept, rpmsgqueue->cfg->name, RL_NS_CREATE) != RL_SUCCESS)
|
||||
{
|
||||
LOG_W("Failed to announce device %s\r\n", rpmsgqueue->cfg->name);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_D("Device %s announced\r\n", rpmsgqueue->cfg->name);
|
||||
}
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
QueueSetMemberHandle_t xActivatedMember = xQueueSelectFromSet(xQueueSet, 1000 / portTICK_PERIOD_MS);
|
||||
if (xActivatedMember != NULL)
|
||||
{
|
||||
LOG_D("Selected queue %p\r\n", xActivatedMember);
|
||||
bool handled = false;
|
||||
LIST_FOREACH(rpmsgqueue, &oblfr_rpmsg_queues, list_entry)
|
||||
{
|
||||
LOG_D("Checking queue %s\r\n", rpmsgqueue->cfg->name);
|
||||
if (rpmsgqueue->queue == xActivatedMember)
|
||||
{
|
||||
LOG_D("Received message on queue %s\r\n", rpmsgqueue->cfg->name);
|
||||
oblfr_process_queue(rpmsgqueue);
|
||||
handled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!handled)
|
||||
{
|
||||
LOG_E("Received message on unknown queue\r\n");
|
||||
}
|
||||
} else {
|
||||
/* occasionally check our RX Queue in case we miss a interupt */
|
||||
env_isr(1);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
|
@ -61,8 +61,11 @@ static oblfr_err_t oblfr_recalc_next_fire() {
|
|||
return OBLFR_ERR_ERROR;
|
||||
}
|
||||
oblfr_timer_t head = LIST_FIRST(&oblfr_timer_list);
|
||||
|
||||
assert(head != NULL);
|
||||
if (head == NULL) {
|
||||
LOG_D("oblfr_recalc_next_fire: no timers\r\n");
|
||||
oblfr_timer_unlock();
|
||||
return OBLFR_OK;
|
||||
}
|
||||
|
||||
uint64_t when = (head->when - bflb_mtimer_get_time_ms());
|
||||
if (when > 1000) {
|
||||
|
@ -174,10 +177,11 @@ oblfr_err_t oblfr_timer_init() {
|
|||
|
||||
vSemaphoreCreateBinary(oblfr_timer_list_lock);
|
||||
|
||||
if (xTaskCreate(oblfr_timer_task, "oblfr_timer_task", 1024, NULL, 5, &oblfr_timer_task_handle) != pdPASS) {
|
||||
if (xTaskCreate(oblfr_timer_task, "timer_task", 1024, NULL, 2, &oblfr_timer_task_handle) != pdPASS) {
|
||||
LOG_E("Create Timer Task failed\r\n");
|
||||
return OBLFR_ERR_ERROR;
|
||||
}
|
||||
LOG_I("oblfr_timer_init: Timer Task created\r\n");
|
||||
bflb_timer_start(timer0);
|
||||
return OBLFR_OK;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue