提交 61b7f618 编写于 作者: J Jean-Philippe Brucker 提交者: Xie XiuQi

iommu/sva: Add a mm_exit callback for device drivers

hulk inclusion
category: feature
bugzilla: 14369
CVE: NA
-------------------

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: NJean-Philippe Brucker <jean-philippe.brucker@arm.com>
Signed-off-by: NFang Lijun <fanglijun3@huawei.com>
Reviewed-by: NHanjun Guo <guohanjun@huawei.com>
Reviewed-by: NZhen Lei <thunder.leizhen@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 59e55d73
...@@ -303,6 +303,7 @@ static void io_mm_detach_locked(struct iommu_bond *bond) ...@@ -303,6 +303,7 @@ static void io_mm_detach_locked(struct iommu_bond *bond)
* @dev: the device * @dev: the device
* @features: bitmask of features that need to be initialized * @features: bitmask of features that need to be initialized
* @max_pasid: max PASID value supported by the device * @max_pasid: max PASID value supported by the device
* @mm_exit: callback to notify the device driver of an mm exiting
* *
* Users of the bind()/unbind() API must call this function to initialize all * Users of the bind()/unbind() API must call this function to initialize all
* features required for SVA. * features required for SVA.
...@@ -313,13 +314,20 @@ static void io_mm_detach_locked(struct iommu_bond *bond) ...@@ -313,13 +314,20 @@ static void io_mm_detach_locked(struct iommu_bond *bond)
* description. Setting @max_pasid to a non-zero value smaller than this limit * description. Setting @max_pasid to a non-zero value smaller than this limit
* overrides it. * overrides it.
* *
* If the driver intends to share process address spaces, it should pass a valid
* @mm_exit handler. Otherwise @mm_exit can be NULL. 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 of bind().
*
* The device should not be performing any DMA while this function is running, * The device should not be performing any DMA while this function is running,
* otherwise the behavior is undefined. * otherwise the behavior is undefined.
* *
* Return 0 if initialization succeeded, or an error. * Return 0 if initialization succeeded, or an error.
*/ */
int iommu_sva_device_init(struct device *dev, unsigned long features, int iommu_sva_device_init(struct device *dev, unsigned long features,
unsigned int max_pasid) unsigned int max_pasid,
iommu_mm_exit_handler_t mm_exit)
{ {
int ret; int ret;
struct iommu_sva_param *param; struct iommu_sva_param *param;
...@@ -337,6 +345,7 @@ int iommu_sva_device_init(struct device *dev, unsigned long features, ...@@ -337,6 +345,7 @@ int iommu_sva_device_init(struct device *dev, unsigned long features,
param->features = features; param->features = features;
param->max_pasid = max_pasid; param->max_pasid = max_pasid;
param->mm_exit = mm_exit;
INIT_LIST_HEAD(&param->mm_list); INIT_LIST_HEAD(&param->mm_list);
/* /*
......
...@@ -60,6 +60,7 @@ struct iommu_fault_event; ...@@ -60,6 +60,7 @@ struct iommu_fault_event;
typedef int (*iommu_fault_handler_t)(struct iommu_domain *, typedef int (*iommu_fault_handler_t)(struct iommu_domain *,
struct device *, unsigned long, int, void *); struct device *, unsigned long, int, void *);
typedef int (*iommu_dev_fault_handler_t)(struct iommu_fault_event *, 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 { struct iommu_domain_geometry {
dma_addr_t aperture_start; /* First address that can be mapped */ dma_addr_t aperture_start; /* First address that can be mapped */
...@@ -231,6 +232,7 @@ struct iommu_sva_param { ...@@ -231,6 +232,7 @@ struct iommu_sva_param {
unsigned int min_pasid; unsigned int min_pasid;
unsigned int max_pasid; unsigned int max_pasid;
struct list_head mm_list; struct list_head mm_list;
iommu_mm_exit_handler_t mm_exit;
}; };
/** /**
...@@ -988,17 +990,20 @@ static inline int iommu_sva_unbind_device(struct device *dev, int pasid) ...@@ -988,17 +990,20 @@ static inline int iommu_sva_unbind_device(struct device *dev, int pasid)
#ifdef CONFIG_IOMMU_SVA #ifdef CONFIG_IOMMU_SVA
extern int iommu_sva_device_init(struct device *dev, unsigned long features, extern int iommu_sva_device_init(struct device *dev, unsigned long features,
unsigned int max_pasid); unsigned int max_pasid,
iommu_mm_exit_handler_t mm_exit);
extern int iommu_sva_device_shutdown(struct device *dev); extern int iommu_sva_device_shutdown(struct device *dev);
extern int __iommu_sva_bind_device(struct device *dev, struct mm_struct *mm, extern int __iommu_sva_bind_device(struct device *dev, struct mm_struct *mm,
int *pasid, unsigned long flags, int *pasid, unsigned long flags,
void *drvdata); void *drvdata);
extern int __iommu_sva_unbind_device(struct device *dev, int pasid); extern int __iommu_sva_unbind_device(struct device *dev, int pasid);
extern void __iommu_sva_unbind_dev_all(struct device *dev); extern void __iommu_sva_unbind_dev_all(struct device *dev);
#else /* CONFIG_IOMMU_SVA */ #else /* CONFIG_IOMMU_SVA */
static inline int iommu_sva_device_init(struct device *dev, static inline int iommu_sva_device_init(struct device *dev,
unsigned long features, unsigned long features,
unsigned int max_pasid) unsigned int max_pasid,
iommu_mm_exit_handler_t mm_exit)
{ {
return -ENODEV; return -ENODEV;
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册