1. __gic_init_bases
1043 static void __init __gic_init_bases(unsigned int gic_nr, int irq_start,
1044 void __iomem *dist_base, void __iomem *cpu_base,
1045 u32 percpu_offset, struct fwnode_handle *handle)
1046 {
1047 irq_hw_number_t hwirq_base;
1048 struct gic_chip_data *gic;
1049 int gic_irqs, irq_base, i;
1050
1051 BUG_ON(gic_nr >= MAX_GIC_NR);
1052
1053 gic_check_cpu_features();
1054
1055 gic = &gic_data[gic_nr];
1056 #ifdef CONFIG_GIC_NON_BANKED
1057 if (percpu_offset) { /* Frankein-GIC without banked registers... */
1058 unsigned int cpu;
1059
1060 gic->dist_base.percpu_base = alloc_percpu(void __iomem *);
1061 gic->cpu_base.percpu_base = alloc_percpu(void __iomem *);
1062 if (WARN_ON(!gic->dist_base.percpu_base ||
1063 !gic->cpu_base.percpu_base)) {
1064 free_percpu(gic->dist_base.percpu_base);
1065 free_percpu(gic->cpu_base.percpu_base);
1066 return;
1067 }
1068
1069 for_each_possible_cpu(cpu) {
1070 u32 mpidr = cpu_logical_map(cpu);
1071 u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
1072 unsigned long offset = percpu_offset * core_id;
1073 *per_cpu_ptr(gic->dist_base.percpu_base, cpu) = dist_base + offset;
1074 *per_cpu_ptr(gic->cpu_base.percpu_base, cpu) = cpu_base + offset;
1075 }
1076
1077 gic_set_base_accessor(gic, gic_get_percpu_base);
1078 } else
1079 #endif
1080 { /* Normal, sane GIC... */
1081 WARN(percpu_offset,
1082 "GIC_NON_BANKED not enabled, ignoring x offset!",
1083 percpu_offset);
1084 gic->dist_base.common_base = dist_base;
1085 gic->cpu_base.common_base = cpu_base;
1086 gic_set_base_accessor(gic, gic_get_common_base);
1087 }
1088
1089 /*
1090 * Find out how many interrupts are supported.
1091 * The GIC only supports up to 1020 interrupt sources.
1092 */
1093 gic_irqs = readl_relaxed(gic_data_dist_base(gic) + GIC_DIST_CTR) & 0x1f;
1094 gic_irqs = (gic_irqs + 1) * 32;
1095 printk("tom gic_irqs=%x\n",gic_irqs);
1096 if (gic_irqs > 1020)
1097 gic_irqs = 1020;
1098 gic->gic_irqs = gic_irqs;
1099
1100 if (handle) { /* DT/ACPI */
1101 printk(KERN_ERR "tom before irq_domain_create_linear\n");
1102 gic->domain = irq_domain_create_linear(handle, gic_irqs,
1103 &gic_irq_domain_hierarchy_ops,
1104 gic);
1105 } else { /* Legacy support */
1106 /*
1107 * For primary GICs, skip over SGIs.
1108 * For secondary GICs, skip over PPIs, too.
1109 */
1110 if (gic_nr == 0 && (irq_start & 31) > 0) {
1111 hwirq_base = 16;
1112 if (irq_start != -1)
1113 irq_start = (irq_start & ~31) + 16;
1114 } else {
1115 hwirq_base = 32;
1116 }
1117
1118 gic_irqs -= hwirq_base; /* calculate # of irqs to allocate */
1119
1120 irq_base = irq_alloc_descs(irq_start, 16, gic_irqs,
1121 numa_node_id());
1122 if (IS_ERR_VALUE(irq_base)) {
1123 WARN(1, "Cannot allocate irq_descs @ IRQ%d, assuming pre-allocated\n",
1124 irq_start);
1125 irq_base = irq_start;
1126 }
1128 gic->domain = irq_domain_add_legacy(NULL, gic_irqs, irq_base,
1129 hwirq_base, &gic_irq_domain_ops, gic);
1130 }
1131
1132 if (WARN_ON(!gic->domain))
1133 return;
1134
1135 if (gic_nr == 0) {
1136 /*
1137 * Initialize the CPU interface map to all CPUs.
1138 * It will be refined as each CPU probes its ID.
1139 * This is only necessary for the primary GIC.
1140 */
1141 for (i = 0; i < NR_GIC_CPU_IF; i++)
1142 gic_cpu_map[i] = 0xff;
1143 #ifdef CONFIG_SMP
1144 set_smp_cross_call(gic_raise_softirq);
1145 register_cpu_notifier(&gic_cpu_notifier);
1146 #endif
1147 set_handle_irq(gic_handle_irq);
1148 if (static_key_true(&supports_deactivate))
1149 pr_info("GIC: Using split EOI/Deactivate mode\n");
1150 }
1151
1152 gic_dist_init(gic);
1153 gic_cpu_init(gic);
1154 gic_pm_init(gic);
1155 }
函数流程:
把中断控制器和CPU的地址给gic在1102行中,调用函数 gic->domain = irq_domain_create_linear(handle, gic_irqs, &gic_irq_domain_hierarchy_ops, gic); 参数: gic_irqs= 0x60 handle- >type=FWNODE_OF=1 handle->secondary=NULL 后续可以通过to_of_node找到这个node节点,通过 irq_domain_create_linear创建一个domain。
2. 初始化gic的dist
135 #define gic_data_dist_base(d) ((d)->dist_base.common_base)
136 #define gic_data_cpu_base(d) ((d)->cpu_base.common_base)
72 static void __init gic_dist_init(struct gic_chip_data *gic)
473 {
474 unsigned int i;
475 u32 cpumask;
476 unsigned int gic_irqs = gic->gic_irqs;
477 void __iomem *base = gic_data_dist_base(gic);
478
479 writel_relaxed(GICD_DISABLE, base + GIC_DIST_CTRL);
480
481 /*
482 * Set all global interrupts to this CPU only.
483 */
484 cpumask = gic_get_cpumask(gic);
485 cpumask |= cpumask << 8;
486 cpumask |= cpumask << 16;
487 for (i = 32; i < gic_irqs; i += 4)
488 writel_relaxed(cpumask, base + GIC_DIST_TARGET + i * 4 / 4);
489
490 gic_dist_config(base, gic_irqs, NULL);
491
492 writel_relaxed(GICD_ENABLE, base + GIC_DIST_CTRL);
493 }
说明: 1)在477行得到的是dts gic的reg的第1个地址的虚拟地址
下面是创建是domain,并且加入链表irq_domain_list中。
3. irq_domain_create_linear
261 static inline struct irq_domain *irq_domain_create_linear(struct fwnode_handle *fwnode,
262 unsigned int size,
263 const struct irq_domain_ops *ops,
264 void *host_data)
265 {
266 return __irq_domain_add(fwnode, size, size, 0, ops, host_data);
267 }
参数: fwnode:就是gic node的handle size: 就是gic支持irq数量 ops: irq_domain_ops操作 host_data: 就是gic的数据,
例如: gic->dist_base.common_base(gic的dist address) gic->cpu_base.common_base (gic的 cpu register)
4. __irq_domain_add
函数的作用: 1)分配一个irq_domain数据结构 2)初始化这个domain的数据, ops(函数操作), host_data, 3) list_add(&domain->link, &irq_domain_list)把这个domain加入到irq_domain_list链表。
of_node:就是对应着interrupt controller内容,是通过to_of_node从fwnode得到of_node。
94 struct irq_domain *__irq_domain_add(struct fwnode_handle *fwnode, int size,
95 irq_hw_number_t hwirq_max, int direct_max,
96 const struct irq_domain_ops *ops,
97 void *host_data)
98 {
99 struct irq_domain *domain;
100 struct device_node *of_node;
101
102 of_node = to_of_node(fwnode);
103
104 domain = kzalloc_node(sizeof(*domain) + (sizeof(unsigned int) * size),
105 GFP_KERNEL, of_node_to_nid(of_node));
106 if (WARN_ON(!domain))
107 return NULL;
108
109 of_node_get(of_node);
110
111 /* Fill structure */
112 INIT_RADIX_TREE(&domain->revmap_tree, GFP_KERNEL);
113 domain->ops = ops;
114 domain->host_data = host_data;
115 domain->fwnode = fwnode;
116 domain->hwirq_max = hwirq_max;
117 domain->revmap_size = size;
118 domain->revmap_direct_max_irq = direct_max;
119 irq_domain_check_hierarchy(domain);
120
121 mutex_lock(&irq_domain_mutex);
122 list_add(&domain->link, &irq_domain_list);
123 mutex_unlock(&irq_domain_mutex);
124
125 pr_debug("Added domain %s\n", domain->name);
126 return domain;
127 }
5. 解析dts中中断,并更新索引。
现在从uart例子分析,dts的配置如下
157 v2m_serial0: uart@09000 {
158 compatible = "arm,pl011", "arm,primecell";
159 reg = <0x09000 0x1000>;
160 interrupts = <5>;
161 clocks = <&v2m_oscclk2>, <&smbclk>;
162 clock-names = "uartclk", "apb_pclk";
163 };
164
165 v2m_serial1: uart@0a000 {
166 compatible = "arm,pl011", "arm,primecell";
167 reg = <0x0a000 0x1000>;
168 interrupts = <6>;
169 clocks = <&v2m_oscclk2>, <&smbclk>;
170 clock-names = "uartclk", "apb_pclk";
171 };
172
173 v2m_serial2: uart@0b000 {
174 compatible = "arm,pl011", "arm,primecell";
175 reg = <0x0b000 0x1000>;
176 interrupts = <7>;
177 clocks = <&v2m_oscclk2>, <&smbclk>;
178 clock-names = "uartclk", "apb_pclk";
179 };
180
181 v2m_serial3: uart@0c000 {
182 compatible = "arm,pl011", "arm,primecell";
183 reg = <0x0c000 0x1000>;
184 interrupts = <8>;
185 clocks = <&v2m_oscclk2>, <&smbclk>;
186 clock-names = "uartclk", "apb_pclk";
187 };
调用流程: of_platform_bus_create----->of_platform_device_create_pdata—>irq_of_parse_and_map
5.1 irq_of_parse_and_map
38 unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
39 {
40 struct of_phandle_args oirq;
41 printk(KERN_ERR "tom irq_of_parse_and_map name=%s",dev->name);
42
43 if (of_irq_parse_one(dev, index, &oirq))
44 return 0;
45
46 return irq_create_of_mapping(&oirq);
47 }