0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

系统休眠过程中,如何suspend设备中断(IRQ)?

454398 来源:蜗窝科技 作者:linuxer 2020-09-21 14:29 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

一、设备IRQ的suspend和resume

本小节主要解决这样一个问题:在系统休眠过程中,如何suspend设备中断(IRQ)?在从休眠中唤醒的过程中,如何resume设备IRQ?

一般而言,在系统suspend过程的后期,各个设备的IRQ (interrupt request line)会被disable掉。具体的时间点是在各个设备的late suspend阶段之后。代码如下(删除了部分无关代码):

static int suspend_enter(suspend_state_t state, bool *wakeup)

{……

error = dpm_suspend_late(PMSG_SUSPEND);-----late suspend阶段

error = platform_suspend_prepare_late(state);

下面的代码中会disable各个设备的irq

error = dpm_suspend_noirq(PMSG_SUSPEND);----进入noirq的阶段

error = platform_suspend_prepare_noirq(state);

……

}

在dpm_suspend_noirq函数中,会针对系统中的每一个device,依次调用device_suspend_noirq来执行该设备noirq情况下的suspend callback函数,当然,在此之前会调用suspend_device_irqs函数来disable所有设备的irq。

之所以这么做,其思路是这样的:在各个设备驱动完成了late suspend之后,按理说这些已经被suspend的设备不应该再触发中断了。如果还有一些设备没有被正确的suspend,那么我们最好的策略是mask该设备的irq,从而阻止中断的递交。此外,在过去的代码中(指interrupt handler),我们对设备共享IRQ的情况处理的不是很好,存在这样的问题:在共享IRQ的设备们完成suspend之后,如果有中断触发,这时候设备驱动的interrupt handler并没有准备好。在有些场景下,interrupt handler会访问已经suspend设备的IO地址空间,从而导致不可预知的issue。这些issue很难debug,因此,我们引入了suspend_device_irqs()以及设备noirq阶段的callback函数。

系统resume过程中,在各个设备的early resume过程之前,各个设备的IRQ会被重新打开,具体代码如下(删除了部分无关代码):

static int suspend_enter(suspend_state_t state, bool *wakeup)

{……

platform_resume_noirq(state);----首先执行noirq阶段的resume

dpm_resume_noirq(PMSG_RESUME);------在这里会恢复irq,然后进入early resume阶段

platform_resume_early(state);

dpm_resume_early(PMSG_RESUME);

……}

在dpm_resume_noirq函数中,会调用各个设备驱动的noirq callback,在此之后,调用resume_device_irqs函数,完成各个设备irq的enable。

二、关于IRQF_NO_SUSPEND Flag

当然,有些中断需要在整个系统的suspend-resume过程中(包括在noirq阶段,包括将nonboot CPU推送到offline状态以及系统resume后,将其重新设置为online的阶段)保持能够触发的状态。一个简单的例子就是timer中断,此外IPI以及一些特殊目的设备中断也需要如此。

在中断申请的时候,IRQF_NO_SUSPEND flag可以用来告知IRQ subsystem,这个中断就是上一段文字中描述的那种中断:需要在系统的suspend-resume过程中保持enable状态。有了这个flag,suspend_device_irqs并不会disable该IRQ,从而让该中断在随后的suspend和resume过程中,保持中断开启。当然,这并不能保证该中断可以将系统唤醒。如果想要达到唤醒的目的,请调用enable_irq_wake。

需要注意的是:IRQF_NO_SUSPEND flag影响使用该IRQ的所有外设(一个IRQ可以被多个外设共享,不过ARM中不会这么用)。如果一个IRQ被多个外设共享,并且各个外设都注册了对应的interrupt handler,如果其一在申请中断的时候使用了IRQF_NO_SUSPEND flag,那么在系统suspend的时候(指suspend_device_irqs之后,按理说各个IRQ已经被disable了),所有该IRQ上的各个设备的interrupt handler都可以被正常的被触发执行,即便是有些设备在调用request_irq(或者其他中断注册函数)的时候没有设定IRQF_NO_SUSPEND flag。正因为如此,我们应该尽可能的避免同时使用IRQF_NO_SUSPEND 和IRQF_SHARED这两个flag。

