irq_domain 中断号映射库

Linux 内核的当前设计使用一个大的编号空间,其中每个单独的 IRQ 源都被分配一个唯一的编号。当只有一个中断控制器时,这很简单。但在具有多个中断控制器的系统中,内核必须确保为每个中断控制器分配不重叠的 Linux IRQ 编号。

注册为唯一 irqchip 的中断控制器数量呈上升趋势。例如,诸如 GPIO 控制器之类的不同类型的子驱动程序通过将其中断处理程序建模为 irqchip 来避免重新实现与 IRQ 核心系统相同的回调机制。即,实际上是级联中断控制器。

因此,在过去,IRQ 编号可以选择为与硬件 IRQ 线匹配到根中断控制器(即,实际向 CPU 发出中断线的组件)。如今,这个数字只是一个数字,并且该数字失去了与硬件中断号的任何对应关系。

因此,我们需要一种机制来分离控制器本地中断号(称为硬件 IRQ)与 Linux IRQ 编号。

irq_alloc_desc*() 和 irq_free_desc*() API 提供 IRQ 编号的分配,但它们不提供对控制器本地 IRQ (hwirq) 编号到 Linux IRQ 编号空间的逆向映射的任何支持。

irq_domain 库在 irq_alloc_desc*() API 之上添加了 hwirq 和 IRQ 编号之间的映射。优先使用 irq_domain 来管理映射,而不是中断控制器驱动程序开放编码其自己的反向映射方案。

irq_domain 还实现了从抽象 struct irq_fwspec 到 hwirq 编号的转换(目前为止为设备树、非 DT 固件节点、ACPI GSI 和软件节点),并且可以轻松扩展以支持其他 IRQ 拓扑数据源。该实现无需任何额外的平台支持代码即可执行。

irq_domain 用法

struct irq_domain 可以定义为 irq 域控制器。也就是说,它处理给定中断域的硬件和虚拟中断号之间的映射。域结构通常由给定 PIC 实例的 PIC 代码创建(尽管域可以覆盖多个 PIC,如果它们具有扁平编号模型)。域回调负责在给定 irq_desc 上设置 irq_chip(在映射之后)。

主机代码和数据结构使用 fwnode_handle 指针来标识域。在某些情况下,为了保持源代码兼容性,此 fwnode 指针被“升级”为 DT device_node。对于那些不为中断控制器提供唯一标识符的固件基础设施,irq_domain 代码提供了一个 fwnode 分配器。

中断控制器驱动程序通过调用 irq_domain_create_*() 函数之一(每种映射方法都有不同的分配器函数,稍后会详细介绍)来创建和注册 struct irq_domain。该函数将成功后返回指向 struct irq_domain 的指针。调用者必须为分配器函数提供一个 struct irq_domain_ops 指针。

在大多数情况下,irq_domain 将以空状态开始,没有任何 hwirq 和 IRQ 编号之间的映射。通过调用 irq_create_mapping() 将映射添加到 irq_domain,该函数接受 irq_domain 和 hwirq 编号作为参数。如果 hwirq 的映射尚不存在,irq_create_mapping() 将分配一个新的 Linux irq_desc,将其与 hwirq 关联,并调用 irq_domain_ops.map() 回调。在那里,驱动程序可以执行任何所需的硬件设置。

一旦建立了映射,就可以通过多种方法检索或使用它

请注意,irq 域查找必须发生在与 RCU 读取端关键部分兼容的上下文中。

必须在任何调用 irq_find_mapping() 之前至少一次调用 irq_create_mapping() 函数,否则不会分配描述符。

如果驱动程序具有 Linux IRQ 编号或 irq_data 指针,并且需要知道关联的 hwirq 编号(例如在 irq_chip 回调中),则可以直接从 irq_data.hwirq 获取。

irq_domain 映射类型

有几种机制可用于从 hwirq 到 Linux irq 的反向映射,每种机制都使用不同的分配函数。应使用哪种反向映射类型取决于用例。以下描述了每种反向映射类型

线性

irq_domain_create_linear()

