Skip to content

Commit be51b1d

Browse files
LuBaolujoergroedel
authored andcommitted
iommu/sva: Refactoring iommu_sva_bind/unbind_device()
The existing iommu SVA interfaces are implemented by calling the SVA specific iommu ops provided by the IOMMU drivers. There's no need for any SVA specific ops in iommu_ops vector anymore as we can achieve this through the generic attach/detach_dev_pasid domain ops. This refactors the IOMMU SVA interfaces implementation by using the iommu_attach/detach_device_pasid interfaces and align them with the concept of the SVA iommu domain. Put the new SVA code in the SVA related file in order to make it self-contained. Signed-off-by: Lu Baolu <[email protected]> Reviewed-by: Jean-Philippe Brucker <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Reviewed-by: Jason Gunthorpe <[email protected]> Tested-by: Zhangfei Gao <[email protected]> Tested-by: Tony Zhu <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Joerg Roedel <[email protected]>
1 parent 386fa64 commit be51b1d

File tree

3 files changed

+134
-111
lines changed

3 files changed

+134
-111
lines changed

drivers/iommu/iommu-sva-lib.c

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
#include <linux/mutex.h>
66
#include <linux/sched/mm.h>
7+
#include <linux/iommu.h>
78

89
#include "iommu-sva-lib.h"
910

@@ -69,3 +70,113 @@ struct mm_struct *iommu_sva_find(ioasid_t pasid)
6970
return ioasid_find(&iommu_sva_pasid, pasid, __mmget_not_zero);
7071
}
7172
EXPORT_SYMBOL_GPL(iommu_sva_find);
73+
74+
/**
75+
* iommu_sva_bind_device() - Bind a process address space to a device
76+
* @dev: the device
77+
* @mm: the mm to bind, caller must hold a reference to mm_users
78+
*
79+
* Create a bond between device and address space, allowing the device to
80+
* access the mm using the PASID returned by iommu_sva_get_pasid(). If a
81+
* bond already exists between @device and @mm, an additional internal
82+
* reference is taken. Caller must call iommu_sva_unbind_device()
83+
* to release each reference.
84+
*
85+
* iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) must be called first, to
86+
* initialize the required SVA features.
87+
*
88+
* On error, returns an ERR_PTR value.
89+
*/
90+
struct iommu_sva *iommu_sva_bind_device(struct device *dev, struct mm_struct *mm)
91+
{
92+
struct iommu_domain *domain;
93+
struct iommu_sva *handle;
94+
ioasid_t max_pasids;
95+
int ret;
96+
97+
max_pasids = dev->iommu->max_pasids;
98+
if (!max_pasids)
99+
return ERR_PTR(-EOPNOTSUPP);
100+
101+
/* Allocate mm->pasid if necessary. */
102+
ret = iommu_sva_alloc_pasid(mm, 1, max_pasids - 1);
103+
if (ret)
104+
return ERR_PTR(ret);
105+
106+
handle = kzalloc(sizeof(*handle), GFP_KERNEL);
107+
if (!handle)
108+
return ERR_PTR(-ENOMEM);
109+
110+
mutex_lock(&iommu_sva_lock);
111+
/* Search for an existing domain. */
112+
domain = iommu_get_domain_for_dev_pasid(dev, mm->pasid,
113+
IOMMU_DOMAIN_SVA);
114+
if (IS_ERR(domain)) {
115+
ret = PTR_ERR(domain);
116+
goto out_unlock;
117+
}
118+
119+
if (domain) {
120+
domain->users++;
121+
goto out;
122+
}
123+
124+
/* Allocate a new domain and set it on device pasid. */
125+
domain = iommu_sva_domain_alloc(dev, mm);
126+
if (!domain) {
127+
ret = -ENOMEM;
128+
goto out_unlock;
129+
}
130+
131+
ret = iommu_attach_device_pasid(domain, dev, mm->pasid);
132+
if (ret)
133+
goto out_free_domain;
134+
domain->users = 1;
135+
out:
136+
mutex_unlock(&iommu_sva_lock);
137+
handle->dev = dev;
138+
handle->domain = domain;
139+
140+
return handle;
141+
142+
out_free_domain:
143+
iommu_domain_free(domain);
144+
out_unlock:
145+
mutex_unlock(&iommu_sva_lock);
146+
kfree(handle);
147+
148+
return ERR_PTR(ret);
149+
}
150+
EXPORT_SYMBOL_GPL(iommu_sva_bind_device);
151+
152+
/**
153+
* iommu_sva_unbind_device() - Remove a bond created with iommu_sva_bind_device
154+
* @handle: the handle returned by iommu_sva_bind_device()
155+
*
156+
* Put reference to a bond between device and address space. The device should
157+
* not be issuing any more transaction for this PASID. All outstanding page
158+
* requests for this PASID must have been flushed to the IOMMU.
159+
*/
160+
void iommu_sva_unbind_device(struct iommu_sva *handle)
161+
{
162+
struct iommu_domain *domain = handle->domain;
163+
ioasid_t pasid = domain->mm->pasid;
164+
struct device *dev = handle->dev;
165+
166+
mutex_lock(&iommu_sva_lock);
167+
if (--domain->users == 0) {
168+
iommu_detach_device_pasid(domain, dev, pasid);
169+
iommu_domain_free(domain);
170+
}
171+
mutex_unlock(&iommu_sva_lock);
172+
kfree(handle);
173+
}
174+
EXPORT_SYMBOL_GPL(iommu_sva_unbind_device);
175+
176+
u32 iommu_sva_get_pasid(struct iommu_sva *handle)
177+
{
178+
struct iommu_domain *domain = handle->domain;
179+
180+
return domain->mm->pasid;
181+
}
182+
EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);

