From: Lu Baolu <baolu.lu@xxxxxxxxxxxxxxx> These two helpers could be used when 1) the iommu group is singleton, or 2) the upper layer has put the iommu group into the secure state by calling iommu_device_init_user_dma(). As we want the iommufd design to be a device-centric model, we want to remove any group knowledge in iommufd. Given that we already have iommu_at[de]tach_device() interface, we could extend it for iommufd simply by doing below: - first device in a group does group attach; - last device in a group does group detach. as long as the group has been put into the secure context. The commit <426a273834eae> ("iommu: Limit iommu_attach/detach_device to device with their own group") deliberately restricts the two interfaces to single-device group. To avoid the conflict with existing usages, we keep this policy and put the new extension only when the group has been marked for user_dma. Signed-off-by: Lu Baolu <baolu.lu@xxxxxxxxxxxxxxx> --- drivers/iommu/iommu.c | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c index bffd84e978fb..b6178997aef1 100644 --- a/drivers/iommu/iommu.c +++ b/drivers/iommu/iommu.c @@ -47,6 +47,7 @@ struct iommu_group { struct list_head entry; unsigned long user_dma_owner_id; refcount_t owner_cnt; + refcount_t attach_cnt; }; struct group_device { @@ -1994,7 +1995,7 @@ static int __iommu_attach_device(struct iommu_domain *domain, int iommu_attach_device(struct iommu_domain *domain, struct device *dev) { struct iommu_group *group; - int ret; + int ret = 0; group = iommu_group_get(dev); if (!group) @@ -2005,11 +2006,23 @@ int iommu_attach_device(struct iommu_domain *domain, struct device *dev) * change while we are attaching */ mutex_lock(&group->mutex); - ret = -EINVAL; - if (iommu_group_device_count(group) != 1) + if (group->user_dma_owner_id) { + if (group->domain) { + if (group->domain != domain) + ret = -EBUSY; + else + refcount_inc(&group->attach_cnt); + + goto out_unlock; + } + } else if (iommu_group_device_count(group) != 1) { + ret = -EINVAL; goto out_unlock; + } ret = __iommu_attach_group(domain, group); + if (!ret && group->user_dma_owner_id) + refcount_set(&group->attach_cnt, 1); out_unlock: mutex_unlock(&group->mutex); @@ -2261,7 +2274,10 @@ void iommu_detach_device(struct iommu_domain *domain, struct device *dev) return; mutex_lock(&group->mutex); - if (iommu_group_device_count(group) != 1) { + if (group->user_dma_owner_id) { + if (!refcount_dec_and_test(&group->attach_cnt)) + goto out_unlock; + } else if (iommu_group_device_count(group) != 1) { WARN_ON(1); goto out_unlock; } @@ -3368,6 +3384,7 @@ static int iommu_group_init_user_dma(struct iommu_group *group, group->user_dma_owner_id = owner; refcount_set(&group->owner_cnt, 1); + refcount_set(&group->attach_cnt, 0); /* default domain is unsafe for user-initiated dma */ if (group->domain == group->default_domain) -- 2.25.1