三、系统中断唤醒接口:enable_irq_wake() 和 disable_irq_wake()

有些中断可以将系统从睡眠状态中唤醒,我们称之“可以唤醒系统的中断”,当然,“可以唤醒系统的中断”需要配置才能启动唤醒系统这样的功能。这样的中断一般在工作状态的时候就是作为普通I/O interrupt出现,只要在准备使能唤醒系统功能的时候,才会发起一些特别的配置和设定。

这样的配置和设定有可能是和硬件系统(例如SOC)上的信号处理逻辑相关的,我们可以考虑下面的HW block图:

外设的中断信号被送到“通用的中断信号处理模块”和“特定中断信号接收模块”。正常工作的时候,我们会turn on“通用的中断信号处理模块”的处理逻辑,而turn off“特定中断信号接收模块” 的处理逻辑。但是,在系统进入睡眠状态的时候,有可能“通用的中断信号处理模块”已经off了,这时候,我们需要启动“特定中断信号接收模块”来接收中断信号,从而让系统suspend-resume模块(它往往是suspend状态时候唯一能够工作的HW block了)可以正常的被该中断信号唤醒。一旦唤醒,我们最好是turn off“特定中断信号接收模块”,让外设的中断处理回到正常的工作模式,同时,也避免了系统suspend-resume模块收到不必要的干扰。

IRQ子系统提供了两个接口函数来完成这个功能:enable_irq_wake()函数用来打开该外设中断线通往系统电源管理模块(也就是上面的suspend-resume模块)之路,另外一个接口是disable_irq_wake(),用来关闭该外设中断线通往系统电源管理模块路径上的各种HW block。

调用了enable_irq_wake会影响系统suspend过程中的suspend_device_irqs处理,代码如下:

static bool suspend_device_irq(struct irq_desc *desc)

{

……

if (irqd_is_wakeup_set(&desc->irq_data)) {

irqd_set(&desc->irq_data, IRQD_WAKEUP_ARMED);

return true;

}

省略Disable 中断的代码

}

也就是说,一旦调用enable_irq_wake设定了该设备的中断作为系统suspend的唤醒源,那么在该外设的中断不会被disable,只是被标记一个IRQD_WAKEUP_ARMED的标记。对于那些不是wakeup source的中断,在suspend_device_irq 函数中会标记IRQS_SUSPENDED并disable该设备的irq。在系统唤醒过程中(resume_device_irqs),被diable的中断会重新enable。

当然,如果在suspend的过程中发生了某些事件(例如wakeup source产生了有效信号),从而导致本次suspend abort,那么这个abort事件也会通知到PM core模块。事件并不需要被立刻通知到PM core模块,一般而言,suspend thread会在某些点上去检查pending的wakeup event。

在系统suspend的过程中,每一个来自wakeup source的中断都会终止suspend过程或者将系统唤醒(如果系统已经进入suspend状态)。但是,在执行了suspend_device_irqs之后,普通的中断被屏蔽了,这时候,即便HW触发了中断信号也无法执行其interrupt handler。作为wakeup source的IRQ会怎样呢?虽然它的中断没有被mask掉,但是其interrupt handler也不会执行(这时候的HW Signal只是用来唤醒系统)。唯一有机会执行的interrupt handler是那些标记IRQF_NO_SUSPEND flag的IRQ,因为它们的中断始终是enable的。当然,这些中断不应该调用enable_irq_wake进行唤醒源的设定。

四、Interrupts and Suspend-to-Idle

Suspend-to-idle (也被称为"freeze" 状态)是一个相对比较新的系统电源管理状态,相关代码如下:

static int suspend_enter(suspend_state_t state, bool *wakeup)

