drivers: mbox: add IVSHMEM based mbox driver
Add initial support of the mailbox driver based on the inter VM shared memory mechanism similar as the existing IPM driver. Signed-off-by: Felipe Neves <ryukokki.felipe@gmail.com>
This commit is contained in:
parent
abfd712cec
commit
9542166589
5 changed files with 199 additions and 1 deletions
|
|
@ -18,3 +18,4 @@ zephyr_library_sources_ifdef(CONFIG_MBOX_NRF_VEVIF_EVENT_TX mbox_nrf_vevif_event
|
|||
zephyr_library_sources_ifdef(CONFIG_MBOX_NRF_BELLBOARD_RX mbox_nrf_bellboard_rx.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_MBOX_NRF_BELLBOARD_TX mbox_nrf_bellboard_tx.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_MBOX_STM32_HSEM mbox_stm32_hsem.c)
|
||||
zephyr_library_sources_ifdef(CONFIG_MBOX_IVSHMEM mbox_ivshmem.c)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ source "drivers/mbox/Kconfig.nrf_vevif_event"
|
|||
source "drivers/mbox/Kconfig.nrf_bellboard"
|
||||
source "drivers/mbox/Kconfig.stm32_hsem"
|
||||
source "drivers/mbox/Kconfig.esp32"
|
||||
|
||||
source "drivers/mbox/Kconfig.ivshmem"
|
||||
|
||||
config MBOX_INIT_PRIORITY
|
||||
int "MBOX init priority"
|
||||
|
|
|
|||
27
drivers/mbox/Kconfig.ivshmem
Normal file
27
drivers/mbox/Kconfig.ivshmem
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
# Copyright (c) 2024, Felipe Neves
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
config MBOX_IVSHMEM
|
||||
bool "MBOX driver based on IVSHMEM-Doorbell"
|
||||
default y
|
||||
depends on DT_HAS_LINARO_IVSHMEM_MBOX_ENABLED
|
||||
depends on IVSHMEM
|
||||
depends on IVSHMEM_DOORBELL
|
||||
help
|
||||
Mailbox driver using IVSHMEM Doorbell mechanism.
|
||||
|
||||
if MBOX_IVSHMEM
|
||||
|
||||
config MBOX_IVSHMEM_EVENT_LOOP_STACK_SIZE
|
||||
int "Stack size in bytes of IVSHMEM MBOX Event loop task"
|
||||
default 8192
|
||||
help
|
||||
Adjust the stack size, in bytes of the ivshmem event loop task.
|
||||
|
||||
config MBOX_IVSHMEM_EVENT_LOOP_PRIO
|
||||
int "Priority of IVSHMEM MBOX Event loop task"
|
||||
default 2
|
||||
help
|
||||
Adjust the priority of the ivshmem event loop task.
|
||||
|
||||
endif
|
||||
155
drivers/mbox/mbox_ivshmem.c
Normal file
155
drivers/mbox/mbox_ivshmem.c
Normal file
|
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* Copyright (c) 2024 Felipe Neves.
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT linaro_ivshmem_mbox
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <zephyr/device.h>
|
||||
#include <zephyr/drivers/mbox.h>
|
||||
#include <zephyr/drivers/virtualization/ivshmem.h>
|
||||
#include <zephyr/logging/log.h>
|
||||
LOG_MODULE_REGISTER(mbox_ivshmem, CONFIG_MBOX_LOG_LEVEL);
|
||||
|
||||
K_THREAD_STACK_DEFINE(ivshmem_ev_loop_stack, CONFIG_MBOX_IVSHMEM_EVENT_LOOP_STACK_SIZE);
|
||||
static struct k_thread ivshmem_ev_loop_thread;
|
||||
|
||||
struct ivshmem_mbox_data {
|
||||
mbox_callback_t cb;
|
||||
void *user_data;
|
||||
};
|
||||
|
||||
struct ivshmem_mbox_config {
|
||||
const struct device *ivshmem_dev;
|
||||
int peer_id;
|
||||
};
|
||||
|
||||
static void ivshmem_mbox_event_loop_thread(void *arg, void *p2, void *p3)
|
||||
{
|
||||
ARG_UNUSED(p2);
|
||||
ARG_UNUSED(p3);
|
||||
|
||||
unsigned int poll_signaled;
|
||||
int ivshmem_vector_rx;
|
||||
struct k_poll_signal sig;
|
||||
struct k_poll_event events[] = {
|
||||
K_POLL_EVENT_INITIALIZER(K_POLL_TYPE_SIGNAL, K_POLL_MODE_NOTIFY_ONLY, &sig),
|
||||
};
|
||||
|
||||
const struct device *dev = (const struct device *)arg;
|
||||
struct ivshmem_mbox_data *dev_data = (struct ivshmem_mbox_data *)dev->data;
|
||||
struct ivshmem_mbox_config *dev_cfg = (struct ivshmem_mbox_config *)dev->config;
|
||||
|
||||
k_poll_signal_init(&sig);
|
||||
int ret = ivshmem_register_handler(dev_cfg->ivshmem_dev, &sig, 0);
|
||||
|
||||
if (ret < 0) {
|
||||
LOG_ERR("registering handlers must be supported: %d\n", ret);
|
||||
k_panic();
|
||||
}
|
||||
|
||||
while (1) {
|
||||
LOG_DBG("%s: waiting interrupt from client...\n", __func__);
|
||||
ret = k_poll(events, ARRAY_SIZE(events), K_FOREVER);
|
||||
|
||||
k_poll_signal_check(&sig, &poll_signaled, &ivshmem_vector_rx);
|
||||
/* get ready for next signal */
|
||||
k_poll_signal_reset(&sig);
|
||||
|
||||
if (dev_data->cb) {
|
||||
dev_data->cb(dev, 0, dev_data->user_data, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int ivshmem_mbox_send(const struct device *dev, mbox_channel_id_t channel,
|
||||
const struct mbox_msg *msg)
|
||||
{
|
||||
ARG_UNUSED(msg);
|
||||
ARG_UNUSED(channel);
|
||||
|
||||
struct ivshmem_mbox_config *dev_cfg = (struct ivshmem_mbox_config *)dev->config;
|
||||
|
||||
LOG_DBG("sending notification to the peer id 0x%x\n", (int)channel);
|
||||
return ivshmem_int_peer(dev_cfg->ivshmem_dev, (int)channel, 0);
|
||||
}
|
||||
|
||||
static int ivshmem_mbox_register_callback(const struct device *dev, mbox_channel_id_t channel,
|
||||
mbox_callback_t cb, void *user_data)
|
||||
{
|
||||
ARG_UNUSED(channel);
|
||||
|
||||
struct ivshmem_mbox_data *dev_data = (struct ivshmem_mbox_data *)dev->data;
|
||||
|
||||
if (!cb) {
|
||||
LOG_ERR("Must provide a callback");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dev_data->cb = cb;
|
||||
dev_data->user_data = user_data;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* some subsystems needs those functions to be at least implemented,
|
||||
* returning some valid values instead of errors, just provide them.
|
||||
*/
|
||||
|
||||
static int ivshmem_mbox_mtu_get(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t ivshmem_mbox_max_channels_get(const struct device *dev)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
|
||||
return UINT16_MAX;
|
||||
}
|
||||
|
||||
static int ivshmem_mbox_set_enabled(const struct device *dev, mbox_channel_id_t channel,
|
||||
bool enable)
|
||||
{
|
||||
ARG_UNUSED(dev);
|
||||
ARG_UNUSED(channel);
|
||||
ARG_UNUSED(enable);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ivshmem_mbox_init(const struct device *dev)
|
||||
{
|
||||
k_thread_create(&ivshmem_ev_loop_thread, ivshmem_ev_loop_stack,
|
||||
CONFIG_MBOX_IVSHMEM_EVENT_LOOP_STACK_SIZE, ivshmem_mbox_event_loop_thread,
|
||||
(void *)dev, NULL, NULL, CONFIG_MBOX_IVSHMEM_EVENT_LOOP_PRIO, 0, K_NO_WAIT);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct mbox_driver_api ivshmem_mbox_driver_api = {
|
||||
.send = ivshmem_mbox_send,
|
||||
.register_callback = ivshmem_mbox_register_callback,
|
||||
.mtu_get = ivshmem_mbox_mtu_get,
|
||||
.max_channels_get = ivshmem_mbox_max_channels_get,
|
||||
.set_enabled = ivshmem_mbox_set_enabled,
|
||||
};
|
||||
|
||||
#define MBOX_IVSHMEM_INIT(inst) \
|
||||
static const struct ivshmem_mbox_config ivshmem_mbox_cfg_##inst = { \
|
||||
.ivshmem_dev = DEVICE_DT_GET(DT_INST_PHANDLE(inst, ivshmem)), \
|
||||
}; \
|
||||
static struct ivshmem_mbox_data ivshmem_mbox_data_##inst = { \
|
||||
.cb = NULL, \
|
||||
.user_data = NULL, \
|
||||
}; \
|
||||
DEVICE_DT_INST_DEFINE(inst, ivshmem_mbox_init, NULL, &ivshmem_mbox_data_##inst, \
|
||||
&ivshmem_mbox_cfg_##inst, POST_KERNEL, \
|
||||
CONFIG_APPLICATION_INIT_PRIORITY, &ivshmem_mbox_driver_api);
|
||||
|
||||
DT_INST_FOREACH_STATUS_OKAY(MBOX_IVSHMEM_INIT);
|
||||
15
dts/bindings/mbox/linaro,ivshmem-mbox.yaml
Normal file
15
dts/bindings/mbox/linaro,ivshmem-mbox.yaml
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# Copyright (c) 2024 Felipe Neves
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: Inter VM shared memory based mailbox binding
|
||||
|
||||
compatible: "linaro,ivshmem-mbox"
|
||||
|
||||
include: base.yaml
|
||||
|
||||
properties:
|
||||
|
||||
ivshmem:
|
||||
type: phandle
|
||||
required: true
|
||||
description: ivshmem device node
|
||||
Loading…
Reference in a new issue