This allows IOMMU drivers to report to user space hypervisors IRQs/events that belong to a viommu.
Signed-off-by: Nicolin Chen nicolinc@nvidia.com --- drivers/iommu/iommufd/viommu_api.c | 40 ++++++++++++++++++++++++++++++ include/linux/iommufd.h | 8 ++++++ 2 files changed, 48 insertions(+)
diff --git a/drivers/iommu/iommufd/viommu_api.c b/drivers/iommu/iommufd/viommu_api.c index 82eb33e047cf..d075727a1b38 100644 --- a/drivers/iommu/iommufd/viommu_api.c +++ b/drivers/iommu/iommufd/viommu_api.c @@ -65,3 +65,43 @@ struct device *iommufd_vdev_id_to_dev(struct iommufd_vdev_id *vdev_id) return vdev_id->idev->dev; } EXPORT_SYMBOL_NS_GPL(iommufd_vdev_id_to_dev, IOMMUFD); + +/** + * IOMMU drivers can call this helper to report a per-VIOMMU virtual IRQ. Caller + * must ensure the lifecycle of the viommu object, likely by passing it from a + * vdev_id structure that was set via a set_vdev_id callback and by holding the + * same driver-level lock to protect the passed-in vdev_id from any race against + * a potential unset_vdev_id callback. + */ +void iommufd_viommu_report_irq(struct iommufd_viommu *viommu, unsigned int type, + void *irq_ptr, size_t irq_len) +{ + struct iommufd_event_virq *event_virq; + struct iommufd_viommu_irq *virq; + void *irq_data; + + might_sleep(); + + if (!viommu) + return; + + down_read(&viommu->virqs_rwsem); + + event_virq = iommufd_viommu_find_event_virq(viommu, type); + if (!event_virq) + goto out_unlock_vdev_ids; + + virq = kzalloc(sizeof(*virq) + irq_len, GFP_KERNEL); + if (!virq) + goto out_unlock_vdev_ids; + irq_data = (void *)virq + sizeof(*virq); + memcpy(irq_data, irq_ptr, irq_len); + + virq->event_virq = event_virq; + virq->irq_len = irq_len; + + iommufd_event_virq_handler(virq); +out_unlock_vdev_ids: + up_read(&viommu->virqs_rwsem); +} +EXPORT_SYMBOL_NS_GPL(iommufd_viommu_report_irq, IOMMUFD); diff --git a/include/linux/iommufd.h b/include/linux/iommufd.h index 88d6586a424f..346a6257ed0c 100644 --- a/include/linux/iommufd.h +++ b/include/linux/iommufd.h @@ -108,6 +108,8 @@ void iommufd_viommu_unlock_vdev_id(struct iommufd_viommu *viommu); struct device *iommufd_viommu_find_device(struct iommufd_viommu *viommu, u64 id); struct iommu_domain * iommufd_viommu_to_parent_domain(struct iommufd_viommu *viommu); +void iommufd_viommu_report_irq(struct iommufd_viommu *viommu, unsigned int type, + void *irq_ptr, size_t irq_len); #else /* !CONFIG_IOMMUFD */ static inline struct iommufd_ctx *iommufd_ctx_from_file(struct file *file) { @@ -173,5 +175,11 @@ iommufd_viommu_to_parent_domain(struct iommufd_viommu *viommu) { return NULL; } + +static inline void +iommufd_viommu_report_irq(struct iommufd_viommu *viommu, unsigned int type, + void *irq_ptr, size_t irq_len) +{ +} #endif /* CONFIG_IOMMUFD */ #endif