rpmsg_virtio_ivshmem.c: rpmsg virtio ivshmem msix interrupt support

Change the rpmsg_virtio_ivshmem from pci bus based to
pci-ivshmem bus based, so rpmsg_virtio_ivshmem can support interrupt
mode and also support the multi instance.

Signed-off-by: wangyongrong <wangyongrong@xiaomi.com>
Signed-off-by: Bowen Wang <wangbowen6@xiaomi.com>
This commit is contained in:
wangyongrong 2024-04-25 19:56:05 +08:00 committed by archer
parent 3ca717ef4a
commit 57cb0cb66f
2 changed files with 96 additions and 104 deletions

View File

@ -41,7 +41,7 @@ config RPMSG_VIRTIO_STACKSIZE
config RPMSG_VIRTIO_IVSHMEM config RPMSG_VIRTIO_IVSHMEM
bool "rpmsg virtio ivshmem support" bool "rpmsg virtio ivshmem support"
default n default n
depends on PCI depends on PCI_IVSHMEM
---help--- ---help---
This is rpmsg virtio driver based on pci ivshmem. This is rpmsg virtio driver based on pci ivshmem.
@ -50,11 +50,11 @@ if RPMSG_VIRTIO_IVSHMEM
config RPMSG_VIRTIO_IVSHMEM_NAME config RPMSG_VIRTIO_IVSHMEM_NAME
string "rpmsg virtio ivshmem name" string "rpmsg virtio ivshmem name"
---help--- ---help---
Using this config to custom the rpmsg virtio ivshmem cpuname and role, Using this config to custom the rpmsg virtio ivshmem id, cpuname and role,
using ";" to split the names. using ";" to split the names.
For example, if RPMSG_VIRTIO_IVSHMEM_CPUNAME = "cpu1:m;cpu2:s" and pass For example, if RPMSG_VIRTIO_IVSHMEM_CPUNAME = "0:cpu1:m;1:cpu2:s" and pass
two ivshmem devices to the qemu, we will get two rpmsg virtio ivshmem drivers two ivshmem devices to the qemu, we will get two rpmsg virtio ivshmem drivers
with remote cpu names: "cpu1", "cpu2", and roles: "master", "slave" with remote cpu ids: "0","1", names: "cpu1", "cpu2", and roles: "master", "slave"
config RPMSG_VIRTIO_IVSHMEM_BUFFSIZE config RPMSG_VIRTIO_IVSHMEM_BUFFSIZE
int "rpmsg virtio ivshmem rpmsg buffer size" int "rpmsg virtio ivshmem rpmsg buffer size"

View File

