news 2026/6/15 6:37:00

Linux handle_level_irq电平触发与mask_ack_irq序列

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Linux handle_level_irq电平触发与mask_ack_irq序列

Linux handle_level_irq电平触发与mask_ack_irq序列

handle_level_irq是Linux内核为电平触发中断提供的标准处理函数。电平触发中断的特点是:当中断信号线处于有效电平(高或低)时,中断请求持续有效。与边沿触发不同,电平触发不会锁存脉冲信号,因此在处理函数返回前必须确保信号线上的有效电平已被设备清除,否则中断会立即再次触发。handle_level_irq围绕mask_ack_irq序列管理这一行为。

函数实现如下:

```c
void handle_level_irq(struct irq_desc *desc)
{
raw_spin_lock(&desc->lock);
mask_ack_irq(desc);
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);

if (unlikely(irqd_irq_disabled(&desc->irq_data))) {
desc->istate |= IRQS_PENDING;
goto out_unlock;
}

if (unlikely(!desc->action)) {
goto out_unlock;
}

kstat_incr_irqs_this_cpu(desc);
irq_compat_set_prog_affinity(desc);
raw_spin_unlock(&desc->lock);

handle_irq_event(desc);

raw_spin_lock(&desc->lock);
if (!(desc->istate & IRQS_DISABLED) && desc->action) {
if (irqd_irq_masked(&desc->irq_data))
unmask_irq(desc);
}
out_unlock:
raw_spin_unlock(&desc->lock);
}
```

核心流程在第一行就执行mask_ack_irq。这是电平触发与边沿触发的关键区别:在运行任何处理函数之前,先屏蔽中断源并确认ACK。为什么必须mask?因为电平触发的信号线在设备服务完毕前持续有效,如果不mask,CPU在开中断后或handler返回瞬间再次被同一中断打断,形成无限递归的中断风暴。mask操作切断了信号线到CPU的路径。

mask_ack_irq函数的实现:

```c
void mask_ack_irq(struct irq_desc *desc)
{
struct irq_chip *chip = desc->irq_data.chip;

if (chip->irq_mask_ack) {
chip->irq_mask_ack(&desc->irq_data);
return;
}

if (chip->irq_mask)
chip->irq_mask(&desc->irq_data);
if (chip->irq_ack)
chip->irq_ack(&desc->irq_data);
}
```

优先使用芯片提供的复合操作chip->irq_mask_ack,因为部分硬件可以在一条寄存器指令中同时完成mask和ack,减少了寄存器读写次数。若芯片未提供复合操作,则分别调用irq_mask和irq_ack。

unmask操作的处理是电平触发的另一关键点。handle_irq_event返回后,desc->lock重新被获取,检查条件后调用unmask_irq:

```c
if (!(desc->istate & IRQS_DISABLED) && desc->action) {
if (irqd_irq_masked(&desc->irq_data))
unmask_irq(desc);
}
```

unmask必须在设备已将中断信号线恢复到非有效电平之后执行。如果设备驱动在handler内正确清除了中断源(写设备寄存器清除中断标志),信号线回到无效状态,此时unmask是安全的。如果设备未能清除中断源,unmask后中断线仍然有效,将立即重新触发mask_ack_irq序列,CPU陷入循环处理。这通常被视为设备驱动bug。

IRQS_PENDING标志在电平触发中的含义与边沿触发不同。当中断在disable状态下到达时,handle_level_irq设置IRQS_PENDING:

```c
if (unlikely(irqd_irq_disabled(&desc->irq_data))) {
desc->istate |= IRQS_PENDING;
goto out_unlock;
}
```

但这个pending在电平触发中不会被二次消费——它仅标记该中断在mask状态下曾经到达。当中断通过enable恢复后,__enable_irq检查IRQS_PENDING并调用desc->handle_irq重新处理。对于电平触发中断,重新处理意味着重新执行mask_ack_irq和handle_irq_event。

电平触发中断的IRQ_WAITING检测机制与边沿触发类似,在中断注册阶段设置IRQS_WAITING标志,handle_level_irq在顶部清除:

```c
desc->istate &= ~(IRQS_REPLAY | IRQS_WAITING);
```

区别在于电平触发的IRQ_WAITING不仅仅是首次中断确认。当电平触发中断的action链表为空时,中断处理会直接将pending中断丢弃但不屏蔽——这与边沿触发不同,边沿触发在action为空时会调用mask_irq永久屏蔽。电平触发之所以不永久屏蔽,是因为电平信号线可以被动监控,设备驱动注册后自然能收到下一次中断。

handle_level_irq与handle_fasteoi_irq的对比值得注意。handle_fasteoi_irq是为支持EOI(End of Interrupt)机制的中断控制器(如GIC)设计的,它不需要显式mask,而是通过EOI通知控制器中断处理结束。但在语义上,fasteoi等效于电平触发——控制器在EOI前不会再次提交相同中断。mask_ack_irq在fasteoi中退化为仅仅执行mask操作,ack由后续的EOI替代。

对于共享中断IRQF_SHARED,电平触发要求所有共享设备的中断触发类型一致。如果共享中断线上任一设备是边沿触发,则不能与电平触发设备共享。这是硬件电气特性决定的——电平信号线是"线与"逻辑,只要有一个设备保持有效电平,中断线持续有效,无法区分是哪个设备触发了中断,因此必须逐个调用action链表处理函数进行polling。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/15 6:31:00

从零开始实战:用Python爬取京东图书“Python”关键词的价格、书名与评论数(附完整代码)

前言:为什么选择爬取京东图书? 在数据分析、市场调研或购书决策中,掌握图书的真实价格和用户反馈至关重要。京东图书作为国内领先的正版图书平台,拥有海量书籍和实时更新的价格。然而,手动复制粘贴几千条数据显然不现实。于是,编写一个自动化的网络爬虫就成了高效解决方…

作者头像 李华
网站建设 2026/6/15 6:21:15

拆解电力四遥:遥测、遥信、遥控、遥调基础知识

本来想写一篇IEC104的文章,仔细思考觉得应该先介绍四遥。四遥是电力调度自动化、SCADA、RTU的关键数据应用类型。本文用通俗语言,帮助大家理解四遥的基本知识。一、四遥是什么四遥,包括遥测、遥信、遥控、遥调四大功能,是通过技术…

作者头像 李华
网站建设 2026/6/15 6:19:50

Keras Callbacks实战指南:构建高效稳定的神经网络训练流程

1. 为什么你训练模型时总在“等”——Keras Callbacks 不是锦上添花,而是生产级训练的呼吸阀你有没有过这样的经历:凌晨两点,盯着 Jupyter Notebook 里model.fit()那行代码,光标在进度条末尾缓慢跳动,而你心里盘算着—…

作者头像 李华
网站建设 2026/6/15 6:18:53

map、filter、reduce:JavaScript数组处理的三大核心范式

1. 这三个函数不是语法糖,而是思维范式的分水岭 你刚学编程时,大概率是从 for 循环开始的:遍历数组、逐个处理、手动推结果。我带过不少转行学员,他们写一个“把所有用户名转大写再筛选出长度大于5的”需求,本能反应…

作者头像 李华