在vexpress-v2p-ca9.dts中smb节点:
10 /dts-v1/;
11
12 / {
13 model = "V2P-CA9";
14 arm,hbi = <0x191>;
15 arm,vexpress,site = <0xf>;
16 compatible = "arm,vexpress,v2p-ca9", "arm,vexpress";
17 interrupt-parent = <&gic>;
18 #address-cells = <1>;
19 #size-cells = <1>;
20
21 chosen { };
22
23 aliases {
24 serial0 = &v2m_serial0;
25 serial1 = &v2m_serial1;
26 serial2 = &v2m_serial2;
27 serial3 = &v2m_serial3;
28 i2c0 = &v2m_i2c_dvi;
29 i2c1 = &v2m_i2c_pcie;
30 };
....
160 gic: interrupt-controller@1e001000 {
161 compatible = "arm,cortex-a9-gic";
162 #interrupt-cells = <3>;
163 #address-cells = <0>;
164 interrupt-controller;
165 reg = <0x1e001000 0x1000>,
166 <0x1e000100 0x100>;
167 };
....
303 smb {
304 compatible = "simple-bus";
305
306 #address-cells = <2>;
307 #size-cells = <1>;
308 ranges = <0 0 0x40000000 0x04000000>,
309 <1 0 0x44000000 0x04000000>,
310 <2 0 0x48000000 0x04000000>,
311 <3 0 0x4c000000 0x04000000>,
312 <7 0 0x10000000 0x00020000>;
313
314 #interrupt-cells = <1>;
315 interrupt-map-mask = <0 0 63>;
316 interrupt-map = <0 0 0 &gic 0 0 4>,
317 <0 0 1 &gic 0 1 4>,
318 <0 0 2 &gic 0 2 4>,
319 <0 0 3 &gic 0 3 4>,
320 <0 0 4 &gic 0 4 4>,
321 <0 0 5 &gic 0 5 4>,
322 <0 0 6 &gic 0 6 4>,
323 <0 0 7 &gic 0 7 4>,
324 <0 0 8 &gic 0 8 4>,
325 <0 0 9 &gic 0 9 4>,
326 <0 0 10 &gic 0 10 4>,
327 <0 0 11 &gic 0 11 4>,
328 <0 0 12 &gic 0 12 4>,
329 <0 0 13 &gic 0 13 4>,
330 <0 0 14 &gic 0 14 4>,
331 <0 0 15 &gic 0 15 4>,
332 <0 0 16 &gic 0 16 4>,
333 <0 0 17 &gic 0 17 4>,
334 <0 0 18 &gic 0 18 4>,
335 <0 0 19 &gic 0 19 4>,
336 <0 0 20 &gic 0 20 4>,
337 <0 0 21 &gic 0 21 4>,
338 <0 0 22 &gic 0 22 4>,
339 <0 0 23 &gic 0 23 4>,
340 <0 0 24 &gic 0 24 4>,
341 <0 0 25 &gic 0 25 4>,
342 <0 0 26 &gic 0 26 4>,
343 <0 0 27 &gic 0 27 4>,
344 <0 0 28 &gic 0 28 4>,
345 <0 0 29 &gic 0 29 4>,
346 <0 0 30 &gic 0 30 4>,
347 <0 0 31 &gic 0 31 4>,
348 <0 0 32 &gic 0 32 4>,
349 <0 0 33 &gic 0 33 4>,
350 <0 0 34 &gic 0 34 4>,
351 <0 0 35 &gic 0 35 4>,
352 <0 0 36 &gic 0 36 4>,
353 <0 0 37 &gic 0 37 4>,
354 <0 0 38 &gic 0 38 4>,
355 <0 0 39 &gic 0 39 4>,
356 <0 0 40 &gic 0 40 4>,
357 <0 0 41 &gic 0 41 4>,
358 <0 0 42 &gic 0 42 4>;
359
360 /include/ "vexpress-v2m.dtsi"
361 };
362 };
在vexpress-v2m.dtsi中motherboard节点:
20 motherboard {
21 model = "V2M-P1";
22 arm,hbi = <0x190>;
23 arm,vexpress,site = <0>;
24 compatible = "arm,vexpress,v2m-p1", "simple-bus";
25 #address-cells = <2>; /* SMB chipselect number and offset */
26 #size-cells = <1>;
27 #interrupt-cells = <1>;
28 ranges;
29
30 flash@0,00000000 {
31 compatible = "arm,vexpress-flash", "cfi-flash";
32 reg = <0 0x00000000 0x04000000>,
33 <1 0x00000000 0x04000000>;
34 bank-width = <4>;
35 };
..........
67 iofpga@7,00000000 {
68 compatible = "arm,amba-bus", "simple-bus";
69 #address-cells = <1>;
70 #size-cells = <1>;
71 ranges = <0 7 0 0x20000>;
72
73 v2m_sysreg: sysreg@00000 {
74 compatible = "arm,vexpress-sysreg";
75 reg = <0x00000 0x1000>;
76
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 };
...
}
说明: v2m_serial0: uart@09000======>iofpga@7,00000000=========>motherboard========>smb
分析解析这个uart节点。
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 };
函数:
1)dev->full_name=/smb/motherboard/iofpga@7,00000000/uart@0b000中interrupts=<7>,找到对应的irq 0 7 4,然后把值赋给oirq
2)调用irq_create_of_mapping创建映射。
30 /**
31 * irq_of_parse_and_map - Parse and map an interrupt into linux virq space
32 * @dev: Device node of the device whose interrupt is to be mapped
33 * @index: Index of the interrupt to map
34 *
35 * This function is a wrapper that chains of_irq_parse_one() and
36 * irq_create_of_mapping() to make things easier to callers
37 */
38 unsigned int irq_of_parse_and_map(struct device_node *dev, int index)
39 {
40 struct of_phandle_args oirq;
41
// dev->full_name=/smb/motherboard/iofpga@7,00000000/uart@0b000
42 if (of_irq_parse_one(dev, index, &oirq))
43 return 0;
44
// oirq->np->full_name=/interrupt-controller@1e001000 oirq.np->fwnode.type=1
// oirq->args[0]= 0 oirq->args[1]= 7 oirq->args[2]= 4
45 return irq_create_of_mapping(&oirq);
46 }
279 /**
280 * of_irq_parse_one - Resolve an interrupt for a device
281 * @device: the device whose interrupt is to be resolved
282 * @index: index of the interrupt to resolve
283 * @out_irq: structure of_irq filled by this function
284 *
285 * This function resolves an interrupt for a node by walking the interrupt tree,
286 * finding which interrupt controller node it is attached to, and returning the
287 * interrupt specifier that can be used to retrieve a Linux IRQ number.
288 */
289 int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_args *out_irq)
290 {
291 struct device_node *p;
292 const __be32 *intspec, *tmp, *addr;
293 u32 intsize, intlen;
294 int i, res;
295
296 pr_debug("of_irq_parse_one: dev=%s, index=%d\n", of_node_full_name(device), index);
//device->name=uart index=0
297
298 /* OldWorld mac stuff is "special", handle out of line */
299 if (of_irq_workarounds & OF_IMAP_OLDWORLD_MAC)
300 return of_irq_parse_oldworld(device, index, out_irq);
301
302 /* Get the reg property (if any) */
303 addr = of_get_property(device, "reg", NULL);
304
// be32_to_cpup(addr)=0xb000 be32_to_cpup(addr+1)=0x1000
305 /* Try the new-style interrupts-extended first */
306 res = of_parse_phandle_with_args(device, "interrupts-extended",
307 "#interrupt-cells", index, out_irq);
//device->name=uart这个节点没有interrupts-extended这个属性值。
308 if (!res)
309 return of_irq_parse_raw(addr, out_irq);
//这会进入of_irq_parse_raw函数
310
311 /* Get the interrupts property */
312 intspec = of_get_property(device, "interrupts", &intlen);
313 if (intspec == NULL)
314 return -EINVAL;
315
316 intlen /= sizeof(*intspec);
317
318 pr_debug(" intspec=%d intlen=%d\n", be32_to_cpup(intspec), intlen);
319
320 /* Look for the interrupt parent. */
321 p = of_irq_find_parent(device);
322 if (p == NULL)
323 return -EINVAL;
324
325 /* Get size of interrupt specifier */
326 tmp = of_get_property(p, "#interrupt-cells", NULL);
327 if (tmp == NULL) {
328 res = -EINVAL;
329 goto out;
330 }
331 intsize = be32_to_cpu(*tmp);
332
333 pr_debug(" intsize=%d intlen=%d\n", intsize, intlen);
334
335 /* Check index */
336 if ((index + 1) * intsize > intlen) {
337 res = -EINVAL;
338 goto out;
339 }
340
341 /* Copy intspec into irq structure */
342 intspec += index * intsize;
343 out_irq->np = p;
344 out_irq->args_count = intsize;
345 for (i = 0; i < intsize; i++)
346 out_irq->args[i] = be32_to_cpup(intspec++);
347
348 /* Check if there are any interrupt-map translations to process */
349 res = of_irq_parse_raw(addr, out_irq);
350 out:
351 of_node_put(p);
352 return res;
353 }
传入参数addr是,be32_to_cpup(addr)=0x0b000,be32_to_cpup(addr+1)=0x01000
out_irq->np->name=motherborad,out_irq->args[0]=0x7
整个函数的策略:
1)利用传进来的addr和out_irq->args[0]=0x7也就是uart@0xb000这个节点中interrupt属性值
2)然后在他的当前节点,如果当前节点没有,则到父节点的 interrupt-map中的 <0 0 7 &gic 0 7 4>, 找到0xb000这个节点中interrupt属性值7,在interrupt-map数组匹配到对应的 <0 0 7 &gic 0 7 4>这个值(第2个值和7相等),然后把0 7 4赋值给out_irq->args,也就是out_irq->args[0]=0x0 out_irq->args[1]=0x7 out_irq->args[2]=0x4。
3)然后通过intrrupt-map这个节点引用&gic,找到gic标签节点interrupt-controller,这个几点有interrupt-controller这个属性,表明是中断控制器,然后退出这个函数。
82 /**
83 * of_irq_parse_raw - Low level interrupt tree parsing
84 * @parent: the device interrupt parent
85 * @addr: address specifier (start of "reg" property of the device) in be32 format
86 * @out_irq: structure of_irq updated by this function
87 *
88 * Returns 0 on success and a negative number on error
89 *
90 * This function is a low-level interrupt tree walking function. It
91 * can be used to do a partial walk with synthetized reg and interrupts
92 * properties, for example when resolving PCI interrupts when no device
93 * node exist for the parent. It takes an interrupt specifier structure as
94 * input, walks the tree looking for any interrupt-map properties, translates
95 * the specifier for each map, and then returns the translated map.
96 */
97 int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
98 {
99 struct device_node *ipar, *tnode, *old = NULL, *newpar = NULL;
100 __be32 initial_match_array[MAX_PHANDLE_ARGS];
101 const __be32 *match_array = initial_match_array;
102 const __be32 *tmp, *imap, *imask, dummy_imask[] = { [0 ... MAX_PHANDLE_ARGS] = ~0 };
103 u32 intsize = 1, addrsize, newintsize = 0, newaddrsize = 0;
104 int imaplen, match, i;
105
106 #ifdef DEBUG
107 of_print_phandle_args("of_irq_parse_raw: ", out_irq);
108 #endif
109
110 ipar = of_node_get(out_irq->np);
111
112 /* First get the #interrupt-cells property of the current cursor
113 * that tells us how to interpret the passed-in intspec. If there
114 * is none, we are nice and just walk up the tree
115 */
116 do {
//ipar->name=motherboard 这个节点有#interrupt-cells属性值是1,传给intsize,然后跳出循环。
117 tmp = of_get_property(ipar, "#interrupt-cells", NULL);
118 if (tmp != NULL) {
119 intsize = be32_to_cpu(*tmp);
120 break;
121 }
122 tnode = ipar;
123 ipar = of_irq_find_parent(ipar);
124 of_node_put(tnode);
125 } while (ipar);
126 if (ipar == NULL) {
127 pr_debug(" -> no parent found !\n");
128 goto fail;
129 }
130
131 pr_debug("of_irq_parse_raw: ipar=%s, size=%d\n", of_node_full_name(ipar), intsize);
132
133 if (out_irq->args_count != intsize)
134 return -EINVAL;
135
136 /* Look for this #address-cells. We have to implement the old linux
137 * trick of looking for the parent here as some device-trees rely on it
138 */
//ipar->name=motherboard intsize=1
139 old = of_node_get(ipar);
140 do {
141 tmp = of_get_property(old, "#address-cells", NULL);
142 tnode = of_get_parent(old);
143 of_node_put(old);
144 old = tnode;
145 } while (old && tmp == NULL);
146 of_node_put(old);
147 old = NULL;
148 addrsize = (tmp == NULL) ? 2 : be32_to_cpu(*tmp);
//addrsize =2
149
150 pr_debug(" -> addrsize=%d\n", addrsize);
151
152 /* Range check so that the temporary buffer doesn't overflow */
153 if (WARN_ON(addrsize + intsize > MAX_PHANDLE_ARGS))
154 goto fail;
156 /* Precalculate the match array - this simplifies match loop */
157 for (i = 0; i < addrsize; i++)
158 initial_match_array[i] = addr ? addr[i] : 0;
// initial_match_array[0]= 0x0b000 initial_match_array[1]=0x01000
159 for (i = 0; i < intsize; i++)
160 initial_match_array[addrsize + i] = cpu_to_be32(out_irq->args[i]);
// initial_match_array[2]= 0x07
161
162 /* Now start the actual "proper" walk of the interrupt tree */
163 while (ipar != NULL) {
164 /* Now check if cursor is an interrupt-controller and if it is
165 * then we are done
166 */
//第一次执行到这里,ipar=motherboard
//第二次执行到这里,ipar=smb
//第三次 ipar>name=interrupt-controller 有 interrupt-controller这个属性则返回0.
167 if (of_get_property(ipar, "interrupt-controller", NULL) !=
168 NULL) {
169 pr_debug(" -> got it !\n");
170 return 0;
171 }
172
173 /*
174 * interrupt-map parsing does not work without a reg
175 * property when #address-cells != 0
176 */
177 if (addrsize && !addr) {
178 pr_debug(" -> no reg passed in when needed !\n");
179 goto fail;
180 }
181
182 /* Now look for an interrupt-map */
183 imap = of_get_property(ipar, "interrupt-map", &imaplen);
184 /* No interrupt map, check for an interrupt parent */
//第一次,ipar->name=mother没有nterrupt-map这个属性
//第二次,ipar->name=smb, interrupt-map = <0 0 0 &gic 0 0 4>, gic引用的值是1
// 则be32_to_cpup(imap)=0 be32_to_cpup(imap+1)=0 be32_to_cpup(imap+2)=1
// 则be32_to_cpup(imap)=0 be32_to_cpup(imap+1)=0 be32_to_cpup(imap+2)=4
185 if (imap == NULL) {
186 pr_debug(" -> no map, getting parent\n");
187 newpar = of_irq_find_parent(ipar);
newar->name=smb
188 goto skiplevel;
//跳转到skiplevel,代码263行处。
189 }
190 imaplen /= sizeof(u32);
191
192 /* Look for a mask */
193 imask = of_get_property(ipar, "interrupt-map-mask", NULL);
//第二次,ipar->name=smb, interrupt-map-mask = <0 0 63>
//则be32_to_cpup(imask)=0 be32_to_cpup(imask+1)=0 be32_to_cpup(imask+2)=63
194 if (!imask)
195 imask = dummy_imask;
196
197 /* Parse interrupt-map */
198 match = 0;
//当match=1时候
199 while (imaplen > (addrsize + intsize + 1) && !match) {
200 /* Compare specifiers */
201 match = 1;
202 for (i = 0; i < (addrsize + intsize); i++, imaplen--)
203 match &= !((match_array[i] ^ *imap++) & imask[i]);
//imap就是interrupt-map中的值
// 显然imask[0]=0 imask[1]=0 ,与上imask[i]后显然为0,则match=1;显然match_array[0]=addr和match_array[1]=addr+1和imap[0]=0 imap[1]=0,没起作用。
//imap[2]的值分别是0,1,2,3,4,....,这边的match_array[2]=7,显然循环到imap[2]=7时候,下一次就退出来了。
204
205 pr_debug(" -> match=%d (imaplen=%d)\n", match, imaplen);
206
207 /* Get the interrupt parent */
208 if (of_irq_workarounds & OF_IMAP_NO_PHANDLE)
209 newpar = of_node_get(of_irq_dflt_pic);
210 else
211 newpar = of_find_node_by_phandle(be32_to_cpup(imap));
//因为imap[3]=&gic=1,然后通过这个phandle找到newpar->name=interrupt-controller
212 imap++;
213 --imaplen;
214
215 /* Check if not found */
216 if (newpar == NULL) {
217 pr_debug(" -> imap parent not found !\n");
218 goto fail;
219 }
220
221 if (!of_device_is_available(newpar))
222 match = 0;
223
224 /* Get #interrupt-cells and #address-cells of new
225 * parent
226 */
227 tmp = of_get_property(newpar, "#interrupt-cells", NULL);
228 if (tmp == NULL) {
229 pr_debug(" -> parent lacks #interrupt-cells!\n");
230 goto fail;
231 }
232 newintsize = be32_to_cpu(*tmp);
233 tmp = of_get_property(newpar, "#address-cells", NULL);
234 newaddrsize = (tmp == NULL) ? 0 : be32_to_cpu(*tmp);
235
236 pr_debug(" -> newintsize=%d, newaddrsize=%d\n",
237 newintsize, newaddrsize);
238
239 /* Check for malformed properties */
240 if (WARN_ON(newaddrsize + newintsize > MAX_PHANDLE_ARGS))
241 goto fail;
242 if (imaplen < (newaddrsize + newintsize))
243 goto fail;
244 //newpar->name=interrupt-controller newaddrsize=3 newintsize=0
245 imap += newaddrsize + newintsize;
246 imaplen -= newaddrsize + newintsize;
247
248 pr_debug(" -> imaplen=%d\n", imaplen);
249 }
250 if (!match)
251 goto fail;
252
253 /*
254 * Successfully parsed an interrrupt-map translation; copy new
255 * interrupt specifier into the out_irq structure
256 */
//当match=1时候,执行到这边
257 match_array = imap - newaddrsize - newintsize;
258 for (i = 0; i < newintsize; i++)
259 out_irq->args[i] = be32_to_cpup(imap - newintsize + i);
// <0 0 7 &gic 0 7 4>, 显然out_irq_args[0]=0 out_irq_args[1]=0 out_irq_args[2]=7
260 out_irq->args_count = intsize = newintsize;
261 addrsize = newaddrsize;
262
263 skiplevel:
264 /* Iterate again with new parent */
265 out_irq->np = newpar;
//第一次是out_irq->np->name=smb
//第二次 out_irq->np->name=interrupt-controller
266 pr_debug(" -> new parent: %s\n", of_node_full_name(newpar));
267 of_node_put(ipar);
268 ipar = newpar;
//第一次是ipar>name=smb
//第二次 ipar->name=interrupt-controller
269 newpar = NULL;
//跳转到代码163行重新执行。
270 }
271 fail:
272 of_node_put(ipar);
273 of_node_put(newpar);
274
275 return -EINVAL;
276 }
617 unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data)
618 {
619 struct irq_fwspec fwspec;
620
621 of_phandle_args_to_fwspec(irq_data, &fwspec);
622 return irq_create_fwspec_mapping(&fwspec);
623 }
步骤:
1)fwspec->fwnode=&irq_data->np->fwnode (irq_data->np->fwnode=1)
2) fwspec->param_count=3 fwspec->param[0]=0 fwspec->param[1]=7 fwspec->param[2]=4
557 static void of_phandle_args_to_fwspec(struct of_phandle_args *irq_data,
558 struct irq_fwspec *fwspec)
559 {
560 int i;
561
562 fwspec->fwnode = irq_data->np ? &irq_data->np->fwnode : NULL;
563 fwspec->param_count = irq_data->args_count;
564
565 for (i = 0; i < irq_data->args_count; i++)
566 fwspec->param[i] = irq_data->args[i];
567 }
569 unsigned int irq_create_fwspec_mapping(struct irq_fwspec *fwspec)
570 {
571 struct irq_domain *domain;
572 irq_hw_number_t hwirq;
573 unsigned int type = IRQ_TYPE_NONE;
574 int virq;
575
576 if (fwspec->fwnode)
577 domain = irq_find_matching_fwnode(fwspec->fwnode, DOMAIN_BUS_ANY);
578 else
579 domain = irq_default_domain;
580
//找到对应的irq_domain
581 if (!domain) {
582 pr_warn("no irq domain found for %s !\n",
583 of_node_full_name(to_of_node(fwspec->fwnode)));
584 return 0;
585 }
586
587 if (irq_domain_translate(domain, fwspec, &hwirq, &type))
588 return 0;
589
590 if (irq_domain_is_hierarchy(domain)) {
591 /*
592 * If we've already configured this interrupt,
593 * don't do it again, or hell will break loose.
594 */
595 virq = irq_find_mapping(domain, hwirq);
596 if (virq)
597 return virq;
598
599 virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, fwspec);
600 if (virq <= 0)
601 return 0;
602 } else {
603 /* Create mapping */
604 virq = irq_create_mapping(domain, hwirq);
605 if (!virq)
606 return virq;
607 }
608
609 /* Set type if specified and different than the current one */
610 if (type != IRQ_TYPE_NONE &&
611 type != irq_get_trigger_type(virq))
612 irq_set_irq_type(virq, type);
613 return virq;
614 }
245 /**
246 * irq_find_matching_fwnode() - Locates a domain for a given fwnode
247 * @fwnode: FW descriptor of the interrupt controller
248 * @bus_token: domain-specific data
249 */
250 struct irq_domain *irq_find_matching_fwnode(struct fwnode_handle *fwnode,
251 enum irq_domain_bus_token bus_token)
252 {
253 struct irq_domain *h, *found = NULL;
254 int rc;
255
256 /* We might want to match the legacy controller last since
257 * it might potentially be set to match all interrupts in
258 * the absence of a device node. This isn't a problem so far
259 * yet though...
260 *
261 * bus_token == DOMAIN_BUS_ANY matches any domain, any other
262 * values must generate an exact match for the domain to be
263 * selected.
264 */
265 mutex_lock(&irq_domain_mutex);
//to_of_node(fwnode)->full_name=/interrupt-controller@1e001000
266 list_for_each_entry(h, &irq_domain_list, link) {
//在添加irq domain时候,match函数为NULL
267 if (h->ops->match)
268 rc = h->ops->match(h, to_of_node(fwnode), bus_token);
269 else
270 rc = ((fwnode != NULL) && (h->fwnode == fwnode) &&
271 ((bus_token == DOMAIN_BUS_ANY) ||
272 (h->bus_token == bus_token)));
// 进入这个分支后,在所有节点中,比较是不是/interrupt-controller@1e001000
273
274 if (rc) {
275 found = h;
276 break;
277 }
278 }
279 mutex_unlock(&irq_domain_mutex);
280 return found;
281 }
说明,在通过fwnode_handle找到device_node方法,因为device_node结构中有fwnode_handle成员,然后container_of找到device_node。
fwspec->param[0]=0 :代表中断类型 0—SPI
fwspec->param[1]=7: 中断hwirq
fwspec->param[1]=4: 中断触发类型
960 static int gic_irq_domain_translate(struct irq_domain *d,
961 struct irq_fwspec *fwspec,
962 unsigned long *hwirq,
963 unsigned int *type)
964 {
965 if (is_of_node(fwspec->fwnode)) {
966 if (fwspec->param_count < 3)
967 return -EINVAL;
968
969 /* Get the interrupt number and add 16 to skip over SGIs */
970 *hwirq = fwspec->param[1] + 16;
// 首先跳过SGI,因为0-16是SGI
971
972 /*
973 * For SPIs, we need to add 16 more to get the GIC irq
974 * ID number
975 */
976 if (!fwspec->param[0])
977 *hwirq += 16;
978
// fwspec->parma[0]=0 fwspec->parma[1]=7 fwspec->parma[2]=4
//如果 fwspec->parma[0]=0 则是SPIs,还需要跳过PPI,*hwirq=0x7+0x10+0x10=0x27
//也就是dts配置的7这个序号,是SPI中第7个中断。
979 *type = fwspec->param[2] & IRQ_TYPE_SENSE_MASK;
//*type=
980 return 0;
981 }
982
983 if (fwspec->fwnode->type == FWNODE_IRQCHIP) {
984 if(fwspec->param_count != 2)
985 return -EINVAL;
986
987 *hwirq = fwspec->param[0];
988 *type = fwspec->param[1];
989 return 0;
990 }
991
992 return -EINVAL;
993 }
总结:
1)根据dts中配置的uart@0b000中的interrupt=<7>,通过父节点的smb中的interrupt-map属性值,得到: 0 7 4三个值和中断的引用&gic是1,也就是名字是GIC的irq domain
2) 0代表SPI类型中断,通过调用GIC的irq domain中的gic_irq_domain_translate,7(是SPI中的序号),在gic_irq_domain_translate转换成:0x07+0x10+0x10=0x27
3) 4会触发类型,在后续函数中会使用。
4)在下一节中,会讲为0x27的hwirq分配virq,这个virq分配desc,并加入到radix树中,并且把hwirq和virq加入到映射表中。