Linux 通用 IRQ 处理¶
- 版权:
© 2005-2010: Thomas Gleixner
- 版权:
© 2005-2006: Ingo Molnar
引言¶
通用中断处理层旨在为设备驱动程序提供完整的中断处理抽象。它能够处理所有不同类型的中断控制器硬件。设备驱动程序使用通用 API 函数来请求、启用、禁用和释放中断。驱动程序无需了解任何中断硬件细节,因此它们可以在不同平台上使用而无需修改代码。
本文档提供给希望在其架构上实现基于通用 IRQ 处理层的中断子系统的开发人员。
原理¶
Linux 中中断处理的原始实现使用了 __do_IRQ()
超级处理程序,它能够处理各种类型的中断逻辑。
最初,Russell King 识别了不同类型的处理程序,为 Linux 2.5/2.6 中的 ARM 中断处理程序实现构建了一个相当通用的集合。他区分了:
电平触发类型
边沿触发类型
简单类型
在实现过程中,我们识别了另一种类型:
快速 EOI 类型
在 __do_IRQ()
超级处理程序的 SMP 世界中,识别出另一种类型:
每 CPU 类型
这种高级 IRQ 处理程序的拆分实现允许我们优化每种特定中断类型的处理流程。这减少了特定代码路径中的复杂性,并允许对给定类型进行优化处理。
原始的通用 IRQ 实现使用 hw_interrupt_type
结构及其 ->ack
、->end
[等] 回调函数来区分超级处理程序中的流程控制。这导致了流程逻辑和低级硬件逻辑的混淆,也导致了不必要的代码重复:例如,在 i386 中,有 ioapic_level_irq
和 ioapic_edge_irq
这两种 IRQ 类型,它们共享许多低级细节但具有不同的流程处理。
更自然的抽象是“irq 流”和“芯片细节”的清晰分离。
分析一些架构的 IRQ 子系统实现表明,它们中的大多数可以使用一组通用的“irq 流”方法,只需要添加芯片级特定代码。这种分离对于需要在 IRQ 流本身而不是芯片细节中进行特定调整的(子)架构也很有价值——因此提供了更透明的 IRQ 子系统设计。
每个中断描述符都分配有自己的高级流处理程序,通常是通用实现之一。(这种高级流处理程序实现还使得提供解复用处理程序变得简单,这可以在各种架构上的嵌入式平台中找到。)
这种分离使通用中断处理层更加灵活和可扩展。例如,一个(子)架构可以为“电平触发”中断使用通用 IRQ 流实现,并添加一个(子)架构特定的“边沿触发”实现。
为了使向新模型的过渡更容易并防止现有实现的破坏,__do_IRQ()
超级处理程序仍然可用。这导致了暂时的一种二元性。随着时间的推移,新模型应该在越来越多的架构中使用,因为它能够实现更小、更干净的 IRQ 子系统。它现在已经被弃用三年了,即将被移除。
已知错误和假设¶
无(敲木头)。
抽象层¶
中断代码中有三个主要的抽象级别:
高级驱动程序 API
高级 IRQ 流处理程序
芯片级硬件封装
中断控制流¶
每个中断都由一个中断描述符结构 irq_desc
描述。中断通过一个“无符号整数”数值引用,该数值在描述符结构数组中选择相应的中断描述结构。描述符结构包含状态信息以及指向分配给此中断的中断流方法和中断芯片结构的指针。
每当中断触发时,低级架构代码通过调用 desc->handle_irq()
进入通用中断代码。此高级 IRQ 处理函数仅使用由分配的芯片描述符结构引用的 desc->irq_data.chip
原语。
高级驱动程序 API¶
高级驱动程序 API 包含以下函数:
disable_irq_nosync()
(仅限 SMP)synchronize_irq()
(仅限 SMP)
详情请参阅自动生成的函数文档。
高级 IRQ 流处理程序¶
通用层提供了一组预定义的中断流方法:
handle_edge_eoi_irq()
中断流处理程序(无论是预定义的还是特定于架构的)由架构在启动期间或设备初始化期间分配给特定的中断。
默认流实现¶
辅助函数¶
辅助函数调用芯片原语,并由默认流实现使用。以下辅助函数已实现(简化摘录):
default_enable(struct irq_data *data)
{
desc->irq_data.chip->irq_unmask(data);
}
default_disable(struct irq_data *data)
{
if (!delay_disable(data))
desc->irq_data.chip->irq_mask(data);
}
default_ack(struct irq_data *data)
{
chip->irq_ack(data);
}
default_mask_ack(struct irq_data *data)
{
if (chip->irq_mask_ack) {
chip->irq_mask_ack(data);
} else {
chip->irq_mask(data);
chip->irq_ack(data);
}
}
noop(struct irq_data *data)
{
}
默认流处理程序实现¶
默认电平 IRQ 流处理程序¶
handle_level_irq
为电平触发中断提供通用实现。
实现以下控制流(简化摘录):
desc->irq_data.chip->irq_mask_ack();
handle_irq_event(desc->action);
desc->irq_data.chip->irq_unmask();
默认快速 EOI IRQ 流处理程序¶
handle_fasteoi_irq
为仅在处理程序结束时需要 EOI 的中断提供通用实现。
实现以下控制流(简化摘录):
handle_irq_event(desc->action);
desc->irq_data.chip->irq_eoi();
默认边沿 IRQ 流处理程序¶
handle_edge_irq
为边沿触发中断提供通用实现。
实现以下控制流(简化摘录):
if (desc->status & running) {
desc->irq_data.chip->irq_mask_ack();
desc->status |= pending | masked;
return;
}
desc->irq_data.chip->irq_ack();
desc->status |= running;
do {
if (desc->status & masked)
desc->irq_data.chip->irq_unmask();
desc->status &= ~pending;
handle_irq_event(desc->action);
} while (desc->status & pending);
desc->status &= ~running;
默认简单 IRQ 流处理程序¶
handle_simple_irq
为简单中断提供通用实现。
注意
简单流处理程序不调用任何处理程序/芯片原语。
实现以下控制流(简化摘录):
handle_irq_event(desc->action);
默认每 CPU 流处理程序¶
handle_percpu_irq
为每 CPU 中断提供通用实现。
每 CPU 中断仅在 SMP 上可用,处理程序提供了一个没有锁定的简化版本。
实现以下控制流(简化摘录):
if (desc->irq_data.chip->irq_ack)
desc->irq_data.chip->irq_ack();
handle_irq_event(desc->action);
if (desc->irq_data.chip->irq_eoi)
desc->irq_data.chip->irq_eoi();
EOI 边沿 IRQ 流处理程序¶
handle_edge_eoi_irq
提供了一个边沿处理程序的异常情况,它仅用于驯服 powerpc/cell 上一个严重损坏的 irq 控制器。
不良 IRQ 流处理程序¶
handle_bad_irq
用于没有实际处理程序分配的伪中断。
怪癖和优化¶
通用函数旨在用于“干净”的架构和芯片,这些架构和芯片没有平台特定的 IRQ 处理怪癖。如果架构需要在“流”级别实现怪癖,则可以通过覆盖高级 irq 流处理程序来实现。
延迟中断禁用¶
此每中断可选功能由 Russell King 在 ARM 中断实现中引入,当调用 disable_irq()
时,它不会在硬件级别屏蔽中断。中断保持启用状态,并在发生中断事件时在流处理程序中屏蔽。这可以防止在硬件级别禁用中断时,硬件不存储边沿中断事件而丢失边沿中断。当 IRQ_DISABLED 标志设置时中断到来时,中断在硬件级别被屏蔽,并且 IRQ_PENDING 位被设置。当通过 enable_irq()
重新启用中断时,会检查 pending 位,如果设置,则通过硬件或软件重发机制重新发送中断。(如果您想使用延迟中断禁用功能并且您的硬件无法重新触发中断,则需要启用 CONFIG_HARDIRQS_SW_RESEND。)延迟中断禁用不可配置。
芯片级硬件封装¶
芯片级硬件描述符结构 irq_chip
包含所有直接与芯片相关的功能,这些功能可以被 irq 流实现使用。
irq_ack
irq_mask_ack
- 可选,建议用于性能irq_mask
irq_unmask
irq_eoi
- 可选,EOI 流处理程序必需irq_retrigger
- 可选irq_set_type
- 可选irq_set_wake
- 可选
这些原语严格按照其字面意思:ack 表示 ACK,masking 表示屏蔽 IRQ 线等。流处理程序(或多个处理程序)负责使用这些低级功能的基本单元。
__do_IRQ 入口点¶
原始实现 __do_IRQ()
是所有类型中断的替代入口点。它不再存在。
此处理程序被证明不适用于所有中断硬件,因此已使用针对边沿/电平/简单/每CPU 中断的拆分功能重新实现。这不仅是功能优化,还缩短了中断的代码路径。
SMP 上的锁定¶
芯片寄存器的锁定由定义芯片原语的架构负责。每个中断结构通过 desc->lock
受通用层保护。
通用中断芯片¶
为了避免重复的 IRQ 芯片实现,核心提供了可配置的通用中断芯片实现。开发人员在自己以略微不同的方式实现相同功能之前,应仔细检查通用芯片是否符合其需求。
参数
struct irq_data *d
irq_data
参数
struct irq_data *d
irq_data
描述
芯片有独立的启用/禁用寄存器,而不是单个屏蔽寄存器。
参数
struct irq_data *d
irq_data
描述
芯片有一个单一的屏蔽寄存器。该寄存器的值被缓存并受 gc->lock 保护。
参数
struct irq_data *d
irq_data
描述
芯片有一个单一的屏蔽寄存器。该寄存器的值被缓存并受 gc->lock 保护。
参数
struct irq_data *d
irq_data
描述
芯片有独立的启用/禁用寄存器,而不是单个屏蔽寄存器。
参数
struct irq_data *d
irq_data
参数
struct irq_data *d
irq_data
描述
此 irq_mask_ack
方法的通用实现适用于具有独立启用/禁用寄存器而非单个屏蔽寄存器的芯片,并且挂起中断通过设置位来确认。
注意
这是目前唯一使用的排列组合。如果需要其他排列组合,应在此处添加类似的通用函数。
参数
struct irq_data *d
irq_data
unsigned int on
指示是否应设置或清除唤醒位
描述
对于唤醒挂起功能未在单独寄存器中配置,且唤醒活动状态仅存储在位掩码中的芯片。
-
struct irq_chip_generic *irq_alloc_generic_chip(const char *name, int num_ct, unsigned int irq_base, void __iomem *reg_base, irq_flow_handler_t handler)¶
分配通用芯片并初始化
参数
const char *name
irq 芯片的名称
int num_ct
与此相关的 irq_chip_type 实例数量
unsigned int irq_base
此芯片的中断基数
void __iomem *reg_base
寄存器基地址(虚拟)
irq_flow_handler_t handler
与此芯片关联的默认流处理程序
描述
返回一个已初始化的 irq_chip_generic
结构。芯片默认为主要(索引 0)的 irq_chip_type
和 handler
-
int irq_domain_alloc_generic_chips(struct irq_domain *d, const struct irq_domain_chip_generic_info *info)¶
为 irq 域分配通用芯片
参数
struct irq_domain *d
要分配芯片的 irq 域
const struct irq_domain_chip_generic_info *info
通用芯片信息
返回
成功返回 0,失败返回负错误码
-
void irq_domain_remove_generic_chips(struct irq_domain *d)¶
从 irq 域中移除通用芯片
参数
struct irq_domain *d
要移除通用芯片的 irq 域
-
int __irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip, int num_ct, const char *name, irq_flow_handler_t handler, unsigned int clr, unsigned int set, enum irq_gc_flags gcflags)¶
为 irq 域分配通用芯片
参数
struct irq_domain *d
要分配芯片的 irq 域
int irqs_per_chip
每个芯片处理的中断数量(最大 32)
int num_ct
与此相关的 irq_chip_type 实例数量
const char *name
irq 芯片的名称
irq_flow_handler_t handler
与这些芯片关联的默认流处理程序
unsigned int clr
在映射函数中要清除的 IRQ_* 位
unsigned int set
在映射函数中要设置的 IRQ_* 位
enum irq_gc_flags gcflags
通用芯片特定设置标志
-
struct irq_chip_generic *irq_get_domain_generic_chip(struct irq_domain *d, unsigned int hw_irq)¶
获取 hw_irq 的通用芯片指针
参数
struct irq_domain *d
irq 域指针
unsigned int hw_irq
硬件中断号,相对于中断域本地
-
void irq_setup_generic_chip(struct irq_chip_generic *gc, u32 msk, enum irq_gc_flags flags, unsigned int clr, unsigned int set)¶
使用通用芯片设置一系列中断
参数
struct irq_chip_generic *gc
包含所有数据的通用 irq 芯片
u32 msk
包含要初始化 irq 的位掩码,相对于 gc->irq_base
enum irq_gc_flags flags
初始化标志
unsigned int clr
要清除的 IRQ_* 位
unsigned int set
要设置的 IRQ_* 位
描述
设置从 gc->irq_base 开始最多 32 个中断。注意,这将所有中断初始化为主 irq_chip_type 及其关联的处理程序。
参数
struct irq_data *d
此中断的 irq_data
unsigned int type
要初始化的流类型
描述
只能从 chip->irq_set_type() 回调中调用。
-
void irq_remove_generic_chip(struct irq_chip_generic *gc, u32 msk, unsigned int clr, unsigned int set)¶
移除芯片
参数
struct irq_chip_generic *gc
包含所有数据的通用 irq 芯片
u32 msk
包含要初始化 irq 的位掩码,相对于 gc->irq_base
unsigned int clr
要清除的 IRQ_* 位
unsigned int set
要设置的 IRQ_* 位
描述
移除从 gc->irq_base 开始最多 32 个中断。
结构体¶
本章包含通用 IRQ 层中使用的结构的自动生成文档。
-
struct irq_common_data¶
所有 irqchip 共享的每个 irq 数据
定义:
struct irq_common_data {
unsigned int __private state_use_accessors;
#ifdef CONFIG_NUMA;
unsigned int node;
#endif;
void *handler_data;
struct msi_desc *msi_desc;
#ifdef CONFIG_SMP;
cpumask_var_t affinity;
#endif;
#ifdef CONFIG_GENERIC_IRQ_EFFECTIVE_AFF_MASK;
cpumask_var_t effective_affinity;
#endif;
#ifdef CONFIG_GENERIC_IRQ_IPI;
unsigned int ipi_offset;
#endif;
};
成员
state_use_accessors
irq 芯片函数的状态信息。使用访问器函数处理它
node
用于平衡的节点索引
handler_data
用于 irq_chip 方法的每个 IRQ 数据
msi_desc
MSI 描述符
affinity
SMP 上的 IRQ 亲和性。如果这是 IPI 相关 irq,则这是可以发送 IPI 的 CPU 掩码。
effective_affinity
SMP 上的有效 IRQ 亲和性,因为某些 irq 芯片不允许多 CPU 目标。是 affinity 的一个子集。
ipi_offset
affinity 中第一个 IPI 目标 CPU 的偏移量。可选。
-
struct irq_data¶
传递给芯片函数的每个 irq 芯片数据
定义:
struct irq_data {
u32 mask;
unsigned int irq;
irq_hw_number_t hwirq;
struct irq_common_data *common;
struct irq_chip *chip;
struct irq_domain *domain;
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY;
struct irq_data *parent_data;
#endif;
void *chip_data;
};
成员
mask
用于访问芯片寄存器的预计算位掩码
irq
中断号
hwirq
硬件中断号,相对于中断域本地
common
指向所有 irqchip 共享的数据
chip
低级中断硬件访问
domain
中断转换域;负责硬件中断号和 Linux 中断号之间的映射。
parent_data
指向父
struct irq_data
的指针,以支持层次结构 irq_domainchip_data
用于芯片方法的平台特定每个芯片私有数据,以允许共享芯片实现
-
struct irq_chip¶
硬件中断芯片描述符
定义:
struct irq_chip {
const char *name;
unsigned int (*irq_startup)(struct irq_data *data);
void (*irq_shutdown)(struct irq_data *data);
void (*irq_enable)(struct irq_data *data);
void (*irq_disable)(struct irq_data *data);
void (*irq_ack)(struct irq_data *data);
void (*irq_mask)(struct irq_data *data);
void (*irq_mask_ack)(struct irq_data *data);
void (*irq_unmask)(struct irq_data *data);
void (*irq_eoi)(struct irq_data *data);
int (*irq_set_affinity)(struct irq_data *data, const struct cpumask *dest, bool force);
int (*irq_retrigger)(struct irq_data *data);
int (*irq_set_type)(struct irq_data *data, unsigned int flow_type);
int (*irq_set_wake)(struct irq_data *data, unsigned int on);
void (*irq_bus_lock)(struct irq_data *data);
void (*irq_bus_sync_unlock)(struct irq_data *data);
#ifdef CONFIG_DEPRECATED_IRQ_CPU_ONOFFLINE;
void (*irq_cpu_online)(struct irq_data *data);
void (*irq_cpu_offline)(struct irq_data *data);
#endif;
void (*irq_suspend)(struct irq_data *data);
void (*irq_resume)(struct irq_data *data);
void (*irq_pm_shutdown)(struct irq_data *data);
void (*irq_calc_mask)(struct irq_data *data);
void (*irq_print_chip)(struct irq_data *data, struct seq_file *p);
int (*irq_request_resources)(struct irq_data *data);
void (*irq_release_resources)(struct irq_data *data);
void (*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
void (*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);
int (*irq_get_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool *state);
int (*irq_set_irqchip_state)(struct irq_data *data, enum irqchip_irq_state which, bool state);
int (*irq_set_vcpu_affinity)(struct irq_data *data, void *vcpu_info);
void (*ipi_send_single)(struct irq_data *data, unsigned int cpu);
void (*ipi_send_mask)(struct irq_data *data, const struct cpumask *dest);
int (*irq_nmi_setup)(struct irq_data *data);
void (*irq_nmi_teardown)(struct irq_data *data);
void (*irq_force_complete_move)(struct irq_data *data);
unsigned long flags;
};
成员
name
用于 /proc/interrupts 的名称
irq_startup
启动中断(如果为 NULL,则默认为 ->enable)
irq_shutdown
关闭中断(如果为 NULL,则默认为 ->disable)
irq_enable
启用中断(如果为 NULL,则默认为 chip->unmask)
irq_disable
禁用中断
irq_ack
新中断的开始
irq_mask
屏蔽中断源
irq_mask_ack
确认并屏蔽中断源
irq_unmask
解除中断源的屏蔽
irq_eoi
中断结束
irq_set_affinity
在 SMP 机器上设置 CPU 亲和性。如果 force 参数为 true,则它告诉驱动程序无条件应用亲和性设置。不需要对提供的亲和性掩码进行健全性检查。这用于 CPU 热插拔,其中目标 CPU 尚未在 cpu_online_mask 中设置。
irq_retrigger
向 CPU 重新发送 IRQ
irq_set_type
设置 IRQ 的流类型(IRQ_TYPE_LEVEL/等)
irq_set_wake
启用/禁用 IRQ 的电源管理唤醒功能
irq_bus_lock
锁定对慢速总线(i2c)芯片访问的函数
irq_bus_sync_unlock
同步和解锁慢速总线(i2c)芯片的函数
irq_cpu_online
为辅助 CPU 配置中断源
irq_cpu_offline
取消配置辅助 CPU 的中断源
irq_suspend
当安装了一个或多个中断时,从核心代码在挂起时为每个芯片调用一次的函数
irq_resume
当安装了一个或多个中断时,从核心代码在恢复时为每个芯片调用一次的函数
irq_pm_shutdown
从核心代码在关闭时为每个芯片调用一次的函数
irq_calc_mask
可选函数,用于为特殊情况设置 irq_data.mask
irq_print_chip
可选,用于在 show_interrupts 中打印特殊的芯片信息
irq_request_resources
可选,用于在调用与此 irq 相关的任何其他回调之前请求资源
irq_release_resources
可选,用于释放通过 irq_request_resources 获取的资源
irq_compose_msi_msg
可选,用于为 MSI 组合消息内容
irq_write_msi_msg
可选,用于为 MSI 写入消息内容
irq_get_irqchip_state
返回中断的内部状态
irq_set_irqchip_state
设置中断的内部状态
irq_set_vcpu_affinity
可选,用于在虚拟机中定位 vCPU
ipi_send_single
向目标 CPU 发送单个 IPI
ipi_send_mask
向 cpumask 中的目标 CPU 发送 IPI
irq_nmi_setup
在启用 NMI 之前从核心代码调用的函数
irq_nmi_teardown
在禁用 NMI 之后从核心代码调用的函数
irq_force_complete_move
可选函数,用于强制完成挂起的中断移动
flags
芯片特定标志
-
struct irq_chip_regs¶
结构体 irq_gci 的寄存器偏移
定义:
struct irq_chip_regs {
unsigned long enable;
unsigned long disable;
unsigned long mask;
unsigned long ack;
unsigned long eoi;
unsigned long type;
};
成员
enable
相对于 reg_base 的启用寄存器偏移
disable
相对于 reg_base 的禁用寄存器偏移
mask
相对于 reg_base 的屏蔽寄存器偏移
ack
相对于 reg_base 的确认寄存器偏移
eoi
相对于 reg_base 的 Eoi 寄存器偏移
type
相对于 reg_base 的类型配置寄存器偏移
-
struct irq_chip_type¶
流类型的通用中断芯片实例
定义:
struct irq_chip_type {
struct irq_chip chip;
struct irq_chip_regs regs;
irq_flow_handler_t handler;
u32 type;
u32 mask_cache_priv;
u32 *mask_cache;
};
成员
chip
提供回调的实际中断芯片
regs
此芯片的寄存器偏移
handler
与此芯片关联的流处理程序
type
芯片可以处理这些流类型
mask_cache_priv
芯片类型私有的缓存屏蔽寄存器
mask_cache
指向缓存屏蔽寄存器的指针
描述
当需要为不同的流类型实现不同的功能和寄存器偏移时,一个 irq_generic_chip
可以有多个 irq_chip_type
实例。
-
struct irq_chip_generic¶
通用 irq 芯片数据结构
定义:
struct irq_chip_generic {
raw_spinlock_t lock;
void __iomem *reg_base;
u32 (*reg_readl)(void __iomem *addr);
void (*reg_writel)(u32 val, void __iomem *addr);
void (*suspend)(struct irq_chip_generic *gc);
void (*resume)(struct irq_chip_generic *gc);
unsigned int irq_base;
unsigned int irq_cnt;
u32 mask_cache;
u32 wake_enabled;
u32 wake_active;
unsigned int num_ct;
void *private;
unsigned long installed;
unsigned long unused;
struct irq_domain *domain;
struct list_head list;
struct irq_chip_type chip_types[];
};
成员
lock
保护寄存器和缓存数据访问的锁
reg_base
寄存器基地址(虚拟)
reg_readl
备用 I/O 访问器(如果为 NULL,则默认为 readl)
reg_writel
备用 I/O 访问器(如果为 NULL,则默认为 writel)
suspend
当芯片未被使用时,从核心代码在挂起时为每个芯片调用一次的函数;可用于处理芯片细节,而无需 irq_chip::suspend
resume
当芯片未被使用时,从核心代码在恢复时为每个芯片调用一次的函数;可用于处理芯片细节,而无需 irq_chip::suspend
irq_base
此芯片的中断基数
irq_cnt
此芯片处理的中断数量
mask_cache
所有芯片类型之间共享的缓存屏蔽寄存器
wake_enabled
中断可以从挂起状态唤醒
wake_active
中断被标记为从挂起状态唤醒的源
num_ct
可用 irq_chip_type 实例的数量(通常为 1)
private
用于非通用芯片回调的私有数据
installed
表示已安装中断的位域
unused
表示未使用中断的位域
domain
irq 域指针
list
实例跟踪的列表头
chip_types
中断 irq_chip_types 数组
描述
请注意,irq_chip_generic
可以有多个 irq_chip_type
实现,这些实现可以关联到 irq_chip_generic
实例的特定 irq 线。这允许在我们需要为 irq_chip_generic
实例实现不同的流机制(电平/边沿)时,共享和保护状态。
-
enum irq_gc_flags¶
通用 irq 芯片的初始化标志
常量
IRQ_GC_INIT_MASK_CACHE
通过读取掩码寄存器初始化 mask_cache
IRQ_GC_INIT_NESTED_LOCK
为需要调用父 irq 上的 irq_set_wake() 的 irq 芯片设置锁类别为嵌套。通常是 GPIO 实现
IRQ_GC_MASK_CACHE_PER_TYPE
掩码缓存是芯片类型私有的
IRQ_GC_NO_MASK
不计算 irq_data->mask
IRQ_GC_BE_IO
使用大端寄存器访问(默认:小端)
-
struct irq_domain_chip_generic_info¶
通用芯片信息结构
定义:
struct irq_domain_chip_generic_info {
const char *name;
irq_flow_handler_t handler;
unsigned int irqs_per_chip;
unsigned int num_ct;
unsigned int irq_flags_to_clear;
unsigned int irq_flags_to_set;
enum irq_gc_flags gc_flags;
int (*init)(struct irq_chip_generic *gc);
void (*exit)(struct irq_chip_generic *gc);
};
成员
name
通用中断芯片的名称
handler
通用中断芯片使用的中断处理程序
irqs_per_chip
每个芯片处理的中断数量(最大 32)
num_ct
与每个芯片关联的 irq_chip_type 实例数量
irq_flags_to_clear
在映射函数中要清除的 IRQ_* 位
irq_flags_to_set
在映射函数中要设置的 IRQ_* 位
gc_flags
通用芯片特定设置标志
init
在每个芯片创建时调用的函数。允许进行一些额外的芯片初始化。
exit
在每个芯片销毁时调用的函数。允许进行一些芯片清理操作。
-
struct irqaction¶
每个中断动作描述符
定义:
struct irqaction {
irq_handler_t handler;
void *dev_id;
void __percpu *percpu_dev_id;
struct irqaction *next;
irq_handler_t thread_fn;
struct task_struct *thread;
struct irqaction *secondary;
unsigned int irq;
unsigned int flags;
unsigned long thread_flags;
unsigned long thread_mask;
const char *name;
struct proc_dir_entry *dir;
};
成员
handler
中断处理函数
dev_id
用于识别设备的 cookie
percpu_dev_id
用于识别设备的 cookie
next
指向共享中断的下一个 irqaction 的指针
thread_fn
线程化中断的中断处理函数
thread
线程化中断的线程指针
secondary
指向辅助 irqaction 的指针(强制线程化)
irq
中断号
flags
flags(参见上面的 IRQF_*)
thread_flags
与 thread 相关的标志
thread_mask
用于跟踪 thread 活动的位掩码
name
设备名称
dir
指向 proc/irq/NN/name 条目的指针
-
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)¶
为中断线添加处理程序
参数
unsigned int irq
要分配的中断线
irq_handler_t handler
中断发生时要调用的函数。线程化中断的主处理程序。如果为 NULL,则安装默认的主处理程序。
unsigned long flags
处理标志
const char *name
生成此中断的设备名称
void *dev
传递给处理函数的 cookie
描述
此调用分配中断并建立处理程序;有关详细信息,请参阅 request_threaded_irq()
的文档。
-
struct irq_affinity_notify¶
IRQ 亲和性更改通知的上下文
定义:
struct irq_affinity_notify {
unsigned int irq;
struct kref kref;
struct work_struct work;
void (*notify)(struct irq_affinity_notify *, const cpumask_t *mask);
void (*release)(struct kref *ref);
};
成员
irq
通知适用的中断
kref
引用计数,供内部使用
work
工作项,供内部使用
notify
更改时要调用的函数。这将在进程上下文中调用。
release
释放时要调用的函数。这将在进程上下文中调用。一旦注册,结构只能在此函数被调用或之后才能释放。
-
struct irq_affinity¶
自动 irq 亲和性分配的描述
定义:
struct irq_affinity {
unsigned int pre_vectors;
unsigned int post_vectors;
unsigned int nr_sets;
unsigned int set_size[IRQ_AFFINITY_MAX_SETS];
void (*calc_sets)(struct irq_affinity *, unsigned int nvecs);
void *priv;
};
成员
pre_vectors
不要将亲和性应用于 MSI(-X) 向量空间开头的 pre_vectors
post_vectors
不要将亲和性应用于 MSI(-X) 向量空间末尾的 post_vectors
nr_sets
需要亲和性扩散的中断集数量
set_size
保存每个中断集大小的数组
calc_sets
计算中断集数量和大小的回调函数
priv
供 calc_sets 使用的私有数据,通常是指向驱动程序/设备特定数据的指针。
-
struct irq_affinity_desc¶
中断亲和性描述符
定义:
struct irq_affinity_desc {
struct cpumask mask;
unsigned int is_managed : 1;
};
成员
mask
用于保存亲和性分配的 cpumask
is_managed
如果中断由内部管理,则为 1
-
int irq_update_affinity_hint(unsigned int irq, const struct cpumask *m)¶
更新亲和性提示
参数
unsigned int irq
要更新的中断
const struct cpumask *m
cpumask 指针(NULL 表示清除提示)
描述
更新亲和性提示,但不更改中断的亲和性。
-
int irq_set_affinity_and_hint(unsigned int irq, const struct cpumask *m)¶
更新亲和性提示并将提供的 cpumask 应用于中断
参数
unsigned int irq
要更新的中断
const struct cpumask *m
cpumask 指针(NULL 表示清除提示)
描述
更新亲和性提示,如果 m 不为 NULL,则将其应用于该中断的亲和性。
提供的公共函数¶
本章包含已导出内核 API 函数的自动生成文档。
-
bool synchronize_hardirq(unsigned int irq)¶
等待挂起的硬 IRQ 处理程序(在其他 CPU 上)
参数
unsigned int irq
要等待的中断号
描述
此函数在返回之前等待此中断的任何挂起硬 IRQ 处理程序完成。如果您在持有 IRQ 处理程序可能需要的资源时使用此函数,则会发生死锁。它不考虑相关的线程化处理程序。
请勿在关闭场景中使用此功能,在这些场景中您必须确保所有部分(硬中断和线程化处理程序)都已完成。
此函数可以——小心地——从 IRQ 上下文调用。
它不检查中断是否在硬件级别正在进行中但尚未服务,因为这可能会在禁用中断且中断的目标 CPU 是当前 CPU 时导致死锁。
返回
如果线程化处理程序处于活动状态,则为 false。
-
void synchronize_irq(unsigned int irq)¶
等待挂起的 IRQ 处理程序(在其他 CPU 上)
参数
unsigned int irq
要等待的中断号
描述
此函数在返回之前等待此中断的任何挂起 IRQ 处理程序完成。如果您在持有 IRQ 处理程序可能需要的资源时使用此函数,则会发生死锁。
只能从可抢占代码中调用,因为当中断线程与 irq 关联时,它可能会休眠。
它(当 irq 芯片支持该方法时)可选地确保中断在任何 CPU 上都没有挂起并等待服务。
-
int irq_can_set_affinity(unsigned int irq)¶
检查给定 irq 的亲和性是否可以设置
参数
unsigned int irq
要检查的中断
-
bool irq_can_set_affinity_usr(unsigned int irq)¶
检查是否可以从用户空间设置 irq 的亲和性
-
void irq_set_thread_affinity(struct irq_desc *desc)¶
通知 irq 线程调整亲和性
参数
struct irq_desc *desc
亲和性已更改的 irq 描述符
描述
只需设置 IRQTF_AFFINITY 并将亲和性设置委托给中断线程本身。我们不能在此处调用 set_cpus_allowed_ptr()
,因为我们持有 desc->lock,并且此代码可以从硬中断上下文调用。
-
int irq_update_affinity_desc(unsigned int irq, struct irq_affinity_desc *affinity)¶
更新中断的亲和性管理
参数
unsigned int irq
要更新的中断号
struct irq_affinity_desc *affinity
指向亲和性描述符的指针
描述
此接口可用于配置已分配中断的亲和性管理。
在何时使用它存在某些限制——尝试在内核配置为通用 IRQ 保留模式(在 config GENERIC_IRQ_RESERVATION_MODE 中)时使用它将失败,因为它可能与托管/非托管中断计数冲突。此外,尝试在已启动或已配置为托管的中断上使用它也将失败,因为这些意味着无效的初始状态或重复初始化。
参数
unsigned int irq
要设置亲和性的中断
const struct cpumask *cpumask
cpumask
描述
如果 cpumask 不包含在线 CPU,则失败
参数
unsigned int irq
要设置亲和性的中断
const struct cpumask *cpumask
cpumask
描述
与 irq_set_affinity 相同,但不检查掩码与在线 CPU 的匹配。
仅用于低级 CPU 热插拔代码,我们需要在 CPU 上线之前使每个 CPU 中断具有亲和性。
-
int irq_set_affinity_notifier(unsigned int irq, struct irq_affinity_notify *notify)¶
控制 IRQ 亲和性更改通知
参数
unsigned int irq
要启用/禁用通知的中断
struct irq_affinity_notify *notify
通知上下文,或
NULL
以禁用通知。函数指针必须已初始化;其他字段将由此函数初始化。
描述
必须在进程上下文中调用。通知只能在 IRQ 分配后启用,并且必须在使用 free_irq()
释放 IRQ 之前禁用。
-
int irq_set_vcpu_affinity(unsigned int irq, void *vcpu_info)¶
设置中断的 vcpu 亲和性
参数
unsigned int irq
要设置亲和性的中断号
void *vcpu_info
vCPU 特定数据或指向 percpu_devid 中断的 vCPU 特定数据每CPU 数组的指针
描述
此函数使用 vCPU 特定数据来设置 irq 的 vCPU 亲和性。vCPU 特定数据从外部传递,例如 KVM。一个示例代码路径如下:KVM -> IOMMU -> irq_set_vcpu_affinity()
。
-
void disable_irq_nosync(unsigned int irq)¶
禁用 irq 而不等待
参数
unsigned int irq
要禁用的中断
描述
禁用选定的中断线。禁用和启用是嵌套的。与 disable_irq()
不同,此函数在返回之前不确保 IRQ 处理程序的现有实例已完成。
此函数可以在 IRQ 上下文调用。
-
void disable_irq(unsigned int irq)¶
禁用 irq 并等待完成
参数
unsigned int irq
要禁用的中断
描述
禁用选定的中断线。启用和禁用是嵌套的。
此函数在返回之前等待此中断的任何挂起 IRQ 处理程序完成。如果您在持有 IRQ 处理程序可能需要的资源时使用此函数,则会发生死锁。
只能从可抢占代码中调用,因为当中断线程与 irq 关联时,它可能会休眠。
-
bool disable_hardirq(unsigned int irq)¶
禁用 irq 并等待硬中断完成
参数
unsigned int irq
要禁用的中断
描述
禁用选定的中断线。启用和禁用是嵌套的。
此函数在返回之前等待此中断的任何挂起硬 IRQ 处理程序完成。如果您在持有硬 IRQ 处理程序可能需要的资源时使用此函数,则会发生死锁。
当用于从原子上下文乐观地禁用中断时,必须检查返回值。
此函数可以——小心地——从 IRQ 上下文调用。
返回
如果线程化处理程序处于活动状态,则为 false。
-
void disable_nmi_nosync(unsigned int irq)¶
禁用 nmi 而不等待
参数
unsigned int irq
要禁用的中断
描述
禁用选定的中断线。禁用和启用是嵌套的。
要禁用的中断必须通过 request_nmi
请求。与 disable_nmi()
不同,此函数在返回之前不确保 IRQ 处理程序的现有实例已完成。
-
void enable_irq(unsigned int irq)¶
启用 irq 处理
参数
unsigned int irq
要启用的中断
描述
撤销一次 disable_irq()
调用的效果。如果这与最后一次禁用匹配,则重新启用此 IRQ 线上中断的处理。
此函数仅当 desc->irq_data.chip->bus_lock
和 desc->chip->bus_sync_unlock
为 NULL 时才能从 IRQ 上下文调用!
-
void enable_nmi(unsigned int irq)¶
启用 nmi 处理
参数
unsigned int irq
要启用的中断
描述
要启用的中断必须通过 request_nmi
请求。撤销一次 disable_nmi()
调用的效果。如果这与最后一次禁用匹配,则重新启用此 IRQ 线上中断的处理。
-
int irq_set_irq_wake(unsigned int irq, unsigned int on)¶
控制 irq 电源管理唤醒
参数
unsigned int irq
要控制的中断
unsigned int on
启用/禁用电源管理唤醒
描述
启用/禁用电源管理唤醒模式,该模式默认禁用。启用和禁用必须匹配,就像它们与非唤醒模式支持匹配一样。
唤醒模式允许此 IRQ 将系统从“挂起到 RAM”等睡眠状态唤醒。
注意
irq 启用/禁用状态与 irq 唤醒的启用/禁用状态完全正交。一个 irq 可以通过 disable_irq()
禁用,但只要 irq 启用了唤醒功能,它仍然可以唤醒系统。如果这不成立,则需要调查底层 irq 芯片和相关驱动程序。
-
void irq_wake_thread(unsigned int irq, void *dev_id)¶
唤醒由 dev_id 标识的动作的 irq 线程
参数
unsigned int irq
中断线
void *dev_id
应唤醒其线程的设备标识
-
const void *free_irq(unsigned int irq, void *dev_id)¶
释放用 request_irq 分配的中断
参数
unsigned int irq
要释放的中断线
void *dev_id
要释放的设备标识
描述
移除中断处理程序。处理程序被移除,如果中断线不再被任何驱动程序使用,则将其禁用。在共享 IRQ 上,调用者必须确保在调用此函数之前,它所驱动的卡上的中断已禁用。函数在针对此 IRQ 的任何正在执行的中断完成之前不会返回。
此函数不得从中断上下文调用。
返回传递给 request_irq
的 devname
参数。
-
int request_threaded_irq(unsigned int irq, irq_handler_t handler, irq_handler_t thread_fn, unsigned long irqflags, const char *devname, void *dev_id)¶
分配中断线
参数
unsigned int irq
要分配的中断线
irq_handler_t handler
中断发生时要调用的函数。线程化中断的主处理程序。如果
handler
为 NULL 且thread_fn
不为 NULL,则安装默认的主处理程序。irq_handler_t thread_fn
从 irq 处理程序线程调用的函数。如果为 NULL,则不创建 irq 线程。
unsigned long irqflags
中断类型标志
const char *devname
声明此设备的 ASCII 名称
void *dev_id
传递回处理函数的一个 cookie
描述
此调用分配中断资源并启用中断线和 IRQ 处理。从调用此函数的那一刻起,您的处理函数可能会被调用。由于您的处理函数必须清除板卡引发的任何中断,因此您必须注意以正确的顺序初始化硬件和设置中断处理程序。
如果您想为您的设备设置线程化 irq 处理程序,则需要提供 handler 和 thread_fn。handler 仍然在硬中断上下文中调用,并且必须检查中断是否源自设备。如果是,它需要禁用设备上的中断并返回 IRQ_WAKE_THREAD,这将唤醒处理程序线程并运行 thread_fn。这种分离的处理程序设计对于支持共享中断是必要的。
dev_id 必须全局唯一。通常,设备数据结构的地址用作 cookie。由于处理程序会收到此值,因此使用它是有意义的。
如果您的中断是共享的,则必须传递一个非 NULL 的 dev_id,因为在释放中断时需要它。
标志
IRQF_SHARED 中断是共享的 IRQF_TRIGGER_* 指定活动边沿或电平 IRQF_ONESHOT 在中断线被屏蔽的情况下运行 thread_fn
-
int request_any_context_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev_id)¶
分配中断线
参数
unsigned int irq
要分配的中断线
irq_handler_t handler
当 IRQ 发生时调用的函数。用于线程化中断的线程化处理程序。
unsigned long flags
中断类型标志
const char *name
声明此设备的 ASCII 名称
void *dev_id
传递回处理函数的一个 cookie
描述
此调用分配中断资源,并启用中断线和 IRQ 处理。它根据上下文选择硬中断(hardirq)或线程化处理方法。
返回
失败时,返回负值。成功时,返回 IRQC_IS_HARDIRQ 或 IRQC_IS_NESTED。
-
int request_nmi(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *name, void *dev_id)¶
分配一条用于 NMI 递送的中断线
参数
unsigned int irq
要分配的中断线
irq_handler_t handler
当 IRQ 发生时调用的函数。用于线程化中断的线程化处理程序。
unsigned long irqflags
中断类型标志
const char *name
声明此设备的 ASCII 名称
void *dev_id
传递回处理函数的一个 cookie
描述
此调用分配中断资源,并启用中断线和 IRQ 处理。它将 IRQ 线设置为作为 NMI 处理。
递送 NMI 的中断线不能共享,且 IRQ 处理不能线程化。
请求用于 NMI 递送的中断线必须生成每个 CPU 的中断,并且自动启用设置必须被禁用。
dev_id 必须全局唯一。通常,设备数据结构的地址用作 cookie。由于处理程序会收到此值,因此使用它是有意义的。
如果中断线不能用于递送 NMI,函数将失败并返回负值。
-
bool irq_percpu_is_enabled(unsigned int irq)¶
检查每个 CPU 中断是否已启用
参数
unsigned int irq
要检查的 Linux irq 号
描述
必须从不可迁移的上下文调用。返回当前 CPU 上每个 CPU 中断的启用状态。
-
void free_percpu_irq(unsigned int irq, void __percpu *dev_id)¶
释放用 request_percpu_irq 分配的中断
参数
unsigned int irq
要释放的中断线
void __percpu *dev_id
要释放的设备标识
描述
移除一个每个 CPU 中断处理程序。处理程序被移除,但中断线并未禁用。在调用此函数之前,必须在每个 CPU 上完成此操作。该函数只有在所有为此 IRQ 正在执行的中断完成后才会返回。
此函数不得从中断上下文调用。
参数
unsigned int irq
要设置的中断线
struct irqaction *act
中断的 irqaction
描述
用于在早期启动过程中静态设置每个 CPU 中断。
-
int __request_percpu_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *devname, void __percpu *dev_id)¶
分配一个每个 CPU 中断线
参数
unsigned int irq
要分配的中断线
irq_handler_t handler
当 IRQ 发生时调用的函数。
unsigned long flags
中断类型标志(仅 IRQF_TIMER)
const char *devname
声明此设备的 ASCII 名称
void __percpu *dev_id
传递回处理函数的每个 CPU cookie
描述
此调用分配中断资源并在本地 CPU 上启用中断。如果中断需要在其他 CPU 上启用,则必须在每个 CPU 上使用 enable_percpu_irq() 完成此操作。
dev_id 必须全局唯一。它是一个每个 CPU 变量,并且处理程序会使用被中断 CPU 的该变量实例来调用。
-
int request_percpu_nmi(unsigned int irq, irq_handler_t handler, const char *name, void __percpu *dev_id)¶
分配一个用于 NMI 递送的每个 CPU 中断线
参数
unsigned int irq
要分配的中断线
irq_handler_t handler
当 IRQ 发生时调用的函数。
const char *name
声明此设备的 ASCII 名称
void __percpu *dev_id
传递回处理函数的每个 CPU cookie
描述
此调用为每个 CPU NMI 分配中断资源。每个 CPU NMI 必须在通过 enable_percpu_nmi() 在同一 CPU 上启用之前,通过调用 prepare_percpu_nmi()
在每个 CPU 上进行设置。
dev_id 必须全局唯一。它是一个每个 CPU 变量,并且处理程序会使用被中断 CPU 的该变量实例来调用。
请求用于 NMI 递送的中断线应该禁用自动启用设置。
如果中断线不能用于递送 NMI,函数将失败并返回负值。
-
int prepare_percpu_nmi(unsigned int irq)¶
执行 NMI 递送的 CPU 本地设置
参数
unsigned int irq
要准备用于 NMI 递送的中断线
描述
此调用准备一条中断线,以便在当前 CPU 上递送 NMI,在此中断线通过 enable_percpu_nmi() 启用之前。
作为 CPU 本地操作,应从不可抢占的上下文调用此函数。
如果中断线不能用于递送 NMI,函数将失败并返回负值。
-
void teardown_percpu_nmi(unsigned int irq)¶
撤销 IRQ 线的 NMI 设置
参数
unsigned int irq
应移除 CPU 本地 NMI 配置的中断线
描述
此调用撤销了由 prepare_percpu_nmi()
完成的设置。
IRQ 线不应为当前 CPU 启用。作为 CPU 本地操作,应从不可抢占的上下文调用此函数。
-
int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, bool *state)¶
返回中断的 irqchip 状态。
参数
unsigned int irq
转发到虚拟机的中断线
enum irqchip_irq_state which
调用者想要了解的 IRQCHIP_STATE_* 之一
bool *state
一个布尔指针,用于存储状态
描述
此调用拍摄中断的内部 irqchip 状态快照,将与阶段 which 对应的位返回到 state 中。
如果中断控制器具有每个 CPU 寄存器,则应禁用抢占来调用此函数。
-
int irq_set_irqchip_state(unsigned int irq, enum irqchip_irq_state which, bool val)¶
设置转发中断的状态。
参数
unsigned int irq
转发到虚拟机的中断线
enum irqchip_irq_state which
要恢复的状态(IRQCHIP_STATE_* 之一)
bool val
对应于 which 的值
描述
此调用根据 which 的值,设置中断的内部 irqchip 状态。
如果中断控制器具有每个 CPU 寄存器,则应禁用迁移来调用此函数。
-
bool irq_has_action(unsigned int irq)¶
检查中断是否已请求
参数
unsigned int irq
Linux irq 号
返回
当前状态的快照
-
bool irq_check_status_bit(unsigned int irq, unsigned int bitmask)¶
检查 irq 描述符状态中的位是否已设置
参数
unsigned int irq
Linux irq 号
unsigned int bitmask
要评估的位掩码
返回
如果 bitmask 中的任一位被设置,则为 True
参数
unsigned int irq
irq 号
const struct irq_chip *chip
指向 irq 芯片描述结构的指针
-
int irq_set_irq_type(unsigned int irq, unsigned int type)¶
设置 irq 的 irq 触发类型
参数
unsigned int irq
irq 号
unsigned int type
IRQ_TYPE_{LEVEL,EDGE}_* 值 - 参见 include/linux/irq.h
-
int irq_set_handler_data(unsigned int irq, void *data)¶
设置 irq 的 irq 处理程序数据
参数
unsigned int irq
中断号
void *data
指向中断特定数据的指针
描述
设置 irq 的硬件 irq 控制器数据
-
int irq_set_chip_data(unsigned int irq, void *data)¶
设置 irq 的 irq 芯片数据
参数
unsigned int irq
中断号
void *data
指向芯片特定数据的指针
描述
设置 irq 的硬件 irq 芯片数据
-
void handle_nested_irq(unsigned int irq)¶
从 irq 线程处理嵌套 irq
参数
unsigned int irq
中断号
描述
处理嵌套到线程化中断处理程序中的中断。处理函数在调用线程的上下文中被调用。
-
void handle_simple_irq(struct irq_desc *desc)¶
简单和软件解码的 IRQ。
参数
struct irq_desc *desc
此 irq 的中断描述结构
描述
简单中断要么从解复用中断处理程序发送,要么来自硬件,其中不需要中断硬件控制。
注意
如果需要,调用者应处理确认、清除、屏蔽和解除屏蔽问题。
-
void handle_untracked_irq(struct irq_desc *desc)¶
简单和软件解码的 IRQ。
参数
struct irq_desc *desc
此 irq 的中断描述结构
描述
未跟踪中断从解复用中断处理程序发送,当解复用器不知道是其多路复用 irq 域中的哪个设备生成了中断时。通过此处处理的 IRQ 不受统计跟踪、随机性或虚假中断检测的影响。
注意
与 handle_simple_irq 类似,如果需要,调用者应处理确认、清除、屏蔽和解除屏蔽问题。
-
void handle_level_irq(struct irq_desc *desc)¶
电平触发 irq 处理程序
参数
struct irq_desc *desc
此 irq 的中断描述结构
描述
电平触发中断在硬件线保持活动电平期间一直处于活动状态。这可能需要屏蔽中断,并在相关处理程序确认设备后解除屏蔽,以便中断线返回非活动状态。
-
void handle_fasteoi_irq(struct irq_desc *desc)¶
透明控制器的 irq 处理程序
参数
struct irq_desc *desc
此 irq 的中断描述结构
描述
只会向芯片发出一个回调:当中断被服务后调用 ->eoi()。这支持现代形式的中断处理程序,这些处理程序以透明方式在硬件中处理流详细信息。
-
void handle_fasteoi_nmi(struct irq_desc *desc)¶
NMI 中断线的 irq 处理程序
参数
struct irq_desc *desc
此 irq 的中断描述结构
一个简单的 NMI 安全处理程序,考虑了 request_nmi 的限制。
只会向芯片发出一个回调:当中断被服务后调用 ->eoi()。这支持现代形式的中断处理程序,这些处理程序以透明方式在硬件中处理流详细信息。
-
void handle_edge_irq(struct irq_desc *desc)¶
边沿触发 IRQ 处理程序
参数
struct irq_desc *desc
此 irq 的中断描述结构
描述
中断发生在硬件信号的下降沿和/或上升沿。发生的中断被锁存到 irq 控制器硬件中,并且必须通过确认才能重新启用。确认后,即使在第一个中断被相关事件处理程序处理之前,同一源上也可能发生另一个中断。如果发生这种情况,可能需要根据控制器硬件禁用(屏蔽)中断。这需要在一个循环中重新启用中断,该循环处理在处理程序运行时到达的中断。如果所有待处理中断都已处理,则退出循环。
-
void handle_fasteoi_ack_irq(struct irq_desc *desc)¶
堆叠在透明控制器上的边沿层级 irq 处理程序
参数
struct irq_desc *desc
此 irq 的中断描述结构
描述
类似于 handle_fasteoi_irq()
,但用于需要调用其 ->irq_ack() 函数的 irq_chip 的层级。
-
void handle_fasteoi_mask_irq(struct irq_desc *desc)¶
堆叠在透明控制器上的电平层级 irq 处理程序
参数
struct irq_desc *desc
此 irq 的中断描述结构
描述
类似于 handle_fasteoi_irq()
,但用于需要调用其 ->irq_mask_ack() 函数的 irq_chip 的层级。
-
int irq_chip_set_parent_state(struct irq_data *data, enum irqchip_irq_state which, bool val)¶
设置父中断的状态。
参数
struct irq_data *data
指向中断特定数据的指针
enum irqchip_irq_state which
要恢复的状态(IRQCHIP_STATE_* 之一)
bool val
对应于 which 的值
描述
如果底层 irqchip 未实现,则有条件成功。
-
int irq_chip_get_parent_state(struct irq_data *data, enum irqchip_irq_state which, bool *state)¶
获取父中断的状态。
参数
struct irq_data *data
指向中断特定数据的指针
enum irqchip_irq_state which
调用者想要了解的 IRQCHIP_STATE_* 之一
bool *state
一个布尔指针,用于存储状态
描述
如果底层 irqchip 未实现,则有条件成功。
参数
struct irq_data *data
指向中断特定数据的指针
参数
struct irq_data *data
指向中断特定数据的指针
参数
struct irq_data *data
指向中断特定数据的指针
参数
struct irq_data *data
指向中断特定数据的指针
参数
struct irq_data *data
指向中断特定数据的指针
参数
struct irq_data *data
指向中断特定数据的指针
参数
struct irq_data *data
指向中断特定数据的指针
-
int irq_chip_set_affinity_parent(struct irq_data *data, const struct cpumask *dest, bool force)¶
设置父中断的亲和性
参数
struct irq_data *data
指向中断特定数据的指针
const struct cpumask *dest
要设置的亲和性掩码
bool force
强制设置的标志(禁用在线检查)
描述
有条件,因为底层父芯片可能未实现它。
参数
struct irq_data *data
指向中断特定数据的指针
unsigned int type
IRQ_TYPE_{LEVEL,EDGE}_* 值 - 参见 include/linux/irq.h
描述
有条件,因为底层父芯片可能未实现它。
参数
struct irq_data *data
指向中断特定数据的指针
描述
遍历中断的域层级,并检查是否存在硬件重新触发函数。如果存在,则调用它。
参数
struct irq_data *data
指向中断特定数据的指针
void *vcpu_info
vcpu 亲和性信息
参数
struct irq_data *data
指向中断特定数据的指针
unsigned int on
是否设置或重置此 irq 的唤醒功能
描述
有条件,因为底层父芯片可能未实现它。
参数
struct irq_data *data
指向中断特定数据的指针
参数
struct irq_data *data
指向中断特定数据的指针
提供的内部函数¶
本章包含内部函数的自动生成文档。
-
unsigned int irq_get_nr_irqs(void)¶
系统支持的中断数量。
参数
void
无参数
-
unsigned int irq_set_nr_irqs(unsigned int nr)¶
设置系统支持的中断数量。
参数
unsigned int nr
新的中断数量。
返回
nr.
-
int generic_handle_irq(unsigned int irq)¶
为特定 irq 调用处理程序
参数
unsigned int irq
要处理的 irq 号
返回
成功时为 0,如果转换失败则为 -EINVAL
此函数必须在 IRQ 上下文中调用,并初始化 irq 寄存器。
-
int generic_handle_irq_safe(unsigned int irq)¶
从任何上下文为特定 irq 调用处理程序。
参数
unsigned int irq
要处理的 irq 号
返回
成功时为 0,错误时为负值。
描述
此函数可以从任何上下文(IRQ 或进程上下文)调用。如果未从 IRQ 上下文调用,并且 irq 已被标记为仅强制 IRQ 上下文,它将报告错误。
-
int generic_handle_domain_irq(struct irq_domain *domain, unsigned int hwirq)¶
为属于某个域的硬件 irq 调用处理程序。
参数
struct irq_domain *domain
执行查找的域
unsigned int hwirq
要转换为逻辑值的硬件 irq 号
返回
成功时为 0,如果转换失败则为 -EINVAL
此函数必须在 IRQ 上下文中调用,并初始化 irq 寄存器。
-
int generic_handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq)¶
为属于某个域的硬件 NMI 调用处理程序。
参数
struct irq_domain *domain
执行查找的域
unsigned int hwirq
要转换为逻辑值的硬件 irq 号
返回
成功时为 0,如果转换失败则为 -EINVAL
此函数必须在 NMI 上下文中调用,并初始化 irq 寄存器。
-
void irq_free_descs(unsigned int from, unsigned int cnt)¶
释放 irq 描述符
参数
unsigned int from
描述符范围的起始
unsigned int cnt
要释放的连续 irq 数量
-
int __ref __irq_alloc_descs(int irq, unsigned int from, unsigned int cnt, int node, struct module *owner, const struct irq_affinity_desc *affinity)¶
分配并初始化一个 irq 描述符范围
参数
int irq
如果 irq >= 0,则为特定 irq 号分配
unsigned int from
从此 irq 号开始搜索
unsigned int cnt
要分配的连续 irq 数量。
int node
优先分配 irq 描述符的节点
struct module *owner
拥有模块(可为 NULL)
const struct irq_affinity_desc *affinity
可选的指向大小为 cnt 的亲和性掩码数组的指针,该数组提示 irq 描述符应分配到何处以及使用哪些默认亲和性
描述
返回第一个 irq 号或错误代码
-
unsigned int irq_get_next_irq(unsigned int offset)¶
获取下一个已分配的 irq 号
参数
unsigned int offset
从何处开始搜索
描述
返回偏移量后的下一个 irq 号,如果未找到则返回 nr_irqs。
-
unsigned int kstat_irqs_cpu(unsigned int irq, int cpu)¶
获取 CPU 上中断的统计信息
参数
unsigned int irq
中断号
int cpu
CPU 号
描述
返回自启动以来 cpu 上 irq 的中断计数总和。调用者必须确保中断不会并发移除。
-
unsigned int kstat_irqs_usr(unsigned int irq)¶
从线程上下文获取中断的统计信息
参数
unsigned int irq
中断号
描述
返回自启动以来所有 CPU 上 irq 的中断计数总和。
它使用 rcu 保护访问,因为中断描述符的并发移除在 delayed_free_desc()/irq_kobj_release() 之前会观察到一个 rcu 宽限期。
-
void handle_bad_irq(struct irq_desc *desc)¶
处理虚假和未处理的 irq
参数
struct irq_desc *desc
中断的描述
描述
处理虚假和未处理的 IRQ。它还会打印一条调试消息。
-
void noinstr generic_handle_arch_irq(struct pt_regs *regs)¶
针对不自行进行入口计数的架构的根 irq 处理程序
参数
struct pt_regs *regs
来自低级处理代码的寄存器文件
-
int irq_set_msi_desc_off(unsigned int irq_base, unsigned int irq_offset, struct msi_desc *entry)¶
在偏移量处为 irq 设置 MSI 描述符数据
参数
unsigned int irq_base
中断号基址
unsigned int irq_offset
中断号偏移量
struct msi_desc *entry
指向 MSI 描述符数据的指针
描述
在偏移量处为 irq 设置 MSI 描述符条目
-
int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry)¶
为 irq 设置 MSI 描述符数据
参数
unsigned int irq
中断号
struct msi_desc *entry
指向 MSI 描述符数据的指针
描述
为 irq 设置 MSI 描述符条目
-
void irq_disable(struct irq_desc *desc)¶
将中断标记为禁用
参数
struct irq_desc *desc
应该被禁用的 irq 描述符
描述
如果芯片未实现 irq_disable 回调,我们采用延迟禁用方法。这意味着我们标记中断为禁用,但让硬件保持未屏蔽状态。这是一个优化,因为我们避免了在标记为禁用后没有中断发生的常见情况下的硬件访问。如果发生中断,则中断流处理程序会在硬件级别屏蔽该线路并将其标记为待处理。
如果中断芯片未实现 irq_disable 回调,驱动程序可以通过调用“irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY)”来禁用特定 irq 线的延迟方法。这可用于在某些情况下无法在设备级别禁用中断,而必须使用 disable_irq[_nosync] 的设备。
-
void handle_percpu_irq(struct irq_desc *desc)¶
每个 CPU 本地 irq 处理程序
参数
struct irq_desc *desc
此 irq 的中断描述结构
SMP 机器上不需要锁定要求的每个 CPU 中断
-
void handle_percpu_devid_irq(struct irq_desc *desc)¶
带有每个 CPU dev_id 的每个 CPU 本地 irq 处理程序
参数
struct irq_desc *desc
此 irq 的中断描述结构
描述
SMP 机器上不需要锁定要求的每个 CPU 中断。与上面 handle_percpu_irq()
相同,但有以下额外功能
action->percpu_dev_id 是指向每个 CPU 变量的指针,这些变量包含调用此处理程序的 CPU 的实际设备 ID
-
void handle_percpu_devid_fasteoi_nmi(struct irq_desc *desc)¶
带有每个 CPU dev_id 的每个 CPU 本地 NMI 处理程序
参数
struct irq_desc *desc
此 irq 的中断描述结构
描述
类似于 handle_fasteoi_nmi,但将 dev_id cookie 作为每个 CPU 指针处理。
-
void irq_cpu_online(void)¶
调用所有 irq_cpu_online 函数。
-
void irq_cpu_offline(void)¶
调用所有 irq_cpu_offline 函数。
参数
struct irq_data *data
指向中断特定数据的指针
struct msi_msg *msg
指向 MSI 消息的指针
描述
对于分层域,我们找到层级中第一个实现 irq_compose_msi_msg 回调的芯片。对于非分层域,我们使用顶层芯片。
参数
struct irq_data *data
指向中断特定数据的指针
描述
启用中断数据结构引用的 IRQ 芯片的电源。
参数
struct irq_data *data
指向中断特定数据的指针
描述
禁用中断数据结构引用的 IRQ 芯片的电源。请注意,只有在所有已调用 irq_chip_pm_get()
的 IRQ 都调用此函数后,电源才会被禁用。
鸣谢¶
以下人员对本文档做出了贡献
Thomas Gleixner tglx@linutronix.de
Ingo Molnar mingo@elte.hu