rpmsg/rpmsg_virtio_ivshmem: add rpmsg virtio ivshmem support

rpmsg_virtio_ivshmem is a ivshmem based rpmsg virtio driver,
with this driver, we can use the rpmsg virtio in qemu platfrom

Signed-off-by: Yongrong Wang <wangyongrong@xiaomi.com>
Signed-off-by: Bowen Wang <wangbowen6@xiaomi.com>
This commit is contained in:
Yongrong Wang 2024-02-23 14:57:40 +08:00 committed by archer
parent af0bde8bca
commit 67e41d0e32
5 changed files with 494 additions and 10 deletions

View File

@ -28,6 +28,7 @@
#include <nuttx/pci/pci_qemu_edu.h> #include <nuttx/pci/pci_qemu_edu.h>
#include <nuttx/pci/pci_qemu_test.h> #include <nuttx/pci/pci_qemu_test.h>
#include <nuttx/rptun/rptun_ivshmem.h> #include <nuttx/rptun/rptun_ivshmem.h>
#include <nuttx/rpmsg/rpmsg_virtio_ivshmem.h>
#include "pci_drivers.h" #include "pci_drivers.h"
@ -63,6 +64,25 @@ int pci_register_drivers(void)
} }
#endif #endif
/* Initialization rptun ivshmem driver */
#ifdef CONFIG_RPTUN_IVSHMEM
ret = pci_register_rptun_ivshmem_driver();
if (ret < 0)
{
pcierr("pci_register_rptun_ivshmem_driver failed, ret=%d\n", ret);
}
#endif
#ifdef CONFIG_RPMSG_VIRTIO_IVSHMEM
ret = pci_register_rpmsg_virtio_ivshmem_driver();
if (ret < 0)
{
pcierr("pci_register_rpmsg_virtio_ivshmem_driver failed, ret=%d\n",
ret);
}
#endif
/* Initialization pci qemu test driver */ /* Initialization pci qemu test driver */
#ifdef CONFIG_PCI_QEMU_TEST #ifdef CONFIG_PCI_QEMU_TEST
@ -83,16 +103,6 @@ int pci_register_drivers(void)
} }
#endif #endif
/* Initialization rptun ivshmem driver */
#ifdef CONFIG_RPTUN_IVSHMEM
ret = pci_register_rptun_ivshmem_driver();
if (ret < 0)
{
pcierr("pci_register_rptun_ivshmem_driver failed, ret=%d\n", ret);
}
#endif
UNUSED(ret); UNUSED(ret);
return ret; return ret;
} }

View File

@ -38,4 +38,38 @@ config RPMSG_VIRTIO_STACKSIZE
int "rpmsg virtio rx thread stack size" int "rpmsg virtio rx thread stack size"
default DEFAULT_TASK_STACKSIZE default DEFAULT_TASK_STACKSIZE
config RPMSG_VIRTIO_IVSHMEM
bool "rpmsg virtio ivshmem support"
default n
depends on PCI
---help---
This is rpmsg virtio driver based on pci ivshmem.
if RPMSG_VIRTIO_IVSHMEM
config RPMSG_VIRTIO_IVSHMEM_NAME
string "rpmsg virtio ivshmem name"
---help---
Using this config to custom the rpmsg virtio ivshmem cpuname and role,
using ";" to split the names.
For example, if RPMSG_VIRTIO_IVSHMEM_CPUNAME = "cpu1:m;cpu2:s" and pass
two ivshmem devices to the qemu, we will get two rpmsg virtio ivshmem drivers
with remote cpu names: "cpu1", "cpu2", and roles: "master", "slave"
config RPMSG_VIRTIO_IVSHMEM_BUFFSIZE
int "rpmsg virtio ivshmem rpmsg buffer size"
default 2048
---help---
The rpmsg buffer size in share memory, the RX and TX buffer size
are same for now.
config RPMSG_VIRTIO_IVSHMEM_BUFFNUM
int "rpmsg virtio ivshmem rpmsg buffer number"
default 8
---help---
The rpmsg virtio buffer number in share memory, the RX and TX buffer number
are same for now.
endif
endif endif

View File

