ret = set_irq_wake_real(irq, on);
if (ret)
desc->wake_depth = 0;
else
irqd_set(&desc->irq_data, IRQD_WAKEUP_STATE);
}
} else {
if (desc->wake_depth == 0) {
WARN(1, "Unbalanced IRQ %d wake disable\n", irq);
} else if (--desc->wake_depth == 0) {
ret = set_irq_wake_real(irq, on);
if (ret)
desc->wake_depth = 1;
else
irqd_clear(&desc->irq_data, IRQD_WAKEUP_STATE);
}
}
irq_put_desc_busunlock(desc, flags);
return ret;
}
1) 首先在set_irq_wake_real函数中通过irq_chip的irq_set_wake回调函数设置SoC相关wakeup寄存器使能中断唤醒功能,如果不使能的话,即使设备在那疯狂的产生中断signal,SoC可不会理睬你哦!
2) 设置irq的state为IRQD_WAKEUP_STATE,这步很重要,suspend流程会用到的。
2.2. Suspend to RAM流程
先画个图示意一下系统Suspend to RAM流程。我们可以看到图片画的很漂亮。从enter_state开始到suspend_ops->enter()结束。对于suspend_ops->enter()调用,我的理解是CPU停在这里了,待到醒来的时候,就从这里开始继续前行的脚步。
1) enable_irq_wake()可以有两种途径,一是在driver的suspend函数中由驱动开发者主动调用;二是在driver的probe函数中调用dev_pm_set_wake_irq()和device_init_wakeup()。因为suspend的过程中会通过dev_pm_arm_wake_irq()打开所有wakeup source的irq wake功能。我更推荐途径1,因为系统已经帮我们做了,何必重复造轮子呢!
2) 对于已经enable 并且使能wakeup的irq,置位IRQD_WAKEUP_ARMED,然后等待IRQ handler和threaded handler执行完成。后续详细分析这一块。
3) 针对仅仅enable的irq,设置IRQS_SUSPENDED标志位,并disable irq。
4) 图中第④步关闭noboot cpu,紧接着第⑤步diasble boot cpu的irq,即cpu不在响应中断。
5) 在cpu sleep之前进行最后一步操作就是syscore suspend。既然是最后suspend,那一定是其他device都依赖的系统核心驱动。后面说说什么的设备会注册syscore suspend。
2.3. resume流程
假设我们使用的是gic-v3代码,边沿触发中断设备。现在设备需要唤醒系统了,产生一个边沿电平触发中断。此时会唤醒boot cpu(因为noboot cpu在suspend的时候已经被disable)。你以为此时就开始跳转中断服务函数了吗?no!还记得上一节说的吗?suspend之后已经diasble boot cpu的irq,因此中断不会立即执行。什么时候呢?当然是等到local_irq_enable()之后。resume流程如下图。
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-77051-3.html
这充分说明我国強大的国防能力
估计都敢骑他头上