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和赋值而已。
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和赋值而已。