当前位置: 首页 > news >正文

一文带你了解linux内核IRQ子系统init过程

一、引言:

        前几天有人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;534535         init_irq_default_affinity();536537         /* 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);541542         if (WARN_ON(nr_irqs > IRQ_BITMAP_BITS))543                 nr_irqs = IRQ_BITMAP_BITS;544545         if (WARN_ON(initcnt > IRQ_BITMAP_BITS))546                 initcnt = IRQ_BITMAP_BITS;547548         if (initcnt > nr_irqs)549                 nr_irqs = initcnt;550551         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;5758         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 structure237  * @fwnode: firmware node for the interrupt controller238  * @size: Size of linear map; 0 for radix mapping only239  * @hwirq_max: Maximum number of interrupts supported by controller240  * @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no241  *              direct mapping242  * @ops: domain callbacks243  * @host_data: Controller private data pointer244  *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;254255         domain = __irq_domain_create(fwnode, size, hwirq_max, direct_max,256                                      ops, host_data);257         if (domain)258                 __irq_domain_publish(domain);259260         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;138139         static atomic_t unknown_domains;140141         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;145146         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;150151         if (is_fwnode_irqchip(fwnode)) {152                 fwid = container_of(fwnode, struct irqchip_fwid, fwnode);153154                 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;173174                 /*175                  * fwnode paths contain '/', which debugfs is legitimately176                  * unhappy about. Replace them with ':', which does177                  * 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                 }184185                 strreplace(name, '/', ':');186187                 domain->name = name;188                 domain->fwnode = fwnode;189                 domain->flags |= IRQ_DOMAIN_NAME_ALLOCATED;190         }191192         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         }203204         fwnode_handle_get(fwnode);205         fwnode_dev_initialized(fwnode, true);206207         /* 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;213214         if (direct_max) {215                 domain->flags |= IRQ_DOMAIN_FLAG_NO_MAP;216         }217218         domain->revmap_size = size;219220         irq_domain_check_hierarchy(domain);221222         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对应的node189         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_SMP75         const struct cpumask    *affinity_hint;76         struct irq_affinity_notify *affinity_notify;77 #ifdef CONFIG_GENERIC_PENDING_IRQ78         cpumask_var_t           pending_mask;79 #endif80 #endif81         unsigned long           threads_oneshot;82         atomic_t                threads_active;83         wait_queue_head_t       wait_for_threads;84 #ifdef CONFIG_PM_SLEEP85         unsigned int            nr_actions;86         unsigned int            no_suspend_depth;87         unsigned int            cond_suspend_depth;88         unsigned int            force_resume_depth;89 #endif90 #ifdef CONFIG_PROC_FS91         struct proc_dir_entry   *dir;92 #endif93 #ifdef CONFIG_GENERIC_IRQ_DEBUGFS94         struct dentry           *debugfs_file;95         const char              *dev_name;96 #endif97 #ifdef CONFIG_SPARSE_IRQ98         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;

3、softirq_init() 


http://www.mrgr.cn/news/44720.html

相关文章:

  • 【Iceberg分析】Spark与Iceberg集成落地实践(一)
  • springboot aop判定用户ip访问次数受限了该如何通知用户
  • C#-委托delegate
  • SafeEar:AI 音频伪造检测的崭新时代
  • 日本数据保护要求
  • 【IC】基于systemverilog(UVM)断言
  • YoloV10改进策略:BackBone改进|CAFormer在YoloV10中的创新应用,显著提升目标检测性能
  • 【含文档】基于Springboot+Android的个人财务系统的设计与实现(含源码+数据库+lw)
  • 家庭用超声波清洗机好用吗?推荐四款性能绝佳的超声波清洗机!
  • shell脚本中for循环的用法
  • 多模态大模型调研BLIP、BLIP2、InstructBLIP
  • java数据类型转换和注释
  • Nginx的正向与反向代理
  • 音视频开发之旅(88) - 视频画质评测算法之Dover
  • VADv2 论文学习
  • C(十五)函数综合(一)--- 开公司吗?
  • 第三届图像处理、计算机视觉与机器学习国际学术会议(ICICML 2024)
  • 分治算法(2)_快速排序_排序数组
  • 不同jdk版本间的替换
  • 原神5.1前瞻网页HTML+CSS+JS