Skip to content

Commit 89395cc

Browse files
LuBaolujgunthorpe
authored andcommitted
iommu: Add device-centric DMA ownership interfaces
These complement the group interfaces used by VFIO and are for use by iommufd. The main difference is that multiple devices in the same group can all share the ownership by passing the same ownership pointer. Move the common code into shared functions. Link: https://lore.kernel.org/r/[email protected] Tested-by: Nicolin Chen <[email protected]> Tested-by: Yi Liu <[email protected]> Tested-by: Lixiao Yang <[email protected]> Tested-by: Matthew Rosato <[email protected]> Reviewed-by: Kevin Tian <[email protected]> Reviewed-by: Eric Auger <[email protected]> Signed-off-by: Lu Baolu <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]>
1 parent 4989764 commit 89395cc

File tree

2 files changed

+107
-26
lines changed

2 files changed

+107
-26
lines changed

drivers/iommu/iommu.c

Lines changed: 95 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3108,41 +3108,49 @@ static int __iommu_group_alloc_blocking_domain(struct iommu_group *group)
31083108
return 0;
31093109
}
31103110

3111+
static int __iommu_take_dma_ownership(struct iommu_group *group, void *owner)
3112+
{
3113+
int ret;
3114+
3115+
if ((group->domain && group->domain != group->default_domain) ||
3116+
!xa_empty(&group->pasid_array))
3117+
return -EBUSY;
3118+
3119+
ret = __iommu_group_alloc_blocking_domain(group);
3120+
if (ret)
3121+
return ret;
3122+
ret = __iommu_group_set_domain(group, group->blocking_domain);
3123+
if (ret)
3124+
return ret;
3125+
3126+
group->owner = owner;
3127+
group->owner_cnt++;
3128+
return 0;
3129+
}
3130+
31113131
/**
31123132
* iommu_group_claim_dma_owner() - Set DMA ownership of a group
31133133
* @group: The group.
31143134
* @owner: Caller specified pointer. Used for exclusive ownership.
31153135
*
3116-
* This is to support backward compatibility for vfio which manages
3117-
* the dma ownership in iommu_group level. New invocations on this
3118-
* interface should be prohibited.
3136+
* This is to support backward compatibility for vfio which manages the dma
3137+
* ownership in iommu_group level. New invocations on this interface should be
3138+
* prohibited. Only a single owner may exist for a group.
31193139
*/
31203140
int iommu_group_claim_dma_owner(struct iommu_group *group, void *owner)
31213141
{
31223142
int ret = 0;
31233143

3144+
if (WARN_ON(!owner))
3145+
return -EINVAL;
3146+
31243147
mutex_lock(&group->mutex);
31253148
if (group->owner_cnt) {
31263149
ret = -EPERM;
31273150
goto unlock_out;
3128-
} else {
3129-
if ((group->domain && group->domain != group->default_domain) ||
3130-
!xa_empty(&group->pasid_array)) {
3131-
ret = -EBUSY;
3132-
goto unlock_out;
3133-
}
3134-
3135-
ret = __iommu_group_alloc_blocking_domain(group);
3136-
if (ret)
3137-
goto unlock_out;
3138-
3139-
ret = __iommu_group_set_domain(group, group->blocking_domain);
3140-
if (ret)
3141-
goto unlock_out;
3142-
group->owner = owner;
31433151
}
31443152

3145-
group->owner_cnt++;
3153+
ret = __iommu_take_dma_ownership(group, owner);
31463154
unlock_out:
31473155
mutex_unlock(&group->mutex);
31483156

@@ -3151,30 +3159,91 @@ int iommu_group_claim_dma_owner(struct iommu_group *group, void *owner)
31513159
EXPORT_SYMBOL_GPL(iommu_group_claim_dma_owner);
31523160

31533161
/**
3154-
* iommu_group_release_dma_owner() - Release DMA ownership of a group
3155-
* @group: The group.
3162+
* iommu_device_claim_dma_owner() - Set DMA ownership of a device
3163+
* @dev: The device.
3164+
* @owner: Caller specified pointer. Used for exclusive ownership.
31563165
*
3157-
* Release the DMA ownership claimed by iommu_group_claim_dma_owner().
3166+
* Claim the DMA ownership of a device. Multiple devices in the same group may
3167+
* concurrently claim ownership if they present the same owner value. Returns 0
3168+
* on success and error code on failure
31583169
*/
3159-
void iommu_group_release_dma_owner(struct iommu_group *group)
3170+
int iommu_device_claim_dma_owner(struct device *dev, void *owner)
31603171
{
3161-
int ret;
3172+
struct iommu_group *group = iommu_group_get(dev);
3173+
int ret = 0;
3174+
3175+
if (!group)
3176+
return -ENODEV;
3177+
if (WARN_ON(!owner))
3178+
return -EINVAL;
31623179

31633180
mutex_lock(&group->mutex);
3181+
if (group->owner_cnt) {
3182+
if (group->owner != owner) {
3183+
ret = -EPERM;
3184+
goto unlock_out;
3185+
}
3186+
group->owner_cnt++;
3187+
goto unlock_out;
3188+
}
3189+
3190+
ret = __iommu_take_dma_ownership(group, owner);
3191+
unlock_out:
3192+
mutex_unlock(&group->mutex);
3193+
iommu_group_put(group);
3194+
3195+
return ret;
3196+
}
3197+
EXPORT_SYMBOL_GPL(iommu_device_claim_dma_owner);
3198+
3199+
static void __iommu_release_dma_ownership(struct iommu_group *group)
3200+
{
3201+
int ret;
3202+
31643203
if (WARN_ON(!group->owner_cnt || !group->owner ||
31653204
!xa_empty(&group->pasid_array)))
3166-
goto unlock_out;
3205+
return;
31673206

31683207
group->owner_cnt = 0;
31693208
group->owner = NULL;
31703209
ret = __iommu_group_set_domain(group, group->default_domain);
31713210
WARN(ret, "iommu driver failed to attach the default domain");
3211+
}
31723212

3173-
unlock_out:
3213+
/**
3214+
* iommu_group_release_dma_owner() - Release DMA ownership of a group
3215+
* @dev: The device
3216+
*
3217+
* Release the DMA ownership claimed by iommu_group_claim_dma_owner().
3218+
*/
3219+
void iommu_group_release_dma_owner(struct iommu_group *group)
3220+
{
3221+
mutex_lock(&group->mutex);
3222+
__iommu_release_dma_ownership(group);
31743223
mutex_unlock(&group->mutex);
31753224
}
31763225
EXPORT_SYMBOL_GPL(iommu_group_release_dma_owner);
31773226

3227+
/**
3228+
* iommu_device_release_dma_owner() - Release DMA ownership of a device
3229+
* @group: The device.
3230+
*
3231+
* Release the DMA ownership claimed by iommu_device_claim_dma_owner().
3232+
*/
3233+
void iommu_device_release_dma_owner(struct device *dev)
3234+
{
3235+
struct iommu_group *group = iommu_group_get(dev);
3236+
3237+
mutex_lock(&group->mutex);
3238+
if (group->owner_cnt > 1)
3239+
group->owner_cnt--;
3240+
else
3241+
__iommu_release_dma_ownership(group);
3242+
mutex_unlock(&group->mutex);
3243+
iommu_group_put(group);
3244+
}
3245+
EXPORT_SYMBOL_GPL(iommu_device_release_dma_owner);
3246+
31783247
/**
31793248
* iommu_group_dma_owner_claimed() - Query group dma ownership status
31803249
* @group: The group.

include/linux/iommu.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -707,6 +707,9 @@ int iommu_group_claim_dma_owner(struct iommu_group *group, void *owner);
707707
void iommu_group_release_dma_owner(struct iommu_group *group);
708708
bool iommu_group_dma_owner_claimed(struct iommu_group *group);
709709

710+
int iommu_device_claim_dma_owner(struct device *dev, void *owner);
711+
void iommu_device_release_dma_owner(struct device *dev);
712+
710713
struct iommu_domain *iommu_sva_domain_alloc(struct device *dev,
711714
struct mm_struct *mm);
712715
int iommu_attach_device_pasid(struct iommu_domain *domain,
@@ -1064,6 +1067,15 @@ static inline bool iommu_group_dma_owner_claimed(struct iommu_group *group)
10641067
return false;
10651068
}
10661069

1070+
static inline void iommu_device_release_dma_owner(struct device *dev)
1071+
{
1072+
}
1073+
1074+
static inline int iommu_device_claim_dma_owner(struct device *dev, void *owner)
1075+
{
1076+
return -ENODEV;
1077+
}
1078+
10671079
static inline struct iommu_domain *
10681080
iommu_sva_domain_alloc(struct device *dev, struct mm_struct *mm)
10691081
{

0 commit comments

Comments
 (0)