Linux休眠后对中断的处理
同事在调试一个外设时发现:
a. 系统正常运行的情况下,使用这个设备会触发中断并调用它的中断处理函数。
b. 系统休眠之后,使用这个设备可以唤醒系统,但中断处理函数却没有被调用。
能够唤醒系统,说明中断一定是触发了。另发现小板上的键盘是可以的,休眠后按键可以
调到keyboard的中断处理函数。
跟踪这个问题,发现以下几点:
1. Linux在系统休眠时会调用dpm_suspend_noirq()-> suspend_device_irqs()。
当系统休眠时,设备驱动需要禁止接收中断,suspend_device_irqs()屏蔽所有正在
使用的中断(置IRQ_DISABLED标志),timer中断除外,因为Timer中段标志中设置了
IRQF_NO_SUSPEND。如果禁止原因是suspend,则设置标志中的IRQ_SUSPENDED位。
所以休眠之后,desc->status |= IRQ_DISABLED;
2. 中断触发类型有很多种,比如边沿触发和电平触发。在Linux里分别用
handle_edge_irq() / handle_level_irq() 来处理它们。
handle_edge_irq() :
* 如果中断有标志 IRQ_INPROGRESS 或 IRQ_DISABLED,说明此中断已经在处理或
已经禁止。边沿触发锁存这次中断请求(置标记IRQ_PENDING),然后退出。
由于中断请求已经锁存了,所以中断处理函数一定会被调用到。
handle_level_irq() :
* 电平都会延续一段时间,在这段时间内电平中断会一直被触发。因此进入电平
中断处理之前会先屏蔽该中断,到最后处理完毕之后再开启。
3. 平台处理函数在初始化的时候将所有GPIO都设置为电平触发 set_irq_handler(gpio, handle_level_irq),
而键盘设备自己注册了handle_edge_irq。
a. 系统正常运行的情况下,使用这个设备会触发中断并调用它的中断处理函数。
b. 系统休眠之后,使用这个设备可以唤醒系统,但中断处理函数却没有被调用。
能够唤醒系统,说明中断一定是触发了。另发现小板上的键盘是可以的,休眠后按键可以
调到keyboard的中断处理函数。
跟踪这个问题,发现以下几点:
1. Linux在系统休眠时会调用dpm_suspend_noirq()-> suspend_device_irqs()。
当系统休眠时,设备驱动需要禁止接收中断,suspend_device_irqs()屏蔽所有正在
使用的中断(置IRQ_DISABLED标志),timer中断除外,因为Timer中段标志中设置了
IRQF_NO_SUSPEND。如果禁止原因是suspend,则设置标志中的IRQ_SUSPENDED位。
所以休眠之后,desc->status |= IRQ_DISABLED;
2. 中断触发类型有很多种,比如边沿触发和电平触发。在Linux里分别用
handle_edge_irq() / handle_level_irq() 来处理它们。
handle_edge_irq() :
* 如果中断有标志 IRQ_INPROGRESS 或 IRQ_DISABLED,说明此中断已经在处理或
已经禁止。边沿触发锁存这次中断请求(置标记IRQ_PENDING),然后退出。
由于中断请求已经锁存了,所以中断处理函数一定会被调用到。
handle_level_irq() :
* 电平都会延续一段时间,在这段时间内电平中断会一直被触发。因此进入电平
中断处理之前会先屏蔽该中断,到最后处理完毕之后再开启。
* 电平中断不允许嵌套。正在处理的中断(IRQ_INPROGRESS)或被禁止的中断(IRQ_DISABLED)
都不会被处理。
3. 平台处理函数在初始化的时候将所有GPIO都设置为电平触发 set_irq_handler(gpio, handle_level_irq),
而键盘设备自己注册了handle_edge_irq。