@ -29,7 +29,7 @@
#include <stdio.h> #include <stdio.h>
#include <nuttx/drivers/addrenv.h> #include <nuttx/drivers/addrenv.h>
#include <nuttx/pci/pci.h> #include <nuttx/pci/pci_ivshmem.h>
#include <nuttx/rpmsg/rpmsg_virtio.h> #include <nuttx/rpmsg/rpmsg_virtio.h>
#include <nuttx/rpmsg/rpmsg_virtio_ivshmem.h> #include <nuttx/rpmsg/rpmsg_virtio_ivshmem.h>
@ -37,8 +37,9 @@
* Pre-processor Definitions * Pre-processor Definitions
****************************************************************************/ ****************************************************************************/
#define RPMSG_VIRTIO_IVSHMEM_SHMEM_BAR 2 #define rpmsg_virtio_ivshmem_from(dev) \
#define RPMSG_VIRTIO_IVSHMEM_READY 0x1 container_of(ivshmem_get_driver(dev), struct rpmsg_virtio_ivshmem_dev_s, drv)
#define RPMSG_VIRTIO_IVSHMEM_WORK_DELAY 1 #define RPMSG_VIRTIO_IVSHMEM_WORK_DELAY 1
#define RPMSG_VIRTIO_VRING_ALIGNMENT 8 #define RPMSG_VIRTIO_VRING_ALIGNMENT 8
@ -60,6 +61,8 @@ struct rpmsg_virtio_ivshmem_mem_s
struct rpmsg_virtio_ivshmem_dev_s struct rpmsg_virtio_ivshmem_dev_s
{ {
struct rpmsg_virtio_s dev; struct rpmsg_virtio_s dev;
struct ivshmem_driver_s drv;
FAR struct ivshmem_device_s *ivdev;
rpmsg_virtio_callback_t callback; rpmsg_virtio_callback_t callback;
FAR void *arg; FAR void *arg;
uint32_t seq; uint32_t seq;
@ -91,9 +94,8 @@ static int
rpmsg_virtio_ivshmem_register_callback(FAR struct rpmsg_virtio_s *dev, rpmsg_virtio_ivshmem_register_callback(FAR struct rpmsg_virtio_s *dev,
rpmsg_virtio_callback_t callback, rpmsg_virtio_callback_t callback,
FAR void *arg); FAR void *arg);
static int rpmsg_virtio_ivshmem_probe(FAR struct ivshmem_device_s *ivdev);
static int rpmsg_virtio_ivshmem_probe(FAR struct pci_device_s *dev); static void rpmsg_virtio_ivshmem_remove(FAR struct ivshmem_device_s *ivdev);
static void rpmsg_virtio_ivshmem_remove(FAR struct pci_device_s *dev);
/**************************************************************************** /****************************************************************************
* Private Data * Private Data
@ -108,21 +110,6 @@ static const struct rpmsg_virtio_ops_s g_rpmsg_virtio_ivshmem_ops =
.register_callback = rpmsg_virtio_ivshmem_register_callback, .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 * Private Functions
****************************************************************************/ ****************************************************************************/
@ -199,7 +186,11 @@ static int rpmsg_virtio_ivshmem_notify(FAR struct rpmsg_virtio_s *dev,
FAR struct rpmsg_virtio_ivshmem_dev_s *priv = FAR struct rpmsg_virtio_ivshmem_dev_s *priv =
(FAR struct rpmsg_virtio_ivshmem_dev_s *)dev; (FAR struct rpmsg_virtio_ivshmem_dev_s *)dev;
if (priv->master) if (ivshmem_support_irq(priv->ivdev))
{
ivshmem_kick_peer(priv->ivdev);
}
else if (priv->master)
{ {
priv->shmem->seqm++; priv->shmem->seqm++;
} }
@ -224,6 +215,23 @@ rpmsg_virtio_ivshmem_register_callback(FAR struct rpmsg_virtio_s *dev,
return 0; return 0;
} }
/****************************************************************************
* Name: rpmsg_virtio_ivshmem_interrupt
****************************************************************************/
static int rpmsg_virtio_ivshmem_interrupt(int irq, FAR void *context,
FAR void *arg)
{
FAR struct rpmsg_virtio_ivshmem_dev_s *priv = arg;
if (priv->callback != NULL)
{
priv->callback(priv->arg, RPMSG_VIRTIO_NOTIFY_ALL);
}
return 0;
}
/**************************************************************************** /****************************************************************************
* Name: rpmsg_virtio_ivshmem_work * Name: rpmsg_virtio_ivshmem_work
****************************************************************************/ ****************************************************************************/
@ -253,84 +261,24 @@ static void rpmsg_virtio_ivshmem_work(FAR void *arg)
RPMSG_VIRTIO_IVSHMEM_WORK_DELAY); 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 * Name: rpmsg_virtio_ivshmem_probe
****************************************************************************/ ****************************************************************************/
static int rpmsg_virtio_ivshmem_probe(FAR struct pci_device_s *dev) static int rpmsg_virtio_ivshmem_probe(FAR struct ivshmem_device_s *ivdev)
{ {
FAR struct rpmsg_virtio_ivshmem_dev_s *priv; FAR struct rpmsg_virtio_ivshmem_dev_s *priv =
rpmsg_virtio_ivshmem_from(ivdev);
int ret; int ret;
priv = kmm_zalloc(sizeof(*priv));
if (priv == NULL)
{
return -ENOMEM;
}
/* Do the rpmsg virtio ivshmem init */ /* Do the rpmsg virtio ivshmem init */
priv->ivdev = ivdev;
priv->dev.ops = &g_rpmsg_virtio_ivshmem_ops; priv->dev.ops = &g_rpmsg_virtio_ivshmem_ops;
priv->ivshmem = dev; priv->shmem = ivshmem_get_shmem(ivdev, &priv->shmem_size);
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 */ ivshmem_attach_irq(ivdev, rpmsg_virtio_ivshmem_interrupt, priv);
ivshmem_control_irq(ivdev, true);
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 */ /* Do rpmsg virtio initialize */
@ -338,18 +286,20 @@ static int rpmsg_virtio_ivshmem_probe(FAR struct pci_device_s *dev)
if (ret < 0) if (ret < 0)
{ {
pcierr("rpmsg virtio intialize failed, ret=%d\n", ret); pcierr("rpmsg virtio intialize failed, ret=%d\n", ret);
goto err_master; goto err;
} }
if (!ivshmem_support_irq(ivdev))
{
work_queue(HPWORK, &priv->worker, rpmsg_virtio_ivshmem_work, priv, 0); work_queue(HPWORK, &priv->worker, rpmsg_virtio_ivshmem_work, priv, 0);
g_rpmsg_virtio_ivshmem_idx++; }
return ret; return ret;
err_master: err:
pci_clear_master(dev); ivshmem_unregister_driver(&priv->drv);
pci_disable_device(dev); ivshmem_control_irq(ivdev, false);
err_priv: ivshmem_detach_irq(ivdev);
kmm_free(priv);
return ret; return ret;
} }
@ -357,9 +307,15 @@ err_priv:
* Name: rpmsg_virtio_ivshmem_remove * Name: rpmsg_virtio_ivshmem_remove
****************************************************************************/ ****************************************************************************/
static void rpmsg_virtio_ivshmem_remove(FAR struct pci_device_s *dev) static void rpmsg_virtio_ivshmem_remove(FAR struct ivshmem_device_s *ivdev)
{ {
pciwarn("Not support remove for now\n"); FAR struct rpmsg_virtio_ivshmem_dev_s *priv =
rpmsg_virtio_ivshmem_from(ivdev);
work_cancel_sync(HPWORK, &priv->worker);
ivshmem_control_irq(ivdev, false);
ivshmem_detach_irq(ivdev);
kmm_free(priv);
} }
/**************************************************************************** /****************************************************************************
@ -368,5 +324,41 @@ static void rpmsg_virtio_ivshmem_remove(FAR struct pci_device_s *dev)
int pci_register_rpmsg_virtio_ivshmem_driver(void) int pci_register_rpmsg_virtio_ivshmem_driver(void)
{ {
return pci_register_driver(&g_rpmsg_virtio_ivshmem_drv); FAR char *name = CONFIG_RPMSG_VIRTIO_IVSHMEM_NAME;
while (name != NULL)
{
FAR const char *str;
FAR struct rpmsg_virtio_ivshmem_dev_s * priv =
kmm_zalloc(sizeof(*priv));
if (priv == NULL)
{
return -ENOMEM;
}
priv->drv.id = strtoul(name, &name, 0);
str = strchr(++name, ':');
snprintf(priv->cpuname, RPMSG_NAME_SIZE, "%.*s", (int)(str - name),
name);
priv->master = *(str + 1) == 'm';
pciinfo("Register ivshmem driver, id=%d, cpuname=%s, master=%d\n",
priv->drv.id, priv->cpuname, priv->master);
priv->drv.probe = rpmsg_virtio_ivshmem_probe;
priv->drv.remove = rpmsg_virtio_ivshmem_remove;
if (ivshmem_register_driver(&priv->drv) < 0)
{
kmm_free(priv);
}
name = strchr(str, ';');
if (name != NULL)
{
name++;
}
}
return 0;
} }