Branch data Line data Source code
1 : : /* SPDX-License-Identifier: (BSD-3-Clause OR GPL-2.0)
2 : : *
3 : : * Copyright 2010-2016 Freescale Semiconductor Inc.
4 : : * Copyright 2017 NXP
5 : : *
6 : : */
7 : :
8 : : #include <dpaa_of.h>
9 : : #include <assert.h>
10 : : #include <eal_export.h>
11 : : #include <rte_string_fns.h>
12 : : #include <dpaax_logs.h>
13 : :
14 : : static int alive;
15 : : static struct dt_dir root_dir;
16 : : static const char *base_dir;
17 : : static COMPAT_LIST_HEAD(linear);
18 : :
19 : : static int
20 : 0 : of_open_dir(const char *relative_path, struct dirent ***d)
21 : : {
22 : : int ret;
23 : : char full_path[PATH_MAX];
24 : :
25 : 0 : snprintf(full_path, PATH_MAX, "%s/%s", base_dir, relative_path);
26 : 0 : ret = scandir(full_path, d, 0, versionsort);
27 [ # # ]: 0 : if (ret < 0)
28 : 0 : DPAAX_LOG(ERR, "Failed to open directory %s",
29 : : full_path);
30 : 0 : return ret;
31 : : }
32 : :
33 : : static void
34 : 0 : of_close_dir(struct dirent **d, int num)
35 : : {
36 [ # # ]: 0 : while (num--)
37 : 0 : free(d[num]);
38 : 0 : free(d);
39 : 0 : }
40 : :
41 : : static int
42 : 0 : of_open_file(const char *relative_path)
43 : : {
44 : : int ret;
45 : : char full_path[PATH_MAX];
46 : :
47 : 0 : snprintf(full_path, PATH_MAX, "%s/%s", base_dir, relative_path);
48 : : ret = open(full_path, O_RDONLY);
49 [ # # ]: 0 : if (ret < 0)
50 : 0 : DPAAX_LOG(ERR, "Failed to open directory %s",
51 : : full_path);
52 : 0 : return ret;
53 : : }
54 : :
55 : : static void
56 : 0 : process_file(struct dirent *dent, struct dt_dir *parent)
57 : : {
58 : : int fd;
59 : 0 : struct dt_file *f = malloc(sizeof(*f));
60 : :
61 [ # # ]: 0 : if (!f) {
62 : 0 : DPAAX_LOG(DEBUG, "Unable to allocate memory for file node");
63 : 0 : return;
64 : : }
65 : 0 : f->node.is_file = 1;
66 : 0 : strlcpy(f->node.node.name, dent->d_name, NAME_MAX);
67 : 0 : snprintf(f->node.node.full_name, PATH_MAX, "%s/%s",
68 : 0 : parent->node.node.full_name, dent->d_name);
69 : 0 : f->parent = parent;
70 : 0 : fd = of_open_file(f->node.node.full_name);
71 [ # # ]: 0 : if (fd < 0) {
72 : 0 : DPAAX_LOG(DEBUG, "Unable to open file node");
73 : 0 : free(f);
74 : 0 : return;
75 : : }
76 [ # # ]: 0 : f->len = read(fd, f->buf, OF_FILE_BUF_MAX);
77 : 0 : close(fd);
78 [ # # ]: 0 : if (f->len < 0) {
79 : 0 : DPAAX_LOG(DEBUG, "Unable to read file node");
80 : 0 : free(f);
81 : 0 : return;
82 : : }
83 : 0 : list_add_tail(&f->node.list, &parent->files);
84 : : }
85 : :
86 : : static const struct dt_dir *
87 : : node2dir(const struct device_node *n)
88 : : {
89 : : struct dt_node *dn = container_of((struct device_node *)n,
90 : : struct dt_node, node);
91 : : const struct dt_dir *d = container_of(dn, struct dt_dir, node);
92 : :
93 [ # # # # : 0 : assert(!dn->is_file);
# # # # #
# # # # #
# # # # #
# ]
94 : : return d;
95 : : }
96 : :
97 : : /* process_dir() calls iterate_dir(), but the latter will also call the former
98 : : * when recursing into sub-directories, so a predeclaration is needed.
99 : : */
100 : : static int process_dir(const char *relative_path, struct dt_dir *dt);
101 : :
102 : : static int
103 : 0 : iterate_dir(struct dirent **d, int num, struct dt_dir *dt)
104 : : {
105 : : int loop;
106 : : /* Iterate the directory contents */
107 [ # # ]: 0 : for (loop = 0; loop < num; loop++) {
108 : : struct dt_dir *subdir;
109 : : int ret;
110 : : /* Ignore dot files of all types (especially "..") */
111 [ # # ]: 0 : if (d[loop]->d_name[0] == '.')
112 : 0 : continue;
113 [ # # # ]: 0 : switch (d[loop]->d_type) {
114 : 0 : case DT_REG:
115 : 0 : process_file(d[loop], dt);
116 : 0 : break;
117 : 0 : case DT_DIR:
118 : 0 : subdir = malloc(sizeof(*subdir));
119 [ # # ]: 0 : if (!subdir) {
120 : 0 : perror("malloc");
121 : 0 : return -ENOMEM;
122 : : }
123 : 0 : strlcpy(subdir->node.node.name, d[loop]->d_name,
124 : : NAME_MAX);
125 : 0 : snprintf(subdir->node.node.full_name, PATH_MAX,
126 : 0 : "%s/%s", dt->node.node.full_name,
127 : 0 : d[loop]->d_name);
128 : 0 : subdir->parent = dt;
129 : 0 : ret = process_dir(subdir->node.node.full_name, subdir);
130 [ # # ]: 0 : if (ret)
131 : 0 : return ret;
132 : 0 : list_add_tail(&subdir->node.list, &dt->subdirs);
133 : 0 : break;
134 : 0 : default:
135 : 0 : DPAAX_LOG(DEBUG, "Ignoring invalid dt entry %s/%s",
136 : : dt->node.node.full_name, d[loop]->d_name);
137 : : }
138 : : }
139 : : return 0;
140 : : }
141 : :
142 : : static int
143 : 0 : process_dir(const char *relative_path, struct dt_dir *dt)
144 : : {
145 : : struct dirent **d;
146 : : int ret, num;
147 : :
148 : 0 : dt->node.is_file = 0;
149 : 0 : INIT_LIST_HEAD(&dt->subdirs);
150 : 0 : INIT_LIST_HEAD(&dt->files);
151 : 0 : ret = of_open_dir(relative_path, &d);
152 [ # # ]: 0 : if (ret < 0)
153 : : return ret;
154 : : num = ret;
155 : 0 : ret = iterate_dir(d, num, dt);
156 : 0 : of_close_dir(d, num);
157 : 0 : return (ret < 0) ? ret : 0;
158 : : }
159 : :
160 : : static void
161 : 0 : linear_dir(struct dt_dir *d)
162 : : {
163 : : struct dt_file *f;
164 : : struct dt_dir *dd;
165 : :
166 : 0 : d->compatible = NULL;
167 : 0 : d->status = NULL;
168 : 0 : d->lphandle = NULL;
169 : 0 : d->a_cells = NULL;
170 : 0 : d->s_cells = NULL;
171 : 0 : d->reg = NULL;
172 [ # # ]: 0 : list_for_each_entry(f, &d->files, node.list) {
173 [ # # ]: 0 : if (!strcmp(f->node.node.name, "compatible")) {
174 [ # # ]: 0 : if (d->compatible)
175 : 0 : DPAAX_LOG(DEBUG, "Duplicate compatible in"
176 : : " %s", d->node.node.full_name);
177 : 0 : d->compatible = f;
178 [ # # ]: 0 : } else if (!strcmp(f->node.node.name, "status")) {
179 [ # # ]: 0 : if (d->status)
180 : 0 : DPAAX_LOG(DEBUG, "Duplicate status in %s",
181 : : d->node.node.full_name);
182 : 0 : d->status = f;
183 [ # # ]: 0 : } else if (!strcmp(f->node.node.name, "linux,phandle")) {
184 [ # # ]: 0 : if (d->lphandle)
185 : 0 : DPAAX_LOG(DEBUG, "Duplicate lphandle in %s",
186 : : d->node.node.full_name);
187 : 0 : d->lphandle = f;
188 [ # # ]: 0 : } else if (!strcmp(f->node.node.name, "phandle")) {
189 [ # # ]: 0 : if (d->lphandle)
190 : 0 : DPAAX_LOG(DEBUG, "Duplicate lphandle in %s",
191 : : d->node.node.full_name);
192 : 0 : d->lphandle = f;
193 [ # # ]: 0 : } else if (!strcmp(f->node.node.name, "#address-cells")) {
194 [ # # ]: 0 : if (d->a_cells)
195 : 0 : DPAAX_LOG(DEBUG, "Duplicate a_cells in %s",
196 : : d->node.node.full_name);
197 : 0 : d->a_cells = f;
198 [ # # ]: 0 : } else if (!strcmp(f->node.node.name, "#size-cells")) {
199 [ # # ]: 0 : if (d->s_cells)
200 : 0 : DPAAX_LOG(DEBUG, "Duplicate s_cells in %s",
201 : : d->node.node.full_name);
202 : 0 : d->s_cells = f;
203 [ # # ]: 0 : } else if (!strcmp(f->node.node.name, "reg")) {
204 [ # # ]: 0 : if (d->reg)
205 : 0 : DPAAX_LOG(DEBUG, "Duplicate reg in %s",
206 : : d->node.node.full_name);
207 : 0 : d->reg = f;
208 : : }
209 : : }
210 : :
211 [ # # ]: 0 : list_for_each_entry(dd, &d->subdirs, node.list) {
212 : 0 : list_add_tail(&dd->linear, &linear);
213 : 0 : linear_dir(dd);
214 : : }
215 : 0 : }
216 : :
217 : : RTE_EXPORT_INTERNAL_SYMBOL(of_init_path)
218 : : int
219 : 0 : of_init_path(const char *dt_path)
220 : : {
221 : : int ret;
222 : :
223 : 0 : base_dir = dt_path;
224 : :
225 : : /* This needs to be singleton initialization */
226 : : DPAAX_HWWARN(alive, "Double-init of device-tree driver!");
227 : :
228 : : /* Prepare root node (the remaining fields are set in process_dir()) */
229 : 0 : root_dir.node.node.name[0] = '\0';
230 : 0 : root_dir.node.node.full_name[0] = '\0';
231 : 0 : INIT_LIST_HEAD(&root_dir.node.list);
232 : 0 : root_dir.parent = NULL;
233 : :
234 : : /* Kick things off... */
235 : 0 : ret = process_dir("", &root_dir);
236 [ # # ]: 0 : if (ret) {
237 : 0 : DPAAX_LOG(ERR, "Unable to parse device tree");
238 : 0 : return ret;
239 : : }
240 : :
241 : : /* Now make a flat, linear list of directories */
242 : 0 : linear_dir(&root_dir);
243 : 0 : alive = 1;
244 : 0 : return 0;
245 : : }
246 : :
247 : : static void
248 : 0 : destroy_dir(struct dt_dir *d)
249 : : {
250 : : struct dt_file *f, *tmpf;
251 : : struct dt_dir *dd, *tmpd;
252 : :
253 [ # # ]: 0 : list_for_each_entry_safe(f, tmpf, &d->files, node.list) {
254 : 0 : list_del(&f->node.list);
255 : 0 : free(f);
256 : : }
257 [ # # ]: 0 : list_for_each_entry_safe(dd, tmpd, &d->subdirs, node.list) {
258 : 0 : destroy_dir(dd);
259 : 0 : list_del(&dd->node.list);
260 : 0 : free(dd);
261 : : }
262 : 0 : }
263 : :
264 : : void
265 : 0 : of_finish(void)
266 : : {
267 : : DPAAX_HWWARN(!alive, "Double-finish of device-tree driver!");
268 : :
269 : 0 : destroy_dir(&root_dir);
270 : 0 : INIT_LIST_HEAD(&linear);
271 : 0 : alive = 0;
272 : 0 : }
273 : :
274 : : static const struct dt_dir *
275 : : next_linear(const struct dt_dir *f)
276 : : {
277 [ # # # # ]: 0 : if (f->linear.next == &linear)
278 : : return NULL;
279 : 0 : return list_entry(f->linear.next, struct dt_dir, linear);
280 : : }
281 : :
282 : : static int
283 : 0 : check_compatible(const struct dt_file *f, const char *compatible)
284 : : {
285 : 0 : const char *c = (char *)f->buf;
286 : 0 : unsigned int len, remains = f->len;
287 : :
288 [ # # ]: 0 : while (remains) {
289 : 0 : len = strlen(c);
290 [ # # ]: 0 : if (!strcmp(c, compatible))
291 : : return 1;
292 : :
293 [ # # ]: 0 : if (remains < len + 1)
294 : : break;
295 : :
296 : 0 : c += (len + 1);
297 : 0 : remains -= (len + 1);
298 : : }
299 : : return 0;
300 : : }
301 : :
302 : : RTE_EXPORT_INTERNAL_SYMBOL(of_find_compatible_node)
303 : : const struct device_node *
304 : 0 : of_find_compatible_node(const struct device_node *from,
305 : : const char *type __rte_unused,
306 : : const char *compatible)
307 : : {
308 : : const struct dt_dir *d;
309 : :
310 : : DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
311 : :
312 [ # # # # ]: 0 : if (list_empty(&linear))
313 : : return NULL;
314 [ # # ]: 0 : if (!from)
315 : 0 : d = list_entry(linear.next, struct dt_dir, linear);
316 : : else
317 : : d = node2dir(from);
318 [ # # # # : 0 : for (d = next_linear(d); d && (!d->compatible ||
# # ]
319 : 0 : !check_compatible(d->compatible,
320 : : compatible));
321 : : d = next_linear(d))
322 : : ;
323 [ # # ]: 0 : if (d)
324 : 0 : return &d->node.node;
325 : : return NULL;
326 : : }
327 : :
328 : : RTE_EXPORT_INTERNAL_SYMBOL(of_get_property)
329 : : const void *
330 [ # # ]: 0 : of_get_property(const struct device_node *from, const char *name,
331 : : size_t *lenp)
332 : : {
333 : : const struct dt_dir *d;
334 : : const struct dt_file *f;
335 : :
336 : : DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
337 : :
338 : : d = node2dir(from);
339 [ # # ]: 0 : list_for_each_entry(f, &d->files, node.list)
340 [ # # ]: 0 : if (!strcmp(f->node.node.name, name)) {
341 [ # # ]: 0 : if (lenp)
342 : 0 : *lenp = f->len;
343 : 0 : return f->buf;
344 : : }
345 : : return NULL;
346 : : }
347 : :
348 : : RTE_EXPORT_INTERNAL_SYMBOL(of_device_is_available)
349 : : bool
350 [ # # ]: 0 : of_device_is_available(const struct device_node *dev_node)
351 : : {
352 : : const struct dt_dir *d;
353 : :
354 : : DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
355 : : d = node2dir(dev_node);
356 [ # # ]: 0 : if (!d->status)
357 : : return true;
358 [ # # ]: 0 : if (!strcmp((char *)d->status->buf, "okay"))
359 : : return true;
360 [ # # ]: 0 : if (!strcmp((char *)d->status->buf, "ok"))
361 : 0 : return true;
362 : : return false;
363 : : }
364 : :
365 : : RTE_EXPORT_INTERNAL_SYMBOL(of_find_node_by_phandle)
366 : : const struct device_node *
367 : 0 : of_find_node_by_phandle(uint64_t ph)
368 : : {
369 : : const struct dt_dir *d;
370 : :
371 : : DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
372 [ # # ]: 0 : list_for_each_entry(d, &linear, linear)
373 [ # # # # ]: 0 : if (d->lphandle && (d->lphandle->len == 4) &&
374 [ # # ]: 0 : !memcmp(d->lphandle->buf, &ph, 4))
375 : 0 : return &d->node.node;
376 : : return NULL;
377 : : }
378 : :
379 : : RTE_EXPORT_INTERNAL_SYMBOL(of_get_parent)
380 : : const struct device_node *
381 : 0 : of_get_parent(const struct device_node *dev_node)
382 : : {
383 : : const struct dt_dir *d;
384 : :
385 : : DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
386 : :
387 [ # # ]: 0 : if (!dev_node)
388 : : return NULL;
389 : : d = node2dir(dev_node);
390 [ # # ]: 0 : if (!d->parent)
391 : : return NULL;
392 : 0 : return &d->parent->node.node;
393 : : }
394 : :
395 : : RTE_EXPORT_INTERNAL_SYMBOL(of_get_next_child)
396 : : const struct device_node *
397 : 0 : of_get_next_child(const struct device_node *dev_node,
398 : : const struct device_node *prev)
399 : : {
400 : : const struct dt_dir *p, *c;
401 : :
402 : : DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
403 : :
404 [ # # ]: 0 : if (!dev_node)
405 : : return NULL;
406 : : p = node2dir(dev_node);
407 [ # # ]: 0 : if (prev) {
408 : : c = node2dir(prev);
409 : : DPAAX_HWWARN((c->parent != p), "Parent/child mismatch");
410 [ # # ]: 0 : if (c->parent != p)
411 : : return NULL;
412 [ # # ]: 0 : if (c->node.list.next == &p->subdirs)
413 : : /* prev was the last child */
414 : : return NULL;
415 : : c = list_entry(c->node.list.next, struct dt_dir, node.list);
416 : 0 : return &c->node.node;
417 : : }
418 : : /* Return first child */
419 [ # # # # ]: 0 : if (list_empty(&p->subdirs))
420 : : return NULL;
421 : : c = list_entry(p->subdirs.next, struct dt_dir, node.list);
422 : 0 : return &c->node.node;
423 : : }
424 : :
425 : : RTE_EXPORT_INTERNAL_SYMBOL(of_n_addr_cells)
426 : : uint32_t
427 : 0 : of_n_addr_cells(const struct device_node *dev_node)
428 : : {
429 : : const struct dt_dir *d;
430 : :
431 : : DPAAX_HWWARN(!alive, "Device-tree driver not initialised");
432 [ # # ]: 0 : if (!dev_node)
433 : : return OF_DEFAULT_NA;
434 : : d = node2dir(dev_node);
435 [ # # ]: 0 : while ((d = d->parent))
436 [ # # ]: 0 : if (d->a_cells) {
437 : : unsigned char *buf =
438 : : (unsigned char *)&d->a_cells->buf[0];
439 [ # # ]: 0 : assert(d->a_cells->len == 4);
440 : 0 : return ((uint32_t)buf[0] << 24) |
441 : 0 : ((uint32_t)buf[1] << 16) |
442 : 0 : ((uint32_t)buf[2] << 8) |
443 : 0 : (uint32_t)buf[3];
444 : : }
445 : : return OF_DEFAULT_NA;
446 : : }
447 : :
448 : : uint32_t
449 : 0 : of_n_size_cells(const struct device_node *dev_node)
450 : : {
451 : : const struct dt_dir *d;
452 : :
453 : : DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
454 [ # # ]: 0 : if (!dev_node)
455 : : return OF_DEFAULT_NA;
456 : : d = node2dir(dev_node);
457 [ # # ]: 0 : while ((d = d->parent))
458 [ # # ]: 0 : if (d->s_cells) {
459 : : unsigned char *buf =
460 : : (unsigned char *)&d->s_cells->buf[0];
461 [ # # ]: 0 : assert(d->s_cells->len == 4);
462 : 0 : return ((uint32_t)buf[0] << 24) |
463 : 0 : ((uint32_t)buf[1] << 16) |
464 : 0 : ((uint32_t)buf[2] << 8) |
465 : 0 : (uint32_t)buf[3];
466 : : }
467 : : return OF_DEFAULT_NS;
468 : : }
469 : :
470 : : RTE_EXPORT_INTERNAL_SYMBOL(of_get_address)
471 : : const uint32_t *
472 : 0 : of_get_address(const struct device_node *dev_node, size_t idx,
473 : : uint64_t *size, uint32_t *flags __rte_unused)
474 : : {
475 : : const struct dt_dir *d;
476 : : const unsigned char *buf;
477 : 0 : uint32_t na = of_n_addr_cells(dev_node);
478 : 0 : uint32_t ns = of_n_size_cells(dev_node);
479 : :
480 [ # # ]: 0 : if (!dev_node)
481 : : d = &root_dir;
482 : : else
483 : : d = node2dir(dev_node);
484 [ # # ]: 0 : if (!d->reg)
485 : : return NULL;
486 [ # # ]: 0 : assert(d->reg->len % ((na + ns) * 4) == 0);
487 [ # # ]: 0 : assert(d->reg->len / ((na + ns) * 4) > (unsigned int) idx);
488 : 0 : buf = (const unsigned char *)&d->reg->buf[0];
489 : 0 : buf += (na + ns) * idx * 4;
490 [ # # ]: 0 : if (size)
491 [ # # ]: 0 : for (*size = 0; ns > 0; ns--, na++)
492 : 0 : *size = (*size << 32) +
493 : 0 : (((uint32_t)buf[4 * na] << 24) |
494 : 0 : ((uint32_t)buf[4 * na + 1] << 16) |
495 : 0 : ((uint32_t)buf[4 * na + 2] << 8) |
496 : 0 : (uint32_t)buf[4 * na + 3]);
497 : : return (const uint32_t *)buf;
498 : : }
499 : :
500 : : RTE_EXPORT_INTERNAL_SYMBOL(of_translate_address)
501 : : uint64_t
502 : 0 : of_translate_address(const struct device_node *dev_node,
503 : : const uint32_t *addr)
504 : : {
505 : : uint64_t phys_addr, tmp_addr;
506 : : const struct device_node *parent;
507 : : const uint32_t *ranges;
508 : : size_t rlen;
509 : : uint32_t na, pna;
510 : :
511 : : DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
512 : : assert(dev_node != NULL);
513 : :
514 : 0 : na = of_n_addr_cells(dev_node);
515 : 0 : phys_addr = of_read_number(addr, na);
516 : :
517 : 0 : dev_node = of_get_parent(dev_node);
518 [ # # ]: 0 : if (!dev_node)
519 : : return 0;
520 [ # # ]: 0 : else if (node2dir(dev_node) == &root_dir)
521 : : return phys_addr;
522 : :
523 : : do {
524 : 0 : pna = of_n_addr_cells(dev_node);
525 : 0 : parent = of_get_parent(dev_node);
526 [ # # ]: 0 : if (!parent)
527 : : return 0;
528 : :
529 : 0 : ranges = of_get_property(dev_node, "ranges", &rlen);
530 : : /* "ranges" property is missing. Translation breaks */
531 [ # # ]: 0 : if (!ranges)
532 : : return 0;
533 : : /* "ranges" property is empty. Do 1:1 translation */
534 [ # # ]: 0 : else if (rlen == 0)
535 : 0 : continue;
536 : : else
537 : 0 : tmp_addr = of_read_number(ranges + na, pna);
538 : :
539 : : na = pna;
540 : : dev_node = parent;
541 : 0 : phys_addr += tmp_addr;
542 [ # # ]: 0 : } while (node2dir(parent) != &root_dir);
543 : :
544 : : return phys_addr;
545 : : }
546 : :
547 : : RTE_EXPORT_INTERNAL_SYMBOL(of_device_is_compatible)
548 : : bool
549 : 0 : of_device_is_compatible(const struct device_node *dev_node,
550 : : const char *compatible)
551 : : {
552 : : const struct dt_dir *d;
553 : :
554 : : DPAAX_HWWARN(!alive, "Device-tree driver not initialised!");
555 [ # # ]: 0 : if (!dev_node)
556 : : d = &root_dir;
557 : : else
558 : : d = node2dir(dev_node);
559 [ # # # # ]: 0 : if (d->compatible && check_compatible(d->compatible, compatible))
560 : 0 : return true;
561 : : return false;
562 : : }
563 : :
564 : : static const void *of_get_mac_addr(const struct device_node *np,
565 : : const char *name)
566 : : {
567 : 0 : return of_get_property(np, name, NULL);
568 : : }
569 : :
570 : : /**
571 : : * Search the device tree for the best MAC address to use. 'mac-address' is
572 : : * checked first, because that is supposed to contain to "most recent" MAC
573 : : * address. If that isn't set, then 'local-mac-address' is checked next,
574 : : * because that is the default address. If that isn't set, then the obsolete
575 : : * 'address' is checked, just in case we're using an old device tree.
576 : : *
577 : : * Note that the 'address' property is supposed to contain a virtual address of
578 : : * the register set, but some DTS files have redefined that property to be the
579 : : * MAC address.
580 : : *
581 : : * All-zero MAC addresses are rejected, because those could be properties that
582 : : * exist in the device tree, but were not set by U-Boot. For example, the
583 : : * DTS could define 'mac-address' and 'local-mac-address', with zero MAC
584 : : * addresses. Some older U-Boots only initialized 'local-mac-address'. In
585 : : * this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
586 : : * but is all zeros.
587 : : */
588 : : RTE_EXPORT_INTERNAL_SYMBOL(of_get_mac_address)
589 : 0 : const void *of_get_mac_address(const struct device_node *np)
590 : : {
591 : : const void *addr;
592 : :
593 : : addr = of_get_mac_addr(np, "mac-address");
594 [ # # ]: 0 : if (addr)
595 : : return addr;
596 : :
597 : : addr = of_get_mac_addr(np, "local-mac-address");
598 [ # # ]: 0 : if (addr)
599 : : return addr;
600 : :
601 : 0 : return of_get_mac_addr(np, "address");
602 : : }
|