Similar to iommu_report_device_fault, this allows IOMMU drivers to report, from threaded IRQ handlers to user space hypervisors, IRQs or events that belong to a vIOMMU.
Signed-off-by: Nicolin Chen nicolinc@nvidia.com --- include/linux/iommufd.h | 9 ++++++++ drivers/iommu/iommufd/driver.c | 41 ++++++++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+)
diff --git a/include/linux/iommufd.h b/include/linux/iommufd.h index 1f5376476cfa..2ce78edec4e9 100644 --- a/include/linux/iommufd.h +++ b/include/linux/iommufd.h @@ -192,6 +192,8 @@ struct device *iommufd_viommu_find_dev(struct iommufd_viommu *viommu, unsigned long vdev_id); unsigned long iommufd_viommu_get_vdev_id(struct iommufd_viommu *viommu, struct device *dev); +int iommufd_viommu_report_irq(struct iommufd_viommu *viommu, unsigned int type, + void *irq_ptr, size_t irq_len); #else /* !CONFIG_IOMMUFD_DRIVER_CORE */ static inline struct iommufd_object * _iommufd_object_alloc(struct iommufd_ctx *ictx, size_t size, @@ -211,6 +213,13 @@ iommufd_viommu_get_vdev_id(struct iommufd_viommu *viommu, struct device *dev) { return 0; } + +static inline int iommufd_viommu_report_irq(struct iommufd_viommu *viommu, + unsigned int type, void *irq_ptr, + size_t irq_len) +{ + return -EOPNOTSUPP; +} #endif /* CONFIG_IOMMUFD_DRIVER_CORE */
/* diff --git a/drivers/iommu/iommufd/driver.c b/drivers/iommu/iommufd/driver.c index 817e430a11bc..339baa270d1e 100644 --- a/drivers/iommu/iommufd/driver.c +++ b/drivers/iommu/iommufd/driver.c @@ -67,5 +67,46 @@ unsigned long iommufd_viommu_get_vdev_id(struct iommufd_viommu *viommu, } EXPORT_SYMBOL_NS_GPL(iommufd_viommu_get_vdev_id, IOMMUFD);
+/* Typically called in driver's threaded IRQ handler */ +int iommufd_viommu_report_irq(struct iommufd_viommu *viommu, unsigned int type, + void *irq_ptr, size_t irq_len) +{ + struct iommufd_eventq_virq *eventq_virq; + struct iommufd_virq *virq; + int rc = 0; + + might_sleep(); + + if (!viommu) + return -ENODEV; + if (WARN_ON_ONCE(!irq_len || !irq_ptr)) + return -EINVAL; + + down_read(&viommu->virqs_rwsem); + + eventq_virq = iommufd_viommu_find_eventq_virq(viommu, type); + if (!eventq_virq) { + rc = -EOPNOTSUPP; + goto out_unlock_vdev_ids; + } + + virq = kzalloc(sizeof(*virq) + irq_len, GFP_KERNEL); + if (!virq) { + rc = -ENOMEM; + goto out_unlock_vdev_ids; + } + virq->irq_data = (void *)virq + sizeof(*virq); + memcpy(virq->irq_data, irq_ptr, irq_len); + + virq->eventq_virq = eventq_virq; + virq->irq_len = irq_len; + + iommufd_eventq_virq_handler(virq); +out_unlock_vdev_ids: + up_read(&viommu->virqs_rwsem); + return rc; +} +EXPORT_SYMBOL_NS_GPL(iommufd_viommu_report_irq, IOMMUFD); + MODULE_DESCRIPTION("iommufd code shared with builtin modules"); MODULE_LICENSE("GPL");