ofwbus.c revision 295754
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: head/sys/dev/ofw/ofwbus.c 295754 2016-02-18 11:53:57Z zbb $"); 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> 4694755Sbenno 47256901Snwhitehorn#include <vm/vm.h> 48256901Snwhitehorn#include <vm/pmap.h> 49256901Snwhitehorn 50256855Snwhitehorn#include <dev/ofw/ofw_bus.h> 51212239Smav#include <dev/ofw/ofw_bus_subr.h> 5294755Sbenno#include <dev/ofw/openfirm.h> 53280772Sian#include <dev/fdt/simplebus.h> 5494755Sbenno 5594755Sbenno#include <machine/bus.h> 5694755Sbenno#include <machine/resource.h> 5794755Sbenno 5894755Sbenno/* 59261513Snwhitehorn * The ofwbus (which is a pseudo-bus actually) iterates over the nodes that 60256901Snwhitehorn * hang from the Open Firmware root node and adds them as devices to this bus 61256901Snwhitehorn * (except some special nodes which are excluded) so that drivers can be 62256901Snwhitehorn * attached to them. 6394755Sbenno * 6494755Sbenno */ 6594755Sbenno 66261513Snwhitehornstruct ofwbus_softc { 67280772Sian struct simplebus_softc simplebus_sc; 68261513Snwhitehorn struct rman sc_intr_rman; 69261513Snwhitehorn struct rman sc_mem_rman; 70261513Snwhitehorn}; 7199652Sbenno 72282480Sandrew#ifndef __aarch64__ 73261513Snwhitehornstatic device_identify_t ofwbus_identify; 74282480Sandrew#endif 75261513Snwhitehornstatic device_probe_t ofwbus_probe; 76261513Snwhitehornstatic device_attach_t ofwbus_attach; 77261513Snwhitehornstatic bus_alloc_resource_t ofwbus_alloc_resource; 78261513Snwhitehornstatic bus_adjust_resource_t ofwbus_adjust_resource; 79261513Snwhitehornstatic bus_release_resource_t ofwbus_release_resource; 8099652Sbenno 81261513Snwhitehornstatic device_method_t ofwbus_methods[] = { 8294755Sbenno /* Device interface */ 83282480Sandrew#ifndef __aarch64__ 84261513Snwhitehorn DEVMETHOD(device_identify, ofwbus_identify), 85282480Sandrew#endif 86261513Snwhitehorn DEVMETHOD(device_probe, ofwbus_probe), 87261513Snwhitehorn DEVMETHOD(device_attach, ofwbus_attach), 8894755Sbenno 89256901Snwhitehorn /* Bus interface */ 90261513Snwhitehorn DEVMETHOD(bus_alloc_resource, ofwbus_alloc_resource), 91261513Snwhitehorn DEVMETHOD(bus_adjust_resource, ofwbus_adjust_resource), 92261513Snwhitehorn DEVMETHOD(bus_release_resource, ofwbus_release_resource), 9394755Sbenno 94227843Smarius DEVMETHOD_END 9594755Sbenno}; 9694755Sbenno 97280772SianDEFINE_CLASS_1(ofwbus, ofwbus_driver, ofwbus_methods, 98280772Sian sizeof(struct ofwbus_softc), simplebus_driver); 99261513Snwhitehornstatic devclass_t ofwbus_devclass; 100269594SianEARLY_DRIVER_MODULE(ofwbus, nexus, ofwbus_driver, ofwbus_devclass, 0, 0, 101269597Sian BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); 102261513SnwhitehornMODULE_VERSION(ofwbus, 1); 10394755Sbenno 104282480Sandrew#ifndef __aarch64__ 105261513Snwhitehornstatic void 106261513Snwhitehornofwbus_identify(driver_t *driver, device_t parent) 107261513Snwhitehorn{ 108261513Snwhitehorn 109261513Snwhitehorn /* Check if Open Firmware has been instantiated */ 110265888Snwhitehorn if (OF_peer(0) == 0) 111261513Snwhitehorn return; 112280772Sian 113261513Snwhitehorn if (device_find_child(parent, "ofwbus", -1) == NULL) 114261513Snwhitehorn BUS_ADD_CHILD(parent, 0, "ofwbus", -1); 115261513Snwhitehorn} 116282480Sandrew#endif 117261513Snwhitehorn 118256901Snwhitehornstatic int 119261513Snwhitehornofwbus_probe(device_t dev) 12094755Sbenno{ 121256901Snwhitehorn 122282480Sandrew#ifdef __aarch64__ 123282480Sandrew if (OF_peer(0) == 0) 124282480Sandrew return (ENXIO); 125282480Sandrew#endif 126282480Sandrew 127261513Snwhitehorn device_set_desc(dev, "Open Firmware Device Tree"); 128261513Snwhitehorn return (BUS_PROBE_NOWILDCARD); 129178367Smarcel} 130178367Smarcel 131178367Smarcelstatic int 132261513Snwhitehornofwbus_attach(device_t dev) 133178367Smarcel{ 134261513Snwhitehorn struct ofwbus_softc *sc; 135256901Snwhitehorn phandle_t node; 136280772Sian struct ofw_bus_devinfo obd; 13794755Sbenno 13899652Sbenno sc = device_get_softc(dev); 13999652Sbenno 140257075Snwhitehorn node = OF_peer(0); 141171805Smarcel 142261513Snwhitehorn /* 143261513Snwhitehorn * If no Open Firmware, bail early 144261513Snwhitehorn */ 145261513Snwhitehorn if (node == -1) 146261513Snwhitehorn return (ENXIO); 147261513Snwhitehorn 148280772Sian /* 149280772Sian * ofwbus bus starts on unamed node in FDT, so we cannot make 150280772Sian * ofw_bus_devinfo from it. Pass node to simplebus_init directly. 151280772Sian */ 152280772Sian simplebus_init(dev, node); 153257075Snwhitehorn sc->sc_intr_rman.rm_type = RMAN_ARRAY; 154257075Snwhitehorn sc->sc_intr_rman.rm_descr = "Interrupts"; 155257075Snwhitehorn sc->sc_mem_rman.rm_type = RMAN_ARRAY; 156257075Snwhitehorn sc->sc_mem_rman.rm_descr = "Device Memory"; 157257075Snwhitehorn if (rman_init(&sc->sc_intr_rman) != 0 || 158257075Snwhitehorn rman_init(&sc->sc_mem_rman) != 0 || 159257075Snwhitehorn rman_manage_region(&sc->sc_intr_rman, 0, ~0) != 0 || 160257075Snwhitehorn rman_manage_region(&sc->sc_mem_rman, 0, BUS_SPACE_MAXADDR) != 0) 161257075Snwhitehorn panic("%s: failed to set up rmans.", __func__); 162171805Smarcel 163256901Snwhitehorn /* 164256901Snwhitehorn * Allow devices to identify. 165256901Snwhitehorn */ 166256901Snwhitehorn bus_generic_probe(dev); 167256901Snwhitehorn 168256901Snwhitehorn /* 169256901Snwhitehorn * Now walk the OFW tree and attach top-level devices. 170256901Snwhitehorn */ 171256901Snwhitehorn for (node = OF_child(node); node > 0; node = OF_peer(node)) { 172280772Sian if (ofw_bus_gen_setup_devinfo(&obd, node) != 0) 173256901Snwhitehorn continue; 174280772Sian simplebus_add_device(dev, node, 0, NULL, -1, NULL); 17594755Sbenno } 176178367Smarcel return (bus_generic_attach(dev)); 17794755Sbenno} 17894755Sbenno 17999652Sbennostatic struct resource * 180261513Snwhitehornofwbus_alloc_resource(device_t bus, device_t child, int type, int *rid, 181294883Sjhibbits rman_res_t start, rman_res_t end, rman_res_t count, u_int flags) 18299652Sbenno{ 183261513Snwhitehorn struct ofwbus_softc *sc; 184256901Snwhitehorn struct rman *rm; 185171805Smarcel struct resource *rv; 186256901Snwhitehorn struct resource_list_entry *rle; 187256901Snwhitehorn int isdefault, passthrough; 18899652Sbenno 189256901Snwhitehorn isdefault = (start == 0UL && end == ~0UL); 190256901Snwhitehorn passthrough = (device_get_parent(child) != bus); 191257075Snwhitehorn sc = device_get_softc(bus); 192256901Snwhitehorn rle = NULL; 193256901Snwhitehorn if (!passthrough && isdefault) { 194256901Snwhitehorn rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child), 195256901Snwhitehorn type, *rid); 196280772Sian if (rle == NULL) { 197280772Sian if (bootverbose) 198280772Sian device_printf(bus, "no default resources for " 199280772Sian "rid = %d, type = %d\n", *rid, type); 200256901Snwhitehorn return (NULL); 201280772Sian } 202256901Snwhitehorn start = rle->start; 203256901Snwhitehorn count = ulmax(count, rle->count); 204256901Snwhitehorn end = ulmax(rle->end, start + count - 1); 205256901Snwhitehorn } 206256901Snwhitehorn 207256901Snwhitehorn switch (type) { 208256901Snwhitehorn case SYS_RES_IRQ: 209256901Snwhitehorn rm = &sc->sc_intr_rman; 210256901Snwhitehorn break; 211256901Snwhitehorn case SYS_RES_MEMORY: 212256901Snwhitehorn rm = &sc->sc_mem_rman; 213256901Snwhitehorn break; 214256901Snwhitehorn default: 21599652Sbenno return (NULL); 21699652Sbenno } 21799652Sbenno 218256901Snwhitehorn rv = rman_reserve_resource(rm, start, end, count, flags & ~RF_ACTIVE, 219256901Snwhitehorn child); 220256901Snwhitehorn if (rv == NULL) 221171805Smarcel return (NULL); 222256901Snwhitehorn rman_set_rid(rv, *rid); 223256901Snwhitehorn 224256901Snwhitehorn if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, type, 225256901Snwhitehorn *rid, rv) != 0) { 226256901Snwhitehorn rman_release_resource(rv); 227256901Snwhitehorn return (NULL); 228171805Smarcel } 22999652Sbenno 230256901Snwhitehorn if (!passthrough && rle != NULL) { 231256901Snwhitehorn rle->res = rv; 232256901Snwhitehorn rle->start = rman_get_start(rv); 233256901Snwhitehorn rle->end = rman_get_end(rv); 234256901Snwhitehorn rle->count = rle->end - rle->start + 1; 235256901Snwhitehorn } 23699652Sbenno 23799652Sbenno return (rv); 23899652Sbenno} 23999652Sbenno 24099652Sbennostatic int 241261513Snwhitehornofwbus_adjust_resource(device_t bus, device_t child __unused, int type, 242294883Sjhibbits struct resource *r, rman_res_t start, rman_res_t end) 24399652Sbenno{ 244261513Snwhitehorn struct ofwbus_softc *sc; 245256901Snwhitehorn struct rman *rm; 246261513Snwhitehorn device_t ofwbus; 24799652Sbenno 248261513Snwhitehorn ofwbus = bus; 249261513Snwhitehorn while (strcmp(device_get_name(device_get_parent(ofwbus)), "root") != 0) 250261513Snwhitehorn ofwbus = device_get_parent(ofwbus); 251261513Snwhitehorn sc = device_get_softc(ofwbus); 252256901Snwhitehorn switch (type) { 253256901Snwhitehorn case SYS_RES_IRQ: 254256901Snwhitehorn rm = &sc->sc_intr_rman; 255256901Snwhitehorn break; 256256901Snwhitehorn case SYS_RES_MEMORY: 257256901Snwhitehorn rm = &sc->sc_mem_rman; 258256901Snwhitehorn break; 259256901Snwhitehorn default: 260124468Sgrehan return (EINVAL); 26199652Sbenno } 262256901Snwhitehorn if (rm == NULL) 263256901Snwhitehorn return (ENXIO); 264256901Snwhitehorn if (rman_is_region_manager(r, rm) == 0) 265256901Snwhitehorn return (EINVAL); 266256901Snwhitehorn return (rman_adjust_resource(r, start, end)); 26799652Sbenno} 26899652Sbenno 269256901Snwhitehornstatic int 270274249Szbbofwbus_release_resource(device_t bus, device_t child, int type, 271256901Snwhitehorn int rid, struct resource *r) 27299652Sbenno{ 273274249Szbb struct resource_list_entry *rle; 274295754Szbb int passthrough; 275256901Snwhitehorn int error; 27699652Sbenno 277295754Szbb passthrough = (device_get_parent(child) != bus); 278295754Szbb if (!passthrough) { 279295754Szbb /* Clean resource list entry */ 280295754Szbb rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child), 281295754Szbb type, rid); 282295754Szbb if (rle != NULL) 283295754Szbb rle->res = NULL; 284295754Szbb } 285274249Szbb 286256901Snwhitehorn if ((rman_get_flags(r) & RF_ACTIVE) != 0) { 287256901Snwhitehorn error = bus_deactivate_resource(child, type, rid, r); 288256901Snwhitehorn if (error) 289256901Snwhitehorn return (error); 290256855Snwhitehorn } 291256901Snwhitehorn return (rman_release_resource(r)); 292256901Snwhitehorn} 293