smmu 学习笔记之domain_alloc

smmu提供iommu_domain_alloc 这个接口来申请iommu_domain,举例如下:
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");
}
可见iommu_domain_alloc只有一个形参,这个形参是bus_type
struct iommu_domain *iommu_domain_alloc(struct bus_type *bus)
{
    return __iommu_domain_alloc(bus, IOMMU_DOMAIN_UNMANAGED);
}
增加type后调用__iommu_domain_alloc
static struct iommu_domain *__iommu_domain_alloc(struct bus_type *bus,
                         unsigned type)
{
    struct iommu_domain *domain;
        //判断bus和bus->iommu_ops  不能为null后
    if (bus == NULL || bus->iommu_ops == NULL)
        return NULL;

    //调用bus->iommu_ops->domain_alloc 申请domain
    domain = bus->iommu_ops->domain_alloc(type);
    if (!domain)
        return NULL;

//给domain的ops赋值为bus->iommu_ops
    domain->ops  = bus->iommu_ops;
    domain->type = type;
    /* Assume all sizes by default; the driver may override this later */
    domain->pgsize_bitmap  = bus->iommu_ops->pgsize_bitmap;

    return domain;
}
我们继续看bus->iommu_ops->domain_alloc。
在arm_smmu_device_probe 函数中会给bus的iommu_ops 赋值
#ifdef CONFIG_PCI
    if (pci_bus_type.iommu_ops != &arm_smmu_ops) {
        pci_request_acs();
        ret = bus_set_iommu(&pci_bus_type, &arm_smmu_ops);
        if (ret)
            return ret;
    }
#endif
#ifdef CONFIG_ARM_AMBA
    if (amba_bustype.iommu_ops != &arm_smmu_ops) {
        ret = bus_set_iommu(&amba_bustype, &arm_smmu_ops);
        if (ret)
            return ret;
    }
#endif
    if (platform_bus_type.iommu_ops != &arm_smmu_ops) {
        ret = bus_set_iommu(&platform_bus_type, &arm_smmu_ops);
        if (ret)
            return ret;
    }
可见总共支持三种总线。
从bus_set_iommu 中就可以看到是将arm_smmu_ops 赋值给bus->iommu_ops
int bus_set_iommu(struct bus_type *bus, const struct iommu_ops *ops)
{
    int err;

    if (bus->iommu_ops != NULL)
        return -EBUSY;

    bus->iommu_ops = ops;

    /* Do IOMMU specific setup for this bus-type */
    err = iommu_bus_init(bus, ops);
    if (err)
        bus->iommu_ops = NULL;

    return err;
}

因此__iommu_domain_alloc 中的bus->iommu_ops->domain_alloc 就等于arm_smmu_ops->domain_alloc
而arm_smmu_ops->domain_alloc = arm_smmu_domain_alloc
static struct iommu_domain *arm_smmu_domain_alloc(unsigned type)
{
    struct arm_smmu_domain *smmu_domain;
//从arm_smmu_domain_alloc 中可以看出type 只能是IOMMU_DOMAIN_UNMANAGED 和 IOMMU_DOMAIN_DMA
    if (type != IOMMU_DOMAIN_UNMANAGED && type != IOMMU_DOMAIN_DMA)
        return NULL;

    /*
     * Allocate the domain and initialise some of its data structures.
     * We can't really do anything meaningful until we've added a
     * master.
     */
//调用kzalloc 来申请arm_smmu_domain结构
    smmu_domain = kzalloc(sizeof(*smmu_domain), GFP_KERNEL);
    if (!smmu_domain)
        return NULL;
//如果type == IOMMU_DOMAIN_DMA的话,还要申请cookie
    if (type == IOMMU_DOMAIN_DMA &&
        iommu_get_dma_cookie(&smmu_domain->domain)) {
        kfree(smmu_domain);
        return NULL;
    }

    mutex_init(&smmu_domain->init_mutex);
    spin_lock_init(&smmu_domain->pgtbl_lock);
    return &smmu_domain->domain;
}

int iommu_get_dma_cookie(struct iommu_domain *domain)
{
    struct iommu_dma_cookie *cookie;

    if (domain->iova_cookie)
        return -EEXIST;

    cookie = kzalloc(sizeof(*cookie), GFP_KERNEL);
    if (!cookie)
        return -ENOMEM;

    spin_lock_init(&cookie->msi_lock);
    INIT_LIST_HEAD(&cookie->msi_page_list);
    domain->iova_cookie = cookie;
    return 0;
}
iommu_get_dma_cookie 也只是简单的申请memory和赋值而已。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值