首页 > 学院 > 开发设计 > 正文

smmu 学习笔记之attach_dev

2019-11-07 23:37:33
字体:
来源:转载
供稿:网友
根据hns_uio_set_iommu 函数中的flowvoid 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 deviceint 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_devicestatic 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 groupstatic 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_devicestatic int iommu_group_do_attach_device(struct device *dev, void *data){    struct iommu_domain *domain = data;    return __iommu_attach_device(domain, dev);}继续调用__iommu_attach_devicestatic 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
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表