enable_irq_wake是如何起作用的

本文深入探讨了Linux内核中enable_irq_wake函数的作用及其实现原理,解释了如何通过该函数使中断具备唤醒系统的功能,从低功耗状态如suspendtoRAM中唤醒系统。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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可以将其从睡眠中唤醒。

<< `Error_Handler` 和 `__disable_irq` 是 C 语言中与嵌入式系统开发相关的两个概念或工具。它们的作用分别用于错误处理以及中断管理。 ### Error_Handler `Error_Handler`通常不是一个标准库函数,而是开发者自己定义的一个通用错误处理器。它的主要作用是在程序检测到无法恢复的严重错误时被调用。例如,在初始化外设失败、非法参数传递等情况下会触发该函数。下面是一个简单的示例: ```c void Error_Handler(void) { // Infinite loop; use interrupt to wake-up in real applications. while (1); } ``` **解释**: 这个版本的 `Error_Handler` 实现了一个死循环。当进入这个函数后,程序将无限期地等待在这里直到外部干预(如硬件复位)。这适合于那些不能容忍任何异常情况的应用场景。当然也可以根据具体需求扩展此功能,比如记录日志数据到非易失存储器,点亮LED指示灯等操作。 ### __disable_irq 函数 `__disable_irq()` 是 ARM Cortex-M 微控制器系列中的一个内联汇编指令封装形式,用于关闭全局中断请求(IRQs),即禁止所有可屏蔽中断的发生直至重新启用为止。它有助于保护临界区内的代码段不受中断干扰。使用方法如下所示: ```c #include "core_cmRx.h" // 根据具体的ARM Cortex M核选择对应的头文件, 比如 core_cm0.h 或者 core_cm3.h etc. // Enter critical section by disabling interrupts globally. __disable_irq(); // Critical code goes here... // Leave critical section and re-enable interrupts if previously enabled. __enable_irq(); ``` **注意:** 在直接操纵中断状态之前应当保存当前的状态以便后续能够正确还原。但上述例子仅展示了最基本用法而没有考虑这一点。如果要更安全地控制,则需结合`portSET_INTERRUPT_MASK_FROM_ISR()`之类的API或者手动读取并存档PRIMASK寄存器值来完成类似任务。 **解释**: 关闭中断对于某些实时性要求高的应用非常必要,特别是在访问共享资源的时候防止竞态条件(race condition)出现。然而长时间禁用中断会影响系统的响应速度甚至可能导致错过重要事件所以必须谨慎运用且尽量缩短无中断期间长度。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值