在iort_init_platform_devices 中会从iort_table 中找node type是ACPI_IORT_NODE_SMMU 或者ACPI_IORT_NODE_SMMU_V3 的node,如果找到就申请一个fwnode_handle 类型的空间
struct fwnode_handle *fwnode;
fwnode = acpi_alloc_fwnode_static();
iort_set_fwnode(iort_node, fwnode);
static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
{
struct fwnode_handle *fwnode;
fwnode = kzalloc(sizeof(struct fwnode_handle), GFP_KERNEL);
if (!fwnode)
return NULL;
fwnode->type = FWNODE_ACPI_STATIC;
return fwnode;
}
从acpi_alloc_fwnode_static 可以看出首先申请一个fwnode_handle *fwnode,然后给type赋值FWNODE_ACPI_STATIC
而fwnode_type 总共有下面这几种.
enum fwnode_type {
FWNODE_INVALID = 0,
FWNODE_OF,
FWNODE_ACPI,
FWNODE_ACPI_DATA,
FWNODE_ACPI_STATIC,
FWNODE_PDATA,
FWNODE_IRQCHIP
};
申请到fwnode_handle *fwnode 后再通过iort_set_fwnode 将fwnode 添加到iort_fwnode_list 中
static inline int iort_set_fwnode(struct acpi_iort_node *iort_node,
struct fwnode_handle *fwnode)
{
struct iort_fwnode *np;
np = kzalloc(sizeof(struct iort_fwnode), GFP_ATOMIC);
if (WARN_ON(!np))
return -ENOMEM;
INIT_LIST_HEAD(&np->list);
np->iort_node = iort_node;
np->fwnode = fwnode;
spin_lock(&iort_fwnode_lock);
list_add_tail(&np->list, &iort_fwnode_list);
spin_unlock(&iort_fwnode_lock);
return 0;
}
在iort_set_fwnode 中先申请一个iort_fwnode *np,然后分别给iort_node和fwnode 赋值,然后添加到iort_fwnode_list 中,后面就可以通过
static inline
struct fwnode_handle *iort_get_fwnode(struct acpi_iort_node *node)
{
struct iort_fwnode *curr;
struct fwnode_handle *fwnode = NULL;
spin_lock(&iort_fwnode_lock);
list_for_each_entry(curr, &iort_fwnode_list, list) {
if (curr->iort_node == node) {
fwnode = curr->fwnode;
break;
}
}
spin_unlock(&iort_fwnode_lock);
return fwnode;
}
来得到fwnode。总的来说fwnode_handle代表smmu 的firmware device node ,得到fwnode 后最终在iort_add_smmu_platform_device赋值给 pdev->dev.fwnode = fwnode; 总的感觉fwnode最大的作用还是用于匹配node。例如下面的code中欧给你就通过对比fwnode来的到iommu_ops
const struct iommu_ops *fwnode_iommu_get_ops(struct fwnode_handle *fwnode)
{
struct iommu_fwentry *node;
const struct iommu_ops *ops = NULL;
spin_lock(&iommu_fwentry_lock);
list_for_each_entry(node, &iommu_fwentry_list, list)
if (node->fwnode == fwnode) {
ops = node->ops;
break;
}
spin_unlock(&iommu_fwentry_lock);
return ops;
}
例如在fwnode_iommu_get_ops 中就是通过iommu_fwentry *node 是否等于fwnode_handle *fwnode 来得到device的iommu_ops。
与之对应的是
void fwnode_iommu_set_ops(struct fwnode_handle *fwnode,
const struct iommu_ops *ops)
{
struct iommu_fwentry *iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
if (WARN_ON(!iommu))
return;
if (is_of_node(fwnode))
of_node_get(to_of_node(fwnode));
INIT_LIST_HEAD(&iommu->list);
iommu->fwnode = fwnode;
iommu->ops = ops;
spin_lock(&iommu_fwentry_lock);
list_add_tail(&iommu->list, &iommu_fwentry_list);
spin_unlock(&iommu_fwentry_lock);
}
明显看到在iommu_fwentry *iommu 中将fwnode和ops绑定,后面就可以通过fwnode_iommu_get_ops 来查找iommu_fwentry_list 来得到iommu_ops
struct fwnode_handle *fwnode;
fwnode = acpi_alloc_fwnode_static();
iort_set_fwnode(iort_node, fwnode);
static inline struct fwnode_handle *acpi_alloc_fwnode_static(void)
{
struct fwnode_handle *fwnode;
fwnode = kzalloc(sizeof(struct fwnode_handle), GFP_KERNEL);
if (!fwnode)
return NULL;
fwnode->type = FWNODE_ACPI_STATIC;
return fwnode;
}
从acpi_alloc_fwnode_static 可以看出首先申请一个fwnode_handle *fwnode,然后给type赋值FWNODE_ACPI_STATIC
而fwnode_type 总共有下面这几种.
enum fwnode_type {
FWNODE_INVALID = 0,
FWNODE_OF,
FWNODE_ACPI,
FWNODE_ACPI_DATA,
FWNODE_ACPI_STATIC,
FWNODE_PDATA,
FWNODE_IRQCHIP
};
申请到fwnode_handle *fwnode 后再通过iort_set_fwnode 将fwnode 添加到iort_fwnode_list 中
static inline int iort_set_fwnode(struct acpi_iort_node *iort_node,
struct fwnode_handle *fwnode)
{
struct iort_fwnode *np;
np = kzalloc(sizeof(struct iort_fwnode), GFP_ATOMIC);
if (WARN_ON(!np))
return -ENOMEM;
INIT_LIST_HEAD(&np->list);
np->iort_node = iort_node;
np->fwnode = fwnode;
spin_lock(&iort_fwnode_lock);
list_add_tail(&np->list, &iort_fwnode_list);
spin_unlock(&iort_fwnode_lock);
return 0;
}
在iort_set_fwnode 中先申请一个iort_fwnode *np,然后分别给iort_node和fwnode 赋值,然后添加到iort_fwnode_list 中,后面就可以通过
static inline
struct fwnode_handle *iort_get_fwnode(struct acpi_iort_node *node)
{
struct iort_fwnode *curr;
struct fwnode_handle *fwnode = NULL;
spin_lock(&iort_fwnode_lock);
list_for_each_entry(curr, &iort_fwnode_list, list) {
if (curr->iort_node == node) {
fwnode = curr->fwnode;
break;
}
}
spin_unlock(&iort_fwnode_lock);
return fwnode;
}
来得到fwnode。总的来说fwnode_handle代表smmu 的firmware device node ,得到fwnode 后最终在iort_add_smmu_platform_device赋值给 pdev->dev.fwnode = fwnode; 总的感觉fwnode最大的作用还是用于匹配node。例如下面的code中欧给你就通过对比fwnode来的到iommu_ops
const struct iommu_ops *fwnode_iommu_get_ops(struct fwnode_handle *fwnode)
{
struct iommu_fwentry *node;
const struct iommu_ops *ops = NULL;
spin_lock(&iommu_fwentry_lock);
list_for_each_entry(node, &iommu_fwentry_list, list)
if (node->fwnode == fwnode) {
ops = node->ops;
break;
}
spin_unlock(&iommu_fwentry_lock);
return ops;
}
例如在fwnode_iommu_get_ops 中就是通过iommu_fwentry *node 是否等于fwnode_handle *fwnode 来得到device的iommu_ops。
与之对应的是
void fwnode_iommu_set_ops(struct fwnode_handle *fwnode,
const struct iommu_ops *ops)
{
struct iommu_fwentry *iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
if (WARN_ON(!iommu))
return;
if (is_of_node(fwnode))
of_node_get(to_of_node(fwnode));
INIT_LIST_HEAD(&iommu->list);
iommu->fwnode = fwnode;
iommu->ops = ops;
spin_lock(&iommu_fwentry_lock);
list_add_tail(&iommu->list, &iommu_fwentry_list);
spin_unlock(&iommu_fwentry_lock);
}
明显看到在iommu_fwentry *iommu 中将fwnode和ops绑定,后面就可以通过fwnode_iommu_get_ops 来查找iommu_fwentry_list 来得到iommu_ops