device_node和platform_device的生成流程

1. machine_desc的匹配

《这篇》有介绍DT_MACHINE_START的一些初始化操作,匹配上就会在后续的初始化中调用DT_MACHINE_START的成员来初始化系统的设备树,时钟,中断等

start_kernel
    setup_arch(&command_line);
		mdesc = setup_machine_fdt(atags_vaddr) //返回成功匹配的machine_desc
        ....
        unflatten_device_tree(); //将设备树解析成device_node

1.1 setup_machine_fdt

early_init_dt_verify校验设备树,和初始化设备树指针;然后of_flat_dt_match_machine匹配MACHINE_START定义machine_desc和设备树

const struct machine_desc * __init setup_machine_fdt(void *dt_virt)
{
	const struct machine_desc *mdesc, *mdesc_best = NULL;
 
#if defined(CONFIG_ARCH_MULTIPLATFORM) || defined(CONFIG_ARM_SINGLE_ARMV7M)
	DT_MACHINE_START(GENERIC_DT, "Generic DT based system")
		.l2c_aux_val = 0x0,
		.l2c_aux_mask = ~0x0,
	MACHINE_END
 
	mdesc_best = &__mach_desc_GENERIC_DT;
#endif
 
	if (!dt_virt || !early_init_dt_verify(dt_virt))
		return NULL;
 
	mdesc = of_flat_dt_match_machine(mdesc_best, arch_get_next_mach);
 
	if (!mdesc) {
		const char *prop;
		int size;
		unsigned long dt_root;
 
		early_print("\nError: unrecognized/unsupported "
			    "device tree compatible list:\n[ ");
 
		dt_root = of_get_flat_dt_root();
		prop = of_get_flat_dt_prop(dt_root, "compatible", &size);
		while (size > 0) {
			early_print("'%s' ", prop);
			size -= strlen(prop) + 1;
			prop += strlen(prop) + 1;
		}
		early_print("]\n\n");
 
		dump_machine_table(); /* does not return */
	}
 
	/* We really don't want to do this, but sometimes firmware provides buggy data */
	if (mdesc->dt_fixup)
		mdesc->dt_fixup();
	early_init_dt_scan_nodes();
	/* Change machine number to match the mdesc we're using */
	__machine_arch_type = mdesc->nr;
 
	return mdesc;
}

1.2 early_init_dt_verify

将设备树指针给到initial_boot_params,供后续直接对设备树操作的api使用

bool __init early_init_dt_verify(void *params)
{
	if (!params)
		return false;

	/* check device tree validity */
	if (fdt_check_header(params))
		return false;

	/* Setup flat device-tree pointer */
	initial_boot_params = params;
	of_fdt_crc32 = crc32_be(~0, initial_boot_params,
				fdt_totalsize(initial_boot_params));
	return true;
}

1.3 of_flat_dt_match_machine

of_flat_dt_match去匹配设备树跟machine_desc的dt_compat成员

const void * __init of_flat_dt_match_machine(const void *default_match,
		const void * (*get_next_compat)(const char * const**))
{
	const void *data = NULL;
	const void *best_data = default_match;
	const char *const *compat;
	unsigned long dt_root;
	unsigned int best_score = ~1, score = 0;

	dt_root = of_get_flat_dt_root();
	while ((data = get_next_compat(&compat))) {
		score = of_flat_dt_match(dt_root, compat);
		if (score > 0 && score < best_score) {
			best_data = data;
			best_score = score;
		}
	}
	if (!best_data) {
		const char *prop;
		int size;

		pr_err("\n unrecognized device tree list:\n[ ");

		prop = of_get_flat_dt_prop(dt_root, "compatible", &size);
		if (prop) {
			while (size > 0) {
				printk("'%s' ", prop);
				size -= strlen(prop) + 1;
				prop += strlen(prop) + 1;
			}
		}
		printk("]\n\n");
		return NULL;
	}

	pr_info("Machine model: %s\n", of_flat_dt_get_machine_name());

	return best_data;
}

1.4 of_flat_dt_match

of_fdt_is_compatible通过设备树指针initial_boot_params找到兼容属性

