in iommu.c [3137:3257]
static int iommu_change_dev_def_domain(struct iommu_group *group,
struct device *prev_dev, int type)
{
struct iommu_domain *prev_dom;
struct group_device *grp_dev;
int ret, dev_def_dom;
struct device *dev;
mutex_lock(&group->mutex);
if (group->default_domain != group->domain) {
dev_err_ratelimited(prev_dev, "Group not assigned to default domain\n");
ret = -EBUSY;
goto out;
}
/*
* iommu group wasn't locked while acquiring device lock in
* iommu_group_store_type(). So, make sure that the device count hasn't
* changed while acquiring device lock.
*
* Changing default domain of an iommu group with two or more devices
* isn't supported because there could be a potential deadlock. Consider
* the following scenario. T1 is trying to acquire device locks of all
* the devices in the group and before it could acquire all of them,
* there could be another thread T2 (from different sub-system and use
* case) that has already acquired some of the device locks and might be
* waiting for T1 to release other device locks.
*/
if (iommu_group_device_count(group) != 1) {
dev_err_ratelimited(prev_dev, "Cannot change default domain: Group has more than one device\n");
ret = -EINVAL;
goto out;
}
/* Since group has only one device */
grp_dev = list_first_entry(&group->devices, struct group_device, list);
dev = grp_dev->dev;
if (prev_dev != dev) {
dev_err_ratelimited(prev_dev, "Cannot change default domain: Device has been changed\n");
ret = -EBUSY;
goto out;
}
prev_dom = group->default_domain;
if (!prev_dom) {
ret = -EINVAL;
goto out;
}
dev_def_dom = iommu_get_def_domain_type(dev);
if (!type) {
/*
* If the user hasn't requested any specific type of domain and
* if the device supports both the domains, then default to the
* domain the device was booted with
*/
type = dev_def_dom ? : iommu_def_domain_type;
} else if (dev_def_dom && type != dev_def_dom) {
dev_err_ratelimited(prev_dev, "Device cannot be in %s domain\n",
iommu_domain_type_str(type));
ret = -EINVAL;
goto out;
}
/*
* Switch to a new domain only if the requested domain type is different
* from the existing default domain type
*/
if (prev_dom->type == type) {
ret = 0;
goto out;
}
/* We can bring up a flush queue without tearing down the domain */
if (type == IOMMU_DOMAIN_DMA_FQ && prev_dom->type == IOMMU_DOMAIN_DMA) {
ret = iommu_dma_init_fq(prev_dom);
if (!ret)
prev_dom->type = IOMMU_DOMAIN_DMA_FQ;
goto out;
}
/* Sets group->default_domain to the newly allocated domain */
ret = iommu_group_alloc_default_domain(dev->bus, group, type);
if (ret)
goto out;
ret = iommu_create_device_direct_mappings(group, dev);
if (ret)
goto free_new_domain;
ret = __iommu_attach_device(group->default_domain, dev);
if (ret)
goto free_new_domain;
group->domain = group->default_domain;
/*
* Release the mutex here because ops->probe_finalize() call-back of
* some vendor IOMMU drivers calls arm_iommu_attach_device() which
* in-turn might call back into IOMMU core code, where it tries to take
* group->mutex, resulting in a deadlock.
*/
mutex_unlock(&group->mutex);
/* Make sure dma_ops is appropriatley set */
iommu_group_do_probe_finalize(dev, group->default_domain);
iommu_domain_free(prev_dom);
return 0;
free_new_domain:
iommu_domain_free(group->default_domain);
group->default_domain = prev_dom;
group->domain = prev_dom;
out:
mutex_unlock(&group->mutex);
return ret;
}