From: Jean-Philippe Brucker <jean-philippe.brucker@xxxxxxx> When enabling SVA, register the fault handler. Device driver will register an I/O page fault queue before or after calling iommu_sva_enable. The fault queue must be flushed before any io_mm is freed, to make sure that its PASID isn't used in any fault queue, and can be reallocated. Add iopf_queue_flush() calls in a few strategic locations. Signed-off-by: Jean-Philippe Brucker <jean-philippe@xxxxxxxxxx> --- drivers/iommu/Kconfig | 1 + drivers/iommu/iommu-sva.c | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig index e4a42e1708b4..211684e785ea 100644 --- a/drivers/iommu/Kconfig +++ b/drivers/iommu/Kconfig @@ -106,6 +106,7 @@ config IOMMU_DMA config IOMMU_SVA bool select IOASID + select IOMMU_PAGE_FAULT select IOMMU_API select MMU_NOTIFIER diff --git a/drivers/iommu/iommu-sva.c b/drivers/iommu/iommu-sva.c index bfd0c477f290..494ca0824e4b 100644 --- a/drivers/iommu/iommu-sva.c +++ b/drivers/iommu/iommu-sva.c @@ -366,6 +366,8 @@ static void io_mm_release(struct mmu_notifier *mn, struct mm_struct *mm) dev_WARN(dev, "possible leak of PASID %u", io_mm->pasid); + iopf_queue_flush_dev(dev, io_mm->pasid); + /* unbind() frees the bond, we just detach it */ io_mm_detach_locked(bond); } @@ -442,11 +444,20 @@ static void iommu_sva_unbind_locked(struct iommu_bond *bond) void iommu_sva_unbind_generic(struct iommu_sva *handle) { + int pasid; struct iommu_param *param = handle->dev->iommu_param; if (WARN_ON(!param)) return; + /* + * Caller stopped the device from issuing PASIDs, now make sure they are + * out of the fault queue. + */ + pasid = iommu_sva_get_pasid_generic(handle); + if (pasid != IOMMU_PASID_INVALID) + iopf_queue_flush_dev(handle->dev, pasid); + mutex_lock(¶m->sva_lock); mutex_lock(&iommu_sva_lock); iommu_sva_unbind_locked(to_iommu_bond(handle)); @@ -484,6 +495,10 @@ int iommu_sva_enable(struct device *dev, struct iommu_sva_param *sva_param) goto err_unlock; } + ret = iommu_register_device_fault_handler(dev, iommu_queue_iopf, dev); + if (ret) + goto err_unlock; + dev->iommu_param->sva_param = new_param; mutex_unlock(¶m->sva_lock); return 0; @@ -521,6 +536,7 @@ int iommu_sva_disable(struct device *dev) goto out_unlock; } + iommu_unregister_device_fault_handler(dev); kfree(param->sva_param); param->sva_param = NULL; out_unlock: -- 2.25.0