drivers/iommu/iommu.c

Lines changed: 0 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -2751,97 +2751,6 @@ int iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features feat)
27512751
}
27522752
EXPORT_SYMBOL_GPL(iommu_dev_disable_feature);
27532753

2754-
/**
2755-
* iommu_sva_bind_device() - Bind a process address space to a device
2756-
* @dev: the device
2757-
* @mm: the mm to bind, caller must hold a reference to it
2758-
*
2759-
* Create a bond between device and address space, allowing the device to access
2760-
* the mm using the returned PASID. If a bond already exists between @device and
2761-
* @mm, it is returned and an additional reference is taken. Caller must call
2762-
* iommu_sva_unbind_device() to release each reference.
2763-
*
2764-
* iommu_dev_enable_feature(dev, IOMMU_DEV_FEAT_SVA) must be called first, to
2765-
* initialize the required SVA features.
2766-
*
2767-
* On error, returns an ERR_PTR value.
2768-
*/
2769-
struct iommu_sva *
2770-
iommu_sva_bind_device(struct device *dev, struct mm_struct *mm)
2771-
{
2772-
struct iommu_group *group;
2773-
struct iommu_sva *handle = ERR_PTR(-EINVAL);
2774-
const struct iommu_ops *ops = dev_iommu_ops(dev);
2775-
2776-
if (!ops->sva_bind)
2777-
return ERR_PTR(-ENODEV);
2778-
2779-
group = iommu_group_get(dev);
2780-
if (!group)
2781-
return ERR_PTR(-ENODEV);
2782-
2783-
/* Ensure device count and domain don't change while we're binding */
2784-
mutex_lock(&group->mutex);
2785-
2786-
/*
2787-
* To keep things simple, SVA currently doesn't support IOMMU groups
2788-
* with more than one device. Existing SVA-capable systems are not
2789-
* affected by the problems that required IOMMU groups (lack of ACS
2790-
* isolation, device ID aliasing and other hardware issues).
2791-
*/
2792-
if (iommu_group_device_count(group) != 1)
2793-
goto out_unlock;
2794-
2795-
handle = ops->sva_bind(dev, mm);
2796-
2797-
out_unlock:
2798-
mutex_unlock(&group->mutex);
2799-
iommu_group_put(group);
2800-
2801-
return handle;
2802-
}
2803-
EXPORT_SYMBOL_GPL(iommu_sva_bind_device);
2804-
2805-
/**
2806-
* iommu_sva_unbind_device() - Remove a bond created with iommu_sva_bind_device
2807-
* @handle: the handle returned by iommu_sva_bind_device()
2808-
*
2809-
* Put reference to a bond between device and address space. The device should
2810-
* not be issuing any more transaction for this PASID. All outstanding page
2811-
* requests for this PASID must have been flushed to the IOMMU.
2812-
*/
2813-
void iommu_sva_unbind_device(struct iommu_sva *handle)
2814-
{
2815-
struct iommu_group *group;
2816-
struct device *dev = handle->dev;
2817-
const struct iommu_ops *ops = dev_iommu_ops(dev);
2818-
2819-
if (!ops->sva_unbind)
2820-
return;
2821-
2822-
group = iommu_group_get(dev);
2823-
if (!group)
2824-
return;
2825-
2826-
mutex_lock(&group->mutex);
2827-
ops->sva_unbind(handle);
2828-
mutex_unlock(&group->mutex);
2829-
2830-
iommu_group_put(group);
2831-
}
2832-
EXPORT_SYMBOL_GPL(iommu_sva_unbind_device);
2833-
2834-
u32 iommu_sva_get_pasid(struct iommu_sva *handle)
2835-
{
2836-
const struct iommu_ops *ops = dev_iommu_ops(handle->dev);
2837-
2838-
if (!ops->sva_get_pasid)
2839-
return IOMMU_PASID_INVALID;
2840-
2841-
return ops->sva_get_pasid(handle);
2842-
}
2843-
EXPORT_SYMBOL_GPL(iommu_sva_get_pasid);
2844-
28452754
/*
28462755
* Changes the default domain of an iommu group that has *only* one device
28472756
*

include/linux/iommu.h

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -645,6 +645,7 @@ struct iommu_fwspec {
645645
*/
646646
struct iommu_sva {
647647
struct device *dev;
648+
struct iommu_domain *domain;
648649
};
649650

