request_irq与request_threaded_irq

本文介绍了一种针对PL011 UART设备的IRQ配置方法。通过使用request_irq或request_threaded_irq函数来为PL011 UART设备分配IRQ资源。此配置支持IRQF_ONESHOT标志。

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

/*
* Allocate the IRQ
*/
#if 0
retval = request_irq(uap->port.irq, pl011_int, 0, "uart-pl011", uap);
#else
retval = request_threaded_irq(uap->port.irq, NULL, pl011_int, IRQ_TYPE_NONE | IRQF_ONESHOT,

"uart-pl011", uap);








本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/sky-heaven/p/5038749.html,如需转载请自行联系原作者




<think>我们正在讨论的是Linux内核中的中断处理函数。用户之前询问了关于设备树中配置GPIO中断的pinctrl状态问题,现在转向了解`devm_request_threaded_irq`函数的用法和解释。根据引用内容,我们已知:-`devm_request_threaded_irq`用于请求并注册一个线程化的中断处理程序[^1]。-使用此函数时需要注意传递有效的中断号,否则会返回错误(如-22)[^2]。-该函数是支持中断线程化的接口,传统的`request_irq`相比,可以简化设计,避免使用tasklet/workqueue等机制[^3]。因此,我们应详细解释该函数的作用、参数、使用方法和注意事项。</think> ### Linux 驱动中 `devm_request_threaded_irq` 函数详解 `devm_request_threaded_irq` 是 Linux 内核中用于管理线程化中断处理的核心函数[^1][^3],传统 `request_irq` 相比,它实现了两大创新: 1. **资源自动管理**:使用 `devm_` 前缀确保驱动卸载时自动释放中断资源 2. **中断线程化**:支持将耗时中断任务转移到内核线程执行,避免阻塞整个系统 #### 一、函数原型参数详解 ```c int devm_request_threaded_irq(struct device *dev, // 关联的设备结构体 unsigned int irq, // 硬件中断号[^2] irq_handler_t handler, // 顶半部函数 irq_handler_t thread_fn, // 底半部线程函数 unsigned long irqflags, // 中断标志 const char *devname, // 设备标识名 void *dev_id); // 共享中断ID ``` **关键参数解析**: 1. `handler`(顶半部): - 在硬中断上下文中运行(原子上下文) - 应小于 100μs,仅执行关键操作(如寄存器读取、状态标记) - 返回: - `IRQ_WAKE_THREAD`:唤醒底半部线程 - `IRQ_HANDLED`:无后续处理 ```c irqreturn_t handler(int irq, void *dev_id) { if (check_hardware_status()) return IRQ_WAKE_THREAD; // 触发线程处理 return IRQ_HANDLED; // 处理完成 } ``` 2. `thread_fn`(底半部): - 在内核线程中运行(可睡眠、调度) - 处理耗时任务(如数据传输、复杂计算) ```c irqreturn_t thread_fn(int irq, void *dev_id) { process_data_from_hardware(); // 可调用kmalloc/schedule_timeout等 return IRQ_HANDLED; } ``` 3. `irqflags` 标志组合: | 标志 | 说明 | 适用场景 | |---|---|---| | `IRQF_TRIGGER_RISING` | 上升沿触发 | GPIO按键[^2] | | `IRQF_ONESHOT` | 执行完成后才开中断 | 避免中断嵌套 | | `IRQF_SHARED` | 共享中断线 | 多个设备共享同中断号 | #### 二、典型使用流程 ```c // 驱动探测函数 static int probe(struct platform_device *pdev) { struct my_device *dev = alloc_device(); // 获取设备树中配置的中断号 int irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; // 错误处理[^2] // 注册线程化中断 int ret = devm_request_threaded_irq(&pdev->dev, irq, top_half_handler, bottom_half_thread, IRQF_TRIGGER_RISING | IRQF_ONESHOT, "my-device", dev); if (ret) { dev_err(&pdev->dev, "中断注册失败: %d\n", ret); return ret; } } ``` #### 三、传统方案的对比 | 方案 | 上下文 | 可睡眠 | 资源管理 | 适用场景 | |---|---|---|---|---| | `request_irq` + Tasklet | 软中断 | ❌ | 手动释放 | 简单实时任务 | | `request_irq` + Workqueue | 进程 | ✅ | 手动释放 | 复杂非实时任务 | | `devm_request_threaded_irq` | 线程 | ✅ | 自动释放 | 推荐通用方案[^3] | #### 四、高频错误处理 1. **返回 -22 (EINVAL)**: - 原因:无效中断号(如 `irq=0` 或超出范围)[^2] - 解决:用 `platform_get_irq()` 替代硬编码 2. **返回 -16 (EBUSY)**: - 原因:共享中断未设置 `IRQF_SHARED` 标志 - 解决:添加共享标志或检查设备树配置 3. **内核崩溃 (oops)**: - 原因:在 `handler` 中使用睡眠函数(如 `msleep()`) - 解决:将耗时操作移至 `thread_fn` > 注意:`IRQF_ONESHOT` 必须线程化中断配合使用,确保顶半部执行期间不会产生二次中断[^1]。 #### 五、设备树集成示例 ```dts // 设备树配置 my_device { compatible = "vendor,my-device"; interrupt-parent = <&gpio1>; interrupts = <3 IRQ_TYPE_EDGE_RISING>; // GPIO1_IO03上升沿触发 }; ``` 驱动通过 `platform_get_irq()` 自动解析该配置,无需硬编码中断号。 --- ### 相关问题 1. 如何验证 `devm_request_threaded_irq` 的顶半部和底半部执行时间? 2. 共享中断场景下 `dev_id` 参数应如何设置? 3. 线程化中断的实时性如何保障? 4. 设备树配置的 GPIO 中断标准硬件中断在函数使用上有何区别?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值