@@ -80,31 +80,32 @@ struct device_node *of_irq_find_parent(struct device_node *child)
8080/**
8181 * of_irq_parse_raw - Low level interrupt tree parsing
8282 * @parent: the device interrupt parent
83- * @intspec: interrupt specifier ("interrupts" property of the device)
84- * @ointsize: size of the passed in interrupt specifier
85- * @addr: address specifier (start of "reg" property of the device)
86- * @out_irq: structure of_irq filled by this function
83+ * @addr: address specifier (start of "reg" property of the device) in be32 format
84+ * @out_irq: structure of_irq updated by this function
8785 *
8886 * Returns 0 on success and a negative number on error
8987 *
9088 * This function is a low-level interrupt tree walking function. It
9189 * can be used to do a partial walk with synthetized reg and interrupts
9290 * properties, for example when resolving PCI interrupts when no device
93- * node exist for the parent.
91+ * node exist for the parent. It takes an interrupt specifier structure as
92+ * input, walks the tree looking for any interrupt-map properties, translates
93+ * the specifier for each map, and then returns the translated map.
9494 */
95- int of_irq_parse_raw (struct device_node * parent , const __be32 * intspec ,
96- u32 ointsize , const __be32 * addr , struct of_phandle_args * out_irq )
95+ int of_irq_parse_raw (const __be32 * addr , struct of_phandle_args * out_irq )
9796{
9897 struct device_node * ipar , * tnode , * old = NULL , * newpar = NULL ;
99- const __be32 * tmp , * imap , * imask ;
98+ __be32 initial_match_array [8 ];
99+ const __be32 * match_array = initial_match_array ;
100+ const __be32 * tmp , * imap , * imask , dummy_imask [] = { ~0 , ~0 , ~0 , ~0 , ~0 };
100101 u32 intsize = 1 , addrsize , newintsize = 0 , newaddrsize = 0 ;
101102 int imaplen , match , i ;
102103
103104 pr_debug ("of_irq_parse_raw: par=%s,intspec=[0x%08x 0x%08x...],ointsize=%d\n" ,
104- of_node_full_name (parent ), be32_to_cpup ( intspec ) ,
105- be32_to_cpup ( intspec + 1 ), ointsize );
105+ of_node_full_name (out_irq -> np ), out_irq -> args [ 0 ], out_irq -> args [ 1 ] ,
106+ out_irq -> args_count );
106107
107- ipar = of_node_get (parent );
108+ ipar = of_node_get (out_irq -> np );
108109
109110 /* First get the #interrupt-cells property of the current cursor
110111 * that tells us how to interpret the passed-in intspec. If there
@@ -127,7 +128,7 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
127128
128129 pr_debug ("of_irq_parse_raw: ipar=%s, size=%d\n" , of_node_full_name (ipar ), intsize );
129130
130- if (ointsize != intsize )
131+ if (out_irq -> args_count != intsize )
131132 return - EINVAL ;
132133
133134 /* Look for this #address-cells. We have to implement the old linux
@@ -146,6 +147,21 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
146147
147148 pr_debug (" -> addrsize=%d\n" , addrsize );
148149
150+ /* If we were passed no "reg" property and we attempt to parse
151+ * an interrupt-map, then #address-cells must be 0.
152+ * Fail if it's not.
153+ */
154+ if (addr == NULL && addrsize != 0 ) {
155+ pr_debug (" -> no reg passed in when needed !\n" );
156+ return - EINVAL ;
157+ }
158+
159+ /* Precalculate the match array - this simplifies match loop */
160+ for (i = 0 ; i < addrsize ; i ++ )
161+ initial_match_array [i ] = addr [i ];
162+ for (i = 0 ; i < intsize ; i ++ )
163+ initial_match_array [addrsize + i ] = cpu_to_be32 (out_irq -> args [i ]);
164+
149165 /* Now start the actual "proper" walk of the interrupt tree */
150166 while (ipar != NULL ) {
151167 /* Now check if cursor is an interrupt-controller and if it is
@@ -154,11 +170,6 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
154170 if (of_get_property (ipar , "interrupt-controller" , NULL ) !=
155171 NULL ) {
156172 pr_debug (" -> got it !\n" );
157- for (i = 0 ; i < intsize ; i ++ )
158- out_irq -> args [i ] =
159- of_read_number (intspec + i , 1 );
160- out_irq -> args_count = intsize ;
161- out_irq -> np = ipar ;
162173 of_node_put (old );
163174 return 0 ;
164175 }
@@ -175,34 +186,16 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
175186
176187 /* Look for a mask */
177188 imask = of_get_property (ipar , "interrupt-map-mask" , NULL );
178-
179- /* If we were passed no "reg" property and we attempt to parse
180- * an interrupt-map, then #address-cells must be 0.
181- * Fail if it's not.
182- */
183- if (addr == NULL && addrsize != 0 ) {
184- pr_debug (" -> no reg passed in when needed !\n" );
185- goto fail ;
186- }
189+ if (!imask )
190+ imask = dummy_imask ;
187191
188192 /* Parse interrupt-map */
189193 match = 0 ;
190194 while (imaplen > (addrsize + intsize + 1 ) && !match ) {
191195 /* Compare specifiers */
192196 match = 1 ;
193- for (i = 0 ; i < addrsize && match ; ++ i ) {
194- __be32 mask = imask ? imask [i ]
195- : cpu_to_be32 (0xffffffffu );
196- match = ((addr [i ] ^ imap [i ]) & mask ) == 0 ;
197- }
198- for (; i < (addrsize + intsize ) && match ; ++ i ) {
199- __be32 mask = imask ? imask [i ]
200- : cpu_to_be32 (0xffffffffu );
201- match =
202- ((intspec [i - addrsize ] ^ imap [i ]) & mask ) == 0 ;
203- }
204- imap += addrsize + intsize ;
205- imaplen -= addrsize + intsize ;
197+ for (i = 0 ; i < (addrsize + intsize ); i ++ , imaplen -- )
198+ match = !((match_array [i ] ^ * imap ++ ) & imask [i ]);
206199
207200 pr_debug (" -> match=%d (imaplen=%d)\n" , match , imaplen );
208201
@@ -247,12 +240,18 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
247240 if (!match )
248241 goto fail ;
249242
250- of_node_put (old );
251- old = of_node_get (newpar );
243+ /*
244+ * Successfully parsed an interrrupt-map translation; copy new
245+ * interrupt specifier into the out_irq structure
246+ */
247+ of_node_put (out_irq -> np );
248+ out_irq -> np = of_node_get (newpar );
249+
250+ match_array = imap - newaddrsize - newintsize ;
251+ for (i = 0 ; i < newintsize ; i ++ )
252+ out_irq -> args [i ] = be32_to_cpup (imap - newintsize + i );
253+ out_irq -> args_count = intsize = newintsize ;
252254 addrsize = newaddrsize ;
253- intsize = newintsize ;
254- intspec = imap - intsize ;
255- addr = intspec - addrsize ;
256255
257256 skiplevel :
258257 /* Iterate again with new parent */
@@ -263,7 +262,7 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
263262 }
264263 fail :
265264 of_node_put (ipar );
266- of_node_put (old );
265+ of_node_put (out_irq -> np );
267266 of_node_put (newpar );
268267
269268 return - EINVAL ;
@@ -276,15 +275,16 @@ EXPORT_SYMBOL_GPL(of_irq_parse_raw);
276275 * @index: index of the interrupt to resolve
277276 * @out_irq: structure of_irq filled by this function
278277 *
279- * This function resolves an interrupt, walking the tree, for a given
280- * device-tree node. It's the high level pendant to of_irq_parse_raw().
278+ * This function resolves an interrupt for a node by walking the interrupt tree,
279+ * finding which interrupt controller node it is attached to, and returning the
280+ * interrupt specifier that can be used to retrieve a Linux IRQ number.
281281 */
282282int of_irq_parse_one (struct device_node * device , int index , struct of_phandle_args * out_irq )
283283{
284284 struct device_node * p ;
285285 const __be32 * intspec , * tmp , * addr ;
286286 u32 intsize , intlen ;
287- int res = - EINVAL ;
287+ int i , res = - EINVAL ;
288288
289289 pr_debug ("of_irq_parse_one: dev=%s, index=%d\n" , of_node_full_name (device ), index );
290290
@@ -320,9 +320,15 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
320320 if ((index + 1 ) * intsize > intlen )
321321 goto out ;
322322
323- /* Get new specifier and map it */
324- res = of_irq_parse_raw (p , intspec + index * intsize , intsize ,
325- addr , out_irq );
323+ /* Copy intspec into irq structure */
324+ intspec += index * intsize ;
325+ out_irq -> np = p ;
326+ out_irq -> args_count = intsize ;
327+ for (i = 0 ; i < intsize ; i ++ )
328+ out_irq -> args [i ] = be32_to_cpup (intspec ++ );
329+
330+ /* Check if there are any interrupt-map translations to process */
331+ res = of_irq_parse_raw (addr , out_irq );
326332 out :
327333 of_node_put (p );
328334 return res ;
0 commit comments