static int __init of_flat_dt_match(unsigned long node, const char *const *compat)
{
	unsigned int tmp, score = 0;

	if (!compat)
		return 0;

	while (*compat) {
		tmp = of_fdt_is_compatible(initial_boot_params, node, *compat);
		if (tmp && (score == 0 || (tmp < score)))
			score = tmp;
		compat++;
	}

	return score;
}

1.5 of_fdt_is_compatible

通过fdt_getprop直接获取compatible 属性,并比较字符串来看匹配上没

static int of_fdt_is_compatible(const void *blob,
		      unsigned long node, const char *compat)
{
	const char *cp;
	int cplen;
	unsigned long l, score = 0;

	cp = fdt_getprop(blob, node, "compatible", &cplen);
	if (cp == NULL)
		return 0;
	while (cplen > 0) {
		score++;
		if (of_compat_cmp(cp, compat, strlen(compat)) == 0)
			return score;
		l = strlen(cp) + 1;
		cp += l;
		cplen -= l;
	}

	return 0;
}

2. device_node的生成

通过上面赋值的initial_boot_params,去将设备树解析成device_node结构的树

void __init unflatten_device_tree(void)
{
	__unflatten_device_tree(initial_boot_params, NULL, &of_root,
				early_init_dt_alloc_memory_arch, false);

	/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
	of_alias_scan(early_init_dt_alloc_memory_arch);

	unittest_unflatten_overlay_base();
}

2.1 unflatten_dt_nodes

通过populate_node填充device_node

static int unflatten_dt_nodes(const void *blob,
			      void *mem,
			      struct device_node *dad,
			      struct device_node **nodepp)
{
	struct device_node *root;
	int offset = 0, depth = 0, initial_depth = 0;
#define FDT_MAX_DEPTH	64
	struct device_node *nps[FDT_MAX_DEPTH];
	void *base = mem;
	bool dryrun = !base;

	if (nodepp)
		*nodepp = NULL;

	/*
	 * We're unflattening device sub-tree if @dad is valid. There are
	 * possibly multiple nodes in the first level of depth. We need
	 * set @depth to 1 to make fdt_next_node() happy as it bails
	 * immediately when negative @depth is found. Otherwise, the device
	 * nodes except the first one won't be unflattened successfully.
	 */
	if (dad)
		depth = initial_depth = 1;

	root = dad;
	nps[depth] = dad;

	for (offset = 0;
	     offset >= 0 && depth >= initial_depth;
	     offset = fdt_next_node(blob, offset, &depth)) {
		if (WARN_ON_ONCE(depth >= FDT_MAX_DEPTH))
			continue;

		if (!IS_ENABLED(CONFIG_OF_KOBJ) &&
		    !of_fdt_device_is_available(blob, offset))
			continue;

		if (!populate_node(blob, offset, &mem, nps[depth],
				   &nps[depth+1], dryrun))
			return mem - base;

		if (!dryrun && nodepp && !*nodepp)
			*nodepp = nps[depth+1];
		if (!dryrun && !root)
			root = nps[depth+1];
	}

	if (offset < 0 && offset != -FDT_ERR_NOTFOUND) {
		pr_err("Error %d processing FDT\n", offset);
		return -EINVAL;
	}

	/*
	 * Reverse the child list. Some drivers assumes node order matches .dts
	 * node order
	 */
	if (!dryrun)
		reverse_nodes(root);

	return mem - base;
}

2.2 populate_node

unflatten_dt_alloc分配节点,并通过populate_properties填充各属性

static bool populate_node(const void *blob,
			  int offset,
			  void **mem,
			  struct device_node *dad,
			  struct device_node **pnp,
			  bool dryrun)
{
	struct device_node *np;
	const char *pathp;
	unsigned int l, allocl;

	pathp = fdt_get_name(blob, offset, &l);
	if (!pathp) {
		*pnp = NULL;
		return false;
	}

	allocl = ++l;

	np = unflatten_dt_alloc(mem, sizeof(struct device_node) + allocl,
				__alignof__(struct device_node));
	if (!dryrun) {
		char *fn;
		of_node_init(np);
		np->full_name = fn = ((char *)np) + sizeof(*np);

		memcpy(fn, pathp, l);

		if (dad != NULL) {
			np->parent = dad;
			np->sibling = dad->child;
			dad->child = np;
		}
	}

	populate_properties(blob, offset, mem, np, pathp, dryrun);
	if (!dryrun) {
		np->name = of_get_property(np, "name", NULL);
		if (!np->name)
			np->name = "<NULL>";
	}

	*pnp = np;
	return true;
}

