enable_irq_wake是如何起作用的
在linux kernel中,调用enable_irq_wake函数,可以将一个irq具有唤醒系统的功能,即把系统从低功耗模式中唤醒,如从suspend to RAM中唤醒。
enable_irq_wake具体如何起作用的呢,今天来学习学习。
先从函数enable_irq_wake开始,实现很简单:
static inline int enable_irq_wake(unsigned int irq) { return irq_set_irq_wake(irq, 1); }
函数irq_set_irq_wake的实现也不是很复杂,并且有注释说明,容易理解:
/** * irq_set_irq_wake - control irq power management wakeup * @irq: interrupt to control * @on: enable/disable power management wakeup * * Enable/disable power management wakeup mode, which is * disabled by default. Enables and disables must match, * just as they match for non-wakeup mode support. * * Wakeup mode lets this IRQ wake the system from sleep * states like "suspend to RAM". */ int irq_set_irq_wake(unsigned int irq, unsigned int on) { unsigned long flags; struct irq_desc *desc = irq_get_desc_buslock(irq, &flags); int ret = 0; if (!desc) return -EINVAL; /* wakeup-capable irqs can be shared between drivers that * don‘t need to have the same sleep mode behaviors. */ if (on) { if (desc->wake_depth++ == 0) { 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; }
其中关键的代码是计数:desc->wake_depth++, 以及调用函数set_irq_wake_real。
set_irq_wake_real函数调用到了具体cpu相关的代码:
static int set_irq_wake_real(unsigned int irq, unsigned int on) { struct irq_desc *desc = irq_to_desc(irq); int ret = -ENXIO; if (desc->irq_data.chip->irq_set_wake) ret = desc->irq_data.chip->irq_set_wake(&desc->irq_data, on); return ret; }
irq_set_wake为cpu相关代码。
例如,xxx cpu对应的arch\arm\mach-xxx\Irq.c文件中,xxx_init_irq函数中有如下语句:
desc->irq_data.chip->irq_set_wake = xxx_gic_irq_set_wake;
xxx_gic_irq_set_wake的实现将irq mask,结果保存在一个数组中gpc_wake_irq。
cpu在做power on/off时会使用到该数组。
如mach-xxx\system.c中的函数xxx_cpu_lp_set中有如下代码:
gpc_set_wakeup(gpc_wake_irq);
函数gpc_set_wakeup的实现:
void gpc_set_wakeup(unsigned int irq[4]) { /* Mask all wake up source */ __raw_writel(~irq[0], gpc_base + 0x8); __raw_writel(~irq[1], gpc_base + 0xc); __raw_writel(~irq[2], gpc_base + 0x10); __raw_writel(~irq[3], gpc_base + 0x14); return; }
将irq mask设置到了cpu中。
中cpu的suspend enter函数中,会调用xxx_cpu_lp_set函数。
如xxx_suspend_enter函数中有如下代码:
switch (state) { case PM_SUSPEND_MEM: ... mxc_cpu_lp_set(ARM_POWER_OFF); arm_pg = true; break; ... }
至此,流程基本清晰了。
enable_irq_wake函数会将irq mask到一个数组。
在进入suspend时,会将irq mask写入到cpu。
也就是告诉cpu哪些irq可以将其从睡眠中唤醒。
enable_irq_wake是如何起作用的,布布扣,bubuko.com
原文:http://blog.csdn.net/njuitjf/article/details/21475405