线性反向映射维护一个由 hwirq 编号索引的固定大小表。当映射 hwirq 时,将为 hwirq 分配一个 irq_desc,并将 IRQ 编号存储在表中。

当 hwirq 的最大数量是固定的并且相对较小(~ < 256)时,线性映射是一个不错的选择。此映射的优点是 IRQ 编号的固定时间查找,并且仅为使用中的 IRQ 分配 irq_desc。缺点是表必须与最大的 hwirq 编号一样大。

大多数驱动程序应使用线性映射。

irq_domain_create_tree()

irq_domain 维护从 hwirq 编号到 Linux IRQ 的基数树映射。当映射 hwirq 时,将分配一个 irq_desc,并且 hwirq 用作基数树的查找键。

如果 hwirq 编号可能非常大,则树映射是一个不错的选择,因为它不需要分配与最大 hwirq 编号一样大的表。缺点是 hwirq 到 IRQ 编号的查找取决于表中有多少个条目。

很少有驱动程序需要此映射。

无映射

irq_domain_create_nomap()

当可以在硬件中对 hwirq 编号进行编程时,应使用无映射。在这种情况下,最好将 Linux IRQ 编号编程到硬件本身中,这样就不需要映射。调用 irq_create_direct_mapping() 将分配一个 Linux IRQ 编号并调用 .map() 回调,以便驱动程序可以将 Linux IRQ 编号编程到硬件中。

大多数驱动程序无法使用此映射,并且它现在已在 CONFIG_IRQ_DOMAIN_NOMAP 选项上进行门控。请避免引入此 API 的新用户。

旧版

irq_domain_create_simple()
irq_domain_create_legacy()

旧版映射是针对已经为 hwirq 分配了一系列 irq_desc 的驱动程序的特殊情况。当无法立即转换驱动程序以使用线性映射时,将使用它。例如,许多嵌入式系统板支持文件使用一组 #defines 作为传递给 struct device 注册的 IRQ 编号。在这种情况下,无法动态分配 Linux IRQ 编号,应使用旧版映射。

顾名思义,*_legacy() 函数已被弃用,仅用于简化对旧平台的支持。不应添加新用户。当 *_simple() 函数的使用导致旧版行为时,也是如此。

旧版映射假定已为控制器分配了连续的 IRQ 编号范围,并且可以通过将固定偏移量添加到 hwirq 编号来计算 IRQ 编号,反之亦然。缺点是它要求中断控制器管理 IRQ 分配,并且即使未使用,也需要为每个 hwirq 分配一个 irq_desc。

仅当必须支持固定 IRQ 映射时,才应使用旧版映射。例如,ISA 控制器将使用旧版映射来映射 Linux IRQ 0-15,以便现有 ISA 驱动程序获得正确的 IRQ 编号。

旧版映射的大多数用户应使用 irq_domain_create_simple(),如果系统提供了 IRQ 范围,则该函数将仅使用旧版域,否则将使用线性域映射。此调用的语义是,如果指定了 IRQ 范围,则将即时分配描述符,如果未指定范围,则将回退到 irq_domain_create_linear(),这意味着不会分配 irq 描述符。

简单域的典型用例是 irqchip 提供程序同时支持动态和静态 IRQ 分配。

为了避免最终使用线性域并且没有分配描述符的情况,非常重要的是,使用简单域的驱动程序在任何 irq_find_mapping() 之前调用 irq_create_mapping(),因为后者实际上适用于静态 IRQ 分配情况。

层次结构 IRQ 域

在某些体系结构上,可能涉及多个中断控制器,以便将中断从设备传递到目标 CPU。让我们看一下 x86 平台上的典型中断传递路径

Device --> IOAPIC -> Interrupt remapping Controller -> Local APIC -> CPU

涉及三个中断控制器

  1. IOAPIC 控制器

  2. 中断重映射控制器

  3. 本地 APIC 控制器

为了支持这样的硬件拓扑并使软件体系结构与硬件体系结构匹配,为每个中断控制器构建了一个 irq_domain 数据结构,并将这些 irq_domain 组织成层次结构。构建 irq_domain 层次结构时,靠近设备的 irq_domain 是子域,靠近 CPU 的 irq_domain 是父域。因此,将为上面的示例构建如下的层次结构

