diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 9ca14e02eb3..fca194f8bb4 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -26,6 +26,15 @@ config DRIVERS_VIRTIO_PCI bool "Virtio PCI Device Support" default n +config DRIVERS_VIRTIO_PCI_POLLING_PERIOD + int "Virtio PCI Polling Period (us)" + depends on DRIVERS_VIRTIO_PCI + default 0 + ---help--- + if Polling Period <= 0, not support polling mode. + if Polling Period > 0, support polling mode, and it represent + polling period (us). + config DRIVERS_VIRTIO_BLK bool "Virtio block support" depends on !DISABLE_MOUNTPOINT diff --git a/drivers/virtio/virtio-pci-legacy.c b/drivers/virtio/virtio-pci-legacy.c index 0f0165f779a..4a383ad1ae7 100644 --- a/drivers/virtio/virtio-pci-legacy.c +++ b/drivers/virtio/virtio-pci-legacy.c @@ -107,7 +107,8 @@ static int virtio_pci_legacy_create_virtqueue(FAR struct virtio_pci_device_s *vpdev, FAR struct virtqueue *vq); static int -virtio_pci_legacy_config_vector(FAR struct virtio_pci_device_s *vpdev); +virtio_pci_legacy_config_vector(FAR struct virtio_pci_device_s *vpdev, + bool enable); static void virtio_pci_legacy_delete_virtqueue(FAR struct virtio_device *vdev, @@ -186,7 +187,9 @@ static int virtio_pci_legacy_create_virtqueue(FAR struct virtio_pci_device_s *vpdev, FAR struct virtqueue *vq) { +#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0 uint16_t msix_vector; +#endif /* Set the pci virtqueue register, active vq, enable vq */ @@ -198,6 +201,8 @@ virtio_pci_legacy_create_virtqueue(FAR struct virtio_pci_device_s *vpdev, pci_write_io_dword(vpdev->dev, vpdev->ioaddr + VIRTIO_PCI_QUEUE_PFN, up_addrenv_va_to_pa(vq->vq_ring.desc) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT); + +#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0 pci_write_io_word(vpdev->dev, vpdev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR, VIRTIO_PCI_INT_VQ); pci_read_io_word(vpdev->dev, vpdev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR, @@ -209,6 +214,7 @@ virtio_pci_legacy_create_virtqueue(FAR struct virtio_pci_device_s *vpdev, vrterr("Msix vector is 0\n"); return -EBUSY; } +#endif return OK; } @@ -218,15 +224,18 @@ virtio_pci_legacy_create_virtqueue(FAR struct virtio_pci_device_s *vpdev, ****************************************************************************/ static int -virtio_pci_legacy_config_vector(FAR struct virtio_pci_device_s *vpdev) +virtio_pci_legacy_config_vector(FAR struct virtio_pci_device_s *vpdev, + bool enable) { + uint16_t vector = enable ? 0 : VIRTIO_PCI_MSI_NO_VECTOR; uint16_t rvector; pci_write_io_word(vpdev->dev, vpdev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR, - VIRTIO_PCI_INT_CFG); + vector); pci_read_io_word(vpdev->dev, vpdev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR, &rvector); - if (rvector == VIRTIO_PCI_MSI_NO_VECTOR) + + if (rvector != vector) { return -EINVAL; } @@ -243,15 +252,20 @@ void virtio_pci_legacy_delete_virtqueue(FAR struct virtio_device *vdev, { FAR struct virtio_pci_device_s *vpdev = (FAR struct virtio_pci_device_s *)vdev; +#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0 uint8_t isr; +#endif pci_write_io_word(vpdev->dev, vpdev->ioaddr + VIRTIO_PCI_QUEUE_SEL, index); + +#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0 pci_write_io_word(vpdev->dev, vpdev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR, VIRTIO_PCI_MSI_NO_VECTOR); /* Flush the write out to device */ pci_read_io_byte(vpdev->dev, vpdev->ioaddr + VIRTIO_PCI_ISR, &isr); +#endif /* Select and deactivate the queue */ @@ -295,13 +309,17 @@ static void virtio_pci_legacy_write_config(FAR struct virtio_device *vdev, { FAR struct virtio_pci_device_s *vpdev = (FAR struct virtio_pci_device_s *)vdev; +#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0 + FAR char *config = vpdev->ioaddr + VIRTIO_PCI_CONFIG_OFF(true) + offset; +#else + FAR char *config = vpdev->ioaddr + VIRTIO_PCI_CONFIG_OFF(false) + offset; +#endif FAR uint8_t *s = src; int i; for (i = 0; i < length; i++) { - pci_write_io_byte(vpdev->dev, vpdev->ioaddr + - VIRTIO_PCI_CONFIG_OFF(true) + offset + i, s[i]); + pci_write_io_byte(vpdev->dev, config + i, s[i]); } } @@ -315,13 +333,17 @@ static void virtio_pci_legacy_read_config(FAR struct virtio_device *vdev, { FAR struct virtio_pci_device_s *vpdev = (FAR struct virtio_pci_device_s *)vdev; +#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0 + FAR char *config = vpdev->ioaddr + VIRTIO_PCI_CONFIG_OFF(true) + offset; +#else + FAR char *config = vpdev->ioaddr + VIRTIO_PCI_CONFIG_OFF(false) + offset; +#endif FAR uint8_t *d = dst; int i; for (i = 0; i < length; i++) { - pci_read_io_byte(vpdev->dev, vpdev->ioaddr + - VIRTIO_PCI_CONFIG_OFF(true) + offset + i, &d[i]); + pci_read_io_byte(vpdev->dev, config + i, &d[i]); } } diff --git a/drivers/virtio/virtio-pci-modern.c b/drivers/virtio/virtio-pci-modern.c index 8f83135191a..d3c06477f56 100644 --- a/drivers/virtio/virtio-pci-modern.c +++ b/drivers/virtio/virtio-pci-modern.c @@ -159,7 +159,8 @@ static uint16_t virtio_pci_modern_get_queue_len(FAR struct virtio_pci_device_s *vpdev, int idx); static int -virtio_pci_modern_config_vector(FAR struct virtio_pci_device_s *vpdev); +virtio_pci_modern_config_vector(FAR struct virtio_pci_device_s *vpdev, + bool enable); static int virtio_pci_modern_create_virtqueue(FAR struct virtio_pci_device_s *vpdev, FAR struct virtqueue *vq); @@ -321,7 +322,9 @@ virtio_pci_modern_create_virtqueue(FAR struct virtio_pci_device_s *vpdev, { FAR struct virtio_pci_common_cfg_s *cfg = vpdev->common; FAR struct virtio_vring_info *vrinfo; +#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0 uint16_t msix_vector; +#endif uint16_t off; /* Activate the queue */ @@ -336,6 +339,7 @@ virtio_pci_modern_create_virtqueue(FAR struct virtio_pci_device_s *vpdev, pci_write_io_qword(vpdev->dev, &cfg->queue_used, up_addrenv_va_to_pa(vq->vq_ring.used)); +#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0 pci_write_io_word(vpdev->dev, &cfg->queue_msix_vector, VIRTIO_PCI_INT_VQ); pci_read_io_word(vpdev->dev, &cfg->queue_msix_vector, &msix_vector); @@ -344,6 +348,7 @@ virtio_pci_modern_create_virtqueue(FAR struct virtio_pci_device_s *vpdev, vrterr("Msix_vector is no vector\n"); return -EBUSY; } +#endif /* Enable vq */ @@ -368,15 +373,16 @@ virtio_pci_modern_create_virtqueue(FAR struct virtio_pci_device_s *vpdev, ****************************************************************************/ static int -virtio_pci_modern_config_vector(FAR struct virtio_pci_device_s *vpdev) +virtio_pci_modern_config_vector(FAR struct virtio_pci_device_s *vpdev, + bool enable) { FAR struct virtio_pci_common_cfg_s *cfg = vpdev->common; + uint16_t vector = enable ? 0 : VIRTIO_PCI_MSI_NO_VECTOR; uint16_t rvector; - pci_write_io_word(vpdev->dev, &cfg->config_msix_vector, - VIRTIO_PCI_INT_CFG); + pci_write_io_word(vpdev->dev, &cfg->config_msix_vector, vector); pci_read_io_word(vpdev->dev, &cfg->config_msix_vector, &rvector); - if (rvector == VIRTIO_PCI_MSI_NO_VECTOR) + if (rvector != vector) { return -EINVAL; } @@ -396,8 +402,11 @@ void virtio_pci_modern_delete_virtqueue(FAR struct virtio_device *vdev, FAR struct virtio_pci_common_cfg_s *cfg = vpdev->common; pci_write_io_word(vpdev->dev, &cfg->queue_select, index); + +#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0 pci_write_io_word(vpdev->dev, &cfg->queue_msix_vector, VIRTIO_PCI_MSI_NO_VECTOR); +#endif } /**************************************************************************** diff --git a/drivers/virtio/virtio-pci.c b/drivers/virtio/virtio-pci.c index d6f20b936d5..f1b904c7132 100644 --- a/drivers/virtio/virtio-pci.c +++ b/drivers/virtio/virtio-pci.c @@ -29,10 +29,18 @@ #include #include +#include #include #include "virtio-pci.h" +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define VIRTIO_PCI_WORK_DELAY \ + USEC2TICK(CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD) + /**************************************************************************** * Private Function Prototypes ****************************************************************************/ @@ -66,24 +74,11 @@ static struct pci_driver_s g_virtio_pci_drv = ****************************************************************************/ /**************************************************************************** - * Name: virtio_pci_config_changed + * Name: virtio_pci_vq_callback ****************************************************************************/ -static int virtio_pci_config_changed(int irq, FAR void *context, - FAR void *arg) +static void virtio_pci_vq_callback(FAR struct virtio_pci_device_s *vpdev) { - /* TODO: not support config changed notification */ - - return OK; -} - -/**************************************************************************** - * Name: virtio_pci_interrupt - ****************************************************************************/ - -static int virtio_pci_interrupt(int irq, FAR void *context, FAR void *arg) -{ - FAR struct virtio_pci_device_s *vpdev = arg; FAR struct virtio_vring_info *vrings_info = vpdev->vdev.vrings_info; FAR struct virtqueue *vq; unsigned int i; @@ -97,10 +92,49 @@ static int virtio_pci_interrupt(int irq, FAR void *context, FAR void *arg) vq->callback(vq); } } +} + +#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0 +/**************************************************************************** + * Name: virtio_pci_interrupt + ****************************************************************************/ + +static int virtio_pci_interrupt(int irq, FAR void *context, FAR void *arg) +{ + FAR struct virtio_pci_device_s *vpdev = arg; + + virtio_pci_vq_callback(vpdev); + return OK; +} + +/**************************************************************************** + * Name: virtio_pci_config_changed + ****************************************************************************/ + +static int virtio_pci_config_changed(int irq, FAR void *context, + FAR void *arg) +{ + /* TODO: not support config changed notification */ return OK; } +#else +/**************************************************************************** + * Name: virtio_pci_wdog + ****************************************************************************/ + +static void virtio_pci_wdog(wdparm_t arg) +{ + FAR struct virtio_pci_device_s *vpdev = + (FAR struct virtio_pci_device_s *)arg; + + virtio_pci_vq_callback(vpdev); + wd_start(&vpdev->wdog, VIRTIO_PCI_WORK_DELAY, virtio_pci_wdog, + (wdparm_t)vpdev); +} +#endif + /**************************************************************************** * Name: virtio_pci_probe ****************************************************************************/ @@ -154,16 +188,18 @@ static int virtio_pci_probe(FAR struct pci_device_s *dev) } } +#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0 + /* Irq init */ ret = pci_alloc_irq(vpdev->dev, vpdev->irq, VIRTIO_PCI_INT_NUM); if (ret != VIRTIO_PCI_INT_NUM) { - vrterr("Failed to allocate MSI %d\n", ret); + vrterr("Failed to allocate MSI, ret=%d\n", ret); goto err_with_enable; } - vrtinfo("Attaching MSI %d to %p, %d to %p\n", + vrtinfo("Interrupt mode: attaching MSI %d to %p, %d to %p\n", vpdev->irq[VIRTIO_PCI_INT_CFG], virtio_pci_config_changed, vpdev->irq[VIRTIO_PCI_INT_VQ], virtio_pci_interrupt); @@ -177,6 +213,9 @@ static int virtio_pci_probe(FAR struct pci_device_s *dev) irq_attach(vpdev->irq[VIRTIO_PCI_INT_CFG], virtio_pci_config_changed, vpdev); irq_attach(vpdev->irq[VIRTIO_PCI_INT_VQ], virtio_pci_interrupt, vpdev); +#else + vrtinfo("Polling mode\n"); +#endif virtio_set_status(vdev, VIRTIO_CONFIG_STATUS_RESET); virtio_set_status(vdev, VIRTIO_CONFIG_STATUS_ACK); @@ -191,10 +230,12 @@ static int virtio_pci_probe(FAR struct pci_device_s *dev) return ret; err_with_attach: +#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0 irq_detach(vpdev->irq[VIRTIO_PCI_INT_CFG]); irq_detach(vpdev->irq[VIRTIO_PCI_INT_VQ]); err_with_irq: pci_release_irq(vpdev->dev, vpdev->irq, VIRTIO_PCI_INT_NUM); +#endif err_with_enable: pci_clear_master(dev); pci_disable_device(dev); @@ -213,9 +254,11 @@ static void virtio_pci_remove(FAR struct pci_device_s *dev) virtio_unregister_device(&vpdev->vdev); +#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0 irq_detach(vpdev->irq[VIRTIO_PCI_INT_CFG]); irq_detach(vpdev->irq[VIRTIO_PCI_INT_VQ]); pci_release_irq(vpdev->dev, vpdev->irq, VIRTIO_PCI_INT_NUM); +#endif pci_clear_master(dev); pci_disable_device(dev); @@ -313,17 +356,10 @@ int virtio_pci_create_virtqueues(FAR struct virtio_device *vdev, vdev->vrings_info = kmm_zalloc(sizeof(struct virtio_vring_info) * nvqs); if (vdev->vrings_info == NULL) { - vrterr("alloc vrings info failed\n"); + vrterr("Alloc vrings info failed\n"); return -ENOMEM; } - ret = vpdev->ops->config_vector(vpdev); - if (ret < 0) - { - vrterr("read virtio pci config msix vector failed\n"); - return ret; - } - /* Alloc and init the virtqueue */ for (i = 0; i < nvqs; i++) @@ -335,10 +371,26 @@ int virtio_pci_create_virtqueues(FAR struct virtio_device *vdev, } } - /* Finally, enable the interrupt */ +#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0 + ret = vpdev->ops->config_vector(vpdev, true); + if (ret < 0) + { + vrterr("Config vector failed, vector=%u\n", ret); + goto err; + } up_enable_irq(vpdev->irq[VIRTIO_PCI_INT_CFG]); up_enable_irq(vpdev->irq[VIRTIO_PCI_INT_VQ]); +#else + ret = wd_start(&vpdev->wdog, VIRTIO_PCI_WORK_DELAY, virtio_pci_wdog, + (wdparm_t)vpdev); + if (ret < 0) + { + pcierr("Wd_start failed: %d\n", ret); + goto err; + } +#endif + return ret; err: @@ -357,10 +409,13 @@ void virtio_pci_delete_virtqueues(FAR struct virtio_device *vdev) FAR struct virtio_vring_info *vrinfo; unsigned int i; - /* Disable interrupt first */ - +#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0 up_disable_irq(vpdev->irq[VIRTIO_PCI_INT_CFG]); up_disable_irq(vpdev->irq[VIRTIO_PCI_INT_VQ]); + vpdev->ops->config_vector(vpdev, false); +#else + wd_cancel(&vpdev->wdog); +#endif /* Free the memory */ diff --git a/drivers/virtio/virtio-pci.h b/drivers/virtio/virtio-pci.h index 411638ba181..2608a21a930 100644 --- a/drivers/virtio/virtio-pci.h +++ b/drivers/virtio/virtio-pci.h @@ -31,6 +31,7 @@ #include #include +#include /**************************************************************************** * Pre-processor Definitions @@ -65,7 +66,8 @@ struct virtio_pci_ops_s { CODE uint16_t (*get_queue_len)(FAR struct virtio_pci_device_s *vpdev, int idx); - CODE int (*config_vector)(FAR struct virtio_pci_device_s *vpdev); + CODE int (*config_vector)(FAR struct virtio_pci_device_s *vpdev, + bool enable); CODE int (*create_virtqueue)(FAR struct virtio_pci_device_s *vpdev, FAR struct virtqueue *vq); CODE void (*delete_virtqueue)(FAR struct virtio_device *vdev, int index); @@ -80,7 +82,11 @@ struct virtio_pci_device_s struct metal_io_region shm_io; /* Share memory io region, * virtqueue use this io. */ +#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0 int irq[VIRTIO_PCI_INT_NUM]; +#else + struct wdog_s wdog; +#endif /* for modern */