在arm_smmu_iort_xlate 主要用于初始化dev->iommu_fwspec 这个结构体
static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
struct fwnode_handle *fwnode,
const struct iommu_ops *ops)
{
int ret = iommu_fwspec_init(dev, fwnode, ops);
if (!ret)
ret = iommu_fwspec_add_ids(dev, &streamid, 1);
return ret;
}
首先调用iommu_fwspec_init 来为dev->iommu_fwspec 申请空间
int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
const struct iommu_ops *ops)
{
struct iommu_fwspec *fwspec = dev->iommu_fwspec;
if (fwspec)
return ops == fwspec->ops ? 0 : -EINVAL;
fwspec = kzalloc(sizeof(*fwspec), GFP_KERNEL);
if (!fwspec)
return -ENOMEM;
of_node_get(to_of_node(iommu_fwnode));
//给fwspec 赋值
fwspec->iommu_fwnode = iommu_fwnode;
fwspec->ops = ops;
//保存到dev->iommu_fwspec 中
dev->iommu_fwspec = fwspec;
return 0;
}
这个函数的第三个参数,针对arm来讲的话,就是arm_smmu_ops。
第一次申请的时候fwspec肯定是NULL,因此调用kzalloc 申请空间并清零.由于我们是ACPI 模式,因此of_node_get(to_of_node(iommu_fwnode));都是空函数
这里给fwspec 赋值后,再保存到dev->iommu_fwspec 中。
回到arm_smmu_iort_xlate 中调用iommu_fwspec_init 成功申请iommu_fwspec空间然后赋值,最后保存到dev->iommu_fwspec 中之后,就调用iommu_fwspec_add_ids
int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
{
struct iommu_fwspec *fwspec = dev->iommu_fwspec;
size_t size;
int i;
if (!fwspec)
return -EINVAL;
size = offsetof(struct iommu_fwspec, ids[fwspec->num_ids + num_ids]);
if (size > sizeof(*fwspec)) {
fwspec = krealloc(dev->iommu_fwspec, size, GFP_KERNEL);
if (!fwspec)
return -ENOMEM;
}
for (i = 0; i < num_ids; i++)
fwspec->ids[fwspec->num_ids + i] = ids[i];
fwspec->num_ids += num_ids;
dev->iommu_fwspec = fwspec;
return 0;
}
从arm_smmu_iort_xlate 中可以知道iommu_fwspec_add_ids的第二个参数ids代表的是streamid,第三个参数num_ids 等于1
在iommu_fwspec_add_ids 中将streamid添加到fwspec->ids 这个数组中,饭后更新整个dev中包含的streamid的个数,然后重新更新dev->iommu_fwspec。
在code中对iommu_fwspec的使用除了获取streadid外,还会通过iommu_fwspec->iommu_priv 得到 arm_smmu_device
用法如下:
struct arm_smmu_device *smmu;
struct arm_smmu_master_data *master;
struct arm_smmu_strtab_ent *ste;
if (!dev->iommu_fwspec)
return -ENOENT;
master = dev->iommu_fwspec->iommu_priv;
smmu = master->smmu;
ste = &master->ste;
这样就可以通过iommu_fwspec 得到arm_smmu_master_data,再从arm_smmu_master_data 中得到arm_smmu_device和arm_smmu_strtab_ent
总结一下,dev->iommu_fwspec 保存这个dev和smmu相关的信息.
static int arm_smmu_iort_xlate(struct device *dev, u32 streamid,
struct fwnode_handle *fwnode,
const struct iommu_ops *ops)
{
int ret = iommu_fwspec_init(dev, fwnode, ops);
if (!ret)
ret = iommu_fwspec_add_ids(dev, &streamid, 1);
return ret;
}
首先调用iommu_fwspec_init 来为dev->iommu_fwspec 申请空间
int iommu_fwspec_init(struct device *dev, struct fwnode_handle *iommu_fwnode,
const struct iommu_ops *ops)
{
struct iommu_fwspec *fwspec = dev->iommu_fwspec;
if (fwspec)
return ops == fwspec->ops ? 0 : -EINVAL;
fwspec = kzalloc(sizeof(*fwspec), GFP_KERNEL);
if (!fwspec)
return -ENOMEM;
of_node_get(to_of_node(iommu_fwnode));
//给fwspec 赋值
fwspec->iommu_fwnode = iommu_fwnode;
fwspec->ops = ops;
//保存到dev->iommu_fwspec 中
dev->iommu_fwspec = fwspec;
return 0;
}
这个函数的第三个参数,针对arm来讲的话,就是arm_smmu_ops。
第一次申请的时候fwspec肯定是NULL,因此调用kzalloc 申请空间并清零.由于我们是ACPI 模式,因此of_node_get(to_of_node(iommu_fwnode));都是空函数
这里给fwspec 赋值后,再保存到dev->iommu_fwspec 中。
回到arm_smmu_iort_xlate 中调用iommu_fwspec_init 成功申请iommu_fwspec空间然后赋值,最后保存到dev->iommu_fwspec 中之后,就调用iommu_fwspec_add_ids
int iommu_fwspec_add_ids(struct device *dev, u32 *ids, int num_ids)
{
struct iommu_fwspec *fwspec = dev->iommu_fwspec;
size_t size;
int i;
if (!fwspec)
return -EINVAL;
size = offsetof(struct iommu_fwspec, ids[fwspec->num_ids + num_ids]);
if (size > sizeof(*fwspec)) {
fwspec = krealloc(dev->iommu_fwspec, size, GFP_KERNEL);
if (!fwspec)
return -ENOMEM;
}
for (i = 0; i < num_ids; i++)
fwspec->ids[fwspec->num_ids + i] = ids[i];
fwspec->num_ids += num_ids;
dev->iommu_fwspec = fwspec;
return 0;
}
从arm_smmu_iort_xlate 中可以知道iommu_fwspec_add_ids的第二个参数ids代表的是streamid,第三个参数num_ids 等于1
在iommu_fwspec_add_ids 中将streamid添加到fwspec->ids 这个数组中,饭后更新整个dev中包含的streamid的个数,然后重新更新dev->iommu_fwspec。
在code中对iommu_fwspec的使用除了获取streadid外,还会通过iommu_fwspec->iommu_priv 得到 arm_smmu_device
用法如下:
struct arm_smmu_device *smmu;
struct arm_smmu_master_data *master;
struct arm_smmu_strtab_ent *ste;
if (!dev->iommu_fwspec)
return -ENOENT;
master = dev->iommu_fwspec->iommu_priv;
smmu = master->smmu;
ste = &master->ste;
这样就可以通过iommu_fwspec 得到arm_smmu_master_data,再从arm_smmu_master_data 中得到arm_smmu_device和arm_smmu_strtab_ent
总结一下,dev->iommu_fwspec 保存这个dev和smmu相关的信息.