ofwbus.c revision 295832
1251875Speter/*- 2251875Speter * Copyright 1998 Massachusetts Institute of Technology 3251875Speter * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. 4251875Speter * Copyright 2006 by Marius Strobl <marius@FreeBSD.org>. 5251875Speter * All rights reserved. 6251875Speter * 7251875Speter * Permission to use, copy, modify, and distribute this software and 8251875Speter * its documentation for any purpose and without fee is hereby 9251875Speter * granted, provided that both the above copyright notice and this 10251875Speter * permission notice appear in all copies, that both the above 11251875Speter * copyright notice and this permission notice appear in all 12251875Speter * supporting documentation, and that the name of M.I.T. not be used 13251875Speter * in advertising or publicity pertaining to distribution of the 14251875Speter * software without specific, written prior permission. M.I.T. makes 15251875Speter * no representations about the suitability of this software for any 16251875Speter * purpose. It is provided "as is" without express or implied 17251875Speter * warranty. 18251875Speter * 19251875Speter * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 20251875Speter * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 21251875Speter * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 22251875Speter * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 23251875Speter * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24251875Speter * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25251875Speter * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 26251875Speter * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 27251875Speter * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28251875Speter * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 29251875Speter * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30251875Speter * SUCH DAMAGE. 31251875Speter * 32251875Speter * from: FreeBSD: src/sys/i386/i386/nexus.c,v 1.43 2001/02/09 33251875Speter */ 34251875Speter 35251875Speter#include <sys/cdefs.h> 36251875Speter__FBSDID("$FreeBSD: head/sys/dev/ofw/ofwbus.c 295832 2016-02-20 01:32:58Z jhibbits $"); 37251875Speter 38251875Speter#include <sys/param.h> 39251875Speter#include <sys/systm.h> 40251875Speter#include <sys/bus.h> 41251875Speter#include <sys/kernel.h> 42289166Speter#include <sys/malloc.h> 43289166Speter#include <sys/module.h> 44251875Speter#include <sys/pcpu.h> 45251875Speter#include <sys/rman.h> 46251875Speter 47251875Speter#include <vm/vm.h> 48251875Speter#include <vm/pmap.h> 49251875Speter 50251875Speter#include <dev/ofw/ofw_bus.h> 51251875Speter#include <dev/ofw/ofw_bus_subr.h> 52251875Speter#include <dev/ofw/openfirm.h> 53251875Speter#include <dev/fdt/simplebus.h> 54251875Speter 55251875Speter#include <machine/bus.h> 56251875Speter#include <machine/resource.h> 57251875Speter 58251875Speter/* 59251875Speter * The ofwbus (which is a pseudo-bus actually) iterates over the nodes that 60251875Speter * hang from the Open Firmware root node and adds them as devices to this bus 61251875Speter * (except some special nodes which are excluded) so that drivers can be 62251875Speter * attached to them. 63251875Speter * 64251875Speter */ 65251875Speter 66251875Speterstruct ofwbus_softc { 67251875Speter struct simplebus_softc simplebus_sc; 68251875Speter struct rman sc_intr_rman; 69251875Speter struct rman sc_mem_rman; 70251875Speter}; 71251875Speter 72251875Speter#ifndef __aarch64__ 73251875Speterstatic device_identify_t ofwbus_identify; 74251875Speter#endif 75251875Speterstatic device_probe_t ofwbus_probe; 76251875Speterstatic device_attach_t ofwbus_attach; 77251875Speterstatic bus_alloc_resource_t ofwbus_alloc_resource; 78289166Speterstatic bus_adjust_resource_t ofwbus_adjust_resource; 79289166Speterstatic bus_release_resource_t ofwbus_release_resource; 80289166Speter 81289166Speterstatic device_method_t ofwbus_methods[] = { 82251875Speter /* Device interface */ 83251875Speter#ifndef __aarch64__ 84251875Speter DEVMETHOD(device_identify, ofwbus_identify), 85251875Speter#endif 86251875Speter DEVMETHOD(device_probe, ofwbus_probe), 87251875Speter DEVMETHOD(device_attach, ofwbus_attach), 88251875Speter 89251875Speter /* Bus interface */ 90251875Speter DEVMETHOD(bus_alloc_resource, ofwbus_alloc_resource), 91251875Speter DEVMETHOD(bus_adjust_resource, ofwbus_adjust_resource), 92251875Speter DEVMETHOD(bus_release_resource, ofwbus_release_resource), 93251875Speter 94251875Speter DEVMETHOD_END 95251875Speter}; 96251875Speter 97251875SpeterDEFINE_CLASS_1(ofwbus, ofwbus_driver, ofwbus_methods, 98251875Speter sizeof(struct ofwbus_softc), simplebus_driver); 99251875Speterstatic devclass_t ofwbus_devclass; 100251875SpeterEARLY_DRIVER_MODULE(ofwbus, nexus, ofwbus_driver, ofwbus_devclass, 0, 0, 101251875Speter BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 102251875SpeterMODULE_VERSION(ofwbus, 1); 103251875Speter 104251875Speter#ifndef __aarch64__ 105251875Speterstatic void 106251875Speterofwbus_identify(driver_t *driver, device_t parent) 107251875Speter{ 108251875Speter 109251875Speter /* Check if Open Firmware has been instantiated */ 110251875Speter if (OF_peer(0) == 0) 111251875Speter return; 112251875Speter 113251875Speter if (device_find_child(parent, "ofwbus", -1) == NULL) 114251875Speter BUS_ADD_CHILD(parent, 0, "ofwbus", -1); 115251875Speter} 116251875Speter#endif 117251875Speter 118251875Speterstatic int 119251875Speterofwbus_probe(device_t dev) 120251875Speter{ 121251875Speter 122251875Speter#ifdef __aarch64__ 123251875Speter if (OF_peer(0) == 0) 124251875Speter return (ENXIO); 125251875Speter#endif 126251875Speter 127251875Speter device_set_desc(dev, "Open Firmware Device Tree"); 128251875Speter return (BUS_PROBE_NOWILDCARD); 129251875Speter} 130251875Speter 131251875Speterstatic int 132251875Speterofwbus_attach(device_t dev) 133251875Speter{ 134251875Speter struct ofwbus_softc *sc; 135251875Speter phandle_t node; 136289166Speter struct ofw_bus_devinfo obd; 137289166Speter 138251875Speter sc = device_get_softc(dev); 139251875Speter 140251875Speter node = OF_peer(0); 141289166Speter 142251875Speter /* 143251875Speter * If no Open Firmware, bail early 144251875Speter */ 145251875Speter if (node == -1) 146251875Speter return (ENXIO); 147251875Speter 148251875Speter /* 149251875Speter * ofwbus bus starts on unamed node in FDT, so we cannot make 150251875Speter * ofw_bus_devinfo from it. Pass node to simplebus_init directly. 151251875Speter */ 152251875Speter simplebus_init(dev, node); 153251875Speter sc->sc_intr_rman.rm_type = RMAN_ARRAY; 154251875Speter sc->sc_intr_rman.rm_descr = "Interrupts"; 155251875Speter sc->sc_mem_rman.rm_type = RMAN_ARRAY; 156251875Speter sc->sc_mem_rman.rm_descr = "Device Memory"; 157251875Speter if (rman_init(&sc->sc_intr_rman) != 0 || 158251875Speter rman_init(&sc->sc_mem_rman) != 0 || 159251875Speter rman_manage_region(&sc->sc_intr_rman, 0, ~0) != 0 || 160251875Speter rman_manage_region(&sc->sc_mem_rman, 0, BUS_SPACE_MAXADDR) != 0) 161251875Speter panic("%s: failed to set up rmans.", __func__); 162251875Speter 163251875Speter /* 164251875Speter * Allow devices to identify. 165251875Speter */ 166251875Speter bus_generic_probe(dev); 167251875Speter 168251875Speter /* 169251875Speter * Now walk the OFW tree and attach top-level devices. 170251875Speter */ 171251875Speter for (node = OF_child(node); node > 0; node = OF_peer(node)) { 172251875Speter if (ofw_bus_gen_setup_devinfo(&obd, node) != 0) 173251875Speter continue; 174251875Speter simplebus_add_device(dev, node, 0, NULL, -1, NULL); 175251875Speter } 176251875Speter return (bus_generic_attach(dev)); 177251875Speter} 178251875Speter 179251875Speterstatic struct resource * 180251875Speterofwbus_alloc_resource(device_t bus, device_t child, int type, int *rid, 181251875Speter rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 182251875Speter{ 183251875Speter struct ofwbus_softc *sc; 184251875Speter struct rman *rm; 185251875Speter struct resource *rv; 186251875Speter struct resource_list_entry *rle; 187251875Speter int isdefault, passthrough; 188251875Speter 189251875Speter isdefault = RMAN_IS_DEFAULT_RANGE(start, end); 190251875Speter passthrough = (device_get_parent(child) != bus); 191251875Speter sc = device_get_softc(bus); 192251875Speter rle = NULL; 193251875Speter if (!passthrough && isdefault) { 194251875Speter rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child), 195251875Speter type, *rid); 196251875Speter if (rle == NULL) { 197251875Speter if (bootverbose) 198251875Speter device_printf(bus, "no default resources for " 199251875Speter "rid = %d, type = %d\n", *rid, type); 200251875Speter return (NULL); 201251875Speter } 202251875Speter start = rle->start; 203251875Speter count = ulmax(count, rle->count); 204251875Speter end = ulmax(rle->end, start + count - 1); 205251875Speter } 206251875Speter 207251875Speter switch (type) { 208251875Speter case SYS_RES_IRQ: 209251875Speter rm = &sc->sc_intr_rman; 210251875Speter break; 211251875Speter case SYS_RES_MEMORY: 212251875Speter rm = &sc->sc_mem_rman; 213251875Speter break; 214251875Speter default: 215251875Speter return (NULL); 216251875Speter } 217251875Speter 218251875Speter rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, 219251875Speter child); 220251875Speter if (rv == NULL) 221251875Speter return (NULL); 222251875Speter rman_set_rid(rv, *rid); 223251875Speter 224251875Speter if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, 225251875Speter *rid, rv) != 0) { 226251875Speter rman_release_resource(rv); 227251875Speter return (NULL); 228251875Speter } 229251875Speter 230251875Speter if (!passthrough && rle != NULL) { 231251875Speter rle->res = rv; 232251875Speter rle->start = rman_get_start(rv); 233251875Speter rle->end = rman_get_end(rv); 234251875Speter rle->count = rle->end - rle->start + 1; 235251875Speter } 236251875Speter 237251875Speter return (rv); 238251875Speter} 239251875Speter 240251875Speterstatic int 241251875Speterofwbus_adjust_resource(device_t bus, device_t child __unused, int type, 242251875Speter struct resource *r, rman_res_t start, rman_res_t end) 243251875Speter{ 244251875Speter struct ofwbus_softc *sc; 245251875Speter struct rman *rm; 246251875Speter device_t ofwbus; 247251875Speter 248251875Speter ofwbus = bus; 249251875Speter while (strcmp(device_get_name(device_get_parent(ofwbus)), "root") != 0) 250251875Speter ofwbus = device_get_parent(ofwbus); 251251875Speter sc = device_get_softc(ofwbus); 252251875Speter switch (type) { 253251875Speter case SYS_RES_IRQ: 254251875Speter rm = &sc->sc_intr_rman; 255251875Speter break; 256251875Speter case SYS_RES_MEMORY: 257251875Speter rm = &sc->sc_mem_rman; 258251875Speter break; 259251875Speter default: 260251875Speter return (EINVAL); 261251875Speter } 262251875Speter if (rm == NULL) 263251875Speter return (ENXIO); 264251875Speter if (rman_is_region_manager(r, rm) == 0) 265251875Speter return (EINVAL); 266251875Speter return (rman_adjust_resource(r, start, end)); 267251875Speter} 268251875Speter 269251875Speterstatic int 270251875Speterofwbus_release_resource(device_t bus, device_t child, int type, 271251875Speter int rid, struct resource *r) 272251875Speter{ 273251875Speter struct resource_list_entry *rle; 274251875Speter int passthrough; 275251875Speter int error; 276251875Speter 277251875Speter passthrough = (device_get_parent(child) != bus); 278251875Speter if (!passthrough) { 279251875Speter /* Clean resource list entry */ 280251875Speter rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child), 281251875Speter type, rid); 282251875Speter if (rle != NULL) 283251875Speter rle->res = NULL; 284251875Speter } 285251875Speter 286251875Speter if ((rman_get_flags(r) & RF_ACTIVE) != 0) { 287251875Speter error = bus_deactivate_resource(child, type, rid, r); 288251875Speter if (error) 289251875Speter return (error); 290251875Speter } 291251875Speter return (rman_release_resource(r)); 292251875Speter} 293251875Speter