3. paltform_device的生成

3.1 init_machine

MACHINE_START中含有一个.dt_compat成员,根据设备树的compatible属性来--锚定具体的machine_desc,;后续也会用init_machine来通过of_platform_populate,构造platfoem_device

static void __init xxx_dt_init_machine(void)
{
        /* mmp_entry_vector_init(); */

        of_platform_populate(NULL, of_default_bus_match_table,
                             xxx_auxdata_lookup, NULL);

}

static const char *XXX_dt_board_compat[] __initdata = {
        "id-xxx,id-yyy",
        NULL,
};

DT_MACHINE_START(XXX_DT, "XXX (Device Tree Support)")
        .map_io         = mmp_map_io,
        .init_irq       = irqchip_init,
        .init_time      = xxx_init_time,
        .reserve        = xxx_reserve,
        .init_machine   = xxx_dt_init_machine,
        .dt_compat      = xxx_dt_board_compat,
        .restart        = xxx_arch_restart,
MACHINE_END

3.2 什么时候生成

系统初始化跑完了,在最后会执行kernel_init这个1号进程;去初始化initcall,和其他的一些初始化操作,最后成为用户层的init进程

start_kernel
    arch_call_rest_init
        kernel_init
            kernel_init_freeable
                do_basic_setup()
                    do_initcalls()

static int __init customize_machine(void)
{
        /*
         * customizes platform devices, or adds new ones
         * On DT based machines, we fall back to populating the
         * machine from the device tree, if no callback is provided,
         * otherwise we would always need an init_machine callback.
         */
        if (machine_desc->init_machine)
                machine_desc->init_machine();

        return 0;
}
arch_initcall(customize_machine);

3.3 什么节点会被生成

1.一般情况下,只对设备树中根的一级子节点进行转换,也就是多级子节点(子节点的子节点)并不处理。

2.但是存在一种特殊情况,就是当某个根子节点的compatible属性为"simple-bus"、"simple-mfd"、"isa"、"arm,amba-bus"时,当前节点中的一级子节点将会被转换成platform_device节点。

3.节点中必须有compatible属性。

const struct of_device_id of_default_bus_match_table[] = {
	{ .compatible = "simple-bus", },
	{ .compatible = "simple-mfd", },
	{ .compatible = "isa", },
#ifdef CONFIG_ARM_AMBA
	{ .compatible = "arm,amba-bus", },
#endif /* CONFIG_ARM_AMBA */
	{} /* Empty terminated list */
};

3.4 生成platfoem_device

终于到了产生platfoem_device地方:

(1)不再直接使用设备树,而是使用前面生成的device_node 

(2)matches作为匹配表(of_default_bus_match_table); lookup作为platform_data(xxx_auxdata_lookup)

(3)生成细节见我们的《这篇》

int of_platform_populate(struct device_node *root,
			const struct of_device_id *matches,
			const struct of_dev_auxdata *lookup,
			struct device *parent)
{
	struct device_node *child;
	int rc = 0;

	root = root ? of_node_get(root) : of_find_node_by_path("/");
	if (!root)
		return -EINVAL;

	pr_debug("%s()\n", __func__);
	pr_debug(" starting at: %pOF\n", root);

	for_each_child_of_node(root, child) {
		rc = of_platform_bus_create(child, matches, lookup, parent, true);
		if (rc) {
			of_node_put(child);
			break;
		}
	}
	of_node_set_flag(root, OF_POPULATED_BUS);