CPU Vector irq_domain (root irq_domain to manage CPU vectors)
        ^
        |
Interrupt Remapping irq_domain (manage irq_remapping entries)
        ^
        |
IOAPIC irq_domain (manage IOAPIC delivery entries/pins)

有四个主要接口可用于层次结构 irq_domain

  1. irq_domain_alloc_irqs():分配 IRQ 描述符和中断控制器相关资源以传递这些中断。

  2. irq_domain_free_irqs():释放与这些中断关联的 IRQ 描述符和中断控制器相关资源。

  3. irq_domain_activate_irq():激活中断控制器硬件以传递中断。

  4. irq_domain_deactivate_irq():停用中断控制器硬件以停止传递中断。

支持层次结构 irq_domain 需要以下内容

  1. struct irq_domain 中的 parent 字段用于维护 irq_domain 层次结构信息。

  2. struct irq_data 中的 parent_data 字段用于构建层次结构 irq_data 以匹配层次结构 irq_domain。irq_data 用于存储 irq_domain 指针和硬件 irq 编号。

  3. struct irq_domain_ops 中的 alloc()free() 和其他回调用于支持层次结构 irq_domain 操作。

在支持层次结构 irq_domain 和层次结构 irq_data 准备就绪后,为每个中断控制器构建一个 irq_domain 结构,并为与 IRQ 关联的每个 irq_domain 分配一个 irq_data 结构。

为了使中断控制器驱动程序支持层次结构 irq_domain,它需要

  1. 实现 irq_domain_ops.alloc() 和 irq_domain_ops.free()

  2. 可选地,实现 irq_domain_ops.activate() 和 irq_domain_ops.deactivate()。

  3. 可选地,实现 irq_chip 以管理中断控制器硬件。

  4. 无需实现 irq_domain_ops.map() 和 irq_domain_ops.unmap()。它们与层次结构 irq_domain 不一起使用。

请注意,层次结构 irq_domain 绝不是 x86 特定的,并且被大量用于支持其他体系结构,例如 ARM、ARM64 等。

堆叠 irq_chip

现在,我们可以更进一步来支持堆叠(层次结构)irq_chip。也就是说,一个 irq_chip 与层次结构中的每个 irq_data 相关联。子 irq_chip 可以通过自身或通过与其父 irq_chip 合作来实现所需的动作。

使用堆叠 irq_chip,中断控制器驱动程序只需要处理自身管理的硬件,并且可以在需要时向其父 irq_chip 请求服务。因此,我们可以实现更清晰的软件体系结构。

调试

通过打开 CONFIG_GENERIC_IRQ_DEBUGFS,IRQ 子系统的大部分内部结构都会在 debugfs 中公开。

提供的结构和公共函数

本章包含用于 IRQ 域的结构和导出的内核 API 函数的自动生成文档。

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

匹配中断控制器 fw 规范。它比 match 更通用,因为它接收完整的 struct irq_fwspec。因此,如果提供了 select,则首选它。匹配时返回 1。

map

创建或更新虚拟 irq 编号和 hw irq 编号之间的映射。对于给定的映射,这只会被调用一次。

unmap

处置此类映射

xlate

给定设备树节点和中断说明符,解码硬件 irq 编号和 linux irq 类型值。

alloc

virq 开始分配 nr_irqs 个中断。

free

virq 开始释放 nr_irqs 个中断。

activate

在 HW 中激活一个中断 (irqd)。如果设置了 reserve,则只保留向量。如果未设置,则分配向量(从 request_irq() 调用)。

deactivate

解除一个中断 (irqd) 的武装。

translate

给定 fwspec,解码硬件 irq 编号 (out_hwirq) 和 linux irq 类型值 (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[] ;
};

成员

link

全局 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 的设备的指针。使用每个设备 irq 域时,这不一定与 pm_dev 相同。

pm_dev

指向可用于与 irq 域相关的电源管理目的的设备的指针。

parent

指向父 irq_domain 以支持层次结构 irq_domain

msi_parent_ops

