2026/10/24 1:23:05

QorIQ平台ONIE内核回移植:从4.14到5.15的驱动适配与设备树实战

QorIQ平台ONIE内核回移植:从4.14到5.15的驱动适配与设备树实战 1. 为什么要在QorIQ平台上折腾ONIE内核回移植白盒交换机这个概念这几年在数据中心和园区网里越来越热核心逻辑就是把硬件和软件解耦硬件买通用的软件自己选。ONIEOpen Network Install Environment就是这套玩法里的关键一环它本质上是一个微型的Linux引导环境负责在裸机交换机上发现、加载并安装网络操作系统NOS。而ONLOpen Network Linux则是另一个层面的东西它是一个开源的交换机操作系统基础框架提供了完整的Linux用户空间和内核补丁让上层NOS能跑起来。问题来了。ONIE和ONL的官方代码库主线支持的内核版本和硬件平台是跟着社区节奏走的。社区里最活跃的往往是那些大批量出货的芯片方案比如某些主流商用交换芯片搭配的ARM或x86平台。而NXP QorIQ系列——尤其是P系列和T系列——在工业控制、军工、通信基础设施里用得很多但在白盒交换机这个圈子里它的社区支持就没那么及时了。你手里可能有一块基于QorIQ T2080或者P2041的板子硬件规格不错有万兆口有PCIe有SATA但你兴冲冲去拉最新的ONL代码发现内核版本是5.10甚至6.1而NXP官方为QorIQ提供的内核BSP可能还停留在4.9或者4.14。这就是典型的“硬件在跑软件追不上”的局面。内核回移植backport就是解决这个错位的手段。简单说就是把新内核里的驱动、子系统、设备树绑定这些玩意儿搬回老内核里去让老内核能认识新硬件或者让新用户空间能在老内核上跑起来。在ONIE/ONL这个场景里回移植的目标通常有两个方向一是把ONL新内核里的网络驱动、I2C驱动、GPIO驱动回移到NXP的BSP内核上二是把ONIE的安装环境适配到QorIQ的启动流程里包括U-Boot环境变量、设备树传递、根文件系统加载方式这些。我这次要聊的就是基于一个模拟的QorIQ T系列平台把ONIE和ONL的内核部分做一次系统性的回移植。整个过程涉及内核配置、驱动移植、设备树修改、启动脚本适配、根文件系统构建这几个大块。适合谁看如果你手头有QorIQ板子想跑白盒交换机系统或者你在做嵌入式Linux的BSP维护需要把新内核特性搬到老内核上这篇文章里的思路和踩坑记录应该能帮你省不少时间。2. 整体方案设计与核心思路拆解2.1 回移植还是前移植这是个问题在动手之前得先想清楚方向。所谓“回移植”字面意思是从新到旧。但实际操作中你面临的选择往往不是单向的。假设ONL主线用的是Linux 5.15NXP官方BSP是Linux 4.14。你有两个选择方案A把ONL的驱动和补丁往前移植到4.14上。这就是标准的backport。好处是NXP的BSP经过了大量板级验证电源管理、时钟树、DDR初始化这些底层东西很稳。坏处是4.14缺少很多新内核的API比如devm_gpiod_get的某些变体、phylink框架的完整实现、device_property_read系列函数你得一个个补。方案B把NXP的BSP补丁往后移植到5.15上。这叫forward port。好处是能用上新内核的网络栈、新驱动模型、更好的调试工具。坏处是NXP的BSP补丁往往和特定内核版本耦合很深尤其是涉及SoC初始化、SerDes配置、DPAAData Path Acceleration Architecture这些部分往后移植的工作量可能比重写还大。我这次选的是方案A理由很实际QorIQ的DPAA网络加速单元在4.14上的驱动是NXP原厂调过的性能数据齐全而5.15上的DPAA驱动社区版还有不少坑。白盒交换机对网络转发性能敏感我不想在驱动层面引入不确定性。所以策略就是以NXP 4.14 BSP为底座把ONL 5.15里需要的驱动和子系统回移植过来。2.2 需要回移植哪些东西不是所有东西都值得回移植。得先做减法。ONL的内核补丁集里真正和QorIQ平台相关的其实就几类第一类是网络驱动。ONL支持很多交换芯片但QorIQ板子上的万兆口通常走的是SoC内部的DPAA或者外挂的PHY。这部分NXP BSP里已经有了不需要动。但ONL可能引入了一些ethtool的扩展特性、switchdev的框架支持这些在4.14里可能不完整需要补。第二类是I2C和GPIO驱动。白盒交换机上有很多I2C设备SFP模块的EEPROM、温度传感器、风扇控制器、LED驱动器。ONL里有一套通用的SFP和光模块管理框架依赖i2c-dev、gpio-consumer这些接口。4.14的I2C核心和GPIO核心已经比较完善了但ONL可能用了一些新的设备树绑定方式比如gpio-line-names、i2c-mux的级联配置这些需要确认兼容性。第三类是MTD和SPI驱动。ONIE的安装环境通常放在SPI NOR或者NAND里QorIQ的eSPI控制器在4.14里有驱动但ONL可能用了spi-nor的新特性比如4-byte addressing、SFDP解析这些在4.14里可能不全。第四类是PCIe和SATA。如果板子上有外挂的交换芯片或者SSDPCIe枚举和SATA AHCI的驱动得确保能用。4.14的PCIe驱动对QorIQ的支持是OK的但ONL可能加了pcieport服务的某些补丁用于热插拔或者错误报告。第五类是内核配置选项。ONL的defconfig里开了一堆CONFIG_NET_SWITCHDEV、CONFIG_PHYLINK、CONFIG_SFP、CONFIG_HWMON之类的选项这些在NXP的defconfig里可能是关的。回移植的时候得把这些选项打开同时解决依赖关系。2.3 设备树怎么处理设备树是回移植里最烦人的部分因为它是硬件描述和驱动匹配的桥梁。ONL的设备树通常是给特定白盒交换机写的里面的节点命名、compatible字符串、phy-handle引用和NXP BSP里的设备树风格可能不一样。我的做法是以NXP BSP的设备树为骨架把ONL设备树里和交换功能相关的节点“嫁接”过来。比如ONL可能定义了一个sfp0节点里面有i2c-bus、gpio、eeprom这些子节点。我需要把这些节点加到NXP设备树的I2C控制器下面同时确保gpio的phandle指向正确的GPIO控制器。这里有个坑NXP的GPIO控制器在4.14里可能用的是fsl,qoriq-gpio这个compatible而ONL的设备树里可能写的是fsl,mpc8572-gpio或者别的。得统一成BSP里实际注册的compatible否则驱动probe会失败。另一个坑是中断映射。QorIQ的中断控制器是fsl,mpicONL设备树里如果用了interrupt-parent指向别的控制器得改过来。还有msi-parent如果PCIe设备要用MSI中断得确保MPIC的MSI控制器节点存在且被引用。2.4 启动流程的适配ONIE的启动流程和普通Linux发行版不太一样。它通常由U-Boot加载一个内核和initramfs然后initramfs里的脚本去发现安装源可能是USB、TFTP、HTTP最后把NOS写到存储里。在QorIQ平台上U-Boot的环境变量、启动参数、设备树传递方式都得调整。关键点有几个一是bootargs里要指定正确的控制台、根文件系统位置、init路径。二是bootcmd要能根据ONIE的启动模式install、rescue、uninstall加载不同的镜像。三是设备树里的chosen节点要包含stdout-path否则内核找不到控制台。四是如果用了secure boot还得处理签名验证不过这个在开发阶段可以先跳过。3. 核心细节解析与实操要点3.1 内核源码的获取与基线选择第一步是搞到两份源码NXP的BSP内核和ONL的内核。NXP的BSP通常可以从其官方Git仓库或者SDK里拿到版本号类似linux-4.14.xx。ONL的内核源码在ONL的GitHub仓库里路径一般是packages/base/linux/下面有对应的内核版本和补丁集。我建议的做法是先建一个干净的Git仓库把NXP BSP的代码作为master分支。然后从ONL的仓库里把内核补丁导出来用git format-patch生成一系列patch文件。接着在NXP的代码上创建一个backport分支逐个git am这些补丁。不要一次性全打上去那样冲突会让你怀疑人生。按子系统分批打先打网络相关的再打I2C/GPIO的最后打MTD/SPI的。注意ONL的补丁集里有些是给特定交换芯片的驱动比如broadcom、marvell的DSA驱动。如果你板子上没有这些芯片这些补丁可以直接跳过省得引入不必要的依赖。3.2 内核配置的合并策略NXP BSP的defconfig在arch/powerpc/configs/下面名字可能是mpc85xx_defconfig或者corenet64_smp_defconfig。ONL的配置在arch/powerpc/configs/或者arch/arm/configs/下面取决于你的平台是32位还是64位。合并配置的时候不要直接make oldconfig然后一路回车。那样会漏掉很多关键选项。我的做法是先用NXP的defconfig生成.config然后用scripts/config脚本手动打开ONL需要的选项。比如# 基于NXP defconfig生成基础配置 make mpc85xx_defconfig # 打开switchdev和phylink支持 scripts/config --enable CONFIG_NET_SWITCHDEV scripts/config --enable CONFIG_PHYLINK scripts/config --enable CONFIG_SFP scripts/config --enable CONFIG_HWMON scripts/config --enable CONFIG_SENSORS_LM75 scripts/config --enable CONFIG_GPIO_SYSFS scripts/config --enable CONFIG_I2C_MUX scripts/config --enable CONFIG_I2C_MUX_PCA954x scripts/config --enable CONFIG_MTD_SPI_NOR scripts/config --enable CONFIG_MTD_SPI_NOR_USE_4K_SECTORS scripts/config --enable CONFIG_SPI_FSL_ESPI # 更新依赖 make olddefconfig这里有个细节CONFIG_PHYLINK在4.14里可能还叫CONFIG_PHYLIB的子选项或者需要先开CONFIG_NETDEVICES。如果olddefconfig报依赖错误就根据提示逐个解决。别嫌麻烦配置阶段多花十分钟编译阶段能省两小时。3.3 网络驱动的回移植要点QorIQ的DPAA网络驱动在4.14里是drivers/net/ethernet/freescale/dpaa/。ONL可能引入了一些ethtool的统计项、ndo_setup_tc的回调、xdp的支持。这些在4.14的DPAA驱动里可能没有。回移植的时候得看ONL的补丁具体改了什么。如果ONL只是加了ethtool -S的统计那相对简单照着补丁把ethtool_ops里的get_strings、get_sset_count、get_ethtool_stats这几个回调补上就行。如果是switchdev的ndo_setup_tc那就麻烦了因为4.14的switchdev框架和5.15的差异很大tc的offload接口在4.14里还是ndo_setup_tc的旧签名5.15已经改成了ndo_setup_tc加flow_cls_offload。这种就得做API适配工作量不小。我的建议是先评估ONL的补丁里哪些是“必须”的哪些是“锦上添花”的。如果只是统计信息可以自己写个简单的ethtool回调不用完全照搬。如果是switchdev这种核心功能那就得老老实实做API转换。3.4 I2C和GPIO子系统的适配ONL里有一套sfp驱动在drivers/net/phy/sfp.c。这个驱动在4.14里可能还不存在或者版本很老。SFP驱动依赖i2c和gpio子系统还依赖hwmon来读温度。回移植的时候得确保i2c核心支持i2c_new_device和i2c_new_dummy_device这两个在4.14里都有。gpio核心支持devm_gpiod_get和gpiod_set_value4.14里也有但gpiod的consumer接口可能和5.15略有不同。hwmon子系统支持devm_hwmon_device_register_with_info这个在4.14里是有的但参数可能不一样。如果sfp.c在4.14上编译不过大概率是hwmon的API变了。可以看看4.14的hwmon头文件把hwmon_device_register_with_info的参数调整一下。另外sfp.c里可能用了phylink而phylink在4.14里可能还没有。如果phylink不可用可以考虑用phy_attach_direct和phy_start这些老接口替代但功能会打折扣。实操心得I2C和GPIO的调试最好用i2cdetect和gpiodetect工具先确认硬件层面能通。如果i2cdetect都看不到设备那驱动移植得再好也没用。先确保设备树里的I2C控制器和GPIO控制器被正确注册再谈上层驱动。3.5 设备树的嫁接与调试设备树的修改我习惯用dtc工具反编译成dts然后手动编辑。NXP BSP的设备树在arch/powerpc/boot/dts/下面ONL的设备树可能在arch/powerpc/boot/dts/或者arch/arm/boot/dts/下面。嫁接的时候先找到NXP设备树里的I2C控制器节点比如i2c118000 { compatible fsl,i2c; reg 0x118000 0x100; interrupts 38 2 0 0; clock-frequency 100000; #address-cells 1; #size-cells 0; };然后把ONL设备树里的SFP节点复制过来放在这个I2C节点下面sfp0: sfp50 { compatible sff,sfp; reg 0x50; i2c-bus i2c0; tx-disable-gpios gpio0 12 GPIO_ACTIVE_HIGH; mod-def0-gpios gpio0 13 GPIO_ACTIVE_LOW; los-gpios gpio0 14 GPIO_ACTIVE_HIGH; };这里的关键是gpio的phandle要指向正确的GPIO控制器。NXP的GPIO控制器节点可能是gpio0: gpio130000得确认gpio0这个label在设备树里定义了。另外GPIO_ACTIVE_HIGH和GPIO_ACTIVE_LOW这些宏在dt-bindings/gpio/gpio.h里得确保#include了。调试设备树的时候/proc/device-tree/是个好东西。启动后进去看看/proc/device-tree/i2c118000/sfp50/下面有没有你写的属性。如果没有说明设备树没被正确加载可能是U-Boot传的dtb不对或者dtb编译有问题。3.6 启动脚本和initramfs的构建ONIE的initramfs里有一堆脚本负责发现安装源、下载NOS镜像、写到存储。在QorIQ平台上这些脚本得适配PowerPC的架构。比如uname -m返回的是ppc64或者ppc脚本里如果有架构判断得加上对应的分支。initramfs的构建ONL通常用buildroot或者yocto。如果只是做原型验证可以用busybox手动搭一个最小的initramfs。关键是要包含busybox提供sh、mount、ifconfig、udhcpc这些基本工具。kmod用于加载内核模块。mtd-utils用于操作SPI NOR或者NAND。iproute2用于网络配置。ethtool用于查看网卡状态。init脚本里先挂载proc、sysfs、devtmpfs然后加载必要的内核模块比如spi-fsl-espi、mtd-spi-nor、i2c-fsl、gpio-fsl。接着配置网络启动udhcpc获取IP最后运行ONIE的发现脚本。注意PowerPC的U-Boot传给内核的bootargs里console参数可能是ttyS0或者ttyS1得和实际串口对应。如果启动后看不到输出先检查bootargs里的console和earlycon参数。4. 实操过程与核心环节实现4.1 环境搭建与源码准备我用的开发环境是一台x86_64的Linux工作站装了gcc-powerpc64-linux-gnu交叉编译工具链。NXP的BSP内核从官方SDK里解压出来版本是4.14.98。ONL的内核源码从GitHub上clone版本是5.15.60。先建目录结构mkdir -p ~/qoriq-onie/{kernel,onl,rootfs,images} cd ~/qoriq-onie/kernel git clone NXP_BSP_REPO linux-nxp cd linux-nxp git checkout -b backport然后从ONL源码里导出补丁cd ~/qoriq-onie/onl git clone ONL_REPO onl-src cd onl-src git format-patch v5.15.60 --output-directory ~/qoriq-onie/patches补丁导出后先看看有多少个ls ~/qoriq-onie/patches | wc -l如果超过200个别慌大部分是给特定硬件的。用grep过滤一下只保留和powerpc、fsl、qoriq、dpaa、i2c、gpio、spi、mtd、sfp、phylink相关的cd ~/qoriq-onie/patches for f in *.patch; do if grep -qE powerpc|fsl|qoriq|dpaa|i2c|gpio|spi|mtd|sfp|phylink $f; then echo $f fi done relevant_patches.txt然后按顺序打补丁cd ~/qoriq-onie/kernel/linux-nxp while read patch; do git am ~/qoriq-onie/patches/$patch || { echo Conflict in $patch git am --abort break } done ~/qoriq-onie/patches/relevant_patches.txt遇到冲突是正常的。比如ONL的补丁可能修改了drivers/net/phy/Kconfig而NXP的BSP里这个文件已经不一样了。这时候手动解决冲突用git add标记解决然后git am --continue。4.2 内核配置与编译补丁打完开始配置内核。先基于NXP的defconfigmake ARCHpowerpc CROSS_COMPILEpowerpc64-linux-gnu- mpc85xx_defconfig然后手动打开ONL需要的选项。我写了个小脚本#!/bin/bash CONFIG_FILE.config enable_config() { if grep -q ^# $1 is not set $CONFIG_FILE; then sed -i s/^# $1 is not set/$1y/ $CONFIG_FILE elif ! grep -q ^$1 $CONFIG_FILE; then echo $1y $CONFIG_FILE fi } enable_config CONFIG_NET_SWITCHDEV enable_config CONFIG_PHYLINK enable_config CONFIG_SFP enable_config CONFIG_HWMON enable_config CONFIG_SENSORS_LM75 enable_config CONFIG_GPIO_SYSFS enable_config CONFIG_I2C_MUX enable_config CONFIG_I2C_MUX_PCA954x enable_config CONFIG_MTD_SPI_NOR enable_config CONFIG_SPI_FSL_ESPI enable_config CONFIG_MTD_CMDLINE_PARTS enable_config CONFIG_DEVTMPFS enable_config CONFIG_DEVTMPFS_MOUNT运行脚本后执行make olddefconfig解决依赖。然后编译make ARCHpowerpc CROSS_COMPILEpowerpc64-linux-gnu- -j$(nproc) uImage make ARCHpowerpc CROSS_COMPILEpowerpc64-linux-gnu- -j$(nproc) modules make ARCHpowerpc CROSS_COMPILEpowerpc64-linux-gnu- dtbs编译过程中如果报错大概率是某个驱动用了新内核的API。比如sfp.c里可能用了fwnode_property_read_u32而4.14里只有device_property_read_u32。这时候得写个兼容宏#ifndef fwnode_property_read_u32 #define fwnode_property_read_u32(fwnode, propname, val) \ device_property_read_u32(NULL, propname, val) #endif这种兼容宏不要太多否则代码会变得很乱。如果某个驱动依赖的新API太多考虑直接放弃这个驱动用老版本替代。4.3 设备树修改与编译设备树文件在arch/powerpc/boot/dts/下面。我用的板子对应的dts是t2080rdb.dts。先备份一份然后编辑cp arch/powerpc/boot/dts/t2080rdb.dts arch/powerpc/boot/dts/t2080rdb.dts.bak在i2c118000节点下面加SFP节点在gpio节点下面确认GPIO控制器的label。然后编译dtbmake ARCHpowerpc CROSS_COMPILEpowerpc64-linux-gnu- t2080rdb.dtb编译好的dtb在arch/powerpc/boot/dts/下面。用dtc反编译检查一下dtc -I dtb -O dts -o /tmp/check.dts arch/powerpc/boot/dts/t2080rdb.dtb grep -A10 sfp /tmp/check.dts确认SFP节点在正确的位置GPIO的phandle能解析到。4.4 U-Boot环境变量配置QorIQ的U-Boot通常支持tftp加载内核和dtb。在U-Boot命令行里设置setenv ipaddr 192.168.1.100 setenv serverip 192.168.1.10 setenv bootargs consolettyS0,115200 root/dev/ram0 rw init/init setenv bootcmd tftp 0x1000000 uImage; tftp 0x2000000 t2080rdb.dtb; bootm 0x1000000 - 0x2000000 saveenv这里bootm的第三个参数是dtb地址。如果内核支持FIT镜像可以用bootm直接加载包含内核和dtb的itb文件更方便。注意QorIQ的U-Boot里tftp加载地址不能和内核解压地址冲突。uImage通常加载到0x1000000dtb加载到0x2000000initramfs加载到0x3000000。具体地址得看板子的内存映射。4.5 initramfs构建与ONIE脚本适配initramfs我用busybox手动搭。先建目录结构mkdir -p ~/qoriq-onie/rootfs/{bin,sbin,etc,proc,sys,dev,tmp,var,usr/bin,usr/sbin,lib/modules} cd ~/qoriq-onie/rootfs把交叉编译好的busybox拷进去创建符号链接cp /path/to/busybox-powerpc64 bin/busybox cd bin for cmd in $(./busybox --list); do ln -sf busybox $cmd done cd ..然后写init脚本#!/bin/busybox sh /bin/busybox --install -s /bin mount -t proc none /proc mount -t sysfs none /sys mount -t devtmpfs none /dev mount -t tmpfs none /tmp # 加载内核模块 modprobe spi-fsl-espi modprobe mtd-spi-nor modprobe i2c-fsl modprobe gpio-fsl modprobe sfp # 配置网络 ifconfig eth0 up udhcpc -i eth0 # 运行ONIE发现脚本 /usr/sbin/onie-discoveronie-discover脚本里用wget或者tftp从服务器下载NOS镜像然后用mtd_debug或者flash_erase写到SPI NOR里。这部分脚本得根据实际的安装源和存储介质来写。4.6 启动测试与验证把uImage、dtb、initramfs放到TFTP服务器目录板子上电U-Boot里执行run bootcmd。如果一切正常串口会输出内核启动日志然后进入initramfs的shell。验证步骤cat /proc/device-tree/i2c118000/sfp50/compatible确认SFP节点存在。i2cdetect -y 0确认I2C设备能扫到。ethtool eth0确认网卡驱动加载。ls /sys/class/gpio/确认GPIO控制器注册。cat /proc/mtd确认SPI NOR分区表。如果SFP节点不存在检查dtb是否被正确加载。可以在U-Boot里用fdt print /i2c118000看看。如果I2C扫不到设备检查硬件上拉电阻和电源。5. 常见问题与排查技巧实录5.1 内核启动卡在“Uncompressing Kernel Image”这个问题在PowerPC上很常见。原因通常是内核解压地址和U-Boot的加载地址冲突或者DDR初始化有问题。排查步骤确认bootm的加载地址和内核的CONFIG_KERNEL_START一致。QorIQ通常用0x1000000。检查U-Boot里的memctl配置确保DDR大小和实际一致。如果用了FIT镜像确认its文件里的load和entry地址正确。5.2 SFP模块识别不到SFP驱动依赖I2C和GPIO。如果i2cdetect能看到0x50地址但ethtool -m eth0读不到信息可能是sfp.c里的i2c-bus引用错了。检查设备树里i2c-bus i2c0确认i2c0这个label在设备树里定义了。GPIO的mod-def0-gpios极性反了。SFP的MOD-DEF0通常是低有效如果写成GPIO_ACTIVE_HIGH驱动会认为模块一直没插入。hwmon没注册成功。dmesg | grep hwmon看看有没有报错。5.3 网络驱动probe失败DPAA驱动probe失败常见原因是设备树里的fsl,fman节点配置不对。检查fsl,fman节点的reg地址和interrupts是否正确。fsl,fman-port节点的cell-index和compatible是否匹配。phy-handle是否指向正确的PHY节点。如果dmesg里报of_irq_parse_one失败说明中断映射有问题。检查interrupt-parent是否指向mpic。5.4 initramfs挂载失败如果内核启动后报VFS: Cannot open root device ram0说明initramfs没被正确加载。检查U-Boot的bootargs里有没有root/dev/ram0。bootm的第三个参数是不是initramfs地址。如果initramfs是单独的文件得用bootm kernel initrd dtb。initramfs的格式是不是cpio.gz。如果是cpio没压缩内核可能不认。5.5 常见问题速查表问题现象可能原因排查方法内核启动卡在解压加载地址冲突检查bootm地址和CONFIG_KERNEL_STARTI2C设备扫不到设备树节点缺失cat /proc/device-tree/i2c.../SFP读不到信息GPIO极性错误检查mod-def0-gpios的GPIO_ACTIVE_*网卡probe失败中断映射错误dmesginitramfs挂载失败bootargs错误检查root和init参数编译报API缺失内核版本差异写兼容宏或放弃该驱动实操心得调试内核启动问题earlycon和earlyprintk是救命稻草。在bootargs里加上earlyconuart8250,mmio,0xffe04500地址根据实际串口改能在内核解压前就看到输出。另外CONFIG_DEBUG_LL和CONFIG_EARLY_PRINTK得打开。6. 回移植后的性能验证与优化建议6.1 网络转发性能测试回移植完成后得验证网络性能有没有下降。用iperf3打流# 服务端 iperf3 -s # 客户端 iperf3 -c server_ip -t 60 -P 4QorIQ T2080的万兆口理论上能跑到9.5Gbps左右。如果只跑到5Gbps可能是DPAA的队列配置不对或者ethtool的rx/txring大小太小。用ethtool -G eth0 rx 1024 tx 1024调大ring。6.2 内核模块加载时间优化initramfs里加载模块的顺序会影响启动时间。把常用的模块编译进内核y而不是编译成模块m能省掉modprobe的时间。比如spi-fsl-espi、i2c-fsl、gpio-fsl这些直接编进内核。6.3 设备树overlay的动态加载如果板子上有多个变种可以用设备树overlay来动态加载SFP配置。在U-Boot里用fdt apply加载overlay或者在内核里用configfs加载。这样不用为每个变种编译一个dtb。6.4 长期维护的建议回移植的代码最好用Git管理每个补丁一个commitcommit message里写清楚来源和修改原因。这样以后升级内核版本的时候能快速定位哪些补丁需要重新适配。另外定期和ONL主线同步看看有没有新的补丁需要回移植。我个人在实际操作中的体会是内核回移植最耗时的不是写代码而是调试。一个I2C不通的问题可能查一整天。所以硬件层面的验证一定要先做确保I2C、GPIO、SPI这些基础外设能通再往上做驱动移植。另外别怕用老版本的驱动有时候4.14自带的驱动比5.15的还稳因为NXP调过。最后再分享一个小技巧用git bisect定位内核启动问题比盲目加printk高效得多。