1139825Simp/*- 286233Stmm * Copyright (c) 1999, 2000 Matthew R. Green 3200879Smarius * Copyright (c) 2009 by Marius Strobl <marius@FreeBSD.org> 486233Stmm * All rights reserved. 586233Stmm * 686233Stmm * Redistribution and use in source and binary forms, with or without 786233Stmm * modification, are permitted provided that the following conditions 886233Stmm * are met: 986233Stmm * 1. Redistributions of source code must retain the above copyright 1086233Stmm * notice, this list of conditions and the following disclaimer. 1186233Stmm * 2. Redistributions in binary form must reproduce the above copyright 1286233Stmm * notice, this list of conditions and the following disclaimer in the 1386233Stmm * documentation and/or other materials provided with the distribution. 1486233Stmm * 3. The name of the author may not be used to endorse or promote products 1586233Stmm * derived from this software without specific prior written permission. 1686233Stmm * 1786233Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1886233Stmm * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1986233Stmm * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2086233Stmm * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2186233Stmm * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 2286233Stmm * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 2386233Stmm * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 2486233Stmm * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2586233Stmm * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2686233Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2786233Stmm * SUCH DAMAGE. 2886233Stmm * 29219567Smarius * from: NetBSD: ebus.c,v 1.52 2008/05/29 14:51:26 mrg Exp 3086233Stmm */ 31219567Smarius/*- 32219567Smarius * Copyright (c) 2001 Thomas Moestl <tmm@FreeBSD.org> 33219567Smarius * All rights reserved. 34219567Smarius * 35219567Smarius * Redistribution and use in source and binary forms, with or without 36219567Smarius * modification, are permitted provided that the following conditions 37219567Smarius * are met: 38219567Smarius * 1. Redistributions of source code must retain the above copyright 39219567Smarius * notice, this list of conditions and the following disclaimer. 40219567Smarius * 2. Redistributions in binary form must reproduce the above copyright 41219567Smarius * notice, this list of conditions and the following disclaimer in the 42219567Smarius * documentation and/or other materials provided with the distribution. 43219567Smarius * 3. The name of the author may not be used to endorse or promote products 44219567Smarius * derived from this software without specific prior written permission. 45219567Smarius * 46219567Smarius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 47219567Smarius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 48219567Smarius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 49219567Smarius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 50219567Smarius * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 51219567Smarius * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 52219567Smarius * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 53219567Smarius * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 54219567Smarius * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 55219567Smarius * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 56219567Smarius * SUCH DAMAGE. 57219567Smarius */ 5886233Stmm 59146409Smarius#include <sys/cdefs.h> 60146409Smarius__FBSDID("$FreeBSD$"); 61146409Smarius 6286233Stmm/* 63200879Smarius * Driver for JBus to EBus and PCI to EBus bridges 6486233Stmm */ 6586233Stmm 6686233Stmm#include <sys/param.h> 6786233Stmm#include <sys/systm.h> 6886233Stmm#include <sys/bus.h> 6986233Stmm#include <sys/kernel.h> 7086233Stmm#include <sys/malloc.h> 71130025Sphk#include <sys/module.h> 7286233Stmm 73128712Stmm#include <sys/rman.h> 74128712Stmm 75133589Smarius#include <dev/ofw/ofw_bus.h> 76152684Smarius#include <dev/ofw/ofw_bus_subr.h> 77119338Simp#include <dev/ofw/openfirm.h> 7893067Stmm 79200879Smarius#include <machine/bus.h> 80200879Smarius#ifndef SUN4V 81200879Smarius#include <machine/bus_common.h> 82200879Smarius#endif 83200879Smarius#include <machine/intr_machdep.h> 8486233Stmm#include <machine/resource.h> 8586233Stmm 86119291Simp#include <dev/pci/pcireg.h> 87119291Simp#include <dev/pci/pcivar.h> 8886233Stmm 8986233Stmm#include <sparc64/pci/ofw_pci.h> 9086233Stmm 9186233Stmm/* 92200879Smarius * The register, interrupt map and for the PCI variant also the ranges 93200879Smarius * properties are identical to the ISA ones. 9486233Stmm */ 9586233Stmm#include <sparc64/isa/ofw_isa.h> 9686233Stmm 97200879Smariusstruct ebus_nexus_ranges { 98200879Smarius uint32_t child_hi; 99200879Smarius uint32_t child_lo; 100200879Smarius uint32_t phys_hi; 101200879Smarius uint32_t phys_lo; 102200879Smarius uint32_t size; 103200879Smarius}; 104200879Smarius 10586233Stmmstruct ebus_devinfo { 106152684Smarius struct ofw_bus_devinfo edi_obdinfo; 10786233Stmm struct resource_list edi_rl; 10886233Stmm}; 10986233Stmm 110128712Stmmstruct ebus_rinfo { 111128712Stmm int eri_rtype; 112128712Stmm struct rman eri_rman; 113128712Stmm struct resource *eri_res; 114128712Stmm}; 115128712Stmm 11686233Stmmstruct ebus_softc { 117200879Smarius void *sc_range; 118128712Stmm struct ebus_rinfo *sc_rinfo; 11986233Stmm 120200879Smarius u_int sc_flags; 121200879Smarius#define EBUS_PCI (1 << 0) 122200879Smarius 12386233Stmm int sc_nrange; 124117119Stmm 125117119Stmm struct ofw_bus_iinfo sc_iinfo; 126200879Smarius 127200879Smarius#ifndef SUN4V 128200879Smarius uint32_t sc_ign; 129200879Smarius#endif 13086233Stmm}; 13186233Stmm 132200879Smariusstatic device_probe_t ebus_nexus_probe; 133200879Smariusstatic device_attach_t ebus_nexus_attach; 134200879Smariusstatic device_probe_t ebus_pci_probe; 135200879Smariusstatic device_attach_t ebus_pci_attach; 136128712Stmmstatic bus_print_child_t ebus_print_child; 137128712Stmmstatic bus_probe_nomatch_t ebus_probe_nomatch; 138128712Stmmstatic bus_alloc_resource_t ebus_alloc_resource; 139225931Smariusstatic bus_activate_resource_t ebus_activate_resource; 140225931Smariusstatic bus_adjust_resource_t ebus_adjust_resource; 141128712Stmmstatic bus_release_resource_t ebus_release_resource; 142200879Smariusstatic bus_setup_intr_t ebus_setup_intr; 143128712Stmmstatic bus_get_resource_list_t ebus_get_resource_list; 144152684Smariusstatic ofw_bus_get_devinfo_t ebus_get_devinfo; 14586233Stmm 146200879Smariusstatic int ebus_attach(device_t dev, struct ebus_softc *sc, phandle_t node); 147200879Smariusstatic struct ebus_devinfo *ebus_setup_dinfo(device_t dev, 148200879Smarius struct ebus_softc *sc, phandle_t node); 149200879Smariusstatic void ebus_destroy_dinfo(struct ebus_devinfo *edi); 150200879Smariusstatic int ebus_print_res(struct ebus_devinfo *edi); 15186233Stmm 152200879Smariusstatic devclass_t ebus_devclass; 153200879Smarius 154200879Smariusstatic device_method_t ebus_nexus_methods[] = { 15586233Stmm /* Device interface */ 156200879Smarius DEVMETHOD(device_probe, ebus_nexus_probe), 157200879Smarius DEVMETHOD(device_attach, ebus_nexus_attach), 158154870Smarius DEVMETHOD(device_shutdown, bus_generic_shutdown), 159154870Smarius DEVMETHOD(device_suspend, bus_generic_suspend), 160154870Smarius DEVMETHOD(device_resume, bus_generic_resume), 16186233Stmm 16286233Stmm /* Bus interface */ 16386233Stmm DEVMETHOD(bus_print_child, ebus_print_child), 16486233Stmm DEVMETHOD(bus_probe_nomatch, ebus_probe_nomatch), 16586233Stmm DEVMETHOD(bus_alloc_resource, ebus_alloc_resource), 166225931Smarius DEVMETHOD(bus_activate_resource, ebus_activate_resource), 16786233Stmm DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 168225931Smarius DEVMETHOD(bus_adjust_resource, ebus_adjust_resource), 169128712Stmm DEVMETHOD(bus_release_resource, ebus_release_resource), 170200879Smarius DEVMETHOD(bus_setup_intr, ebus_setup_intr), 171200879Smarius DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 172200879Smarius DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 173200879Smarius DEVMETHOD(bus_get_resource_list, ebus_get_resource_list), 174200879Smarius DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), 175200879Smarius 176200879Smarius /* ofw_bus interface */ 177200879Smarius DEVMETHOD(ofw_bus_get_devinfo, ebus_get_devinfo), 178200879Smarius DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 179200879Smarius DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 180200879Smarius DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 181200879Smarius DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 182200879Smarius DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 183200879Smarius 184227848Smarius DEVMETHOD_END 185200879Smarius}; 186200879Smarius 187200879Smariusstatic driver_t ebus_nexus_driver = { 188200879Smarius "ebus", 189200879Smarius ebus_nexus_methods, 190200879Smarius sizeof(struct ebus_softc), 191200879Smarius}; 192200879Smarius 193200879Smarius/* 194200879Smarius * NB: we rely on the interrupt controllers of the accompanying PCI-Express 195200879Smarius * bridge to be registered as the nexus variant of the EBus bridges doesn't 196200879Smarius * employ its own one. 197200879Smarius */ 198200879SmariusEARLY_DRIVER_MODULE(ebus, nexus, ebus_nexus_driver, ebus_devclass, 0, 0, 199200879Smarius BUS_PASS_BUS + 1); 200200879SmariusMODULE_DEPEND(ebus, nexus, 1, 1, 1); 201200879Smarius 202200879Smariusstatic device_method_t ebus_pci_methods[] = { 203200879Smarius /* Device interface */ 204200879Smarius DEVMETHOD(device_probe, ebus_pci_probe), 205200879Smarius DEVMETHOD(device_attach, ebus_pci_attach), 206200879Smarius DEVMETHOD(device_shutdown, bus_generic_shutdown), 207200879Smarius DEVMETHOD(device_suspend, bus_generic_suspend), 208200879Smarius DEVMETHOD(device_resume, bus_generic_resume), 209200879Smarius 210200879Smarius /* Bus interface */ 211200879Smarius DEVMETHOD(bus_print_child, ebus_print_child), 212200879Smarius DEVMETHOD(bus_probe_nomatch, ebus_probe_nomatch), 213200879Smarius DEVMETHOD(bus_alloc_resource, ebus_alloc_resource), 214200879Smarius DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 215200879Smarius DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 216200879Smarius DEVMETHOD(bus_release_resource, ebus_release_resource), 217190099Smarius DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 218190099Smarius DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 219146967Smarius DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 220190099Smarius DEVMETHOD(bus_get_resource_list, ebus_get_resource_list), 221186128Snwhitehorn DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), 22286233Stmm 223133589Smarius /* ofw_bus interface */ 224152684Smarius DEVMETHOD(ofw_bus_get_devinfo, ebus_get_devinfo), 225152684Smarius DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 226152684Smarius DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 227152684Smarius DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 228152684Smarius DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 229152684Smarius DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 230133589Smarius 231227848Smarius DEVMETHOD_END 23286233Stmm}; 23386233Stmm 234200879Smariusstatic driver_t ebus_pci_driver = { 23586233Stmm "ebus", 236200879Smarius ebus_pci_methods, 23786233Stmm sizeof(struct ebus_softc), 23886233Stmm}; 23986233Stmm 240200879SmariusEARLY_DRIVER_MODULE(ebus, pci, ebus_pci_driver, ebus_devclass, 0, 0, 241200874Smarius BUS_PASS_BUS); 242182066SmariusMODULE_DEPEND(ebus, pci, 1, 1, 1); 243182066SmariusMODULE_VERSION(ebus, 1); 24486233Stmm 24586233Stmmstatic int 246200879Smariusebus_nexus_probe(device_t dev) 24786233Stmm{ 248200879Smarius const char* compat; 24986233Stmm 250200879Smarius compat = ofw_bus_get_compat(dev); 251200879Smarius if (compat != NULL && strcmp(ofw_bus_get_name(dev), "ebus") == 0 && 252200879Smarius strcmp(compat, "jbus-ebus") == 0) { 253200879Smarius device_set_desc(dev, "JBus-EBus bridge"); 254200879Smarius return (BUS_PROBE_GENERIC); 255200879Smarius } 256200879Smarius return (ENXIO); 257200879Smarius} 258200879Smarius 259200879Smariusstatic int 260200879Smariusebus_pci_probe(device_t dev) 261200879Smarius{ 262200879Smarius 26386233Stmm if (pci_get_class(dev) != PCIC_BRIDGE || 26486233Stmm pci_get_vendor(dev) != 0x108e || 265146409Smarius strcmp(ofw_bus_get_name(dev), "ebus") != 0) 26686233Stmm return (ENXIO); 26786233Stmm 26886233Stmm if (pci_get_device(dev) == 0x1000) 26986233Stmm device_set_desc(dev, "PCI-EBus2 bridge"); 27086233Stmm else if (pci_get_device(dev) == 0x1100) 27186233Stmm device_set_desc(dev, "PCI-EBus3 bridge"); 27286233Stmm else 27386233Stmm return (ENXIO); 274200879Smarius return (BUS_PROBE_GENERIC); 275128712Stmm} 27686233Stmm 277128712Stmmstatic int 278200879Smariusebus_nexus_attach(device_t dev) 279128712Stmm{ 280128712Stmm struct ebus_softc *sc; 281200879Smarius phandle_t node; 282200879Smarius 283200879Smarius sc = device_get_softc(dev); 284200879Smarius node = ofw_bus_get_node(dev); 285200879Smarius 286200879Smarius#ifndef SUN4V 287200879Smarius if (OF_getprop(node, "portid", &sc->sc_ign, 288200879Smarius sizeof(sc->sc_ign)) == -1) { 289200879Smarius device_printf(dev, "could not determine IGN"); 290200879Smarius return (ENXIO); 291200879Smarius } 292200879Smarius#endif 293200879Smarius 294200879Smarius sc->sc_nrange = OF_getprop_alloc(node, "ranges", 295200879Smarius sizeof(struct ebus_nexus_ranges), &sc->sc_range); 296200879Smarius if (sc->sc_nrange == -1) { 297200879Smarius printf("%s: could not get ranges property\n", __func__); 298200879Smarius return (ENXIO); 299200879Smarius } 300200879Smarius return (ebus_attach(dev, sc, node)); 301200879Smarius} 302200879Smarius 303200879Smariusstatic int 304200879Smariusebus_pci_attach(device_t dev) 305200879Smarius{ 306200879Smarius struct ebus_softc *sc; 307128712Stmm struct ebus_rinfo *eri; 308128712Stmm struct resource *res; 309128712Stmm phandle_t node; 310128712Stmm int i, rnum, rid; 31186233Stmm 31286233Stmm sc = device_get_softc(dev); 313200879Smarius sc->sc_flags |= EBUS_PCI; 31486233Stmm 315200879Smarius pci_write_config(dev, PCIR_COMMAND, 316200879Smarius pci_read_config(dev, PCIR_COMMAND, 2) | PCIM_CMD_SERRESPEN | 317200879Smarius PCIM_CMD_PERRESPEN | PCIM_CMD_BUSMASTEREN | PCIM_CMD_MEMEN, 2); 318200879Smarius pci_write_config(dev, PCIR_CACHELNSZ, 16 /* 64 bytes */, 1); 319200879Smarius pci_write_config(dev, PCIR_LATTIMER, 64 /* 64 PCI cycles */, 1); 320200879Smarius 321182066Smarius node = ofw_bus_get_node(dev); 32286233Stmm sc->sc_nrange = OF_getprop_alloc(node, "ranges", 323200879Smarius sizeof(struct isa_ranges), &sc->sc_range); 324128712Stmm if (sc->sc_nrange == -1) { 325200879Smarius printf("%s: could not get ranges property\n", __func__); 326128712Stmm return (ENXIO); 327128712Stmm } 32886233Stmm 329128712Stmm sc->sc_rinfo = malloc(sizeof(*sc->sc_rinfo) * sc->sc_nrange, M_DEVBUF, 330128712Stmm M_WAITOK | M_ZERO); 331128712Stmm 332128712Stmm /* For every range, there must be a matching resource. */ 333128712Stmm for (rnum = 0; rnum < sc->sc_nrange; rnum++) { 334128712Stmm eri = &sc->sc_rinfo[rnum]; 335200879Smarius eri->eri_rtype = ofw_isa_range_restype( 336200879Smarius &((struct isa_ranges *)sc->sc_range)[rnum]); 337128712Stmm rid = PCIR_BAR(rnum); 338128712Stmm res = bus_alloc_resource_any(dev, eri->eri_rtype, &rid, 339128712Stmm RF_ACTIVE); 340128712Stmm if (res == NULL) { 341200879Smarius printf("%s: failed to allocate range resource!\n", 342200879Smarius __func__); 343128712Stmm goto fail; 344128712Stmm } 345128712Stmm eri->eri_res = res; 346128712Stmm eri->eri_rman.rm_type = RMAN_ARRAY; 347128712Stmm eri->eri_rman.rm_descr = "EBus range"; 348225931Smarius if (rman_init_from_resource(&eri->eri_rman, res) != 0) { 349200879Smarius printf("%s: failed to initialize rman!", __func__); 350128712Stmm goto fail; 351128712Stmm } 352128712Stmm } 353200879Smarius return (ebus_attach(dev, sc, node)); 354128712Stmm 355200879Smarius fail: 356200879Smarius for (i = rnum; i >= 0; i--) { 357200879Smarius eri = &sc->sc_rinfo[i]; 358200879Smarius if (i < rnum) 359200879Smarius rman_fini(&eri->eri_rman); 360200879Smarius if (eri->eri_res != 0) { 361200879Smarius bus_release_resource(dev, eri->eri_rtype, 362200879Smarius PCIR_BAR(rnum), eri->eri_res); 363200879Smarius } 364200879Smarius } 365200879Smarius free(sc->sc_rinfo, M_DEVBUF); 366200879Smarius free(sc->sc_range, M_OFWPROP); 367200879Smarius return (ENXIO); 368200879Smarius} 369200879Smarius 370200879Smariusstatic int 371200879Smariusebus_attach(device_t dev, struct ebus_softc *sc, phandle_t node) 372200879Smarius{ 373200879Smarius struct ebus_devinfo *edi; 374200879Smarius device_t cdev; 375200879Smarius 376117119Stmm ofw_bus_setup_iinfo(node, &sc->sc_iinfo, sizeof(ofw_isa_intr_t)); 377117119Stmm 37886233Stmm /* 379117119Stmm * Now attach our children. 38086233Stmm */ 38186233Stmm for (node = OF_child(node); node > 0; node = OF_peer(node)) { 382152684Smarius if ((edi = ebus_setup_dinfo(dev, sc, node)) == NULL) 38386233Stmm continue; 384152684Smarius if ((cdev = device_add_child(dev, NULL, -1)) == NULL) { 385152684Smarius device_printf(dev, "<%s>: device_add_child failed\n", 386152684Smarius edi->edi_obdinfo.obd_name); 387152684Smarius ebus_destroy_dinfo(edi); 38886233Stmm continue; 38986233Stmm } 39086233Stmm device_set_ivars(cdev, edi); 39186233Stmm } 392128712Stmm return (bus_generic_attach(dev)); 39386233Stmm} 39486233Stmm 39586233Stmmstatic int 39686233Stmmebus_print_child(device_t dev, device_t child) 39786233Stmm{ 39886233Stmm int retval; 39986233Stmm 40086233Stmm retval = bus_print_child_header(dev, child); 401152684Smarius retval += ebus_print_res(device_get_ivars(child)); 40286233Stmm retval += bus_print_child_footer(dev, child); 40386233Stmm return (retval); 40486233Stmm} 40586233Stmm 40686233Stmmstatic void 40786233Stmmebus_probe_nomatch(device_t dev, device_t child) 40886233Stmm{ 40986233Stmm 410152684Smarius device_printf(dev, "<%s>", ofw_bus_get_name(child)); 411152684Smarius ebus_print_res(device_get_ivars(child)); 41286233Stmm printf(" (no driver attached)\n"); 41386233Stmm} 41486233Stmm 41586233Stmmstatic struct resource * 41686233Stmmebus_alloc_resource(device_t bus, device_t child, int type, int *rid, 41786233Stmm u_long start, u_long end, u_long count, u_int flags) 41886233Stmm{ 41986233Stmm struct ebus_softc *sc; 42086233Stmm struct resource_list *rl; 421128712Stmm struct resource_list_entry *rle = NULL; 422128712Stmm struct resource *res; 423225931Smarius struct ebus_rinfo *eri; 424200879Smarius struct ebus_nexus_ranges *enr; 425200879Smarius uint64_t cend, cstart, offset; 426225931Smarius int i, isdefault, passthrough, ridx; 42786233Stmm 428200879Smarius isdefault = (start == 0UL && end == ~0UL); 429200879Smarius passthrough = (device_get_parent(child) != bus); 430200879Smarius sc = device_get_softc(bus); 431128712Stmm rl = BUS_GET_RESOURCE_LIST(bus, child); 43286233Stmm switch (type) { 433146409Smarius case SYS_RES_MEMORY: 434128712Stmm KASSERT(!(isdefault && passthrough), 435200879Smarius ("%s: passthrough of default allocation", __func__)); 436128712Stmm if (!passthrough) { 437146967Smarius rle = resource_list_find(rl, type, *rid); 438128712Stmm if (rle == NULL) 439128712Stmm return (NULL); 440128712Stmm KASSERT(rle->res == NULL, 441200879Smarius ("%s: resource entry is busy", __func__)); 442128712Stmm if (isdefault) { 443128712Stmm start = rle->start; 444128712Stmm count = ulmax(count, rle->count); 445128712Stmm end = ulmax(rle->end, start + count - 1); 446128712Stmm } 44786233Stmm } 448128712Stmm 449200879Smarius res = NULL; 450200879Smarius if ((sc->sc_flags & EBUS_PCI) != 0) { 451200879Smarius /* 452200879Smarius * Map EBus ranges to PCI ranges. This may include 453200879Smarius * changing the allocation type. 454200879Smarius */ 455200879Smarius (void)ofw_isa_range_map(sc->sc_range, sc->sc_nrange, 456200879Smarius &start, &end, &ridx); 457225931Smarius eri = &sc->sc_rinfo[ridx]; 458225931Smarius res = rman_reserve_resource(&eri->eri_rman, start, 459225931Smarius end, count, flags & ~RF_ACTIVE, child); 460200879Smarius if (res == NULL) 461200879Smarius return (NULL); 462200879Smarius rman_set_rid(res, *rid); 463225931Smarius if ((flags & RF_ACTIVE) != 0 && bus_activate_resource( 464225931Smarius child, type, *rid, res) != 0) { 465200879Smarius rman_release_resource(res); 466200879Smarius return (NULL); 467200879Smarius } 468200879Smarius } else { 469200879Smarius /* Map EBus ranges to nexus ranges. */ 470200879Smarius for (i = 0; i < sc->sc_nrange; i++) { 471200879Smarius enr = &((struct ebus_nexus_ranges *) 472200879Smarius sc->sc_range)[i]; 473200879Smarius cstart = (((uint64_t)enr->child_hi) << 32) | 474200879Smarius enr->child_lo; 475200879Smarius cend = cstart + enr->size - 1; 476200879Smarius if (start >= cstart && end <= cend) { 477200879Smarius offset = 478200879Smarius (((uint64_t)enr->phys_hi) << 32) | 479200879Smarius enr->phys_lo; 480200879Smarius start += offset - cstart; 481200879Smarius end += offset - cstart; 482200879Smarius res = bus_generic_alloc_resource(bus, 483200879Smarius child, type, rid, start, end, 484200879Smarius count, flags); 485200879Smarius break; 486200879Smarius } 487200879Smarius } 48886233Stmm } 489128712Stmm if (!passthrough) 490128712Stmm rle->res = res; 491128712Stmm return (res); 49286233Stmm case SYS_RES_IRQ: 493128712Stmm return (resource_list_alloc(rl, bus, child, type, rid, start, 494128712Stmm end, count, flags)); 49586233Stmm } 496139942Smarcel return (NULL); 497128712Stmm} 49890610Stmm 499182066Smariusstatic int 500225931Smariusebus_activate_resource(device_t bus, device_t child, int type, int rid, 501225931Smarius struct resource *res) 502225931Smarius{ 503225931Smarius struct ebus_softc *sc; 504225931Smarius struct ebus_rinfo *eri; 505225931Smarius bus_space_tag_t bt; 506225931Smarius bus_space_handle_t bh; 507225931Smarius int i, rv; 508225931Smarius 509225931Smarius sc = device_get_softc(bus); 510225931Smarius if ((sc->sc_flags & EBUS_PCI) != 0 && type == SYS_RES_MEMORY) { 511225931Smarius for (i = 0; i < sc->sc_nrange; i++) { 512225931Smarius eri = &sc->sc_rinfo[i]; 513225931Smarius if (rman_is_region_manager(res, &eri->eri_rman) != 0) { 514225931Smarius bt = rman_get_bustag(eri->eri_res); 515225931Smarius rv = bus_space_subregion(bt, 516225931Smarius rman_get_bushandle(eri->eri_res), 517225931Smarius rman_get_start(res) - 518225931Smarius rman_get_start(eri->eri_res), 519225931Smarius rman_get_size(res), &bh); 520225931Smarius if (rv != 0) 521225931Smarius return (rv); 522225931Smarius rman_set_bustag(res, bt); 523225931Smarius rman_set_bushandle(res, bh); 524225931Smarius return (rman_activate_resource(res)); 525225931Smarius } 526225931Smarius } 527225931Smarius return (EINVAL); 528225931Smarius } 529225931Smarius return (bus_generic_activate_resource(bus, child, type, rid, res)); 530225931Smarius} 531225931Smarius 532225931Smariusstatic int 533225931Smariusebus_adjust_resource(device_t bus __unused, device_t child __unused, 534225931Smarius int type __unused, struct resource *res __unused, u_long start __unused, 535225931Smarius u_long end __unused) 536225931Smarius{ 537225931Smarius 538225931Smarius return (ENXIO); 539225931Smarius} 540225931Smarius 541225931Smariusstatic int 542128712Stmmebus_release_resource(device_t bus, device_t child, int type, int rid, 543128712Stmm struct resource *res) 544128712Stmm{ 545200879Smarius struct ebus_softc *sc; 546128712Stmm struct resource_list *rl; 547128712Stmm struct resource_list_entry *rle; 548200879Smarius int passthrough, rv; 54986233Stmm 550200879Smarius passthrough = (device_get_parent(child) != bus); 551128712Stmm rl = BUS_GET_RESOURCE_LIST(bus, child); 552225931Smarius sc = device_get_softc(bus); 553225931Smarius if ((sc->sc_flags & EBUS_PCI) != 0 && type == SYS_RES_MEMORY) { 554225931Smarius if ((rman_get_flags(res) & RF_ACTIVE) != 0 ){ 555225931Smarius rv = bus_deactivate_resource(child, type, rid, res); 556225931Smarius if (rv != 0) 557225931Smarius return (rv); 558225931Smarius } 559225931Smarius rv = rman_release_resource(res); 560225931Smarius if (rv != 0) 561128712Stmm return (rv); 562128712Stmm if (!passthrough) { 563146967Smarius rle = resource_list_find(rl, type, rid); 564200879Smarius KASSERT(rle != NULL, 565200879Smarius ("%s: resource entry not found!", __func__)); 566200879Smarius KASSERT(rle->res != NULL, 567200879Smarius ("%s: resource entry is not busy", __func__)); 568128712Stmm rle->res = NULL; 56986233Stmm } 570225931Smarius return (0); 57186233Stmm } 572225931Smarius return (resource_list_release(rl, bus, child, type, rid, res)); 57386233Stmm} 57486233Stmm 575200879Smariusstatic int 576200879Smariusebus_setup_intr(device_t dev, device_t child, struct resource *ires, 577200879Smarius int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, 578200879Smarius void **cookiep) 579200879Smarius{ 580200879Smarius#ifndef SUN4V 581200879Smarius struct ebus_softc *sc; 582200879Smarius u_long vec; 583200879Smarius 584200879Smarius sc = device_get_softc(dev); 585200879Smarius if ((sc->sc_flags & EBUS_PCI) == 0) { 586200879Smarius /* 587200879Smarius * Make sure the vector is fully specified. This isn't 588200879Smarius * necessarily the case with the PCI variant. 589200879Smarius */ 590200879Smarius vec = rman_get_start(ires); 591200879Smarius if (INTIGN(vec) != sc->sc_ign) { 592200879Smarius device_printf(dev, 593200879Smarius "invalid interrupt vector 0x%lx\n", vec); 594200879Smarius return (EINVAL); 595200879Smarius } 596200879Smarius 597200879Smarius /* 598200879Smarius * As we rely on the interrupt controllers of the 599200879Smarius * accompanying PCI-Express bridge ensure at least 600200879Smarius * something is registered for this vector. 601200879Smarius */ 602200879Smarius if (intr_vectors[vec].iv_ic == NULL) { 603200879Smarius device_printf(dev, 604200879Smarius "invalid interrupt controller for vector 0x%lx\n", 605200879Smarius vec); 606200879Smarius return (EINVAL); 607200879Smarius } 608200879Smarius } 609200879Smarius#endif 610200879Smarius return (bus_generic_setup_intr(dev, child, ires, flags, filt, intr, 611200879Smarius arg, cookiep)); 612200879Smarius} 613200879Smarius 61486233Stmmstatic struct resource_list * 61586233Stmmebus_get_resource_list(device_t dev, device_t child) 61686233Stmm{ 61786233Stmm struct ebus_devinfo *edi; 61886233Stmm 61986233Stmm edi = device_get_ivars(child); 62086233Stmm return (&edi->edi_rl); 62186233Stmm} 62286233Stmm 623152684Smariusstatic const struct ofw_bus_devinfo * 624152684Smariusebus_get_devinfo(device_t bus, device_t dev) 625152684Smarius{ 626152684Smarius struct ebus_devinfo *edi; 627152684Smarius 628152684Smarius edi = device_get_ivars(dev); 629152684Smarius return (&edi->edi_obdinfo); 630152684Smarius} 631152684Smarius 63286233Stmmstatic struct ebus_devinfo * 633152684Smariusebus_setup_dinfo(device_t dev, struct ebus_softc *sc, phandle_t node) 63486233Stmm{ 635200879Smarius struct isa_regs reg, *regs; 636200879Smarius ofw_isa_intr_t intr, *intrs; 63786233Stmm struct ebus_devinfo *edi; 638200879Smarius uint64_t start; 639200879Smarius uint32_t rintr; 640200879Smarius int i, nintr, nreg, rv; 641200879Smarius uint8_t maskbuf[sizeof(reg) + sizeof(intr)]; 64286233Stmm 643111119Simp edi = malloc(sizeof(*edi), M_DEVBUF, M_ZERO | M_WAITOK); 644152684Smarius if (ofw_bus_gen_setup_devinfo(&edi->edi_obdinfo, node) != 0) { 645152684Smarius free(edi, M_DEVBUF); 64686233Stmm return (NULL); 647152684Smarius } 64886233Stmm resource_list_init(&edi->edi_rl); 649200879Smarius nreg = OF_getprop_alloc(node, "reg", sizeof(*regs), (void **)®s); 65086233Stmm if (nreg == -1) { 651152684Smarius device_printf(dev, "<%s>: incomplete\n", 652152684Smarius edi->edi_obdinfo.obd_name); 653200879Smarius ebus_destroy_dinfo(edi); 654200879Smarius return (NULL); 65586233Stmm } 65686233Stmm for (i = 0; i < nreg; i++) { 657200879Smarius start = ISA_REG_PHYS(regs + i); 658200879Smarius (void)resource_list_add(&edi->edi_rl, SYS_RES_MEMORY, i, 659200879Smarius start, start + regs[i].size - 1, regs[i].size); 66086233Stmm } 661200879Smarius free(regs, M_OFWPROP); 66286233Stmm 66386233Stmm nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intrs), 66486233Stmm (void **)&intrs); 665200879Smarius if (nintr == -1) 666200879Smarius return (edi); 66786233Stmm for (i = 0; i < nintr; i++) { 668200879Smarius rv = 0; 669200879Smarius if ((sc->sc_flags & EBUS_PCI) != 0) { 670200879Smarius rintr = ofw_isa_route_intr(dev, node, &sc->sc_iinfo, 671200879Smarius intrs[i]); 672200879Smarius } else { 673200879Smarius intr = intrs[i]; 674200879Smarius rv = ofw_bus_lookup_imap(node, &sc->sc_iinfo, ®, 675200879Smarius sizeof(reg), &intr, sizeof(intr), &rintr, 676209298Snwhitehorn sizeof(rintr), NULL, maskbuf); 677200879Smarius#ifndef SUN4V 678200879Smarius if (rv != 0) 679200879Smarius rintr = INTMAP_VEC(sc->sc_ign, rintr); 680200879Smarius#endif 681200879Smarius } 682200879Smarius if ((sc->sc_flags & EBUS_PCI) == 0 ? rv == 0 : 683200879Smarius rintr == PCI_INVALID_IRQ) { 684152684Smarius device_printf(dev, 685152684Smarius "<%s>: could not map EBus interrupt %d\n", 686152684Smarius edi->edi_obdinfo.obd_name, intrs[i]); 687200879Smarius continue; 688152684Smarius } 689200879Smarius (void)resource_list_add(&edi->edi_rl, SYS_RES_IRQ, i, rintr, 690200879Smarius rintr, 1); 69186233Stmm } 692117119Stmm free(intrs, M_OFWPROP); 69386233Stmm return (edi); 69486233Stmm} 69586233Stmm 69686233Stmmstatic void 69786233Stmmebus_destroy_dinfo(struct ebus_devinfo *edi) 69886233Stmm{ 69986233Stmm 70086233Stmm resource_list_free(&edi->edi_rl); 701152684Smarius ofw_bus_gen_destroy_devinfo(&edi->edi_obdinfo); 70286233Stmm free(edi, M_DEVBUF); 70386233Stmm} 70486233Stmm 70586233Stmmstatic int 70686233Stmmebus_print_res(struct ebus_devinfo *edi) 70786233Stmm{ 70886233Stmm int retval; 70986233Stmm 71086233Stmm retval = 0; 711146409Smarius retval += resource_list_print_type(&edi->edi_rl, "addr", SYS_RES_MEMORY, 71286233Stmm "%#lx"); 71386233Stmm retval += resource_list_print_type(&edi->edi_rl, "irq", SYS_RES_IRQ, 71486233Stmm "%ld"); 71586233Stmm return (retval); 71686233Stmm} 717