用于每个设备域初始化的指向 MSI 父域方法的指针

exit

销毁域时调用的函数

hwirq_max

HW irq 编号的上限。特别是为了避免与保留的 HW irq 发生冲突/故障。可以是 ~0。

revmap_size

线性映射表 revmap 的大小

revmap_tree

用于不适合线性映射的 hwirq 的基数映射树

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

要添加到域标志的其他标志

size

线性映射的大小;对于仅基数映射,为 0

hwirq_max

控制器支持的最大中断数

direct_max

直接映射的最大值;对于无限制,请使用 ~0;对于无直接映射,请使用 0

hwirq_base

第一个硬件中断号(仅限旧版域)

virq_base

旧版域的第一个 Linux 中断号,用于在域创建后立即关联中断

bus_token

域总线令牌

name_suffix

可选名称后缀,以避免使用相同 fwnode 添加多个域时发生冲突

ops

域操作回调

host_data

控制器私有数据指针

parent

指向层次结构域中使用的父 irq 域的指针

dgc_info

如果不是 NULL,则用于为域创建通用芯片的 Geneneric 芯片信息结构指针。

init

创建域时调用的函数。允许进行一些额外的域初始化。

exit

销毁域时调用的函数。允许执行一些额外的清理操作。

struct irq_domain *irq_domain_create_linear(struct fwnode_handle *fwnode, unsigned int size, const struct irq_domain_ops *ops, void *host_data)

分配和注册线性 revmap irq_domain。

参数

struct fwnode_handle *fwnode

指向中断控制器的 FW 节点的指针。

unsigned int size

域中的中断数。

const struct irq_domain_ops *ops

map/unmap 域回调

void *host_data

控制器私有数据指针

返回

新创建的 irq_domain

unsigned int irq_create_mapping(struct irq_domain *domain, irq_hw_number_t hwirq)

将硬件中断映射到 linux irq 空间

参数

struct irq_domain *domain

拥有此硬件中断的域,如果为 NULL,则表示默认域

irq_hw_number_t hwirq

该域空间中的硬件 irq 编号

描述

每个硬件中断只允许一个映射。

如果要指定感应/触发器,则应在从该调用返回的编号上调用 set_irq_type()。

返回

Linux irq 编号,如果出错,则为 0

struct irq_desc *irq_resolve_mapping(struct irq_domain *domain, irq_hw_number_t hwirq)

从 hw irq 编号查找 linux irq。

参数

struct irq_domain *domain

拥有此硬件中断的域

irq_hw_number_t hwirq

该域空间中的硬件 irq 编号

返回

中断描述符

unsigned int irq_find_mapping(struct irq_domain *domain, irq_hw_number_t hwirq)

从 hw irq 编号查找 linux irq。

参数

struct irq_domain *domain

拥有此硬件中断的域

irq_hw_number_t hwirq

该域空间中的硬件 irq 编号

返回

Linux irq 编号,如果未找到,则为 0

struct irq_domain *irq_domain_create_hierarchy(struct irq_domain *parent, unsigned int flags, unsigned int size, struct fwnode_handle *fwnode, const struct irq_domain_ops *ops, void *host_data)

将 irqdomain 添加到层次结构中

参数

struct irq_domain *parent

要与新域关联的父 irq 域

unsigned int flags

与域关联的 Irq 域标志

unsigned int size

域的大小。请参见下文

struct fwnode_handle *fwnode

中断控制器的可选 fwnode

const struct irq_domain_ops *ops

指向中断域回调的指针

void *host_data

控制器私有数据指针

描述

如果 size 为 0,则创建树域,否则创建线性域。

如果成功,则将父级与新域关联,并设置域标志。

返回

指向 IRQ 域的指针,如果失败,则为 NULL

int irq_domain_alloc_irqs(struct irq_domain *domain, unsigned int nr_irqs, int node, void *arg)

从域分配 IRQ

参数

struct irq_domain *domain

要从中分配的域

unsigned int nr_irqs

要分配的 IRQ 数

int node

用于内存分配的 NUMA 节点 ID

void *arg

特定于域的参数

描述