{

……

各个设备的late suspend阶段

各个设备的noirq suspend阶段

if (state == PM_SUSPEND_FREEZE) {

freeze_enter();

goto Platform_wake;

}

……

}

Freeze和suspend的前面的操作基本是一样的:首先冻结系统中的进程,然后是suspend系统中的形形色色的device,不一样的地方在noirq suspend完成之后,freeze不会disable那些non-BSP的处理器和syscore suspend阶段,而是调用freeze_enter函数,把所有的处理器推送到idle状态。这时候,任何的enable的中断都可以将系统唤醒。而这也就意味着那些标记IRQF_NO_SUSPEND(其IRQ没有在suspend_device_irqs过程中被mask掉)是有能力将处理器从idle状态中唤醒(不过,需要注意的是:这种信号并不会触发一个系统唤醒信号),而普通中断由于其IRQ被disable了,因此无法唤醒idle状态中的处理器。

那些能够唤醒系统的wakeup interrupt呢?由于其中断没有被mask掉,因此也可以将系统从suspend-to-idle状态中唤醒。整个过程和将系统从suspend状态中唤醒一样,唯一不同的是:将系统从freeze状态唤醒走的中断处理路径,而将系统从suspend状态唤醒走的唤醒处理路径,需要电源管理HW BLOCK中特别的中断处理逻辑的参与。

五、IRQF_NO_SUSPEND 标志和enable_irq_wake函数不能同时使用

针对一个设备,在申请中断的时候使用IRQF_NO_SUSPEND flag,又同时调用enable_irq_wake设定唤醒源是不合理的,主要原因如下:

1、如果IRQ没有共享,使用IRQF_NO_SUSPEND flag说明你想要在整个系统的suspend-resume过程中(包括suspend_device_irqs之后的阶段)保持中断打开以便正常的调用其interrupt handler。而调用enable_irq_wake函数则说明你想要将该设备的irq信号设定为中断源,因此并不期望调用其interrupt handler。而这两个需求明显是互斥的。

2、IRQF_NO_SUSPEND 标志和enable_irq_wake函数都不是针对一个interrupt handler的,而是针对该IRQ上的所有注册的handler的。在一个IRQ上共享唤醒源以及no suspend中断源是比较荒谬的。

不过,在非常特殊的场合下,一个IRQ可以被设定为wakeup source,同时也设定IRQF_NO_SUSPEND 标志。为了代码逻辑正确,该设备的驱动代码需要满足一些特别的需求。

参考文献

1、内核文档power/suspend-and-interrupts.txt

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 处理器
    +关注

    关注

    68

    文章

    20149

    浏览量

    247240
  • 中断
    +关注

    关注

    5

    文章

    913

    浏览量

    43566
  • IRQ
    IRQ
    +关注

    关注

    0

    文章

    16

    浏览量

    11374
  • Freeze
    +关注

    关注

    0

    文章

    4

    浏览量

    8152
