如何从内存中找acpi表子表,以iort为例

博主最新文章
博主热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)Linux 源码分析(636)
在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);
首先调用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_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_fwspec-&ops =//保存到dev-&iommu_fwspec 中dev-&iommu_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_size_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_ i++)fwspec-&ids[fwspec-&num_ids + i] = ids[i];fwspec-&num_ids += num_dev-&iommu_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 *struct arm_smmu_master_data *struct arm_smmu_strtab_ent *if (!dev-&iommu_fwspec)return -ENOENT;master = dev-&iommu_fwspec-&iommu_smmu = master-&ste = &master-&
这样就可以通过iommu_fwspec 得到arm_smmu_master_data,再从arm_smmu_master_data 中得到arm_smmu_device和arm_smmu_strtab_ent
总结一下,dev-&iommu_fwspec 保存这个dev和smmu相关的信息.博主最新文章
博主热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)Linux 源码分析(636)
在arch/arm64/mm/dma-mapping.c 中定义了三种dma的ops,分别是:dummy_dma_ops/swiotlb_dma_ops/iommu_dma_ops 。那kernel是如何选择iommu的呢?
如果acpi表中定义了IORT 子表的话,flow如下:
acpi_iort_init-&iort_init_platform_devices
static void __init iort_init_platform_devices(void)
if ((iort_node-&type == ACPI_IORT_NODE_SMMU) ||
(iort_node-&type == ACPI_IORT_NODE_SMMU_V3)) {
fwnode = acpi_alloc_fwnode_static();
if (!fwnode)
iort_set_fwnode(iort_node, fwnode);
ret = iort_add_smmu_platform_device(iort_node);
if (ret) {
iort_delete_fwnode(iort_node);
acpi_free_fwnode_static(fwnode);
从iort_init_platform_devices 中可以知道当前kernel同时support SMMU 和SMMUV3
iort_add_smmu_platform_device-&acpi_dma_configure-&arch_setup_dma_ops-&acpi_dma_configure
在acpi_dma_configure 中会调用arch_setup_dma_ops 这里需要注意attr == DEV_DMA_COHERENT
arch_setup_dma_ops(dev, 0, dev-&coherent_dma_mask + 1, iommu,
attr == DEV_DMA_COHERENT);
在arch_setup_dma_ops 函数中dev-&archdata.dma_ops == NULL
void arch_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
const struct iommu_ops *iommu, bool coherent)
if (!dev-&archdata.dma_ops)
dev-&archdata.dma_ops = &swiotlb_dma_
dev-&archdata.dma_coherent =
__iommu_setup_dma_ops(dev, dma_base, size, iommu);
我们这边暂时给dev-&archdata.dma_ops = &swiotlb_dma_ops 以防后面iommu赋值失败。这里继续调用__iommu_setup_dma_ops
static void __iommu_setup_dma_ops(struct device *dev, u64 dma_base, u64 size,
const struct iommu_ops *ops)
struct iommu_group *
* TODO: As a concession to the future, we're ready to handle being
* called both early and late (i.e. after bus_add_device). Once all
* the platform bus code is reworked to call us late and the notifier
* junk above goes away, move the body of do_iommu_attach here.
group = iommu_group_get(dev);
if (group) {
do_iommu_attach(dev, ops, dma_base, size);
iommu_group_put(group);
queue_iommu_attach(dev, ops, dma_base, size);
在__iommu_setup_dma_ops 中ops显然部位NULL,且group也不为null,因此调用do_iommu_attach
static bool do_iommu_attach(struct device *dev, const struct iommu_ops *ops,
u64 dma_base, u64 size)
struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
* If the IOMMU driver has the DMA domain support that we require,
* then the IOMMU core will have already configured a group for this
* device, and allocated the default domain for that group.
if (!domain || iommu_dma_init_domain(domain, dma_base, size, dev)) {
pr_warn("Failed to set up IOMMU for device %s; retaining platform DMA ops\n",
dev_name(dev));
dev-&archdata.dma_ops = &iommu_dma_
哈哈哈,在do_iommu_attach 中终于赋值了dev-&archdata.dma_ops = &iommu_dma_博主最新文章
博主热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)

我要回帖

更多关于 acpi驱动 的文章

 

随机推荐