请参见 __irq_domain_alloc_irqs() 的文档。

struct fwnode_handle *__irq_domain_alloc_fwnode(unsigned int type, int id, const char *name, phys_addr_t *pa)

分配适合于标识 irq 域的 fwnode_handle

参数

unsigned int type

irqchip_fwnode 的类型。请参见 linux/irqdomain.h

int id

如果 name != NULL,则为可选的用户提供的 id

const char *name

可选的用户提供的域名

phys_addr_t *pa

可选的用户提供的物理地址

描述

分配一个 struct irqchip_fwid,并返回指向嵌入的 fwnode_handle 的指针(如果失败,则返回 NULL)。

注意

类型 IRQCHIP_FWNODE_NAMED 和 IRQCHIP_FWNODE_NAMED_ID 仅用于将名称信息传输到 irqdomain 创建代码。该节点未存储。对于其他类型,指针保存在 irq 域结构中。

void irq_domain_free_fwnode(struct fwnode_handle *fwnode)

释放一个非OF支持的 fwnode_handle

参数

struct fwnode_handle *fwnode

要释放的 fwnode_handle

描述

释放一个用 irq_domain_alloc_fwnode 分配的 fwnode_handle。

struct irq_domain *irq_domain_instantiate(const struct irq_domain_info *info)

实例化一个新的 irq 域数据结构

参数

const struct irq_domain_info *info

指向此域信息的域信息指针

返回

指向实例化的 irq 域的指针,或一个 ERR_PTR 值。

void irq_domain_remove(struct irq_domain *domain)

移除一个 irq 域。

参数

struct irq_domain *domain

要移除的域

描述

此例程用于移除一个 irq 域。调用者必须确保在使用之前,域中的所有映射都已根据 revmap 类型进行处理。

struct irq_domain *irq_domain_create_simple(struct fwnode_handle *fwnode, unsigned int size, unsigned int first_irq, const struct irq_domain_ops *ops, void *host_data)

注册一个 irq_domain 并可选择映射一个 irq 范围

参数

struct fwnode_handle *fwnode

中断控制器的固件节点

unsigned int size

映射中的 irq 总数

unsigned int first_irq

分配给域的 irq 块的第一个数字,传递零以动态分配 irq。如果 first_irq 非零,则预先将域中的所有 irq 映射到从 first_irq 开始的 virq。

const struct irq_domain_ops *ops

域回调

void *host_data

控制器私有数据指针

描述

分配一个 irq_domain,如果 first_irq 为正,则可选择分配 irq_descs 并将所有 hwirq 映射到从 first_irq 开始的 virq。

此操作旨在实现大多数中断控制器的预期行为。如果使用设备树,则 first_irq 将为 0,并且 irq 会动态地进行映射。但是,如果控制器需要静态 virq 分配(非 DT 引导),则可以正确设置。

struct irq_domain *irq_find_matching_fwspec(struct irq_fwspec *fwspec, enum irq_domain_bus_token bus_token)

为给定的 fwspec 查找域

参数

struct irq_fwspec *fwspec

中断的 FW 说明符

enum irq_domain_bus_token bus_token

特定于域的数据

void irq_set_default_domain(struct irq_domain *domain)

设置一个“默认” irq 域

参数

struct irq_domain *domain

默认域指针

描述

为了方便起见,可以设置一个“默认”域,每当将 NULL 传递给 irq_create_mapping() 时,都会使用它。这使得平台更容易处理设备树中未正确表示的一些硬编码中断号。

struct irq_domain *irq_get_default_domain(void)

检索“默认” irq 域

参数

void

无参数

返回

默认域(如果有)。

描述

现代代码永远不应使用此函数。此函数只应在无法实现 firmware->fwnode 映射的系统上使用(DT 和 ACPI 均提供)。

unsigned int irq_create_direct_mapping(struct irq_domain *domain)

为直接映射分配一个 irq

参数

struct irq_domain *domain

为其分配 irq 的域,或 NULL 表示默认域

描述

