kernel driver probe sequence

本文介绍了解决Linux kernel驱动初始化依赖问题的两种方法:通过定义不同优先级使被依赖的驱动优先初始化;使用deferprobe机制推迟驱动初始化直到所需资源就绪。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


kernel驱动由于资源的使用,经常遇到某一个driver的初始化依赖另一个driver是否初始化完成。

比如touch依赖i2c。


本篇总结两种解决方案。

方法一,定义不同级别的driver ,使被依赖的driver高优先初始化

内核为满足不同初始化等级,设计了1~7个等级,以及1s~7s个等级。共14个等级。如下图:


常用的module init 宏定义如下:

#define module_init(x)__initcall(x)    include/linux/module.h


具体原理参考 here

方法二,利用defer probe机制, 推迟初始化driver

kernel driver初始化过程中,如果遇到依赖的资源没有准备好,返回EPROBE_DEFER ,则1~7等级的driver将会在1s~7s对应等级中再次probe 。

kernel probe过程参考 here

defer probe实现原理如下,


EPROBE_DEFER返回值的module driver 加入到probe_pending_list ,

同一级别driver probe过程中,local_trigger_count与defered_trigger_count相等,不会触发defer probe


注意: 

如下图really_probe函数中返回EPROBE_DEFER同时通过devres_release_all释放devm_xxx申请的硬件资源。

sysfs , drvdata 等等也释放。



defer probe是如何再次启动的呢??? 


如上图,定义1s~7s对应等级defererd probe driver, 及late_initcall driver module:deferred_probe_enable_fn ,

该函数会触发defer probe动作。


如下图,从probe_pending_list取出再probe 。












