25
25
#include <linux/string.h>
26
26
#include <linux/slab.h>
27
27
28
+ #include "of_private.h"
29
+
28
30
/**
29
31
* irq_of_parse_and_map - Parse and map an interrupt into linux virq space
30
32
* @dev: Device node of the device whose interrupt is to be mapped
@@ -96,6 +98,57 @@ static const char * const of_irq_imap_abusers[] = {
96
98
NULL ,
97
99
};
98
100
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
+
99
152
/**
100
153
* of_irq_parse_raw - Low level interrupt tree parsing
101
154
* @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[] = {
112
165
*/
113
166
int of_irq_parse_raw (const __be32 * addr , struct of_phandle_args * out_irq )
114
167
{
115
- struct device_node * ipar , * tnode , * old = NULL , * newpar = NULL ;
168
+ struct device_node * ipar , * tnode , * old = NULL ;
116
169
__be32 initial_match_array [MAX_PHANDLE_ARGS ];
117
170
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 ;
121
174
122
175
#ifdef DEBUG
123
176
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)
176
229
177
230
/* Now start the actual "proper" walk of the interrupt tree */
178
231
while (ipar != NULL ) {
232
+ int imaplen , match ;
233
+ const __be32 * imap , * oldimap , * imask ;
234
+ struct device_node * newpar ;
179
235
/*
180
236
* Now check if cursor is an interrupt-controller and
181
237
* 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)
216
272
217
273
/* Parse interrupt-map */
218
274
match = 0 ;
219
- while (imaplen > (addrsize + intsize + 1 ) && ! match ) {
275
+ while (imaplen > (addrsize + intsize + 1 )) {
220
276
/* Compare specifiers */
221
277
match = 1 ;
222
278
for (i = 0 ; i < (addrsize + intsize ); i ++ , imaplen -- )
223
279
match &= !((match_array [i ] ^ * imap ++ ) & imask [i ]);
224
280
225
281
pr_debug (" -> match=%d (imaplen=%d)\n" , match , imaplen );
226
282
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 )
263
286
goto fail ;
264
- }
265
287
266
- imap += newaddrsize + newintsize ;
267
- imaplen -= newaddrsize + newintsize ;
288
+ match &= of_device_is_available (out_irq -> np );
289
+ if (match )
290
+ break ;
268
291
292
+ of_node_put (out_irq -> np );
293
+ imaplen -= imap - oldimap ;
269
294
pr_debug (" -> imaplen=%d\n" , imaplen );
270
295
}
271
296
if (!match ) {
@@ -287,11 +312,11 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
287
312
* Successfully parsed an interrupt-map translation; copy new
288
313
* interrupt specifier into the out_irq structure
289
314
*/
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 ;
295
320
296
321
if (ipar == newpar ) {
297
322
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)
300
325
301
326
skiplevel :
302
327
/* Iterate again with new parent */
303
- out_irq -> np = newpar ;
304
328
pr_debug (" -> new parent: %pOF\n" , newpar );
305
329
of_node_put (ipar );
306
330
ipar = newpar ;
@@ -310,7 +334,6 @@ int of_irq_parse_raw(const __be32 *addr, struct of_phandle_args *out_irq)
310
334
311
335
fail :
312
336
of_node_put (ipar );
313
- of_node_put (newpar );
314
337
315
338
return rc ;
316
339
}
0 commit comments