中断-解析串口节点

1. DTS文件

在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

2.代码解析

分析解析这个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                         };         

2.1 irq_of_parse_and_map

函数:
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 }  

2.2 of_irq_parse_one

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 }                                                                                                          

2.3 of_parse_raw

传入参数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 }                                                                                            

2.4 irq_create_of_mapping

 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 }  

2.5 of_phandle_args_to_fwspec

步骤:
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 }   

irq_create_fwspec_mapping

 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 }   

irq_find_matching_fwnode

 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。

2.8 gic_irq_domain_translate

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加入到映射表中。

你可能感兴趣的:(dts)