根据hns_uio_set_iommu 函数中的flow
void hns_uio_set_iommu(struct nic_uio_device *priv, unsigned long iova,
unsigned long paddr, int gfp_order)
{
struct iommu_domain *domain;
int ret = 0;
domain = iommu_domain_alloc(priv->dev->bus);
if (!domain)
PRINT(KERN_ERR, "domain is null\n");
ret = iommu_attach_device(domain, priv->dev);
PRINT(KERN_ERR, "domain is null = %d\n", ret);
ret =
iommu_map(domain, iova, (phys_addr_t)paddr, gfp_order,
(IOMMU_WRITE | IOMMU_READ | IOMMU_CACHE));
PRINT(KERN_ERR, "domain is null = %d\n", ret);
}
申请domain之后,如果domain不为null的话,就要attach device
int iommu_attach_device(struct iommu_domain *domain, struct device *dev)
{
struct iommu_group *group;
int ret;
group = iommu_group_get(dev);
/* FIXME: Remove this when groups a mandatory for iommu drivers */
if (group == NULL)
return __iommu_attach_device(domain, dev);
/*
* We have a group - lock it to make sure the device-count doesn't
* change while we are attaching
*/
mutex_lock(&group->mutex);
ret = -EINVAL;
if (iommu_group_device_count(group) != 1)
goto out_unlock;
ret = __iommu_attach_group(domain, group);
out_unlock:
mutex_unlock(&group->mutex);
iommu_group_put(group);
return ret;
}
在iommu_attach_device 中首先通过group = iommu_group_get(dev); 得到group
在smmu v3版本中的group有两种,其也是在arm_smmu_ops的device_group 中定义的
static struct iommu_ops arm_smmu_ops = {
.capable = arm_smmu_capable,
.domain_alloc = arm_smmu_domain_alloc,
.domain_free = arm_smmu_domain_free,
.attach_dev = arm_smmu_attach_dev,
.map = arm_smmu_map,
.unmap = arm_smmu_unmap,
.map_sg = default_iommu_map_sg,
.iova_to_phys = arm_smmu_iova_to_phys,
.add_device = arm_smmu_add_device,
.remove_device = arm_smmu_remove_device,
.device_group = arm_smmu_device_group,
.domain_get_attr = arm_smmu_domain_get_attr,
.domain_set_attr = arm_smmu_domain_set_attr,
.of_xlate = arm_smmu_of_xlate,
.pgsize_bitmap = -1UL, /* Restricted during device attach */
};
static struct iommu_group *arm_smmu_device_group(struct device *dev)
{
struct iommu_group *group;
/*
* We don't support devices sharing stream IDs other than PCI RID
* aliases, since the necessary ID-to-device lookup becomes rather
* impractical given a potential sparse 32-bit stream ID space.
*/
if (dev_is_pci(dev))
group = pci_device_group(dev);
else
group = generic_device_group(dev);
return group;
}
从arm_smmu_device_group 函数可以看出group分为pci group和generic group
在iommu_attach_device 函数中我们以generic group为例,如果group为null的话,就调用__iommu_attach_device
static int __iommu_attach_device(struct iommu_domain *domain,
struct device *dev)
{
int ret;
if (unlikely(domain->ops->attach_dev == NULL))
return -ENODEV;
ret = domain->ops->attach_dev(domain, dev);
if (!ret)
trace_attach_device_to_domain(dev);
return ret;
}
最终也是调用arm_smmu_ops 中的attach_dev 即arm_smmu_attach_dev。这个函数前面已经有介绍了
然后在iommu_attach_device 中调用iommu_group_device_count 来看当时是否已经有group了
static int iommu_group_device_count(struct iommu_group *group)
{
struct iommu_device *entry;
int ret = 0;
list_for_each_entry(entry, &group->devices, list)
ret++;
return ret;
}
只要group->devices 不为null,ret 就自加
如果最终的group大于1,就调用__iommu_attach_group 来attach group
static int __iommu_attach_group(struct iommu_domain *domain,
struct iommu_group *group)
{
int ret;
if (group->default_domain && group->domain != group->default_domain)
return -EBUSY;
ret = __iommu_group_for_each_dev(group, domain,
iommu_group_do_attach_device);
if (ret == 0)
group->domain = domain;
return ret;
}
__iommu_attach_group 中进行参数判断后,继续调用__iommu_group_for_each_dev。如果ret == 0的话,说明执行成功,就将这个申请的domian赋值给group->domain = domain,为每个domain都调用iommu_group_do_attach_device
static int iommu_group_do_attach_device(struct device *dev, void *data)
{
struct iommu_domain *domain = data;
return __iommu_attach_device(domain, dev);
}
继续调用__iommu_attach_device
static int __iommu_attach_device(struct iommu_domain *domain,
struct device *dev)
{
int ret;
if (unlikely(domain->ops->attach_dev == NULL))
return -ENODEV;
ret = domain->ops->attach_dev(domain, dev);
if (!ret)
trace_attach_device_to_domain(dev);
return ret;
}
最终还是调用domain->ops->attach_dev,最中还是调用arm_smmu_ops 中的attach_dev也就是arm_smmu_attach_dev
void hns_uio_set_iommu(struct nic_uio_device *priv, unsigned long iova,
unsigned long paddr, int gfp_order)
{
struct iommu_domain *domain;
int ret = 0;
domain = iommu_domain_alloc(priv->dev->bus);
if (!domain)
PRINT(KERN_ERR, "domain is null\n");
ret = iommu_attach_device(domain, priv->dev);
PRINT(KERN_ERR, "domain is null = %d\n", ret);
ret =
iommu_map(domain, iova, (phys_addr_t)paddr, gfp_order,
(IOMMU_WRITE | IOMMU_READ | IOMMU_CACHE));
PRINT(KERN_ERR, "domain is null = %d\n", ret);
}
申请domain之后,如果domain不为null的话,就要attach device
int iommu_attach_device(struct iommu_domain *domain, struct device *dev)
{
struct iommu_group *group;
int ret;
group = iommu_group_get(dev);
/* FIXME: Remove this when groups a mandatory for iommu drivers */
if (group == NULL)
return __iommu_attach_device(domain, dev);
/*
* We have a group - lock it to make sure the device-count doesn't
* change while we are attaching
*/
mutex_lock(&group->mutex);
ret = -EINVAL;
if (iommu_group_device_count(group) != 1)
goto out_unlock;
ret = __iommu_attach_group(domain, group);
out_unlock:
mutex_unlock(&group->mutex);
iommu_group_put(group);
return ret;
}
在iommu_attach_device 中首先通过group = iommu_group_get(dev); 得到group
在smmu v3版本中的group有两种,其也是在arm_smmu_ops的device_group 中定义的
static struct iommu_ops arm_smmu_ops = {
.capable = arm_smmu_capable,
.domain_alloc = arm_smmu_domain_alloc,
.domain_free = arm_smmu_domain_free,
.attach_dev = arm_smmu_attach_dev,
.map = arm_smmu_map,
.unmap = arm_smmu_unmap,
.map_sg = default_iommu_map_sg,
.iova_to_phys = arm_smmu_iova_to_phys,
.add_device = arm_smmu_add_device,
.remove_device = arm_smmu_remove_device,
.device_group = arm_smmu_device_group,
.domain_get_attr = arm_smmu_domain_get_attr,
.domain_set_attr = arm_smmu_domain_set_attr,
.of_xlate = arm_smmu_of_xlate,
.pgsize_bitmap = -1UL, /* Restricted during device attach */
};
static struct iommu_group *arm_smmu_device_group(struct device *dev)
{
struct iommu_group *group;
/*
* We don't support devices sharing stream IDs other than PCI RID
* aliases, since the necessary ID-to-device lookup becomes rather
* impractical given a potential sparse 32-bit stream ID space.
*/
if (dev_is_pci(dev))
group = pci_device_group(dev);
else
group = generic_device_group(dev);
return group;
}
从arm_smmu_device_group 函数可以看出group分为pci group和generic group
在iommu_attach_device 函数中我们以generic group为例,如果group为null的话,就调用__iommu_attach_device
static int __iommu_attach_device(struct iommu_domain *domain,
struct device *dev)
{
int ret;
if (unlikely(domain->ops->attach_dev == NULL))
return -ENODEV;
ret = domain->ops->attach_dev(domain, dev);
if (!ret)
trace_attach_device_to_domain(dev);
return ret;
}
最终也是调用arm_smmu_ops 中的attach_dev 即arm_smmu_attach_dev。这个函数前面已经有介绍了
然后在iommu_attach_device 中调用iommu_group_device_count 来看当时是否已经有group了
static int iommu_group_device_count(struct iommu_group *group)
{
struct iommu_device *entry;
int ret = 0;
list_for_each_entry(entry, &group->devices, list)
ret++;
return ret;
}
只要group->devices 不为null,ret 就自加
如果最终的group大于1,就调用__iommu_attach_group 来attach group
static int __iommu_attach_group(struct iommu_domain *domain,
struct iommu_group *group)
{
int ret;
if (group->default_domain && group->domain != group->default_domain)
return -EBUSY;
ret = __iommu_group_for_each_dev(group, domain,
iommu_group_do_attach_device);
if (ret == 0)
group->domain = domain;
return ret;
}
__iommu_attach_group 中进行参数判断后,继续调用__iommu_group_for_each_dev。如果ret == 0的话,说明执行成功,就将这个申请的domian赋值给group->domain = domain,为每个domain都调用iommu_group_do_attach_device
static int iommu_group_do_attach_device(struct device *dev, void *data)
{
struct iommu_domain *domain = data;
return __iommu_attach_device(domain, dev);
}
继续调用__iommu_attach_device
static int __iommu_attach_device(struct iommu_domain *domain,
struct device *dev)
{
int ret;
if (unlikely(domain->ops->attach_dev == NULL))
return -ENODEV;
ret = domain->ops->attach_dev(domain, dev);
if (!ret)
trace_attach_device_to_domain(dev);
return ret;
}
最终还是调用domain->ops->attach_dev,最中还是调用arm_smmu_ops 中的attach_dev也就是arm_smmu_attach_dev