ofwbus.c revision 269597
1168561Sthompsa/*- 2168561Sthompsa * Copyright 1998 Massachusetts Institute of Technology 3168561Sthompsa * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. 4168561Sthompsa * Copyright 2006 by Marius Strobl <marius@FreeBSD.org>. 5168561Sthompsa * All rights reserved. 6168561Sthompsa * 7168561Sthompsa * Permission to use, copy, modify, and distribute this software and 8168561Sthompsa * its documentation for any purpose and without fee is hereby 9168561Sthompsa * granted, provided that both the above copyright notice and this 10168561Sthompsa * permission notice appear in all copies, that both the above 11168561Sthompsa * copyright notice and this permission notice appear in all 12168561Sthompsa * supporting documentation, and that the name of M.I.T. not be used 13168561Sthompsa * in advertising or publicity pertaining to distribution of the 14168561Sthompsa * software without specific, written prior permission. M.I.T. makes 15168561Sthompsa * no representations about the suitability of this software for any 16168561Sthompsa * purpose. It is provided "as is" without express or implied 17168561Sthompsa * warranty. 18168561Sthompsa * 19168561Sthompsa * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 20168561Sthompsa * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 21168561Sthompsa * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 22168561Sthompsa * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 23168561Sthompsa * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24168561Sthompsa * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25168561Sthompsa * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 26168561Sthompsa * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27168561Sthompsa * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28168561Sthompsa * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 29168561Sthompsa * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30168561Sthompsa * SUCH DAMAGE. 31168561Sthompsa * 32168561Sthompsa * from: FreeBSD: src/sys/i386/i386/nexus.c,v 1.43 2001/02/09 33168561Sthompsa */ 34168561Sthompsa 35168561Sthompsa#include <sys/cdefs.h> 36168561Sthompsa__FBSDID("$FreeBSD: head/sys/dev/ofw/ofwbus.c 269597 2014-08-05 17:32:47Z ian $"); 37168561Sthompsa 38168561Sthompsa#include <sys/param.h> 39168561Sthompsa#include <sys/systm.h> 40168561Sthompsa#include <sys/bus.h> 41169569Sthompsa#include <sys/kernel.h> 42169569Sthompsa#include <sys/malloc.h> 43169569Sthompsa#include <sys/module.h> 44168561Sthompsa#include <sys/pcpu.h> 45168561Sthompsa#include <sys/rman.h> 46168561Sthompsa 47168561Sthompsa#include <vm/vm.h> 48168561Sthompsa#include <vm/pmap.h> 49168561Sthompsa 50168561Sthompsa#include <dev/ofw/ofw_bus.h> 51168793Sthompsa#include <dev/ofw/ofw_bus_subr.h> 52168561Sthompsa#include <dev/ofw/openfirm.h> 53168561Sthompsa 54168561Sthompsa#include <machine/bus.h> 55168561Sthompsa#include <machine/resource.h> 56168561Sthompsa 57168561Sthompsa/* 58168561Sthompsa * The ofwbus (which is a pseudo-bus actually) iterates over the nodes that 59168561Sthompsa * hang from the Open Firmware root node and adds them as devices to this bus 60168561Sthompsa * (except some special nodes which are excluded) so that drivers can be 61168561Sthompsa * attached to them. 62168561Sthompsa * 63168561Sthompsa */ 64168561Sthompsa 65168561Sthompsastruct ofwbus_devinfo { 66168561Sthompsa struct ofw_bus_devinfo ndi_obdinfo; 67168561Sthompsa struct resource_list ndi_rl; 68168561Sthompsa}; 69168561Sthompsa 70168561Sthompsastruct ofwbus_softc { 71168561Sthompsa uint32_t acells, scells; 72168561Sthompsa struct rman sc_intr_rman; 73168561Sthompsa struct rman sc_mem_rman; 74168561Sthompsa}; 75168561Sthompsa 76168561Sthompsastatic device_identify_t ofwbus_identify; 77168561Sthompsastatic device_probe_t ofwbus_probe; 78169739Sthompsastatic device_attach_t ofwbus_attach; 79169739Sthompsastatic bus_print_child_t ofwbus_print_child; 80168561Sthompsastatic bus_add_child_t ofwbus_add_child; 81168561Sthompsastatic bus_probe_nomatch_t ofwbus_probe_nomatch; 82168561Sthompsastatic bus_alloc_resource_t ofwbus_alloc_resource; 83168561Sthompsastatic bus_adjust_resource_t ofwbus_adjust_resource; 84169739Sthompsastatic bus_release_resource_t ofwbus_release_resource; 85169739Sthompsastatic bus_get_resource_list_t ofwbus_get_resource_list; 86168561Sthompsastatic ofw_bus_get_devinfo_t ofwbus_get_devinfo; 87168561Sthompsa 88168561Sthompsastatic int ofwbus_inlist(const char *, const char *const *); 89168561Sthompsastatic struct ofwbus_devinfo * ofwbus_setup_dinfo(device_t, phandle_t); 90169739Sthompsastatic void ofwbus_destroy_dinfo(struct ofwbus_devinfo *); 91169739Sthompsastatic int ofwbus_print_res(struct ofwbus_devinfo *); 92168561Sthompsa 93168561Sthompsastatic device_method_t ofwbus_methods[] = { 94168561Sthompsa /* Device interface */ 95168561Sthompsa DEVMETHOD(device_identify, ofwbus_identify), 96168561Sthompsa DEVMETHOD(device_probe, ofwbus_probe), 97168561Sthompsa DEVMETHOD(device_attach, ofwbus_attach), 98168561Sthompsa DEVMETHOD(device_detach, bus_generic_detach), 99168561Sthompsa DEVMETHOD(device_shutdown, bus_generic_shutdown), 100168561Sthompsa DEVMETHOD(device_suspend, bus_generic_suspend), 101168561Sthompsa DEVMETHOD(device_resume, bus_generic_resume), 102168561Sthompsa 103168561Sthompsa /* Bus interface */ 104168561Sthompsa DEVMETHOD(bus_print_child, ofwbus_print_child), 105168561Sthompsa DEVMETHOD(bus_probe_nomatch, ofwbus_probe_nomatch), 106168561Sthompsa DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), 107168561Sthompsa DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), 108168561Sthompsa DEVMETHOD(bus_add_child, ofwbus_add_child), 109168561Sthompsa DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), 110168561Sthompsa DEVMETHOD(bus_alloc_resource, ofwbus_alloc_resource), 111168561Sthompsa DEVMETHOD(bus_adjust_resource, ofwbus_adjust_resource), 112168561Sthompsa DEVMETHOD(bus_release_resource, ofwbus_release_resource), 113168561Sthompsa DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 114168561Sthompsa DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 115168561Sthompsa DEVMETHOD(bus_get_resource_list, ofwbus_get_resource_list), 116168561Sthompsa DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 117168561Sthompsa DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 118168561Sthompsa DEVMETHOD(bus_config_intr, bus_generic_config_intr), 119168561Sthompsa DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 120168561Sthompsa DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 121169569Sthompsa 122169569Sthompsa /* ofw_bus interface */ 123169569Sthompsa DEVMETHOD(ofw_bus_get_devinfo, ofwbus_get_devinfo), 124168561Sthompsa DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 125168561Sthompsa DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 126168561Sthompsa DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 127168561Sthompsa DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 128168561Sthompsa DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 129168561Sthompsa 130168561Sthompsa DEVMETHOD_END 131168561Sthompsa}; 132168561Sthompsa 133168561Sthompsastatic driver_t ofwbus_driver = { 134168561Sthompsa "ofwbus", 135168561Sthompsa ofwbus_methods, 136168561Sthompsa sizeof(struct ofwbus_softc) 137168561Sthompsa}; 138168561Sthompsastatic devclass_t ofwbus_devclass; 139168561SthompsaEARLY_DRIVER_MODULE(ofwbus, nexus, ofwbus_driver, ofwbus_devclass, 0, 0, 140168561Sthompsa BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 141168561SthompsaMODULE_VERSION(ofwbus, 1); 142168561Sthompsa 143168561Sthompsastatic const char *const ofwbus_excl_name[] = { 144168561Sthompsa "FJSV,system", 145168561Sthompsa "aliases", 146168561Sthompsa "associations", 147168561Sthompsa "chosen", 148168561Sthompsa "cmp", 149168561Sthompsa "counter-timer", /* No separate device; handled by psycho/sbus */ 150168561Sthompsa "failsafe", 151168561Sthompsa "memory", 152168561Sthompsa "openprom", 153168561Sthompsa "options", 154168561Sthompsa "packages", 155168561Sthompsa "physical-memory", 156168561Sthompsa "rsc", 157168561Sthompsa "sgcn", 158168561Sthompsa "todsg", 159168561Sthompsa "virtual-memory", 160168561Sthompsa NULL 161168561Sthompsa}; 162168561Sthompsa 163168561Sthompsastatic const char *const ofwbus_excl_type[] = { 164168561Sthompsa "core", 165168561Sthompsa "cpu", 166168561Sthompsa NULL 167168561Sthompsa}; 168168561Sthompsa 169169739Sthompsastatic int 170168561Sthompsaofwbus_inlist(const char *name, const char *const *list) 171168561Sthompsa{ 172168561Sthompsa int i; 173168561Sthompsa 174168561Sthompsa if (name == NULL) 175168561Sthompsa return (0); 176168561Sthompsa for (i = 0; list[i] != NULL; i++) 177168561Sthompsa if (strcmp(name, list[i]) == 0) 178168561Sthompsa return (1); 179168561Sthompsa return (0); 180168561Sthompsa} 181168561Sthompsa 182168561Sthompsa#define OFWBUS_EXCLUDED(name, type) \ 183168561Sthompsa (ofwbus_inlist((name), ofwbus_excl_name) || \ 184168561Sthompsa ((type) != NULL && ofwbus_inlist((type), ofwbus_excl_type))) 185168561Sthompsa 186168561Sthompsastatic void 187168561Sthompsaofwbus_identify(driver_t *driver, device_t parent) 188168561Sthompsa{ 189168561Sthompsa 190168561Sthompsa /* Check if Open Firmware has been instantiated */ 191168561Sthompsa if (OF_peer(0) == 0) 192168561Sthompsa return; 193168561Sthompsa 194168561Sthompsa if (device_find_child(parent, "ofwbus", -1) == NULL) 195168561Sthompsa BUS_ADD_CHILD(parent, 0, "ofwbus", -1); 196168561Sthompsa} 197168561Sthompsa 198168561Sthompsastatic int 199168561Sthompsaofwbus_probe(device_t dev) 200168561Sthompsa{ 201168561Sthompsa 202168561Sthompsa device_set_desc(dev, "Open Firmware Device Tree"); 203168561Sthompsa return (BUS_PROBE_NOWILDCARD); 204168561Sthompsa} 205168561Sthompsa 206168561Sthompsastatic int 207168561Sthompsaofwbus_attach(device_t dev) 208168561Sthompsa{ 209168561Sthompsa struct ofwbus_devinfo *ndi; 210168561Sthompsa struct ofwbus_softc *sc; 211168561Sthompsa device_t cdev; 212168561Sthompsa phandle_t node; 213168561Sthompsa 214168561Sthompsa sc = device_get_softc(dev); 215168561Sthompsa 216169569Sthompsa node = OF_peer(0); 217169569Sthompsa 218169569Sthompsa /* 219170599Sthompsa * If no Open Firmware, bail early 220170599Sthompsa */ 221169569Sthompsa if (node == -1) 222169569Sthompsa return (ENXIO); 223169569Sthompsa 224169569Sthompsa sc->sc_intr_rman.rm_type = RMAN_ARRAY; 225169569Sthompsa sc->sc_intr_rman.rm_descr = "Interrupts"; 226169569Sthompsa sc->sc_mem_rman.rm_type = RMAN_ARRAY; 227169569Sthompsa sc->sc_mem_rman.rm_descr = "Device Memory"; 228169569Sthompsa if (rman_init(&sc->sc_intr_rman) != 0 || 229169569Sthompsa rman_init(&sc->sc_mem_rman) != 0 || 230169569Sthompsa rman_manage_region(&sc->sc_intr_rman, 0, ~0) != 0 || 231169569Sthompsa rman_manage_region(&sc->sc_mem_rman, 0, BUS_SPACE_MAXADDR) != 0) 232169569Sthompsa panic("%s: failed to set up rmans.", __func__); 233169569Sthompsa 234169569Sthompsa /* 235169569Sthompsa * Allow devices to identify. 236169569Sthompsa */ 237169569Sthompsa bus_generic_probe(dev); 238169569Sthompsa 239169569Sthompsa /* 240169569Sthompsa * Some important numbers 241169569Sthompsa */ 242169569Sthompsa sc->acells = 2; 243169569Sthompsa OF_getencprop(node, "#address-cells", &sc->acells, sizeof(sc->acells)); 244169569Sthompsa sc->scells = 1; 245169569Sthompsa OF_getencprop(node, "#size-cells", &sc->scells, sizeof(sc->scells)); 246169569Sthompsa 247169569Sthompsa /* 248169569Sthompsa * Now walk the OFW tree and attach top-level devices. 249169569Sthompsa */ 250170599Sthompsa for (node = OF_child(node); node > 0; node = OF_peer(node)) { 251169569Sthompsa if ((ndi = ofwbus_setup_dinfo(dev, node)) == NULL) 252169569Sthompsa continue; 253169569Sthompsa cdev = device_add_child(dev, NULL, -1); 254169569Sthompsa if (cdev == NULL) { 255169569Sthompsa device_printf(dev, "<%s>: device_add_child failed\n", 256169569Sthompsa ndi->ndi_obdinfo.obd_name); 257169569Sthompsa ofwbus_destroy_dinfo(ndi); 258169569Sthompsa continue; 259169569Sthompsa } 260169569Sthompsa device_set_ivars(cdev, ndi); 261169569Sthompsa } 262169569Sthompsa return (bus_generic_attach(dev)); 263169569Sthompsa} 264169569Sthompsa 265168561Sthompsastatic device_t 266169569Sthompsaofwbus_add_child(device_t dev, u_int order, const char *name, int unit) 267168561Sthompsa{ 268169569Sthompsa device_t cdev; 269169569Sthompsa struct ofwbus_devinfo *ndi; 270168561Sthompsa 271168793Sthompsa cdev = device_add_child_ordered(dev, order, name, unit); 272168561Sthompsa if (cdev == NULL) 273168561Sthompsa return (NULL); 274168561Sthompsa 275170599Sthompsa ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); 276168561Sthompsa ndi->ndi_obdinfo.obd_node = -1; 277168561Sthompsa resource_list_init(&ndi->ndi_rl); 278168561Sthompsa device_set_ivars(cdev, ndi); 279168561Sthompsa 280168561Sthompsa return (cdev); 281168561Sthompsa} 282168561Sthompsa 283168561Sthompsastatic int 284168561Sthompsaofwbus_print_child(device_t bus, device_t child) 285168561Sthompsa{ 286168561Sthompsa int rv; 287168561Sthompsa 288168561Sthompsa rv = bus_print_child_header(bus, child); 289168561Sthompsa rv += ofwbus_print_res(device_get_ivars(child)); 290168561Sthompsa rv += bus_print_child_footer(bus, child); 291168561Sthompsa return (rv); 292168561Sthompsa} 293168561Sthompsa 294168561Sthompsastatic void 295168561Sthompsaofwbus_probe_nomatch(device_t bus, device_t child) 296168561Sthompsa{ 297168561Sthompsa const char *name, *type; 298168561Sthompsa 299168561Sthompsa if (!bootverbose) 300168561Sthompsa return; 301168561Sthompsa 302168561Sthompsa name = ofw_bus_get_name(child); 303168561Sthompsa type = ofw_bus_get_type(child); 304168561Sthompsa 305168561Sthompsa device_printf(bus, "<%s>", 306168561Sthompsa name != NULL ? name : "unknown"); 307168561Sthompsa ofwbus_print_res(device_get_ivars(child)); 308168561Sthompsa printf(" type %s (no driver attached)\n", 309168561Sthompsa type != NULL ? type : "unknown"); 310168561Sthompsa} 311168561Sthompsa 312168561Sthompsastatic struct resource * 313168561Sthompsaofwbus_alloc_resource(device_t bus, device_t child, int type, int *rid, 314168561Sthompsa u_long start, u_long end, u_long count, u_int flags) 315168561Sthompsa{ 316168561Sthompsa struct ofwbus_softc *sc; 317168561Sthompsa struct rman *rm; 318168561Sthompsa struct resource *rv; 319168561Sthompsa struct resource_list_entry *rle; 320168561Sthompsa int isdefault, passthrough; 321168561Sthompsa 322168561Sthompsa isdefault = (start == 0UL && end == ~0UL); 323168561Sthompsa passthrough = (device_get_parent(child) != bus); 324168561Sthompsa sc = device_get_softc(bus); 325168561Sthompsa rle = NULL; 326168561Sthompsa 327168561Sthompsa if (!passthrough && isdefault) { 328168561Sthompsa rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child), 329168561Sthompsa type, *rid); 330168561Sthompsa if (rle == NULL) 331168561Sthompsa return (NULL); 332168561Sthompsa if (rle->res != NULL) 333168561Sthompsa panic("%s: resource entry is busy", __func__); 334168561Sthompsa start = rle->start; 335168561Sthompsa count = ulmax(count, rle->count); 336168793Sthompsa end = ulmax(rle->end, start + count - 1); 337170599Sthompsa } 338168561Sthompsa 339168561Sthompsa switch (type) { 340168561Sthompsa case SYS_RES_IRQ: 341170599Sthompsa rm = &sc->sc_intr_rman; 342168561Sthompsa break; 343168561Sthompsa case SYS_RES_MEMORY: 344168561Sthompsa rm = &sc->sc_mem_rman; 345168561Sthompsa break; 346168561Sthompsa default: 347169739Sthompsa return (NULL); 348169739Sthompsa } 349169739Sthompsa 350169739Sthompsa rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, 351169739Sthompsa child); 352169739Sthompsa if (rv == NULL) 353169739Sthompsa return (NULL); 354169739Sthompsa rman_set_rid(rv, *rid); 355169739Sthompsa 356169739Sthompsa if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, 357169739Sthompsa *rid, rv) != 0) { 358168561Sthompsa rman_release_resource(rv); 359168561Sthompsa return (NULL); 360168561Sthompsa } 361168793Sthompsa 362168561Sthompsa if (!passthrough && rle != NULL) { 363168561Sthompsa rle->res = rv; 364168561Sthompsa rle->start = rman_get_start(rv); 365168561Sthompsa rle->end = rman_get_end(rv); 366170599Sthompsa rle->count = rle->end - rle->start + 1; 367168561Sthompsa } 368168561Sthompsa 369168561Sthompsa return (rv); 370168561Sthompsa} 371168561Sthompsa 372168561Sthompsastatic int 373168561Sthompsaofwbus_adjust_resource(device_t bus, device_t child __unused, int type, 374168561Sthompsa struct resource *r, u_long start, u_long end) 375168561Sthompsa{ 376168561Sthompsa struct ofwbus_softc *sc; 377168561Sthompsa struct rman *rm; 378168561Sthompsa device_t ofwbus; 379168793Sthompsa 380168561Sthompsa ofwbus = bus; 381168561Sthompsa while (strcmp(device_get_name(device_get_parent(ofwbus)), "root") != 0) 382168561Sthompsa ofwbus = device_get_parent(ofwbus); 383168561Sthompsa sc = device_get_softc(ofwbus); 384168561Sthompsa switch (type) { 385168561Sthompsa case SYS_RES_IRQ: 386168561Sthompsa rm = &sc->sc_intr_rman; 387168561Sthompsa break; 388168561Sthompsa case SYS_RES_MEMORY: 389168561Sthompsa rm = &sc->sc_mem_rman; 390168561Sthompsa break; 391168561Sthompsa default: 392168561Sthompsa return (EINVAL); 393168561Sthompsa } 394168561Sthompsa if (rm == NULL) 395168561Sthompsa return (ENXIO); 396168561Sthompsa if (rman_is_region_manager(r, rm) == 0) 397168561Sthompsa return (EINVAL); 398168561Sthompsa return (rman_adjust_resource(r, start, end)); 399168561Sthompsa} 400168561Sthompsa 401168561Sthompsastatic int 402168561Sthompsaofwbus_release_resource(device_t bus __unused, device_t child, int type, 403168561Sthompsa int rid, struct resource *r) 404168561Sthompsa{ 405168561Sthompsa int error; 406168561Sthompsa 407168561Sthompsa if ((rman_get_flags(r) & RF_ACTIVE) != 0) { 408168793Sthompsa error = bus_deactivate_resource(child, type, rid, r); 409168561Sthompsa if (error) 410168561Sthompsa return (error); 411168561Sthompsa } 412169739Sthompsa return (rman_release_resource(r)); 413169739Sthompsa} 414169739Sthompsa 415169739Sthompsastatic struct resource_list * 416169739Sthompsaofwbus_get_resource_list(device_t bus __unused, device_t child) 417169739Sthompsa{ 418169739Sthompsa struct ofwbus_devinfo *ndi; 419169739Sthompsa 420170599Sthompsa ndi = device_get_ivars(child); 421169739Sthompsa return (&ndi->ndi_rl); 422169739Sthompsa} 423169739Sthompsa 424169739Sthompsastatic const struct ofw_bus_devinfo * 425169739Sthompsaofwbus_get_devinfo(device_t bus __unused, device_t child) 426169739Sthompsa{ 427169739Sthompsa struct ofwbus_devinfo *ndi; 428169739Sthompsa 429169739Sthompsa ndi = device_get_ivars(child); 430169739Sthompsa return (&ndi->ndi_obdinfo); 431169739Sthompsa} 432169739Sthompsa 433169739Sthompsastatic struct ofwbus_devinfo * 434169739Sthompsaofwbus_setup_dinfo(device_t dev, phandle_t node) 435169739Sthompsa{ 436169739Sthompsa struct ofwbus_softc *sc; 437169739Sthompsa struct ofwbus_devinfo *ndi; 438169739Sthompsa uint32_t *reg, *intr, icells; 439169739Sthompsa uint64_t phys, size; 440169739Sthompsa phandle_t iparent; 441169739Sthompsa int i, j; 442169739Sthompsa int nintr; 443169739Sthompsa int nreg; 444169739Sthompsa 445169739Sthompsa sc = device_get_softc(dev); 446169739Sthompsa 447169739Sthompsa ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); 448169739Sthompsa if (ofw_bus_gen_setup_devinfo(&ndi->ndi_obdinfo, node) != 0) { 449169739Sthompsa free(ndi, M_DEVBUF); 450169739Sthompsa return (NULL); 451169739Sthompsa } 452168561Sthompsa if (OFWBUS_EXCLUDED(ndi->ndi_obdinfo.obd_name, 453168793Sthompsa ndi->ndi_obdinfo.obd_type)) { 454168561Sthompsa ofw_bus_gen_destroy_devinfo(&ndi->ndi_obdinfo); 455168793Sthompsa free(ndi, M_DEVBUF); 456168793Sthompsa return (NULL); 457168561Sthompsa } 458168561Sthompsa 459168561Sthompsa resource_list_init(&ndi->ndi_rl); 460168561Sthompsa nreg = OF_getencprop_alloc(node, "reg", sizeof(*reg), (void **)®); 461168561Sthompsa if (nreg == -1) 462168561Sthompsa nreg = 0; 463170599Sthompsa if (nreg % (sc->acells + sc->scells) != 0) { 464168561Sthompsa if (bootverbose) 465168561Sthompsa device_printf(dev, "Malformed reg property on <%s>\n", 466168561Sthompsa ndi->ndi_obdinfo.obd_name); 467168561Sthompsa nreg = 0; 468168561Sthompsa } 469168561Sthompsa 470168561Sthompsa for (i = 0; i < nreg; i += sc->acells + sc->scells) { 471169227Sthompsa phys = size = 0; 472169227Sthompsa for (j = 0; j < sc->acells; j++) { 473169227Sthompsa phys <<= 32; 474168561Sthompsa phys |= reg[i + j]; 475168561Sthompsa } 476168561Sthompsa for (j = 0; j < sc->scells; j++) { 477168561Sthompsa size <<= 32; 478170599Sthompsa size |= reg[i + sc->acells + j]; 479169227Sthompsa } 480169227Sthompsa /* Skip the dummy reg property of glue devices like ssm(4). */ 481169227Sthompsa if (size != 0) 482169227Sthompsa resource_list_add(&ndi->ndi_rl, SYS_RES_MEMORY, i, 483169227Sthompsa phys, phys + size - 1, size); 484168561Sthompsa } 485168561Sthompsa free(reg, M_OFWPROP); 486168561Sthompsa 487168561Sthompsa nintr = OF_getencprop_alloc(node, "interrupts", sizeof(*intr), 488168561Sthompsa (void **)&intr); 489168561Sthompsa if (nintr > 0) { 490168561Sthompsa iparent = 0; 491168561Sthompsa OF_searchencprop(node, "interrupt-parent", &iparent, 492168561Sthompsa sizeof(iparent)); 493168561Sthompsa OF_searchencprop(OF_xref_phandle(iparent), "#interrupt-cells", 494168561Sthompsa &icells, sizeof(icells)); 495168561Sthompsa for (i = 0; i < nintr; i+= icells) { 496168561Sthompsa intr[i] = ofw_bus_map_intr(dev, iparent, icells, 497168561Sthompsa &intr[i]); 498168561Sthompsa resource_list_add(&ndi->ndi_rl, SYS_RES_IRQ, i, intr[i], 499168561Sthompsa intr[i], 1); 500170599Sthompsa } 501168561Sthompsa free(intr, M_OFWPROP); 502168561Sthompsa } 503169569Sthompsa 504168561Sthompsa return (ndi); 505168561Sthompsa} 506168561Sthompsa 507168561Sthompsastatic void 508168561Sthompsaofwbus_destroy_dinfo(struct ofwbus_devinfo *ndi) 509168561Sthompsa{ 510168561Sthompsa 511168561Sthompsa resource_list_free(&ndi->ndi_rl); 512168561Sthompsa ofw_bus_gen_destroy_devinfo(&ndi->ndi_obdinfo); 513168561Sthompsa free(ndi, M_DEVBUF); 514168561Sthompsa} 515169569Sthompsa 516168561Sthompsastatic int 517168561Sthompsaofwbus_print_res(struct ofwbus_devinfo *ndi) 518168561Sthompsa{ 519168561Sthompsa int rv; 520168793Sthompsa 521168561Sthompsa rv = 0; 522170599Sthompsa rv += resource_list_print_type(&ndi->ndi_rl, "mem", SYS_RES_MEMORY, 523170599Sthompsa "%#lx"); 524168561Sthompsa rv += resource_list_print_type(&ndi->ndi_rl, "irq", SYS_RES_IRQ, 525168793Sthompsa "%ld"); 526168561Sthompsa return (rv); 527168561Sthompsa} 528168561Sthompsa 529168561Sthompsa