一、引言:
前几天有人WX上问中断trigger类型设置问题,引起我的兴趣,阅读了kernel6.1关于中断子系统init流程,并用EVB实际验证了自己的理解,现将其记录下来,和大家做个交流。
二、代码导读
玩过Linux内核的同学对start_kernel()并不陌生,它是内核执行各个子系统init流程的入口,其中与中断子系统有关的部分如下:
asmlinkage __visible void __init __no_sanitize_address start_kernel(void)
{
。。。
early_irq_init();
init_IRQ();
。。。
softirq_init();
}
1、early_irq_init()
kernel/irq/irqdesc.c
在arm64体系中,由于arch_probe_nr_irqs()返回值为0,所以并没有提前分配struct irq_desc,且arch_early_irq_init()也是空函数,所以其实什么也没做
530 int __init early_irq_init(void)
531 {
532 int i, initcnt, node = first_online_node;
533 struct irq_desc *desc;
534
535 init_irq_default_affinity();
536
537 /* Let arch update nr_irqs and return the nr of preallocated irqs */
538 initcnt = arch_probe_nr_irqs();
539 printk(KERN_INFO "NR_IRQS: %d, nr_irqs: %d, preallocated irqs: %d\n",
540 NR_IRQS, nr_irqs, initcnt);
541
542 if (WARN_ON(nr_irqs > IRQ_BITMAP_BITS))
543 nr_irqs = IRQ_BITMAP_BITS;
544
545 if (WARN_ON(initcnt > IRQ_BITMAP_BITS))
546 initcnt = IRQ_BITMAP_BITS;
547
548 if (initcnt > nr_irqs)
549 nr_irqs = initcnt;
550
551 for (i = 0; i < initcnt; i++) {
552 desc = alloc_desc(i, node, 0, NULL, NULL);
553 set_bit(i, allocated_irqs);
554 irq_insert_desc(i, desc);
555 }
556 return arch_early_irq_init();
557 }
2、init_IRQ()
arch/arm64/kernel/irq.c
121 void __init init_IRQ(void)
122 {
123 init_irq_stacks();
124 init_irq_scs();
125 irqchip_init();
126
127 if (system_uses_irq_prio_masking()) {
128 /*
129 * Now that we have a stack for our IRQ handler, set
130 * the PMR/PSR pair to a consistent state.
131 */
132 WARN_ON(read_sysreg(daif) & PSR_A_BIT);
133 local_daif_restore(DAIF_PROCCTX_NOIRQ);
134 }
135 }
2.1 init_irq_stacks()
arch/arm64/kernel/irq.c
53 static void init_irq_stacks(void)
54 {
55 int cpu;
56 unsigned long *p;
57
58 for_each_possible_cpu(cpu) {
59 p = arch_alloc_vmap_stack(IRQ_STACK_SIZE, cpu_to_node(cpu));
60 per_cpu(irq_stack_ptr, cpu) = p;
61 }
62 }
为每个cpu从vmalloc区域分配8k的irq stack,并赋值给全局per-cpu变量irq_stack_str
2.2 init_irq_scs()
由于默认CONFIG_SHADOW_CALL_STACK没被设置,所以直接retrun;
2.3 irqchip_init()
drivers/irqchip/irqchip.c
29 void __init irqchip_init(void)
30 {
31 of_irq_init(__irqchip_of_table);
32 。。。
33 }
2.3.1 of_irq_init(__irqchip_of_table)
drivers/of/irq.c
518 /**
519 * of_irq_init - Scan and init matching interrupt controllers in DT
520 * @matches: 0 terminated array of nodes to match and init function to call
521 *
522 * This function scans the device tree for matching interrupt controller nodes,
523 * and calls their initialization functions in order with parents first.
524 */
525 void __init of_irq_init(const struct of_device_id *matches)
526 {
527 const struct of_device_id *match;
528 struct device_node *np, *parent = NULL;
529 struct of_intc_desc *desc, *temp_desc;
530 struct list_head intc_desc_list, intc_parent_list;
531
532 INIT_LIST_HEAD(&intc_desc_list);
533 INIT_LIST_HEAD(&intc_parent_list);
534
535 for_each_matching_node_and_match(np, matches, &match) {
536 if (!of_property_read_bool(np, "interrupt-controller") ||
537 !of_device_is_available(np))
538 continue;
539
540 if (WARN(!match->data, "of_irq_init: no init function for %s\n",
541 match->compatible))
542 continue;
543
544 /*
545 * Here, we allocate and populate an of_intc_desc with the node
546 * pointer, interrupt-parent device_node etc.
547 */
548 desc = kzalloc(sizeof(*desc), GFP_KERNEL);
549 if (!desc) {
550 of_node_put(np);
551 goto err;
552 }
553
554 desc->irq_init_cb = match->data;
555 desc->dev = of_node_get(np);
556 /*
557 * interrupts-extended can reference multiple parent domains.
558 * Arbitrarily pick the first one; assume any other parents
559 * are the same distance away from the root irq controller.
560 */
561 desc->interrupt_parent = of_parse_phandle(np, "interrupts-extended", 0);
562 if (!desc->interrupt_parent)
563 desc->interrupt_parent = of_irq_find_parent(np);
564 if (desc->interrupt_parent == np) {
565 of_node_put(desc->interrupt_parent);
566 desc->interrupt_parent = NULL;
567 }
568 list_add_tail(&desc->list, &intc_desc_list);
569 }
570
571 /*
572 * The root irq controller is the one without an interrupt-parent.
573 * That one goes first, followed by the controllers that reference it,
574 * followed by the ones that reference the 2nd level controllers, etc.
575 */
576 while (!list_empty(&intc_desc_list)) {
577 /*
578 * Process all controllers with the current 'parent'.
579 * First pass will be looking for NULL as the parent.
580 * The assumption is that NULL parent means a root controller.
581 */
582 list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
583 int ret;
584
585 if (desc->interrupt_parent != parent)
586 continue;
587
588 list_del(&desc->list);
589
590 of_node_set_flag(desc->dev, OF_POPULATED);
591
592 pr_debug("of_irq_init: init %pOF (%p), parent %p\n",
593 desc->dev,
594 desc->dev, desc->interrupt_parent);
595 ret = desc->irq_init_cb(desc->dev,
596 desc->interrupt_parent);
597 if (ret) {
598 pr_err("%s: Failed to init %pOF (%p), parent %p\n",
599 __func__, desc->dev, desc->dev,
600 desc->interrupt_parent);
601 of_node_clear_flag(desc->dev, OF_POPULATED);
602 kfree(desc);
603 continue;
604 }
605
606 /*
607 * This one is now set up; add it to the parent list so
608 * its children can get processed in a subsequent pass.
609 */
610 list_add_tail(&desc->list, &intc_parent_list);
611 }
612
613 /* Get the next pending parent that might have children */
614 desc = list_first_entry_or_null(&intc_parent_list,
615 typeof(*desc), list);
616 if (!desc) {
617 pr_err("of_irq_init: children remain, but no parents\n");
618 break;
619 }
620 list_del(&desc->list);
621 parent = desc->dev;
622 kfree(desc);
623 }
624
625 list_for_each_entry_safe(desc, temp_desc, &intc_parent_list, list) {
626 list_del(&desc->list);
627 kfree(desc);
628 }
629 err:
630 list_for_each_entry_safe(desc, temp_desc, &intc_desc_list, list) {
631 list_del(&desc->list);
632 of_node_put(desc->dev);
633 kfree(desc);
634 }
635 }
先看下__irqchip_of_table定义:
extern struct of_device_id __irqchip_of_table[];
从System.map文件可以看到:__irqchip_of_table到irqchip_of_table_end之间的of_device_id table
那这个table怎么形成的?这里以当前常用的__of_table_gic_v3为例说明:
在drivers/irqchip/irq-gic-v3.c中,有一个宏定义:IRQCHIP_DECLARE(gic_v3, "arm,gic-v3", gic_of_init);
展开以后就是:
static const struct of_device_id __of_table_gic_v3
__used __section("__irqchip_of_table")
__aligned(__alignof__(struct of_device_id))
= { .compatible = "arm,gic-v3",
.data = gic_of_init
}
现在回到of_irq_init(),该函数分两部分:上半部分和下半部分
2.3.1.1 of_irq_init()上半部分
先扫描DT,找出与compatible对应,且带“interrupt-controller”属性,并且status为okay的节点,并填充struct of_intc_desc结构体,然后将其添加到全局链表intc_desc_list
struct of_intc_desc结构体定义如下:
511 struct of_intc_desc {
512 struct list_head list;
513 of_irq_init_cb_t irq_init_cb;
514 struct device_node *dev;
515 struct device_node *interrupt_parent;
516 };
这里要注意的是irq_init_cb成员,以gic v3为例, irq_init_cb = gic_of_init
2.3.1.2 of_irq_init()下半部分
从全局链表intc_desc_list中,查找最上级的中断控制器,并调用irq_init_cb()对其进行初始化,并将其添加到全局链表intc_parent_list。以gic v3为例,就会调用gic_of_init()
2.3.2 gic_of_init()
2178 static int __init gic_of_init(struct device_node *node, struct device_node *parent)
2179 {
2180 phys_addr_t dist_phys_base;
2181 void __iomem *dist_base;
2182 struct redist_region *rdist_regs;
2183 struct resource res;
2184 u64 redist_stride;
2185 u32 nr_redist_regions;
2186 int err, i;
2187 bool single_redist = false;
2188
2189 dist_base = gic_of_iomap(node, 0, "GICD", &res);
2190 if (IS_ERR(dist_base)) {
2191 pr_err("%pOF: unable to map gic dist registers\n", node);
2192 return PTR_ERR(dist_base);
2193 }
2194
2195 dist_phys_base = res.start;
2196
2197 err = gic_validate_dist_version(dist_base);
2198 if (err) {
2199 pr_err("%pOF: no distributor detected, giving up\n", node);
2200 goto out_unmap_dist;
2201 }
2202
2203 if (of_property_read_u32(node, "#redistributor-regions", &nr_redist_regions))
2204 nr_redist_regions = 1;
2205
2206 rdist_regs = kcalloc(nr_redist_regions, sizeof(*rdist_regs),
2207 GFP_KERNEL);
2208 if (!rdist_regs) {
2209 err = -ENOMEM;
2210 goto out_unmap_dist;
2211 }
2212
2213 if (of_property_read_bool(node, "single-redist"))
2214 single_redist = true;
2215
2216 for (i = 0; i < nr_redist_regions; i++) {
2217 rdist_regs[i].redist_base = gic_of_iomap(node, 1 + i, "GICR", &res);
2218 if (IS_ERR(rdist_regs[i].redist_base)) {
2219 pr_err("%pOF: couldn't map region %d\n", node, i);
2220 err = -ENODEV;
2221 goto out_unmap_rdist;
2222 }
2223 rdist_regs[i].phys_base = res.start;
2224 rdist_regs[i].single_redist = single_redist;
2225 }
2226
2227 if (of_property_read_u64(node, "redistributor-stride", &redist_stride))
2228 redist_stride = 0;
2229
2230 gic_enable_of_quirks(node, gic_quirks, &gic_data);
2231
2232 err = gic_init_bases(dist_phys_base, dist_base, rdist_regs,
2233 nr_redist_regions, redist_stride, &node->fwnode);
2234 if (err)
2235 goto out_unmap_rdist;
2236
2237 gic_populate_ppi_partitions(node);
2238
2239 if (static_branch_likely(&supports_deactivate_key))
2240 gic_of_setup_kvm_info(node);
2241 return 0;
2242
2243 out_unmap_rdist:
2244 for (i = 0; i < nr_redist_regions; i++)
2245 if (rdist_regs[i].redist_base && !IS_ERR(rdist_regs[i].redist_base))
2246 iounmap(rdist_regs[i].redist_base);
2247 kfree(rdist_regs);
2248 out_unmap_dist:
2249 iounmap(dist_base);
2250 return err;
2251 }
这里会对gic v3做一系列init操作:
line 2189---2195 从DTS里获取GICD,并映射到vmalloc区域,将虚拟地址保存到dist_base,对应的物流地址保存到dist_phys_base
line 2197---2201 check gic版本信息
line 2203---2204 读取#redistributor-regions信息,并赋值给nr_redist_regions
line 2206---2225 分配struct redist_region数组,并根据dts信息填充对应的成员
45 struct redist_region {
46 void __iomem *redist_base;
47 phys_addr_t phys_base;
48 bool single_redist;
49 };
紧接着调用gic_init_bases()
2.3.3 gic_init_bases()
1923 static int __init gic_init_bases(phys_addr_t dist_phys_base,
1924 void __iomem *dist_base,
1925 struct redist_region *rdist_regs,
1926 u32 nr_redist_regions,
1927 u64 redist_stride,
1928 struct fwnode_handle *handle)
1929 {
1930 u32 typer;
1931 int err;
1932
1933 if (!is_hyp_mode_available())
1934 static_branch_disable(&supports_deactivate_key);
1935
1936 if (static_branch_likely(&supports_deactivate_key))
1937 pr_info("GIC: Using split EOI/Deactivate mode\n");
1938
1939 gic_data.fwnode = handle;
1940 gic_data.dist_phys_base = dist_phys_base;
1941 gic_data.dist_base = dist_base;
1942 gic_data.redist_regions = rdist_regs;
1943 gic_data.nr_redist_regions = nr_redist_regions;
1944 gic_data.redist_stride = redist_stride;
1945
1946 /*
1947 * Find out how many interrupts are supported.
1948 */
1949 typer = readl_relaxed(gic_data.dist_base + GICD_TYPER);
1950 gic_data.rdists.gicd_typer = typer;
1951
1952 gic_enable_quirks(readl_relaxed(gic_data.dist_base + GICD_IIDR),
1953 gic_quirks, &gic_data);
1954
1955 pr_info("%d SPIs implemented\n", GIC_LINE_NR - 32);
1956 pr_info("%d Extended SPIs implemented\n", GIC_ESPI_NR);
1957
1958 /*
1959 * ThunderX1 explodes on reading GICD_TYPER2, in violation of the
1960 * architecture spec (which says that reserved registers are RES0).
1961 */
1962 if (!(gic_data.flags & FLAGS_WORKAROUND_CAVIUM_ERRATUM_38539))
1963 gic_data.rdists.gicd_typer2 = readl_relaxed(gic_data.dist_base + GICD_TYPER2);
1964
1965 gic_data.domain = irq_domain_create_tree(handle, &gic_irq_domain_ops,
1966 &gic_data);
1967 gic_data.rdists.rdist = alloc_percpu(typeof(*gic_data.rdists.rdist));
1968 if (!static_branch_unlikely(&gic_nvidia_t241_erratum)) {
1969 /* Disable GICv4.x features for the erratum T241-FABRIC-4 */
1970 gic_data.rdists.has_rvpeid = true;
1971 gic_data.rdists.has_vlpis = true;
1972 gic_data.rdists.has_direct_lpi = true;
1973 gic_data.rdists.has_vpend_valid_dirty = true;
1974 }
1975
1976 if (WARN_ON(!gic_data.domain) || WARN_ON(!gic_data.rdists.rdist)) {
1977 err = -ENOMEM;
1978 goto out_free;
1979 }
1980
1981 irq_domain_update_bus_token(gic_data.domain, DOMAIN_BUS_WIRED);
1982
1983 gic_data.has_rss = !!(typer & GICD_TYPER_RSS);
1984
1985 if (typer & GICD_TYPER_MBIS) {
1986 err = mbi_init(handle, gic_data.domain);
1987 if (err)
1988 pr_err("Failed to initialize MBIs\n");
1989 }
1990
1991 set_handle_irq(gic_handle_irq);
1992
1993 gic_update_rdist_properties();
1994
1995 gic_dist_init();
1996 gic_cpu_init();
1997 gic_smp_init();
1998 gic_cpu_pm_init();
1999
2000 if (gic_dist_supports_lpis()) {
2001 its_init(handle, &gic_data.rdists, gic_data.domain);
2002 its_cpu_init();
2003 its_lpi_memreserve_init();
2004 } else {
2005 if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
2006 gicv2m_init(handle, gic_data.domain);
2007 }
2008
2009 gic_enable_nmi_support();
2010
2011 return 0;
2012
2013 out_free:
2014 if (gic_data.domain)
2015 irq_domain_remove(gic_data.domain);
2016 free_percpu(gic_data.rdists.rdist);
2017 return err;
2018 }
gic_data定义如下:
static struct gic_chip_data gic_data[CONFIG_ARM_GIC_MAX_NR] __read_mostly;
从.config可知,默认CONFIG_ARM_GIC_MAX_NR = 1
struct gic_chip_data定义如下:
51 struct gic_chip_data {
52 struct fwnode_handle *fwnode;
53 phys_addr_t dist_phys_base;
54 void __iomem *dist_base;
55 struct redist_region *redist_regions;
56 struct rdists rdists;
57 struct irq_domain *domain;
58 u64 redist_stride;
59 u32 nr_redist_regions;
60 u64 flags;
61 bool has_rss;
62 unsigned int ppi_nr;
63 struct partition_desc **ppi_descs;
64 };
gic_init_bases()前半部填充了gic_data相关成员,紧着着会调用irq_domain_create_tree()
2.3.4 irq_domain_create_tree()
392 static inline struct irq_domain *irq_domain_create_tree(struct fwnode_handle *fwnode,
393 const struct irq_domain_ops *ops,
394 void *host_data)
395 {
396 return __irq_domain_add(fwnode, 0, ~0, 0, ops, host_data);
397 }
直接调用了__irq_domain_add()
235 /**
236 * __irq_domain_add() - Allocate a new irq_domain data structure
237 * @fwnode: firmware node for the interrupt controller
238 * @size: Size of linear map; 0 for radix mapping only
239 * @hwirq_max: Maximum number of interrupts supported by controller
240 * @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no
241 * direct mapping
242 * @ops: domain callbacks
243 * @host_data: Controller private data pointer
244 *
245 * Allocates and initializes an irq_domain structure.
246 * Returns pointer to IRQ domain, or NULL on failure.
247 */
248 struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, unsigned int size,
249 irq_hw_number_t hwirq_max, int direct_max,
250 const struct irq_domain_ops *ops,
251 void *host_data)
252 {
253 struct irq_domain *domain;
254
255 domain = __irq_domain_create(fwnode, size, hwirq_max, direct_max,
256 ops, host_data);
257 if (domain)
258 __irq_domain_publish(domain);
259
260 return domain;
261 }
262 EXPORT_SYMBOL_GPL(__irq_domain_add);
2.3.5 __irq_domain_create()
129 static struct irq_domain *__irq_domain_create(struct fwnode_handle *fwnode,
130 unsigned int size,
131 irq_hw_number_t hwirq_max,
132 int direct_max,
133 const struct irq_domain_ops *ops,
134 void *host_data)
135 {
136 struct irqchip_fwid *fwid;
137 struct irq_domain *domain;
138
139 static atomic_t unknown_domains;
140
141 if (WARN_ON((size && direct_max) ||
142 (!IS_ENABLED(CONFIG_IRQ_DOMAIN_NOMAP) && direct_max) ||
143 (direct_max && (direct_max != hwirq_max))))
144 return NULL;
145
146 domain = kzalloc_node(struct_size(domain, revmap, size),
147 GFP_KERNEL, of_node_to_nid(to_of_node(fwnode)));
148 if (!domain)
149 return NULL;
150
151 if (is_fwnode_irqchip(fwnode)) {
152 fwid = container_of(fwnode, struct irqchip_fwid, fwnode);
153
154 switch (fwid->type) {
155 case IRQCHIP_FWNODE_NAMED:
156 case IRQCHIP_FWNODE_NAMED_ID:
157 domain->fwnode = fwnode;
158 domain->name = kstrdup(fwid->name, GFP_KERNEL);
159 if (!domain->name) {
160 kfree(domain);
161 return NULL;
162 }
163 domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
164 break;
165 default:
166 domain->fwnode = fwnode;
167 domain->name = fwid->name;
168 break;
169 }
170 } else if (is_of_node(fwnode) || is_acpi_device_node(fwnode) ||
171 is_software_node(fwnode)) {
172 char *name;
173
174 /*
175 * fwnode paths contain '/', which debugfs is legitimately
176 * unhappy about. Replace them with ':', which does
177 * the trick and is not as offensive as '\'...
178 */
179 name = kasprintf(GFP_KERNEL, "%pfw", fwnode);
180 if (!name) {
181 kfree(domain);
182 return NULL;
183 }
184
185 strreplace(name, '/', ':');
186
187 domain->name = name;
188 domain->fwnode = fwnode;
189 domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
190 }
191
192 if (!domain->name) {
193 if (fwnode)
194 pr_err("Invalid fwnode type for irqdomain\n");
195 domain->name = kasprintf(GFP_KERNEL, "unknown-%d",
196 atomic_inc_return(&unknown_domains));
197 if (!domain->name) {
198 kfree(domain);
199 return NULL;
200 }
201 domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
202 }
203
204 fwnode_handle_get(fwnode);
205 fwnode_dev_initialized(fwnode, true);
206
207 /* Fill structure */
208 INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL);
209 mutex_init(&domain->revmap_mutex);
210 domain->ops = ops;
211 domain->host_data = host_data;
212 domain->hwirq_max = hwirq_max;
213
214 if (direct_max) {
215 domain->flags |= IRQ_DOMAIN_FLAG_NO_MAP;
216 }
217
218 domain->revmap_size = size;
219
220 irq_domain_check_hierarchy(domain);
221
222 return domain;
223 }
struct irq_domain定义如下:
138 /**
139 * struct irq_domain - Hardware interrupt number translation object
140 * @link: Element in global irq_domain list.
141 * @name: Name of interrupt domain
142 * @ops: pointer to irq_domain methods
143 * @host_data: private data pointer for use by owner. Not touched by irq_domain
144 * core code.
145 * @flags: host per irq_domain flags
146 * @mapcount: The number of mapped interrupts
147 *
148 * Optional elements
149 * @fwnode: Pointer to firmware node associated with the irq_domain. Pretty easy
150 * to swap it for the of_node via the irq_domain_get_of_node accessor
151 * @gc: Pointer to a list of generic chips. There is a helper function for
152 * setting up one or more generic chips for interrupt controllers
153 * drivers using the generic chip library which uses this pointer.
154 * @dev: Pointer to a device that the domain represent, and that will be
155 * used for power management purposes.
156 * @parent: Pointer to parent irq_domain to support hierarchy irq_domains
157 *
158 * Revmap data, used internally by irq_domain
159 * @revmap_size: Size of the linear map table @revmap[]
160 * @revmap_tree: Radix map tree for hwirqs that don't fit in the linear map
161 * @revmap_mutex: Lock for the revmap
162 * @revmap: Linear table of irq_data pointers
163 */
164 struct irq_domain {
165 struct list_head link;
166 const char *name;
167 const struct irq_domain_ops *ops;
168 void *host_data;
169 unsigned int flags;
170 unsigned int mapcount;
171
172 /* Optional data */
173 struct fwnode_handle *fwnode;
174 enum irq_domain_bus_token bus_token;
175 struct irq_domain_chip_generic *gc;
176 struct device *dev;
177 #ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
178 struct irq_domain *parent;
179 #endif
180
181 /* reverse map data. The linear map gets appended to the irq_domain */
182 irq_hw_number_t hwirq_max;
183 unsigned int revmap_size;
184 struct radix_tree_root revmap_tree;
185 struct mutex revmap_mutex;
186 struct irq_data __rcu *revmap[];
187 };
__irq_domain_create() 创建一个struct irq_domain结构体,并填充了这些成员:
187 domain->name = name;
188 domain->fwnode = fwnode; //gic对应的node
189 domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;
208 INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL);
209 mutex_init(&domain->revmap_mutex);
210 domain->ops = &gic_irq_domain_ops;
211 domain->host_data = &gic_data;
212 domain->hwirq_max = ~0;
218 domain->revmap_size = 0;
回到__irq_domain_add(),__irq_domain_create调用完成后,会调用__irq_domain_publish(),将刚创建的struct irq_domain结构体添加到全局链表irq_domain_list中
现在irq_domain_create_tree()执行完成,让我们再次回到gic_init_bases(),
1991 set_handle_irq(gic_handle_irq);
arch/arm64/kernel/irq.c
101 int __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
102 {
103 if (handle_arch_irq != default_handle_irq)
104 return -EBUSY;
105
106 handle_arch_irq = handle_irq;
107 pr_info("Root IRQ handler: %ps\n", handle_irq);
108 return 0;
109 }
这里会将handle_arch_irq设置为gic_handle_irq
待继续。。。。
struct irq_desc结构体定义如下:
include/linux/irqdesc.h
55 struct irq_desc {
56 struct irq_common_data irq_common_data;
57 struct irq_data irq_data;
58 unsigned int __percpu *kstat_irqs;
59 irq_flow_handler_t handle_irq;
60 struct irqaction *action; /* IRQ action list */
61 unsigned int status_use_accessors;
62 unsigned int core_internal_state__do_not_mess_with_it;
63 unsigned int depth; /* nested irq disables */
64 unsigned int wake_depth; /* nested wake enables */
65 unsigned int tot_count;
66 unsigned int irq_count; /* For detecting broken IRQs */
67 unsigned long last_unhandled; /* Aging timer for unhandled count */
68 unsigned int irqs_unhandled;
69 atomic_t threads_handled;
70 int threads_handled_last;
71 raw_spinlock_t lock;
72 struct cpumask *percpu_enabled;
73 const struct cpumask *percpu_affinity;
74 #ifdef CONFIG_SMP
75 const struct cpumask *affinity_hint;
76 struct irq_affinity_notify *affinity_notify;
77 #ifdef CONFIG_GENERIC_PENDING_IRQ
78 cpumask_var_t pending_mask;
79 #endif
80 #endif
81 unsigned long threads_oneshot;
82 atomic_t threads_active;
83 wait_queue_head_t wait_for_threads;
84 #ifdef CONFIG_PM_SLEEP
85 unsigned int nr_actions;
86 unsigned int no_suspend_depth;
87 unsigned int cond_suspend_depth;
88 unsigned int force_resume_depth;
89 #endif
90 #ifdef CONFIG_PROC_FS
91 struct proc_dir_entry *dir;
92 #endif
93 #ifdef CONFIG_GENERIC_IRQ_DEBUGFS
94 struct dentry *debugfs_file;
95 const char *dev_name;
96 #endif
97 #ifdef CONFIG_SPARSE_IRQ
98 struct rcu_head rcu;
99 struct kobject kobj;
100 #endif
101 struct mutex request_mutex;
102 int parent_irq;
103 struct module *owner;
104 const char *name;
105 } ____cacheline_internodealigned_in_smp;