@@ -111,7 +111,8 @@ static void __of_adjust_tree_phandles(struct device_node *node,
111
111
__of_adjust_tree_phandles (child , phandle_delta );
112
112
}
113
113
114
- static int __of_adjust_phandle_ref (struct device_node * node , struct property * rprop , int value , bool is_delta )
114
+ static int __of_adjust_phandle_ref (struct device_node * node ,
115
+ struct property * rprop , int value )
115
116
{
116
117
phandle phandle ;
117
118
struct device_node * refnode ;
@@ -181,7 +182,7 @@ static int __of_adjust_phandle_ref(struct device_node *node, struct property *rp
181
182
goto err_fail ;
182
183
}
183
184
184
- phandle = is_delta ? be32_to_cpup ( sprop -> value + offset ) + value : value ;
185
+ phandle = value ;
185
186
* (__be32 * )(sprop -> value + offset ) = cpu_to_be32 (phandle );
186
187
}
187
188
@@ -190,36 +191,97 @@ static int __of_adjust_phandle_ref(struct device_node *node, struct property *rp
190
191
return err ;
191
192
}
192
193
194
+ /* compare nodes taking into account that 'name' strips out the @ part */
195
+ static int __of_node_name_cmp (const struct device_node * dn1 ,
196
+ const struct device_node * dn2 )
197
+ {
198
+ const char * n1 = strrchr (dn1 -> full_name , '/' ) ? : "/" ;
199
+ const char * n2 = strrchr (dn2 -> full_name , '/' ) ? : "/" ;
200
+
201
+ return of_node_cmp (n1 , n2 );
202
+ }
203
+
193
204
/*
194
205
* Adjust the local phandle references by the given phandle delta.
195
- * Assumes the existances of a __local_fixups__ node at the root
196
- * of the tree. Does not take any devtree locks so make sure you
197
- * call this on a tree which is at the detached state.
206
+ * Assumes the existances of a __local_fixups__ node at the root.
207
+ * Assumes that __of_verify_tree_phandle_references has been called.
208
+ * Does not take any devtree locks so make sure you call this on a tree
209
+ * which is at the detached state.
198
210
*/
199
211
static int __of_adjust_tree_phandle_references (struct device_node * node ,
200
- int phandle_delta )
212
+ struct device_node * target , int phandle_delta )
201
213
{
202
- struct device_node * child ;
203
- struct property * rprop ;
204
- int err ;
205
-
206
- /* locate the symbols & fixups nodes on resolve */
207
- for_each_child_of_node (node , child )
208
- if (of_node_cmp (child -> name , "__local_fixups__" ) == 0 )
209
- break ;
214
+ struct device_node * child , * childtarget ;
215
+ struct property * rprop , * sprop ;
216
+ int err , i , count ;
217
+ unsigned int off ;
218
+ phandle phandle ;
210
219
211
- /* no local fixups */
212
- if (!child )
220
+ if (node == NULL )
213
221
return 0 ;
214
222
215
- /* find the local fixups property */
216
- for_each_property_of_node ( child , rprop ) {
223
+ for_each_property_of_node ( node , rprop ) {
224
+
217
225
/* skip properties added automatically */
218
- if (of_prop_cmp (rprop -> name , "name" ) == 0 )
226
+ if (of_prop_cmp (rprop -> name , "name" ) == 0 ||
227
+ of_prop_cmp (rprop -> name , "phandle" ) == 0 ||
228
+ of_prop_cmp (rprop -> name , "linux,phandle" ) == 0 )
219
229
continue ;
220
230
221
- err = __of_adjust_phandle_ref (node , rprop , phandle_delta , true);
222
- if (err )
231
+ if ((rprop -> length % 4 ) != 0 || rprop -> length == 0 ) {
232
+ pr_err ("%s: Illegal property (size) '%s' @%s\n" ,
233
+ __func__ , rprop -> name , node -> full_name );
234
+ return - EINVAL ;
235
+ }
236
+ count = rprop -> length / sizeof (__be32 );
237
+
238
+ /* now find the target property */
239
+ for_each_property_of_node (target , sprop ) {
240
+ if (of_prop_cmp (sprop -> name , rprop -> name ) == 0 )
241
+ break ;
242
+ }
243
+
244
+ if (sprop == NULL ) {
245
+ pr_err ("%s: Could not find target property '%s' @%s\n" ,
246
+ __func__ , rprop -> name , node -> full_name );
247
+ return - EINVAL ;
248
+ }
249
+
250
+ for (i = 0 ; i < count ; i ++ ) {
251
+ off = be32_to_cpu (((__be32 * )rprop -> value )[i ]);
252
+ /* make sure the offset doesn't overstep (even wrap) */
253
+ if (off >= sprop -> length ||
254
+ (off + 4 ) > sprop -> length ) {
255
+ pr_err ("%s: Illegal property '%s' @%s\n" ,
256
+ __func__ , rprop -> name ,
257
+ node -> full_name );
258
+ return - EINVAL ;
259
+ }
260
+
261
+ if (phandle_delta ) {
262
+ /* adjust */
263
+ phandle = be32_to_cpu (* (__be32 * )(sprop -> value + off ));
264
+ phandle += phandle_delta ;
265
+ * (__be32 * )(sprop -> value + off ) = cpu_to_be32 (phandle );
266
+ }
267
+ }
268
+ }
269
+
270
+ for_each_child_of_node (node , child ) {
271
+
272
+ for_each_child_of_node (target , childtarget )
273
+ if (__of_node_name_cmp (child , childtarget ) == 0 )
274
+ break ;
275
+
276
+ if (!childtarget ) {
277
+ pr_err ("%s: Could not find target child '%s' @%s\n" ,
278
+ __func__ , child -> name , node -> full_name );
279
+ return - EINVAL ;
280
+ }
281
+
282
+ err = __of_adjust_tree_phandle_references (child , childtarget ,
283
+ phandle_delta );
284
+ if (err != 0 )
223
285
return err ;
224
286
}
225
287
@@ -241,7 +303,7 @@ static int __of_adjust_tree_phandle_references(struct device_node *node,
241
303
*/
242
304
int of_resolve_phandles (struct device_node * resolve )
243
305
{
244
- struct device_node * child , * refnode ;
306
+ struct device_node * child , * childroot , * refnode ;
245
307
struct device_node * root_sym , * resolve_sym , * resolve_fix ;
246
308
struct property * rprop ;
247
309
const char * refpath ;
@@ -255,9 +317,23 @@ int of_resolve_phandles(struct device_node *resolve)
255
317
/* first we need to adjust the phandles */
256
318
phandle_delta = of_get_tree_max_phandle () + 1 ;
257
319
__of_adjust_tree_phandles (resolve , phandle_delta );
258
- err = __of_adjust_tree_phandle_references (resolve , phandle_delta );
259
- if (err != 0 )
260
- return err ;
320
+
321
+ /* locate the local fixups */
322
+ childroot = NULL ;
323
+ for_each_child_of_node (resolve , childroot )
324
+ if (of_node_cmp (childroot -> name , "__local_fixups__" ) == 0 )
325
+ break ;
326
+
327
+ if (childroot != NULL ) {
328
+ /* resolve root is guaranteed to be the '/' */
329
+ err = __of_adjust_tree_phandle_references (childroot ,
330
+ resolve , 0 );
331
+ if (err != 0 )
332
+ return err ;
333
+
334
+ BUG_ON (__of_adjust_tree_phandle_references (childroot ,
335
+ resolve , phandle_delta ));
336
+ }
261
337
262
338
root_sym = NULL ;
263
339
resolve_sym = NULL ;
@@ -322,7 +398,7 @@ int of_resolve_phandles(struct device_node *resolve)
322
398
pr_debug ("%s: %s phandle is 0x%08x\n" ,
323
399
__func__ , rprop -> name , phandle );
324
400
325
- err = __of_adjust_phandle_ref (resolve , rprop , phandle , false );
401
+ err = __of_adjust_phandle_ref (resolve , rprop , phandle );
326
402
if (err )
327
403
break ;
328
404
}
0 commit comments