190618Stmm/*- 2219567Smarius * Copyright (c) 1999-2002 Eduardo Horvath 390618Stmm * All rights reserved. 490618Stmm * 590618Stmm * Redistribution and use in source and binary forms, with or without 690618Stmm * modification, are permitted provided that the following conditions 790618Stmm * are met: 890618Stmm * 1. Redistributions of source code must retain the above copyright 990618Stmm * notice, this list of conditions and the following disclaimer. 1090618Stmm * 2. Redistributions in binary form must reproduce the above copyright 1190618Stmm * notice, this list of conditions and the following disclaimer in the 1290618Stmm * documentation and/or other materials provided with the distribution. 13219567Smarius * 3. The name of the author may not be used to endorse or promote products 14219567Smarius * derived from this software without specific prior written permission. 1590618Stmm * 16219567Smarius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17219567Smarius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18219567Smarius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19219567Smarius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20219567Smarius * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21219567Smarius * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22219567Smarius * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23219567Smarius * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24219567Smarius * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2590618Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2690618Stmm * SUCH DAMAGE. 27219567Smarius * 28219567Smarius * from: NetBSD: sbus.c,v 1.50 2002/06/20 18:26:24 eeh Exp 2990618Stmm */ 30139825Simp/*- 3190618Stmm * Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>. 32167308Smarius * Copyright (c) 2005 Marius Strobl <marius@FreeBSD.org> 3390618Stmm * All rights reserved. 3490618Stmm * 3590618Stmm * Redistribution and use in source and binary forms, with or without 3690618Stmm * modification, are permitted provided that the following conditions 3790618Stmm * are met: 3890618Stmm * 1. Redistributions of source code must retain the above copyright 3990618Stmm * notice, this list of conditions and the following disclaimer. 4090618Stmm * 4190618Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 4290618Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 4390618Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 4490618Stmm * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE 4590618Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 4690618Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 4790618Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 4890618Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 4990618Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 5090618Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 5190618Stmm * SUCH DAMAGE. 5290618Stmm */ 5390618Stmm 54145185Smarius#include <sys/cdefs.h> 55145185Smarius__FBSDID("$FreeBSD$"); 56145185Smarius 5790618Stmm/* 58145185Smarius * SBus support. 5990618Stmm */ 60131376Smarius 6190618Stmm#include <sys/param.h> 6290618Stmm#include <sys/systm.h> 6390618Stmm#include <sys/bus.h> 6490618Stmm#include <sys/kernel.h> 6590618Stmm#include <sys/malloc.h> 66130068Sphk#include <sys/module.h> 67107477Stmm#include <sys/pcpu.h> 68171730Smarius#include <sys/queue.h> 6990618Stmm#include <sys/reboot.h> 70171730Smarius#include <sys/rman.h> 7190618Stmm 72133589Smarius#include <dev/ofw/ofw_bus.h> 73152684Smarius#include <dev/ofw/ofw_bus_subr.h> 74119338Simp#include <dev/ofw/openfirm.h> 7590618Stmm 7690618Stmm#include <machine/bus.h> 77171730Smarius#include <machine/bus_common.h> 78116541Stmm#include <machine/bus_private.h> 7990618Stmm#include <machine/iommureg.h> 80171730Smarius#include <machine/iommuvar.h> 8190618Stmm#include <machine/resource.h> 8290618Stmm 8390618Stmm#include <sparc64/sbus/ofw_sbus.h> 8490618Stmm#include <sparc64/sbus/sbusreg.h> 8590618Stmm#include <sparc64/sbus/sbusvar.h> 8690618Stmm 8790618Stmmstruct sbus_devinfo { 8890618Stmm int sdi_burstsz; 89145186Smarius int sdi_clockfreq; 9090618Stmm int sdi_slot; 9190618Stmm 92152684Smarius struct ofw_bus_devinfo sdi_obdinfo; 9390618Stmm struct resource_list sdi_rl; 9490618Stmm}; 9590618Stmm 9690618Stmm/* Range descriptor, allocated for each sc_range. */ 9790618Stmmstruct sbus_rd { 9890618Stmm bus_addr_t rd_poffset; 9990618Stmm bus_addr_t rd_pend; 10090618Stmm int rd_slot; 10190618Stmm bus_addr_t rd_coffset; 10290618Stmm bus_addr_t rd_cend; 10390618Stmm struct rman rd_rman; 10490618Stmm bus_space_handle_t rd_bushandle; 10590618Stmm struct resource *rd_res; 10690618Stmm}; 10790618Stmm 10890618Stmmstruct sbus_softc { 109172066Smarius device_t sc_dev; 11090618Stmm bus_dma_tag_t sc_cdmatag; 11190618Stmm int sc_clockfreq; /* clock frequency (in Hz) */ 11290618Stmm int sc_nrange; 11390618Stmm struct sbus_rd *sc_rd; 114145185Smarius int sc_burst; /* burst transfer sizes supp. */ 11590618Stmm 11690618Stmm struct resource *sc_sysio_res; 117145185Smarius int sc_ign; /* IGN for this sysio */ 118145185Smarius struct iommu_state sc_is; /* IOMMU state (iommuvar.h) */ 11990618Stmm 12090618Stmm struct resource *sc_ot_ires; 12190618Stmm void *sc_ot_ihand; 12290618Stmm struct resource *sc_pf_ires; 12390618Stmm void *sc_pf_ihand; 12490618Stmm}; 12590618Stmm 126206018Smarius#define SYSIO_READ8(sc, off) \ 127170852Smarius bus_read_8((sc)->sc_sysio_res, (off)) 128206018Smarius#define SYSIO_WRITE8(sc, off, v) \ 129170852Smarius bus_write_8((sc)->sc_sysio_res, (off), (v)) 13090618Stmm 131145185Smariusstatic device_probe_t sbus_probe; 132145186Smariusstatic device_attach_t sbus_attach; 133145185Smariusstatic bus_print_child_t sbus_print_child; 134145185Smariusstatic bus_probe_nomatch_t sbus_probe_nomatch; 135145185Smariusstatic bus_read_ivar_t sbus_read_ivar; 136145185Smariusstatic bus_get_resource_list_t sbus_get_resource_list; 137145185Smariusstatic bus_setup_intr_t sbus_setup_intr; 138145185Smariusstatic bus_alloc_resource_t sbus_alloc_resource; 139230687Smariusstatic bus_activate_resource_t sbus_activate_resource; 140230687Smariusstatic bus_adjust_resource_t sbus_adjust_resource; 141145185Smariusstatic bus_release_resource_t sbus_release_resource; 142167308Smariusstatic bus_get_dma_tag_t sbus_get_dma_tag; 143152684Smariusstatic ofw_bus_get_devinfo_t sbus_get_devinfo; 14490618Stmm 145190112Smariusstatic int sbus_inlist(const char *, const char *const *); 146152684Smariusstatic struct sbus_devinfo * sbus_setup_dinfo(device_t, struct sbus_softc *, 147152684Smarius phandle_t); 148152684Smariusstatic void sbus_destroy_dinfo(struct sbus_devinfo *); 149172066Smariusstatic void sbus_intr_enable(void *); 150172066Smariusstatic void sbus_intr_disable(void *); 151178443Smariusstatic void sbus_intr_assign(void *); 152178443Smariusstatic void sbus_intr_clear(void *); 153172066Smariusstatic int sbus_find_intrmap(struct sbus_softc *, u_int, bus_addr_t *, 154172066Smarius bus_addr_t *); 155170852Smariusstatic driver_intr_t sbus_overtemp; 156170852Smariusstatic driver_intr_t sbus_pwrfail; 157152684Smariusstatic int sbus_print_res(struct sbus_devinfo *); 15890618Stmm 15990618Stmmstatic device_method_t sbus_methods[] = { 16090618Stmm /* Device interface */ 16190618Stmm DEVMETHOD(device_probe, sbus_probe), 162145186Smarius DEVMETHOD(device_attach, sbus_attach), 163154870Smarius DEVMETHOD(device_shutdown, bus_generic_shutdown), 164154870Smarius DEVMETHOD(device_suspend, bus_generic_suspend), 165154870Smarius DEVMETHOD(device_resume, bus_generic_resume), 16690618Stmm 16790618Stmm /* Bus interface */ 16890618Stmm DEVMETHOD(bus_print_child, sbus_print_child), 16990618Stmm DEVMETHOD(bus_probe_nomatch, sbus_probe_nomatch), 17090618Stmm DEVMETHOD(bus_read_ivar, sbus_read_ivar), 17190618Stmm DEVMETHOD(bus_alloc_resource, sbus_alloc_resource), 172230687Smarius DEVMETHOD(bus_activate_resource, sbus_activate_resource), 173230687Smarius DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 174230687Smarius DEVMETHOD(bus_adjust_resource, sbus_adjust_resource), 17590618Stmm DEVMETHOD(bus_release_resource, sbus_release_resource), 176230687Smarius DEVMETHOD(bus_setup_intr, sbus_setup_intr), 177190112Smarius DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 178190112Smarius DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 17990618Stmm DEVMETHOD(bus_get_resource_list, sbus_get_resource_list), 180190114Smarius DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str), 181167308Smarius DEVMETHOD(bus_get_dma_tag, sbus_get_dma_tag), 18290618Stmm 183133589Smarius /* ofw_bus interface */ 184152684Smarius DEVMETHOD(ofw_bus_get_devinfo, sbus_get_devinfo), 185152684Smarius DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), 186152684Smarius DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), 187152684Smarius DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), 188152684Smarius DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), 189152684Smarius DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), 190133589Smarius 191229093Shselasky DEVMETHOD_END 19290618Stmm}; 19390618Stmm 19490618Stmmstatic driver_t sbus_driver = { 19590618Stmm "sbus", 19690618Stmm sbus_methods, 19790618Stmm sizeof(struct sbus_softc), 19890618Stmm}; 19990618Stmm 20090618Stmmstatic devclass_t sbus_devclass; 20190618Stmm 202248050SmariusEARLY_DRIVER_MODULE(sbus, nexus, sbus_driver, sbus_devclass, NULL, NULL, 203200874Smarius BUS_PASS_BUS); 204200816SmariusMODULE_DEPEND(sbus, nexus, 1, 1, 1); 205182062SmariusMODULE_VERSION(sbus, 1); 20690618Stmm 20790618Stmm#define OFW_SBUS_TYPE "sbus" 20890618Stmm#define OFW_SBUS_NAME "sbus" 20990618Stmm 210172066Smariusstatic const struct intr_controller sbus_ic = { 211172066Smarius sbus_intr_enable, 212172066Smarius sbus_intr_disable, 213178443Smarius sbus_intr_assign, 214178443Smarius sbus_intr_clear 215172066Smarius}; 216172066Smarius 217172066Smariusstruct sbus_icarg { 218172066Smarius struct sbus_softc *sica_sc; 219172066Smarius bus_addr_t sica_map; 220172066Smarius bus_addr_t sica_clr; 221172066Smarius}; 222172066Smarius 223190112Smariusstatic const char *const sbus_order_first[] = { 224146391Smarius "auxio", 225146391Smarius "dma", 226146391Smarius NULL 227146391Smarius}; 228146391Smarius 22990618Stmmstatic int 230190112Smariussbus_inlist(const char *name, const char *const *list) 231146391Smarius{ 232146391Smarius int i; 233146391Smarius 234146391Smarius if (name == NULL) 235146391Smarius return (0); 236146391Smarius for (i = 0; list[i] != NULL; i++) { 237146391Smarius if (strcmp(name, list[i]) == 0) 238146391Smarius return (1); 239146391Smarius } 240146391Smarius return (0); 241146391Smarius} 242146391Smarius 243146391Smariusstatic int 24490618Stmmsbus_probe(device_t dev) 24590618Stmm{ 246167308Smarius const char *t; 247145186Smarius 248167308Smarius t = ofw_bus_get_type(dev); 249145186Smarius if (((t == NULL || strcmp(t, OFW_SBUS_TYPE) != 0)) && 250167308Smarius strcmp(ofw_bus_get_name(dev), OFW_SBUS_NAME) != 0) 251145186Smarius return (ENXIO); 252145186Smarius device_set_desc(dev, "U2S UPA-SBus bridge"); 253145186Smarius return (0); 254145186Smarius} 255145186Smarius 256145186Smariusstatic int 257145186Smariussbus_attach(device_t dev) 258145186Smarius{ 259145185Smarius struct sbus_softc *sc; 26090618Stmm struct sbus_devinfo *sdi; 261172066Smarius struct sbus_icarg *sica; 26290618Stmm struct sbus_ranges *range; 26390618Stmm struct resource *res; 264167308Smarius struct resource_list *rl; 26590618Stmm device_t cdev; 266172066Smarius bus_addr_t intrclr, intrmap, phys; 26790618Stmm bus_size_t size; 268172066Smarius u_long vec; 269145185Smarius phandle_t child, node; 270190112Smarius uint32_t prop; 271190112Smarius int i, j; 27290618Stmm 273145185Smarius sc = device_get_softc(dev); 274172066Smarius sc->sc_dev = dev; 275167308Smarius node = ofw_bus_get_node(dev); 276145185Smarius 277190112Smarius i = 0; 278190112Smarius sc->sc_sysio_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i, 279167308Smarius RF_ACTIVE); 280167308Smarius if (sc->sc_sysio_res == NULL) 281145185Smarius panic("%s: cannot allocate device memory", __func__); 28290618Stmm 283190112Smarius if (OF_getprop(node, "interrupts", &prop, sizeof(prop)) == -1) 284145185Smarius panic("%s: cannot get IGN", __func__); 285190112Smarius sc->sc_ign = INTIGN(prop); 28690618Stmm 28790618Stmm /* 28890618Stmm * Record clock frequency for synchronous SCSI. 28990618Stmm * IS THIS THE CORRECT DEFAULT?? 29090618Stmm */ 291190112Smarius if (OF_getprop(node, "clock-frequency", &prop, sizeof(prop)) == -1) 292190112Smarius prop = 25000000; 293190112Smarius sc->sc_clockfreq = prop; 294190112Smarius prop /= 1000; 295190112Smarius device_printf(dev, "clock %d.%03d MHz\n", prop / 1000, prop % 1000); 29690618Stmm 29790618Stmm /* 29890618Stmm * Collect address translations from the OBP. 29990618Stmm */ 30090618Stmm if ((sc->sc_nrange = OF_getprop_alloc(node, "ranges", 30190618Stmm sizeof(*range), (void **)&range)) == -1) { 302145185Smarius panic("%s: error getting ranges property", __func__); 30390618Stmm } 304225229Smarius sc->sc_rd = malloc(sizeof(*sc->sc_rd) * sc->sc_nrange, M_DEVBUF, 305225229Smarius M_NOWAIT | M_ZERO); 30690618Stmm if (sc->sc_rd == NULL) 307145185Smarius panic("%s: cannot allocate rmans", __func__); 30890618Stmm /* 30990618Stmm * Preallocate all space that the SBus bridge decodes, so that nothing 31090618Stmm * else gets in the way; set up rmans etc. 31190618Stmm */ 312167308Smarius rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); 31390618Stmm for (i = 0; i < sc->sc_nrange; i++) { 31490618Stmm phys = range[i].poffset | ((bus_addr_t)range[i].pspace << 32); 31590618Stmm size = range[i].size; 31690618Stmm sc->sc_rd[i].rd_slot = range[i].cspace; 31790618Stmm sc->sc_rd[i].rd_coffset = range[i].coffset; 31890618Stmm sc->sc_rd[i].rd_cend = sc->sc_rd[i].rd_coffset + size; 319190112Smarius j = resource_list_add_next(rl, SYS_RES_MEMORY, phys, 320167308Smarius phys + size - 1, size); 321190112Smarius if ((res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &j, 322167308Smarius RF_ACTIVE)) == NULL) 323145185Smarius panic("%s: cannot allocate decoded range", __func__); 32490618Stmm sc->sc_rd[i].rd_bushandle = rman_get_bushandle(res); 32590618Stmm sc->sc_rd[i].rd_rman.rm_type = RMAN_ARRAY; 32690618Stmm sc->sc_rd[i].rd_rman.rm_descr = "SBus Device Memory"; 32790618Stmm if (rman_init(&sc->sc_rd[i].rd_rman) != 0 || 32890618Stmm rman_manage_region(&sc->sc_rd[i].rd_rman, 0, size) != 0) 329145185Smarius panic("%s: failed to set up memory rman", __func__); 33090618Stmm sc->sc_rd[i].rd_poffset = phys; 33190618Stmm sc->sc_rd[i].rd_pend = phys + size; 33290618Stmm sc->sc_rd[i].rd_res = res; 33390618Stmm } 33490618Stmm free(range, M_OFWPROP); 33590618Stmm 33690618Stmm /* 33790618Stmm * Get the SBus burst transfer size if burst transfers are supported. 33890618Stmm */ 339190112Smarius if (OF_getprop(node, "up-burst-sizes", &sc->sc_burst, 34090618Stmm sizeof(sc->sc_burst)) == -1 || sc->sc_burst == 0) 341190112Smarius sc->sc_burst = 342190112Smarius (SBUS_BURST64_DEF << SBUS_BURST64_SHIFT) | SBUS_BURST_DEF; 34390618Stmm 34490618Stmm /* initalise the IOMMU */ 34590618Stmm 34690618Stmm /* punch in our copies */ 347171730Smarius sc->sc_is.is_pmaxaddr = IOMMU_MAXADDR(SBUS_IOMMU_BITS); 348170852Smarius sc->sc_is.is_bustag = rman_get_bustag(sc->sc_sysio_res); 349170852Smarius sc->sc_is.is_bushandle = rman_get_bushandle(sc->sc_sysio_res); 35090618Stmm sc->sc_is.is_iommu = SBR_IOMMU; 35190618Stmm sc->sc_is.is_dtag = SBR_IOMMU_TLB_TAG_DIAG; 35290618Stmm sc->sc_is.is_ddram = SBR_IOMMU_TLB_DATA_DIAG; 35390618Stmm sc->sc_is.is_dqueue = SBR_IOMMU_QUEUE_DIAG; 35490618Stmm sc->sc_is.is_dva = SBR_IOMMU_SVADIAG; 35590618Stmm sc->sc_is.is_dtcmp = 0; 35690618Stmm sc->sc_is.is_sb[0] = SBR_STRBUF; 357123865Sobrien sc->sc_is.is_sb[1] = 0; 35890618Stmm 359100188Stmm /* 360100188Stmm * Note: the SBus IOMMU ignores the high bits of an address, so a NULL 361100188Stmm * DMA pointer will be translated by the first page of the IOTSB. 362100188Stmm * To detect bugs we'll allocate and ignore the first entry. 363100188Stmm */ 364178840Smarius iommu_init(device_get_nameunit(dev), &sc->sc_is, 3, -1, 1); 36590618Stmm 366116213Stmm /* Create the DMA tag. */ 367171730Smarius if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0, 368171730Smarius sc->sc_is.is_pmaxaddr, ~0, NULL, NULL, sc->sc_is.is_pmaxaddr, 369171730Smarius 0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_cdmatag) != 0) 370145185Smarius panic("%s: bus_dma_tag_create failed", __func__); 371116213Stmm /* Customize the tag. */ 372116213Stmm sc->sc_cdmatag->dt_cookie = &sc->sc_is; 373116541Stmm sc->sc_cdmatag->dt_mt = &iommu_dma_methods; 374116213Stmm 375230687Smarius /* 376172066Smarius * Hunt through all the interrupt mapping regs and register our 377172066Smarius * interrupt controller for the corresponding interrupt vectors. 378190112Smarius * We do this early in order to be able to catch stray interrupts. 379172066Smarius */ 380172066Smarius for (i = 0; i <= SBUS_MAX_INO; i++) { 381172066Smarius if (sbus_find_intrmap(sc, i, &intrmap, &intrclr) == 0) 382172066Smarius continue; 383172066Smarius sica = malloc(sizeof(*sica), M_DEVBUF, M_NOWAIT); 384172066Smarius if (sica == NULL) 385172066Smarius panic("%s: could not allocate interrupt controller " 386172066Smarius "argument", __func__); 387172066Smarius sica->sica_sc = sc; 388172066Smarius sica->sica_map = intrmap; 389172066Smarius sica->sica_clr = intrclr; 390172066Smarius#ifdef SBUS_DEBUG 391172066Smarius device_printf(dev, 392172066Smarius "intr map (INO %d, %s) %#lx: %#lx, clr: %#lx\n", 393172066Smarius i, (i & INTMAP_OBIO_MASK) == 0 ? "SBus slot" : "OBIO", 394172066Smarius (u_long)intrmap, (u_long)SYSIO_READ8(sc, intrmap), 395172066Smarius (u_long)intrclr); 396172066Smarius#endif 397190112Smarius j = intr_controller_register(INTMAP_VEC(sc->sc_ign, i), 398190112Smarius &sbus_ic, sica); 399190112Smarius if (j != 0) 400190112Smarius device_printf(dev, "could not register interrupt " 401190112Smarius "controller for INO %d (%d)\n", i, j); 402172066Smarius } 403172066Smarius 404145185Smarius /* Enable the over-temperature and power-fail interrupts. */ 405190112Smarius i = 4; 406190112Smarius sc->sc_ot_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, 407167308Smarius RF_ACTIVE); 408166034Smarius if (sc->sc_ot_ires == NULL || 409172066Smarius INTIGN(vec = rman_get_start(sc->sc_ot_ires)) != sc->sc_ign || 410172066Smarius INTVEC(SYSIO_READ8(sc, SBR_THERM_INT_MAP)) != vec || 411172066Smarius intr_vectors[vec].iv_ic != &sbus_ic || 412216961Smarius bus_setup_intr(dev, sc->sc_ot_ires, INTR_TYPE_MISC | INTR_BRIDGE, 413170852Smarius NULL, sbus_overtemp, sc, &sc->sc_ot_ihand) != 0) 414166034Smarius panic("%s: failed to set up temperature interrupt", __func__); 415190112Smarius i = 3; 416190112Smarius sc->sc_pf_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, 417167308Smarius RF_ACTIVE); 418166034Smarius if (sc->sc_pf_ires == NULL || 419172066Smarius INTIGN(vec = rman_get_start(sc->sc_pf_ires)) != sc->sc_ign || 420172066Smarius INTVEC(SYSIO_READ8(sc, SBR_POWER_INT_MAP)) != vec || 421172066Smarius intr_vectors[vec].iv_ic != &sbus_ic || 422216961Smarius bus_setup_intr(dev, sc->sc_pf_ires, INTR_TYPE_MISC | INTR_BRIDGE, 423170852Smarius NULL, sbus_pwrfail, sc, &sc->sc_pf_ihand) != 0) 424166034Smarius panic("%s: failed to set up power fail interrupt", __func__); 42590618Stmm 42690618Stmm /* Initialize the counter-timer. */ 427178840Smarius sparc64_counter_init(device_get_nameunit(dev), 428178840Smarius rman_get_bustag(sc->sc_sysio_res), 429170852Smarius rman_get_bushandle(sc->sc_sysio_res), SBR_TC0); 43090618Stmm 43190618Stmm /* 43290618Stmm * Loop through ROM children, fixing any relative addresses 43390618Stmm * and then configuring each device. 43490618Stmm */ 43590618Stmm for (child = OF_child(node); child != 0; child = OF_peer(child)) { 436152684Smarius if ((sdi = sbus_setup_dinfo(dev, sc, child)) == NULL) 43790618Stmm continue; 438146391Smarius /* 439146391Smarius * For devices where there are variants that are actually 440146391Smarius * split into two SBus devices (as opposed to the first 441146391Smarius * half of the device being a SBus device and the second 442146391Smarius * half hanging off of the first one) like 'auxio' and 443146391Smarius * 'SUNW,fdtwo' or 'dma' and 'esp' probe the SBus device 444146391Smarius * which is a prerequisite to the driver attaching to the 445146391Smarius * second one with a lower order. Saves us from dealing 446146391Smarius * with different probe orders in the respective device 447146391Smarius * drivers which generally is more hackish. 448146391Smarius */ 449146391Smarius cdev = device_add_child_ordered(dev, (OF_child(child) == 0 && 450152684Smarius sbus_inlist(sdi->sdi_obdinfo.obd_name, sbus_order_first)) ? 451152684Smarius SBUS_ORDER_FIRST : SBUS_ORDER_NORMAL, NULL, -1); 452152684Smarius if (cdev == NULL) { 453152684Smarius device_printf(dev, 454152684Smarius "<%s>: device_add_child_ordered failed\n", 455152684Smarius sdi->sdi_obdinfo.obd_name); 456152684Smarius sbus_destroy_dinfo(sdi); 457152684Smarius continue; 458152684Smarius } 45990618Stmm device_set_ivars(cdev, sdi); 46090618Stmm } 461145186Smarius return (bus_generic_attach(dev)); 46290618Stmm} 46390618Stmm 46490618Stmmstatic struct sbus_devinfo * 465152684Smariussbus_setup_dinfo(device_t dev, struct sbus_softc *sc, phandle_t node) 46690618Stmm{ 46790618Stmm struct sbus_devinfo *sdi; 46890618Stmm struct sbus_regs *reg; 46990618Stmm u_int32_t base, iv, *intr; 47090618Stmm int i, nreg, nintr, slot, rslot; 47190618Stmm 472111119Simp sdi = malloc(sizeof(*sdi), M_DEVBUF, M_ZERO | M_WAITOK); 473152684Smarius if (ofw_bus_gen_setup_devinfo(&sdi->sdi_obdinfo, node) != 0) { 474152684Smarius free(sdi, M_DEVBUF); 47590618Stmm return (NULL); 476152684Smarius } 47790618Stmm resource_list_init(&sdi->sdi_rl); 47890618Stmm slot = -1; 47990618Stmm nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)®); 48090618Stmm if (nreg == -1) { 481152684Smarius if (sdi->sdi_obdinfo.obd_type == NULL || 482152684Smarius strcmp(sdi->sdi_obdinfo.obd_type, "hierarchical") != 0) { 483152684Smarius device_printf(dev, "<%s>: incomplete\n", 484152684Smarius sdi->sdi_obdinfo.obd_name); 485152684Smarius goto fail; 48690618Stmm } 48790618Stmm } else { 48890618Stmm for (i = 0; i < nreg; i++) { 48990618Stmm base = reg[i].sbr_offset; 49090618Stmm if (SBUS_ABS(base)) { 49190618Stmm rslot = SBUS_ABS_TO_SLOT(base); 49290618Stmm base = SBUS_ABS_TO_OFFSET(base); 49390618Stmm } else 49490618Stmm rslot = reg[i].sbr_slot; 495152684Smarius if (slot != -1 && slot != rslot) { 496152684Smarius device_printf(dev, "<%s>: multiple slots\n", 497152684Smarius sdi->sdi_obdinfo.obd_name); 498152684Smarius free(reg, M_OFWPROP); 499152684Smarius goto fail; 500152684Smarius } 50190618Stmm slot = rslot; 50290618Stmm 50390618Stmm resource_list_add(&sdi->sdi_rl, SYS_RES_MEMORY, i, 50490618Stmm base, base + reg[i].sbr_size, reg[i].sbr_size); 50590618Stmm } 50690618Stmm free(reg, M_OFWPROP); 50790618Stmm } 50890618Stmm sdi->sdi_slot = slot; 50990618Stmm 51090618Stmm /* 511145185Smarius * The `interrupts' property contains the SBus interrupt level. 51290618Stmm */ 513145185Smarius nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intr), 514145185Smarius (void **)&intr); 51590618Stmm if (nintr != -1) { 51690618Stmm for (i = 0; i < nintr; i++) { 51790618Stmm iv = intr[i]; 51890618Stmm /* 519145185Smarius * SBus card devices need the slot number encoded into 52090618Stmm * the vector as this is generally not done. 52190618Stmm */ 522107477Stmm if ((iv & INTMAP_OBIO_MASK) == 0) 52390618Stmm iv |= slot << 3; 524172066Smarius iv = INTMAP_VEC(sc->sc_ign, iv); 52590618Stmm resource_list_add(&sdi->sdi_rl, SYS_RES_IRQ, i, 52690618Stmm iv, iv, 1); 52790618Stmm } 52890618Stmm free(intr, M_OFWPROP); 52990618Stmm } 53090618Stmm if (OF_getprop(node, "burst-sizes", &sdi->sdi_burstsz, 53190618Stmm sizeof(sdi->sdi_burstsz)) == -1) 53290618Stmm sdi->sdi_burstsz = sc->sc_burst; 53390618Stmm else 53490618Stmm sdi->sdi_burstsz &= sc->sc_burst; 535145186Smarius if (OF_getprop(node, "clock-frequency", &sdi->sdi_clockfreq, 536145186Smarius sizeof(sdi->sdi_clockfreq)) == -1) 537145186Smarius sdi->sdi_clockfreq = sc->sc_clockfreq; 53890618Stmm 53990618Stmm return (sdi); 540152684Smarius 541152684Smariusfail: 542152684Smarius sbus_destroy_dinfo(sdi); 543152684Smarius return (NULL); 54490618Stmm} 54590618Stmm 54690618Stmmstatic void 54790618Stmmsbus_destroy_dinfo(struct sbus_devinfo *dinfo) 54890618Stmm{ 54990618Stmm 55090618Stmm resource_list_free(&dinfo->sdi_rl); 551152684Smarius ofw_bus_gen_destroy_devinfo(&dinfo->sdi_obdinfo); 55290618Stmm free(dinfo, M_DEVBUF); 55390618Stmm} 55490618Stmm 55590618Stmmstatic int 55690618Stmmsbus_print_child(device_t dev, device_t child) 55790618Stmm{ 55890618Stmm int rv; 55990618Stmm 56090618Stmm rv = bus_print_child_header(dev, child); 561152684Smarius rv += sbus_print_res(device_get_ivars(child)); 56290618Stmm rv += bus_print_child_footer(dev, child); 56390618Stmm return (rv); 56490618Stmm} 56590618Stmm 56690618Stmmstatic void 56790618Stmmsbus_probe_nomatch(device_t dev, device_t child) 56890618Stmm{ 569152684Smarius const char *type; 57090618Stmm 571152684Smarius device_printf(dev, "<%s>", ofw_bus_get_name(child)); 572152684Smarius sbus_print_res(device_get_ivars(child)); 573152684Smarius type = ofw_bus_get_type(child); 574145186Smarius printf(" type %s (no driver attached)\n", 575152684Smarius type != NULL ? type : "unknown"); 57690618Stmm} 57790618Stmm 57890618Stmmstatic int 57990618Stmmsbus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 58090618Stmm{ 581146391Smarius struct sbus_softc *sc; 58290618Stmm struct sbus_devinfo *dinfo; 58390618Stmm 584146391Smarius sc = device_get_softc(dev); 58590618Stmm if ((dinfo = device_get_ivars(child)) == NULL) 58690618Stmm return (ENOENT); 58790618Stmm switch (which) { 58890618Stmm case SBUS_IVAR_BURSTSZ: 58990618Stmm *result = dinfo->sdi_burstsz; 59090618Stmm break; 59190618Stmm case SBUS_IVAR_CLOCKFREQ: 592145186Smarius *result = dinfo->sdi_clockfreq; 59390618Stmm break; 594146391Smarius case SBUS_IVAR_IGN: 595146391Smarius *result = sc->sc_ign; 596146391Smarius break; 59790618Stmm case SBUS_IVAR_SLOT: 59890618Stmm *result = dinfo->sdi_slot; 59990618Stmm break; 60090618Stmm default: 60190618Stmm return (ENOENT); 60290618Stmm } 603146391Smarius return (0); 60490618Stmm} 60590618Stmm 60690618Stmmstatic struct resource_list * 60790618Stmmsbus_get_resource_list(device_t dev, device_t child) 60890618Stmm{ 60990618Stmm struct sbus_devinfo *sdi; 61090618Stmm 61190618Stmm sdi = device_get_ivars(child); 61290618Stmm return (&sdi->sdi_rl); 61390618Stmm} 61490618Stmm 615172066Smariusstatic void 616172066Smariussbus_intr_enable(void *arg) 617170387Spiso{ 618172066Smarius struct intr_vector *iv = arg; 619172066Smarius struct sbus_icarg *sica = iv->iv_icarg; 620170387Spiso 621172066Smarius SYSIO_WRITE8(sica->sica_sc, sica->sica_map, 622172066Smarius INTMAP_ENABLE(iv->iv_vec, iv->iv_mid)); 623170387Spiso} 624178443Smarius 625172066Smariusstatic void 626172066Smariussbus_intr_disable(void *arg) 627172066Smarius{ 628172066Smarius struct intr_vector *iv = arg; 629172066Smarius struct sbus_icarg *sica = iv->iv_icarg; 630170387Spiso 631172066Smarius SYSIO_WRITE8(sica->sica_sc, sica->sica_map, iv->iv_vec); 632172066Smarius} 633172066Smarius 634170387Spisostatic void 635178443Smariussbus_intr_assign(void *arg) 63690618Stmm{ 637172066Smarius struct intr_vector *iv = arg; 638172066Smarius struct sbus_icarg *sica = iv->iv_icarg; 63990618Stmm 640178443Smarius SYSIO_WRITE8(sica->sica_sc, sica->sica_map, INTMAP_TID( 641178443Smarius SYSIO_READ8(sica->sica_sc, sica->sica_map), iv->iv_mid)); 642178443Smarius} 643178443Smarius 644178443Smariusstatic void 645178443Smariussbus_intr_clear(void *arg) 646178443Smarius{ 647178443Smarius struct intr_vector *iv = arg; 648178443Smarius struct sbus_icarg *sica = iv->iv_icarg; 649178443Smarius 650206018Smarius SYSIO_WRITE8(sica->sica_sc, sica->sica_clr, INTCLR_IDLE); 65190618Stmm} 65290618Stmm 65390618Stmmstatic int 654172066Smariussbus_find_intrmap(struct sbus_softc *sc, u_int ino, bus_addr_t *intrmapptr, 655172066Smarius bus_addr_t *intrclrptr) 65690618Stmm{ 657172066Smarius bus_addr_t intrclr, intrmap; 658172066Smarius int i; 65990618Stmm 660172066Smarius if (ino > SBUS_MAX_INO) { 661172066Smarius device_printf(sc->sc_dev, "out of range INO %d requested\n", 662172066Smarius ino); 663172066Smarius return (0); 664107474Stmm } 66590618Stmm 666172066Smarius if ((ino & INTMAP_OBIO_MASK) == 0) { 667172066Smarius intrmap = SBR_SLOT0_INT_MAP + INTSLOT(ino) * 8; 668172066Smarius intrclr = SBR_SLOT0_INT_CLR + 669172066Smarius (INTSLOT(ino) * 8 * 8) + (INTPRI(ino) * 8); 670172066Smarius } else { 671172066Smarius intrclr = 0; 672172066Smarius for (i = 0, intrmap = SBR_SCSI_INT_MAP; 673172066Smarius intrmap <= SBR_RESERVED_INT_MAP; intrmap += 8, i++) { 674172066Smarius if (INTVEC(SYSIO_READ8(sc, intrmap)) == 675172066Smarius INTMAP_VEC(sc->sc_ign, ino)) { 676172066Smarius intrclr = SBR_SCSI_INT_CLR + i * 8; 677172066Smarius break; 678172066Smarius } 679172066Smarius } 680172066Smarius if (intrclr == 0) 681172066Smarius return (0); 68290618Stmm } 683172066Smarius if (intrmapptr != NULL) 684172066Smarius *intrmapptr = intrmap; 685172066Smarius if (intrclrptr != NULL) 686172066Smarius *intrclrptr = intrclr; 687172066Smarius return (1); 68890618Stmm} 68990618Stmm 69090618Stmmstatic int 691172066Smariussbus_setup_intr(device_t dev, device_t child, struct resource *ires, int flags, 692172066Smarius driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) 69390618Stmm{ 694172066Smarius struct sbus_softc *sc; 695172066Smarius u_long vec; 69690618Stmm 697172066Smarius sc = device_get_softc(dev); 69890618Stmm /* 699172066Smarius * Make sure the vector is fully specified and we registered 700172066Smarius * our interrupt controller for it. 701230687Smarius */ 702172066Smarius vec = rman_get_start(ires); 703172066Smarius if (INTIGN(vec) != sc->sc_ign || intr_vectors[vec].iv_ic != &sbus_ic) { 704172066Smarius device_printf(dev, "invalid interrupt vector 0x%lx\n", vec); 705230687Smarius return (EINVAL); 706230687Smarius } 707172066Smarius return (bus_generic_setup_intr(dev, child, ires, flags, filt, intr, 708172066Smarius arg, cookiep)); 70990618Stmm} 71090618Stmm 71190618Stmmstatic struct resource * 71290618Stmmsbus_alloc_resource(device_t bus, device_t child, int type, int *rid, 71390618Stmm u_long start, u_long end, u_long count, u_int flags) 71490618Stmm{ 71590618Stmm struct sbus_softc *sc; 71690618Stmm struct rman *rm; 71790618Stmm struct resource *rv; 71890618Stmm struct resource_list *rl; 71990618Stmm struct resource_list_entry *rle; 720145186Smarius device_t schild; 72190618Stmm bus_addr_t toffs; 72290618Stmm bus_size_t tend; 723145186Smarius int i, slot; 724230687Smarius int isdefault, passthrough; 72590618Stmm 726145185Smarius isdefault = (start == 0UL && end == ~0UL); 727145186Smarius passthrough = (device_get_parent(child) != bus); 728145186Smarius rle = NULL; 729145186Smarius sc = device_get_softc(bus); 730145186Smarius rl = BUS_GET_RESOURCE_LIST(bus, child); 73190618Stmm switch (type) { 73290618Stmm case SYS_RES_IRQ: 733145186Smarius return (resource_list_alloc(rl, bus, child, type, rid, start, 734145186Smarius end, count, flags)); 73590618Stmm case SYS_RES_MEMORY: 736145186Smarius if (!passthrough) { 737145186Smarius rle = resource_list_find(rl, type, *rid); 738145186Smarius if (rle == NULL) 739145186Smarius return (NULL); 740145186Smarius if (rle->res != NULL) 741145186Smarius panic("%s: resource entry is busy", __func__); 742145186Smarius if (isdefault) { 743145186Smarius start = rle->start; 744145186Smarius count = ulmax(count, rle->count); 745145186Smarius end = ulmax(rle->end, start + count - 1); 746145186Smarius } 747145186Smarius } 74890618Stmm rm = NULL; 749145186Smarius schild = child; 750145186Smarius while (device_get_parent(schild) != bus) 751172066Smarius schild = device_get_parent(schild); 752145186Smarius slot = sbus_get_slot(schild); 75390618Stmm for (i = 0; i < sc->sc_nrange; i++) { 754145186Smarius if (sc->sc_rd[i].rd_slot != slot || 75590618Stmm start < sc->sc_rd[i].rd_coffset || 75690618Stmm start > sc->sc_rd[i].rd_cend) 75790618Stmm continue; 75890618Stmm /* Disallow cross-range allocations. */ 75990618Stmm if (end > sc->sc_rd[i].rd_cend) 76090618Stmm return (NULL); 76190618Stmm /* We've found the connection to the parent bus */ 76290618Stmm toffs = start - sc->sc_rd[i].rd_coffset; 76390618Stmm tend = end - sc->sc_rd[i].rd_coffset; 76490618Stmm rm = &sc->sc_rd[i].rd_rman; 765159413Smarius break; 76690618Stmm } 767159413Smarius if (rm == NULL) 76890618Stmm return (NULL); 769230687Smarius 770230687Smarius rv = rman_reserve_resource(rm, toffs, tend, count, flags & 771230687Smarius ~RF_ACTIVE, child); 77290618Stmm if (rv == NULL) 77390618Stmm return (NULL); 774157896Simp rman_set_rid(rv, *rid); 775230687Smarius 776230687Smarius if ((flags & RF_ACTIVE) != 0 && bus_activate_resource(child, 777230687Smarius type, *rid, rv)) { 778230687Smarius rman_release_resource(rv); 779230687Smarius return (NULL); 78090618Stmm } 781145186Smarius if (!passthrough) 782145186Smarius rle->res = rv; 783145186Smarius return (rv); 78490618Stmm default: 78590618Stmm return (NULL); 78690618Stmm } 78790618Stmm} 78890618Stmm 78990618Stmmstatic int 79090618Stmmsbus_activate_resource(device_t bus, device_t child, int type, int rid, 79190618Stmm struct resource *r) 79290618Stmm{ 793230687Smarius struct sbus_softc *sc; 794230687Smarius struct bus_space_tag *tag; 795230687Smarius int i; 79690618Stmm 797230687Smarius switch (type) { 798230687Smarius case SYS_RES_IRQ: 799230687Smarius return (bus_generic_activate_resource(bus, child, type, rid, 800230687Smarius r)); 801230687Smarius case SYS_RES_MEMORY: 802230687Smarius sc = device_get_softc(bus); 803230687Smarius for (i = 0; i < sc->sc_nrange; i++) { 804230687Smarius if (rman_is_region_manager(r, 805230687Smarius &sc->sc_rd[i].rd_rman) != 0) { 806230687Smarius tag = sparc64_alloc_bus_tag(r, 807230687Smarius rman_get_bustag(sc->sc_sysio_res), 808230687Smarius SBUS_BUS_SPACE, NULL); 809230687Smarius if (tag == NULL) 810230687Smarius return (ENOMEM); 811230687Smarius rman_set_bustag(r, tag); 812230687Smarius rman_set_bushandle(r, 813230687Smarius sc->sc_rd[i].rd_bushandle + 814230687Smarius rman_get_start(r)); 815230687Smarius return (rman_activate_resource(r)); 816230687Smarius } 817230687Smarius } 818230687Smarius /* FALLTHROUGH */ 819230687Smarius default: 820230687Smarius return (EINVAL); 821108798Stmm } 82290618Stmm} 82390618Stmm 82490618Stmmstatic int 825230687Smariussbus_adjust_resource(device_t bus, device_t child, int type, 826230687Smarius struct resource *r, u_long start, u_long end) 82790618Stmm{ 828230687Smarius struct sbus_softc *sc; 829230687Smarius int i; 83090618Stmm 831159413Smarius if (type == SYS_RES_MEMORY) { 832230687Smarius sc = device_get_softc(bus); 833230687Smarius for (i = 0; i < sc->sc_nrange; i++) 834230687Smarius if (rman_is_region_manager(r, 835230687Smarius &sc->sc_rd[i].rd_rman) != 0) 836230687Smarius return (rman_adjust_resource(r, start, end)); 837230687Smarius return (EINVAL); 838159413Smarius } 839230687Smarius return (bus_generic_adjust_resource(bus, child, type, r, start, end)); 84090618Stmm} 84190618Stmm 84290618Stmmstatic int 84390618Stmmsbus_release_resource(device_t bus, device_t child, int type, int rid, 84490618Stmm struct resource *r) 84590618Stmm{ 846145186Smarius struct resource_list *rl; 847108798Stmm struct resource_list_entry *rle; 848145186Smarius int error, passthrough; 84990618Stmm 850145186Smarius passthrough = (device_get_parent(child) != bus); 851145186Smarius rl = BUS_GET_RESOURCE_LIST(bus, child); 852230687Smarius if (type == SYS_RES_MEMORY) { 853230687Smarius if ((rman_get_flags(r) & RF_ACTIVE) != 0) { 854230687Smarius error = bus_deactivate_resource(child, type, rid, r); 855230687Smarius if (error) 856230687Smarius return (error); 857230687Smarius } 858230687Smarius error = rman_release_resource(r); 859108798Stmm if (error != 0) 860108798Stmm return (error); 861230687Smarius if (!passthrough) { 862230687Smarius rle = resource_list_find(rl, type, rid); 863230687Smarius KASSERT(rle != NULL, 864230687Smarius ("%s: resource entry not found!", __func__)); 865230687Smarius KASSERT(rle->res != NULL, 866230687Smarius ("%s: resource entry is not busy", __func__)); 867230687Smarius rle->res = NULL; 868230687Smarius } 869230687Smarius return (0); 87090618Stmm } 871230687Smarius return (resource_list_release(rl, bus, child, type, rid, r)); 87290618Stmm} 87390618Stmm 874167308Smariusstatic bus_dma_tag_t 875167308Smariussbus_get_dma_tag(device_t bus, device_t child) 876167308Smarius{ 877167308Smarius struct sbus_softc *sc; 878167308Smarius 879167308Smarius sc = device_get_softc(bus); 880167308Smarius return (sc->sc_cdmatag); 881167308Smarius} 882167308Smarius 883152684Smariusstatic const struct ofw_bus_devinfo * 884152684Smariussbus_get_devinfo(device_t bus, device_t child) 885152684Smarius{ 886152684Smarius struct sbus_devinfo *sdi; 887152684Smarius 888152684Smarius sdi = device_get_ivars(child); 889152684Smarius return (&sdi->sdi_obdinfo); 890152684Smarius} 891152684Smarius 89290618Stmm/* 89390618Stmm * Handle an overtemp situation. 89490618Stmm * 89590618Stmm * SPARCs have temperature sensors which generate interrupts 89690618Stmm * if the machine's temperature exceeds a certain threshold. 89790618Stmm * This handles the interrupt and powers off the machine. 89890618Stmm * The same needs to be done to PCI controller drivers. 89990618Stmm */ 900170852Smariusstatic void 901248050Smariussbus_overtemp(void *arg __unused) 90290618Stmm{ 903172066Smarius static int shutdown; 90490618Stmm 905172066Smarius /* As the interrupt is cleared we may be called multiple times. */ 906172066Smarius if (shutdown != 0) 907172066Smarius return; 908172066Smarius shutdown++; 90990618Stmm printf("DANGER: OVER TEMPERATURE detected\nShutting down NOW.\n"); 91090618Stmm shutdown_nice(RB_POWEROFF); 91190618Stmm} 91290618Stmm 91390618Stmm/* Try to shut down in time in case of power failure. */ 914170852Smariusstatic void 915248050Smariussbus_pwrfail(void *arg __unused) 91690618Stmm{ 917172066Smarius static int shutdown; 91890618Stmm 919172066Smarius /* As the interrupt is cleared we may be called multiple times. */ 920172066Smarius if (shutdown != 0) 921172066Smarius return; 922172066Smarius shutdown++; 92390618Stmm printf("Power failure detected\nShutting down NOW.\n"); 924248050Smarius shutdown_nice(RB_POWEROFF); 92590618Stmm} 92690618Stmm 927152684Smariusstatic int 928152684Smariussbus_print_res(struct sbus_devinfo *sdi) 929133589Smarius{ 930152684Smarius int rv; 931133589Smarius 932152684Smarius rv = 0; 933152684Smarius rv += resource_list_print_type(&sdi->sdi_rl, "mem", SYS_RES_MEMORY, 934152684Smarius "%#lx"); 935152684Smarius rv += resource_list_print_type(&sdi->sdi_rl, "irq", SYS_RES_IRQ, 936152684Smarius "%ld"); 937152684Smarius return (rv); 938133589Smarius} 939