MSIX spec requires that device can be operated with all vectors masked, by polling pending bits. Add APIs to recall an msix notification, and make polling mode possible in virtio-pci by clearing the pending bits and setting ISR appropriately on ISR read. Signed-off-by: Michael S. Tsirkin <mst@xxxxxxxxxx> --- hw/msix.c | 26 ++++++++++++++++++++++++++ hw/msix.h | 3 +++ hw/virtio-pci.c | 11 ++++++++++- 3 files changed, 39 insertions(+), 1 deletions(-) diff --git a/hw/msix.c b/hw/msix.c index 63b41b9..fe967c9 100644 --- a/hw/msix.c +++ b/hw/msix.c @@ -349,6 +349,32 @@ void msix_notify(PCIDevice *dev, unsigned vector) stl_le_phys(address, data); } +/* Recall outstanding MSI-X notifications for a vector, if possible. + * Return true if any were outstanding. */ +bool msix_recall(PCIDevice *dev, unsigned vector) +{ + bool ret; + if (vector >= dev->msix_entries_nr) + return false; + ret = msix_is_pending(dev, vector); + msix_clr_pending(dev, vector); + return ret; +} + +/* Recall outstanding MSI-X notifications for all vectors, if possible. + * Return true if any were outstanding. */ +bool msix_recall_all(PCIDevice *dev) +{ + uint8_t ret = 0; + uint8_t *b; + for (b = dev->msix_table_page + MSIX_PAGE_PENDING; + b <= msix_pending_byte(dev, dev->msix_entries_nr - 1); ++b) { + ret |= *b; + *b = 0; + } + return ret; +} + void msix_reset(PCIDevice *dev) { if (!(dev->cap_present & QEMU_PCI_CAP_MSIX)) diff --git a/hw/msix.h b/hw/msix.h index 7e04336..86a92b1 100644 --- a/hw/msix.h +++ b/hw/msix.h @@ -27,6 +27,9 @@ void msix_unuse_all_vectors(PCIDevice *dev); void msix_notify(PCIDevice *dev, unsigned vector); +bool msix_recall(PCIDevice *dev, unsigned vector); +bool msix_recall_all(PCIDevice *dev); + void msix_reset(PCIDevice *dev); extern int msix_supported; diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c index df27c19..cab7dde 100644 --- a/hw/virtio-pci.c +++ b/hw/virtio-pci.c @@ -393,7 +393,16 @@ static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr) /* reading from the ISR also clears it. */ ret = vdev->isr; vdev->isr = 0; - qemu_set_irq(proxy->pci_dev.irq[0], 0); + if (msix_enabled(&proxy->pci_dev)) { + if (msix_recall(&proxy->pci_dev, vdev->config_vector)) { + ret |= VIRTIO_ISR_CONFIG; + } + if (msix_recall_all(&proxy->pci_dev)) { + ret |= VIRTIO_ISR_VQ; + } + } else { + qemu_set_irq(proxy->pci_dev.irq[0], 0); + } break; case VIRTIO_MSI_CONFIG_VECTOR: ret = vdev->config_vector; -- 1.7.5.53.gc233e _______________________________________________ Virtualization mailing list Virtualization@xxxxxxxxxxxxxxxxxxxxxxxxxx https://lists.linuxfoundation.org/mailman/listinfo/virtualization