Skip to content

Commit 1660370

Browse files
LuBaolujoergroedel
authored andcommitted
iommu: Add attach/detach_dev_pasid iommu interfaces
Attaching an IOMMU domain to a PASID of a device is a generic operation for modern IOMMU drivers which support PASID-granular DMA address translation. Currently visible usage scenarios include (but not limited): - SVA (Shared Virtual Address) - kernel DMA with PASID - hardware-assist mediated device This adds the set_dev_pasid domain ops for setting the domain onto a PASID of a device and remove_dev_pasid iommu ops for removing any setup on a PASID of device. This also adds interfaces for device drivers to attach/detach/retrieve a domain for a PASID of a device. If multiple devices share a single group, it's fine as long the fabric always routes every TLP marked with a PASID to the host bridge and only the host bridge. For example, ACS achieves this universally and has been checked when pci_enable_pasid() is called. As we can't reliably tell the source apart in a group, all the devices in a group have to be considered as the same source, and mapped to the same PASID table. The DMA ownership is about the whole device (more precisely, iommu group), including the RID and PASIDs. When the ownership is converted, the pasid array must be empty. This also adds necessary checks in the DMA ownership interfaces. Signed-off-by: Lu Baolu <[email protected]> Reviewed-by: Jean-Philippe Brucker <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Reviewed-by: Yi Liu <[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 201007e commit 1660370

File tree

2 files changed

+169
-4
lines changed

2 files changed

+169
-4
lines changed

drivers/iommu/iommu.c

Lines changed: 137 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ struct iommu_group {
4343
struct kobject kobj;
4444
struct kobject *devices_kobj;
4545
struct list_head devices;
46+
struct xarray pasid_array;
4647
struct mutex mutex;
4748
void *iommu_data;
4849
void (*iommu_data_release)(void *iommu_data);
@@ -723,6 +724,7 @@ struct iommu_group *iommu_group_alloc(void)
723724
mutex_init(&group->mutex);
724725
INIT_LIST_HEAD(&group->devices);
725726
INIT_LIST_HEAD(&group->entry);
727+
xa_init(&group->pasid_array);
726728

727729
ret = ida_alloc(&iommu_group_ida, GFP_KERNEL);
728730
if (ret < 0) {
@@ -3106,7 +3108,8 @@ int iommu_device_use_default_domain(struct device *dev)
31063108

31073109
mutex_lock(&group->mutex);
31083110
if (group->owner_cnt) {
3109-
if (group->owner || !iommu_is_default_domain(group)) {
3111+
if (group->owner || !iommu_is_default_domain(group) ||
3112+
!xa_empty(&group->pasid_array)) {
31103113
ret = -EBUSY;
31113114
goto unlock_out;
31123115
}
@@ -3137,7 +3140,7 @@ void iommu_device_unuse_default_domain(struct device *dev)
31373140
return;
31383141

31393142
mutex_lock(&group->mutex);
3140-
if (!WARN_ON(!group->owner_cnt))
3143+
if (!WARN_ON(!group->owner_cnt || !xa_empty(&group->pasid_array)))
31413144
group->owner_cnt--;
31423145

31433146
mutex_unlock(&group->mutex);
@@ -3185,7 +3188,8 @@ int iommu_group_claim_dma_owner(struct iommu_group *group, void *owner)
31853188
ret = -EPERM;
31863189
goto unlock_out;
31873190
} else {
3188-
if (group->domain && group->domain != group->default_domain) {
3191+
if ((group->domain && group->domain != group->default_domain) ||
3192+
!xa_empty(&group->pasid_array)) {
31893193
ret = -EBUSY;
31903194
goto unlock_out;
31913195
}
@@ -3219,7 +3223,8 @@ void iommu_group_release_dma_owner(struct iommu_group *group)
32193223
int ret;
32203224

32213225
mutex_lock(&group->mutex);
3222-
if (WARN_ON(!group->owner_cnt || !group->owner))
3226+
if (WARN_ON(!group->owner_cnt || !group->owner ||
3227+
!xa_empty(&group->pasid_array)))
32233228
goto unlock_out;
32243229

32253230
group->owner_cnt = 0;
@@ -3250,3 +3255,131 @@ bool iommu_group_dma_owner_claimed(struct iommu_group *group)
32503255
return user;
32513256
}
32523257
EXPORT_SYMBOL_GPL(iommu_group_dma_owner_claimed);
3258+
3259+
static int __iommu_set_group_pasid(struct iommu_domain *domain,
3260+
struct iommu_group *group, ioasid_t pasid)
3261+
{
3262+
struct group_device *device;
3263+
int ret = 0;
3264+
3265+
list_for_each_entry(device, &group->devices, list) {
3266+
ret = domain->ops->set_dev_pasid(domain, device->dev, pasid);
3267+
if (ret)
3268+
break;
3269+
}
3270+
3271+
return ret;
3272+
}
3273+
3274+
static void __iommu_remove_group_pasid(struct iommu_group *group,
3275+
ioasid_t pasid)
3276+
{
3277+
struct group_device *device;
3278+
const struct iommu_ops *ops;
3279+
3280+
list_for_each_entry(device, &group->devices, list) {
3281+
ops = dev_iommu_ops(device->dev);
3282+
ops->remove_dev_pasid(device->dev, pasid);
3283+
}
3284+
}
3285+
3286+
/*
3287+
* iommu_attach_device_pasid() - Attach a domain to pasid of device
3288+
* @domain: the iommu domain.
3289+
* @dev: the attached device.
3290+
* @pasid: the pasid of the device.
3291+
*
3292+
* Return: 0 on success, or an error.
3293+
*/
3294+
int iommu_attach_device_pasid(struct iommu_domain *domain,
3295+
struct device *dev, ioasid_t pasid)
3296+
{
3297+
struct iommu_group *group;
3298+
void *curr;
3299+
int ret;
3300+
3301+
if (!domain->ops->set_dev_pasid)
3302+
return -EOPNOTSUPP;
3303+
3304+
group = iommu_group_get(dev);
3305+
if (!group)
3306+
return -ENODEV;
3307+
3308+
mutex_lock(&group->mutex);
3309+
curr = xa_cmpxchg(&group->pasid_array, pasid, NULL, domain, GFP_KERNEL);
3310+
if (curr) {
3311+
ret = xa_err(curr) ? : -EBUSY;
3312+
goto out_unlock;
3313+
}
3314+
3315+
ret = __iommu_set_group_pasid(domain, group, pasid);
3316+
if (ret) {
3317+
__iommu_remove_group_pasid(group, pasid);
3318+
xa_erase(&group->pasid_array, pasid);
3319+
}
3320+
out_unlock:
3321+
mutex_unlock(&group->mutex);
3322+
iommu_group_put(group);
3323+
3324+
return ret;
3325+
}
3326+
EXPORT_SYMBOL_GPL(iommu_attach_device_pasid);
3327+
3328+
/*
3329+
* iommu_detach_device_pasid() - Detach the domain from pasid of device
3330+
* @domain: the iommu domain.
3331+
* @dev: the attached device.
3332+
* @pasid: the pasid of the device.
3333+
*
3334+
* The @domain must have been attached to @pasid of the @dev with
3335+
* iommu_attach_device_pasid().
3336+
*/
3337+
void iommu_detach_device_pasid(struct iommu_domain *domain, struct device *dev,
3338+
ioasid_t pasid)
3339+
{
3340+
struct iommu_group *group = iommu_group_get(dev);
3341+
3342+
mutex_lock(&group->mutex);
3343+
__iommu_remove_group_pasid(group, pasid);
3344+
WARN_ON(xa_erase(&group->pasid_array, pasid) != domain);
3345+
mutex_unlock(&group->mutex);
3346+
3347+
iommu_group_put(group);
3348+
}
3349+
EXPORT_SYMBOL_GPL(iommu_detach_device_pasid);
3350+
3351+
/*
3352+
* iommu_get_domain_for_dev_pasid() - Retrieve domain for @pasid of @dev
3353+
* @dev: the queried device
3354+
* @pasid: the pasid of the device
3355+
* @type: matched domain type, 0 for any match
3356+
*
3357+
* This is a variant of iommu_get_domain_for_dev(). It returns the existing
3358+
* domain attached to pasid of a device. Callers must hold a lock around this
3359+
* function, and both iommu_attach/detach_dev_pasid() whenever a domain of
3360+
* type is being manipulated. This API does not internally resolve races with
3361+
* attach/detach.
3362+
*
3363+
* Return: attached domain on success, NULL otherwise.
3364+
*/
3365+
struct iommu_domain *iommu_get_domain_for_dev_pasid(struct device *dev,
3366+
ioasid_t pasid,
3367+
unsigned int type)
3368+
{
3369+
struct iommu_domain *domain;
3370+
struct iommu_group *group;
3371+
3372+
group = iommu_group_get(dev);
3373+
if (!group)
3374+
return NULL;
3375+
3376+
xa_lock(&group->pasid_array);
3377+
domain = xa_load(&group->pasid_array, pasid);
3378+
if (type && domain && domain->type != type)
3379+
domain = ERR_PTR(-EBUSY);
3380+
xa_unlock(&group->pasid_array);
3381+
iommu_group_put(group);
3382+
3383+
return domain;
3384+
}
3385+
EXPORT_SYMBOL_GPL(iommu_get_domain_for_dev_pasid);

include/linux/iommu.h

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,9 @@ struct iommu_iotlb_gather {
223223
* - IOMMU_DOMAIN_DMA: must use a dma domain
224224
* - 0: use the default setting
225225
* @default_domain_ops: the default ops for domains
226+
* @remove_dev_pasid: Remove any translation configurations of a specific
227+
* pasid, so that any DMA transactions with this pasid
228+
* will be blocked by the hardware.
226229
* @pgsize_bitmap: bitmap of all possible supported page sizes
227230
* @owner: Driver module providing these ops
228231
*/
@@ -256,6 +259,7 @@ struct iommu_ops {
256259
struct iommu_page_response *msg);
257260

258261
int (*def_domain_type)(struct device *dev);
262+
void (*remove_dev_pasid)(struct device *dev, ioasid_t pasid);
259263

260264
const struct iommu_domain_ops *default_domain_ops;
261265
unsigned long pgsize_bitmap;
@@ -266,6 +270,7 @@ struct iommu_ops {
266270
* struct iommu_domain_ops - domain specific operations
267271
* @attach_dev: attach an iommu domain to a device
268272
* @detach_dev: detach an iommu domain from a device
273+
* @set_dev_pasid: set an iommu domain to a pasid of device
269274
* @map: map a physically contiguous memory region to an iommu domain
270275
* @map_pages: map a physically contiguous set of pages of the same size to
271276
* an iommu domain.
@@ -286,6 +291,8 @@ struct iommu_ops {
286291
struct iommu_domain_ops {
287292
int (*attach_dev)(struct iommu_domain *domain, struct device *dev);
288293
void (*detach_dev)(struct iommu_domain *domain, struct device *dev);
294+
int (*set_dev_pasid)(struct iommu_domain *domain, struct device *dev,
295+
ioasid_t pasid);
289296

290297
int (*map)(struct iommu_domain *domain, unsigned long iova,
291298
phys_addr_t paddr, size_t size, int prot, gfp_t gfp);
@@ -678,6 +685,13 @@ int iommu_group_claim_dma_owner(struct iommu_group *group, void *owner);
678685
void iommu_group_release_dma_owner(struct iommu_group *group);
679686
bool iommu_group_dma_owner_claimed(struct iommu_group *group);
680687

688+
int iommu_attach_device_pasid(struct iommu_domain *domain,
689+
struct device *dev, ioasid_t pasid);
690+
void iommu_detach_device_pasid(struct iommu_domain *domain,
691+
struct device *dev, ioasid_t pasid);
692+
struct iommu_domain *
693+
iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid,
694+
unsigned int type);
681695
#else /* CONFIG_IOMMU_API */
682696

683697
struct iommu_ops {};
@@ -1040,6 +1054,24 @@ static inline bool iommu_group_dma_owner_claimed(struct iommu_group *group)
10401054
{
10411055
return false;
10421056
}
1057+
1058+
static inline int iommu_attach_device_pasid(struct iommu_domain *domain,
1059+
struct device *dev, ioasid_t pasid)
1060+
{
1061+
return -ENODEV;
1062+
}
1063+
1064+
static inline void iommu_detach_device_pasid(struct iommu_domain *domain,
1065+
struct device *dev, ioasid_t pasid)
1066+
{
1067+
}
1068+
1069+
static inline struct iommu_domain *
1070+
iommu_get_domain_for_dev_pasid(struct device *dev, ioasid_t pasid,
1071+
unsigned int type)
1072+
{
1073+
return NULL;
1074+
}
10431075
#endif /* CONFIG_IOMMU_API */
10441076

10451077
/**

0 commit comments

Comments
 (0)