一文带你了解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;
 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;

3、softirq_init() 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值