2525#include <linux/string.h>
2626#include <linux/slab.h>
2727
28+ #include "of_private.h"
29+
2830/**
2931 * irq_of_parse_and_map - Parse and map an interrupt into linux virq space
3032 * @dev: Device node of the device whose interrupt is to be mapped
@@ -96,6 +98,57 @@ static const char * const of_irq_imap_abusers[] = {
9698 NULL ,
9799};
98100
101+ const __be32 * of_irq_parse_imap_parent (const __be32 * imap , int len , struct of_phandle_args * out_irq )
102+ {
103+ u32 intsize , addrsize ;
104+ struct device_node * np ;
105+
106+ /* Get the interrupt parent */
107+ if (of_irq_workarounds & OF_IMAP_NO_PHANDLE )
108+ np = of_node_get (of_irq_dflt_pic );
109+ else
110+ np = of_find_node_by_phandle (be32_to_cpup (imap ));
111+ imap ++ ;
112+
113+ /* Check if not found */
114+ if (!np ) {
115+ pr_debug (" -> imap parent not found !\n" );
116+ return NULL ;
117+ }
118+
119+ /* Get #interrupt-cells and #address-cells of new parent */
120+ if (of_property_read_u32 (np , "#interrupt-cells" ,
121+ & intsize )) {
122+ pr_debug (" -> parent lacks #interrupt-cells!\n" );
123+ of_node_put (np );
124+ return NULL ;
125+ }
126+ if (of_property_read_u32 (np , "#address-cells" ,
127+ & addrsize ))
128+ addrsize = 0 ;
129+
130+ pr_debug (" -> intsize=%d, addrsize=%d\n" ,
131+ intsize , addrsize );
132+
133+ /* Check for malformed properties */
134+ if (WARN_ON (addrsize + intsize > MAX_PHANDLE_ARGS )
135+ || (len < (addrsize + intsize ))) {
136+ of_node_put (np );
137+ return NULL ;
138+ }
139+
140+ pr_debug (" -> imaplen=%d\n" , len );
141+
142+ imap += addrsize + intsize ;
143+
144+ out_irq -> np = np ;
145+ for (int i = 0 ; i < intsize ; i ++ )
146+ out_irq -> args [i ] = be32_to_cpup (imap - intsize + i );
147+ out_irq -> args_count = intsize ;
148+
149+ return imap ;
150+ }
151+
99152/**
100153 * of_irq_parse_raw - Low level interrupt tree parsing
101154 * @addr: address specifier (start of "reg" property of the device) in be32 format
@@ -112,12 +165,12 @@ static const char * const of_irq_imap_abusers[] = {
112165 */
113166int of_irq_parse_raw (const __be32 * addr , struct of_phandle_args * out_irq )
114167{
115- struct device_node * ipar , * tnode , * old = NULL , * newpar = NULL ;
168+ struct device_node * ipar , * tnode , * old = NULL ;
116169 __be32 initial_match_array [MAX_PHANDLE_ARGS ];
117170 const __be32 * match_array = initial_match_array ;
118- const __be32 * tmp , * imap , * imask , dummy_imask [] = { [0 ... MAX_PHANDLE_ARGS ] = cpu_to_be32 (~0 ) };
119- u32 intsize = 1 , addrsize , newintsize = 0 , newaddrsize = 0 ;
120- int imaplen , match , i , rc = - EINVAL ;
171+ const __be32 * tmp , dummy_imask [] = { [0 ... MAX_PHANDLE_ARGS ] = cpu_to_be32 (~0 ) };
172+ u32 intsize = 1 , addrsize ;
173+ int i , rc = - EINVAL ;
121174
122175#ifdef DEBUG
123176 of_print_phandle_args ("of_irq_parse_raw: " , out_irq );
@@ -176,6 +229,9 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
176229
177230 /* Now start the actual "proper" walk of the interrupt tree */
178231 while (ipar != NULL ) {
232+ int imaplen , match ;
233+ const __be32 * imap , * oldimap , * imask ;
234+ struct device_node * newpar ;
179235 /*
180236 * Now check if cursor is an interrupt-controller and
181237 * if it is then we are done, unless there is an
@@ -216,56 +272,25 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
216272
217273 /* Parse interrupt-map */
218274 match = 0 ;
219- while (imaplen > (addrsize + intsize + 1 ) && ! match ) {
275+ while (imaplen > (addrsize + intsize + 1 )) {
220276 /* Compare specifiers */
221277 match = 1 ;
222278 for (i = 0 ; i < (addrsize + intsize ); i ++ , imaplen -- )
223279 match &= !((match_array [i ] ^ * imap ++ ) & imask [i ]);
224280
225281 pr_debug (" -> match=%d (imaplen=%d)\n" , match , imaplen );
226282
227- /* Get the interrupt parent */
228- if (of_irq_workarounds & OF_IMAP_NO_PHANDLE )
229- newpar = of_node_get (of_irq_dflt_pic );
230- else
231- newpar = of_find_node_by_phandle (be32_to_cpup (imap ));
232- imap ++ ;
233- -- imaplen ;
234-
235- /* Check if not found */
236- if (newpar == NULL ) {
237- pr_debug (" -> imap parent not found !\n" );
238- goto fail ;
239- }
240-
241- if (!of_device_is_available (newpar ))
242- match = 0 ;
243-
244- /* Get #interrupt-cells and #address-cells of new
245- * parent
246- */
247- if (of_property_read_u32 (newpar , "#interrupt-cells" ,
248- & newintsize )) {
249- pr_debug (" -> parent lacks #interrupt-cells!\n" );
250- goto fail ;
251- }
252- if (of_property_read_u32 (newpar , "#address-cells" ,
253- & newaddrsize ))
254- newaddrsize = 0 ;
255-
256- pr_debug (" -> newintsize=%d, newaddrsize=%d\n" ,
257- newintsize , newaddrsize );
258-
259- /* Check for malformed properties */
260- if (WARN_ON (newaddrsize + newintsize > MAX_PHANDLE_ARGS )
261- || (imaplen < (newaddrsize + newintsize ))) {
262- rc = - EFAULT ;
283+ oldimap = imap ;
284+ imap = of_irq_parse_imap_parent (oldimap , imaplen , out_irq );
285+ if (!imap )
263286 goto fail ;
264- }
265287
266- imap += newaddrsize + newintsize ;
267- imaplen -= newaddrsize + newintsize ;
288+ match &= of_device_is_available (out_irq -> np );
289+ if (match )
290+ break ;
268291
292+ of_node_put (out_irq -> np );
293+ imaplen -= imap - oldimap ;
269294 pr_debug (" -> imaplen=%d\n" , imaplen );
270295 }
271296 if (!match ) {
@@ -287,11 +312,11 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
287312 * Successfully parsed an interrupt-map translation; copy new
288313 * interrupt specifier into the out_irq structure
289314 */
290- match_array = imap - newaddrsize - newintsize ;
291- for ( i = 0 ; i < newintsize ; i ++ )
292- out_irq -> args [ i ] = be32_to_cpup ( imap - newintsize + i ) ;
293- out_irq -> args_count = intsize = newintsize ;
294- addrsize = newaddrsize ;
315+ match_array = oldimap + 1 ;
316+
317+ newpar = out_irq -> np ;
318+ intsize = out_irq -> args_count ;
319+ addrsize = ( imap - match_array ) - intsize ;
295320
296321 if (ipar == newpar ) {
297322 pr_debug ("%pOF interrupt-map entry to self\n" , ipar );
@@ -300,7 +325,6 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
300325
301326 skiplevel :
302327 /* Iterate again with new parent */
303- out_irq -> np = newpar ;
304328 pr_debug (" -> new parent: %pOF\n" , newpar );
305329 of_node_put (ipar );
306330 ipar = newpar ;
@@ -310,7 +334,6 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
310334
311335 fail :
312336 of_node_put (ipar );
313- of_node_put (newpar );
314337
315338 return rc ;
316339}
0 commit comments