	of_node_put(root);
	return rc;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/761770.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何在本地一键配置最强国产大模型

自从OpenAI的ChatGPT横空出世以来&#xff0c;国内外各类大语言模型&#xff08;LLM&#xff09;层出不穷&#xff0c;其中不乏Google的Gemini、Claude、文心一言等等。相较于竞争激烈的商业模型赛道&#xff0c;以Llama为代表的开源大模型的进步速度也十分惊人。 伴随着大语言…

ANSYS新能源汽车动力电池仿真应用案例

燃料电池是一种非燃烧过程的电化学能转换装置&#xff0c;将氢气&#xff08;等燃料&#xff09;和氧气的化学能连续不断地转换为电能&#xff0c;是发电设备而非储能设备。 根据电解质的不同&#xff0c;分为碱性燃料电池AFC、磷酸燃料电池PAFC、熔融碳酸盐燃料电池MCFC、固体…

微机原理 复习

第一章导论 1.3 冯诺依曼体系结构 &#xff08;1&#xff09;以二进制形式表示指令和数据 &#xff08;2&#xff09;程序和数据事先放在存储器中&#xff08;预存储&#xff09; &#xff08;3&#xff09;由运算器、控制器、输入设备和输出设备五大部件组成 字长、主频…

css实现一个三角形

实现不用方向的三角形可根据border进行设置。具体代码如下&#xff1a; .triangle-up {width: 0;height: 0;border-top: 10px solid transparent;border-left: 10px solid transparent;border-right: 10px solid transparent;border-bottom: 10px solid black;}.triangle-rig…

6-14题连接 - 高频 SQL 50 题基础版

目录 1. 相关知识点2. 例子2.6. 使用唯一标识码替换员工ID2.7- 产品销售分析 I2.8 - 进店却未进行过交易的顾客2.9 - 上升的温度2.10 - 每台机器的进程平均运行时间2.11- 员工奖金2.12-学生们参加各科测试的次数2.13-至少有5名直接下属的经理2.14 - 确认率 1. 相关知识点 left …

Redis Cluster 模式 的具体实施细节是什么样的?

概述 参考&#xff1a;What are Redis Cluster and How to setup Redis Cluster locally ? | by Rajat Pachauri | Medium Redis Cluster 的工作原理是将数据分布在多个节点上&#xff0c;同时确保高可用性和容错能力。以下是 Redis Cluster 运行方式的简要概述&#xff1a; …

Vue 快速入门案例

步骤一&#xff1a;引入vue.js文件 添加<script>标签并标明路径 步骤二&#xff1a;定义Vue对象 el Vue接管区域 data 定义数据模型 步骤三&#xff1a;编写视图层的展示 v-model 绑定数据模型 {{要展示的数据模型}} 运行效果 总结 文本框里的值&a…

欢太主题商店 官方资源提取与应用第三方资源方法一览

前言叠甲&#xff1a;支持正版&#xff0c;尊重他人劳动成果&#xff0c;反对盗版提取&#xff0c;不要传播提取版&#xff0c;我本人也在支持正版&#xff0c;但是最近懒得用主题&#xff0c;用一段时间的默认吧&#xff0c;如有主题开发者不满&#xff0c;请联系删除 &#x…

湖南省教育网络协会莅临麒麟信安调研教育网络数字化建设及教育信创发展情况

6月28日下午&#xff0c;湖南省教育网络协会理事长张智勇、秘书长刘志勇、副理事长黄旭、胡洪波、周中伟等协会相关负责人一行莅临麒麟信安&#xff0c;就湖南省教育网络数字化建设、教育信创工作等主题进行深入调研。麒麟信安副总裁王攀热情接待。 协会成员一行来到麒麟信安展…

让企业更进一步:AAA信用企业认证详解

AAA信用企业认证是企业在市场竞争中展示其信用和实力的重要方式&#xff0c;它不仅能够提升企业的公信力&#xff0c;还有助于企业在多方面获得竞争优势。以下是对AAA信用企业认证的详细解释&#xff1a; AAA信用企业认证的定义 AAA信用企业认证&#xff0c;又称3A认证&#…

《数据安全技术的数据分类分级规则》解析

数据安全技术的数据分类分级规则是一项国家标准&#xff0c;用于指导和规范数据分类与分级的方法和标准&#xff0c;以保障数据的安全性和保密性。该标准明确了数据分类与分级的基本原则&#xff0c;包括业务相关性、数据敏感性、风险可控性等。具体而言&#xff0c;数据分类应…

【UE5.1】Chaos物理系统基础——01 创建可被破坏的物体

目录 步骤 一、通过笔刷创建静态网格体 二、破裂静态网格体 三、“统一” 多层级破裂 四、“簇” 群集化的破裂 五、几何体集的材质 六、防止几何体集自动破碎 步骤 一、通过笔刷创建静态网格体 1. 可以在Quixel Bridge中下载两个纹理&#xff0c;用于表示石块的内外纹…

MySQL中的常用逻辑操作符

逻辑运算符在MySQL查询中扮演着重要角色&#xff0c;通过AND、OR、NOT等运算符的组合使用&#xff0c;可以提高查询的准确性和灵活性&#xff0c;确保查询结果满足业务需求。合理使用这些运算符还能优化查询性能&#xff0c;减少不必要的数据检索&#xff0c;并提高SQL语句的可…

SpringBoot创建一个初始化项目

提示&#xff1a;这一篇文章&#xff0c;主要是为了之后可以快速的去搭建项目&#xff0c;当然这篇博客&#xff0c;作者也会根据以后学习到的东西&#xff0c;慢慢去整理 文章目录 前言 搭建一个SpringBoot项目&#xff0c;目的是为了快速开发项目 项目列表 响应枚举类 /***…

AI奥林匹克竞赛:Claude-3.5-Sonnet对决GPT-4o,谁是最聪明的AI?

目录 实验设置 评估对象 评估方法 结果与分析 针对学科的细粒度分析 GPT-4o vs. Claude-3.5-Sonnet GPT-4V vs. Gemini-1.5-Pro 结论 AI技术日新月异&#xff0c;Anthropic公司最新发布的Claude-3.5-Sonnet因在知识型推理、数学推理、编程任务及视觉推理等任务上设立新…

网络攻防题录集

文章目录 第一章 网络攻防概述第二章 密码学第三章 网络协议脆弱性分析第四 自测题三第五章 自测题五第六章 自测题六第七章 自测题七第八章 自测题八第九章 自测题九第十章 自测题十第十一章 自测题十一第十二章 自测题十二第十三章 自测题十三 第一章 网络攻防概述 第一代安…

Anti-Canine Heartworm Antibody (Chicken) - HRP Conjugated

犬心丝虫&#xff08;学名Dirofilaria immitis&#xff09;是一种寄生丝虫&#xff0c;通过蚊子叮咬而传播。感染犬在早期阶段&#xff0c;大多不会出现症状。随着病情发展&#xff0c;将出现咳嗽、呼吸困难等症状&#xff0c;并伴有右心功能衰竭&#xff0c;最终全身衰弱或虚脱…

2008-2022年款哈弗维修手册和电路图线路图接线图资料更新

经过整理&#xff0c;2005-2022年款长城哈弗全系列已经更新至汽修帮手资料库内&#xff0c;覆盖市面上99%车型&#xff0c;包括维修手册、电路图、新车特征、车身钣金维修数据、全车拆装、扭力、发动机大修、发动机正时、保养、电路图、针脚定义、模块传感器、保险丝盒图解对照…

关于windows,wifi图标显示不了的解决方法

解决方法一&#xff08;解决了我的问题的方法&#xff09;&#xff1a; winr -->输入 regedit 打开注册表 --> 删除HKEY-CLASSES_ROOT\CLSID\{3d09c1ca-2bcc-40b7-b9bb-3f3ec143a87b} CLSID在下面仔细找&#xff0c;然后找到09开头那个删掉重启就可以了&#xff0c;可能…

工程师这几招降低电机EMI的方法,提高系统电磁兼容性能

通过在电机端子之间放置陶瓷电容器、工模滤波器或BDL滤波器均可抑制差模和共模噪声&#xff0c;以提高系统的EMC性能。工程师在本文详细介绍这几种降低电机EMI的方法。 EMC和EMI背景 电磁干扰(EMI)是系统上的电磁噪声的辐射或感应。与大多数电磁电路组件一样&#xff0c;直流…