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@xxxxxxxxxx> --- include/linux/iommufd.h | 9 +++++++++ drivers/iommu/iommufd/driver.c | 37 ++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/include/linux/iommufd.h b/include/linux/iommufd.h index ac1f1897d290..c5909125775a 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 e5d7397c0a6c..2ab793f27f72 100644 --- a/drivers/iommu/iommufd/driver.c +++ b/drivers/iommu/iommufd/driver.c @@ -69,5 +69,42 @@ 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_virq_header *header; + struct iommufd_virq *virq; + int rc = 0; + + if (!viommu) + return -ENODEV; + if (WARN_ON_ONCE(!irq_len || !irq_ptr)) + return -EINVAL; + + down_read(&viommu->virqs_rwsem); + + virq = iommufd_viommu_find_virq(viommu, type); + if (!virq) { + rc = -EOPNOTSUPP; + goto out_unlock_virqs; + } + + header = kzalloc(sizeof(*header) + irq_len, GFP_KERNEL); + if (!header) { + rc = -ENOMEM; + goto out_unlock_virqs; + } + header->irq_data = (void *)header + sizeof(*header); + memcpy(header->irq_data, irq_ptr, irq_len); + header->irq_len = irq_len; + + iommufd_virq_handler(virq, header); +out_unlock_virqs: + 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"); -- 2.43.0