ofwbus.c (51dd214c84efceda87c2ac10d34b7e3ee5b6c28f) | ofwbus.c (ecaecbc7d8bc212d8e854088106b3b21e631bb52) |
---|---|
1/*- 2 * Copyright 1998 Massachusetts Institute of Technology 3 * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. 4 * Copyright 2006 by Marius Strobl <marius@FreeBSD.org>. 5 * All rights reserved. 6 * 7 * Permission to use, copy, modify, and distribute this software and 8 * its documentation for any purpose and without fee is hereby --- 36 unchanged lines hidden (view full) --- 45#include <sys/rman.h> 46 47#include <vm/vm.h> 48#include <vm/pmap.h> 49 50#include <dev/ofw/ofw_bus.h> 51#include <dev/ofw/ofw_bus_subr.h> 52#include <dev/ofw/openfirm.h> | 1/*- 2 * Copyright 1998 Massachusetts Institute of Technology 3 * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. 4 * Copyright 2006 by Marius Strobl <marius@FreeBSD.org>. 5 * All rights reserved. 6 * 7 * Permission to use, copy, modify, and distribute this software and 8 * its documentation for any purpose and without fee is hereby --- 36 unchanged lines hidden (view full) --- 45#include <sys/rman.h> 46 47#include <vm/vm.h> 48#include <vm/pmap.h> 49 50#include <dev/ofw/ofw_bus.h> 51#include <dev/ofw/ofw_bus_subr.h> 52#include <dev/ofw/openfirm.h> |
53#include <dev/fdt/simplebus.h> |
|
53 54#include <machine/bus.h> 55#include <machine/resource.h> 56 57/* 58 * The ofwbus (which is a pseudo-bus actually) iterates over the nodes that 59 * hang from the Open Firmware root node and adds them as devices to this bus 60 * (except some special nodes which are excluded) so that drivers can be 61 * attached to them. 62 * 63 */ 64 | 54 55#include <machine/bus.h> 56#include <machine/resource.h> 57 58/* 59 * The ofwbus (which is a pseudo-bus actually) iterates over the nodes that 60 * hang from the Open Firmware root node and adds them as devices to this bus 61 * (except some special nodes which are excluded) so that drivers can be 62 * attached to them. 63 * 64 */ 65 |
65struct ofwbus_devinfo { 66 struct ofw_bus_devinfo ndi_obdinfo; 67 struct resource_list ndi_rl; 68}; 69 | |
70struct ofwbus_softc { | 66struct ofwbus_softc { |
71 uint32_t acells, scells; | 67 struct simplebus_softc simplebus_sc; |
72 struct rman sc_intr_rman; 73 struct rman sc_mem_rman; 74}; 75 76static device_identify_t ofwbus_identify; 77static device_probe_t ofwbus_probe; 78static device_attach_t ofwbus_attach; | 68 struct rman sc_intr_rman; 69 struct rman sc_mem_rman; 70}; 71 72static device_identify_t ofwbus_identify; 73static device_probe_t ofwbus_probe; 74static device_attach_t ofwbus_attach; |
79static bus_print_child_t ofwbus_print_child; 80static bus_add_child_t ofwbus_add_child; 81static bus_probe_nomatch_t ofwbus_probe_nomatch; | |
82static bus_alloc_resource_t ofwbus_alloc_resource; 83static bus_adjust_resource_t ofwbus_adjust_resource; 84static bus_release_resource_t ofwbus_release_resource; | 75static bus_alloc_resource_t ofwbus_alloc_resource; 76static bus_adjust_resource_t ofwbus_adjust_resource; 77static bus_release_resource_t ofwbus_release_resource; |
85static bus_get_resource_list_t ofwbus_get_resource_list; 86static ofw_bus_get_devinfo_t ofwbus_get_devinfo; | |
87 | 78 |
88static int ofwbus_inlist(const char *, const char *const *); 89static struct ofwbus_devinfo * ofwbus_setup_dinfo(device_t, phandle_t); 90static void ofwbus_destroy_dinfo(struct ofwbus_devinfo *); 91static int ofwbus_print_res(struct ofwbus_devinfo *); 92 | |
93static device_method_t ofwbus_methods[] = { 94 /* Device interface */ 95 DEVMETHOD(device_identify, ofwbus_identify), 96 DEVMETHOD(device_probe, ofwbus_probe), 97 DEVMETHOD(device_attach, ofwbus_attach), | 79static device_method_t ofwbus_methods[] = { 80 /* Device interface */ 81 DEVMETHOD(device_identify, ofwbus_identify), 82 DEVMETHOD(device_probe, ofwbus_probe), 83 DEVMETHOD(device_attach, ofwbus_attach), |
98 DEVMETHOD(device_detach, bus_generic_detach), 99 DEVMETHOD(device_shutdown, bus_generic_shutdown), 100 DEVMETHOD(device_suspend, bus_generic_suspend), 101 DEVMETHOD(device_resume, bus_generic_resume), | |
102 103 /* Bus interface */ | 84 85 /* Bus interface */ |
104 DEVMETHOD(bus_print_child, ofwbus_print_child), 105 DEVMETHOD(bus_probe_nomatch, ofwbus_probe_nomatch), 106 DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), 107 DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), 108 DEVMETHOD(bus_add_child, ofwbus_add_child), 109 DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), | |
110 DEVMETHOD(bus_alloc_resource, ofwbus_alloc_resource), 111 DEVMETHOD(bus_adjust_resource, ofwbus_adjust_resource), 112 DEVMETHOD(bus_release_resource, ofwbus_release_resource), | 86 DEVMETHOD(bus_alloc_resource, ofwbus_alloc_resource), 87 DEVMETHOD(bus_adjust_resource, ofwbus_adjust_resource), 88 DEVMETHOD(bus_release_resource, ofwbus_release_resource), |
113 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 114 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 115 DEVMETHOD(bus_get_resource_list, ofwbus_get_resource_list), 116 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 117 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 118 DEVMETHOD(bus_config_intr, bus_generic_config_intr), 119 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 120 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), | |
121 | 89 |
122 /* ofw_bus interface */ 123 DEVMETHOD(ofw_bus_get_devinfo, ofwbus_get_devinfo), 124 DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 125 DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 126 DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 127 DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 128 DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 129 | |
130 DEVMETHOD_END 131}; 132 | 90 DEVMETHOD_END 91}; 92 |
133static driver_t ofwbus_driver = { 134 "ofwbus", 135 ofwbus_methods, 136 sizeof(struct ofwbus_softc) 137}; | 93DEFINE_CLASS_1(ofwbus, ofwbus_driver, ofwbus_methods, 94 sizeof(struct ofwbus_softc), simplebus_driver); |
138static devclass_t ofwbus_devclass; 139EARLY_DRIVER_MODULE(ofwbus, nexus, ofwbus_driver, ofwbus_devclass, 0, 0, 140 BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 141MODULE_VERSION(ofwbus, 1); 142 | 95static devclass_t ofwbus_devclass; 96EARLY_DRIVER_MODULE(ofwbus, nexus, ofwbus_driver, ofwbus_devclass, 0, 0, 97 BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 98MODULE_VERSION(ofwbus, 1); 99 |
143static const char *const ofwbus_excl_name[] = { 144 "FJSV,system", 145 "aliases", 146 "associations", 147 "chosen", 148 "cmp", 149 "counter-timer", /* No separate device; handled by psycho/sbus */ 150 "failsafe", 151 "memory", 152 "openprom", 153 "options", 154 "packages", 155 "physical-memory", 156 "rsc", 157 "sgcn", 158 "todsg", 159 "virtual-memory", 160 NULL 161}; 162 163static const char *const ofwbus_excl_type[] = { 164 "core", 165 "cpu", 166 NULL 167}; 168 169static int 170ofwbus_inlist(const char *name, const char *const *list) 171{ 172 int i; 173 174 if (name == NULL) 175 return (0); 176 for (i = 0; list[i] != NULL; i++) 177 if (strcmp(name, list[i]) == 0) 178 return (1); 179 return (0); 180} 181 182#define OFWBUS_EXCLUDED(name, type) \ 183 (ofwbus_inlist((name), ofwbus_excl_name) || \ 184 ((type) != NULL && ofwbus_inlist((type), ofwbus_excl_type))) 185 | |
186static void 187ofwbus_identify(driver_t *driver, device_t parent) 188{ 189 190 /* Check if Open Firmware has been instantiated */ 191 if (OF_peer(0) == 0) 192 return; | 100static void 101ofwbus_identify(driver_t *driver, device_t parent) 102{ 103 104 /* Check if Open Firmware has been instantiated */ 105 if (OF_peer(0) == 0) 106 return; |
193 | 107 |
194 if (device_find_child(parent, "ofwbus", -1) == NULL) 195 BUS_ADD_CHILD(parent, 0, "ofwbus", -1); 196} 197 198static int 199ofwbus_probe(device_t dev) 200{ 201 202 device_set_desc(dev, "Open Firmware Device Tree"); 203 return (BUS_PROBE_NOWILDCARD); 204} 205 206static int 207ofwbus_attach(device_t dev) 208{ | 108 if (device_find_child(parent, "ofwbus", -1) == NULL) 109 BUS_ADD_CHILD(parent, 0, "ofwbus", -1); 110} 111 112static int 113ofwbus_probe(device_t dev) 114{ 115 116 device_set_desc(dev, "Open Firmware Device Tree"); 117 return (BUS_PROBE_NOWILDCARD); 118} 119 120static int 121ofwbus_attach(device_t dev) 122{ |
209 struct ofwbus_devinfo *ndi; | |
210 struct ofwbus_softc *sc; | 123 struct ofwbus_softc *sc; |
211 device_t cdev; | |
212 phandle_t node; | 124 phandle_t node; |
125 struct ofw_bus_devinfo obd; |
|
213 214 sc = device_get_softc(dev); 215 216 node = OF_peer(0); 217 218 /* 219 * If no Open Firmware, bail early 220 */ 221 if (node == -1) 222 return (ENXIO); 223 | 126 127 sc = device_get_softc(dev); 128 129 node = OF_peer(0); 130 131 /* 132 * If no Open Firmware, bail early 133 */ 134 if (node == -1) 135 return (ENXIO); 136 |
137 /* 138 * ofwbus bus starts on unamed node in FDT, so we cannot make 139 * ofw_bus_devinfo from it. Pass node to simplebus_init directly. 140 */ 141 simplebus_init(dev, node); |
|
224 sc->sc_intr_rman.rm_type = RMAN_ARRAY; 225 sc->sc_intr_rman.rm_descr = "Interrupts"; 226 sc->sc_mem_rman.rm_type = RMAN_ARRAY; 227 sc->sc_mem_rman.rm_descr = "Device Memory"; 228 if (rman_init(&sc->sc_intr_rman) != 0 || 229 rman_init(&sc->sc_mem_rman) != 0 || 230 rman_manage_region(&sc->sc_intr_rman, 0, ~0) != 0 || 231 rman_manage_region(&sc->sc_mem_rman, 0, BUS_SPACE_MAXADDR) != 0) 232 panic("%s: failed to set up rmans.", __func__); 233 234 /* 235 * Allow devices to identify. 236 */ 237 bus_generic_probe(dev); 238 239 /* | 142 sc->sc_intr_rman.rm_type = RMAN_ARRAY; 143 sc->sc_intr_rman.rm_descr = "Interrupts"; 144 sc->sc_mem_rman.rm_type = RMAN_ARRAY; 145 sc->sc_mem_rman.rm_descr = "Device Memory"; 146 if (rman_init(&sc->sc_intr_rman) != 0 || 147 rman_init(&sc->sc_mem_rman) != 0 || 148 rman_manage_region(&sc->sc_intr_rman, 0, ~0) != 0 || 149 rman_manage_region(&sc->sc_mem_rman, 0, BUS_SPACE_MAXADDR) != 0) 150 panic("%s: failed to set up rmans.", __func__); 151 152 /* 153 * Allow devices to identify. 154 */ 155 bus_generic_probe(dev); 156 157 /* |
240 * Some important numbers 241 */ 242 sc->acells = 2; 243 OF_getencprop(node, "#address-cells", &sc->acells, sizeof(sc->acells)); 244 sc->scells = 1; 245 OF_getencprop(node, "#size-cells", &sc->scells, sizeof(sc->scells)); 246 247 /* | |
248 * Now walk the OFW tree and attach top-level devices. 249 */ 250 for (node = OF_child(node); node > 0; node = OF_peer(node)) { | 158 * Now walk the OFW tree and attach top-level devices. 159 */ 160 for (node = OF_child(node); node > 0; node = OF_peer(node)) { |
251 if ((ndi = ofwbus_setup_dinfo(dev, node)) == NULL) | 161 if (ofw_bus_gen_setup_devinfo(&obd, node) != 0) |
252 continue; | 162 continue; |
253 cdev = device_add_child(dev, NULL, -1); 254 if (cdev == NULL) { 255 device_printf(dev, "<%s>: device_add_child failed\n", 256 ndi->ndi_obdinfo.obd_name); 257 ofwbus_destroy_dinfo(ndi); 258 continue; 259 } 260 device_set_ivars(cdev, ndi); | 163 simplebus_add_device(dev, node, 0, NULL, -1, NULL); |
261 } 262 return (bus_generic_attach(dev)); 263} 264 | 164 } 165 return (bus_generic_attach(dev)); 166} 167 |
265static device_t 266ofwbus_add_child(device_t dev, u_int order, const char *name, int unit) 267{ 268 device_t cdev; 269 struct ofwbus_devinfo *ndi; 270 271 cdev = device_add_child_ordered(dev, order, name, unit); 272 if (cdev == NULL) 273 return (NULL); 274 275 ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); 276 ndi->ndi_obdinfo.obd_node = -1; 277 resource_list_init(&ndi->ndi_rl); 278 device_set_ivars(cdev, ndi); 279 280 return (cdev); 281} 282 283static int 284ofwbus_print_child(device_t bus, device_t child) 285{ 286 int rv; 287 288 rv = bus_print_child_header(bus, child); 289 rv += ofwbus_print_res(device_get_ivars(child)); 290 rv += bus_print_child_footer(bus, child); 291 return (rv); 292} 293 294static void 295ofwbus_probe_nomatch(device_t bus, device_t child) 296{ 297 const char *name, *type; 298 299 if (!bootverbose) 300 return; 301 302 name = ofw_bus_get_name(child); 303 type = ofw_bus_get_type(child); 304 305 device_printf(bus, "<%s>", 306 name != NULL ? name : "unknown"); 307 ofwbus_print_res(device_get_ivars(child)); 308 printf(" type %s (no driver attached)\n", 309 type != NULL ? type : "unknown"); 310} 311 | |
312static struct resource * 313ofwbus_alloc_resource(device_t bus, device_t child, int type, int *rid, 314 u_long start, u_long end, u_long count, u_int flags) 315{ 316 struct ofwbus_softc *sc; 317 struct rman *rm; 318 struct resource *rv; 319 struct resource_list_entry *rle; 320 int isdefault, passthrough; 321 322 isdefault = (start == 0UL && end == ~0UL); 323 passthrough = (device_get_parent(child) != bus); 324 sc = device_get_softc(bus); 325 rle = NULL; | 168static struct resource * 169ofwbus_alloc_resource(device_t bus, device_t child, int type, int *rid, 170 u_long start, u_long end, u_long count, u_int flags) 171{ 172 struct ofwbus_softc *sc; 173 struct rman *rm; 174 struct resource *rv; 175 struct resource_list_entry *rle; 176 int isdefault, passthrough; 177 178 isdefault = (start == 0UL && end == ~0UL); 179 passthrough = (device_get_parent(child) != bus); 180 sc = device_get_softc(bus); 181 rle = NULL; |
326 | |
327 if (!passthrough && isdefault) { 328 rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child), 329 type, *rid); | 182 if (!passthrough && isdefault) { 183 rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child), 184 type, *rid); |
330 if (rle == NULL) | 185 if (rle == NULL) { 186 if (bootverbose) 187 device_printf(bus, "no default resources for " 188 "rid = %d, type = %d\n", *rid, type); |
331 return (NULL); | 189 return (NULL); |
332 if (rle->res != NULL) 333 panic("%s: resource entry is busy", __func__); | 190 } |
334 start = rle->start; 335 count = ulmax(count, rle->count); 336 end = ulmax(rle->end, start + count - 1); 337 } 338 339 switch (type) { 340 case SYS_RES_IRQ: 341 rm = &sc->sc_intr_rman; --- 70 unchanged lines hidden (view full) --- 412 413 if ((rman_get_flags(r) & RF_ACTIVE) != 0) { 414 error = bus_deactivate_resource(child, type, rid, r); 415 if (error) 416 return (error); 417 } 418 return (rman_release_resource(r)); 419} | 191 start = rle->start; 192 count = ulmax(count, rle->count); 193 end = ulmax(rle->end, start + count - 1); 194 } 195 196 switch (type) { 197 case SYS_RES_IRQ: 198 rm = &sc->sc_intr_rman; --- 70 unchanged lines hidden (view full) --- 269 270 if ((rman_get_flags(r) & RF_ACTIVE) != 0) { 271 error = bus_deactivate_resource(child, type, rid, r); 272 if (error) 273 return (error); 274 } 275 return (rman_release_resource(r)); 276} |
420 421static struct resource_list * 422ofwbus_get_resource_list(device_t bus __unused, device_t child) 423{ 424 struct ofwbus_devinfo *ndi; 425 426 ndi = device_get_ivars(child); 427 return (&ndi->ndi_rl); 428} 429 430static const struct ofw_bus_devinfo * 431ofwbus_get_devinfo(device_t bus __unused, device_t child) 432{ 433 struct ofwbus_devinfo *ndi; 434 435 ndi = device_get_ivars(child); 436 return (&ndi->ndi_obdinfo); 437} 438 439static struct ofwbus_devinfo * 440ofwbus_setup_dinfo(device_t dev, phandle_t node) 441{ 442 struct ofwbus_softc *sc; 443 struct ofwbus_devinfo *ndi; 444 const char *nodename; 445 446 sc = device_get_softc(dev); 447 448 ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); 449 if (ofw_bus_gen_setup_devinfo(&ndi->ndi_obdinfo, node) != 0) { 450 free(ndi, M_DEVBUF); 451 return (NULL); 452 } 453 nodename = ndi->ndi_obdinfo.obd_name; 454 if (OFWBUS_EXCLUDED(nodename, ndi->ndi_obdinfo.obd_type)) { 455 ofw_bus_gen_destroy_devinfo(&ndi->ndi_obdinfo); 456 free(ndi, M_DEVBUF); 457 return (NULL); 458 } 459 460 resource_list_init(&ndi->ndi_rl); 461 ofw_bus_reg_to_rl(dev, node, sc->acells, sc->scells, &ndi->ndi_rl); 462 ofw_bus_intr_to_rl(dev, node, &ndi->ndi_rl); 463 464 return (ndi); 465} 466 467static void 468ofwbus_destroy_dinfo(struct ofwbus_devinfo *ndi) 469{ 470 471 resource_list_free(&ndi->ndi_rl); 472 ofw_bus_gen_destroy_devinfo(&ndi->ndi_obdinfo); 473 free(ndi, M_DEVBUF); 474} 475 476static int 477ofwbus_print_res(struct ofwbus_devinfo *ndi) 478{ 479 int rv; 480 481 rv = 0; 482 rv += resource_list_print_type(&ndi->ndi_rl, "mem", SYS_RES_MEMORY, 483 "%#lx"); 484 rv += resource_list_print_type(&ndi->ndi_rl, "irq", SYS_RES_IRQ, 485 "%ld"); 486 return (rv); 487} 488 | |