此例程用于可以选择其生成的硬件中断号的 irq 控制器。在这种情况下,最简单的方法是将 Linux irq 用作硬件中断号。它仍然使用线性或基数树来存储映射,但 irq 控制器可以通过直接使用 hwirq 来优化 revmap 路径。

unsigned int irq_create_mapping_affinity(struct irq_domain *domain, irq_hw_number_t hwirq, const struct irq_affinity_desc *affinity)

将硬件中断映射到 linux irq 空间

参数

struct irq_domain *domain

拥有此硬件中断的域,如果为 NULL,则表示默认域

irq_hw_number_t hwirq

该域空间中的硬件 irq 编号

const struct irq_affinity_desc *affinity

irq 亲和性

描述

每个硬件中断只允许一个映射。返回一个 Linux irq 号码。如果要指定感应/触发器,则应在从该调用返回的号码上调用 set_irq_type()。

void irq_dispose_mapping(unsigned int virq)

取消映射一个中断

参数

unsigned int virq

要取消映射的中断的 Linux irq 号码

struct irq_desc *__irq_resolve_mapping(struct irq_domain *domain, irq_hw_number_t hwirq, unsigned int *irq)

从 hw irq 编号查找 linux irq。

参数

struct irq_domain *domain

拥有此硬件中断的域

irq_hw_number_t hwirq

该域空间中的硬件 irq 编号

unsigned int *irq

可选指针,用于在需要时返回 Linux irq

描述

返回中断描述符。

int irq_domain_xlate_onecell(struct irq_domain *d, struct device_node *ctrlr, const u32 *intspec, unsigned int intsize, unsigned long *out_hwirq, unsigned int *out_type)

用于直接单元格绑定的通用 xlate

参数

struct irq_domain *d

参与转换的中断域

struct device_node *ctrlr

设备树节点,用于转换其中断的设备

const u32 *intspec

来自设备树的中断说明符数据

unsigned int intsize

intspec 中的条目数

unsigned long *out_hwirq

用于存储硬件中断号的指针

unsigned int *out_type

用于存储中断类型的指针

描述

设备树 IRQ 说明符转换函数,适用于单元格值直接映射到 hwirq 号码的一个单元格绑定。

int irq_domain_xlate_twocell(struct irq_domain *d, struct device_node *ctrlr, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_type)

用于直接双单元格绑定的通用 xlate

参数

struct irq_domain *d

参与转换的中断域

struct device_node *ctrlr

设备树节点,用于转换其中断的设备

const u32 *intspec

来自设备树的中断说明符数据

unsigned int intsize

intspec 中的条目数

irq_hw_number_t *out_hwirq

用于存储硬件中断号的指针

unsigned int *out_type

用于存储中断类型的指针

描述

设备树 IRQ 说明符转换函数,适用于单元格值直接映射到 hwirq 号码和 Linux irq 标志的双单元格绑定。

int irq_domain_xlate_twothreecell(struct irq_domain *d, struct device_node *ctrlr, const u32 *intspec, unsigned int intsize, irq_hw_number_t *out_hwirq, unsigned int *out_type)

用于直接双单元格或三单元格绑定的通用 xlate

参数

struct irq_domain *d

参与转换的中断域

struct device_node *ctrlr

设备树节点,用于转换其中断的设备

const u32 *intspec

来自设备树的中断说明符数据

unsigned int intsize

intspec 中的条目数

irq_hw_number_t *out_hwirq

用于存储硬件中断号的指针

unsigned int *out_type

用于存储中断类型的指针

描述

用于双单元格或三单元格绑定的设备树中断说明符转换函数,其中单元格值直接映射到硬件中断号和类型说明符。

int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr, const u32 *intspec, unsigned int intsize, unsigned long *out_hwirq, unsigned int *out_type)

用于单单元格或双单元格绑定的通用 xlate

参数

struct irq_domain *d

参与转换的中断域

struct device_node *ctrlr

设备树节点,用于转换其中断的设备

const u32 *intspec

来自设备树的中断说明符数据

unsigned int intsize

intspec 中的条目数

unsigned long *out_hwirq

用于存储硬件中断号的指针

unsigned int *out_type

用于存储中断类型的指针

描述

设备树 IRQ 说明符转换函数,适用于单元格值直接映射到 hwirq 号码和 Linux irq 标志的单单元格或双单元格绑定。

注意

除非您的中断控制器明确支持单单元格和双单元格绑定,否则请勿使用此函数。对于大多数控制器,应使用上面的 _onecell() 或 _twocell() 变体。

int irq_domain_translate_onecell(struct irq_domain *d, struct irq_fwspec *fwspec, unsigned long *out_hwirq, unsigned int *out_type)

用于直接单元格绑定的通用转换

参数

struct irq_domain *d

参与转换的中断域

struct irq_fwspec *fwspec

要转换的固件中断说明符

unsigned long *out_hwirq

用于存储硬件中断号的指针

unsigned int *out_type

用于存储中断类型的指针

int irq_domain_translate_twocell(struct irq_domain *d, struct irq_fwspec *fwspec, unsigned long *out_hwirq, unsigned int *out_type)

用于直接双单元格绑定的通用转换

参数

struct irq_domain *d

参与转换的中断域

struct irq_fwspec *fwspec

要转换的固件中断说明符

unsigned long *out_hwirq

用于存储硬件中断号的指针

unsigned int *out_type

用于存储中断类型的指针

描述

设备树 IRQ 说明符转换函数,适用于单元格值直接映射到 hwirq 号码和 Linux irq 标志的双单元格绑定。

int irq_domain_translate_twothreecell(struct irq_domain *d, struct irq_fwspec *fwspec, unsigned long *out_hwirq, unsigned int *out_type)

用于直接双单元格或三单元格绑定的通用转换

参数

struct irq_domain *d

参与转换的中断域

struct irq_fwspec *fwspec

要转换的固件中断说明符

unsigned long *out_hwirq

用于存储硬件中断号的指针

unsigned int *out_type

用于存储中断类型的指针

描述

用于双单元格或三单元格规范的固件中断说明符转换函数,其中参数值直接映射到硬件中断号和类型说明符。

void irq_domain_reset_irq_data(struct irq_data *irq_data)

清除 irq_data 中的 hwirq、chip 和 chip_data

参数

struct irq_data *irq_data

指向 irq_data 的指针

int irq_domain_disconnect_hierarchy(struct irq_domain *domain, unsigned int virq)

标记层次结构的第一个未使用的级别

参数

struct irq_domain *domain

要断开层次结构的 IRQ 域

unsigned int virq

要在其中修剪层次结构的 IRQ 号码

描述

将属于 domainvirq 级别标记为已断开连接。如果 virq 没有指向 domain 的有效 irq_data,则返回 -EINVAL。

它的唯一用途是能够修剪此中断没有任何实际意义的层次结构级别,并且驱动程序从其 .alloc() 回调中将其标记为这样。

struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain, unsigned int virq)

获取与 virqdomain 关联的 irq_data

参数

struct irq_domain *domain

要匹配的域

unsigned int virq

要获取 irq_data 的 IRQ 号码

int irq_domain_set_hwirq_and_chip(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq, const struct irq_chip *chip, void *chip_data)

domain 设置 virq 的 hwirq 和 irqchip

参数

struct irq_domain *domain

要匹配的中断域

unsigned int virq

IRQ 号码

irq_hw_number_t hwirq

hwirq 号码

const struct irq_chip *chip

关联的中断芯片

void *chip_data

关联的芯片数据

void irq_domain_set_info(struct irq_domain *domain, unsigned int virq, irq_hw_number_t hwirq, const struct irq_chip *chip, void *chip_data, irq_flow_handler_t handler, void *handler_data, const char *handler_name)

domain 中设置 virq 的完整数据

参数

struct irq_domain *domain

要匹配的中断域

unsigned int virq

IRQ 号码

irq_hw_number_t hwirq

硬件中断号

const struct irq_chip *chip

关联的中断芯片

void *chip_data

关联的中断芯片数据

irq_flow_handler_t handler

中断流处理程序

void *handler_data

中断流处理程序数据

const char *handler_name

中断处理程序名称

void irq_domain_free_irqs_common(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs)

