1139825Simp/*- 294755Sbenno * Copyright 1998 Massachusetts Institute of Technology 3256901Snwhitehorn * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>. 4256901Snwhitehorn * Copyright 2006 by Marius Strobl <marius@FreeBSD.org>. 5256901Snwhitehorn * All rights reserved. 694755Sbenno * 794755Sbenno * Permission to use, copy, modify, and distribute this software and 894755Sbenno * its documentation for any purpose and without fee is hereby 994755Sbenno * granted, provided that both the above copyright notice and this 1094755Sbenno * permission notice appear in all copies, that both the above 1194755Sbenno * copyright notice and this permission notice appear in all 1294755Sbenno * supporting documentation, and that the name of M.I.T. not be used 1394755Sbenno * in advertising or publicity pertaining to distribution of the 1494755Sbenno * software without specific, written prior permission. M.I.T. makes 1594755Sbenno * no representations about the suitability of this software for any 1694755Sbenno * purpose. It is provided "as is" without express or implied 1794755Sbenno * warranty. 18125702Sgrehan * 1994755Sbenno * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 2094755Sbenno * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 2194755Sbenno * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 2294755Sbenno * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 2394755Sbenno * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2494755Sbenno * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2594755Sbenno * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 2694755Sbenno * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 2794755Sbenno * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2894755Sbenno * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 2994755Sbenno * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3094755Sbenno * SUCH DAMAGE. 3194755Sbenno * 3294755Sbenno * from: FreeBSD: src/sys/i386/i386/nexus.c,v 1.43 2001/02/09 3394755Sbenno */ 3494755Sbenno 35227843Smarius#include <sys/cdefs.h> 36227843Smarius__FBSDID("$FreeBSD: stable/11/sys/dev/ofw/ofwbus.c 308333 2016-11-05 10:23:02Z mmel $"); 37227843Smarius 3894755Sbenno#include <sys/param.h> 3994755Sbenno#include <sys/systm.h> 4094755Sbenno#include <sys/bus.h> 4194755Sbenno#include <sys/kernel.h> 4294755Sbenno#include <sys/malloc.h> 43256901Snwhitehorn#include <sys/module.h> 44256901Snwhitehorn#include <sys/pcpu.h> 45256901Snwhitehorn#include <sys/rman.h> 46301453Sskra#ifdef INTRNG 47301453Sskra#include <sys/intr.h> 48301453Sskra#endif 4994755Sbenno 50256901Snwhitehorn#include <vm/vm.h> 51256901Snwhitehorn#include <vm/pmap.h> 52256901Snwhitehorn 53256855Snwhitehorn#include <dev/ofw/ofw_bus.h> 54212239Smav#include <dev/ofw/ofw_bus_subr.h> 5594755Sbenno#include <dev/ofw/openfirm.h> 56280772Sian#include <dev/fdt/simplebus.h> 5794755Sbenno 5894755Sbenno#include <machine/bus.h> 5994755Sbenno#include <machine/resource.h> 6094755Sbenno 6194755Sbenno/* 62261513Snwhitehorn * The ofwbus (which is a pseudo-bus actually) iterates over the nodes that 63256901Snwhitehorn * hang from the Open Firmware root node and adds them as devices to this bus 64256901Snwhitehorn * (except some special nodes which are excluded) so that drivers can be 65256901Snwhitehorn * attached to them. 6694755Sbenno * 6794755Sbenno */ 6894755Sbenno 69261513Snwhitehornstruct ofwbus_softc { 70280772Sian struct simplebus_softc simplebus_sc; 71261513Snwhitehorn struct rman sc_intr_rman; 72261513Snwhitehorn struct rman sc_mem_rman; 73261513Snwhitehorn}; 7499652Sbenno 75282480Sandrew#ifndef __aarch64__ 76261513Snwhitehornstatic device_identify_t ofwbus_identify; 77282480Sandrew#endif 78261513Snwhitehornstatic device_probe_t ofwbus_probe; 79261513Snwhitehornstatic device_attach_t ofwbus_attach; 80261513Snwhitehornstatic bus_alloc_resource_t ofwbus_alloc_resource; 81261513Snwhitehornstatic bus_adjust_resource_t ofwbus_adjust_resource; 82261513Snwhitehornstatic bus_release_resource_t ofwbus_release_resource; 8399652Sbenno 84261513Snwhitehornstatic device_method_t ofwbus_methods[] = { 8594755Sbenno /* Device interface */ 86282480Sandrew#ifndef __aarch64__ 87261513Snwhitehorn DEVMETHOD(device_identify, ofwbus_identify), 88282480Sandrew#endif 89261513Snwhitehorn DEVMETHOD(device_probe, ofwbus_probe), 90261513Snwhitehorn DEVMETHOD(device_attach, ofwbus_attach), 9194755Sbenno 92256901Snwhitehorn /* Bus interface */ 93261513Snwhitehorn DEVMETHOD(bus_alloc_resource, ofwbus_alloc_resource), 94261513Snwhitehorn DEVMETHOD(bus_adjust_resource, ofwbus_adjust_resource), 95261513Snwhitehorn DEVMETHOD(bus_release_resource, ofwbus_release_resource), 9694755Sbenno 97227843Smarius DEVMETHOD_END 9894755Sbenno}; 9994755Sbenno 100280772SianDEFINE_CLASS_1(ofwbus, ofwbus_driver, ofwbus_methods, 101280772Sian sizeof(struct ofwbus_softc), simplebus_driver); 102261513Snwhitehornstatic devclass_t ofwbus_devclass; 103269594SianEARLY_DRIVER_MODULE(ofwbus, nexus, ofwbus_driver, ofwbus_devclass, 0, 0, 104269597Sian BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 105261513SnwhitehornMODULE_VERSION(ofwbus, 1); 10694755Sbenno 107282480Sandrew#ifndef __aarch64__ 108261513Snwhitehornstatic void 109261513Snwhitehornofwbus_identify(driver_t *driver, device_t parent) 110261513Snwhitehorn{ 111261513Snwhitehorn 112261513Snwhitehorn /* Check if Open Firmware has been instantiated */ 113265888Snwhitehorn if (OF_peer(0) == 0) 114261513Snwhitehorn return; 115280772Sian 116261513Snwhitehorn if (device_find_child(parent, "ofwbus", -1) == NULL) 117261513Snwhitehorn BUS_ADD_CHILD(parent, 0, "ofwbus", -1); 118261513Snwhitehorn} 119282480Sandrew#endif 120261513Snwhitehorn 121256901Snwhitehornstatic int 122261513Snwhitehornofwbus_probe(device_t dev) 12394755Sbenno{ 124256901Snwhitehorn 125282480Sandrew#ifdef __aarch64__ 126282480Sandrew if (OF_peer(0) == 0) 127282480Sandrew return (ENXIO); 128282480Sandrew#endif 129282480Sandrew 130261513Snwhitehorn device_set_desc(dev, "Open Firmware Device Tree"); 131261513Snwhitehorn return (BUS_PROBE_NOWILDCARD); 132178367Smarcel} 133178367Smarcel 134178367Smarcelstatic int 135261513Snwhitehornofwbus_attach(device_t dev) 136178367Smarcel{ 137261513Snwhitehorn struct ofwbus_softc *sc; 138256901Snwhitehorn phandle_t node; 139280772Sian struct ofw_bus_devinfo obd; 14094755Sbenno 14199652Sbenno sc = device_get_softc(dev); 14299652Sbenno 143257075Snwhitehorn node = OF_peer(0); 144171805Smarcel 145261513Snwhitehorn /* 146261513Snwhitehorn * If no Open Firmware, bail early 147261513Snwhitehorn */ 148261513Snwhitehorn if (node == -1) 149261513Snwhitehorn return (ENXIO); 150261513Snwhitehorn 151280772Sian /* 152280772Sian * ofwbus bus starts on unamed node in FDT, so we cannot make 153280772Sian * ofw_bus_devinfo from it. Pass node to simplebus_init directly. 154280772Sian */ 155280772Sian simplebus_init(dev, node); 156257075Snwhitehorn sc->sc_intr_rman.rm_type = RMAN_ARRAY; 157257075Snwhitehorn sc->sc_intr_rman.rm_descr = "Interrupts"; 158257075Snwhitehorn sc->sc_mem_rman.rm_type = RMAN_ARRAY; 159257075Snwhitehorn sc->sc_mem_rman.rm_descr = "Device Memory"; 160257075Snwhitehorn if (rman_init(&sc->sc_intr_rman) != 0 || 161257075Snwhitehorn rman_init(&sc->sc_mem_rman) != 0 || 162257075Snwhitehorn rman_manage_region(&sc->sc_intr_rman, 0, ~0) != 0 || 163257075Snwhitehorn rman_manage_region(&sc->sc_mem_rman, 0, BUS_SPACE_MAXADDR) != 0) 164257075Snwhitehorn panic("%s: failed to set up rmans.", __func__); 165171805Smarcel 166256901Snwhitehorn /* 167256901Snwhitehorn * Allow devices to identify. 168256901Snwhitehorn */ 169256901Snwhitehorn bus_generic_probe(dev); 170256901Snwhitehorn 171256901Snwhitehorn /* 172256901Snwhitehorn * Now walk the OFW tree and attach top-level devices. 173256901Snwhitehorn */ 174256901Snwhitehorn for (node = OF_child(node); node > 0; node = OF_peer(node)) { 175280772Sian if (ofw_bus_gen_setup_devinfo(&obd, node) != 0) 176256901Snwhitehorn continue; 177280772Sian simplebus_add_device(dev, node, 0, NULL, -1, NULL); 17894755Sbenno } 179178367Smarcel return (bus_generic_attach(dev)); 18094755Sbenno} 18194755Sbenno 18299652Sbennostatic struct resource * 183261513Snwhitehornofwbus_alloc_resource(device_t bus, device_t child, int type, int *rid, 184294883Sjhibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 18599652Sbenno{ 186261513Snwhitehorn struct ofwbus_softc *sc; 187256901Snwhitehorn struct rman *rm; 188171805Smarcel struct resource *rv; 189256901Snwhitehorn struct resource_list_entry *rle; 190256901Snwhitehorn int isdefault, passthrough; 19199652Sbenno 192295832Sjhibbits isdefault = RMAN_IS_DEFAULT_RANGE(start, end); 193256901Snwhitehorn passthrough = (device_get_parent(child) != bus); 194257075Snwhitehorn sc = device_get_softc(bus); 195256901Snwhitehorn rle = NULL; 196256901Snwhitehorn if (!passthrough && isdefault) { 197256901Snwhitehorn rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child), 198256901Snwhitehorn type, *rid); 199280772Sian if (rle == NULL) { 200280772Sian if (bootverbose) 201280772Sian device_printf(bus, "no default resources for " 202280772Sian "rid = %d, type = %d\n", *rid, type); 203256901Snwhitehorn return (NULL); 204280772Sian } 205256901Snwhitehorn start = rle->start; 206297000Sjhibbits count = ummax(count, rle->count); 207297000Sjhibbits end = ummax(rle->end, start + count - 1); 208256901Snwhitehorn } 209256901Snwhitehorn 210256901Snwhitehorn switch (type) { 211256901Snwhitehorn case SYS_RES_IRQ: 212256901Snwhitehorn rm = &sc->sc_intr_rman; 213256901Snwhitehorn break; 214256901Snwhitehorn case SYS_RES_MEMORY: 215256901Snwhitehorn rm = &sc->sc_mem_rman; 216256901Snwhitehorn break; 217256901Snwhitehorn default: 21899652Sbenno return (NULL); 21999652Sbenno } 22099652Sbenno 221256901Snwhitehorn rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, 222256901Snwhitehorn child); 223256901Snwhitehorn if (rv == NULL) 224171805Smarcel return (NULL); 225256901Snwhitehorn rman_set_rid(rv, *rid); 226256901Snwhitehorn 227256901Snwhitehorn if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, 228256901Snwhitehorn *rid, rv) != 0) { 229256901Snwhitehorn rman_release_resource(rv); 230256901Snwhitehorn return (NULL); 231171805Smarcel } 23299652Sbenno 233256901Snwhitehorn if (!passthrough && rle != NULL) { 234256901Snwhitehorn rle->res = rv; 235256901Snwhitehorn rle->start = rman_get_start(rv); 236256901Snwhitehorn rle->end = rman_get_end(rv); 237256901Snwhitehorn rle->count = rle->end - rle->start + 1; 238256901Snwhitehorn } 23999652Sbenno 24099652Sbenno return (rv); 24199652Sbenno} 24299652Sbenno 24399652Sbennostatic int 244261513Snwhitehornofwbus_adjust_resource(device_t bus, device_t child __unused, int type, 245294883Sjhibbits struct resource *r, rman_res_t start, rman_res_t end) 24699652Sbenno{ 247261513Snwhitehorn struct ofwbus_softc *sc; 248256901Snwhitehorn struct rman *rm; 249261513Snwhitehorn device_t ofwbus; 25099652Sbenno 251261513Snwhitehorn ofwbus = bus; 252261513Snwhitehorn while (strcmp(device_get_name(device_get_parent(ofwbus)), "root") != 0) 253261513Snwhitehorn ofwbus = device_get_parent(ofwbus); 254261513Snwhitehorn sc = device_get_softc(ofwbus); 255256901Snwhitehorn switch (type) { 256256901Snwhitehorn case SYS_RES_IRQ: 257256901Snwhitehorn rm = &sc->sc_intr_rman; 258256901Snwhitehorn break; 259256901Snwhitehorn case SYS_RES_MEMORY: 260256901Snwhitehorn rm = &sc->sc_mem_rman; 261256901Snwhitehorn break; 262256901Snwhitehorn default: 263124468Sgrehan return (EINVAL); 26499652Sbenno } 265256901Snwhitehorn if (rm == NULL) 266256901Snwhitehorn return (ENXIO); 267256901Snwhitehorn if (rman_is_region_manager(r, rm) == 0) 268256901Snwhitehorn return (EINVAL); 269256901Snwhitehorn return (rman_adjust_resource(r, start, end)); 27099652Sbenno} 27199652Sbenno 272256901Snwhitehornstatic int 273274249Szbbofwbus_release_resource(device_t bus, device_t child, int type, 274256901Snwhitehorn int rid, struct resource *r) 27599652Sbenno{ 276274249Szbb struct resource_list_entry *rle; 277295754Szbb int passthrough; 278256901Snwhitehorn int error; 27999652Sbenno 280295754Szbb passthrough = (device_get_parent(child) != bus); 281295754Szbb if (!passthrough) { 282295754Szbb /* Clean resource list entry */ 283295754Szbb rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child), 284295754Szbb type, rid); 285295754Szbb if (rle != NULL) 286295754Szbb rle->res = NULL; 287295754Szbb } 288274249Szbb 289256901Snwhitehorn if ((rman_get_flags(r) & RF_ACTIVE) != 0) { 290256901Snwhitehorn error = bus_deactivate_resource(child, type, rid, r); 291256901Snwhitehorn if (error) 292256901Snwhitehorn return (error); 293256855Snwhitehorn } 294256901Snwhitehorn return (rman_release_resource(r)); 295256901Snwhitehorn} 296