@ -33,6 +33,10 @@ CSRCS += rpmsg_virtio.c
CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)openamp$(DELIM)open-amp$(DELIM)lib CFLAGS += ${INCDIR_PREFIX}$(TOPDIR)$(DELIM)openamp$(DELIM)open-amp$(DELIM)lib
endif endif
ifeq ($(CONFIG_RPMSG_VIRTIO_IVSHMEM),y)
CSRCS += rpmsg_virtio_ivshmem.c
endif
DEPPATH += --dep-path rpmsg DEPPATH += --dep-path rpmsg
VPATH += :rpmsg VPATH += :rpmsg

View File

@ -0,0 +1,373 @@
/****************************************************************************
* drivers/rpmsg/rpmsg_virtio_ivshmem.c
*
* 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.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <debug.h>
#include <errno.h>
#include <stdio.h>
#include <nuttx/drivers/addrenv.h>
#include <nuttx/pci/pci.h>
#include <nuttx/rpmsg/rpmsg_virtio.h>
#include <nuttx/rpmsg/rpmsg_virtio_ivshmem.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
#define RPMSG_VIRTIO_IVSHMEM_SHMEM_BAR 2
#define RPMSG_VIRTIO_IVSHMEM_READY 0x1
#define RPMSG_VIRTIO_IVSHMEM_WORK_DELAY 1
#define RPMSG_VIRTIO_VRING_ALIGNMENT 8
/****************************************************************************
* Private Types
****************************************************************************/
struct rpmsg_virtio_ivshmem_mem_s
{
volatile uint64_t basem;
volatile uint32_t seqs;
volatile uint32_t seqm;
volatile uint32_t cmds;
volatile uint32_t cmdm;
struct rpmsg_virtio_rsc_s rsc;
};
struct rpmsg_virtio_ivshmem_dev_s
{
struct rpmsg_virtio_s dev;
rpmsg_virtio_callback_t callback;
FAR void *arg;
uint32_t seq;
FAR struct rpmsg_virtio_ivshmem_mem_s *shmem;
size_t shmem_size;
struct simple_addrenv_s addrenv;
int master;
char cpuname[RPMSG_NAME_SIZE + 1];
FAR struct pci_device_s *ivshmem;
/* Work queue for transmit */
struct work_s worker;
};
/****************************************************************************
* Private Function Prototypes
****************************************************************************/
static const FAR char *
rpmsg_virtio_ivshmem_get_cpuname(FAR struct rpmsg_virtio_s *dev);
static FAR struct rpmsg_virtio_rsc_s *
rpmsg_virtio_ivshmem_get_resource(FAR struct rpmsg_virtio_s *dev);
static int
rpmsg_virtio_ivshmem_is_master(FAR struct rpmsg_virtio_s *dev);
static int rpmsg_virtio_ivshmem_notify(FAR struct rpmsg_virtio_s *dev,
uint32_t notifyid);
static int
rpmsg_virtio_ivshmem_register_callback(FAR struct rpmsg_virtio_s *dev,
rpmsg_virtio_callback_t callback,
FAR void *arg);
static int rpmsg_virtio_ivshmem_probe(FAR struct pci_device_s *dev);
static void rpmsg_virtio_ivshmem_remove(FAR struct pci_device_s *dev);
/****************************************************************************
* Private Data
****************************************************************************/
static const struct rpmsg_virtio_ops_s g_rpmsg_virtio_ivshmem_ops =
{
.get_cpuname = rpmsg_virtio_ivshmem_get_cpuname,
.get_resource = rpmsg_virtio_ivshmem_get_resource,
.is_master = rpmsg_virtio_ivshmem_is_master,
.notify = rpmsg_virtio_ivshmem_notify,
.register_callback = rpmsg_virtio_ivshmem_register_callback,
};
static const struct pci_device_id_s g_rpmsg_virtio_ivshmem_ids[] =
{
{ PCI_DEVICE(0x1af4, 0x1110) },
{ 0, }
};
static struct pci_driver_s g_rpmsg_virtio_ivshmem_drv =
{
g_rpmsg_virtio_ivshmem_ids, /* PCI id_tables */
rpmsg_virtio_ivshmem_probe, /* Probe function */
rpmsg_virtio_ivshmem_remove, /* Remove function */
};
static int g_rpmsg_virtio_ivshmem_idx = 0;
/****************************************************************************
* Private Functions
****************************************************************************/
static const FAR char *
rpmsg_virtio_ivshmem_get_cpuname(FAR struct rpmsg_virtio_s *dev)
{
FAR struct rpmsg_virtio_ivshmem_dev_s *priv =
(FAR struct rpmsg_virtio_ivshmem_dev_s *)dev;
return priv->cpuname;
}
static FAR struct rpmsg_virtio_rsc_s *
rpmsg_virtio_ivshmem_get_resource(FAR struct rpmsg_virtio_s *dev)
{
FAR struct rpmsg_virtio_ivshmem_dev_s *priv =
(FAR struct rpmsg_virtio_ivshmem_dev_s *)dev;
FAR struct rpmsg_virtio_rsc_s *rsc;
rsc = &priv->shmem->rsc;
if (priv->master)
{
memset(priv->shmem, 0, priv->shmem_size);
rsc->rpmsg_vdev.id = VIRTIO_ID_RPMSG;
rsc->rpmsg_vdev.dfeatures = 1 << VIRTIO_RPMSG_F_NS |
1 << VIRTIO_RPMSG_F_ACK |
1 << VIRTIO_RPMSG_F_BUFSZ;
rsc->rpmsg_vdev.config_len = sizeof(struct fw_rsc_config);
rsc->rpmsg_vdev.num_of_vrings = 2;
rsc->rpmsg_vring0.da = 0;
rsc->rpmsg_vring0.align = RPMSG_VIRTIO_VRING_ALIGNMENT;
rsc->rpmsg_vring0.num = CONFIG_RPMSG_VIRTIO_IVSHMEM_BUFFNUM;
rsc->rpmsg_vring1.da = 0;
rsc->rpmsg_vring1.align = RPMSG_VIRTIO_VRING_ALIGNMENT;
rsc->rpmsg_vring1.num = CONFIG_RPMSG_VIRTIO_IVSHMEM_BUFFNUM;
rsc->config.r2h_buf_size = CONFIG_RPMSG_VIRTIO_IVSHMEM_BUFFSIZE;
rsc->config.h2r_buf_size = CONFIG_RPMSG_VIRTIO_IVSHMEM_BUFFSIZE;
priv->shmem->basem = (uint64_t)(uintptr_t)priv->shmem;
}
else
{
/* Wait untils master is ready, salve need use master base to
* initialize addrenv.
*/
while (priv->shmem->basem == 0)
{
usleep(1000);
}
priv->addrenv.va = (uint64_t)(uintptr_t)priv->shmem;
priv->addrenv.pa = priv->shmem->basem;
priv->addrenv.size = priv->shmem_size;
simple_addrenv_initialize(&priv->addrenv);
priv->shmem->basem = 0;
}
return rsc;
}
static int rpmsg_virtio_ivshmem_is_master(FAR struct rpmsg_virtio_s *dev)
{
FAR struct rpmsg_virtio_ivshmem_dev_s *priv =
(FAR struct rpmsg_virtio_ivshmem_dev_s *)dev;
return priv->master;
}
static int rpmsg_virtio_ivshmem_notify(FAR struct rpmsg_virtio_s *dev,
uint32_t vqid)
{
FAR struct rpmsg_virtio_ivshmem_dev_s *priv =
(FAR struct rpmsg_virtio_ivshmem_dev_s *)dev;
if (priv->master)
{
priv->shmem->seqm++;
}
else
{
priv->shmem->seqs++;
}
return 0;
}
static int
rpmsg_virtio_ivshmem_register_callback(FAR struct rpmsg_virtio_s *dev,
rpmsg_virtio_callback_t callback,
FAR void *arg)
{
FAR struct rpmsg_virtio_ivshmem_dev_s *priv =
(FAR struct rpmsg_virtio_ivshmem_dev_s *)dev;
priv->callback = callback;
priv->arg = arg;
return 0;
}
/****************************************************************************
* Name: rpmsg_virtio_ivshmem_work
****************************************************************************/
static void rpmsg_virtio_ivshmem_work(FAR void *arg)
{
FAR struct rpmsg_virtio_ivshmem_dev_s *priv = arg;
bool should_notify = false;
if (priv->master && priv->seq != priv->shmem->seqs)
{
priv->seq = priv->shmem->seqs;
should_notify = true;
}
else if (!priv->master && priv->seq != priv->shmem->seqm)
{
priv->seq = priv->shmem->seqm;
should_notify = true;
}
if (should_notify && priv->callback != NULL)
{
priv->callback(priv->arg, RPMSG_VIRTIO_NOTIFY_ALL);
}
work_queue(HPWORK, &priv->worker, rpmsg_virtio_ivshmem_work, priv,
RPMSG_VIRTIO_IVSHMEM_WORK_DELAY);
}
/****************************************************************************
* Name: rpmsg_virtio_ivshmem_get_info
****************************************************************************/
static int rpmsg_virtio_ivshmem_get_info(FAR char *cpuname, FAR int *master)
{
FAR const char *name = CONFIG_RPMSG_VIRTIO_IVSHMEM_NAME;
int start = 0;
int i;
int j;
for (i = 0, j = 0; name[start] != '\0'; i++)
{
if (name[i] == ';' || name[i] == '\0')
{
if (j++ == g_rpmsg_virtio_ivshmem_idx)
{
snprintf(cpuname, RPMSG_NAME_SIZE, "%.*s", i - start - 2,
&name[start]);
*master = name[i - 1] == 'm';
return 0;
}
start = i + 1;
}
}
return -ENODEV;
}
/****************************************************************************
* Name: rpmsg_virtio_ivshmem_probe
****************************************************************************/
static int rpmsg_virtio_ivshmem_probe(FAR struct pci_device_s *dev)
{
FAR struct rpmsg_virtio_ivshmem_dev_s *priv;
int ret;
priv = kmm_zalloc(sizeof(*priv));
if (priv == NULL)
{
return -ENOMEM;
}
/* Do the rpmsg virtio ivshmem init */
priv->dev.ops = &g_rpmsg_virtio_ivshmem_ops;
priv->ivshmem = dev;
ret = rpmsg_virtio_ivshmem_get_info(priv->cpuname, &priv->master);
if (ret < 0)
{
goto err_priv;
}
/* Configure the ivshmem device and get share memory address */
ret = pci_enable_device(dev);
if (ret < 0)
{
pcierr("Enable device failed, ret=%d\n", ret);
goto err_priv;
}
pci_set_master(dev);
priv->shmem = (FAR struct rpmsg_virtio_ivshmem_mem_s *)
pci_map_bar(dev, RPMSG_VIRTIO_IVSHMEM_SHMEM_BAR);
if (priv->shmem == NULL)
{
ret = -ENOTSUP;
pcierr("Device not support share memory bar\n");
goto err_master;
}
priv->shmem_size = pci_resource_len(dev, RPMSG_VIRTIO_IVSHMEM_SHMEM_BAR);
pciinfo("shmem addr=%p size=%zu\n", priv->shmem, priv->shmem_size);
/* Do rpmsg virtio initialize */
ret = rpmsg_virtio_initialize(&priv->dev);
if (ret < 0)
{
pcierr("rpmsg virtio intialize failed, ret=%d\n", ret);
goto err_master;
}
work_queue(HPWORK, &priv->worker, rpmsg_virtio_ivshmem_work, priv, 0);
g_rpmsg_virtio_ivshmem_idx++;
return ret;
err_master:
pci_clear_master(dev);
pci_disable_device(dev);
err_priv:
kmm_free(priv);
return ret;
}
/****************************************************************************
* Name: rpmsg_virtio_ivshmem_remove
****************************************************************************/
static void rpmsg_virtio_ivshmem_remove(FAR struct pci_device_s *dev)
{
pciwarn("Not support remove for now\n");
}
/****************************************************************************
* Public Functions
****************************************************************************/
int pci_register_rpmsg_virtio_ivshmem_driver(void)
{
return pci_register_driver(&g_rpmsg_virtio_ivshmem_drv);
}

View File

@ -0,0 +1,63 @@
/****************************************************************************
* include/nuttx/rpmsg/rpmsg_virtio_ivshmem.h
*
* 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.
*
****************************************************************************/
#ifndef __INCLUDE_NUTTX_RPMSG_RPMSG_VIRTIO_IVSHMEM_H
#define __INCLUDE_NUTTX_RPMSG_RPMSG_VIRTIO_IVSHMEM_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#ifdef CONFIG_RPMSG_VIRTIO_IVSHMEM
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Name: rpmsg_virtio_ivshmem_driver_init
*
* Description:
* Initializes the rptun ivshmem driver.
*
* Returned Value:
* OK on success, negated errno on failure
*
****************************************************************************/
int pci_register_rpmsg_virtio_ivshmem_driver(void);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* CONFIG_RPMSG_VIRTIO_IVSHMEM */
#endif /* __INCLUDE_NUTTX_RPMSG_RPMSG_VIRTIO_IVSHMEM_H */