sbus.c revision 190114
190618Stmm/*-
290618Stmm * Copyright (c) 1998 The NetBSD Foundation, Inc.
390618Stmm * All rights reserved.
490618Stmm *
590618Stmm * This code is derived from software contributed to The NetBSD Foundation
690618Stmm * by Paul Kranenburg.
790618Stmm *
890618Stmm * Redistribution and use in source and binary forms, with or without
990618Stmm * modification, are permitted provided that the following conditions
1090618Stmm * are met:
1190618Stmm * 1. Redistributions of source code must retain the above copyright
1290618Stmm *    notice, this list of conditions and the following disclaimer.
1390618Stmm * 2. Redistributions in binary form must reproduce the above copyright
1490618Stmm *    notice, this list of conditions and the following disclaimer in the
1590618Stmm *    documentation and/or other materials provided with the distribution.
1690618Stmm * 3. All advertising materials mentioning features or use of this software
1790618Stmm *    must display the following acknowledgement:
1890618Stmm *        This product includes software developed by the NetBSD
1990618Stmm *        Foundation, Inc. and its contributors.
2090618Stmm * 4. Neither the name of The NetBSD Foundation nor the names of its
2190618Stmm *    contributors may be used to endorse or promote products derived
2290618Stmm *    from this software without specific prior written permission.
2390618Stmm *
2490618Stmm * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2590618Stmm * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2690618Stmm * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2790618Stmm * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2890618Stmm * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2990618Stmm * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
3090618Stmm * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
3190618Stmm * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
3290618Stmm * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3390618Stmm * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3490618Stmm * POSSIBILITY OF SUCH DAMAGE.
3590618Stmm */
36139825Simp/*-
3790618Stmm * Copyright (c) 1992, 1993
3890618Stmm *	The Regents of the University of California.  All rights reserved.
3990618Stmm *
4090618Stmm * This software was developed by the Computer Systems Engineering group
4190618Stmm * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
4290618Stmm * contributed to Berkeley.
4390618Stmm *
4490618Stmm * All advertising materials mentioning features or use of this software
4590618Stmm * must display the following acknowledgement:
4690618Stmm *	This product includes software developed by the University of
4790618Stmm *	California, Lawrence Berkeley Laboratory.
4890618Stmm *
4990618Stmm * Redistribution and use in source and binary forms, with or without
5090618Stmm * modification, are permitted provided that the following conditions
5190618Stmm * are met:
5290618Stmm * 1. Redistributions of source code must retain the above copyright
5390618Stmm *    notice, this list of conditions and the following disclaimer.
5490618Stmm * 2. Redistributions in binary form must reproduce the above copyright
5590618Stmm *    notice, this list of conditions and the following disclaimer in the
5690618Stmm *    documentation and/or other materials provided with the distribution.
5790618Stmm * 4. Neither the name of the University nor the names of its contributors
5890618Stmm *    may be used to endorse or promote products derived from this software
5990618Stmm *    without specific prior written permission.
6090618Stmm *
6190618Stmm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
6290618Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
6390618Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
6490618Stmm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
6590618Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
6690618Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6790618Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6890618Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6990618Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
7090618Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
7190618Stmm * SUCH DAMAGE.
7290618Stmm */
73139825Simp/*-
7490618Stmm * Copyright (c) 1999 Eduardo Horvath
7590618Stmm * Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>.
76167308Smarius * Copyright (c) 2005 Marius Strobl <marius@FreeBSD.org>
7790618Stmm * All rights reserved.
7890618Stmm *
7990618Stmm * Redistribution and use in source and binary forms, with or without
8090618Stmm * modification, are permitted provided that the following conditions
8190618Stmm * are met:
8290618Stmm * 1. Redistributions of source code must retain the above copyright
8390618Stmm *    notice, this list of conditions and the following disclaimer.
8490618Stmm *
8590618Stmm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR  ``AS IS'' AND
8690618Stmm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
8790618Stmm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
8890618Stmm * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR  BE LIABLE
8990618Stmm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
9090618Stmm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
9190618Stmm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
9290618Stmm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
9390618Stmm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
9490618Stmm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
9590618Stmm * SUCH DAMAGE.
9690618Stmm *
9790618Stmm *	from: @(#)sbus.c	8.1 (Berkeley) 6/11/93
9890618Stmm *	from: NetBSD: sbus.c,v 1.46 2001/10/07 20:30:41 eeh Exp
9990618Stmm */
10090618Stmm
101145185Smarius#include <sys/cdefs.h>
102145185Smarius__FBSDID("$FreeBSD: head/sys/sparc64/sbus/sbus.c 190114 2009-03-19 21:14:45Z marius $");
103145185Smarius
10490618Stmm/*
105145185Smarius * SBus support.
10690618Stmm */
107131376Smarius
10890618Stmm#include <sys/param.h>
10990618Stmm#include <sys/systm.h>
11090618Stmm#include <sys/bus.h>
11190618Stmm#include <sys/kernel.h>
11290618Stmm#include <sys/malloc.h>
113130068Sphk#include <sys/module.h>
114107477Stmm#include <sys/pcpu.h>
115171730Smarius#include <sys/queue.h>
11690618Stmm#include <sys/reboot.h>
117171730Smarius#include <sys/rman.h>
11890618Stmm
119133589Smarius#include <dev/ofw/ofw_bus.h>
120152684Smarius#include <dev/ofw/ofw_bus_subr.h>
121119338Simp#include <dev/ofw/openfirm.h>
12290618Stmm
12390618Stmm#include <machine/bus.h>
124171730Smarius#include <machine/bus_common.h>
125116541Stmm#include <machine/bus_private.h>
12690618Stmm#include <machine/iommureg.h>
127171730Smarius#include <machine/iommuvar.h>
12890618Stmm#include <machine/resource.h>
12990618Stmm
13090618Stmm#include <sparc64/sbus/ofw_sbus.h>
13190618Stmm#include <sparc64/sbus/sbusreg.h>
13290618Stmm#include <sparc64/sbus/sbusvar.h>
13390618Stmm
13490618Stmmstruct sbus_devinfo {
13590618Stmm	int			sdi_burstsz;
136145186Smarius	int			sdi_clockfreq;
13790618Stmm	int			sdi_slot;
13890618Stmm
139152684Smarius	struct ofw_bus_devinfo	sdi_obdinfo;
14090618Stmm	struct resource_list	sdi_rl;
14190618Stmm};
14290618Stmm
14390618Stmm/* Range descriptor, allocated for each sc_range. */
14490618Stmmstruct sbus_rd {
14590618Stmm	bus_addr_t		rd_poffset;
14690618Stmm	bus_addr_t		rd_pend;
14790618Stmm	int			rd_slot;
14890618Stmm	bus_addr_t		rd_coffset;
14990618Stmm	bus_addr_t		rd_cend;
15090618Stmm	struct rman		rd_rman;
15190618Stmm	bus_space_handle_t	rd_bushandle;
15290618Stmm	struct resource		*rd_res;
15390618Stmm};
15490618Stmm
15590618Stmmstruct sbus_softc {
156172066Smarius	device_t		sc_dev;
15790618Stmm	bus_dma_tag_t		sc_cdmatag;
15890618Stmm	bus_space_tag_t		sc_cbustag;
15990618Stmm	int			sc_clockfreq;	/* clock frequency (in Hz) */
16090618Stmm	int			sc_nrange;
16190618Stmm	struct sbus_rd		*sc_rd;
162145185Smarius	int			sc_burst;	/* burst transfer sizes supp. */
16390618Stmm
16490618Stmm	struct resource		*sc_sysio_res;
165145185Smarius	int			sc_ign;		/* IGN for this sysio */
166145185Smarius	struct iommu_state	sc_is;		/* IOMMU state (iommuvar.h) */
16790618Stmm
16890618Stmm	struct resource		*sc_ot_ires;
16990618Stmm	void			*sc_ot_ihand;
17090618Stmm	struct resource		*sc_pf_ires;
17190618Stmm	void			*sc_pf_ihand;
17290618Stmm};
17390618Stmm
17490618Stmm#define	SYSIO_READ8(sc, off) \
175170852Smarius	bus_read_8((sc)->sc_sysio_res, (off))
17690618Stmm#define	SYSIO_WRITE8(sc, off, v) \
177170852Smarius	bus_write_8((sc)->sc_sysio_res, (off), (v))
17890618Stmm
179145185Smariusstatic device_probe_t sbus_probe;
180145186Smariusstatic device_attach_t sbus_attach;
181145185Smariusstatic bus_print_child_t sbus_print_child;
182145185Smariusstatic bus_probe_nomatch_t sbus_probe_nomatch;
183145185Smariusstatic bus_read_ivar_t sbus_read_ivar;
184145185Smariusstatic bus_get_resource_list_t sbus_get_resource_list;
185145185Smariusstatic bus_setup_intr_t sbus_setup_intr;
186145185Smariusstatic bus_alloc_resource_t sbus_alloc_resource;
187145185Smariusstatic bus_release_resource_t sbus_release_resource;
188145185Smariusstatic bus_activate_resource_t sbus_activate_resource;
189145185Smariusstatic bus_deactivate_resource_t sbus_deactivate_resource;
190167308Smariusstatic bus_get_dma_tag_t sbus_get_dma_tag;
191152684Smariusstatic ofw_bus_get_devinfo_t sbus_get_devinfo;
19290618Stmm
193190112Smariusstatic int sbus_inlist(const char *, const char *const *);
194152684Smariusstatic struct sbus_devinfo * sbus_setup_dinfo(device_t, struct sbus_softc *,
195152684Smarius    phandle_t);
196152684Smariusstatic void sbus_destroy_dinfo(struct sbus_devinfo *);
197172066Smariusstatic void sbus_intr_enable(void *);
198172066Smariusstatic void sbus_intr_disable(void *);
199178443Smariusstatic void sbus_intr_assign(void *);
200178443Smariusstatic void sbus_intr_clear(void *);
201172066Smariusstatic int sbus_find_intrmap(struct sbus_softc *, u_int, bus_addr_t *,
202172066Smarius    bus_addr_t *);
20390618Stmmstatic bus_space_tag_t sbus_alloc_bustag(struct sbus_softc *);
204170852Smariusstatic driver_intr_t sbus_overtemp;
205170852Smariusstatic driver_intr_t sbus_pwrfail;
206152684Smariusstatic int sbus_print_res(struct sbus_devinfo *);
20790618Stmm
20890618Stmmstatic device_method_t sbus_methods[] = {
20990618Stmm	/* Device interface */
21090618Stmm	DEVMETHOD(device_probe,		sbus_probe),
211145186Smarius	DEVMETHOD(device_attach,	sbus_attach),
212154870Smarius	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
213154870Smarius	DEVMETHOD(device_suspend,	bus_generic_suspend),
214154870Smarius	DEVMETHOD(device_resume,	bus_generic_resume),
21590618Stmm
21690618Stmm	/* Bus interface */
21790618Stmm	DEVMETHOD(bus_print_child,	sbus_print_child),
21890618Stmm	DEVMETHOD(bus_probe_nomatch,	sbus_probe_nomatch),
21990618Stmm	DEVMETHOD(bus_read_ivar,	sbus_read_ivar),
22090618Stmm	DEVMETHOD(bus_alloc_resource,	sbus_alloc_resource),
22190618Stmm	DEVMETHOD(bus_activate_resource,	sbus_activate_resource),
22290618Stmm	DEVMETHOD(bus_deactivate_resource,	sbus_deactivate_resource),
22390618Stmm	DEVMETHOD(bus_release_resource,	sbus_release_resource),
224190112Smarius	DEVMETHOD(bus_setup_intr, 	sbus_setup_intr),
225190112Smarius	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
226190112Smarius	DEVMETHOD(bus_get_resource,	bus_generic_rl_get_resource),
22790618Stmm	DEVMETHOD(bus_get_resource_list, sbus_get_resource_list),
228190114Smarius	DEVMETHOD(bus_child_pnpinfo_str, ofw_bus_gen_child_pnpinfo_str),
229167308Smarius	DEVMETHOD(bus_get_dma_tag,	sbus_get_dma_tag),
23090618Stmm
231133589Smarius	/* ofw_bus interface */
232152684Smarius	DEVMETHOD(ofw_bus_get_devinfo,	sbus_get_devinfo),
233152684Smarius	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
234152684Smarius	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
235152684Smarius	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
236152684Smarius	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
237152684Smarius	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
238133589Smarius
239190112Smarius	KOBJMETHOD_END
24090618Stmm};
24190618Stmm
24290618Stmmstatic driver_t sbus_driver = {
24390618Stmm	"sbus",
24490618Stmm	sbus_methods,
24590618Stmm	sizeof(struct sbus_softc),
24690618Stmm};
24790618Stmm
24890618Stmmstatic devclass_t sbus_devclass;
24990618Stmm
25090618StmmDRIVER_MODULE(sbus, nexus, sbus_driver, sbus_devclass, 0, 0);
251182062SmariusMODULE_VERSION(sbus, 1);
25290618Stmm
25390618Stmm#define	OFW_SBUS_TYPE	"sbus"
25490618Stmm#define	OFW_SBUS_NAME	"sbus"
25590618Stmm
256172066Smariusstatic const struct intr_controller sbus_ic = {
257172066Smarius	sbus_intr_enable,
258172066Smarius	sbus_intr_disable,
259178443Smarius	sbus_intr_assign,
260178443Smarius	sbus_intr_clear
261172066Smarius};
262172066Smarius
263172066Smariusstruct sbus_icarg {
264172066Smarius	struct sbus_softc	*sica_sc;
265172066Smarius	bus_addr_t		sica_map;
266172066Smarius	bus_addr_t		sica_clr;
267172066Smarius};
268172066Smarius
269190112Smariusstatic const char *const sbus_order_first[] = {
270146391Smarius	"auxio",
271146391Smarius	"dma",
272146391Smarius	NULL
273146391Smarius};
274146391Smarius
27590618Stmmstatic int
276190112Smariussbus_inlist(const char *name, const char *const *list)
277146391Smarius{
278146391Smarius	int i;
279146391Smarius
280146391Smarius	if (name == NULL)
281146391Smarius		return (0);
282146391Smarius	for (i = 0; list[i] != NULL; i++) {
283146391Smarius		if (strcmp(name, list[i]) == 0)
284146391Smarius			return (1);
285146391Smarius	}
286146391Smarius	return (0);
287146391Smarius}
288146391Smarius
289146391Smariusstatic int
29090618Stmmsbus_probe(device_t dev)
29190618Stmm{
292167308Smarius	const char *t;
293145186Smarius
294167308Smarius	t = ofw_bus_get_type(dev);
295145186Smarius	if (((t == NULL || strcmp(t, OFW_SBUS_TYPE) != 0)) &&
296167308Smarius	    strcmp(ofw_bus_get_name(dev), OFW_SBUS_NAME) != 0)
297145186Smarius		return (ENXIO);
298145186Smarius	device_set_desc(dev, "U2S UPA-SBus bridge");
299145186Smarius	return (0);
300145186Smarius}
301145186Smarius
302145186Smariusstatic int
303145186Smariussbus_attach(device_t dev)
304145186Smarius{
305145185Smarius	struct sbus_softc *sc;
30690618Stmm	struct sbus_devinfo *sdi;
307172066Smarius	struct sbus_icarg *sica;
30890618Stmm	struct sbus_ranges *range;
30990618Stmm	struct resource *res;
310167308Smarius	struct resource_list *rl;
31190618Stmm	device_t cdev;
312172066Smarius	bus_addr_t intrclr, intrmap, phys;
31390618Stmm	bus_size_t size;
314172066Smarius	u_long vec;
315145185Smarius	phandle_t child, node;
316190112Smarius	uint32_t prop;
317190112Smarius	int i, j;
31890618Stmm
319145185Smarius	sc = device_get_softc(dev);
320172066Smarius	sc->sc_dev = dev;
321167308Smarius	node = ofw_bus_get_node(dev);
322145185Smarius
323190112Smarius	i = 0;
324190112Smarius	sc->sc_sysio_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &i,
325167308Smarius	    RF_ACTIVE);
326167308Smarius	if (sc->sc_sysio_res == NULL)
327145185Smarius		panic("%s: cannot allocate device memory", __func__);
32890618Stmm
329190112Smarius	if (OF_getprop(node, "interrupts", &prop, sizeof(prop)) == -1)
330145185Smarius		panic("%s: cannot get IGN", __func__);
331190112Smarius	sc->sc_ign = INTIGN(prop);
33290618Stmm	sc->sc_cbustag = sbus_alloc_bustag(sc);
33390618Stmm
33490618Stmm	/*
33590618Stmm	 * Record clock frequency for synchronous SCSI.
33690618Stmm	 * IS THIS THE CORRECT DEFAULT??
33790618Stmm	 */
338190112Smarius	if (OF_getprop(node, "clock-frequency", &prop, sizeof(prop)) == -1)
339190112Smarius		prop = 25000000;
340190112Smarius	sc->sc_clockfreq = prop;
341190112Smarius	prop /= 1000;
342190112Smarius	device_printf(dev, "clock %d.%03d MHz\n", prop / 1000, prop % 1000);
34390618Stmm
34490618Stmm	/*
34590618Stmm	 * Collect address translations from the OBP.
34690618Stmm	 */
34790618Stmm	if ((sc->sc_nrange = OF_getprop_alloc(node, "ranges",
34890618Stmm	    sizeof(*range), (void **)&range)) == -1) {
349145185Smarius		panic("%s: error getting ranges property", __func__);
35090618Stmm	}
35190618Stmm	sc->sc_rd = (struct sbus_rd *)malloc(sizeof(*sc->sc_rd) * sc->sc_nrange,
35290618Stmm	    M_DEVBUF, M_NOWAIT);
35390618Stmm	if (sc->sc_rd == NULL)
354145185Smarius		panic("%s: cannot allocate rmans", __func__);
35590618Stmm	/*
35690618Stmm	 * Preallocate all space that the SBus bridge decodes, so that nothing
35790618Stmm	 * else gets in the way; set up rmans etc.
35890618Stmm	 */
359167308Smarius	rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
36090618Stmm	for (i = 0; i < sc->sc_nrange; i++) {
36190618Stmm		phys = range[i].poffset | ((bus_addr_t)range[i].pspace << 32);
36290618Stmm		size = range[i].size;
36390618Stmm		sc->sc_rd[i].rd_slot = range[i].cspace;
36490618Stmm		sc->sc_rd[i].rd_coffset = range[i].coffset;
36590618Stmm		sc->sc_rd[i].rd_cend = sc->sc_rd[i].rd_coffset + size;
366190112Smarius		j = resource_list_add_next(rl, SYS_RES_MEMORY, phys,
367167308Smarius		    phys + size - 1, size);
368190112Smarius		if ((res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &j,
369167308Smarius		    RF_ACTIVE)) == NULL)
370145185Smarius			panic("%s: cannot allocate decoded range", __func__);
37190618Stmm		sc->sc_rd[i].rd_bushandle = rman_get_bushandle(res);
37290618Stmm		sc->sc_rd[i].rd_rman.rm_type = RMAN_ARRAY;
37390618Stmm		sc->sc_rd[i].rd_rman.rm_descr = "SBus Device Memory";
37490618Stmm		if (rman_init(&sc->sc_rd[i].rd_rman) != 0 ||
37590618Stmm		    rman_manage_region(&sc->sc_rd[i].rd_rman, 0, size) != 0)
376145185Smarius			panic("%s: failed to set up memory rman", __func__);
37790618Stmm		sc->sc_rd[i].rd_poffset = phys;
37890618Stmm		sc->sc_rd[i].rd_pend = phys + size;
37990618Stmm		sc->sc_rd[i].rd_res = res;
38090618Stmm	}
38190618Stmm	free(range, M_OFWPROP);
38290618Stmm
38390618Stmm	/*
38490618Stmm	 * Get the SBus burst transfer size if burst transfers are supported.
38590618Stmm	 */
386190112Smarius	if (OF_getprop(node, "up-burst-sizes", &sc->sc_burst,
38790618Stmm	    sizeof(sc->sc_burst)) == -1 || sc->sc_burst == 0)
388190112Smarius		sc->sc_burst =
389190112Smarius		    (SBUS_BURST64_DEF << SBUS_BURST64_SHIFT) | SBUS_BURST_DEF;
39090618Stmm
391190112Smarius
39290618Stmm	/* initalise the IOMMU */
39390618Stmm
39490618Stmm	/* punch in our copies */
395171730Smarius	sc->sc_is.is_pmaxaddr = IOMMU_MAXADDR(SBUS_IOMMU_BITS);
396170852Smarius	sc->sc_is.is_bustag = rman_get_bustag(sc->sc_sysio_res);
397170852Smarius	sc->sc_is.is_bushandle = rman_get_bushandle(sc->sc_sysio_res);
39890618Stmm	sc->sc_is.is_iommu = SBR_IOMMU;
39990618Stmm	sc->sc_is.is_dtag = SBR_IOMMU_TLB_TAG_DIAG;
40090618Stmm	sc->sc_is.is_ddram = SBR_IOMMU_TLB_DATA_DIAG;
40190618Stmm	sc->sc_is.is_dqueue = SBR_IOMMU_QUEUE_DIAG;
40290618Stmm	sc->sc_is.is_dva = SBR_IOMMU_SVADIAG;
40390618Stmm	sc->sc_is.is_dtcmp = 0;
40490618Stmm	sc->sc_is.is_sb[0] = SBR_STRBUF;
405123865Sobrien	sc->sc_is.is_sb[1] = 0;
40690618Stmm
407100188Stmm	/*
408100188Stmm	 * Note: the SBus IOMMU ignores the high bits of an address, so a NULL
409100188Stmm	 * DMA pointer will be translated by the first page of the IOTSB.
410100188Stmm	 * To detect bugs we'll allocate and ignore the first entry.
411100188Stmm	 */
412178840Smarius	iommu_init(device_get_nameunit(dev), &sc->sc_is, 3, -1, 1);
41390618Stmm
414116213Stmm	/* Create the DMA tag. */
415171730Smarius	if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0,
416171730Smarius	    sc->sc_is.is_pmaxaddr, ~0, NULL, NULL, sc->sc_is.is_pmaxaddr,
417171730Smarius	    0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_cdmatag) != 0)
418145185Smarius		panic("%s: bus_dma_tag_create failed", __func__);
419116213Stmm	/* Customize the tag. */
420116213Stmm	sc->sc_cdmatag->dt_cookie = &sc->sc_is;
421116541Stmm	sc->sc_cdmatag->dt_mt = &iommu_dma_methods;
422116213Stmm
423172066Smarius 	/*
424172066Smarius	 * Hunt through all the interrupt mapping regs and register our
425172066Smarius	 * interrupt controller for the corresponding interrupt vectors.
426190112Smarius	 * We do this early in order to be able to catch stray interrupts.
427172066Smarius	 */
428172066Smarius	for (i = 0; i <= SBUS_MAX_INO; i++) {
429172066Smarius		if (sbus_find_intrmap(sc, i, &intrmap, &intrclr) == 0)
430172066Smarius			continue;
431172066Smarius		sica = malloc(sizeof(*sica), M_DEVBUF, M_NOWAIT);
432172066Smarius		if (sica == NULL)
433172066Smarius			panic("%s: could not allocate interrupt controller "
434172066Smarius			    "argument", __func__);
435172066Smarius		sica->sica_sc = sc;
436172066Smarius		sica->sica_map = intrmap;
437172066Smarius		sica->sica_clr = intrclr;
438172066Smarius#ifdef SBUS_DEBUG
439172066Smarius		device_printf(dev,
440172066Smarius		    "intr map (INO %d, %s) %#lx: %#lx, clr: %#lx\n",
441172066Smarius		    i, (i & INTMAP_OBIO_MASK) == 0 ? "SBus slot" : "OBIO",
442172066Smarius		    (u_long)intrmap, (u_long)SYSIO_READ8(sc, intrmap),
443172066Smarius		    (u_long)intrclr);
444172066Smarius#endif
445190112Smarius		j = intr_controller_register(INTMAP_VEC(sc->sc_ign, i),
446190112Smarius		    &sbus_ic, sica);
447190112Smarius		if (j != 0)
448190112Smarius			device_printf(dev, "could not register interrupt "
449190112Smarius			    "controller for INO %d (%d)\n", i, j);
450172066Smarius	}
451172066Smarius
452145185Smarius	/* Enable the over-temperature and power-fail interrupts. */
453190112Smarius	i = 4;
454190112Smarius	sc->sc_ot_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i,
455167308Smarius	    RF_ACTIVE);
456166034Smarius	if (sc->sc_ot_ires == NULL ||
457172066Smarius	    INTIGN(vec = rman_get_start(sc->sc_ot_ires)) != sc->sc_ign ||
458172066Smarius	    INTVEC(SYSIO_READ8(sc, SBR_THERM_INT_MAP)) != vec ||
459172066Smarius	    intr_vectors[vec].iv_ic != &sbus_ic ||
460190112Smarius	    bus_setup_intr(dev, sc->sc_ot_ires, INTR_TYPE_MISC | INTR_FAST,
461170852Smarius	    NULL, sbus_overtemp, sc, &sc->sc_ot_ihand) != 0)
462166034Smarius		panic("%s: failed to set up temperature interrupt", __func__);
463190112Smarius	i = 3;
464190112Smarius	sc->sc_pf_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i,
465167308Smarius	    RF_ACTIVE);
466166034Smarius	if (sc->sc_pf_ires == NULL ||
467172066Smarius	    INTIGN(vec = rman_get_start(sc->sc_pf_ires)) != sc->sc_ign ||
468172066Smarius	    INTVEC(SYSIO_READ8(sc, SBR_POWER_INT_MAP)) != vec ||
469172066Smarius	    intr_vectors[vec].iv_ic != &sbus_ic ||
470190112Smarius	    bus_setup_intr(dev, sc->sc_pf_ires, INTR_TYPE_MISC | INTR_FAST,
471170852Smarius	    NULL, sbus_pwrfail, sc, &sc->sc_pf_ihand) != 0)
472166034Smarius		panic("%s: failed to set up power fail interrupt", __func__);
47390618Stmm
47490618Stmm	/* Initialize the counter-timer. */
475178840Smarius	sparc64_counter_init(device_get_nameunit(dev),
476178840Smarius	    rman_get_bustag(sc->sc_sysio_res),
477170852Smarius	    rman_get_bushandle(sc->sc_sysio_res), SBR_TC0);
47890618Stmm
47990618Stmm	/*
48090618Stmm	 * Loop through ROM children, fixing any relative addresses
48190618Stmm	 * and then configuring each device.
48290618Stmm	 */
48390618Stmm	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
484152684Smarius		if ((sdi = sbus_setup_dinfo(dev, sc, child)) == NULL)
48590618Stmm			continue;
486146391Smarius		/*
487146391Smarius		 * For devices where there are variants that are actually
488146391Smarius		 * split into two SBus devices (as opposed to the first
489146391Smarius		 * half of the device being a SBus device and the second
490146391Smarius		 * half hanging off of the first one) like 'auxio' and
491146391Smarius		 * 'SUNW,fdtwo' or 'dma' and 'esp' probe the SBus device
492146391Smarius		 * which is a prerequisite to the driver attaching to the
493146391Smarius		 * second one with a lower order. Saves us from dealing
494146391Smarius		 * with different probe orders in the respective device
495146391Smarius		 * drivers which generally is more hackish.
496146391Smarius		 */
497146391Smarius		cdev = device_add_child_ordered(dev, (OF_child(child) == 0 &&
498152684Smarius		    sbus_inlist(sdi->sdi_obdinfo.obd_name, sbus_order_first)) ?
499152684Smarius		    SBUS_ORDER_FIRST : SBUS_ORDER_NORMAL, NULL, -1);
500152684Smarius		if (cdev == NULL) {
501152684Smarius			device_printf(dev,
502152684Smarius			    "<%s>: device_add_child_ordered failed\n",
503152684Smarius			    sdi->sdi_obdinfo.obd_name);
504152684Smarius			sbus_destroy_dinfo(sdi);
505152684Smarius			continue;
506152684Smarius		}
50790618Stmm		device_set_ivars(cdev, sdi);
50890618Stmm	}
509145186Smarius	return (bus_generic_attach(dev));
51090618Stmm}
51190618Stmm
51290618Stmmstatic struct sbus_devinfo *
513152684Smariussbus_setup_dinfo(device_t dev, struct sbus_softc *sc, phandle_t node)
51490618Stmm{
51590618Stmm	struct sbus_devinfo *sdi;
51690618Stmm	struct sbus_regs *reg;
51790618Stmm	u_int32_t base, iv, *intr;
51890618Stmm	int i, nreg, nintr, slot, rslot;
51990618Stmm
520111119Simp	sdi = malloc(sizeof(*sdi), M_DEVBUF, M_ZERO | M_WAITOK);
521152684Smarius	if (ofw_bus_gen_setup_devinfo(&sdi->sdi_obdinfo, node) != 0) {
522152684Smarius		free(sdi, M_DEVBUF);
52390618Stmm		return (NULL);
524152684Smarius	}
52590618Stmm	resource_list_init(&sdi->sdi_rl);
52690618Stmm	slot = -1;
52790618Stmm	nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)&reg);
52890618Stmm	if (nreg == -1) {
529152684Smarius		if (sdi->sdi_obdinfo.obd_type == NULL ||
530152684Smarius		    strcmp(sdi->sdi_obdinfo.obd_type, "hierarchical") != 0) {
531152684Smarius			device_printf(dev, "<%s>: incomplete\n",
532152684Smarius			    sdi->sdi_obdinfo.obd_name);
533152684Smarius			goto fail;
53490618Stmm		}
53590618Stmm	} else {
53690618Stmm		for (i = 0; i < nreg; i++) {
53790618Stmm			base = reg[i].sbr_offset;
53890618Stmm			if (SBUS_ABS(base)) {
53990618Stmm				rslot = SBUS_ABS_TO_SLOT(base);
54090618Stmm				base = SBUS_ABS_TO_OFFSET(base);
54190618Stmm			} else
54290618Stmm				rslot = reg[i].sbr_slot;
543152684Smarius			if (slot != -1 && slot != rslot) {
544152684Smarius				device_printf(dev, "<%s>: multiple slots\n",
545152684Smarius				    sdi->sdi_obdinfo.obd_name);
546152684Smarius				free(reg, M_OFWPROP);
547152684Smarius				goto fail;
548152684Smarius			}
54990618Stmm			slot = rslot;
55090618Stmm
55190618Stmm			resource_list_add(&sdi->sdi_rl, SYS_RES_MEMORY, i,
55290618Stmm			    base, base + reg[i].sbr_size, reg[i].sbr_size);
55390618Stmm		}
55490618Stmm		free(reg, M_OFWPROP);
55590618Stmm	}
55690618Stmm	sdi->sdi_slot = slot;
55790618Stmm
55890618Stmm	/*
559145185Smarius	 * The `interrupts' property contains the SBus interrupt level.
56090618Stmm	 */
561145185Smarius	nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intr),
562145185Smarius	    (void **)&intr);
56390618Stmm	if (nintr != -1) {
56490618Stmm		for (i = 0; i < nintr; i++) {
56590618Stmm			iv = intr[i];
56690618Stmm			/*
567145185Smarius			 * SBus card devices need the slot number encoded into
56890618Stmm			 * the vector as this is generally not done.
56990618Stmm			 */
570107477Stmm			if ((iv & INTMAP_OBIO_MASK) == 0)
57190618Stmm				iv |= slot << 3;
572172066Smarius			iv = INTMAP_VEC(sc->sc_ign, iv);
57390618Stmm			resource_list_add(&sdi->sdi_rl, SYS_RES_IRQ, i,
57490618Stmm			    iv, iv, 1);
57590618Stmm		}
57690618Stmm		free(intr, M_OFWPROP);
57790618Stmm	}
57890618Stmm	if (OF_getprop(node, "burst-sizes", &sdi->sdi_burstsz,
57990618Stmm	    sizeof(sdi->sdi_burstsz)) == -1)
58090618Stmm		sdi->sdi_burstsz = sc->sc_burst;
58190618Stmm	else
58290618Stmm		sdi->sdi_burstsz &= sc->sc_burst;
583145186Smarius	if (OF_getprop(node, "clock-frequency", &sdi->sdi_clockfreq,
584145186Smarius	    sizeof(sdi->sdi_clockfreq)) == -1)
585145186Smarius		sdi->sdi_clockfreq = sc->sc_clockfreq;
58690618Stmm
58790618Stmm	return (sdi);
588152684Smarius
589152684Smariusfail:
590152684Smarius	sbus_destroy_dinfo(sdi);
591152684Smarius	return (NULL);
59290618Stmm}
59390618Stmm
59490618Stmmstatic void
59590618Stmmsbus_destroy_dinfo(struct sbus_devinfo *dinfo)
59690618Stmm{
59790618Stmm
59890618Stmm	resource_list_free(&dinfo->sdi_rl);
599152684Smarius	ofw_bus_gen_destroy_devinfo(&dinfo->sdi_obdinfo);
60090618Stmm	free(dinfo, M_DEVBUF);
60190618Stmm}
60290618Stmm
60390618Stmmstatic int
60490618Stmmsbus_print_child(device_t dev, device_t child)
60590618Stmm{
60690618Stmm	int rv;
60790618Stmm
60890618Stmm	rv = bus_print_child_header(dev, child);
609152684Smarius	rv += sbus_print_res(device_get_ivars(child));
61090618Stmm	rv += bus_print_child_footer(dev, child);
61190618Stmm	return (rv);
61290618Stmm}
61390618Stmm
61490618Stmmstatic void
61590618Stmmsbus_probe_nomatch(device_t dev, device_t child)
61690618Stmm{
617152684Smarius	const char *type;
61890618Stmm
619152684Smarius	device_printf(dev, "<%s>", ofw_bus_get_name(child));
620152684Smarius	sbus_print_res(device_get_ivars(child));
621152684Smarius	type = ofw_bus_get_type(child);
622145186Smarius	printf(" type %s (no driver attached)\n",
623152684Smarius	    type != NULL ? type : "unknown");
62490618Stmm}
62590618Stmm
62690618Stmmstatic int
62790618Stmmsbus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
62890618Stmm{
629146391Smarius	struct sbus_softc *sc;
63090618Stmm	struct sbus_devinfo *dinfo;
63190618Stmm
632146391Smarius	sc = device_get_softc(dev);
63390618Stmm	if ((dinfo = device_get_ivars(child)) == NULL)
63490618Stmm		return (ENOENT);
63590618Stmm	switch (which) {
63690618Stmm	case SBUS_IVAR_BURSTSZ:
63790618Stmm		*result = dinfo->sdi_burstsz;
63890618Stmm		break;
63990618Stmm	case SBUS_IVAR_CLOCKFREQ:
640145186Smarius		*result = dinfo->sdi_clockfreq;
64190618Stmm		break;
642146391Smarius	case SBUS_IVAR_IGN:
643146391Smarius		*result = sc->sc_ign;
644146391Smarius		break;
64590618Stmm	case SBUS_IVAR_SLOT:
64690618Stmm		*result = dinfo->sdi_slot;
64790618Stmm		break;
64890618Stmm	default:
64990618Stmm		return (ENOENT);
65090618Stmm	}
651146391Smarius	return (0);
65290618Stmm}
65390618Stmm
65490618Stmmstatic struct resource_list *
65590618Stmmsbus_get_resource_list(device_t dev, device_t child)
65690618Stmm{
65790618Stmm	struct sbus_devinfo *sdi;
65890618Stmm
65990618Stmm	sdi = device_get_ivars(child);
66090618Stmm	return (&sdi->sdi_rl);
66190618Stmm}
66290618Stmm
663172066Smariusstatic void
664172066Smariussbus_intr_enable(void *arg)
665170387Spiso{
666172066Smarius	struct intr_vector *iv = arg;
667172066Smarius	struct sbus_icarg *sica = iv->iv_icarg;
668170387Spiso
669172066Smarius	SYSIO_WRITE8(sica->sica_sc, sica->sica_map,
670172066Smarius	    INTMAP_ENABLE(iv->iv_vec, iv->iv_mid));
671170387Spiso}
672178443Smarius
673172066Smariusstatic void
674172066Smariussbus_intr_disable(void *arg)
675172066Smarius{
676172066Smarius	struct intr_vector *iv = arg;
677172066Smarius	struct sbus_icarg *sica = iv->iv_icarg;
678170387Spiso
679172066Smarius	SYSIO_WRITE8(sica->sica_sc, sica->sica_map, iv->iv_vec);
680172066Smarius}
681172066Smarius
682170387Spisostatic void
683178443Smariussbus_intr_assign(void *arg)
68490618Stmm{
685172066Smarius	struct intr_vector *iv = arg;
686172066Smarius	struct sbus_icarg *sica = iv->iv_icarg;
68790618Stmm
688178443Smarius	SYSIO_WRITE8(sica->sica_sc, sica->sica_map, INTMAP_TID(
689178443Smarius	    SYSIO_READ8(sica->sica_sc, sica->sica_map), iv->iv_mid));
690178443Smarius}
691178443Smarius
692178443Smariusstatic void
693178443Smariussbus_intr_clear(void *arg)
694178443Smarius{
695178443Smarius	struct intr_vector *iv = arg;
696178443Smarius	struct sbus_icarg *sica = iv->iv_icarg;
697178443Smarius
698172066Smarius	SYSIO_WRITE8(sica->sica_sc, sica->sica_clr, 0);
69990618Stmm}
70090618Stmm
70190618Stmmstatic int
702172066Smariussbus_find_intrmap(struct sbus_softc *sc, u_int ino, bus_addr_t *intrmapptr,
703172066Smarius    bus_addr_t *intrclrptr)
70490618Stmm{
705172066Smarius	bus_addr_t intrclr, intrmap;
706172066Smarius	int i;
70790618Stmm
708172066Smarius	if (ino > SBUS_MAX_INO) {
709172066Smarius		device_printf(sc->sc_dev, "out of range INO %d requested\n",
710172066Smarius		    ino);
711172066Smarius		return (0);
712107474Stmm	}
71390618Stmm
714172066Smarius	if ((ino & INTMAP_OBIO_MASK) == 0) {
715172066Smarius		intrmap = SBR_SLOT0_INT_MAP + INTSLOT(ino) * 8;
716172066Smarius		intrclr = SBR_SLOT0_INT_CLR +
717172066Smarius		    (INTSLOT(ino) * 8 * 8) + (INTPRI(ino) * 8);
718172066Smarius	} else {
719172066Smarius		intrclr = 0;
720172066Smarius		for (i = 0, intrmap = SBR_SCSI_INT_MAP;
721172066Smarius		    intrmap <= SBR_RESERVED_INT_MAP; intrmap += 8, i++) {
722172066Smarius			if (INTVEC(SYSIO_READ8(sc, intrmap)) ==
723172066Smarius			    INTMAP_VEC(sc->sc_ign, ino)) {
724172066Smarius				intrclr = SBR_SCSI_INT_CLR + i * 8;
725172066Smarius				break;
726172066Smarius			}
727172066Smarius		}
728172066Smarius		if (intrclr == 0)
729172066Smarius			return (0);
73090618Stmm	}
731172066Smarius	if (intrmapptr != NULL)
732172066Smarius		*intrmapptr = intrmap;
733172066Smarius	if (intrclrptr != NULL)
734172066Smarius		*intrclrptr = intrclr;
735172066Smarius	return (1);
73690618Stmm}
73790618Stmm
73890618Stmmstatic int
739172066Smariussbus_setup_intr(device_t dev, device_t child, struct resource *ires, int flags,
740172066Smarius    driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep)
74190618Stmm{
742172066Smarius	struct sbus_softc *sc;
743172066Smarius	u_long vec;
74490618Stmm
745172066Smarius	sc = device_get_softc(dev);
74690618Stmm	/*
747172066Smarius	 * Make sure the vector is fully specified and we registered
748172066Smarius	 * our interrupt controller for it.
749172066Smarius 	 */
750172066Smarius	vec = rman_get_start(ires);
751172066Smarius	if (INTIGN(vec) != sc->sc_ign || intr_vectors[vec].iv_ic != &sbus_ic) {
752172066Smarius		device_printf(dev, "invalid interrupt vector 0x%lx\n", vec);
753172066Smarius 		return (EINVAL);
754172066Smarius 	}
755172066Smarius	return (bus_generic_setup_intr(dev, child, ires, flags, filt, intr,
756172066Smarius	    arg, cookiep));
75790618Stmm}
75890618Stmm
75990618Stmmstatic struct resource *
76090618Stmmsbus_alloc_resource(device_t bus, device_t child, int type, int *rid,
76190618Stmm    u_long start, u_long end, u_long count, u_int flags)
76290618Stmm{
76390618Stmm	struct sbus_softc *sc;
76490618Stmm	struct rman *rm;
76590618Stmm	struct resource *rv;
76690618Stmm	struct resource_list *rl;
76790618Stmm	struct resource_list_entry *rle;
768145186Smarius	device_t schild;
76990618Stmm	bus_space_handle_t bh;
77090618Stmm	bus_addr_t toffs;
77190618Stmm	bus_size_t tend;
772145186Smarius	int i, slot;
773145186Smarius	int isdefault, needactivate, passthrough;
77490618Stmm
775145185Smarius	isdefault = (start == 0UL && end == ~0UL);
776145185Smarius	needactivate = flags & RF_ACTIVE;
777145186Smarius	passthrough = (device_get_parent(child) != bus);
778145186Smarius	rle = NULL;
779145186Smarius	sc = device_get_softc(bus);
780145186Smarius	rl = BUS_GET_RESOURCE_LIST(bus, child);
78190618Stmm	switch (type) {
78290618Stmm	case SYS_RES_IRQ:
783145186Smarius		return (resource_list_alloc(rl, bus, child, type, rid, start,
784145186Smarius		    end, count, flags));
78590618Stmm	case SYS_RES_MEMORY:
786145186Smarius		if (!passthrough) {
787145186Smarius			rle = resource_list_find(rl, type, *rid);
788145186Smarius			if (rle == NULL)
789145186Smarius				return (NULL);
790145186Smarius			if (rle->res != NULL)
791145186Smarius				panic("%s: resource entry is busy", __func__);
792145186Smarius			if (isdefault) {
793145186Smarius				start = rle->start;
794145186Smarius				count = ulmax(count, rle->count);
795145186Smarius				end = ulmax(rle->end, start + count - 1);
796145186Smarius			}
797145186Smarius		}
79890618Stmm		rm = NULL;
79990618Stmm		bh = toffs = tend = 0;
800145186Smarius		schild = child;
801145186Smarius		while (device_get_parent(schild) != bus)
802172066Smarius			schild = device_get_parent(schild);
803145186Smarius		slot = sbus_get_slot(schild);
80490618Stmm		for (i = 0; i < sc->sc_nrange; i++) {
805145186Smarius			if (sc->sc_rd[i].rd_slot != slot ||
80690618Stmm			    start < sc->sc_rd[i].rd_coffset ||
80790618Stmm			    start > sc->sc_rd[i].rd_cend)
80890618Stmm				continue;
80990618Stmm			/* Disallow cross-range allocations. */
81090618Stmm			if (end > sc->sc_rd[i].rd_cend)
81190618Stmm				return (NULL);
81290618Stmm			/* We've found the connection to the parent bus */
81390618Stmm			toffs = start - sc->sc_rd[i].rd_coffset;
81490618Stmm			tend = end - sc->sc_rd[i].rd_coffset;
81590618Stmm			rm = &sc->sc_rd[i].rd_rman;
81690618Stmm			bh = sc->sc_rd[i].rd_bushandle;
817159413Smarius			break;
81890618Stmm		}
819159413Smarius		if (rm == NULL)
82090618Stmm			return (NULL);
82190618Stmm		flags &= ~RF_ACTIVE;
82290618Stmm		rv = rman_reserve_resource(rm, toffs, tend, count, flags,
82390618Stmm		    child);
82490618Stmm		if (rv == NULL)
82590618Stmm			return (NULL);
826157896Simp		rman_set_rid(rv, *rid);
82790618Stmm		rman_set_bustag(rv, sc->sc_cbustag);
82890618Stmm		rman_set_bushandle(rv, bh + rman_get_start(rv));
82990618Stmm		if (needactivate) {
83090618Stmm			if (bus_activate_resource(child, type, *rid, rv)) {
83190618Stmm				rman_release_resource(rv);
83290618Stmm				return (NULL);
83390618Stmm			}
83490618Stmm		}
835145186Smarius		if (!passthrough)
836145186Smarius			rle->res = rv;
837145186Smarius		return (rv);
83890618Stmm	default:
83990618Stmm		return (NULL);
84090618Stmm	}
84190618Stmm}
84290618Stmm
84390618Stmmstatic int
84490618Stmmsbus_activate_resource(device_t bus, device_t child, int type, int rid,
84590618Stmm    struct resource *r)
84690618Stmm{
847159413Smarius	void *p;
848159413Smarius	int error;
84990618Stmm
850108798Stmm	if (type == SYS_RES_IRQ) {
851108798Stmm		return (BUS_ACTIVATE_RESOURCE(device_get_parent(bus),
852108798Stmm		    child, type, rid, r));
853108798Stmm	}
854159413Smarius	if (type == SYS_RES_MEMORY) {
855159413Smarius		/*
856190112Smarius		 * Need to memory-map the device space, as some drivers
857190112Smarius		 * depend on the virtual address being set and usable.
858159413Smarius		 */
859159413Smarius		error = sparc64_bus_mem_map(rman_get_bustag(r),
860159413Smarius		    rman_get_bushandle(r), rman_get_size(r), 0, 0, &p);
861159413Smarius		if (error != 0)
862159413Smarius			return (error);
863159413Smarius		rman_set_virtual(r, p);
864159413Smarius	}
86590618Stmm	return (rman_activate_resource(r));
86690618Stmm}
86790618Stmm
86890618Stmmstatic int
86990618Stmmsbus_deactivate_resource(device_t bus, device_t child, int type, int rid,
87090618Stmm    struct resource *r)
87190618Stmm{
87290618Stmm
873108798Stmm	if (type == SYS_RES_IRQ) {
874108798Stmm		return (BUS_DEACTIVATE_RESOURCE(device_get_parent(bus),
875108798Stmm		    child, type, rid, r));
876108798Stmm	}
877159413Smarius	if (type == SYS_RES_MEMORY) {
878159413Smarius		sparc64_bus_mem_unmap(rman_get_virtual(r), rman_get_size(r));
879159413Smarius		rman_set_virtual(r, NULL);
880159413Smarius	}
88190618Stmm	return (rman_deactivate_resource(r));
88290618Stmm}
88390618Stmm
88490618Stmmstatic int
88590618Stmmsbus_release_resource(device_t bus, device_t child, int type, int rid,
88690618Stmm    struct resource *r)
88790618Stmm{
888145186Smarius	struct resource_list *rl;
889108798Stmm	struct resource_list_entry *rle;
890145186Smarius	int error, passthrough;
89190618Stmm
892145186Smarius	passthrough = (device_get_parent(child) != bus);
893145186Smarius	rl = BUS_GET_RESOURCE_LIST(bus, child);
89490618Stmm	if (type == SYS_RES_IRQ)
895145186Smarius		return (resource_list_release(rl, bus, child, type, rid, r));
896145186Smarius	if ((rman_get_flags(r) & RF_ACTIVE) != 0) {
897145186Smarius		error = bus_deactivate_resource(child, type, rid, r);
898108798Stmm		if (error != 0)
899108798Stmm			return (error);
90090618Stmm	}
901145186Smarius	error = rman_release_resource(r);
902145186Smarius	if (error != 0 || passthrough)
903108798Stmm		return (error);
904145186Smarius	rle = resource_list_find(rl, type, rid);
905108798Stmm	if (rle == NULL)
906145185Smarius		panic("%s: cannot find resource", __func__);
907108798Stmm	if (rle->res == NULL)
908145185Smarius		panic("%s: resource entry is not busy", __func__);
909108798Stmm	rle->res = NULL;
910108798Stmm	return (0);
91190618Stmm}
91290618Stmm
913167308Smariusstatic bus_dma_tag_t
914167308Smariussbus_get_dma_tag(device_t bus, device_t child)
915167308Smarius{
916167308Smarius	struct sbus_softc *sc;
917167308Smarius
918167308Smarius	sc = device_get_softc(bus);
919167308Smarius	return (sc->sc_cdmatag);
920167308Smarius}
921167308Smarius
922152684Smariusstatic const struct ofw_bus_devinfo *
923152684Smariussbus_get_devinfo(device_t bus, device_t child)
924152684Smarius{
925152684Smarius	struct sbus_devinfo *sdi;
926152684Smarius
927152684Smarius	sdi = device_get_ivars(child);
928152684Smarius	return (&sdi->sdi_obdinfo);
929152684Smarius}
930152684Smarius
93190618Stmm/*
93290618Stmm * Handle an overtemp situation.
93390618Stmm *
93490618Stmm * SPARCs have temperature sensors which generate interrupts
93590618Stmm * if the machine's temperature exceeds a certain threshold.
93690618Stmm * This handles the interrupt and powers off the machine.
93790618Stmm * The same needs to be done to PCI controller drivers.
93890618Stmm */
939170852Smariusstatic void
94090618Stmmsbus_overtemp(void *arg)
94190618Stmm{
942172066Smarius	static int shutdown;
94390618Stmm
944172066Smarius	/* As the interrupt is cleared we may be called multiple times. */
945172066Smarius	if (shutdown != 0)
946172066Smarius		return;
947172066Smarius	shutdown++;
94890618Stmm	printf("DANGER: OVER TEMPERATURE detected\nShutting down NOW.\n");
94990618Stmm	shutdown_nice(RB_POWEROFF);
95090618Stmm}
95190618Stmm
95290618Stmm/* Try to shut down in time in case of power failure. */
953170852Smariusstatic void
95490618Stmmsbus_pwrfail(void *arg)
95590618Stmm{
956172066Smarius	static int shutdown;
95790618Stmm
958172066Smarius	/* As the interrupt is cleared we may be called multiple times. */
959172066Smarius	if (shutdown != 0)
960172066Smarius		return;
961172066Smarius	shutdown++;
96290618Stmm	printf("Power failure detected\nShutting down NOW.\n");
96390618Stmm	shutdown_nice(0);
96490618Stmm}
96590618Stmm
96690618Stmmstatic bus_space_tag_t
96790618Stmmsbus_alloc_bustag(struct sbus_softc *sc)
96890618Stmm{
96990618Stmm	bus_space_tag_t sbt;
97090618Stmm
97190618Stmm	sbt = (bus_space_tag_t)malloc(sizeof(struct bus_space_tag), M_DEVBUF,
97290618Stmm	    M_NOWAIT | M_ZERO);
97390618Stmm	if (sbt == NULL)
974145185Smarius		panic("%s: out of memory", __func__);
97590618Stmm
976108815Stmm	sbt->bst_cookie = sc;
977170852Smarius	sbt->bst_parent = rman_get_bustag(sc->sc_sysio_res);
978108815Stmm	sbt->bst_type = SBUS_BUS_SPACE;
97990618Stmm	return (sbt);
98090618Stmm}
981133589Smarius
982152684Smariusstatic int
983152684Smariussbus_print_res(struct sbus_devinfo *sdi)
984133589Smarius{
985152684Smarius	int rv;
986133589Smarius
987152684Smarius	rv = 0;
988152684Smarius	rv += resource_list_print_type(&sdi->sdi_rl, "mem", SYS_RES_MEMORY,
989152684Smarius	    "%#lx");
990152684Smarius	rv += resource_list_print_type(&sdi->sdi_rl, "irq", SYS_RES_IRQ,
991152684Smarius	    "%ld");
992152684Smarius	return (rv);
993133589Smarius}
994