<think>嗯,用户问的是设备驱动中probe函数的作用和需要执行的任务。结合用户之前关于IP179n交换芯片的问题,看来用户正在深入Linux驱动开发领域,可能是个嵌入式开发工程师或者物联网设备开发者。 用户引用了四段资料,但核心关注点很明确:probe函数到底怎么用。从引用内容看,用户似乎遇到过probe函数使用不当导致驱动失效的问题(引用3),也困惑于probe的参数来源(引用1)。这反映出用户需要的是实践性指导而非纯理论。 让我拆解这个问题: 首先需要说明probe的触发机制。根据引用2,总线匹配设备时会调用probe,这个机制必须讲清楚,特别是对于使用设备树的现代Linux系统。用户之前配置过全志平台的设备树,应该能理解设备树节点与驱动的匹配关系。 然后重点在于probe函数里的任务清单。用户需要具体可操作的指导,比如初始化硬件、分配资源、注册设备等步骤。考虑到用户做过交换芯片驱动开发,举例时可以结合MDIO总线操作这类实际场景。 注意到用户引用4展示了一个杂项设备驱动,这个例子虽然简单但暴露了关键点:probe函数和传统init函数的区别。应该强调现代驱动架构中probe的核心地位,以及为何要取代直接写在init函数里的操作(资源管理、热插拔支持等)。 用户可能还隐含了调试需求。当probe出错时如何排查?比如引用3里用户自己添加probe导致驱动失效的情况。需要给出常见错误模式:资源冲突、设备树匹配失败、硬件初始化顺序错误等。 最后要关联用户之前的开发经验。IP179n驱动中肯定实现了probe函数,可以暗示用户去对照源码,这样理解会更深刻。毕竟用户已经接触过phy-address配置这类实际驱动开发场景。</think>在 Linux 设备驱动模型中,**`probe` 函数**是驱动初始化的核心入口点,主要负责**设备识别、资源分配和初始化**。其作用和关键任务如下: --- ### 一、`probe` 函数的核心作用 1. **设备匹配验证** 当内核检测到设备与驱动兼容(通过设备树 `compatible` 属性、ACPI ID 或总线匹配规则)时,总线层(如 I²C、SPI、Platform 总线)自动调用驱动的 `probe` 函数[^2]。 2. **设备初始化入口** 替代传统 `init` 函数,实现**按需初始化**:仅在设备存在时执行初始化,避免资源浪费[^3]。 3. **资源管理中枢** 统一管理设备所需的硬件资源(寄存器、中断、DMA 等)和软件资源(内存、设备节点)。 --- ### 二、`probe` 函数必须完成的关键任务 #### 1. **获取设备资源** ```c // 从设备树获取寄存器地址 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); base = devm_ioremap_resource(&pdev->dev, res); // 获取中断号 irq = platform_get_irq(pdev, 0); ret = devm_request_irq(&pdev->dev, irq, handler, IRQF_TRIGGER_RISING, "dev_irq", dev); ``` - 使用 `devm_` 前缀的 API 自动管理资源生命周期(驱动卸载时自动释放) #### 2. **初始化硬件** - 配置寄存器(如使能时钟、复位电路) - 检测设备状态(如读取芯片 ID 寄存器验证通信) ```c // 示例:交换芯片复位 gpiod_set_value(dev->reset_gpio, 0); mdelay(10); gpiod_set_value(dev->reset_gpio, 1); ``` #### 3. **注册设备接口** | 接口类型 | API 示例 | 作用 | |-------------------|--------------------------|--------------------------| | 字符设备 | `misc_register()` | 创建 /dev 节点 | | 网络设备 | `register_netdev()` | 注册网络协议栈接口 | | 输入设备 | `input_register_device()`| 注册输入事件上报 | ```c // 注册杂项设备(引用[4]示例扩展) static const struct file_operations misc_fops = { ... }; struct miscdevice misc_dev = { .minor = MISC_DYNAMIC_MINOR, .name = "mydev", .fops = &misc_fops, }; misc_register(&misc_dev); // 在 probe 中调用 ``` #### 4. **初始化驱动数据结构** ```c struct my_device *dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL); platform_set_drvdata(pdev, dev); // 存储设备私有数据 ``` #### 5. **启动后台处理** - 创建工作队列(`create_singlethread_workqueue`) - 启动内核线程(`kthread_run`) - 初始化定时器(`timer_setup`) --- ### 三、`probe` 函数执行流程示意图 ```mermaid sequenceDiagram participant Bus as 总线层 participant Driver as 驱动 probe 函数 participant HW as 硬件设备 Bus->>Driver: 检测到设备匹配 Driver->>HW: 1. 获取资源(寄存器/中断) Driver->>HW: 2. 复位/初始化硬件 Driver->>Driver: 3. 分配私有数据结构 Driver->>Kernel: 4. 注册设备接口(如misc_register) Driver->>Driver: 5. 启动工作队列/定时器 Driver-->>Bus: 返回成功(0)或错误码 ``` --- ### 四、典型错误处理 ```c static int my_probe(struct platform_device *pdev) { // 1. 资源获取 res = platform_get_resource(...); if (!res) return -ENXIO; // 资源不存在 // 2. 内存分配 dev = devm_kzalloc(...); if (!dev) return -ENOMEM; // 3. 硬件初始化 if (init_hw(dev) < 0) goto err_cleanup; // 4. 注册接口 if (misc_register(...) != 0) goto err_hw; return 0; // 成功 err_hw: cleanup_hw(dev); // 反初始化硬件 err_cleanup: kfree(dev); // 非devm分配需手动释放 return -EIO; } ``` > **关键原则**:错误处理路径必须**逆向释放已申请的资源**,防止内存泄漏或资源冲突[^1]。 --- ### 五、`probe` 与 `init` 的区别 | 特性 | `probe` 函数 | 传统 `init` 函数 | |-------------------|-------------------------------|------------------------------| | 调用时机 | 设备匹配时动态调用 | 模块加载时强制调用 | | 设备依赖 | 仅当设备存在时执行 | 无论设备是否存在都执行 | | 热插拔支持 | ✅ 支持设备热插入 | ❌ 不支持 | | 资源管理 | 通过 `devm_*` API 自动管理 | 需手动释放资源 | --- ### 六、调试建议 1. **检查匹配条件** ```bash # 查看设备树匹配状态 cat /sys/firmware/devicetree/base/soc/ethernet/compatible ``` 2. **跟踪 probe 调用** ```bash dmesg | grep "probe" # 观察驱动探测日志 ``` 3. **验证资源分配** ```bash cat /proc/interrupts # 查看中断注册 cat /proc/iomem # 查看IO内存映射 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值