irq wakeup in linux
作者:schspa 发布于:2021-11-15 18:41 分类:电源管理子系统
irq wakeup in linux
Table of Contents
术语
简写 | 全称 |
TRM | Technical Reference Manual |
GIC | Generic Interrupt Controller |
smccc | SMC CALLING CONVENTION |
硬件架构
在本篇文章中基于AARCH64平台,GIC作为中断控制器来进行讨论
下面是GIC-600的系统框架图:
看图可知,Wake Request模块就是为了唤醒功能提供的信号输出。
gic对唤醒功能的支持
在gic600的TRM手册中,可以看到gic600有wake_request的输出信号,Power controller可以根据这个信号来将对应的cpu唤醒。
唤醒信号:
Signal | Type | Source or destination | Description |
wake_request[ |
Output |
Power controller |
Wake request signal to power controller indicating that an interrupt is targeting this core and it must be woken. When asserted, the wake_request is sticky unless the Distributor is put into the gated state. |
GIC power down ?
GIC可以被关闭电源,也可以不关闭电源,这个在SOC设计阶段就可以选择。
对于Arm gic来言,一般具有两种情况
-
GIC处于always on的power domain之中,这样gic在休眠时由于没有断电,仍旧可以正常工作,任何的中断都可以正常唤醒soc 1, 如图中的Wakeup Request的信号
-
GIC在可以断电的power domain中,这样在休眠时一般都会对gic进行断电,这种状况下,系统需要soc特定的实现来进行唤醒。
具体实现各家SOC都不相同,在此不做讨论,只需要知道这个唤醒功能和GIC没有关系,完全由SOC厂商在设计时实现。
CPU Power Down
下面是ARM Crotext A55 CPU的下电流程,CPU有寄存器CPUPWRCTLR来控制电源控制相关功能,当CPUPWRCTLR.CORE_PWRDN_EN置1时,就是代表CPU在下次执行WFI指令时要进入掉电状态。2
The Cortex-A55 core uses the following power down sequence.
To power down a core, perform the following programming sequence:
- Save all architectural state.
- Configure the GIC distributor to disable or reroute interrupts away from this core.
- Set the CPUPWRCTLR.CORE_PWRDN_EN bit to 1 to indicate to the power controller that a powerdown is requested.
- Execute an Instruction Synchronization Barrier (ISB) instruction.
- Execute a WFI instruction.
After executing WFI and then receiving a powerdown request from the power controller, the hardware performs the following:
• Disabling and flushing of caches (L1 and L2).
• Removal of the core from coherency.
从上面的掉电流程可知,A55在下电时,还需要SOC内部power controller的支持,不同的SOC厂商实现的方式千奇百怪,并且设计泄密在此不做深入。
CPU Power Up
从上边Power Down的流程可知,系统在进入Power Down之后需要进行reset才可以将CPU重新启动,具体的过程也是SOC厂商自己定义的行为,没有太大分析的必要。
Reset之后,CPU需要从RVBAR寄存器所显示的地址来重新启动。RVBAR寄存器是通过CPU的外部信号线进行输入的。
RESET的执行地址
由于没有在A55的TRM中找到关于此信号的定义,拿A53的来充个数。
从手册可知,复位执行地址是可以通过配置来修改的,并且4byte对齐(因为bit0,1不可配置)
Suspend In Linux
下图是Linux系统中suspend以及resume的流程图,图中以PSCI为例,描写了系统在休眠时的调用流程。
上面的流程着重描写了系统通过PSCI休眠时的调用流程,包括Linux系统从休眠状态唤醒之后的resume流程。
Linux唤醒时,运行的Linux内核的第一段指令是cpu_resume,之后再经过arm64 psci相关的一系列调用返回到psci_system_suspend_enter继续执行。
Linux irq wakeup
在Linux系统中,如果想要唤醒已经进入休眠状态中的cpu,就需要通过~enable_irq_wake~来设置开启唤醒功能3。
实际上,芯片支持的唤醒源个数是有限的,并不是每种中断都可以正常的唤醒系统。
irq flags
IRQCHIP_MASK_ON_SUSPEND
Mask non wake irqs in the suspend path
IRQCHIP_SKIP_SET_WAKE
Skip chip.irq_set_wake(), for this irq chip
由以下patch引入,提交说明已经很明确
60f96b41f71d2a13d1c0a457b8b77958f77142d1 Author: Santosh Shilimkar <santosh.shilimkar@ti.com> AuthorDate: Fri Sep 9 13:59:35 2011 +0530 Commit: Thomas Gleixner <tglx@linutronix.de> CommitDate: Mon Sep 12 09:52:49 2011 +0200 Parent: ed585a651681e genirq: Make irq_shutdown() symmetric vs. irq_startup again Contained: (no branch) master Follows: v3.1-rc5 (93) Precedes: v3.2-rc1 (11433) genirq: Add IRQCHIP_SKIP_SET_WAKE flag Some irq chips need the irq_set_wake() functionality, but do not require a irq_set_wake() callback. Instead of forcing an empty callback to be implemented add a flag which notes this fact. Check for the flag in set_irq_wake_real() and return success when set. Signed-off-by: Santosh Shilimkar <santosh.shilimkar@ti.com> Cc: Thomas Gleixner <tglx@linutronix.de>
arm-gic
在arm gic的实现中,既没有提供IRQCHIP_SKIP_SET_WAKE的flag,也没有实现set_irq_wake的实现。这是因为Linux内核认为gic不处理休眠唤醒的问题,这些应该由平台来基于stacked irqchip来实现。4
Marc Zyngier在内核的邮件有如下回复
I don't have any strong feeling against this series (anything that
removes hacks from the GIC code has my full and unconditional support),
but I'd just like to make sure I understand the issue.There is (AFAIU) 3 cases when suspending:
- The GIC is in an always-on domain: SKIP_SET_WAKE is set, because
there is nothing to do (we can always wake up). Problem solved.
- The GIC gets powered off, but we have additional HW that will take
care of the wake-up: this is implemented by a stacked irqchip that will
do the right thing: irq_set_wake only looks at the top level irqchip, so
the GIC flag isn't observed, and this should work (maybe by luck…).
- The GIC gets powered off and nothing will wake us up. I'd say that in
this case, having programmed a wake-up interrupt is a bit silly, and
doing S2R is equivalent to committing suicide. Do we have any mechanism
that would avoid getting in that situation?Thanks,
M.
在Marc Zyngier的回复中,已经提到3种case
-
GIC处于always on的电源域,这种情况下,通过设置SKIP_SET_WAKE就可以简单的解决我们的问题,因为不需要做任何事,系统总可以通过gic来唤醒。
-
GIC会被掉电,这种情况下,需要额外的硬件来将系统唤醒(意味着各个SOC厂商都有各不相同的实现),这种情况下,gic的驱动也无法去处理,这就需要通过stacked irqchip来实现,平台的irqchip通过作为顶级的irqchip,gic作为下级irqchip就可以由SOC厂商去具体定制唤醒功能的设置。
-
GIC会掉电,没有任何办法唤醒系统。这种情况完全是错误的,休眠等于自杀,需要避免进入这个状况。
所以当soc据有唤醒能力时,需要通过平台的gic驱动来实现,arm gic驱动作为平台gic的父设备。
linux内核接口
-
/sys/power/pm_wakeup_irq
可以查询到最近一次休眠的唤醒源
implement stacked irqchip
used function & macors
-
IRQCHIP_DECLARE
用来声明一个irqchip驱动,包含compatible属性,irqchip的名称,以及初始化函数
device tree
dts中配置了sysirq,其parent是gic,gic: interrupt-controller@58000000 { status = "okay"; compatible = "arm,gic-v3"; #interrupt-cells = <3>; #address-cells = <2>; #size-cells = <2>; ranges; interrupt-controller; reg = <0x0 0x58000000 0x0 0x10000>, // GICD <0x0 0x58040000 0x0 0x100000>; // GICR0~7 interrupts = <1 9 4>; }; sysirq: sysirq@system { compatible = "xxx,XX-sysirq", "syscon"; #interrupt-cells = <3>; interrupt-parent = <&gic>; interrupt-controller; ranges; services = <&tee_regmap>; irq-map = <48 2 0>, // GPIO <29 4 1>, // AON RTC <31 6 0>, // aon timer1 <30 8 0>, // aon time0 <9 10 0>, // eth0 <33 18 0>, // canfd0 <36 14 0>; // canfd1 reg = <0x0 0x43060000 0x0 0x634>; };
-
get map configuration from device tree node.
irq-map = <irq-number enable-bit polar-bit>; #address-cells = <2>; #size-cells = <2>; reg = <0x0 0x43840000 0x0 0x634>;
irq domain
关于irq domain可以参考以下文档
https://lwn.net/Articles/487684/
irq initialization
(gdb) bt #0 XX_irq_of_init (node=0xffffffc03efed568, parent=0x0 <bl1_entrypoint>) at ./include/linux/irqdomain.h:298 #1 0xffffff8008856224 in of_irq_init (matches=<optimized out>) at drivers/of/irq.c:546 #2 0xffffff8008849240 in irqchip_init () at drivers/irqchip/irqchip.c:29 #3 0xffffff800883241c in init_IRQ () at arch/arm64/kernel/irq.c:91 #4 0xffffff80088309f8 in start_kernel () at init/main.c:611 #5 0x0000000000000000 in ?? () Backtrace stopped: previous frame identical to this frame (corrupt stack?)
查找partent的irq, 并添加新的irq_domain
domain_parent = irq_find_host(parent); if (!domain_parent) { pr_err("XX_irq: interrupt-parent not found\n"); return -EINVAL; } domain = irq_domain_add_hierarchy(domain_parent, 0, intpol_num, node, &sysirq_domain_ops, chip_data); if (!domain) { ret = -ENOMEM; goto out_unmap; }
上面是主要内容,分为两步
-
获取parent的irq domain
-
添加新的irq_domain来实现需要的操作
irq domain ops
static int XX_irq_domain_translate(struct irq_domain *d, struct irq_fwspec *fwspec, unsigned long *hwirq, unsigned int *type) { if (is_of_node(fwspec->fwnode)) { if (fwspec->param_count != 3) return -EINVAL; /* No PPI should point to this domain */ if (fwspec->param[0] != GIC_SPI) return -EINVAL; *hwirq = fwspec->param[1]; *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK; return 0; } return -EINVAL; } static const struct irq_domain_ops sysirq_domain_ops = { .translate = XX_irq_domain_translate, .alloc = XX_irq_domain_alloc, .free = irq_domain_free_irqs_common, };
其中最重要的就是 translate 接口,这个接口实现了irq号的转换功能。
ATF软件
arm atf中实现了psci协议,当系统休眠时,可以通过psci来进入休眠。psci方法:PSCI_CPU_SUSPEND_AARCH64,PSCI_CPU_SUSPEND_AARCH32
suspend的方法原型为:
int psci_cpu_suspend(unsigned int power_state, uintptr_t entrypoint, u_register_t context_id);
参数:
- power_state
-
power_state参数比较复杂,power_state定义了系统要处于的低功耗模式,根据系统的实现,有两种格式可供选择。
- entrypoint
-
resume之后的入口地址,需要提供PA,或者IPA
The entry_point_address parameter is used by the caller to specify where code execution needs to resume at wakeup time. The parameter must be a Physical Address (PA), or, for a guest OS in a virtualized platform, an Intermediate Physical Address (IPA). In this case, the hypervisor must trap the call. Further details can be found in section
- context_id
-
回传参数,当系统resume之后,psci将这个值放入X0/W0/R0,作为第一个参数传递过去。
平台相关实现
在平台的实现中,ATF有几个函数是需要SOC平台进行实现的。
在atf中,psci lib已经实现了平台无关部份的代码,部份代码需要soc平台来根据自己的需要来实现。psci lib中与休眠唤醒关系不大,上述参数中entrypoint以及context_id都时psci代码来处理,SOC平台无需关心此部份代码。
为了有一个对atf中的休眠唤醒流程有一个直观的影响,使用下面的代码调用时序图来说明
标签: suspend sleep 电源管理 中断子系统 aarch64

评论:
2021-11-26 12:40
arm gic驱动作为平台gic的父设备。
从下方示例中可以看到:gic是sysirq的parent
sysirq: sysirq@system {
compatible = "xxx,XX-sysirq", "syscon";
#interrupt-cells = <3>;
interrupt-parent = <&gic>;
interrupt-controller;
ranges;
services = <&tee_regmap>;
irq-map = <48 2 0>, // GPIO
<29 4 1>, // AON RTC
<31 6 0>, // aon timer1
<30 8 0>, // aon time0
<9 10 0>, // eth0
<33 18 0>, // canfd0
<36 14 0>; // canfd1
reg = <0x0 0x43060000 0x0 0x634>;
};
功能
最新评论
- wangjing
写得太好了 - wangjing
写得太好了! - DRAM
圖面都沒辦法顯示出來好像掛點了。 - Simbr
bus至少是不是还有个subsystem? - troy
@testtest:只要ldrex-modify-strex... - gh
Linux 内核在 sparse 内存模型基础上实现了vme...
文章分类
随机文章
文章存档
- 2025年4月(5)
- 2024年2月(1)
- 2023年5月(1)
- 2022年10月(1)
- 2022年8月(1)
- 2022年6月(1)
- 2022年5月(1)
- 2022年4月(2)
- 2022年2月(2)
- 2021年12月(1)
- 2021年11月(5)
- 2021年7月(1)
- 2021年6月(1)
- 2021年5月(3)
- 2020年3月(3)
- 2020年2月(2)
- 2020年1月(3)
- 2019年12月(3)
- 2019年5月(4)
- 2019年3月(1)
- 2019年1月(3)
- 2018年12月(2)
- 2018年11月(1)
- 2018年10月(2)
- 2018年8月(1)
- 2018年6月(1)
- 2018年5月(1)
- 2018年4月(7)
- 2018年2月(4)
- 2018年1月(5)
- 2017年12月(2)
- 2017年11月(2)
- 2017年10月(1)
- 2017年9月(5)
- 2017年8月(4)
- 2017年7月(4)
- 2017年6月(3)
- 2017年5月(3)
- 2017年4月(1)
- 2017年3月(8)
- 2017年2月(6)
- 2017年1月(5)
- 2016年12月(6)
- 2016年11月(11)
- 2016年10月(9)
- 2016年9月(6)
- 2016年8月(9)
- 2016年7月(5)
- 2016年6月(8)
- 2016年5月(8)
- 2016年4月(7)
- 2016年3月(5)
- 2016年2月(5)
- 2016年1月(6)
- 2015年12月(6)
- 2015年11月(9)
- 2015年10月(9)
- 2015年9月(4)
- 2015年8月(3)
- 2015年7月(7)
- 2015年6月(3)
- 2015年5月(6)
- 2015年4月(9)
- 2015年3月(9)
- 2015年2月(6)
- 2015年1月(6)
- 2014年12月(17)
- 2014年11月(8)
- 2014年10月(9)
- 2014年9月(7)
- 2014年8月(12)
- 2014年7月(6)
- 2014年6月(6)
- 2014年5月(9)
- 2014年4月(9)
- 2014年3月(7)
- 2014年2月(3)
- 2014年1月(4)
2021-11-26 09:57
2.GIC会被掉电,这种情况下,需要额外的硬件来将系统唤醒(意味着各个SOC厂商都有各不相同的实现),这种情况下,gic的驱动也无法去处理,这就需要通过stacked irqchip来实现,平台的irqchip通过作为顶级的irqchip,gic作为下级irqchip就可以由SOC厂商去具体定制唤醒功能的设置。
所以当soc据有唤醒能力时,需要通过平台的gic驱动来实现,arm gic驱动作为平台gic的父设备。"
这两段描述有冲突吧!vendor的irqchip 和arm的gic,到底谁是在最顶级?谁做父设备?