aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/vfio/pci/vfio_pci.c44
-rw-r--r--drivers/vfio/pci/vfio_pci_intrs.c64
-rw-r--r--drivers/vfio/pci/vfio_pci_private.h1
-rw-r--r--include/uapi/linux/vfio.h1
4 files changed, 109 insertions, 1 deletions
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 8189cb6a86af..acfcb1ae77bc 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -201,7 +201,9 @@ static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)
201 201
202 return (flags & PCI_MSIX_FLAGS_QSIZE) + 1; 202 return (flags & PCI_MSIX_FLAGS_QSIZE) + 1;
203 } 203 }
204 } 204 } else if (irq_type == VFIO_PCI_ERR_IRQ_INDEX)
205 if (pci_is_pcie(vdev->pdev))
206 return 1;
205 207
206 return 0; 208 return 0;
207} 209}
@@ -317,6 +319,17 @@ static long vfio_pci_ioctl(void *device_data,
317 if (info.argsz < minsz || info.index >= VFIO_PCI_NUM_IRQS) 319 if (info.argsz < minsz || info.index >= VFIO_PCI_NUM_IRQS)
318 return -EINVAL; 320 return -EINVAL;
319 321
322 switch (info.index) {
323 case VFIO_PCI_INTX_IRQ_INDEX ... VFIO_PCI_MSIX_IRQ_INDEX:
324 break;
325 case VFIO_PCI_ERR_IRQ_INDEX:
326 if (pci_is_pcie(vdev->pdev))
327 break;
328 /* pass thru to return error */
329 default:
330 return -EINVAL;
331 }
332
320 info.flags = VFIO_IRQ_INFO_EVENTFD; 333 info.flags = VFIO_IRQ_INFO_EVENTFD;
321 334
322 info.count = vfio_pci_get_irq_count(vdev, info.index); 335 info.count = vfio_pci_get_irq_count(vdev, info.index);
@@ -551,11 +564,40 @@ static void vfio_pci_remove(struct pci_dev *pdev)
551 kfree(vdev); 564 kfree(vdev);
552} 565}
553 566
567static pci_ers_result_t vfio_pci_aer_err_detected(struct pci_dev *pdev,
568 pci_channel_state_t state)
569{
570 struct vfio_pci_device *vdev;
571 struct vfio_device *device;
572
573 device = vfio_device_get_from_dev(&pdev->dev);
574 if (device == NULL)
575 return PCI_ERS_RESULT_DISCONNECT;
576
577 vdev = vfio_device_data(device);
578 if (vdev == NULL) {
579 vfio_device_put(device);
580 return PCI_ERS_RESULT_DISCONNECT;
581 }
582
583 if (vdev->err_trigger)
584 eventfd_signal(vdev->err_trigger, 1);
585
586 vfio_device_put(device);
587
588 return PCI_ERS_RESULT_CAN_RECOVER;
589}
590
591static struct pci_error_handlers vfio_err_handlers = {
592 .error_detected = vfio_pci_aer_err_detected,
593};
594
554static struct pci_driver vfio_pci_driver = { 595static struct pci_driver vfio_pci_driver = {
555 .name = "vfio-pci", 596 .name = "vfio-pci",
556 .id_table = NULL, /* only dynamic ids */ 597 .id_table = NULL, /* only dynamic ids */
557 .probe = vfio_pci_probe, 598 .probe = vfio_pci_probe,
558 .remove = vfio_pci_remove, 599 .remove = vfio_pci_remove,
600 .err_handler = &vfio_err_handlers,
559}; 601};
560 602
561static void __exit vfio_pci_cleanup(void) 603static void __exit vfio_pci_cleanup(void)
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
index 3639371fa697..b84bf2210a91 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -745,6 +745,63 @@ static int vfio_pci_set_msi_trigger(struct vfio_pci_device *vdev,
745 return 0; 745 return 0;
746} 746}
747 747
748static int vfio_pci_set_err_trigger(struct vfio_pci_device *vdev,
749 unsigned index, unsigned start,
750 unsigned count, uint32_t flags, void *data)
751{
752 int32_t fd = *(int32_t *)data;
753 struct pci_dev *pdev = vdev->pdev;
754
755 if ((index != VFIO_PCI_ERR_IRQ_INDEX) ||
756 !(flags & VFIO_IRQ_SET_DATA_TYPE_MASK))
757 return -EINVAL;
758
759 /*
760 * device_lock synchronizes setting and checking of
761 * err_trigger. The vfio_pci_aer_err_detected() is also
762 * called with device_lock held.
763 */
764
765 /* DATA_NONE/DATA_BOOL enables loopback testing */
766
767 if (flags & VFIO_IRQ_SET_DATA_NONE) {
768 device_lock(&pdev->dev);
769 if (vdev->err_trigger)
770 eventfd_signal(vdev->err_trigger, 1);
771 device_unlock(&pdev->dev);
772 return 0;
773 } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
774 uint8_t trigger = *(uint8_t *)data;
775 device_lock(&pdev->dev);
776 if (trigger && vdev->err_trigger)
777 eventfd_signal(vdev->err_trigger, 1);
778 device_unlock(&pdev->dev);
779 return 0;
780 }
781
782 /* Handle SET_DATA_EVENTFD */
783
784 if (fd == -1) {
785 device_lock(&pdev->dev);
786 if (vdev->err_trigger)
787 eventfd_ctx_put(vdev->err_trigger);
788 vdev->err_trigger = NULL;
789 device_unlock(&pdev->dev);
790 return 0;
791 } else if (fd >= 0) {
792 struct eventfd_ctx *efdctx;
793 efdctx = eventfd_ctx_fdget(fd);
794 if (IS_ERR(efdctx))
795 return PTR_ERR(efdctx);
796 device_lock(&pdev->dev);
797 if (vdev->err_trigger)
798 eventfd_ctx_put(vdev->err_trigger);
799 vdev->err_trigger = efdctx;
800 device_unlock(&pdev->dev);
801 return 0;
802 } else
803 return -EINVAL;
804}
748int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, uint32_t flags, 805int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, uint32_t flags,
749 unsigned index, unsigned start, unsigned count, 806 unsigned index, unsigned start, unsigned count,
750 void *data) 807 void *data)
@@ -779,6 +836,13 @@ int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, uint32_t flags,
779 break; 836 break;
780 } 837 }
781 break; 838 break;
839 case VFIO_PCI_ERR_IRQ_INDEX:
840 switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
841 case VFIO_IRQ_SET_ACTION_TRIGGER:
842 if (pci_is_pcie(vdev->pdev))
843 func = vfio_pci_set_err_trigger;
844 break;
845 }
782 } 846 }
783 847
784 if (!func) 848 if (!func)
diff --git a/drivers/vfio/pci/vfio_pci_private.h b/drivers/vfio/pci/vfio_pci_private.h
index d7e55d03f49e..9c6d5d0f3b02 100644
--- a/drivers/vfio/pci/vfio_pci_private.h
+++ b/drivers/vfio/pci/vfio_pci_private.h
@@ -56,6 +56,7 @@ struct vfio_pci_device {
56 bool has_vga; 56 bool has_vga;
57 struct pci_saved_state *pci_saved_state; 57 struct pci_saved_state *pci_saved_state;
58 atomic_t refcnt; 58 atomic_t refcnt;
59 struct eventfd_ctx *err_trigger;
59}; 60};
60 61
61#define is_intx(vdev) (vdev->irq_type == VFIO_PCI_INTX_IRQ_INDEX) 62#define is_intx(vdev) (vdev->irq_type == VFIO_PCI_INTX_IRQ_INDEX)
diff --git a/include/uapi/linux/vfio.h b/include/uapi/linux/vfio.h
index 4f41f309911e..284ff2436829 100644
--- a/include/uapi/linux/vfio.h
+++ b/include/uapi/linux/vfio.h
@@ -319,6 +319,7 @@ enum {
319 VFIO_PCI_INTX_IRQ_INDEX, 319 VFIO_PCI_INTX_IRQ_INDEX,
320 VFIO_PCI_MSI_IRQ_INDEX, 320 VFIO_PCI_MSI_IRQ_INDEX,
321 VFIO_PCI_MSIX_IRQ_INDEX, 321 VFIO_PCI_MSIX_IRQ_INDEX,
322 VFIO_PCI_ERR_IRQ_INDEX,
322 VFIO_PCI_NUM_IRQS 323 VFIO_PCI_NUM_IRQS
323}; 324};
324 325