diff options
Diffstat (limited to 'drivers/vfio/pci/vfio_pci_intrs.c')
-rw-r--r-- | drivers/vfio/pci/vfio_pci_intrs.c | 85 |
1 files changed, 49 insertions, 36 deletions
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c index 15ecfc9c5f6c..152b43822ef1 100644 --- a/drivers/vfio/pci/vfio_pci_intrs.c +++ b/drivers/vfio/pci/vfio_pci_intrs.c | |||
@@ -564,67 +564,80 @@ static int vfio_pci_set_msi_trigger(struct vfio_pci_device *vdev, | |||
564 | } | 564 | } |
565 | 565 | ||
566 | static int vfio_pci_set_ctx_trigger_single(struct eventfd_ctx **ctx, | 566 | static int vfio_pci_set_ctx_trigger_single(struct eventfd_ctx **ctx, |
567 | uint32_t flags, void *data) | 567 | unsigned int count, uint32_t flags, |
568 | void *data) | ||
568 | { | 569 | { |
569 | int32_t fd = *(int32_t *)data; | ||
570 | |||
571 | if (!(flags & VFIO_IRQ_SET_DATA_TYPE_MASK)) | ||
572 | return -EINVAL; | ||
573 | |||
574 | /* DATA_NONE/DATA_BOOL enables loopback testing */ | 570 | /* DATA_NONE/DATA_BOOL enables loopback testing */ |
575 | if (flags & VFIO_IRQ_SET_DATA_NONE) { | 571 | if (flags & VFIO_IRQ_SET_DATA_NONE) { |
576 | if (*ctx) | 572 | if (*ctx) { |
577 | eventfd_signal(*ctx, 1); | 573 | if (count) { |
578 | return 0; | 574 | eventfd_signal(*ctx, 1); |
575 | } else { | ||
576 | eventfd_ctx_put(*ctx); | ||
577 | *ctx = NULL; | ||
578 | } | ||
579 | return 0; | ||
580 | } | ||
579 | } else if (flags & VFIO_IRQ_SET_DATA_BOOL) { | 581 | } else if (flags & VFIO_IRQ_SET_DATA_BOOL) { |
580 | uint8_t trigger = *(uint8_t *)data; | 582 | uint8_t trigger; |
583 | |||
584 | if (!count) | ||
585 | return -EINVAL; | ||
586 | |||
587 | trigger = *(uint8_t *)data; | ||
581 | if (trigger && *ctx) | 588 | if (trigger && *ctx) |
582 | eventfd_signal(*ctx, 1); | 589 | eventfd_signal(*ctx, 1); |
583 | return 0; | ||
584 | } | ||
585 | 590 | ||
586 | /* Handle SET_DATA_EVENTFD */ | ||
587 | if (fd == -1) { | ||
588 | if (*ctx) | ||
589 | eventfd_ctx_put(*ctx); | ||
590 | *ctx = NULL; | ||
591 | return 0; | 591 | return 0; |
592 | } else if (fd >= 0) { | 592 | } else if (flags & VFIO_IRQ_SET_DATA_EVENTFD) { |
593 | struct eventfd_ctx *efdctx; | 593 | int32_t fd; |
594 | efdctx = eventfd_ctx_fdget(fd); | 594 | |
595 | if (IS_ERR(efdctx)) | 595 | if (!count) |
596 | return PTR_ERR(efdctx); | 596 | return -EINVAL; |
597 | if (*ctx) | 597 | |
598 | eventfd_ctx_put(*ctx); | 598 | fd = *(int32_t *)data; |
599 | *ctx = efdctx; | 599 | if (fd == -1) { |
600 | if (*ctx) | ||
601 | eventfd_ctx_put(*ctx); | ||
602 | *ctx = NULL; | ||
603 | } else if (fd >= 0) { | ||
604 | struct eventfd_ctx *efdctx; | ||
605 | |||
606 | efdctx = eventfd_ctx_fdget(fd); | ||
607 | if (IS_ERR(efdctx)) | ||
608 | return PTR_ERR(efdctx); | ||
609 | |||
610 | if (*ctx) | ||
611 | eventfd_ctx_put(*ctx); | ||
612 | |||
613 | *ctx = efdctx; | ||
614 | } | ||
600 | return 0; | 615 | return 0; |
601 | } else | 616 | } |
602 | return -EINVAL; | 617 | |
618 | return -EINVAL; | ||
603 | } | 619 | } |
604 | 620 | ||
605 | static int vfio_pci_set_err_trigger(struct vfio_pci_device *vdev, | 621 | static int vfio_pci_set_err_trigger(struct vfio_pci_device *vdev, |
606 | unsigned index, unsigned start, | 622 | unsigned index, unsigned start, |
607 | unsigned count, uint32_t flags, void *data) | 623 | unsigned count, uint32_t flags, void *data) |
608 | { | 624 | { |
609 | if (index != VFIO_PCI_ERR_IRQ_INDEX) | 625 | if (index != VFIO_PCI_ERR_IRQ_INDEX || start != 0 || count > 1) |
610 | return -EINVAL; | 626 | return -EINVAL; |
611 | 627 | ||
612 | /* | 628 | return vfio_pci_set_ctx_trigger_single(&vdev->err_trigger, |
613 | * We should sanitize start & count, but that wasn't caught | 629 | count, flags, data); |
614 | * originally, so this IRQ index must forever ignore them :-( | ||
615 | */ | ||
616 | |||
617 | return vfio_pci_set_ctx_trigger_single(&vdev->err_trigger, flags, data); | ||
618 | } | 630 | } |
619 | 631 | ||
620 | static int vfio_pci_set_req_trigger(struct vfio_pci_device *vdev, | 632 | static int vfio_pci_set_req_trigger(struct vfio_pci_device *vdev, |
621 | unsigned index, unsigned start, | 633 | unsigned index, unsigned start, |
622 | unsigned count, uint32_t flags, void *data) | 634 | unsigned count, uint32_t flags, void *data) |
623 | { | 635 | { |
624 | if (index != VFIO_PCI_REQ_IRQ_INDEX || start != 0 || count != 1) | 636 | if (index != VFIO_PCI_REQ_IRQ_INDEX || start != 0 || count > 1) |
625 | return -EINVAL; | 637 | return -EINVAL; |
626 | 638 | ||
627 | return vfio_pci_set_ctx_trigger_single(&vdev->req_trigger, flags, data); | 639 | return vfio_pci_set_ctx_trigger_single(&vdev->req_trigger, |
640 | count, flags, data); | ||
628 | } | 641 | } |
629 | 642 | ||
630 | int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, uint32_t flags, | 643 | int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, uint32_t flags, |