upa.c revision 225931
1101099Srwatson/*- 2101099Srwatson * Copyright (c) 2006 Marius Strobl <marius@FreeBSD.org> 3101099Srwatson * All rights reserved. 4101099Srwatson * 5101099Srwatson * Redistribution and use in source and binary forms, with or without 6101099Srwatson * modification, are permitted provided that the following conditions 7101099Srwatson * are met: 8101099Srwatson * 1. Redistributions of source code must retain the above copyright 9101099Srwatson * notice, this list of conditions and the following disclaimer. 10101099Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11101099Srwatson * notice, this list of conditions and the following disclaimer in the 12101099Srwatson * documentation and/or other materials provided with the distribution. 13101099Srwatson * 14101099Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15101099Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16101099Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17101099Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18101099Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19101099Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20101099Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21101099Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22101099Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23101099Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24101099Srwatson * SUCH DAMAGE. 25101099Srwatson */ 26101099Srwatson 27101099Srwatson#include <sys/cdefs.h> 28101099Srwatson__FBSDID("$FreeBSD: head/sys/sparc64/sparc64/upa.c 225931 2011-10-02 23:22:38Z marius $"); 29101099Srwatson 30101099Srwatson#include <sys/param.h> 31101099Srwatson#include <sys/systm.h> 32101099Srwatson#include <sys/bus.h> 33101099Srwatson#include <sys/kernel.h> 34101099Srwatson#include <sys/module.h> 35101099Srwatson#include <sys/resource.h> 36101099Srwatson#include <sys/rman.h> 37101099Srwatson 38101099Srwatson#include <dev/ofw/ofw_bus.h> 39101099Srwatson#include <dev/ofw/ofw_bus_subr.h> 40101099Srwatson#include <dev/ofw/openfirm.h> 41101099Srwatson 42101099Srwatson#include <machine/bus.h> 43101099Srwatson#include <machine/bus_common.h> 44101099Srwatson#include <machine/intr_machdep.h> 45101099Srwatson#include <machine/resource.h> 46101099Srwatson 47101099Srwatson#define UPA_NREG 3 48101099Srwatson 49101099Srwatson#define UPA_CFG 0 50101099Srwatson#define UPA_IMR1 1 51101099Srwatson#define UPA_IMR2 2 52101099Srwatson 53101099Srwatson/* UPA_CFG bank */ 54101099Srwatson#define UPA_CFG_UPA0 0x00 /* UPA0 config register */ 55101099Srwatson#define UPA_CFG_UPA1 0x08 /* UPA1 config register */ 56101099Srwatson#define UPA_CFG_IF 0x10 /* interface config register */ 57101099Srwatson#define UPA_CFG_IF_RST 0x00 58101099Srwatson#define UPA_CFG_IF_POK_RST 0x02 59101099Srwatson#define UPA_CFG_IF_POK 0x03 60101099Srwatson#define UPA_CFG_ESTAR 0x18 /* Estar config register */ 61101099Srwatson#define UPA_CFG_ESTAR_SPEED_FULL 0x01 62101099Srwatson#define UPA_CFG_ESTAR_SPEED_1_2 0x02 63101099Srwatson#define UPA_CFG_ESTAR_SPEED_1_64 0x40 64101099Srwatson 65101099Srwatson#define UPA_INO_BASE 0x2a 66101099Srwatson#define UPA_INO_MAX 0x2b 67101099Srwatson 68101099Srwatsonstruct upa_regs { 69101099Srwatson uint64_t phys; 70101099Srwatson uint64_t size; 71101099Srwatson}; 72101099Srwatson 73101099Srwatsonstruct upa_ranges { 74101099Srwatson uint64_t child; 75101099Srwatson uint64_t parent; 76101099Srwatson uint64_t size; 77101099Srwatson}; 78101099Srwatson 79101099Srwatsonstruct upa_devinfo { 80101099Srwatson struct ofw_bus_devinfo udi_obdinfo; 81101099Srwatson struct resource_list udi_rl; 82101099Srwatson}; 83101099Srwatson 84101099Srwatsonstruct upa_softc { 85101099Srwatson struct resource *sc_res[UPA_NREG]; 86101099Srwatson bus_space_tag_t sc_bt[UPA_NREG]; 87101099Srwatson bus_space_handle_t sc_bh[UPA_NREG]; 88101099Srwatson 89101099Srwatson uint32_t sc_ign; 90101099Srwatson 91101099Srwatson int sc_nrange; 92101099Srwatson struct upa_ranges *sc_ranges; 93101099Srwatson}; 94101099Srwatson 95101099Srwatson#define UPA_READ(sc, reg, off) \ 96101099Srwatson bus_space_read_8((sc)->sc_bt[(reg)], (sc)->sc_bh[(reg)], (off)) 97101099Srwatson#define UPA_WRITE(sc, reg, off, val) \ 98101099Srwatson bus_space_write_8((sc)->sc_bt[(reg)], (sc)->sc_bh[(reg)], (off), (val)) 99101099Srwatson 100101099Srwatsonstatic device_probe_t upa_probe; 101101099Srwatsonstatic device_attach_t upa_attach; 102101099Srwatsonstatic bus_print_child_t upa_print_child; 103101099Srwatsonstatic bus_probe_nomatch_t upa_probe_nomatch; 104101099Srwatsonstatic bus_alloc_resource_t upa_alloc_resource; 105101099Srwatsonstatic bus_adjust_resource_t upa_adjust_resource; 106101099Srwatsonstatic bus_setup_intr_t upa_setup_intr; 107101099Srwatsonstatic bus_get_resource_list_t upa_get_resource_list; 108101099Srwatsonstatic ofw_bus_get_devinfo_t upa_get_devinfo; 109101099Srwatson 110101099Srwatsonstatic void upa_intr_enable(void *); 111101099Srwatsonstatic void upa_intr_disable(void *); 112101099Srwatsonstatic void upa_intr_assign(void *); 113101099Srwatsonstatic struct upa_devinfo *upa_setup_dinfo(device_t, struct upa_softc *, 114101099Srwatson phandle_t, uint32_t); 115101099Srwatsonstatic void upa_destroy_dinfo(struct upa_devinfo *); 116101099Srwatsonstatic int upa_print_res(struct upa_devinfo *); 117101099Srwatson 118101099Srwatsonstatic device_method_t upa_methods[] = { 119101099Srwatson /* Device interface */ 120101099Srwatson DEVMETHOD(device_probe, upa_probe), 121101099Srwatson DEVMETHOD(device_attach, upa_attach), 122101099Srwatson DEVMETHOD(device_shutdown, bus_generic_shutdown), 123101099Srwatson DEVMETHOD(device_suspend, bus_generic_suspend), 124101099Srwatson DEVMETHOD(device_resume, bus_generic_resume), 125101099Srwatson 126101099Srwatson /* Bus interface */ 127101099Srwatson DEVMETHOD(bus_print_child, upa_print_child), 128101099Srwatson DEVMETHOD(bus_probe_nomatch, upa_probe_nomatch), 129101099Srwatson DEVMETHOD(bus_read_ivar, bus_generic_read_ivar), 130101099Srwatson DEVMETHOD(bus_write_ivar, bus_generic_write_ivar), 131101099Srwatson DEVMETHOD(bus_alloc_resource, upa_alloc_resource), 132101099Srwatson DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 133101099Srwatson DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 134101099Srwatson DEVMETHOD(bus_adjust_resource, upa_adjust_resource), 135101099Srwatson DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), 136101099Srwatson DEVMETHOD(bus_setup_intr, upa_setup_intr), 137101099Srwatson DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 138101099Srwatson DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 139101099Srwatson DEVMETHOD(bus_get_resource_list, upa_get_resource_list), 140101099Srwatson DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), 141101099Srwatson 142101099Srwatson /* ofw_bus interface */ 143101099Srwatson DEVMETHOD(ofw_bus_get_devinfo, upa_get_devinfo), 144101099Srwatson DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 145101099Srwatson DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 146101099Srwatson DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 147101099Srwatson DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 148101099Srwatson DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 149101099Srwatson 150101099Srwatson KOBJMETHOD_END 151101099Srwatson}; 152101099Srwatson 153101099Srwatsonstatic devclass_t upa_devclass; 154101099Srwatson 155101099SrwatsonDEFINE_CLASS_0(upa, upa_driver, upa_methods, sizeof(struct upa_softc)); 156101099SrwatsonEARLY_DRIVER_MODULE(upa, nexus, upa_driver, upa_devclass, 0, 0, BUS_PASS_BUS); 157101099Srwatson 158101099Srwatsonstatic const struct intr_controller upa_ic = { 159101099Srwatson upa_intr_enable, 160101099Srwatson upa_intr_disable, 161101099Srwatson upa_intr_assign, 162101099Srwatson /* The interrupts are pulse type and thus automatically cleared. */ 163101099Srwatson NULL 164101099Srwatson}; 165101099Srwatson 166101099Srwatsonstruct upa_icarg { 167101099Srwatson struct upa_softc *uica_sc; 168101099Srwatson u_int uica_imr; 169101099Srwatson}; 170101099Srwatson 171101099Srwatsonstatic int 172101099Srwatsonupa_probe(device_t dev) 173101099Srwatson{ 174101099Srwatson const char* compat; 175101099Srwatson 176101099Srwatson compat = ofw_bus_get_compat(dev); 177101099Srwatson if (compat != NULL && strcmp(ofw_bus_get_name(dev), "upa") == 0 && 178101099Srwatson strcmp(compat, "upa64s") == 0) { 179101099Srwatson device_set_desc(dev, "UPA bridge"); 180101099Srwatson return (BUS_PROBE_DEFAULT); 181101099Srwatson } 182101099Srwatson return (ENXIO); 183101099Srwatson} 184101099Srwatson 185101099Srwatsonstatic int 186101099Srwatsonupa_attach(device_t dev) 187101099Srwatson{ 188101099Srwatson struct upa_devinfo *udi; 189101099Srwatson struct upa_icarg *uica; 190101099Srwatson struct upa_softc *sc; 191101099Srwatson phandle_t child, node; 192101099Srwatson device_t cdev; 193101099Srwatson uint32_t portid; 194101099Srwatson int i, imr, j, rid; 195101099Srwatson#if 1 196101099Srwatson device_t *children, schizo; 197101099Srwatson u_long scount, sstart, ucount, ustart; 198101099Srwatson int nchildren; 199101099Srwatson#endif 200101099Srwatson 201101099Srwatson sc = device_get_softc(dev); 202101099Srwatson node = ofw_bus_get_node(dev); 203101099Srwatson for (i = UPA_CFG; i <= UPA_IMR2; i++) { 204101099Srwatson rid = i; 205101099Srwatson /* 206101099Srwatson * The UPA_IMR{1,2} resources are shared with that of the 207101099Srwatson * Schizo PCI bus B CSR bank. 208101099Srwatson */ 209101099Srwatson#if 0 210101099Srwatson sc->sc_res[i] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 211101099Srwatson &rid, ((i == UPA_IMR1 || i == UPA_IMR2) ? RF_SHAREABLE : 212101099Srwatson 0) | RF_ACTIVE); 213101099Srwatson if (sc->sc_res[i] == NULL) { 214101099Srwatson device_printf(dev, 215101099Srwatson "could not allocate resource %d\n", i); 216101099Srwatson goto fail; 217101099Srwatson } 218101099Srwatson sc->sc_bt[i] = rman_get_bustag(sc->sc_res[i]); 219101099Srwatson sc->sc_bh[i] = rman_get_bushandle(sc->sc_res[i]); 220101099Srwatson#else 221101099Srwatson /* 222101099Srwatson * Workaround for the fact that rman(9) only allows to 223101099Srwatson * share resources of the same size. 224101099Srwatson */ 225101099Srwatson if (i == UPA_IMR1 || i == UPA_IMR2) { 226101099Srwatson if (bus_get_resource(dev, SYS_RES_MEMORY, i, &ustart, 227101099Srwatson &ucount) != 0) { 228101099Srwatson device_printf(dev, 229101099Srwatson "could not determine UPA resource\n"); 230101099Srwatson goto fail; 231101099Srwatson } 232101099Srwatson if (device_get_children(device_get_parent(dev), 233101099Srwatson &children, &nchildren) != 0) { 234101099Srwatson device_printf(dev, "could not get children\n"); 235101099Srwatson goto fail; 236101099Srwatson } 237101099Srwatson schizo = NULL; 238101099Srwatson for (j = 0; j < nchildren; j++) { 239101099Srwatson if (ofw_bus_get_type(children[j]) != NULL && 240101099Srwatson strcmp(ofw_bus_get_type(children[j]), 241101099Srwatson "pci") == 0 && 242101099Srwatson ofw_bus_get_compat(children[j]) != NULL && 243101099Srwatson strcmp(ofw_bus_get_compat(children[j]), 244101099Srwatson "pci108e,8001") == 0 && 245101099Srwatson ((bus_get_resource_start(children[j], 246101099Srwatson SYS_RES_MEMORY, 0) >> 20) & 1) == 1) { 247101099Srwatson schizo = children[j]; 248101099Srwatson break; 249101099Srwatson } 250101099Srwatson } 251101099Srwatson free(children, M_TEMP); 252101099Srwatson if (schizo == NULL) { 253101099Srwatson device_printf(dev, "could not find Schizo\n"); 254101099Srwatson goto fail; 255101099Srwatson } 256101099Srwatson if (bus_get_resource(schizo, SYS_RES_MEMORY, 0, 257101099Srwatson &sstart, &scount) != 0) { 258101099Srwatson device_printf(dev, 259101099Srwatson "could not determine Schizo resource\n"); 260101099Srwatson goto fail; 261101099Srwatson } 262101099Srwatson sc->sc_res[i] = bus_alloc_resource(dev, SYS_RES_MEMORY, 263101099Srwatson &rid, sstart, sstart + scount - 1, scount, 264101099Srwatson RF_SHAREABLE | RF_ACTIVE); 265101099Srwatson } else 266101099Srwatson sc->sc_res[i] = bus_alloc_resource_any(dev, 267101099Srwatson SYS_RES_MEMORY, &rid, RF_ACTIVE); 268101099Srwatson if (sc->sc_res[i] == NULL) { 269101099Srwatson device_printf(dev, 270101099Srwatson "could not allocate resource %d\n", i); 271101099Srwatson goto fail; 272101099Srwatson } 273101099Srwatson sc->sc_bt[i] = rman_get_bustag(sc->sc_res[i]); 274101099Srwatson sc->sc_bh[i] = rman_get_bushandle(sc->sc_res[i]); 275101099Srwatson if (i == UPA_IMR1 || i == UPA_IMR2) 276101099Srwatson bus_space_subregion(sc->sc_bt[i], sc->sc_bh[i], 277101099Srwatson ustart - sstart, ucount, &sc->sc_bh[i]); 278101099Srwatson#endif 279101099Srwatson } 280101099Srwatson 281101099Srwatson if (OF_getprop(node, "portid", &sc->sc_ign, sizeof(sc->sc_ign)) == -1) { 282101099Srwatson device_printf(dev, "could not determine IGN\n"); 283101099Srwatson goto fail; 284101099Srwatson } 285101099Srwatson 286101099Srwatson sc->sc_nrange = OF_getprop_alloc(node, "ranges", sizeof(*sc->sc_ranges), 287101099Srwatson (void **)&sc->sc_ranges); 288101099Srwatson if (sc->sc_nrange == -1) { 289101099Srwatson device_printf(dev, "could not determine ranges\n"); 290101099Srwatson goto fail; 291101099Srwatson } 292101099Srwatson 293101099Srwatson /* 294101099Srwatson * Hunt through all the interrupt mapping regs and register our 295101099Srwatson * interrupt controller for the corresponding interrupt vectors. 296101099Srwatson * We do this early in order to be able to catch stray interrupts. 297101099Srwatson */ 298101099Srwatson for (i = UPA_INO_BASE; i <= UPA_INO_MAX; i++) { 299101099Srwatson imr = 0; 300101099Srwatson for (j = UPA_IMR1; j <= UPA_IMR2; j++) { 301101099Srwatson if (INTVEC(UPA_READ(sc, j, 0x0)) == 302101099Srwatson INTMAP_VEC(sc->sc_ign, i)) { 303101099Srwatson imr = j; 304101099Srwatson break; 305101099Srwatson } 306101099Srwatson } 307101099Srwatson if (imr == 0) 308101099Srwatson continue; 309101099Srwatson uica = malloc(sizeof(*uica), M_DEVBUF, M_NOWAIT); 310101099Srwatson if (uica == NULL) 311101099Srwatson panic("%s: could not allocate interrupt controller " 312101099Srwatson "argument", __func__); 313101099Srwatson uica->uica_sc = sc; 314101099Srwatson uica->uica_imr = imr; 315101099Srwatson#ifdef UPA_DEBUG 316101099Srwatson device_printf(dev, "intr map (INO %d) IMR%d: %#lx\n", 317101099Srwatson i, imr, (u_long)UPA_READ(sc, imr, 0x0)); 318101099Srwatson#endif 319101099Srwatson j = intr_controller_register(INTMAP_VEC(sc->sc_ign, i), 320101099Srwatson &upa_ic, uica); 321101099Srwatson if (j != 0) 322101099Srwatson device_printf(dev, "could not register interrupt " 323101099Srwatson "controller for INO %d (%d)\n", i, j); 324101099Srwatson } 325101099Srwatson 326101099Srwatson /* Make sure the power level is appropriate for normal operation. */ 327101099Srwatson if (UPA_READ(sc, UPA_CFG, UPA_CFG_IF) != UPA_CFG_IF_POK) { 328101099Srwatson if (bootverbose) 329101099Srwatson device_printf(dev, "applying power\n"); 330101099Srwatson UPA_WRITE(sc, UPA_CFG, UPA_CFG_ESTAR, UPA_CFG_ESTAR_SPEED_1_2); 331101099Srwatson UPA_WRITE(sc, UPA_CFG, UPA_CFG_ESTAR, UPA_CFG_ESTAR_SPEED_FULL); 332101099Srwatson (void)UPA_READ(sc, UPA_CFG, UPA_CFG_ESTAR); 333101099Srwatson UPA_WRITE(sc, UPA_CFG, UPA_CFG_IF, UPA_CFG_IF_POK_RST); 334101099Srwatson (void)UPA_READ(sc, UPA_CFG, UPA_CFG_IF); 335101099Srwatson DELAY(20000); 336101099Srwatson UPA_WRITE(sc, UPA_CFG, UPA_CFG_IF, UPA_CFG_IF_POK); 337101099Srwatson (void)UPA_READ(sc, UPA_CFG, UPA_CFG_IF); 338101099Srwatson } 339101099Srwatson 340101099Srwatson for (child = OF_child(node); child != 0; child = OF_peer(child)) { 341101099Srwatson /* 342101099Srwatson * The `upa-portid' properties of the children are used as 343101099Srwatson * index for the interrupt mapping registers. 344101099Srwatson * The `upa-portid' properties are also used to make up the 345101099Srwatson * INOs of the children as the values contained in their 346101099Srwatson * `interrupts' properties are bogus. 347101099Srwatson */ 348101099Srwatson if (OF_getprop(child, "upa-portid", &portid, 349101099Srwatson sizeof(portid)) == -1) { 350101099Srwatson device_printf(dev, 351101099Srwatson "could not determine upa-portid of child 0x%lx\n", 352101099Srwatson (unsigned long)child); 353101099Srwatson continue; 354101099Srwatson } 355101099Srwatson if (portid > 1) { 356101099Srwatson device_printf(dev, 357101099Srwatson "upa-portid %d of child 0x%lx invalid\n", portid, 358101099Srwatson (unsigned long)child); 359101099Srwatson continue; 360101099Srwatson } 361101099Srwatson if ((udi = upa_setup_dinfo(dev, sc, child, portid)) == NULL) 362101099Srwatson continue; 363101099Srwatson if ((cdev = device_add_child(dev, NULL, -1)) == NULL) { 364101099Srwatson device_printf(dev, "<%s>: device_add_child failed\n", 365101099Srwatson udi->udi_obdinfo.obd_name); 366101099Srwatson upa_destroy_dinfo(udi); 367101099Srwatson continue; 368101099Srwatson } 369101099Srwatson device_set_ivars(cdev, udi); 370101099Srwatson } 371101099Srwatson 372101099Srwatson return (bus_generic_attach(dev)); 373101099Srwatson 374101099Srwatson fail: 375101099Srwatson for (i = UPA_CFG; i <= UPA_IMR2 && sc->sc_res[i] != NULL; i++) 376101099Srwatson bus_release_resource(dev, SYS_RES_MEMORY, 377101099Srwatson rman_get_rid(sc->sc_res[i]), sc->sc_res[i]); 378101099Srwatson return (ENXIO); 379101099Srwatson} 380101099Srwatson 381101099Srwatsonstatic int 382101099Srwatsonupa_print_child(device_t dev, device_t child) 383101099Srwatson{ 384101099Srwatson int rv; 385101099Srwatson 386101099Srwatson rv = bus_print_child_header(dev, child); 387101099Srwatson rv += upa_print_res(device_get_ivars(child)); 388101099Srwatson rv += bus_print_child_footer(dev, child); 389101099Srwatson return (rv); 390101099Srwatson} 391101099Srwatson 392101099Srwatsonstatic void 393101099Srwatsonupa_probe_nomatch(device_t dev, device_t child) 394101099Srwatson{ 395101099Srwatson const char *type; 396101099Srwatson 397101099Srwatson device_printf(dev, "<%s>", ofw_bus_get_name(child)); 398101099Srwatson upa_print_res(device_get_ivars(child)); 399101099Srwatson type = ofw_bus_get_type(child); 400101099Srwatson printf(" type %s (no driver attached)\n", 401101099Srwatson type != NULL ? type : "unknown"); 402101099Srwatson} 403101099Srwatson 404101099Srwatsonstatic struct resource * 405101099Srwatsonupa_alloc_resource(device_t dev, device_t child, int type, int *rid, 406101099Srwatson u_long start, u_long end, u_long count, u_int flags) 407101099Srwatson{ 408101099Srwatson struct resource_list *rl; 409101099Srwatson struct resource_list_entry *rle; 410101099Srwatson struct upa_softc *sc; 411101099Srwatson struct resource *rv; 412101099Srwatson bus_addr_t cend, cstart; 413101099Srwatson int i, isdefault, passthrough; 414101099Srwatson 415101099Srwatson isdefault = (start == 0UL && end == ~0UL); 416101099Srwatson passthrough = (device_get_parent(child) != dev); 417101099Srwatson sc = device_get_softc(dev); 418101099Srwatson rl = BUS_GET_RESOURCE_LIST(dev, child); 419101099Srwatson rle = NULL; 420101099Srwatson switch (type) { 421101099Srwatson case SYS_RES_IRQ: 422101099Srwatson return (resource_list_alloc(rl, dev, child, type, rid, start, 423101099Srwatson end, count, flags)); 424101099Srwatson case SYS_RES_MEMORY: 425101099Srwatson if (!passthrough) { 426101099Srwatson rle = resource_list_find(rl, type, *rid); 427101099Srwatson if (rle == NULL) 428101099Srwatson return (NULL); 429101099Srwatson if (rle->res != NULL) 430101099Srwatson panic("%s: resource entry is busy", __func__); 431101099Srwatson if (isdefault) { 432101099Srwatson start = rle->start; 433101099Srwatson count = ulmax(count, rle->count); 434101099Srwatson end = ulmax(rle->end, start + count - 1); 435101099Srwatson } 436101099Srwatson } 437101099Srwatson for (i = 0; i < sc->sc_nrange; i++) { 438101099Srwatson cstart = sc->sc_ranges[i].child; 439101099Srwatson cend = cstart + sc->sc_ranges[i].size - 1; 440101099Srwatson if (start < cstart || start > cend) 441101099Srwatson continue; 442101099Srwatson if (end < cstart || end > cend) 443101099Srwatson return (NULL); 444101099Srwatson start += sc->sc_ranges[i].parent - cstart; 445101099Srwatson end += sc->sc_ranges[i].parent - cstart; 446101099Srwatson rv = bus_generic_alloc_resource(dev, child, type, rid, 447101099Srwatson start, end, count, flags); 448101099Srwatson if (!passthrough) 449101099Srwatson rle->res = rv; 450101099Srwatson return (rv); 451101099Srwatson } 452101099Srwatson /* FALLTHROUGH */ 453101099Srwatson default: 454101099Srwatson return (NULL); 455101099Srwatson } 456101099Srwatson} 457101099Srwatson 458101099Srwatsonstatic void 459101099Srwatsonupa_intr_enable(void *arg) 460101099Srwatson{ 461101099Srwatson struct intr_vector *iv = arg; 462101099Srwatson struct upa_icarg *uica = iv->iv_icarg; 463101099Srwatson 464101099Srwatson UPA_WRITE(uica->uica_sc, uica->uica_imr, 0x0, 465101099Srwatson INTMAP_ENABLE(iv->iv_vec, iv->iv_mid)); 466101099Srwatson (void)UPA_READ(uica->uica_sc, uica->uica_imr, 0x0); 467101099Srwatson} 468101099Srwatson 469101099Srwatsonstatic void 470101099Srwatsonupa_intr_disable(void *arg) 471101099Srwatson{ 472101099Srwatson struct intr_vector *iv = arg; 473101099Srwatson struct upa_icarg *uica = iv->iv_icarg; 474101099Srwatson 475101099Srwatson UPA_WRITE(uica->uica_sc, uica->uica_imr, 0x0, iv->iv_vec); 476101099Srwatson (void)UPA_READ(uica->uica_sc, uica->uica_imr, 0x0); 477101099Srwatson} 478101099Srwatson 479101099Srwatsonstatic void 480101099Srwatsonupa_intr_assign(void *arg) 481101099Srwatson{ 482101099Srwatson struct intr_vector *iv = arg; 483101099Srwatson struct upa_icarg *uica = iv->iv_icarg; 484101099Srwatson 485101099Srwatson UPA_WRITE(uica->uica_sc, uica->uica_imr, 0x0, INTMAP_TID( 486101099Srwatson UPA_READ(uica->uica_sc, uica->uica_imr, 0x0), iv->iv_mid)); 487101099Srwatson (void)UPA_READ(uica->uica_sc, uica->uica_imr, 0x0); 488101099Srwatson} 489101099Srwatson 490101099Srwatsonstatic int 491101099Srwatsonupa_setup_intr(device_t dev, device_t child, struct resource *ires, int flags, 492101099Srwatson driver_filter_t *filt, driver_intr_t *func, void *arg, void **cookiep) 493101099Srwatson{ 494101099Srwatson struct upa_softc *sc; 495101099Srwatson u_long vec; 496101099Srwatson 497101099Srwatson sc = device_get_softc(dev); 498101099Srwatson /* 499101099Srwatson * Make sure the vector is fully specified and we registered 500101099Srwatson * our interrupt controller for it. 501101099Srwatson */ 502101099Srwatson vec = rman_get_start(ires); 503101099Srwatson if (INTIGN(vec) != sc->sc_ign || intr_vectors[vec].iv_ic != &upa_ic) { 504101099Srwatson device_printf(dev, "invalid interrupt vector 0x%lx\n", vec); 505101099Srwatson return (EINVAL); 506101099Srwatson } 507101099Srwatson return (bus_generic_setup_intr(dev, child, ires, flags, filt, func, 508101099Srwatson arg, cookiep)); 509101099Srwatson} 510101099Srwatson 511101099Srwatsonstatic int 512101099Srwatsonupa_adjust_resource(device_t bus __unused, device_t child __unused, 513101099Srwatson int type __unused, struct resource *r __unused, u_long start __unused, 514101099Srwatson u_long end __unused) 515101099Srwatson{ 516101099Srwatson 517101099Srwatson return (ENXIO); 518101099Srwatson} 519101099Srwatson 520101099Srwatsonstatic struct resource_list * 521101099Srwatsonupa_get_resource_list(device_t dev, device_t child) 522101099Srwatson{ 523101099Srwatson struct upa_devinfo *udi; 524101099Srwatson 525101099Srwatson udi = device_get_ivars(child); 526101099Srwatson return (&udi->udi_rl); 527101099Srwatson} 528101099Srwatson 529101099Srwatsonstatic const struct ofw_bus_devinfo * 530101099Srwatsonupa_get_devinfo(device_t dev, device_t child) 531101099Srwatson{ 532101099Srwatson struct upa_devinfo *udi; 533101099Srwatson 534101099Srwatson udi = device_get_ivars(child); 535101099Srwatson return (&udi->udi_obdinfo); 536101099Srwatson} 537101099Srwatson 538101099Srwatsonstatic struct upa_devinfo * 539101099Srwatsonupa_setup_dinfo(device_t dev, struct upa_softc *sc, phandle_t node, 540101099Srwatson uint32_t portid) 541101099Srwatson{ 542101099Srwatson struct upa_devinfo *udi; 543101099Srwatson struct upa_regs *reg; 544101099Srwatson uint32_t intr; 545101099Srwatson int i, nreg; 546101099Srwatson 547101099Srwatson udi = malloc(sizeof(*udi), M_DEVBUF, M_WAITOK | M_ZERO); 548101099Srwatson if (ofw_bus_gen_setup_devinfo(&udi->udi_obdinfo, node) != 0) { 549101099Srwatson free(udi, M_DEVBUF); 550101099Srwatson return (NULL); 551101099Srwatson } 552101099Srwatson resource_list_init(&udi->udi_rl); 553101099Srwatson 554101099Srwatson nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)®); 555101099Srwatson if (nreg == -1) { 556101099Srwatson device_printf(dev, "<%s>: incomplete\n", 557101099Srwatson udi->udi_obdinfo.obd_name); 558101099Srwatson goto fail; 559101099Srwatson } 560101099Srwatson for (i = 0; i < nreg; i++) 561101099Srwatson resource_list_add(&udi->udi_rl, SYS_RES_MEMORY, i, reg[i].phys, 562101099Srwatson reg[i].phys + reg[i].size - 1, reg[i].size); 563101099Srwatson free(reg, M_OFWPROP); 564101099Srwatson 565101099Srwatson intr = INTMAP_VEC(sc->sc_ign, (UPA_INO_BASE + portid)); 566101099Srwatson resource_list_add(&udi->udi_rl, SYS_RES_IRQ, 0, intr, intr, 1); 567101099Srwatson 568101099Srwatson return (udi); 569101099Srwatson 570101099Srwatson fail: 571101099Srwatson upa_destroy_dinfo(udi); 572101099Srwatson return (NULL); 573101099Srwatson} 574101099Srwatson 575101099Srwatsonstatic void 576101099Srwatsonupa_destroy_dinfo(struct upa_devinfo *dinfo) 577101099Srwatson{ 578101099Srwatson 579101099Srwatson resource_list_free(&dinfo->udi_rl); 580101099Srwatson ofw_bus_gen_destroy_devinfo(&dinfo->udi_obdinfo); 581101099Srwatson free(dinfo, M_DEVBUF); 582101099Srwatson} 583101099Srwatson 584101099Srwatsonstatic int 585101099Srwatsonupa_print_res(struct upa_devinfo *udi) 586101099Srwatson{ 587101099Srwatson int rv; 588101099Srwatson 589101099Srwatson rv = 0; 590101099Srwatson rv += resource_list_print_type(&udi->udi_rl, "mem", SYS_RES_MEMORY, 591101099Srwatson "%#lx"); 592101099Srwatson rv += resource_list_print_type(&udi->udi_rl, "irq", SYS_RES_IRQ, 593101099Srwatson "%ld"); 594101099Srwatson return (rv); 595101099Srwatson} 596101099Srwatson