設備樹DTS 學習:Linux DTS文件加載過程


背景

了解機制有利於對內核有更深的認識。

wget https://mirrors.aliyun.com/linux-kernel/v3.x/linux-3.2.61.tar.xz

內核

  1. 在drivers/of/fdt.c 中有如下初始化函數 注釋上:展開設備樹,創建device_nodes到全局變量allnodes中

Linux不同內核版本的 fdt.c 文件在不同的地方,使用 find | grep fdt.c 進行查找

/**
 * unflatten_device_tree - create tree of device_nodes from flat blob
 *
 * unflattens the device-tree passed by the firmware, creating the
 * tree of struct device_node. It also fills the "name" and "type"
 * pointers of the nodes so the normal device-tree walking functions
 * can be used.
 */

void __init unflatten_device_tree(void)
{
    __unflatten_device_tree(initial_boot_params, &allnodes,
                early_init_dt_alloc_memory_arch);

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

unflatten_device_tree函數被setup_arch函數調用,因為我們使用的是arm平台所以存在arch\arm\kernel\setup.c中

void __init setup_arch(char **cmdline_p)
{
    ...
    unflatten_device_tree();
}

setup_arch函數在kernel啟動是被調用,如下啟動kernel存在init\main.c

asmlinkage void __init start_kernel(void)
{
    ...
    setup_arch(&command_line);
    ...
}

這些工作完成解析DTS文件。保存到全局鏈表allnodes中。

2、在arch/arm/boot/Makefile中有這段話來編譯dts文件:

$(obj)/A20%.dtb: $(src)/dts/A20%.dts FORCE
    $(call if_changed_dep,dtc)

$(obj)/A68M%.dtb: $(src)/dts/A68M%.dts FORCE
    $(call if_changed_dep,dtc)

3、
在 board-8226.c中有初始化函數-->啟動自動掉用
void __init msm8226_init(void)
{
of_platform_populate(NULL, of_default_bus_match_table, adata, NULL);
}

of_platform_populate在kernel\driver\of\platform.c中定義,回查詢

root = root ? of_node_get(root) : of_find_node_by_path("/");
for_each_child_of_node(root, child)
    {
    rc = of_platform_bus_create(child, matches, lookup, parent, true);
    if (rc)
        break;
}
of_node_put(root);

在這里用到得函數of_find_node_by_path會最終調用到kernel\driver\of\base.c中得函數
struct device_node *of_find_node_by_path(const char *path)
{
遍歷第1步中得allnodes找到根節點
}

of_platform_bus_create()函數中創建得內容存在了 adata中。

(2)使用DTS注冊總線設備的過程
以高通8974平台為例,在注冊i2c總線時,會調用到qup_i2c_probe()接口,該接口用於申請總線資源和添加i2c適配器。在成功添加i2c適配器后,會調用of_i2c_register_devices()接口。此接口會解析i2c總線節點的子節點(掛載在該總線上的i2c設備節點),獲取i2c設備的地址、中斷號等硬件信息。然后調用request_module()加載設備對應的驅動文件,調用i2c_new_device(),生成i2c設備。此時設備和驅動都已加載,於是drvier里面的probe方法將被調用。后面流程就和之前一樣了。
簡而言之,Linux采用DTS描述設備硬件信息后,省去了大量板文件垃圾信息。Linux在開機啟動階段,會解析DTS文件,保存到全局鏈表allnodes中,在掉用.init_machine時,會跟據allnodes中的信息注冊平台總線和設備。值得注意的是,加載流程並不是按找從樹根到樹葉的方式遞歸注冊,而是只注冊根節點下的第一級子節點,第二級及之后的子節點暫不注冊。Linux系統下的設備大多都是掛載在平台總線下的,因此在平台總線被注冊后,會根據allnodes節點的樹結構,去尋找該總線的子節點,所有的子節點將被作為設備注冊到該總線上。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM