[toc]

drivers/irqchip/irqchip.c

irqchip_init 初始化函数

1
2
3
4
5
6
7
8
9
10
//.lds
__irqchip_of_table = .; KEEP(*(__irqchip_of_table)) KEEP(*(__irqchip_of_table_end)) . = ALIGN(8);

extern struct of_device_id __irqchip_of_table[];

void __init irqchip_init(void)
{
of_irq_init(__irqchip_of_table);
acpi_probe_device_table(irqchip);
}

drivers/irqchip/irq-nvic.c

nvic_irq_init 初始化函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
static int __init nvic_of_init(struct device_node *node,
struct device_node *parent)
{
unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
unsigned int irqs, i, ret, numbanks;
void __iomem *nvic_base;

numbanks = (readl_relaxed(V7M_SCS_ICTR) &
V7M_SCS_ICTR_INTLINESNUM_MASK) + 1;

nvic_base = of_iomap(node, 0);
if (!nvic_base) {
pr_warn("unable to map nvic registers\n");
return -ENOMEM;
}

irqs = numbanks * 32;
if (irqs > NVIC_MAX_IRQ)
irqs = NVIC_MAX_IRQ;

nvic_irq_domain =
irq_domain_add_linear(node, irqs, &nvic_irq_domain_ops, NULL);

if (!nvic_irq_domain) {
pr_warn("Failed to allocate irq domain\n");
iounmap(nvic_base);
return -ENOMEM;
}

ret = irq_alloc_domain_generic_chips(nvic_irq_domain, 32, 1,
"nvic_irq", handle_fasteoi_irq,
clr, 0, IRQ_GC_INIT_MASK_CACHE);
if (ret) {
pr_warn("Failed to allocate irq chips\n");
irq_domain_remove(nvic_irq_domain);
iounmap(nvic_base);
return ret;
}

for (i = 0; i < numbanks; ++i) {
struct irq_chip_generic *gc;

gc = irq_get_domain_generic_chip(nvic_irq_domain, 32 * i);
gc->reg_base = nvic_base + 4 * i;
gc->chip_types[0].regs.enable = NVIC_ISER;
gc->chip_types[0].regs.disable = NVIC_ICER;
gc->chip_types[0].chip.irq_mask = irq_gc_mask_disable_reg;
gc->chip_types[0].chip.irq_unmask = irq_gc_unmask_enable_reg;
/* This is a no-op as end of interrupt is signaled by the
* exception return sequence.
*/
gc->chip_types[0].chip.irq_eoi = irq_gc_noop;

/* disable interrupts */
writel_relaxed(~0, gc->reg_base + NVIC_ICER);
}

/* 设置所有中断的优先级
将优先级设置为 0,表示最低优先级*/
for (i = 0; i < irqs; i += 4)
writel_relaxed(0, nvic_base + NVIC_IPR + i);

set_handle_irq(nvic_handle_irq);
return 0;
}
IRQCHIP_DECLARE(armv7m_nvic, "arm,armv7m-nvic", nvic_of_init);

nvic_handle_irq NVIC 中断处理函数

1
2
3
4
5
6
7
8
9
10
11
static struct irq_domain *nvic_irq_domain;

static void __irq_entry nvic_handle_irq(struct pt_regs *regs)
{
/* 提取当前活动的中断号。*/
unsigned long icsr = readl_relaxed(BASEADDR_V7M_SCB + V7M_SCB_ICSR);
/* Cortex-M 的中断号从 16 开始(前 16 个是系统异常),因此需要减去 16 才能得到硬件中断号(hwirq) */
irq_hw_number_t hwirq = (icsr & V7M_SCB_ICSR_VECTACTIVE) - 16;

generic_handle_domain_irq(nvic_irq_domain, hwirq);
}

drivers/irqchip/irq-stm32-exti.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
static const struct stm32_exti_bank stm32h7xx_exti_b1 = {
.imr_ofst = 0x80,
.emr_ofst = 0x84,
.rtsr_ofst = 0x00,
.ftsr_ofst = 0x04,
.swier_ofst = 0x08,
.rpr_ofst = 0x88,
};

static const struct stm32_exti_bank stm32h7xx_exti_b2 = {
.imr_ofst = 0x90,
.emr_ofst = 0x94,
.rtsr_ofst = 0x20,
.ftsr_ofst = 0x24,
.swier_ofst = 0x28,
.rpr_ofst = 0x98,
};

static const struct stm32_exti_bank stm32h7xx_exti_b3 = {
.imr_ofst = 0xA0,
.emr_ofst = 0xA4,
.rtsr_ofst = 0x40,
.ftsr_ofst = 0x44,
.swier_ofst = 0x48,
.rpr_ofst = 0xA8,
};

static const struct stm32_exti_bank *stm32h7xx_exti_banks[] = {
&stm32h7xx_exti_b1,
&stm32h7xx_exti_b2,
&stm32h7xx_exti_b3,
};

static const struct stm32_exti_drv_data stm32h7xx_drv_data = {
.exti_banks = stm32h7xx_exti_banks,
.bank_nr = ARRAY_SIZE(stm32h7xx_exti_banks),
};

stm32_exti_chip_init 初始化中断控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
static struct
stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data,
u32 bank_idx,
struct device_node *node)
{
const struct stm32_exti_bank *stm32_bank;
struct stm32_exti_chip_data *chip_data;
void __iomem *base = h_data->base;

stm32_bank = h_data->drv_data->exti_banks[bank_idx];
chip_data = &h_data->chips_data[bank_idx];
chip_data->host_data = h_data;
chip_data->reg_bank = stm32_bank;

/*
* This IP has no reset, so after hot reboot we should
* clear registers to avoid residue
*/
writel_relaxed(0, base + stm32_bank->imr_ofst);
writel_relaxed(0, base + stm32_bank->emr_ofst);

pr_info("%pOF: bank%d\n", node, bank_idx);

return chip_data;
}

stm32_exti_of_init 初始化函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*
* 这是一个静态的、仅在初始化阶段调用的函数,负责初始化通用的STM32 EXTI控制器。
* @drv_data: 指向一个包含了特定于芯片系列(如F4, H7)的配置数据的结构体。
* @node: 指向该EXTI控制器在设备树中的节点。
*/
static int __init stm32_exti_init(const struct stm32_exti_drv_data *drv_data,
struct device_node *node)
{
/* host_data: 指向包含了主机(host)通用数据(如寄存器基地址)的结构体。*/
struct stm32_exti_host_data *host_data;
/* clr: 一组标志,用于在分配通用芯片时,清除某些默认的中断属性。*/
unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
/* nr_irqs, ret, i: 局部变量,分别用于存储中断数量、返回值和循环计数。*/
int nr_irqs, ret, i;
/* gc: 指向一个通用的中断芯片(generic chip)数据结构。*/
struct irq_chip_generic *gc;
/* domain: 指向为此EXTI控制器创建的中断域。*/
struct irq_domain *domain;

/* 调用辅助函数,初始化主机数据,主要是进行iomap获取寄存器虚拟地址。*/
host_data = stm32_exti_host_init(drv_data, node);
if (!host_data)
return -ENOMEM;

/*
* 调用irq_domain_add_linear,创建一个线性的中断域。
* 它将管理 drv_data->bank_nr * IRQS_PER_BANK 个中断。
* irq_exti_domain_ops 定义了该域的映射等操作。
*/
domain = irq_domain_add_linear(node, drv_data->bank_nr * IRQS_PER_BANK,
&irq_exti_domain_ops, NULL);
if (!domain) {
pr_err("%pOFn: Could not register interrupt domain.\n",
node);
ret = -ENOMEM;
goto out_unmap;
}

/*
* 为这个域分配一组通用的中断芯片数据结构。每个chip管理IRQS_PER_BANK个中断。
* handle_edge_irq被设置为这些中断的默认流处理器。
*/
ret = irq_alloc_domain_generic_chips(domain, IRQS_PER_BANK, 1, "exti",
handle_edge_irq, clr, 0, 0);
if (ret) {
pr_err("%pOF: Could not allocate generic interrupt chip.\n",
node);
goto out_free_domain;
}

/* 循环遍历所有的中断bank,对每个bank的通用芯片进行定制化。*/
for (i = 0; i < drv_data->bank_nr; i++) {
const struct stm32_exti_bank *stm32_bank;
struct stm32_exti_chip_data *chip_data;

stm32_bank = drv_data->exti_banks[i];
chip_data = stm32_exti_chip_init(host_data, i, node);

/* 获取当前bank i 对应的通用中断芯片数据。*/
gc = irq_get_domain_generic_chip(domain, i * IRQS_PER_BANK);

/* 开始用特定于STM32硬件的回调函数,来覆盖通用模板中的函数指针。*/
gc->reg_base = host_data->base;
gc->chip_types->type = IRQ_TYPE_EDGE_BOTH;
gc->chip_types->chip.irq_ack = stm32_irq_ack;
gc->chip_types->chip.irq_mask = irq_gc_mask_clr_bit;
gc->chip_types->chip.irq_unmask = irq_gc_mask_set_bit;
gc->chip_types->chip.irq_set_type = stm32_irq_set_type;
gc->chip_types->chip.irq_set_wake = irq_gc_set_wake;
/* 设置挂起(suspend)和恢复(resume)时的回调。*/
gc->suspend = stm32_irq_suspend;
gc->resume = stm32_irq_resume;
gc->wake_enabled = IRQ_MSK(IRQS_PER_BANK);

/* 将硬件寄存器的偏移量设置到通用结构中。*/
gc->chip_types->regs.mask = stm32_bank->imr_ofst;
/* 存储私有数据。*/
gc->private = (void *)chip_data;
}

/* 获取EXTI控制器自身连接到上级控制器的中断线的数量。*/
nr_irqs = of_irq_count(node);
/* 循环处理每一条中断线(通常只有一条)。*/
for (i = 0; i < nr_irqs; i++) {
/* 解析设备树,获取这条中断线对应的Linux IRQ编号。*/
unsigned int irq = irq_of_parse_and_map(node, i);

/* 为这个顶层IRQ设置handler data,让其ISR可以反向找到domain。*/
irq_set_handler_data(irq, domain);
/*
* 将stm32_irq_handler注册为这个顶层IRQ的链式中断处理器。
* 这是最关键的链接步骤。
*/
irq_set_chained_handler(irq, stm32_irq_handler);
}

return 0;

/* 错误处理路径 */
out_free_domain:
irq_domain_remove(domain);
out_unmap:
iounmap(host_data->base);
kfree(host_data->chips_data);
kfree(host_data);
return ret;
}

/*
* 这是一个静态的、特定于STM32H7的设备树初始化函数。
*/
static int __init stm32h7_exti_of_init(struct device_node *np,
struct device_node *parent)
{
/* 它只是一个包装器,调用通用的stm32_exti_init,并传入STM32H7的特定数据。*/
return stm32_exti_init(&stm32h7xx_drv_data, np);
}

/*
* 使用IRQCHIP_DECLARE宏,将本驱动注册到内核。
* - stm32h7_exti: 驱动的唯一名称。
* - "st,stm32h7-exti": 它所匹配的设备树compatible字符串。
* - stm32h7_exti_of_init: 匹配成功后要调用的初始化函数。
*/
IRQCHIP_DECLARE(stm32h7_exti, "st,stm32h7-exti", stm32h7_exti_of_init);

stm32_exti_pending 获取挂起的中断状态

1
2
3
4
5
6
7
static unsigned long stm32_exti_pending(struct irq_chip_generic *gc)
{
struct stm32_exti_chip_data *chip_data = gc->private;
const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;

return irq_reg_readl(gc, stm32_bank->rpr_ofst);
}

stm32_irq_handler 中断处理函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
/*
* 这是一个静态函数,作为STM32 EXTI控制器的链式中断处理器。
* @desc: 指向代表EXTI这个聚合中断线的、顶层的irq_desc结构体。
*/
static void stm32_irq_handler(struct irq_desc *desc)
{
/* domain: 指向与这个EXTI中断相关的irq_domain。irq_domain负责IRQ编号的管理和映射。*/
struct irq_domain *domain = irq_desc_get_handler_data(desc);
/* chip: 指向顶层的irq_chip,即EXTI中断线的控制器芯片。*/
struct irq_chip *chip = irq_desc_get_chip(desc);
/* nbanks: 获取这个irq_domain管理的芯片(bank)的数量。*/
unsigned int nbanks = domain->gc->num_chips;
/* gc: 指向当前正在处理的bank所对应的irq_chip_generic结构体。*/
struct irq_chip_generic *gc;
/* pending: 一个位掩码,用于存储从硬件寄存器中读出的挂起中断状态。*/
unsigned long pending;
/* n: 在循环中,代表一个被置位的比特编号,即一个具体的中断源。*/
/* i: 用于循环遍历所有的bank。*/
/* irq_base: 当前bank中第一个中断源对应的Linux IRQ基准编号。*/
int n, i, irq_base = 0;

/*
* 调用此函数,进入链式中断处理上下文。
* 它会屏蔽顶层的硬件中断线(desc),并处理中断状态和嵌套计数。
*/
chained_irq_enter(chip, desc);

/* 循环遍历所有的中断bank。*/
for (i = 0; i < nbanks; i++, irq_base += IRQS_PER_BANK) {
/* 获取当前bank i 对应的通用中断芯片数据。*/
gc = irq_get_domain_generic_chip(domain, irq_base);

/*
* 只要当前bank中还有挂起的中断,就一直循环。
* stm32_exti_pending()会读取硬件的挂起寄存器。
*/
while ((pending = stm32_exti_pending(gc))) {
/*
* 使用for_each_set_bit宏,高效地遍历pending掩码中所有被置位的比特n。
*/
for_each_set_bit(n, &pending, IRQS_PER_BANK)
/*
* 对于每一个被触发的中断源n,计算出其全局Linux IRQ编号(irq_base + n),
* 然后调用通用的generic_handle_domain_irq函数。
* 这个函数会负责调用该IRQ最终注册的设备驱动ISR。
*/
generic_handle_domain_irq(domain, irq_base + n);
}
}

/*
* 调用此函数,退出链式中断处理上下文。
* 它会重新使能(unmask)顶层的硬件中断线(desc)。
*/
chained_irq_exit(chip, desc);
}

stm32_chip_resume stm32_irq_resume 使能唤醒源的中断 恢复中断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/* 这是一个静态函数,负责挂起一个中断bank的硬件状态。*/
static void stm32_chip_suspend(struct stm32_exti_chip_data *chip_data,
u32 wake_active)
{
/* ... (获取寄存器基地址和bank信息) ... */
const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
void __iomem *base = chip_data->host_data->base;

/* 保存rtsr(上升沿触发选择)和ftsr(下降沿触发选择)寄存器的当前值到内存中。*/
chip_data->rtsr_cache = readl_relaxed(base + stm32_bank->rtsr_ofst);
chip_data->ftsr_cache = readl_relaxed(base + stm32_bank->ftsr_ofst);

/* 将wake_active掩码写入中断屏蔽寄存器(imr),从而只使能那些作为唤醒源的中断。*/
writel_relaxed(wake_active, base + stm32_bank->imr_ofst);
}

/* 这是注册到irq_chip的.suspend回调。*/
static void stm32_irq_suspend(struct irq_chip_generic *gc)
{
struct stm32_exti_chip_data *chip_data = gc->private;

/* 获取锁,然后调用核心挂起函数。gc->wake_active是由上层PM框架准备好的唤醒掩码。*/
guard(raw_spinlock)(&gc->lock);
stm32_chip_suspend(chip_data, gc->wake_active);
}

/* 这是一个静态函数,负责恢复一个中断bank的硬件状态。*/
static void stm32_chip_resume(struct stm32_exti_chip_data *chip_data,
u32 mask_cache)
{
/* ... (获取寄存器基地址和bank信息) ... */
const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;
void __iomem *base = chip_data->host_data->base;

/* 恢复rtsr和ftsr寄存器。*/
writel_relaxed(chip_data->rtsr_cache, base + stm32_bank->rtsr_ofst);
writel_relaxed(chip_data->ftsr_cache, base + stm32_bank->ftsr_ofst);

/* 恢复中断屏蔽寄存器(imr)到休眠前的状态。*/
writel_relaxed(mask_cache, base + stm32_bank->imr_ofst);
}

/* 这是注册到irq_chip的.resume回调。*/
static void stm32_irq_resume(struct irq_chip_generic *gc)
{
struct stm32_exti_chip_data *chip_data = gc->private;

/* 获取锁,然后调用核心恢复函数。gc->mask_cache是由通用层维护的休眠前屏蔽状态。*/
guard(raw_spinlock)(&gc->lock);
stm32_chip_resume(chip_data, gc->mask_cache);
}

stm32_irq_ack 中断确认 清除该位的挂起状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
* 这是一个静态函数,作为irq_chip的.irq_ack回调实现。
* 它用于确认一个中断。
* @d: 指向被确认中断的irq_data结构体。
*/
static void stm32_irq_ack(struct irq_data *d)
{
/* gc: 获取与该中断域关联的通用中断芯片数据。*/
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
/* chip_data: 获取驱动的私有数据。*/
struct stm32_exti_chip_data *chip_data = gc->private;
/* stm32_bank: 获取该中断所属bank的寄存器偏移量信息。*/
const struct stm32_exti_bank *stm32_bank = chip_data->reg_bank;

/*
* 使用guard宏来获取并自动释放gc->lock自旋锁。
* 这确保了对共享寄存器的访问是原子的。
*/
guard(raw_spinlock)(&gc->lock);
/*
* 调用irq_reg_writel,向硬件寄存器写入数据。
* - gc: 通用芯片数据,包含了寄存器基地址。
* - d->mask: 一个位掩码,只有当前中断对应的位是1。
* - rpr_ofst: STM32 EXTI的挂起寄存器偏移量。
*
* 对于STM32 EXTI,向挂起寄存器的某位写1,会清除该位的挂起状态。
*/
irq_reg_writel(gc, d->mask, stm32_bank->rpr_ofst);
}

drivers/of/irq.c

of_irq_init 扫描并初始化设备树中的匹配中断控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/**
* of_irq_init - 扫描并初始化设备树中的匹配中断控制器
* @matches: 0 终止的节点数组以匹配和调用初始化函数
*
* 该函数扫描设备树以查找匹配的中断控制器节点,并按顺序调用它们的初始化函数,优先调用父节点。
*/
void __init of_irq_init(const struct of_device_id *matches)
{
const struct of_device_id *match;
struct device_node *np, *parent = NULL;
struct of_intc_desc *desc, *temp_desc;
struct list_head intc_desc_list, intc_parent_list;

INIT_LIST_HEAD(&intc_desc_list);
INIT_LIST_HEAD(&intc_parent_list);

/* 遍历设备树中与 matches 匹配的节点 */
for_each_matching_node_and_match(np, matches, &match) {
/* 节点是否具有 interrupt-controller 属性 */
if (!of_property_read_bool(np, "interrupt-controller") ||
/* 节点是否可用 */
!of_device_is_available(np))
continue;

if (WARN(!match->data, "of_irq_init: no init function for %s\n",
match->compatible))
continue;

/*
* 在这里,我们分配并填充一个 of_intc_desc,包括节点指针、中断父设备节点等。
*/
desc = kzalloc(sizeof(*desc), GFP_KERNEL);
if (!desc) {
of_node_put(np);
goto err;
}

desc->irq_init_cb = match->data;
desc->dev = of_node_get(np);
/*
* 中断扩展可以引用多个父域。随意选择第一个;假设其他任何父级与根IRQ控制器的距离相同。
* nterrupt_parent:中断父节点:
优先从 interrupts-extended 属性解析。
如果未找到,则调用 of_irq_find_parent 获取父节点。
如果父节点是自身,则清除父节点指针。
*/
desc->interrupt_parent = of_parse_phandle(np, "interrupts-extended", 0);
if (!desc->interrupt_parent)
desc->interrupt_parent = of_irq_find_parent(np);
if (desc->interrupt_parent == np) {
of_node_put(desc->interrupt_parent);
desc->interrupt_parent = NULL;
}
list_add_tail(&desc->list, &intc_desc_list);
}

/*
* 按照父节点优先的顺序初始化中断控制器:
根中断控制器(无父节点)优先初始化。
依次初始化引用根控制器的节点,以及引用二级控制器的节点
*/
while (!list_empty(&intc_desc_list)) {
/*
* 处理所有与当前“父级”相关的控制器。第一次通行将查找 NULL 作为父级。假设 NULL 父级意味着根控制器。
* 对当前父节点(parent)的所有子节点进行初始化
*/
list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
int ret;

if (desc->interrupt_parent != parent)
continue;
/* 将当前描述符(desc)从原链表(intc_desc_list)中移除 */
list_del(&desc->list);

of_node_set_flag(desc->dev, OF_POPULATED);/* device already created */

pr_debug("of_irq_init: init %pOF (%p), parent %p\n",
desc->dev,
desc->dev, desc->interrupt_parent);
ret = desc->irq_init_cb(desc->dev,
desc->interrupt_parent);
if (ret) {
pr_err("%s: Failed to init %pOF (%p), parent %p\n",
__func__, desc->dev, desc->dev,
desc->interrupt_parent);
of_node_clear_flag(desc->dev, OF_POPULATED);
of_node_put(desc->interrupt_parent);
of_node_put(desc->dev);
kfree(desc);
continue;
}

/*
* 这个已经设置好了;添加到父列表中,以便它的子项可以在后续处理中处理。
* 将描述符添加到另一个链表(intc_parent_list)的尾部
*/
list_add_tail(&desc->list, &intc_parent_list);
}

/* 获取下一个可能有子女的待处理父项 */
desc = list_first_entry_or_null(&intc_parent_list,
typeof(*desc), list);
if (!desc) {
pr_err("of_irq_init: children remain, but no parents\n");
break;
}
list_del(&desc->list);
parent = desc->dev;
kfree(desc);
}
/* 释放所有未使用的描述符和节点引用。 */
list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) {
list_del(&desc->list);
kfree(desc);
}
err:
list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
list_del(&desc->list);
of_node_put(desc->interrupt_parent);
of_node_put(desc->dev);
kfree(desc);
}
}
1
2
OF: of_irq_init: init /interrupt-controller@e000e100 ((ptrval)), parent 00000000
OF: of_irq_init: init /soc/interrupt-controller@58000000 ((ptrval)), parent (ptrval)

arch/arm/kernel/irq.c

init_IRQ 中断初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
static void __init init_irq_stacks(void)
{
u8 *stack;
int cpu;

for_each_possible_cpu(cpu) {
if (!IS_ENABLED(CONFIG_VMAP_STACK))
stack = (u8 *)__get_free_pages(GFP_KERNEL,
THREAD_SIZE_ORDER);
else
stack = __vmalloc_node(THREAD_SIZE, THREAD_ALIGN,
THREADINFO_GFP, NUMA_NO_NODE,
__builtin_return_address(0));

if (WARN_ON(!stack))
break;
per_cpu(irq_stack_ptr, cpu) = &stack[THREAD_SIZE];
}
}

void __init init_IRQ(void)
{
int ret;

#ifdef CONFIG_IRQSTACKS
/* 初始化中断堆栈 */
init_irq_stacks();
#endif
/* 初始化中断控制器 */
if (IS_ENABLED(CONFIG_OF) && !machine_desc->init_irq)
irqchip_init();
else
machine_desc->init_irq();
/* 调用平台特定的缓存初始化 */
uniphier_cache_init();
}