650651
int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
@@ -686,11 +687,6 @@ void iommu_release_device(struct device *dev);
686687
int iommu_dev_enable_feature(struct device *dev, enum iommu_dev_features f);
687688
int iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features f);
688689

689-
struct iommu_sva *iommu_sva_bind_device(struct device *dev,
690-
struct mm_struct *mm);
691-
void iommu_sva_unbind_device(struct iommu_sva *handle);
692-
u32 iommu_sva_get_pasid(struct iommu_sva *handle);
693-
694690
int iommu_device_use_default_domain(struct device *dev);
695691
void iommu_device_unuse_default_domain(struct device *dev);
696692

@@ -1026,21 +1022,6 @@ iommu_dev_disable_feature(struct device *dev, enum iommu_dev_features feat)
10261022
return -ENODEV;
10271023
}
10281024

1029-
static inline struct iommu_sva *
1030-
iommu_sva_bind_device(struct device *dev, struct mm_struct *mm)
1031-
{
1032-
return NULL;
1033-
}
1034-
1035-
static inline void iommu_sva_unbind_device(struct iommu_sva *handle)
1036-
{
1037-
}
1038-
1039-
static inline u32 iommu_sva_get_pasid(struct iommu_sva *handle)
1040-
{
1041-
return IOMMU_PASID_INVALID;
1042-
}
1043-
10441025
static inline struct iommu_fwspec *dev_iommu_fwspec_get(struct device *dev)
10451026
{
10461027
return NULL;
@@ -1154,4 +1135,26 @@ static inline void iommu_dma_compose_msi_msg(struct msi_desc *desc, struct msi_m
11541135

11551136
#endif /* CONFIG_IOMMU_DMA */
11561137

1138+
#ifdef CONFIG_IOMMU_SVA
1139+
struct iommu_sva *iommu_sva_bind_device(struct device *dev,
1140+
struct mm_struct *mm);
1141+
void iommu_sva_unbind_device(struct iommu_sva *handle);
1142+
u32 iommu_sva_get_pasid(struct iommu_sva *handle);
1143+
#else
1144+
static inline struct iommu_sva *
1145+
iommu_sva_bind_device(struct device *dev, struct mm_struct *mm)
1146+
{
1147+
return NULL;
1148+
}
1149+
1150+
static inline void iommu_sva_unbind_device(struct iommu_sva *handle)
1151+
{
1152+
}
1153+
1154+
static inline u32 iommu_sva_get_pasid(struct iommu_sva *handle)
1155+
{
1156+
return IOMMU_PASID_INVALID;
1157+
}
1158+
#endif /* CONFIG_IOMMU_SVA */
1159+
11571160
#endif /* __LINUX_IOMMU_H */

0 commit comments

Comments
 (0)