mirror of
https://github.com/apache/nuttx.git
synced 2026-08-01 20:28:58 +00:00
virtio/virtio-pci: add PCI INTX interrupt fallback support
Fall back to INTX interrupt mode when MSI/MSI-X is not supported or MSI-X IRQ connection fails. This improves compatibility with more virtio-pci devices. Signed-off-by: Bowen Wang <wangbowen6@xiaomi.com>
This commit is contained in:
parent
63c147bfa4
commit
4f591e19db
4 changed files with 78 additions and 20 deletions
|
|
@ -204,6 +204,11 @@ virtio_pci_legacy_create_virtqueue(FAR struct virtio_pci_device_s *vpdev,
|
|||
VIRTIO_PCI_QUEUE_ADDR_SHIFT);
|
||||
|
||||
#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0
|
||||
if (vpdev->intx)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
pci_write_io_word(vpdev->dev,
|
||||
(uintptr_t)(vpdev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR),
|
||||
0);
|
||||
|
|
@ -241,14 +246,17 @@ void virtio_pci_legacy_delete_virtqueue(FAR struct virtio_device *vdev,
|
|||
index);
|
||||
|
||||
#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0
|
||||
pci_write_io_word(vpdev->dev,
|
||||
(uintptr_t)(vpdev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR),
|
||||
VIRTIO_PCI_MSI_NO_VECTOR);
|
||||
if (!vpdev->intx)
|
||||
{
|
||||
pci_write_io_word(vpdev->dev,
|
||||
(uintptr_t)(vpdev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR),
|
||||
VIRTIO_PCI_MSI_NO_VECTOR);
|
||||
|
||||
/* Flush the write out to device */
|
||||
/* Flush the write out to device */
|
||||
|
||||
pci_read_io_byte(vpdev->dev,
|
||||
(uintptr_t)(vpdev->ioaddr + VIRTIO_PCI_ISR), &isr);
|
||||
pci_read_io_byte(vpdev->dev,
|
||||
(uintptr_t)(vpdev->ioaddr + VIRTIO_PCI_ISR), &isr);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Select and deactivate the queue */
|
||||
|
|
@ -411,6 +419,7 @@ virtio_pci_legacy_init_device(FAR struct virtio_pci_device_s *vpdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
vpdev->isr = vpdev->ioaddr + VIRTIO_PCI_ISR;
|
||||
vdev->id.vendor = dev->subsystem_vendor;
|
||||
vdev->id.device = dev->subsystem_device;
|
||||
|
||||
|
|
|
|||
|
|
@ -340,13 +340,16 @@ virtio_pci_modern_create_virtqueue(FAR struct virtio_pci_device_s *vpdev,
|
|||
up_addrenv_va_to_pa(vq->vq_ring.used));
|
||||
|
||||
#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0
|
||||
pci_write_io_word(vpdev->dev, (uintptr_t)&cfg->queue_msix_vector, 0);
|
||||
pci_read_io_word(vpdev->dev, (uintptr_t)&cfg->queue_msix_vector,
|
||||
&msix_vector);
|
||||
if (msix_vector == VIRTIO_PCI_MSI_NO_VECTOR)
|
||||
if (!vpdev->intx)
|
||||
{
|
||||
vrterr("Msix_vector is no vector\n");
|
||||
return -EBUSY;
|
||||
pci_write_io_word(vpdev->dev, (uintptr_t)&cfg->queue_msix_vector, 0);
|
||||
pci_read_io_word(vpdev->dev, (uintptr_t)&cfg->queue_msix_vector,
|
||||
&msix_vector);
|
||||
if (msix_vector == VIRTIO_PCI_MSI_NO_VECTOR)
|
||||
{
|
||||
vrterr("Msix_vector is no vector\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
@ -383,8 +386,11 @@ void virtio_pci_modern_delete_virtqueue(FAR struct virtio_device *vdev,
|
|||
pci_write_io_word(vpdev->dev, (uintptr_t)&cfg->queue_select, index);
|
||||
|
||||
#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0
|
||||
pci_write_io_word(vpdev->dev, (uintptr_t)&cfg->queue_msix_vector,
|
||||
VIRTIO_PCI_MSI_NO_VECTOR);
|
||||
if (!vpdev->intx)
|
||||
{
|
||||
pci_write_io_word(vpdev->dev, (uintptr_t)&cfg->queue_msix_vector,
|
||||
VIRTIO_PCI_MSI_NO_VECTOR);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -598,6 +604,7 @@ static int virtio_pci_init_device(FAR struct virtio_pci_device_s *vpdev)
|
|||
uint8_t common;
|
||||
uint8_t notify;
|
||||
uint8_t device;
|
||||
uint8_t isr;
|
||||
|
||||
if (dev->device < 0x1040)
|
||||
{
|
||||
|
|
@ -626,11 +633,19 @@ static int virtio_pci_init_device(FAR struct virtio_pci_device_s *vpdev)
|
|||
return -ENODEV;
|
||||
}
|
||||
|
||||
isr = virtio_pci_find_capability(dev, VIRTIO_PCI_CAP_ISR_CFG,
|
||||
PCI_RESOURCE_MEM);
|
||||
if (isr == 0)
|
||||
{
|
||||
vrterr("Missing isr capabilities\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
notify = virtio_pci_find_capability(dev, VIRTIO_PCI_CAP_NOTIFY_CFG,
|
||||
PCI_RESOURCE_MEM);
|
||||
if (notify == 0)
|
||||
{
|
||||
vrterr("Missing capabilities %d %d\n", common, notify);
|
||||
vrterr("Missing capabilities %d %d %d\n", isr, common, notify);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
@ -646,6 +661,12 @@ static int virtio_pci_init_device(FAR struct virtio_pci_device_s *vpdev)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
vpdev->isr = virtio_pci_map_capability(vpdev, isr, NULL);
|
||||
if (vpdev->isr == NULL)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pci_read_config_dword(dev, notify +
|
||||
offsetof(struct virtio_pci_notify_cap_s,
|
||||
notify_off_multiplier),
|
||||
|
|
|
|||
|
|
@ -115,6 +115,16 @@ static void virtio_pci_vq_callback(FAR struct virtio_pci_device_s *vpdev)
|
|||
static int virtio_pci_interrupt(int irq, FAR void *context, FAR void *arg)
|
||||
{
|
||||
FAR struct virtio_pci_device_s *vpdev = arg;
|
||||
uint8_t isr;
|
||||
|
||||
if (vpdev->intx)
|
||||
{
|
||||
pci_read_io_byte(vpdev->dev, (uintptr_t)vpdev->isr, &isr);
|
||||
if (isr == 0)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
virtio_pci_vq_callback(vpdev);
|
||||
return OK;
|
||||
|
|
@ -227,8 +237,17 @@ static int virtio_pci_probe(FAR struct pci_device_s *dev)
|
|||
ret = pci_connect_irq(vpdev->dev, &vpdev->irq, 1);
|
||||
if (ret < 0)
|
||||
{
|
||||
vrterr("Failed to connect MSI %d\n", ret);
|
||||
goto err_with_irq;
|
||||
vrterr("Failed to connect MSI %d, try legacy irq mode\n", ret);
|
||||
pci_release_irq(vpdev->dev, &vpdev->irq, 1);
|
||||
ret = pci_get_irq(vpdev->dev);
|
||||
if (ret < 0)
|
||||
{
|
||||
vrterr("Failed to get legacy irq %d\n", ret);
|
||||
goto err_with_enable;
|
||||
}
|
||||
|
||||
vpdev->irq = ret;
|
||||
vpdev->intx = true;
|
||||
}
|
||||
|
||||
irq_attach(vpdev->irq, virtio_pci_interrupt, vpdev);
|
||||
|
|
@ -251,8 +270,11 @@ static int virtio_pci_probe(FAR struct pci_device_s *dev)
|
|||
err_with_attach:
|
||||
#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0
|
||||
irq_detach(vpdev->irq);
|
||||
err_with_irq:
|
||||
pci_release_irq(vpdev->dev, &vpdev->irq, 1);
|
||||
if (!vpdev->intx)
|
||||
{
|
||||
pci_release_irq(vpdev->dev, &vpdev->irq, 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
err_with_enable:
|
||||
pci_clear_master(dev);
|
||||
|
|
@ -274,7 +296,10 @@ static void virtio_pci_remove(FAR struct pci_device_s *dev)
|
|||
|
||||
#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0
|
||||
irq_detach(vpdev->irq);
|
||||
pci_release_irq(vpdev->dev, &vpdev->irq, 1);
|
||||
if (!vpdev->intx)
|
||||
{
|
||||
pci_release_irq(vpdev->dev, &vpdev->irq, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
pci_clear_master(dev);
|
||||
|
|
|
|||
|
|
@ -81,10 +81,13 @@ struct virtio_pci_device_s
|
|||
*/
|
||||
#if CONFIG_DRIVERS_VIRTIO_PCI_POLLING_PERIOD <= 0
|
||||
int irq;
|
||||
bool intx; /* INTX irq mode */
|
||||
#else
|
||||
struct wdog_s wdog;
|
||||
#endif
|
||||
|
||||
FAR void *isr;
|
||||
|
||||
/* for modern */
|
||||
|
||||
FAR void *common;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue