smmu 学习笔记之attach_dev

根据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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值