@@ -80,31 +80,32 @@ struct device_node *of_irq_find_parent(struct device_node *child)
80
80
/**
81
81
* of_irq_parse_raw - Low level interrupt tree parsing
82
82
* @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
87
85
*
88
86
* Returns 0 on success and a negative number on error
89
87
*
90
88
* This function is a low-level interrupt tree walking function. It
91
89
* can be used to do a partial walk with synthetized reg and interrupts
92
90
* 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.
94
94
*/
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 )
97
96
{
98
97
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 };
100
101
u32 intsize = 1 , addrsize , newintsize = 0 , newaddrsize = 0 ;
101
102
int imaplen , match , i ;
102
103
103
104
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 );
106
107
107
- ipar = of_node_get (parent );
108
+ ipar = of_node_get (out_irq -> np );
108
109
109
110
/* First get the #interrupt-cells property of the current cursor
110
111
* 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,
127
128
128
129
pr_debug ("of_irq_parse_raw: ipar=%s, size=%d\n" , of_node_full_name (ipar ), intsize );
129
130
130
- if (ointsize != intsize )
131
+ if (out_irq -> args_count != intsize )
131
132
return - EINVAL ;
132
133
133
134
/* 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,
146
147
147
148
pr_debug (" -> addrsize=%d\n" , addrsize );
148
149
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
+
149
165
/* Now start the actual "proper" walk of the interrupt tree */
150
166
while (ipar != NULL ) {
151
167
/* 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,
154
170
if (of_get_property (ipar , "interrupt-controller" , NULL ) !=
155
171
NULL ) {
156
172
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 ;
162
173
of_node_put (old );
163
174
return 0 ;
164
175
}
@@ -175,34 +186,16 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
175
186
176
187
/* Look for a mask */
177
188
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 ;
187
191
188
192
/* Parse interrupt-map */
189
193
match = 0 ;
190
194
while (imaplen > (addrsize + intsize + 1 ) && !match ) {
191
195
/* Compare specifiers */
192
196
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 ]);
206
199
207
200
pr_debug (" -> match=%d (imaplen=%d)\n" , match , imaplen );
208
201
@@ -247,12 +240,18 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
247
240
if (!match )
248
241
goto fail ;
249
242
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 ;
252
254
addrsize = newaddrsize ;
253
- intsize = newintsize ;
254
- intspec = imap - intsize ;
255
- addr = intspec - addrsize ;
256
255
257
256
skiplevel :
258
257
/* Iterate again with new parent */
@@ -263,7 +262,7 @@ int of_irq_parse_raw(struct device_node *parent, const __be32 *intspec,
263
262
}
264
263
fail :
265
264
of_node_put (ipar );
266
- of_node_put (old );
265
+ of_node_put (out_irq -> np );
267
266
of_node_put (newpar );
268
267
269
268
return - EINVAL ;
@@ -276,15 +275,16 @@ EXPORT_SYMBOL_GPL(of_irq_parse_raw);
276
275
* @index: index of the interrupt to resolve
277
276
* @out_irq: structure of_irq filled by this function
278
277
*
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.
281
281
*/
282
282
int of_irq_parse_one (struct device_node * device , int index , struct of_phandle_args * out_irq )
283
283
{
284
284
struct device_node * p ;
285
285
const __be32 * intspec , * tmp , * addr ;
286
286
u32 intsize , intlen ;
287
- int res = - EINVAL ;
287
+ int i , res = - EINVAL ;
288
288
289
289
pr_debug ("of_irq_parse_one: dev=%s, index=%d\n" , of_node_full_name (device ), index );
290
290
@@ -320,9 +320,15 @@ int of_irq_parse_one(struct device_node *device, int index, struct of_phandle_ar
320
320
if ((index + 1 ) * intsize > intlen )
321
321
goto out ;
322
322
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 );
326
332
out :
327
333
of_node_put (p );
328
334
return res ;
0 commit comments