@@ -436,6 +436,7 @@ EXPORT_SYMBOL_GPL(iommu_sva_unbind_device_all);
* @features: bitmask of features that need to be initialized
* @min_pasid: min PASID value supported by the device
* @max_pasid: max PASID value supported by the device
+ * @mm_exit: callback for process address space release
*
* Users of the bind()/unbind() API must call this function to initialize all
* features required for SVA.
@@ -447,13 +448,19 @@ EXPORT_SYMBOL_GPL(iommu_sva_unbind_device_all);
* overrides it. Similarly, @min_pasid overrides the lower PASID limit supported
* by the IOMMU.
*
+ * @mm_exit is called when an address space bound to the device is about to be
+ * torn down by exit_mmap. After @mm_exit returns, the device must not issue any
+ * more transaction with the PASID given as argument. The handler gets an opaque
+ * pointer corresponding to the drvdata passed as argument to bind().
+ *
* The device should not be performing any DMA while this function is running,
* otherwise the behavior is undefined.
*
* Return 0 if initialization succeeded, or an error.
*/
int iommu_sva_init_device(struct device *dev, unsigned long features,
- unsigned int min_pasid, unsigned int max_pasid)
+ unsigned int min_pasid, unsigned int max_pasid,
+ iommu_mm_exit_handler_t mm_exit)
{
int ret;
struct iommu_sva_param *param;
@@ -472,6 +479,7 @@ int iommu_sva_init_device(struct device *dev, unsigned long features,
param->features = features;
param->min_pasid = min_pasid;
param->max_pasid = max_pasid;
+ param->mm_exit = mm_exit;
INIT_LIST_HEAD(¶m->mm_list);
mutex_lock(&dev->iommu_param->sva_lock);
@@ -60,6 +60,7 @@ struct iommu_fault_event;
typedef int (*iommu_fault_handler_t)(struct iommu_domain *,
struct device *, unsigned long, int, void *);
typedef int (*iommu_dev_fault_handler_t)(struct iommu_fault_event *, void *);
+typedef int (*iommu_mm_exit_handler_t)(struct device *dev, int pasid, void *);
struct iommu_domain_geometry {
dma_addr_t aperture_start; /* First address that can be mapped */
@@ -216,6 +217,7 @@ struct iommu_sva_param {
unsigned int min_pasid;
unsigned int max_pasid;
struct list_head mm_list;
+ iommu_mm_exit_handler_t mm_exit;
};
/**
@@ -967,7 +969,8 @@ static inline void iommu_debugfs_setup(void) {}
#ifdef CONFIG_IOMMU_SVA
extern int iommu_sva_init_device(struct device *dev, unsigned long features,
unsigned int min_pasid,
- unsigned int max_pasid);
+ unsigned int max_pasid,
+ iommu_mm_exit_handler_t mm_exit);
extern void iommu_sva_shutdown_device(struct device *dev);
extern int __iommu_sva_bind_device(struct device *dev, struct mm_struct *mm,
int *pasid, unsigned long flags,
@@ -978,7 +981,8 @@ extern void iommu_sva_unbind_device_all(struct device *dev);
static inline int iommu_sva_init_device(struct device *dev,
unsigned long features,
unsigned int min_pasid,
- unsigned int max_pasid)
+ unsigned int max_pasid,
+ iommu_mm_exit_handler_t mm_exit)
{
return -ENODEV;
}
When an mm exits, devices that were bound to it must stop performing DMA on its PASID. Let device drivers register a callback to be notified on mm exit. Add the callback to the sva_param structure attached to struct device. Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com> --- drivers/iommu/iommu-sva.c | 10 +++++++++- include/linux/iommu.h | 8 ++++++-- 2 files changed, 15 insertions(+), 3 deletions(-)