清除 irq_data 并释放父项

参数

struct irq_domain *domain

要匹配的中断域

unsigned int virq

要从其开始的 IRQ 号码

unsigned int nr_irqs

要释放的 irq 的数量

int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base, unsigned int nr_irqs, int node, void *arg, bool realloc, const struct irq_affinity_desc *affinity)

从域分配 IRQ

参数

struct irq_domain *domain

要从中分配的域

int irq_base

如果 irq_base >= 0,则分配指定的 IRQ 号码

unsigned int nr_irqs

要分配的 IRQ 数

int node

用于内存分配的 NUMA 节点 ID

void *arg

特定于域的参数

bool realloc

如果为 true,则已分配 IRQ 描述符

const struct irq_affinity_desc *affinity

多队列设备的可选 irq 亲和性掩码

描述

分配 IRQ 号码并初始化所有数据结构以支持层次结构 IRQ 域。参数 realloc 主要用于支持旧版 IRQ。返回错误代码或分配的 IRQ 号码

设置 IRQ 的整个过程已分为两个步骤。第一步,__irq_domain_alloc_irqs(),用于分配 IRQ 描述符和所需的硬件资源。第二步,irq_domain_activate_irq(),用于使用预分配的资源对硬件进行编程。这样,当无法分配资源时,更容易回滚。

int irq_domain_push_irq(struct irq_domain *domain, int virq, void *arg)

将域推送到层次结构的顶部。

参数

struct irq_domain *domain

要推送的域。

int virq

要将域推送到的 Irq。

void *arg

传递给 irq_domain_ops alloc() 函数。

描述

对于已存在的 irqdomain 层次结构(可能通过调用 pci_enable_msix() 获得),将一个附加域添加到处理链的头部。必须在调用 request_irq() 之前调用。

int irq_domain_pop_irq(struct irq_domain *domain, int virq)

从层次结构的顶部移除域。

参数

struct irq_domain *domain

要移除的域。

int virq

要从中移除域的 Irq。

描述

撤销对 irq_domain_push_irq() 调用的影响。必须在 request_irq() 之前或 free_irq() 之后调用。

int irq_domain_alloc_irqs_parent(struct irq_domain *domain, unsigned int irq_base, unsigned int nr_irqs, void *arg)

从父域分配中断

参数

struct irq_domain *domain

必须分配中断的域

unsigned int irq_base

基本 IRQ 编号

unsigned int nr_irqs

要分配的 IRQ 数量

void *arg

分配数据(特定于 arch/domain)

void irq_domain_free_irqs_parent(struct irq_domain *domain, unsigned int irq_base, unsigned int nr_irqs)

从父域释放中断

参数

struct irq_domain *domain

必须释放中断的域

unsigned int irq_base

基本 IRQ 编号

unsigned int nr_irqs

要释放的 IRQ 数量

提供的内部函数

本章包含内部函数的自动生成文档。

void irq_domain_free_irqs_top(struct irq_domain *domain, unsigned int virq, unsigned int nr_irqs)

清除处理程序和处理程序数据,清除 irqdata 并释放父级

参数

struct irq_domain *domain

要匹配的中断域

unsigned int virq

要从其开始的 IRQ 号码

unsigned int nr_irqs

要释放的 irq 的数量

void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs)

释放 IRQ 编号和关联的数据结构

参数

unsigned int virq

基本 IRQ 编号

unsigned int nr_irqs

要释放的 IRQ 数量

int irq_domain_activate_irq(struct irq_data *irq_data, bool reserve)

递归调用 domain_ops->activate 以激活中断

参数

struct irq_data *irq_data

与中断关联的最外层 irq_data

bool reserve

如果设置,则仅保留中断向量而不是分配一个

描述

这是调用 domain_ops->activate 以编程中断控制器的第二步,因此中断实际上可以传递。

void irq_domain_deactivate_irq(struct irq_data *irq_data)

递归调用 domain_ops->deactivate 以停用中断

参数

struct irq_data *irq_data

与中断关联的最外层 irq_data

描述

它调用 domain_ops->deactivate 以编程中断控制器以禁用中断传递。