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 流程处理程序¶
通用层提供一组预定义的 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 表示确认,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
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)¶
从中断域中移除通用芯片
参数
struct irq_domain *d
要从中移除通用芯片的中断域
-
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
中断域指针
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
保存所有数据的通用中断芯片
u32 msk
相对于 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
保存所有数据的通用中断芯片
u32 msk
相对于 gc->irq_base 要初始化的中断的位掩码
unsigned int clr
要清除的 IRQ_* 位
unsigned int set
要设置的 IRQ_* 位
描述
移除从 gc->irq_base 开始的最大 32 个中断。
结构体¶
本章包含通用 IRQ 层中使用的结构的自动生成文档。
-
struct irq_common_data¶
所有中断芯片共享的每个中断数据
定义:
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
中断芯片函数的状态信息。 使用访问器函数来处理它
node
对平衡有用的节点索引
handler_data
用于 irq_chip 方法的每个中断数据
msi_desc
MSI 描述符
affinity
SMP 上的 IRQ 亲和性。如果这是与 IPI 相关的中断,则这是可以发送 IPI 的 CPU 的掩码。
effective_affinity
SMP 上有效的 IRQ 亲和性,因为某些中断芯片不允许多个 CPU 目标。**affinity** 的子集。
ipi_offset
**affinity** 中第一个 IPI 目标 CPU 的偏移量。可选。
-
struct irq_data¶
传递给芯片函数的每个中断芯片数据
定义:
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
指向所有中断芯片共享的数据
chip
底层中断硬件访问
domain
中断转换域;负责在 hwirq 号和 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);
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
将 IRQ 重新发送到 CPU
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 之后从核心代码调用的函数
flags
芯片特定的标志
-
struct irq_chip_regs¶
struct 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
Mask
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 访问器(默认为 readl,如果为 NULL)
reg_writel
备用 I/O 访问器(默认为 writel,如果为 NULL)
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
中断域指针
list
用于跟踪实例的列表头
chip_types
中断 irq_chip_type 的数组
描述
请注意,当我们需要为 irq_chip_generic 实例的不同 irq 线实现不同的流机制(电平/边沿)时,irq_chip_generic 可以有多个 irq_chip_type 实现,这允许在 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 芯片,将 irq 的锁类设置为嵌套。通常是 GPIO 实现
IRQ_GC_MASK_CACHE_PER_TYPE
掩码缓存是芯片类型私有的
IRQ_GC_NO_MASK
不计算 irq_data->mask
IRQ_GC_BE_IO
使用大端寄存器访问(默认值:LE)
-
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
发生 IRQ 时要调用的函数。线程化中断的主处理程序。如果为 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,则将其作为该中断的亲和性应用。
-
struct irq_fwspec¶
通用 IRQ 说明符结构
定义:
struct irq_fwspec {
struct fwnode_handle *fwnode;
int param_count;
u32 param[IRQ_DOMAIN_IRQ_SPEC_PARAMS];
};
成员
fwnode
指向固件特定描述符的指针
param_count
设备特定参数的数量
param
设备特定参数
描述
此结构直接模仿 of_phandle_args,用于传递中断的设备特定描述。
-
struct irq_domain_ops¶
用于 irq_domain 对象的方法
定义:
struct irq_domain_ops {
int (*match)(struct irq_domain *d, struct device_node *node, enum irq_domain_bus_token bus_token);
int (*select)(struct irq_domain *d, struct irq_fwspec *fwspec, enum irq_domain_bus_token bus_token);
int (*map)(struct irq_domain *d, unsigned int virq, irq_hw_number_t hw);
void (*unmap)(struct irq_domain *d, unsigned int virq);
int (*xlate)(struct irq_domain *d, struct device_node *node,const u32 *intspec, unsigned int intsize, unsigned long *out_hwirq, unsigned int *out_type);
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY;
int (*alloc)(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs, void *arg);
void (*free)(struct irq_domain *d, unsigned int virq, unsigned int nr_irqs);
int (*activate)(struct irq_domain *d, struct irq_data *irqd, bool reserve);
void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
int (*translate)(struct irq_domain *d, struct irq_fwspec *fwspec, unsigned long *out_hwirq, unsigned int *out_type);
#endif;
#ifdef CONFIG_GENERIC_IRQ_DEBUGFS;
void (*debug_show)(struct seq_file *m, struct irq_domain *d, struct irq_data *irqd, int ind);
#endif;
};
成员
match
将中断控制器设备节点与主机匹配,匹配时返回 1
select
匹配中断控制器固件规范。它比 match 更通用,因为它接收一个完整的
struct irq_fwspec
。因此,如果提供,则首选 select。匹配时返回 1。映射
创建或更新虚拟中断号和硬件中断号之间的映射。对于给定的映射,此函数仅调用一次。
取消映射
处置此类映射
转换
给定设备树节点和中断说明符,解码硬件中断号和 Linux 中断类型值。
分配
从 virq 开始分配 nr_irqs 个中断。
释放
从 virq 开始释放 nr_irqs 个中断。
激活
激活硬件中的一个中断(irqd)。如果设置了 reserve,则仅保留向量。如果未设置,则分配向量(从
request_irq()
调用)。停用
禁用一个中断 (irqd)。
翻译
给定 fwspec,解码硬件中断号 (out_hwirq) 和 Linux 中断类型值 (out_type)。这是 xlate 的通用版本(通过
struct irq_fwspec
),如果提供,则首选此方法。debug_show
用于域在 debugfs 中显示中断的特定数据。
描述
以下函数由驱动程序提供,并在创建新映射或处置旧映射时调用。然后,驱动程序可以继续执行所需的任何内部数据结构管理。从 map() 返回时,它还需要设置 irq_desc。
-
struct irq_domain¶
硬件中断号转换对象
定义:
struct irq_domain {
struct list_head link;
const char *name;
const struct irq_domain_ops *ops;
void *host_data;
unsigned int flags;
unsigned int mapcount;
struct mutex mutex;
struct irq_domain *root;
struct fwnode_handle *fwnode;
enum irq_domain_bus_token bus_token;
struct irq_domain_chip_generic *gc;
struct device *dev;
struct device *pm_dev;
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY;
struct irq_domain *parent;
#endif;
#ifdef CONFIG_GENERIC_MSI_IRQ;
const struct msi_parent_ops *msi_parent_ops;
#endif;
void (*exit)(struct irq_domain *d);
irq_hw_number_t hwirq_max;
unsigned int revmap_size;
struct radix_tree_root revmap_tree;
struct irq_data __rcu *revmap[] ;
};
成员
链接
全局 irq_domain 列表中的元素。
name
中断域的名称
ops
指向 irq_domain 方法的指针
host_data
所有者使用的私有数据指针。不会被 irq_domain 核心代码触及。
flags
每个 irq_domain 的标志
mapcount
已映射的中断数
mutex
域锁,分层域使用根域的锁
root
指向根域的指针,如果是非分层结构,则指向包含结构
fwnode
指向与 irq_domain 关联的固件节点的指针。可以通过 irq_domain_get_of_node 访问器轻松将其交换为 of_node
bus_token
fwnode 的 device_node 可能用于多个 irq 域。但是,结合 bus_token,该对在系统中应该是唯一的。
gc
指向通用芯片列表的指针。有一个辅助函数用于使用通用芯片库为中断控制器驱动程序设置一个或多个通用芯片,该库使用此指针。
dev
指向实例化 irqdomain 的设备的指针。对于每个设备的中断域,这不一定与 pm_dev 相同。
pm_dev
指向可用于与中断域相关的电源管理目的的设备的指针。
parent
指向父 irq_domain 的指针,以支持分层 irq_domain
msi_parent_ops
指向每个设备域初始化 MSI 父域方法的指针
exit
域被销毁时调用的函数
hwirq_max
硬件中断号的上限。特别是为了避免与保留的硬件中断冲突/失败。可以是 ~0。
revmap_size
线性映射表 revmap 的大小
revmap_tree
不适合线性映射的硬件中断的基数映射树
revmap
irq_data 指针的线性表
描述
可选元素:Revmap 数据,供 irq 域代码在内部使用
-
struct irq_domain_info¶
域信息结构
定义:
struct irq_domain_info {
struct fwnode_handle *fwnode;
unsigned int domain_flags;
unsigned int size;
irq_hw_number_t hwirq_max;
int direct_max;
unsigned int hwirq_base;
unsigned int virq_base;
enum irq_domain_bus_token bus_token;
const char *name_suffix;
const struct irq_domain_ops *ops;
void *host_data;
#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY;
struct irq_domain *parent;
#endif;
struct irq_domain_chip_generic_info *dgc_info;
int (*init)(struct irq_domain *d);
void (*exit)(struct irq_domain *d);
};
成员
fwnode
中断控制器的固件节点
domain_flags
添加到域标志的其他标志
大小
线性映射的大小;仅基数映射为 0
hwirq_max
控制器支持的最大中断数
direct_max
直接映射的最大值;无限制使用 ~0;无直接映射使用 0
hwirq_base
第一个硬件中断号(仅限旧式域)
virq_base
旧式域的第一个 Linux 中断号,用于在域创建后立即关联中断
bus_token
域总线令牌
name_suffix
可选名称后缀,以避免在使用同一 fwnode 添加多个域时发生冲突
ops
域操作回调
host_data
控制器私有数据指针
parent
指向分层域中使用的父中断域的指针
dgc_info
如果为 NULL,则用于为域创建通用芯片的通用芯片信息结构指针。
init
域创建时调用的函数。允许进行一些额外的域初始化。
exit
域销毁时调用的函数。允许执行一些额外的清理操作。
-
struct irq_domain *irq_domain_add_linear(struct device_node *of_node, unsigned int size, const struct irq_domain_ops *ops, void *host_data)¶
分配并注册线性反向映射 irq_domain。
参数
struct device_node *of_node
指向中断控制器的设备树节点的指针。
unsigned int size
域中的中断数。
const struct irq_domain_ops *ops
映射/取消映射域回调
void *host_data
控制器私有数据指针
-
unsigned int irq_find_mapping(struct irq_domain *domain, irq_hw_number_t hwirq)¶
从硬件中断号查找 Linux 中断。
参数
struct irq_domain *domain
拥有此硬件中断的域
irq_hw_number_t hwirq
该域空间中的硬件中断号
提供的公共函数¶
本章包含导出的内核 API 函数的自动生成文档。
-
bool synchronize_hardirq(unsigned int irq)¶
等待挂起的硬 IRQ 处理程序(在其他 CPU 上)
参数
unsigned int irq
要等待的中断号
此函数等待此中断的任何挂起硬 IRQ 处理程序完成,然后返回。如果在持有 IRQ 处理程序可能需要的资源时使用此函数,将会发生死锁。它不考虑关联的线程处理程序。
不要将其用于关闭场景,在这些场景中,您必须确保所有部分(硬中断和线程处理程序)都已完成。
返回
如果线程处理程序处于活动状态,则返回 false。
此函数可以(小心)从 IRQ 上下文调用。
它不会检查硬件级别是否有一个正在飞行但尚未处理的中断,因为当禁用中断并使用中断的目标 CPU 是当前 CPU 调用时,这可能会导致死锁。
-
void synchronize_irq(unsigned int irq)¶
等待挂起的中断处理程序(在其他 CPU 上)
参数
unsigned int irq
要等待的中断号
此函数等待此中断的任何挂起中断处理程序完成,然后返回。如果在持有 IRQ 处理程序可能需要的资源时使用此函数,将会发生死锁。
只能从可抢占代码调用,因为当中断线程与 irq 关联时,它可能会休眠。
它还会可选地确保(当中断芯片支持该方法时)中断在任何 CPU 中都没有挂起并等待服务。
-
int irq_can_set_affinity(unsigned int irq)¶
检查是否可以设置给定中断的亲和性
参数
unsigned int irq
要检查的中断
-
bool irq_can_set_affinity_usr(unsigned int irq)¶
检查是否可以从用户空间设置中断的亲和性。
-
void irq_set_thread_affinity(struct irq_desc *desc)¶
通知中断线程调整亲和性。
参数
struct irq_desc *desc
已更改亲和性的中断描述符。
我们只是设置 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 保留模式(在配置 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 特定数据或指向每个 CPU 设备 ID 中断的 vCPU 特定数据的每个 CPU 数组的指针。
此函数使用 vCPU 特定数据为中断设置 vCPU 亲和性。vCPU 特定数据从外部传递,例如 KVM。一个示例代码路径如下:KVM -> IOMMU ->
irq_set_vcpu_affinity()
。
-
void disable_irq_nosync(unsigned int irq)¶
禁用中断而不等待。
参数
unsigned int irq
要禁用的中断。
禁用选定的中断线。禁用和启用是嵌套的。与
disable_irq()
不同,此函数不保证 IRQ 处理程序的现有实例在返回之前已完成。此函数可以从 IRQ 上下文中调用。
-
void disable_irq(unsigned int irq)¶
禁用中断并等待完成。
参数
unsigned int irq
要禁用的中断。
禁用选定的中断线。启用和禁用是嵌套的。此函数会等待此中断的任何待处理 IRQ 处理程序在返回之前完成。如果在持有 IRQ 处理程序可能需要的资源时使用此函数,则会发生死锁。
只能从可抢占代码调用,因为当中断线程与 irq 关联时,它可能会休眠。
-
bool disable_hardirq(unsigned int irq)¶
禁用中断并等待硬中断完成。
参数
unsigned int irq
要禁用的中断。
禁用选定的中断线。启用和禁用是嵌套的。此函数会等待此中断的任何待处理硬 IRQ 处理程序在返回之前完成。如果在持有硬 IRQ 处理程序可能需要的资源时使用此函数,则会发生死锁。
当用于从原子上下文中乐观地禁用中断时,必须检查返回值。
返回
如果线程处理程序处于活动状态,则返回 false。
此函数可以(小心)从 IRQ 上下文调用。
-
void disable_nmi_nosync(unsigned int irq)¶
禁用 NMI 而不等待。
参数
unsigned int irq
要禁用的中断。
禁用选定的中断线。禁用和启用是嵌套的。要禁用的中断必须已通过 request_nmi 请求。与 disable_nmi() 不同,此函数不保证 IRQ 处理程序的现有实例在返回之前已完成。
-
void enable_irq(unsigned int 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)¶
控制中断电源管理唤醒。
参数
unsigned int irq
要控制的中断。
unsigned int on
启用/禁用电源管理唤醒。
启用/禁用电源管理唤醒模式,默认情况下禁用。启用和禁用必须匹配,就像它们匹配非唤醒模式支持一样。
唤醒模式允许此 IRQ 从睡眠状态(如“挂起到 RAM”)唤醒系统。
注意
- 中断使能/禁用状态是完全正交的
与中断唤醒的使能/禁用状态无关。可以使用
disable_irq()
禁用中断,只要该中断启用了唤醒功能,它仍然可以唤醒系统。如果情况并非如此,则需要检查底层中断芯片和相关驱动程序。
-
void irq_wake_thread(unsigned int irq, void *dev_id)¶
为 dev_id 标识的操作唤醒中断线程
参数
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
当 IRQ 发生时要调用的函数。线程中断的主要处理程序。如果 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 的 irq 是否已启用
参数
unsigned int irq
要检查的 Linux irq 编号
描述
必须从不可迁移的上下文中调用。返回当前 CPU 上每个 CPU 中断的启用状态。
参数
unsigned int irq
要释放的中断线
struct irqaction *act
中断的 irqaction
描述
用于移除早期启动过程静态设置的中断。
-
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 上启用,则必须使用 enable_percpu_irq() 在每个 CPU 上执行此操作。
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 必须通过调用
prepare_percpu_nmi()
进行设置,然后才能使用 enable_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 配置的中断线
-
int irq_get_irqchip_state(unsigned int irq, enum irqchip_irq_state which, bool *state)¶
返回中断的 irqchip 状态。
参数
unsigned int irq
转发到 VM 的中断线
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
转发到 VM 的中断线
enum irqchip_irq_state which
要恢复的状态(IRQCHIP_STATE_* 之一)
bool val
与 which 对应的值
此调用根据 which 的值设置中断的内部 irqchip 状态。
如果中断控制器具有每个 CPU 的寄存器,则应在禁用迁移的情况下调用此函数。
-
bool irq_has_action(unsigned int irq)¶
检查是否请求了中断
参数
unsigned int irq
Linux 中断号
返回
当前状态的快照
-
bool irq_check_status_bit(unsigned int irq, unsigned int bitmask)¶
检查是否设置了 irq 描述符状态中的位
参数
unsigned int irq
Linux 中断号
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_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 不会进行统计跟踪、随机性或杂散中断检测。
注意
- 与 handle_simple_irq 类似,调用者需要处理
必要的 ack、clear、mask 和 unmask 问题。
-
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_chip 也需要调用其 ->irq_ack() 函数的层次结构。
-
void handle_fasteoi_mask_irq(struct irq_desc *desc)¶
堆叠在透明控制器上的电平层次结构的 irq 处理程序
参数
struct irq_desc *desc
此 irq 的中断描述结构
与
handle_fasteoi_irq()
类似,但用于 irq_chip 也需要调用其 ->irq_mask_ack() 函数的层次结构。
-
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)¶
调用属于域的 HW irq 的处理程序。
参数
struct irq_domain *domain
执行查找的域
unsigned int hwirq
要转换为逻辑编号的 HW irq 编号
返回
成功返回 0,如果转换失败返回 -EINVAL
此函数必须在 IRQ 上下文中调用,且 irq 寄存器已初始化。
-
int generic_handle_domain_nmi(struct irq_domain *domain, unsigned int hwirq)¶
调用属于域的 HW nmi 的处理程序。
参数
struct irq_domain *domain
执行查找的域
unsigned int hwirq
要转换为逻辑编号的 HW 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
从哪里开始搜索
描述
返回 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)¶
处理伪中断和未处理的中断
参数
struct irq_desc *desc
中断的描述
描述
处理伪中断和未处理的 IRQ。 它还会打印调试消息。
-
void noinstr generic_handle_arch_irq(struct pt_regs *regs)¶
对于不自行进行入口计数的架构的根中断处理程序
参数
struct pt_regs *regs
来自底层处理代码的寄存器文件
-
int irq_set_msi_desc_off(unsigned int irq_base, unsigned int irq_offset, struct msi_desc *entry)¶
在偏移量处为中断设置 MSI 描述符数据
参数
unsigned int irq_base
中断号基数
unsigned int irq_offset
中断号偏移量
struct msi_desc *entry
指向 MSI 描述符数据的指针
在偏移量处为中断设置 MSI 描述符条目
-
int irq_set_msi_desc(unsigned int irq, struct msi_desc *entry)¶
为中断设置 MSI 描述符数据
参数
unsigned int irq
中断号
struct msi_desc *entry
指向 MSI 描述符数据的指针
为中断设置 MSI 描述符条目
-
void irq_disable(struct irq_desc *desc)¶
标记中断已禁用
参数
struct irq_desc *desc
应禁用的中断描述符
描述
如果芯片未实现 irq_disable 回调,我们将使用惰性禁用方法。 这意味着我们将中断标记为已禁用,但保持硬件未屏蔽。 这是一种优化,因为我们可以避免在将中断标记为禁用后没有中断发生的常见情况下的硬件访问。 如果发生中断,则中断流处理程序会在硬件级别屏蔽该线路并将其标记为挂起。
如果中断芯片未实现 irq_disable 回调,则驱动程序可以通过调用 ‘irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY)’ 来禁用特定中断线的惰性方法。 这可以用于在某些情况下无法在设备级别禁用中断并且必须使用 disable_irq[_nosync] 的设备。
-
void handle_edge_eoi_irq(struct irq_desc *desc)¶
边沿 EOI 类型 IRQ 处理程序
参数
struct irq_desc *desc
此 irq 的中断描述结构
描述
与上面的 handle_edge_irq 类似,但使用 eoi 且没有屏蔽/取消屏蔽逻辑。
-
void handle_percpu_irq(struct irq_desc *desc)¶
每个 CPU 的本地中断处理程序
参数
struct irq_desc *desc
此 irq 的中断描述结构
在没有锁定要求的 SMP 机器上的每个 CPU 中断
-
void handle_percpu_devid_irq(struct irq_desc *desc)¶
带有每个 CPU 设备 ID 的每个 CPU 本地中断处理程序
参数
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 设备 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
指向中断特定数据的指针
描述
禁用由中断数据结构 `belongs` 引用的 IRQ 芯片的电源。请注意,只有在所有调用过 irq_chip_pm_get()
的 IRQ 都调用过此函数后,才会禁用电源。
致谢¶
以下人员为本文档做出了贡献
Thomas Gleixner tglx@linutronix.de
Ingo Molnar mingo@elte.hu