收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    NVIDIA DGX Spark系统恢复过程与步骤

    在使用 NVIDIA DGX Spark 的过程中,可能会出现配置故障,而导致开发中断的问题,本篇教程将带大家了解如何一步步完成系统恢复。
    的头像 发表于 11-28 09:46 3615次阅读
    NVIDIA DGX Spark<b class='flag-5'>系统</b>恢复<b class='flag-5'>过程</b>与步骤

    芯源MCU进入休眠模式或深度休眠模式

    使用M0+ 内核的ARM 等待中断专用指令,WFI(Wait for Interrupt),配合M0+ 内核的系统控制寄存器(SCR, System Control Register
    发表于 11-26 07:41

    关于蜂鸟E203内核中断硬件实现中断嵌套的设计

    开发板:MCU200T 中断机制即处理器核在执行程序指令流的过程中突然被别的请求打断而中止执行当前程序,转而处理别的事情,处理完重新回到之前程序终端的位置继续执行。处理器收到中断请求,保存当前
    发表于 10-23 07:07

    中断机制在计算机系统的作用,如何在e203处理器利用外部中断来处理用户输入输出

    的效果。 7.总结 本文详细介绍了中断机制在计算机系统的作用,以及如何在e203处理器利用外部中断来处理用户输入输出。除此之外,
    发表于 10-21 12:47

    rtthread在线程执行过程中,被中断打断后进入中断处理时,是否有保护FPU的状态?

    rtthread 3.1.3版本 程序实现的是正弦波的计算输出,在运行过程中,为了保证执行效率,会在中断中进行当前幅值输出的计算; 同时在运行过程中会接收界面下传的新一个幅值的数据,接收的新幅值数据
    发表于 09-24 07:50

    瑞萨RA系列MCU的中断过程介绍

    中断来临的时候会最先经过IRQ寄存器,IRQ寄存器检测到中断的时候,会向中央处理嵌套向量中断控制器NVIC发送
    的头像 发表于 09-23 09:45 987次阅读
    瑞萨RA系列MCU的<b class='flag-5'>中断过程</b>介绍

    服务器数据恢复—热备盘上线过程中硬盘掉线导致数据丢失,数据恢复揭秘

    一台某品牌存储设备中有一组由8块硬盘(包括热备盘)组建的raid5磁盘阵列。上层安装的Linux操作系统。 raid5磁盘阵列有一块硬盘掉线,热备盘自动上线并开始同步数据。在热备盘同步数据的过程中,raid5阵列又有一块硬盘由
    的头像 发表于 08-26 13:24 194次阅读

    固件升级过程中,如何禁用EC INT中断

    固件升级过程中,EC INT中断经常会被触发,如何禁用? 这个中断,协议栈是怎么触发的或者说需要满足什么条件?
    发表于 07-25 06:43

    RK3128 Android 7.1 进入深度休眠流程分析

    /sys/kernel/debug/suspend_stats 或查看内核日志休眠/唤醒记录:text dmesg | grep -i suspend 注意事项 确保所
    发表于 07-22 10:45

    嵌入式学习-飞凌嵌入式ElfBoard ELF 1板卡-Linux系统中断之按键中断驱动

    设备节点相关的头文件 #include //包含gpio子系统相关函数头文件 #include//包含中断函数相关头文件 #define DEVICE_NAME \"button_irq
    发表于 03-31 16:50

    嵌入式学习-飞凌嵌入式ElfBoard ELF 1板卡-Linux系统中断之Linux中断介绍

    能够正确地响应中断事件。在中断处理程序,可以执行相应的操作,如读取设备数据、处理中断状态等。(三)中断
    发表于 03-28 10:44

    飞凌嵌入式ElfBoard ELF 1板卡-Linux系统中断之按键中断驱动

    #include //包含gpio子系统相关函数头文件#include//包含中断函数相关头文件 #define DEVICE_NAME \"button_irq\"// 设备名称
    发表于 03-28 10:42

    飞凌嵌入式ElfBoard ELF 1板卡-Linux系统中断之Linux中断介绍

    能够正确地响应中断事件。在中断处理程序,可以执行相应的操作,如读取设备数据、处理中断状态等。(三)中断
    发表于 03-27 10:28

    TIM2输入捕获,DMA开启中断传输输入捕获数据,程序跑的过程中,DMA一直中断,TIM6只触发一次中断,怎么解决?

    用TIM2捕获输入的数据,并且通过DMA存储,在开启DMA中断同时,TIM6中断也开启(用于计时)。但是程序跑的过程中,DMA一直中断,TIM6只触发一次
    发表于 03-14 06:39

    Jtti:有哪些工具可以帮助我监控自动更新过程中系统状态?

    监控自动更新过程中系统状态对于确保系统的稳定性和性能至关重要。以下是一些可以帮助你监控系统状态的工具: 1.系统日志工具 dmesg:显示
    的头像 发表于 12-10 15:46 710次阅读