FreeBSD kernel amd64 OFW device code
ofw_bus_subr.c
Go to the documentation of this file.
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>.
5 * Copyright (c) 2005 Marius Strobl <marius@FreeBSD.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions, and the following disclaimer,
13 * without modification, immediately at the beginning of the file.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
23 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD$");
34
35#include "opt_platform.h"
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/bus.h>
39#include <sys/errno.h>
40#include <sys/libkern.h>
41#include <sys/sbuf.h>
42
43#include <machine/resource.h>
44
45#include <dev/ofw/ofw_bus.h>
47#include <dev/ofw/openfirm.h>
48
49#include "ofw_bus_if.h"
50
51#define OFW_COMPAT_LEN 255
52#define OFW_STATUS_LEN 16
53
54int
55ofw_bus_gen_setup_devinfo(struct ofw_bus_devinfo *obd, phandle_t node)
56{
57
58 if (obd == NULL)
59 return (ENOMEM);
60 /* The 'name' property is considered mandatory. */
61 if ((OF_getprop_alloc(node, "name", (void **)&obd->obd_name)) == -1)
62 return (EINVAL);
63 OF_getprop_alloc(node, "compatible", (void **)&obd->obd_compat);
64 OF_getprop_alloc(node, "device_type", (void **)&obd->obd_type);
65 OF_getprop_alloc(node, "model", (void **)&obd->obd_model);
66 OF_getprop_alloc(node, "status", (void **)&obd->obd_status);
67 obd->obd_node = node;
68 return (0);
69}
70
71void
72ofw_bus_gen_destroy_devinfo(struct ofw_bus_devinfo *obd)
73{
74
75 if (obd == NULL)
76 return;
77 if (obd->obd_compat != NULL)
78 free(obd->obd_compat, M_OFWPROP);
79 if (obd->obd_model != NULL)
80 free(obd->obd_model, M_OFWPROP);
81 if (obd->obd_name != NULL)
82 free(obd->obd_name, M_OFWPROP);
83 if (obd->obd_type != NULL)
84 free(obd->obd_type, M_OFWPROP);
85 if (obd->obd_status != NULL)
86 free(obd->obd_status, M_OFWPROP);
87}
88
89int
90ofw_bus_gen_child_pnpinfo(device_t cbdev, device_t child, struct sbuf *sb)
91{
92
94 return (0);
95
96 if (ofw_bus_get_name(child) != NULL) {
97 sbuf_printf(sb, "name=%s ", ofw_bus_get_name(child));
98 }
99
100 if (ofw_bus_get_compat(child) != NULL) {
101 sbuf_printf(sb, "compat=%s ", ofw_bus_get_compat(child));
102 }
103
104 return (0);
105};
106
107const char *
108ofw_bus_gen_get_compat(device_t bus, device_t dev)
109{
110 const struct ofw_bus_devinfo *obd;
111
112 obd = OFW_BUS_GET_DEVINFO(bus, dev);
113 if (obd == NULL)
114 return (NULL);
115 return (obd->obd_compat);
116}
117
118const char *
119ofw_bus_gen_get_model(device_t bus, device_t dev)
120{
121 const struct ofw_bus_devinfo *obd;
122
123 obd = OFW_BUS_GET_DEVINFO(bus, dev);
124 if (obd == NULL)
125 return (NULL);
126 return (obd->obd_model);
127}
128
129const char *
130ofw_bus_gen_get_name(device_t bus, device_t dev)
131{
132 const struct ofw_bus_devinfo *obd;
133
134 obd = OFW_BUS_GET_DEVINFO(bus, dev);
135 if (obd == NULL)
136 return (NULL);
137 return (obd->obd_name);
138}
139
141ofw_bus_gen_get_node(device_t bus, device_t dev)
142{
143 const struct ofw_bus_devinfo *obd;
144
145 obd = OFW_BUS_GET_DEVINFO(bus, dev);
146 if (obd == NULL)
147 return ((phandle_t)-1);
148 return (obd->obd_node);
149}
150
151const char *
152ofw_bus_gen_get_type(device_t bus, device_t dev)
153{
154 const struct ofw_bus_devinfo *obd;
155
156 obd = OFW_BUS_GET_DEVINFO(bus, dev);
157 if (obd == NULL)
158 return (NULL);
159 return (obd->obd_type);
160}
161
162const char *
164{
165 const struct ofw_bus_devinfo *obd;
166
167 obd = OFW_BUS_GET_DEVINFO(device_get_parent(dev), dev);
168 if (obd == NULL)
169 return (NULL);
170
171 return (obd->obd_status);
172}
173
174int
176{
177 const char *status;
178
179 status = ofw_bus_get_status(dev);
180 if (status == NULL || strcmp(status, "okay") == 0 ||
181 strcmp(status, "ok") == 0)
182 return (1);
183
184 return (0);
185}
186
187int
189{
190 char status[OFW_STATUS_LEN];
191 int len;
192
193 len = OF_getproplen(node, "status");
194 if (len <= 0)
195 return (1);
196
197 OF_getprop(node, "status", status, OFW_STATUS_LEN);
198 if ((len == 5 && (bcmp(status, "okay", len) == 0)) ||
199 (len == 3 && (bcmp(status, "ok", len))))
200 return (1);
201
202 return (0);
203}
204
205static int
206ofw_bus_node_is_compatible_int(const char *compat, int len,
207 const char *onecompat)
208{
209 int onelen, l, ret;
210
211 onelen = strlen(onecompat);
212
213 ret = 0;
214 while (len > 0) {
215 if (strlen(compat) == onelen &&
216 strncasecmp(compat, onecompat, onelen) == 0) {
217 /* Found it. */
218 ret = 1;
219 break;
220 }
221
222 /* Slide to the next sub-string. */
223 l = strlen(compat) + 1;
224 compat += l;
225 len -= l;
226 }
227
228 return (ret);
229}
230
231int
232ofw_bus_node_is_compatible(phandle_t node, const char *compatstr)
233{
234 char compat[OFW_COMPAT_LEN];
235 int len, rv;
236
237 if ((len = OF_getproplen(node, "compatible")) <= 0)
238 return (0);
239
240 bzero(compat, OFW_COMPAT_LEN);
241
242 if (OF_getprop(node, "compatible", compat, OFW_COMPAT_LEN) < 0)
243 return (0);
244
245 rv = ofw_bus_node_is_compatible_int(compat, len, compatstr);
246
247 return (rv);
248}
249
250int
251ofw_bus_is_compatible(device_t dev, const char *onecompat)
252{
253 phandle_t node;
254 const char *compat;
255 int len;
256
257 if ((compat = ofw_bus_get_compat(dev)) == NULL)
258 return (0);
259
260 if ((node = ofw_bus_get_node(dev)) == -1)
261 return (0);
262
263 /* Get total 'compatible' prop len */
264 if ((len = OF_getproplen(node, "compatible")) <= 0)
265 return (0);
266
267 return (ofw_bus_node_is_compatible_int(compat, len, onecompat));
268}
269
270int
271ofw_bus_is_compatible_strict(device_t dev, const char *compatible)
272{
273 const char *compat;
274 size_t len;
275
276 if ((compat = ofw_bus_get_compat(dev)) == NULL)
277 return (0);
278
279 len = strlen(compatible);
280 if (strlen(compat) == len &&
281 strncasecmp(compat, compatible, len) == 0)
282 return (1);
283
284 return (0);
285}
286
287const struct ofw_compat_data *
288ofw_bus_search_compatible(device_t dev, const struct ofw_compat_data *compat)
289{
290
291 if (compat == NULL)
292 return NULL;
293
294 for (; compat->ocd_str != NULL; ++compat) {
295 if (ofw_bus_is_compatible(dev, compat->ocd_str))
296 break;
297 }
298
299 return (compat);
300}
301
302int
303ofw_bus_has_prop(device_t dev, const char *propname)
304{
305 phandle_t node;
306
307 if ((node = ofw_bus_get_node(dev)) == -1)
308 return (0);
309
310 return (OF_hasprop(node, propname));
311}
312
313void
314ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz)
315{
316 pcell_t addrc;
317 int msksz;
318
319 if (OF_getencprop(node, "#address-cells", &addrc, sizeof(addrc)) == -1)
320 addrc = 2;
321 ii->opi_addrc = addrc * sizeof(pcell_t);
322
323 ii->opi_imapsz = OF_getencprop_alloc(node, "interrupt-map",
324 (void **)&ii->opi_imap);
325 if (ii->opi_imapsz > 0) {
326 msksz = OF_getencprop_alloc(node, "interrupt-map-mask",
327 (void **)&ii->opi_imapmsk);
328 /*
329 * Failure to get the mask is ignored; a full mask is used
330 * then. We barf on bad mask sizes, however.
331 */
332 if (msksz != -1 && msksz != ii->opi_addrc + intrsz)
333 panic("ofw_bus_setup_iinfo: bad interrupt-map-mask "
334 "property!");
335 }
336}
337
338int
339ofw_bus_lookup_imap(phandle_t node, struct ofw_bus_iinfo *ii, void *reg,
340 int regsz, void *pintr, int pintrsz, void *mintr, int mintrsz,
342{
343 uint8_t maskbuf[regsz + pintrsz];
344 int rv;
345
346 if (ii->opi_imapsz <= 0)
347 return (0);
348 KASSERT(regsz >= ii->opi_addrc,
349 ("ofw_bus_lookup_imap: register size too small: %d < %d",
350 regsz, ii->opi_addrc));
351 if (node != -1) {
352 rv = OF_getencprop(node, "reg", reg, regsz);
353 if (rv < regsz)
354 panic("ofw_bus_lookup_imap: cannot get reg property");
355 }
356 return (ofw_bus_search_intrmap(pintr, pintrsz, reg, ii->opi_addrc,
357 ii->opi_imap, ii->opi_imapsz, ii->opi_imapmsk, maskbuf, mintr,
358 mintrsz, iparent));
359}
360
361/*
362 * Map an interrupt using the firmware reg, interrupt-map and
363 * interrupt-map-mask properties.
364 * The interrupt property to be mapped must be of size intrsz, and pointed to
365 * by intr. The regs property of the node for which the mapping is done must
366 * be passed as regs. This property is an array of register specifications;
367 * the size of the address part of such a specification must be passed as
368 * physsz. Only the first element of the property is used.
369 * imap and imapsz hold the interrupt mask and it's size.
370 * imapmsk is a pointer to the interrupt-map-mask property, which must have
371 * a size of physsz + intrsz; it may be NULL, in which case a full mask is
372 * assumed.
373 * maskbuf must point to a buffer of length physsz + intrsz.
374 * The interrupt is returned in result, which must point to a buffer of length
375 * rintrsz (which gives the expected size of the mapped interrupt).
376 * Returns number of cells in the interrupt if a mapping was found, 0 otherwise.
377 */
378int
379ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz,
380 void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result,
381 int rintrsz, phandle_t *iparent)
382{
384 uint8_t *ref = maskbuf;
385 uint8_t *uiintr = intr;
386 uint8_t *uiregs = regs;
387 uint8_t *uiimapmsk = imapmsk;
388 uint8_t *mptr;
389 pcell_t paddrsz;
390 pcell_t pintrsz;
391 int i, tsz;
392
393 if (imapmsk != NULL) {
394 for (i = 0; i < physsz; i++)
395 ref[i] = uiregs[i] & uiimapmsk[i];
396 for (i = 0; i < intrsz; i++)
397 ref[physsz + i] = uiintr[i] & uiimapmsk[physsz + i];
398 } else {
399 bcopy(regs, ref, physsz);
400 bcopy(intr, ref + physsz, intrsz);
401 }
402
403 mptr = imap;
404 i = imapsz;
405 paddrsz = 0;
406 while (i > 0) {
407 bcopy(mptr + physsz + intrsz, &parent, sizeof(parent));
408#ifndef OFW_IMAP_NO_IPARENT_ADDR_CELLS
409 /*
410 * Find if we need to read the parent address data.
411 * CHRP-derived OF bindings, including ePAPR-compliant FDTs,
412 * use this as an optional part of the specifier.
413 */
415 "#address-cells", &paddrsz, sizeof(paddrsz)) == -1)
416 paddrsz = 0; /* default */
417 paddrsz *= sizeof(pcell_t);
418#endif
419
421 "#interrupt-cells", &pintrsz, sizeof(pintrsz)) == -1)
422 pintrsz = 1; /* default */
423 pintrsz *= sizeof(pcell_t);
424
425 /* Compute the map stride size. */
426 tsz = physsz + intrsz + sizeof(phandle_t) + paddrsz + pintrsz;
427 KASSERT(i >= tsz, ("ofw_bus_search_intrmap: truncated map"));
428
429 if (bcmp(ref, mptr, physsz + intrsz) == 0) {
430 bcopy(mptr + physsz + intrsz + sizeof(parent) + paddrsz,
431 result, MIN(rintrsz, pintrsz));
432
433 if (iparent != NULL)
434 *iparent = parent;
435 return (pintrsz/sizeof(pcell_t));
436 }
437 mptr += tsz;
438 i -= tsz;
439 }
440 return (0);
441}
442
443int
444ofw_bus_msimap(phandle_t node, uint16_t pci_rid, phandle_t *msi_parent,
445 uint32_t *msi_rid)
446{
447 pcell_t *map, mask, msi_base, rid_base, rid_length;
448 ssize_t len;
449 uint32_t masked_rid;
450 int err, i;
451
452 /* TODO: This should be OF_searchprop_alloc if we had it */
453 len = OF_getencprop_alloc_multi(node, "msi-map", sizeof(*map),
454 (void **)&map);
455 if (len < 0) {
456 if (msi_parent != NULL) {
457 *msi_parent = 0;
458 OF_getencprop(node, "msi-parent", msi_parent,
459 sizeof(*msi_parent));
460 }
461 if (msi_rid != NULL)
462 *msi_rid = pci_rid;
463 return (0);
464 }
465
466 err = ENOENT;
467 mask = 0xffffffff;
468 OF_getencprop(node, "msi-map-mask", &mask, sizeof(mask));
469
470 masked_rid = pci_rid & mask;
471 for (i = 0; i < len; i += 4) {
472 rid_base = map[i + 0];
473 rid_length = map[i + 3];
474
475 if (masked_rid < rid_base ||
476 masked_rid >= (rid_base + rid_length))
477 continue;
478
479 msi_base = map[i + 2];
480
481 if (msi_parent != NULL)
482 *msi_parent = map[i + 1];
483 if (msi_rid != NULL)
484 *msi_rid = masked_rid - rid_base + msi_base;
485 err = 0;
486 break;
487 }
488
489 free(map, M_OFWPROP);
490
491 return (err);
492}
493
494static int
495ofw_bus_reg_to_rl_helper(device_t dev, phandle_t node, pcell_t acells, pcell_t scells,
496 struct resource_list *rl, const char *reg_source)
497{
498 uint64_t phys, size;
499 ssize_t i, j, rid, nreg, ret;
500 uint32_t *reg;
501 char *name;
502
503 /*
504 * This may be just redundant when having ofw_bus_devinfo
505 * but makes this routine independent of it.
506 */
507 ret = OF_getprop_alloc(node, "name", (void **)&name);
508 if (ret == -1)
509 name = NULL;
510
511 ret = OF_getencprop_alloc_multi(node, reg_source, sizeof(*reg),
512 (void **)&reg);
513 nreg = (ret == -1) ? 0 : ret;
514
515 if (nreg % (acells + scells) != 0) {
516 if (bootverbose)
517 device_printf(dev, "Malformed reg property on <%s>\n",
518 (name == NULL) ? "unknown" : name);
519 nreg = 0;
520 }
521
522 for (i = 0, rid = 0; i < nreg; i += acells + scells, rid++) {
523 phys = size = 0;
524 for (j = 0; j < acells; j++) {
525 phys <<= 32;
526 phys |= reg[i + j];
527 }
528 for (j = 0; j < scells; j++) {
529 size <<= 32;
530 size |= reg[i + acells + j];
531 }
532 /* Skip the dummy reg property of glue devices like ssm(4). */
533 if (size != 0)
534 resource_list_add(rl, SYS_RES_MEMORY, rid,
535 phys, phys + size - 1, size);
536 }
537 free(name, M_OFWPROP);
538 free(reg, M_OFWPROP);
539
540 return (0);
541}
542
543int
544ofw_bus_reg_to_rl(device_t dev, phandle_t node, pcell_t acells, pcell_t scells,
545 struct resource_list *rl)
546{
547
548 return (ofw_bus_reg_to_rl_helper(dev, node, acells, scells, rl, "reg"));
549}
550
551int
553 pcell_t scells, struct resource_list *rl)
554{
555
556 return (ofw_bus_reg_to_rl_helper(dev, node, acells, scells,
557 rl, "assigned-addresses"));
558}
559
560/*
561 * Get interrupt parent for given node.
562 * Returns 0 if interrupt parent doesn't exist.
563 */
566{
568
569 if (OF_searchencprop(node, "interrupt-parent", &iparent,
570 sizeof(iparent)) == -1) {
571 for (iparent = node; iparent != 0;
573 if (OF_hasprop(iparent, "interrupt-controller"))
574 break;
575 }
577 }
578 return (iparent);
579}
580
581int
583 struct resource_list *rl, int *rlen)
584{
586 uint32_t icells, *intr;
587 int err, i, irqnum, nintr, rid;
588 boolean_t extended;
589
590 nintr = OF_getencprop_alloc_multi(node, "interrupts", sizeof(*intr),
591 (void **)&intr);
592 if (nintr > 0) {
594 if (iparent == 0) {
595 device_printf(dev, "No interrupt-parent found, "
596 "assuming direct parent\n");
597 iparent = OF_parent(node);
599 }
601 "#interrupt-cells", &icells, sizeof(icells)) == -1) {
602 device_printf(dev, "Missing #interrupt-cells "
603 "property, assuming <1>\n");
604 icells = 1;
605 }
606 if (icells < 1 || icells > nintr) {
607 device_printf(dev, "Invalid #interrupt-cells property "
608 "value <%d>, assuming <1>\n", icells);
609 icells = 1;
610 }
611 extended = false;
612 } else {
613 nintr = OF_getencprop_alloc_multi(node, "interrupts-extended",
614 sizeof(*intr), (void **)&intr);
615 if (nintr <= 0)
616 return (0);
617 extended = true;
618 }
619 err = 0;
620 rid = 0;
621 for (i = 0; i < nintr; i += icells) {
622 if (extended) {
623 iparent = intr[i++];
625 "#interrupt-cells", &icells, sizeof(icells)) == -1) {
626 device_printf(dev, "Missing #interrupt-cells "
627 "property\n");
628 err = ENOENT;
629 break;
630 }
631 if (icells < 1 || (i + icells) > nintr) {
632 device_printf(dev, "Invalid #interrupt-cells "
633 "property value <%d>\n", icells);
634 err = ERANGE;
635 break;
636 }
637 }
638 irqnum = ofw_bus_map_intr(dev, iparent, icells, &intr[i]);
639 resource_list_add(rl, SYS_RES_IRQ, rid++, irqnum, irqnum, 1);
640 }
641 if (rlen != NULL)
642 *rlen = rid;
643 free(intr, M_OFWPROP);
644 return (err);
645}
646
647int
648ofw_bus_intr_by_rid(device_t dev, phandle_t node, int wanted_rid,
649 phandle_t *producer, int *ncells, pcell_t **cells)
650{
652 uint32_t icells, *intr;
653 int err, i, nintr, rid;
654 boolean_t extended;
655
656 nintr = OF_getencprop_alloc_multi(node, "interrupts", sizeof(*intr),
657 (void **)&intr);
658 if (nintr > 0) {
660 if (iparent == 0) {
661 device_printf(dev, "No interrupt-parent found, "
662 "assuming direct parent\n");
663 iparent = OF_parent(node);
665 }
667 "#interrupt-cells", &icells, sizeof(icells)) == -1) {
668 device_printf(dev, "Missing #interrupt-cells "
669 "property, assuming <1>\n");
670 icells = 1;
671 }
672 if (icells < 1 || icells > nintr) {
673 device_printf(dev, "Invalid #interrupt-cells property "
674 "value <%d>, assuming <1>\n", icells);
675 icells = 1;
676 }
677 extended = false;
678 } else {
679 nintr = OF_getencprop_alloc_multi(node, "interrupts-extended",
680 sizeof(*intr), (void **)&intr);
681 if (nintr <= 0)
682 return (ESRCH);
683 extended = true;
684 }
685 err = ESRCH;
686 rid = 0;
687 for (i = 0; i < nintr; i += icells, rid++) {
688 if (extended) {
689 iparent = intr[i++];
691 "#interrupt-cells", &icells, sizeof(icells)) == -1) {
692 device_printf(dev, "Missing #interrupt-cells "
693 "property\n");
694 err = ENOENT;
695 break;
696 }
697 if (icells < 1 || (i + icells) > nintr) {
698 device_printf(dev, "Invalid #interrupt-cells "
699 "property value <%d>\n", icells);
700 err = ERANGE;
701 break;
702 }
703 }
704 if (rid == wanted_rid) {
705 *cells = malloc(icells * sizeof(**cells), M_OFWPROP,
706 M_WAITOK);
707 *producer = iparent;
708 *ncells= icells;
709 memcpy(*cells, intr + i, icells * sizeof(**cells));
710 err = 0;
711 break;
712 }
713 }
714 free(intr, M_OFWPROP);
715 return (err);
716}
717
719ofw_bus_find_child(phandle_t start, const char *child_name)
720{
721 char *name;
722 int ret;
724
725 for (child = OF_child(start); child != 0; child = OF_peer(child)) {
726 ret = OF_getprop_alloc(child, "name", (void **)&name);
727 if (ret == -1)
728 continue;
729 if (strcmp(name, child_name) == 0) {
730 free(name, M_OFWPROP);
731 return (child);
732 }
733
734 free(name, M_OFWPROP);
735 }
736
737 return (0);
738}
739
741ofw_bus_find_compatible(phandle_t node, const char *onecompat)
742{
743 phandle_t child, ret;
744
745 /*
746 * Traverse all children of 'start' node, and find first with
747 * matching 'compatible' property.
748 */
749 for (child = OF_child(node); child != 0; child = OF_peer(child)) {
750 if (ofw_bus_node_is_compatible(child, onecompat) != 0)
751 return (child);
752
753 ret = ofw_bus_find_compatible(child, onecompat);
754 if (ret != 0)
755 return (ret);
756 }
757 return (0);
758}
759
769device_t
771{
772 device_t *children, retval, child;
773 int nkid, i;
774
775 /*
776 * Nothing can match the flag value for no node.
777 */
778 if (node == -1)
779 return (NULL);
780
781 /*
782 * Search the children for a match. We microoptimize
783 * a bit by not using ofw_bus_get since we already know
784 * the parent. We do not recurse.
785 */
786 if (device_get_children(bus, &children, &nkid) != 0)
787 return (NULL);
788 retval = NULL;
789 for (i = 0; i < nkid; i++) {
790 child = children[i];
791 if (OFW_BUS_GET_NODE(bus, child) == node) {
792 retval = child;
793 break;
794 }
795 }
796 free(children, M_TEMP);
797
798 return (retval);
799}
800
801/*
802 * Parse property that contain list of xrefs and values
803 * (like standard "clocks" and "resets" properties)
804 * Input arguments:
805 * node - consumers device node
806 * list_name - name of parsed list - "clocks"
807 * cells_name - name of size property - "#clock-cells"
808 * idx - the index of the requested list entry, or, if -1, an indication
809 * to return the number of entries in the parsed list.
810 * Output arguments:
811 * producer - handle of producer
812 * ncells - number of cells in result or the number of items in the list when
813 * idx == -1.
814 * cells - array of decoded cells
815 */
816static int
817ofw_bus_parse_xref_list_internal(phandle_t node, const char *list_name,
818 const char *cells_name, int idx, phandle_t *producer, int *ncells,
819 pcell_t **cells)
820{
821 phandle_t pnode;
822 phandle_t *elems;
823 uint32_t pcells;
824 int rv, i, j, nelems, cnt;
825
826 elems = NULL;
827 nelems = OF_getencprop_alloc_multi(node, list_name, sizeof(*elems),
828 (void **)&elems);
829 if (nelems <= 0)
830 return (ENOENT);
831 rv = (idx == -1) ? 0 : ENOENT;
832 for (i = 0, cnt = 0; i < nelems; i += pcells, cnt++) {
833 pnode = elems[i++];
835 cells_name, &pcells, sizeof(pcells)) == -1) {
836 printf("Missing %s property\n", cells_name);
837 rv = ENOENT;
838 break;
839 }
840
841 if ((i + pcells) > nelems) {
842 printf("Invalid %s property value <%d>\n", cells_name,
843 pcells);
844 rv = ERANGE;
845 break;
846 }
847 if (cnt == idx) {
848 *cells= malloc(pcells * sizeof(**cells), M_OFWPROP,
849 M_WAITOK);
850 *producer = pnode;
851 *ncells = pcells;
852 for (j = 0; j < pcells; j++)
853 (*cells)[j] = elems[i + j];
854 rv = 0;
855 break;
856 }
857 }
858 if (elems != NULL)
859 free(elems, M_OFWPROP);
860 if (idx == -1 && rv == 0)
861 *ncells = cnt;
862 return (rv);
863}
864
865/*
866 * Parse property that contain list of xrefs and values
867 * (like standard "clocks" and "resets" properties)
868 * Input arguments:
869 * node - consumers device node
870 * list_name - name of parsed list - "clocks"
871 * cells_name - name of size property - "#clock-cells"
872 * idx - the index of the requested list entry (>= 0)
873 * Output arguments:
874 * producer - handle of producer
875 * ncells - number of cells in result
876 * cells - array of decoded cells
877 */
878int
879ofw_bus_parse_xref_list_alloc(phandle_t node, const char *list_name,
880 const char *cells_name, int idx, phandle_t *producer, int *ncells,
881 pcell_t **cells)
882{
883
884 KASSERT(idx >= 0,
885 ("ofw_bus_parse_xref_list_alloc: negative index supplied"));
886
887 return (ofw_bus_parse_xref_list_internal(node, list_name, cells_name,
888 idx, producer, ncells, cells));
889}
890
891/*
892 * Parse property that contain list of xrefs and values
893 * (like standard "clocks" and "resets" properties)
894 * and determine the number of items in the list
895 * Input arguments:
896 * node - consumers device node
897 * list_name - name of parsed list - "clocks"
898 * cells_name - name of size property - "#clock-cells"
899 * Output arguments:
900 * count - number of items in list
901 */
902int
904 const char *cells_name, int *count)
905{
906
907 return (ofw_bus_parse_xref_list_internal(node, list_name, cells_name,
908 -1, NULL, count, NULL));
909}
910
911/*
912 * Find index of string in string list property (case sensitive).
913 */
914int
915ofw_bus_find_string_index(phandle_t node, const char *list_name,
916 const char *name, int *idx)
917{
918 char *elems;
919 int rv, i, cnt, nelems;
920
921 elems = NULL;
922 nelems = OF_getprop_alloc(node, list_name, (void **)&elems);
923 if (nelems <= 0)
924 return (ENOENT);
925
926 rv = ENOENT;
927 for (i = 0, cnt = 0; i < nelems; cnt++) {
928 if (strcmp(elems + i, name) == 0) {
929 *idx = cnt;
930 rv = 0;
931 break;
932 }
933 i += strlen(elems + i) + 1;
934 }
935
936 if (elems != NULL)
937 free(elems, M_OFWPROP);
938 return (rv);
939}
940
941/*
942 * Create zero terminated array of strings from string list property.
943 */
944int
945ofw_bus_string_list_to_array(phandle_t node, const char *list_name,
946 const char ***out_array)
947{
948 char *elems, *tptr;
949 const char **array;
950 int i, cnt, nelems, len;
951
952 elems = NULL;
953 nelems = OF_getprop_alloc(node, list_name, (void **)&elems);
954 if (nelems <= 0)
955 return (nelems);
956
957 /* Count number of strings. */
958 for (i = 0, cnt = 0; i < nelems; cnt++)
959 i += strlen(elems + i) + 1;
960
961 /* Allocate space for arrays and all strings. */
962 array = malloc((cnt + 1) * sizeof(char *) + nelems, M_OFWPROP,
963 M_WAITOK);
964
965 /* Get address of first string. */
966 tptr = (char *)(array + cnt + 1);
967
968 /* Copy strings. */
969 memcpy(tptr, elems, nelems);
970 free(elems, M_OFWPROP);
971
972 /* Fill string pointers. */
973 for (i = 0, cnt = 0; i < nelems; cnt++) {
974 len = strlen(tptr) + 1;
975 array[cnt] = tptr;
976 i += len;
977 tptr += len;
978 }
979 array[cnt] = NULL;
980 *out_array = array;
981
982 return (cnt);
983}
METHOD phandle_t parent
Return parent of node.
Definition: ofw_if.m:66
size_t size
Definition: ofw_if.m:283
METHOD phandle_t child
Return first child of node.
Definition: ofw_if.m:76
static __inline phandle_t ofw_bus_get_node(device_t dev)
Definition: ofw_bus.h:62
static __inline int ofw_bus_map_intr(device_t dev, phandle_t iparent, int icells, pcell_t *intr)
Definition: ofw_bus.h:76
static __inline const char * ofw_bus_get_compat(device_t dev)
Definition: ofw_bus.h:41
static __inline const char * ofw_bus_get_name(device_t dev)
Definition: ofw_bus.h:55
device_t dev
Definition: ofw_bus_if.m:124
int icells
Definition: ofw_bus_if.m:169
phandle_t iparent
Definition: ofw_bus_if.m:168
static int ofw_bus_node_is_compatible_int(const char *compat, int len, const char *onecompat)
Definition: ofw_bus_subr.c:206
int ofw_bus_node_is_compatible(phandle_t node, const char *compatstr)
Definition: ofw_bus_subr.c:232
static int ofw_bus_reg_to_rl_helper(device_t dev, phandle_t node, pcell_t acells, pcell_t scells, struct resource_list *rl, const char *reg_source)
Definition: ofw_bus_subr.c:495
int ofw_bus_msimap(phandle_t node, uint16_t pci_rid, phandle_t *msi_parent, uint32_t *msi_rid)
Definition: ofw_bus_subr.c:444
int ofw_bus_reg_to_rl(device_t dev, phandle_t node, pcell_t acells, pcell_t scells, struct resource_list *rl)
Definition: ofw_bus_subr.c:544
int ofw_bus_parse_xref_list_get_length(phandle_t node, const char *list_name, const char *cells_name, int *count)
Definition: ofw_bus_subr.c:903
const char * ofw_bus_get_status(device_t dev)
Definition: ofw_bus_subr.c:163
phandle_t ofw_bus_gen_get_node(device_t bus, device_t dev)
Definition: ofw_bus_subr.c:141
int ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz, void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result, int rintrsz, phandle_t *iparent)
Definition: ofw_bus_subr.c:379
static int ofw_bus_parse_xref_list_internal(phandle_t node, const char *list_name, const char *cells_name, int idx, phandle_t *producer, int *ncells, pcell_t **cells)
Definition: ofw_bus_subr.c:817
int ofw_bus_is_compatible(device_t dev, const char *onecompat)
Definition: ofw_bus_subr.c:251
const char * ofw_bus_gen_get_compat(device_t bus, device_t dev)
Definition: ofw_bus_subr.c:108
int ofw_bus_string_list_to_array(phandle_t node, const char *list_name, const char ***out_array)
Definition: ofw_bus_subr.c:945
int ofw_bus_node_status_okay(phandle_t node)
Definition: ofw_bus_subr.c:188
#define OFW_COMPAT_LEN
Definition: ofw_bus_subr.c:51
int ofw_bus_has_prop(device_t dev, const char *propname)
Definition: ofw_bus_subr.c:303
const char * ofw_bus_gen_get_name(device_t bus, device_t dev)
Definition: ofw_bus_subr.c:130
void ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz)
Definition: ofw_bus_subr.c:314
int ofw_bus_intr_to_rl(device_t dev, phandle_t node, struct resource_list *rl, int *rlen)
Definition: ofw_bus_subr.c:582
int ofw_bus_parse_xref_list_alloc(phandle_t node, const char *list_name, const char *cells_name, int idx, phandle_t *producer, int *ncells, pcell_t **cells)
Definition: ofw_bus_subr.c:879
__FBSDID("$FreeBSD$")
#define OFW_STATUS_LEN
Definition: ofw_bus_subr.c:52
int ofw_bus_status_okay(device_t dev)
Definition: ofw_bus_subr.c:175
int ofw_bus_is_compatible_strict(device_t dev, const char *compatible)
Definition: ofw_bus_subr.c:271
void ofw_bus_gen_destroy_devinfo(struct ofw_bus_devinfo *obd)
Definition: ofw_bus_subr.c:72
const struct ofw_compat_data * ofw_bus_search_compatible(device_t dev, const struct ofw_compat_data *compat)
Definition: ofw_bus_subr.c:288
int ofw_bus_gen_setup_devinfo(struct ofw_bus_devinfo *obd, phandle_t node)
Definition: ofw_bus_subr.c:55
phandle_t ofw_bus_find_compatible(phandle_t node, const char *onecompat)
Definition: ofw_bus_subr.c:741
const char * ofw_bus_gen_get_model(device_t bus, device_t dev)
Definition: ofw_bus_subr.c:119
device_t ofw_bus_find_child_device_by_phandle(device_t bus, phandle_t node)
Return child of bus whose phandle is node.
Definition: ofw_bus_subr.c:770
int ofw_bus_gen_child_pnpinfo(device_t cbdev, device_t child, struct sbuf *sb)
Definition: ofw_bus_subr.c:90
int ofw_bus_intr_by_rid(device_t dev, phandle_t node, int wanted_rid, phandle_t *producer, int *ncells, pcell_t **cells)
Definition: ofw_bus_subr.c:648
const char * ofw_bus_gen_get_type(device_t bus, device_t dev)
Definition: ofw_bus_subr.c:152
phandle_t ofw_bus_find_child(phandle_t start, const char *child_name)
Definition: ofw_bus_subr.c:719
phandle_t ofw_bus_find_iparent(phandle_t node)
Definition: ofw_bus_subr.c:565
int ofw_bus_find_string_index(phandle_t node, const char *list_name, const char *name, int *idx)
Definition: ofw_bus_subr.c:915
int ofw_bus_lookup_imap(phandle_t node, struct ofw_bus_iinfo *ii, void *reg, int regsz, void *pintr, int pintrsz, void *mintr, int mintrsz, phandle_t *iparent)
Definition: ofw_bus_subr.c:339
int ofw_bus_assigned_addresses_to_rl(device_t dev, phandle_t node, pcell_t acells, pcell_t scells, struct resource_list *rl)
Definition: ofw_bus_subr.c:552
ssize_t OF_getencprop_alloc(phandle_t package, const char *name, void **buf)
Definition: openfirm.c:492
ssize_t OF_getencprop_alloc_multi(phandle_t package, const char *name, int elsz, void **buf)
Definition: openfirm.c:505
phandle_t OF_node_from_xref(phandle_t xref)
Definition: openfirm.c:627
ssize_t OF_searchencprop(phandle_t node, const char *propname, pcell_t *buf, size_t len)
Definition: openfirm.c:431
phandle_t OF_peer(phandle_t node)
Definition: openfirm.c:324
phandle_t OF_xref_from_node(phandle_t node)
Definition: openfirm.c:644
ssize_t OF_getproplen(phandle_t package, const char *propname)
Definition: openfirm.c:368
phandle_t OF_parent(phandle_t node)
Definition: openfirm.c:346
ssize_t OF_getencprop(phandle_t node, const char *propname, pcell_t *buf, size_t len)
Definition: openfirm.c:397
int OF_hasprop(phandle_t package, const char *propname)
Definition: openfirm.c:379
ssize_t OF_getprop_alloc(phandle_t package, const char *propname, void **buf)
Definition: openfirm.c:446
phandle_t OF_child(phandle_t node)
Definition: openfirm.c:335
ssize_t OF_getprop(phandle_t package, const char *propname, void *buf, size_t buflen)
Definition: openfirm.c:387
uint32_t phandle_t
Definition: openfirm.h:73
uint32_t pcell_t
Definition: openfirm.h:74
uint8_t * opi_imap
Definition: ofw_bus_subr.h:48
uint8_t * opi_imapmsk
Definition: ofw_bus_subr.h:49
pcell_t opi_addrc
Definition: ofw_bus_subr.h:51
const char * ocd_str
Definition: ofw_bus_subr.h:55