sbus.c revision 170387
1138568Ssam/*-
2178354Ssam * Copyright (c) 1998 The NetBSD Foundation, Inc.
3138568Ssam * All rights reserved.
4138568Ssam *
5138568Ssam * This code is derived from software contributed to The NetBSD Foundation
6138568Ssam * by Paul Kranenburg.
7138568Ssam *
8138568Ssam * Redistribution and use in source and binary forms, with or without
9138568Ssam * modification, are permitted provided that the following conditions
10138568Ssam * are met:
11138568Ssam * 1. Redistributions of source code must retain the above copyright
12138568Ssam *    notice, this list of conditions and the following disclaimer.
13138568Ssam * 2. Redistributions in binary form must reproduce the above copyright
14138568Ssam *    notice, this list of conditions and the following disclaimer in the
15138568Ssam *    documentation and/or other materials provided with the distribution.
16138568Ssam * 3. All advertising materials mentioning features or use of this software
17138568Ssam *    must display the following acknowledgement:
18138568Ssam *        This product includes software developed by the NetBSD
19138568Ssam *        Foundation, Inc. and its contributors.
20138568Ssam * 4. Neither the name of The NetBSD Foundation nor the names of its
21138568Ssam *    contributors may be used to endorse or promote products derived
22138568Ssam *    from this software without specific prior written permission.
23138568Ssam *
24138568Ssam * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25138568Ssam * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26138568Ssam * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27138568Ssam * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28138568Ssam * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29138568Ssam * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30165911Ssam * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31178354Ssam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32178354Ssam * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33178354Ssam * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34178354Ssam * POSSIBILITY OF SUCH DAMAGE.
35192473Ssam */
36191746Sthompsa/*-
37178354Ssam * Copyright (c) 1992, 1993
38138568Ssam *	The Regents of the University of California.  All rights reserved.
39170530Ssam *
40170530Ssam * This software was developed by the Computer Systems Engineering group
41179388Ssam * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
42179388Ssam * contributed to Berkeley.
43179388Ssam *
44179388Ssam * All advertising materials mentioning features or use of this software
45179388Ssam * must display the following acknowledgement:
46179388Ssam *	This product includes software developed by the University of
47179388Ssam *	California, Lawrence Berkeley Laboratory.
48179388Ssam *
49179388Ssam * Redistribution and use in source and binary forms, with or without
50179388Ssam * modification, are permitted provided that the following conditions
51179388Ssam * are met:
52179388Ssam * 1. Redistributions of source code must retain the above copyright
53179388Ssam *    notice, this list of conditions and the following disclaimer.
54170530Ssam * 2. Redistributions in binary form must reproduce the above copyright
55179388Ssam *    notice, this list of conditions and the following disclaimer in the
56243532Sadrian *    documentation and/or other materials provided with the distribution.
57243532Sadrian * 4. Neither the name of the University nor the names of its contributors
58170530Ssam *    may be used to endorse or promote products derived from this software
59170530Ssam *    without specific prior written permission.
60248069Sadrian *
61248069Sadrian * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
62248069Sadrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
63248069Sadrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
64248069Sadrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
65248069Sadrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
66248069Sadrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
67248069Sadrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
68248069Sadrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
69248069Sadrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
70248069Sadrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
71248069Sadrian * SUCH DAMAGE.
72248069Sadrian */
73248069Sadrian/*-
74248069Sadrian * Copyright (c) 1999 Eduardo Horvath
75248069Sadrian * Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>.
76248069Sadrian * Copyright (c) 2005 Marius Strobl <marius@FreeBSD.org>
77248069Sadrian * All rights reserved.
78248069Sadrian *
79248069Sadrian * Redistribution and use in source and binary forms, with or without
80248069Sadrian * modification, are permitted provided that the following conditions
81248069Sadrian * are met:
82248069Sadrian * 1. Redistributions of source code must retain the above copyright
83248069Sadrian *    notice, this list of conditions and the following disclaimer.
84138568Ssam *
85138568Ssam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR  ``AS IS'' AND
86178354Ssam * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
87178354Ssam * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
88178354Ssam * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR  BE LIABLE
89178354Ssam * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
90178354Ssam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
91178354Ssam * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
92178354Ssam * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
93179388Ssam * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
94178354Ssam * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
95179388Ssam * SUCH DAMAGE.
96178354Ssam *
97179388Ssam *	from: @(#)sbus.c	8.1 (Berkeley) 6/11/93
98178354Ssam *	from: NetBSD: sbus.c,v 1.46 2001/10/07 20:30:41 eeh Exp
99179388Ssam */
100178354Ssam
101179388Ssam#include <sys/cdefs.h>
102178354Ssam__FBSDID("$FreeBSD: head/sys/sparc64/sbus/sbus.c 170387 2007-06-06 22:19:23Z piso $");
103179388Ssam
104178354Ssam/*
105179388Ssam * SBus support.
106138568Ssam */
107138568Ssam
108178354Ssam#include <sys/param.h>
109178354Ssam#include <sys/systm.h>
110178354Ssam#include <sys/bus.h>
111138568Ssam#include <sys/kernel.h>
112178354Ssam#include <sys/malloc.h>
113178354Ssam#include <sys/module.h>
114178354Ssam#include <sys/pcpu.h>
115178354Ssam#include <sys/reboot.h>
116178354Ssam
117178354Ssam#include <dev/ofw/ofw_bus.h>
118178354Ssam#include <dev/ofw/ofw_bus_subr.h>
119179388Ssam#include <dev/ofw/openfirm.h>
120178354Ssam
121179388Ssam#include <machine/bus.h>
122178354Ssam#include <machine/bus_private.h>
123179388Ssam#include <machine/iommureg.h>
124178354Ssam#include <machine/bus_common.h>
125179388Ssam#include <machine/resource.h>
126178354Ssam
127179388Ssam#include <sys/rman.h>
128138568Ssam
129138568Ssam#include <machine/iommuvar.h>
130184288Ssam
131138568Ssam#include <sparc64/sbus/ofw_sbus.h>
132184288Ssam#include <sparc64/sbus/sbusreg.h>
133184288Ssam#include <sparc64/sbus/sbusvar.h>
134195379Ssam
135184288Ssamstruct sbus_devinfo {
136184288Ssam	int			sdi_burstsz;
137184288Ssam	int			sdi_clockfreq;
138138568Ssam	int			sdi_slot;
139167284Ssam
140167284Ssam	struct ofw_bus_devinfo	sdi_obdinfo;
141167284Ssam	struct resource_list	sdi_rl;
142167284Ssam};
143167284Ssam
144167284Ssam/* Range descriptor, allocated for each sc_range. */
145167284Ssamstruct sbus_rd {
146167284Ssam	bus_addr_t		rd_poffset;
147167284Ssam	bus_addr_t		rd_pend;
148167284Ssam	int			rd_slot;
149167284Ssam	bus_addr_t		rd_coffset;
150167284Ssam	bus_addr_t		rd_cend;
151167284Ssam	struct rman		rd_rman;
152167284Ssam	bus_space_handle_t	rd_bushandle;
153195379Ssam	struct resource		*rd_res;
154195379Ssam};
155195379Ssam
156195379Ssamstruct sbus_softc {
157195379Ssam	bus_space_tag_t		sc_bustag;
158195379Ssam	bus_space_handle_t	sc_bushandle;
159195379Ssam	bus_dma_tag_t		sc_cdmatag;
160195379Ssam	bus_space_tag_t		sc_cbustag;
161195379Ssam	int			sc_clockfreq;	/* clock frequency (in Hz) */
162195379Ssam	int			sc_nrange;
163167284Ssam	struct sbus_rd		*sc_rd;
164138568Ssam	int			sc_burst;	/* burst transfer sizes supp. */
165138568Ssam
166138568Ssam	struct resource		*sc_sysio_res;
167138568Ssam	int			sc_ign;		/* IGN for this sysio */
168138568Ssam	struct iommu_state	sc_is;		/* IOMMU state (iommuvar.h) */
169138568Ssam
170138568Ssam	struct resource		*sc_ot_ires;
171138568Ssam	void			*sc_ot_ihand;
172138568Ssam	struct resource		*sc_pf_ires;
173138568Ssam	void			*sc_pf_ihand;
174138568Ssam};
175138568Ssam
176138568Ssamstruct sbus_clr {
177206617Srpaulo	struct sbus_softc	*scl_sc;
178206617Srpaulo	bus_addr_t		scl_clr;	/* clear register */
179206617Srpaulo	driver_filter_t		*scl_filter;
180206617Srpaulo	driver_intr_t		*scl_handler;	/* handler to call */
181206617Srpaulo	void			*scl_arg;	/* argument for the handler */
182206617Srpaulo	void			*scl_cookie;	/* parent bus int. cookie */
183206617Srpaulo};
184206617Srpaulo
185206617Srpaulo#define	SYSIO_READ8(sc, off) \
186206617Srpaulo	bus_space_read_8((sc)->sc_bustag, (sc)->sc_bushandle, (off))
187138568Ssam#define	SYSIO_WRITE8(sc, off, v) \
188138568Ssam	bus_space_write_8((sc)->sc_bustag, (sc)->sc_bushandle, (off), (v))
189138568Ssam
190138568Ssamstatic device_probe_t sbus_probe;
191138568Ssamstatic device_attach_t sbus_attach;
192138568Ssamstatic bus_print_child_t sbus_print_child;
193138568Ssamstatic bus_probe_nomatch_t sbus_probe_nomatch;
194138568Ssamstatic bus_read_ivar_t sbus_read_ivar;
195138568Ssamstatic bus_get_resource_list_t sbus_get_resource_list;
196138568Ssamstatic bus_setup_intr_t sbus_setup_intr;
197138568Ssamstatic bus_teardown_intr_t sbus_teardown_intr;
198138568Ssamstatic bus_alloc_resource_t sbus_alloc_resource;
199138568Ssamstatic bus_release_resource_t sbus_release_resource;
200138568Ssamstatic bus_activate_resource_t sbus_activate_resource;
201138568Ssamstatic bus_deactivate_resource_t sbus_deactivate_resource;
202138568Ssamstatic bus_get_dma_tag_t sbus_get_dma_tag;
203138568Ssamstatic ofw_bus_get_devinfo_t sbus_get_devinfo;
204138568Ssam
205144618Ssamstatic int sbus_inlist(const char *, const char **);
206138568Ssamstatic struct sbus_devinfo * sbus_setup_dinfo(device_t, struct sbus_softc *,
207138568Ssam    phandle_t);
208165904Ssamstatic void sbus_destroy_dinfo(struct sbus_devinfo *);
209178354Ssamstatic driver_filter_t sbus_filter_stub;
210165894Ssamstatic driver_intr_t sbus_intr_stub;
211178354Ssamstatic bus_space_tag_t sbus_alloc_bustag(struct sbus_softc *);
212165894Ssamstatic driver_filter_t sbus_overtemp;
213178354Ssamstatic driver_filter_t sbus_pwrfail;
214178354Ssamstatic int sbus_print_res(struct sbus_devinfo *);
215178354Ssam
216178354Ssamstatic device_method_t sbus_methods[] = {
217178354Ssam	/* Device interface */
218178354Ssam	DEVMETHOD(device_probe,		sbus_probe),
219171022Ssam	DEVMETHOD(device_attach,	sbus_attach),
220178354Ssam	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
221178354Ssam	DEVMETHOD(device_suspend,	bus_generic_suspend),
222170530Ssam	DEVMETHOD(device_resume,	bus_generic_resume),
223170530Ssam
224170530Ssam	/* Bus interface */
225170530Ssam	DEVMETHOD(bus_print_child,	sbus_print_child),
226170530Ssam	DEVMETHOD(bus_probe_nomatch,	sbus_probe_nomatch),
227170530Ssam	DEVMETHOD(bus_read_ivar,	sbus_read_ivar),
228172054Ssam	DEVMETHOD(bus_setup_intr, 	sbus_setup_intr),
229170530Ssam	DEVMETHOD(bus_teardown_intr,	sbus_teardown_intr),
230184286Ssam	DEVMETHOD(bus_alloc_resource,	sbus_alloc_resource),
231178354Ssam	DEVMETHOD(bus_activate_resource,	sbus_activate_resource),
232138568Ssam	DEVMETHOD(bus_deactivate_resource,	sbus_deactivate_resource),
233147789Ssam	DEVMETHOD(bus_release_resource,	sbus_release_resource),
234178354Ssam	DEVMETHOD(bus_get_resource_list, sbus_get_resource_list),
235178354Ssam	DEVMETHOD(bus_get_resource,	bus_generic_rl_get_resource),
236183247Ssam	DEVMETHOD(bus_get_dma_tag,	sbus_get_dma_tag),
237254640Sadrian
238254640Sadrian	/* ofw_bus interface */
239254640Sadrian	DEVMETHOD(ofw_bus_get_devinfo,	sbus_get_devinfo),
240254640Sadrian	DEVMETHOD(ofw_bus_get_compat,	ofw_bus_gen_get_compat),
241254640Sadrian	DEVMETHOD(ofw_bus_get_model,	ofw_bus_gen_get_model),
242254640Sadrian	DEVMETHOD(ofw_bus_get_name,	ofw_bus_gen_get_name),
243254640Sadrian	DEVMETHOD(ofw_bus_get_node,	ofw_bus_gen_get_node),
244254640Sadrian	DEVMETHOD(ofw_bus_get_type,	ofw_bus_gen_get_type),
245254640Sadrian
246254640Sadrian	{ 0, 0 }
247254640Sadrian};
248254526Sandre
249254526Sandrestatic driver_t sbus_driver = {
250254526Sandre	"sbus",
251254640Sadrian	sbus_methods,
252254640Sadrian	sizeof(struct sbus_softc),
253178354Ssam};
254254526Sandre
255254526Sandrestatic devclass_t sbus_devclass;
256172054Ssam
257170530SsamDRIVER_MODULE(sbus, nexus, sbus_driver, sbus_devclass, 0, 0);
258183247Ssam
259172054Ssam#define	OFW_SBUS_TYPE	"sbus"
260183247Ssam#define	OFW_SBUS_NAME	"sbus"
261183247Ssam
262183247Ssamstatic const char *sbus_order_first[] = {
263183247Ssam	"auxio",
264195618Srpaulo	"dma",
265254640Sadrian	NULL
266195618Srpaulo};
267254527Sandre
268254527Sandrestatic int
269254527Sandresbus_inlist(const char *name, const char **list)
270254640Sadrian{
271254640Sadrian	int i;
272254640Sadrian
273254640Sadrian	if (name == NULL)
274254640Sadrian		return (0);
275254640Sadrian	for (i = 0; list[i] != NULL; i++) {
276254640Sadrian		if (strcmp(name, list[i]) == 0)
277195618Srpaulo			return (1);
278195618Srpaulo	}
279254527Sandre	return (0);
280254527Sandre}
281195618Srpaulo
282138568Ssamstatic int
283178354Ssamsbus_probe(device_t dev)
284178354Ssam{
285178354Ssam	const char *t;
286178354Ssam
287178354Ssam	t = ofw_bus_get_type(dev);
288138568Ssam	if (((t == NULL || strcmp(t, OFW_SBUS_TYPE) != 0)) &&
289138568Ssam	    strcmp(ofw_bus_get_name(dev), OFW_SBUS_NAME) != 0)
290178354Ssam		return (ENXIO);
291178354Ssam	device_set_desc(dev, "U2S UPA-SBus bridge");
292138568Ssam	return (0);
293138568Ssam}
294138568Ssam
295138568Ssamstatic int
296138568Ssamsbus_attach(device_t dev)
297138568Ssam{
298138568Ssam	struct sbus_softc *sc;
299138568Ssam	struct sbus_devinfo *sdi;
300138568Ssam	struct sbus_ranges *range;
301138568Ssam	struct resource *res;
302191571Ssam	struct resource_list *rl;
303191571Ssam	device_t cdev;
304191571Ssam	bus_addr_t phys;
305191571Ssam	bus_size_t size;
306191571Ssam	char *name;
307191571Ssam	phandle_t child, node;
308191571Ssam	u_int64_t mr;
309170530Ssam	int clock, i, intr, rid;
310170530Ssam
311170530Ssam	sc = device_get_softc(dev);
312170530Ssam	node = ofw_bus_get_node(dev);
313170530Ssam
314170530Ssam	rid = 0;
315170530Ssam	sc->sc_sysio_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
316170530Ssam	    RF_ACTIVE);
317170530Ssam	if (sc->sc_sysio_res == NULL)
318170530Ssam		panic("%s: cannot allocate device memory", __func__);
319170530Ssam	sc->sc_bustag = rman_get_bustag(sc->sc_sysio_res);
320248069Sadrian	sc->sc_bushandle = rman_get_bushandle(sc->sc_sysio_res);
321254082Sadrian
322254082Sadrian	if (OF_getprop(node, "interrupts", &intr, sizeof(intr)) == -1)
323248069Sadrian		panic("%s: cannot get IGN", __func__);
324144618Ssam	sc->sc_ign = (intr & INTMAP_IGN_MASK) >> INTMAP_IGN_SHIFT;
325138568Ssam	sc->sc_cbustag = sbus_alloc_bustag(sc);
326138568Ssam
327138568Ssam	/*
328178354Ssam	 * Record clock frequency for synchronous SCSI.
329178354Ssam	 * IS THIS THE CORRECT DEFAULT??
330138568Ssam	 */
331192473Ssam	if (OF_getprop(node, "clock-frequency", &clock, sizeof(clock)) == -1)
332192473Ssam		clock = 25000000;
333192473Ssam	sc->sc_clockfreq = clock;
334138568Ssam	clock /= 1000;
335170530Ssam	device_printf(dev, "clock %d.%03d MHz\n", clock / 1000, clock % 1000);
336178354Ssam
337178354Ssam	/*
338178354Ssam	 * Collect address translations from the OBP.
339178354Ssam	 */
340178354Ssam	if ((sc->sc_nrange = OF_getprop_alloc(node, "ranges",
341178354Ssam	    sizeof(*range), (void **)&range)) == -1) {
342178354Ssam		panic("%s: error getting ranges property", __func__);
343178354Ssam	}
344170530Ssam	sc->sc_rd = (struct sbus_rd *)malloc(sizeof(*sc->sc_rd) * sc->sc_nrange,
345178354Ssam	    M_DEVBUF, M_NOWAIT);
346170530Ssam	if (sc->sc_rd == NULL)
347178354Ssam		panic("%s: cannot allocate rmans", __func__);
348170530Ssam	/*
349170530Ssam	 * Preallocate all space that the SBus bridge decodes, so that nothing
350178354Ssam	 * else gets in the way; set up rmans etc.
351178354Ssam	 */
352178354Ssam	rl = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev);
353178354Ssam	for (i = 0; i < sc->sc_nrange; i++) {
354170530Ssam		phys = range[i].poffset | ((bus_addr_t)range[i].pspace << 32);
355170530Ssam		size = range[i].size;
356170530Ssam		sc->sc_rd[i].rd_slot = range[i].cspace;
357170530Ssam		sc->sc_rd[i].rd_coffset = range[i].coffset;
358170530Ssam		sc->sc_rd[i].rd_cend = sc->sc_rd[i].rd_coffset + size;
359170530Ssam		rid = resource_list_add_next(rl, SYS_RES_MEMORY, phys,
360170530Ssam		    phys + size - 1, size);
361170530Ssam		if ((res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
362178354Ssam		    RF_ACTIVE)) == NULL)
363178354Ssam			panic("%s: cannot allocate decoded range", __func__);
364178354Ssam		sc->sc_rd[i].rd_bushandle = rman_get_bushandle(res);
365178354Ssam		sc->sc_rd[i].rd_rman.rm_type = RMAN_ARRAY;
366178354Ssam		sc->sc_rd[i].rd_rman.rm_descr = "SBus Device Memory";
367178354Ssam		if (rman_init(&sc->sc_rd[i].rd_rman) != 0 ||
368170530Ssam		    rman_manage_region(&sc->sc_rd[i].rd_rman, 0, size) != 0)
369170530Ssam			panic("%s: failed to set up memory rman", __func__);
370170530Ssam		sc->sc_rd[i].rd_poffset = phys;
371170530Ssam		sc->sc_rd[i].rd_pend = phys + size;
372170530Ssam		sc->sc_rd[i].rd_res = res;
373170530Ssam	}
374178354Ssam	free(range, M_OFWPROP);
375241394Skevlo
376170530Ssam	/*
377170530Ssam	 * Get the SBus burst transfer size if burst transfers are supported.
378170530Ssam	 * XXX: is the default correct?
379170530Ssam	 */
380178354Ssam	if (OF_getprop(node, "burst-sizes", &sc->sc_burst,
381178354Ssam	    sizeof(sc->sc_burst)) == -1 || sc->sc_burst == 0)
382178354Ssam		sc->sc_burst = SBUS_BURST_DEF;
383178354Ssam
384178354Ssam	/* initalise the IOMMU */
385178354Ssam
386178354Ssam	/* punch in our copies */
387178354Ssam	sc->sc_is.is_bustag = sc->sc_bustag;
388178354Ssam	sc->sc_is.is_bushandle = sc->sc_bushandle;
389178354Ssam	sc->sc_is.is_iommu = SBR_IOMMU;
390178354Ssam	sc->sc_is.is_dtag = SBR_IOMMU_TLB_TAG_DIAG;
391178354Ssam	sc->sc_is.is_ddram = SBR_IOMMU_TLB_DATA_DIAG;
392178354Ssam	sc->sc_is.is_dqueue = SBR_IOMMU_QUEUE_DIAG;
393178354Ssam	sc->sc_is.is_dva = SBR_IOMMU_SVADIAG;
394178354Ssam	sc->sc_is.is_dtcmp = 0;
395178354Ssam	sc->sc_is.is_sb[0] = SBR_STRBUF;
396178354Ssam	sc->sc_is.is_sb[1] = 0;
397178354Ssam
398178354Ssam	/* give us a nice name.. */
399178354Ssam	name = (char *)malloc(32, M_DEVBUF, M_NOWAIT);
400178354Ssam	if (name == NULL)
401178354Ssam		panic("%s: cannot malloc iommu name", __func__);
402178354Ssam	snprintf(name, 32, "%s dvma", device_get_name(dev));
403178354Ssam
404178354Ssam	/*
405178354Ssam	 * Note: the SBus IOMMU ignores the high bits of an address, so a NULL
406178354Ssam	 * DMA pointer will be translated by the first page of the IOTSB.
407178354Ssam	 * To detect bugs we'll allocate and ignore the first entry.
408178354Ssam	 */
409178354Ssam	iommu_init(name, &sc->sc_is, 3, -1, 1);
410178354Ssam
411178354Ssam	/* Create the DMA tag. */
412178354Ssam	if (bus_dma_tag_create(bus_get_dma_tag(dev), 8, 0, IOMMU_MAXADDR, ~0,
413178354Ssam	    NULL, NULL, IOMMU_MAXADDR, 0xff, 0xffffffff, 0, NULL, NULL,
414178354Ssam	    &sc->sc_cdmatag) != 0)
415178354Ssam		panic("%s: bus_dma_tag_create failed", __func__);
416178354Ssam	/* Customize the tag. */
417178354Ssam	sc->sc_cdmatag->dt_cookie = &sc->sc_is;
418178354Ssam	sc->sc_cdmatag->dt_mt = &iommu_dma_methods;
419178354Ssam
420178354Ssam	/* Enable the over-temperature and power-fail interrupts. */
421178354Ssam	rid = 4;
422178354Ssam	mr = SYSIO_READ8(sc, SBR_THERM_INT_MAP);
423178354Ssam	sc->sc_ot_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
424178354Ssam	    RF_ACTIVE);
425178354Ssam	if (sc->sc_ot_ires == NULL ||
426178354Ssam	    rman_get_start(sc->sc_ot_ires) != INTVEC(mr) ||
427178354Ssam	    bus_setup_intr(dev, sc->sc_ot_ires, INTR_TYPE_MISC,
428178354Ssam	    sbus_overtemp, NULL, sc, &sc->sc_ot_ihand) != 0)
429178354Ssam		panic("%s: failed to set up temperature interrupt", __func__);
430178354Ssam	SYSIO_WRITE8(sc, SBR_THERM_INT_MAP, INTMAP_ENABLE(mr, PCPU_GET(mid)));
431178354Ssam	rid = 3;
432178354Ssam	mr = SYSIO_READ8(sc, SBR_POWER_INT_MAP);
433178354Ssam	sc->sc_pf_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
434178354Ssam	    RF_ACTIVE);
435178354Ssam	if (sc->sc_pf_ires == NULL ||
436178354Ssam	    rman_get_start(sc->sc_pf_ires) != INTVEC(mr) ||
437178354Ssam	    bus_setup_intr(dev, sc->sc_pf_ires, INTR_TYPE_MISC,
438178354Ssam	    sbus_pwrfail, NULL, sc, &sc->sc_pf_ihand) != 0)
439178354Ssam		panic("%s: failed to set up power fail interrupt", __func__);
440178354Ssam	SYSIO_WRITE8(sc, SBR_POWER_INT_MAP, INTMAP_ENABLE(mr, PCPU_GET(mid)));
441178354Ssam
442178354Ssam	/* Initialize the counter-timer. */
443178354Ssam	sparc64_counter_init(sc->sc_bustag, sc->sc_bushandle, SBR_TC0);
444178354Ssam
445178354Ssam	/*
446178354Ssam	 * Loop through ROM children, fixing any relative addresses
447178354Ssam	 * and then configuring each device.
448206358Srpaulo	 */
449206358Srpaulo	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
450206358Srpaulo		if ((sdi = sbus_setup_dinfo(dev, sc, child)) == NULL)
451206358Srpaulo			continue;
452178354Ssam		/*
453178354Ssam		 * For devices where there are variants that are actually
454178354Ssam		 * split into two SBus devices (as opposed to the first
455206358Srpaulo		 * half of the device being a SBus device and the second
456206358Srpaulo		 * half hanging off of the first one) like 'auxio' and
457206358Srpaulo		 * 'SUNW,fdtwo' or 'dma' and 'esp' probe the SBus device
458206358Srpaulo		 * which is a prerequisite to the driver attaching to the
459178354Ssam		 * second one with a lower order. Saves us from dealing
460206358Srpaulo		 * with different probe orders in the respective device
461138568Ssam		 * drivers which generally is more hackish.
462190384Ssam		 */
463190384Ssam		cdev = device_add_child_ordered(dev, (OF_child(child) == 0 &&
464190384Ssam		    sbus_inlist(sdi->sdi_obdinfo.obd_name, sbus_order_first)) ?
465190384Ssam		    SBUS_ORDER_FIRST : SBUS_ORDER_NORMAL, NULL, -1);
466190384Ssam		if (cdev == NULL) {
467190384Ssam			device_printf(dev,
468190384Ssam			    "<%s>: device_add_child_ordered failed\n",
469190384Ssam			    sdi->sdi_obdinfo.obd_name);
470190384Ssam			sbus_destroy_dinfo(sdi);
471190384Ssam			continue;
472190394Ssam		}
473190384Ssam		device_set_ivars(cdev, sdi);
474138568Ssam	}
475138568Ssam	return (bus_generic_attach(dev));
476138568Ssam}
477138568Ssam
478138568Ssamstatic struct sbus_devinfo *
479138568Ssamsbus_setup_dinfo(device_t dev, struct sbus_softc *sc, phandle_t node)
480138568Ssam{
481138568Ssam	struct sbus_devinfo *sdi;
482138568Ssam	struct sbus_regs *reg;
483138568Ssam	u_int32_t base, iv, *intr;
484138568Ssam	int i, nreg, nintr, slot, rslot;
485138568Ssam
486138568Ssam	sdi = malloc(sizeof(*sdi), M_DEVBUF, M_ZERO | M_WAITOK);
487138568Ssam	if (ofw_bus_gen_setup_devinfo(&sdi->sdi_obdinfo, node) != 0) {
488138568Ssam		free(sdi, M_DEVBUF);
489138568Ssam		return (NULL);
490138568Ssam	}
491138568Ssam	resource_list_init(&sdi->sdi_rl);
492138568Ssam	slot = -1;
493138568Ssam	nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)&reg);
494138568Ssam	if (nreg == -1) {
495138568Ssam		if (sdi->sdi_obdinfo.obd_type == NULL ||
496138568Ssam		    strcmp(sdi->sdi_obdinfo.obd_type, "hierarchical") != 0) {
497138568Ssam			device_printf(dev, "<%s>: incomplete\n",
498138568Ssam			    sdi->sdi_obdinfo.obd_name);
499138568Ssam			goto fail;
500138568Ssam		}
501138568Ssam	} else {
502138568Ssam		for (i = 0; i < nreg; i++) {
503138568Ssam			base = reg[i].sbr_offset;
504178354Ssam			if (SBUS_ABS(base)) {
505178354Ssam				rslot = SBUS_ABS_TO_SLOT(base);
506178354Ssam				base = SBUS_ABS_TO_OFFSET(base);
507178354Ssam			} else
508178354Ssam				rslot = reg[i].sbr_slot;
509178354Ssam			if (slot != -1 && slot != rslot) {
510178354Ssam				device_printf(dev, "<%s>: multiple slots\n",
511178354Ssam				    sdi->sdi_obdinfo.obd_name);
512178354Ssam				free(reg, M_OFWPROP);
513178354Ssam				goto fail;
514178354Ssam			}
515178354Ssam			slot = rslot;
516178354Ssam
517178354Ssam			resource_list_add(&sdi->sdi_rl, SYS_RES_MEMORY, i,
518178354Ssam			    base, base + reg[i].sbr_size, reg[i].sbr_size);
519178354Ssam		}
520178354Ssam		free(reg, M_OFWPROP);
521178354Ssam	}
522178354Ssam	sdi->sdi_slot = slot;
523178354Ssam
524178354Ssam	/*
525178354Ssam	 * The `interrupts' property contains the SBus interrupt level.
526178354Ssam	 */
527178354Ssam	nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intr),
528178354Ssam	    (void **)&intr);
529178354Ssam	if (nintr != -1) {
530178354Ssam		for (i = 0; i < nintr; i++) {
531178354Ssam			iv = intr[i];
532178354Ssam			/*
533178354Ssam			 * SBus card devices need the slot number encoded into
534178354Ssam			 * the vector as this is generally not done.
535178354Ssam			 */
536178354Ssam			if ((iv & INTMAP_OBIO_MASK) == 0)
537178354Ssam				iv |= slot << 3;
538178354Ssam			/* Set the ign as appropriate. */
539178354Ssam			iv |= sc->sc_ign << INTMAP_IGN_SHIFT;
540178354Ssam			resource_list_add(&sdi->sdi_rl, SYS_RES_IRQ, i,
541178354Ssam			    iv, iv, 1);
542178354Ssam		}
543178354Ssam		free(intr, M_OFWPROP);
544178354Ssam	}
545178354Ssam	if (OF_getprop(node, "burst-sizes", &sdi->sdi_burstsz,
546178354Ssam	    sizeof(sdi->sdi_burstsz)) == -1)
547178354Ssam		sdi->sdi_burstsz = sc->sc_burst;
548138568Ssam	else
549138568Ssam		sdi->sdi_burstsz &= sc->sc_burst;
550138568Ssam	if (OF_getprop(node, "clock-frequency", &sdi->sdi_clockfreq,
551138568Ssam	    sizeof(sdi->sdi_clockfreq)) == -1)
552138568Ssam		sdi->sdi_clockfreq = sc->sc_clockfreq;
553138568Ssam
554138568Ssam	return (sdi);
555138568Ssam
556144302Ssamfail:
557178354Ssam	sbus_destroy_dinfo(sdi);
558178354Ssam	return (NULL);
559178354Ssam}
560178354Ssam
561178354Ssamstatic void
562178354Ssamsbus_destroy_dinfo(struct sbus_devinfo *dinfo)
563178354Ssam{
564178354Ssam
565138568Ssam	resource_list_free(&dinfo->sdi_rl);
566160690Ssam	ofw_bus_gen_destroy_devinfo(&dinfo->sdi_obdinfo);
567160690Ssam	free(dinfo, M_DEVBUF);
568160690Ssam}
569160690Ssam
570160690Ssamstatic int
571160690Ssamsbus_print_child(device_t dev, device_t child)
572160690Ssam{
573160690Ssam	int rv;
574160690Ssam
575160690Ssam	rv = bus_print_child_header(dev, child);
576160690Ssam	rv += sbus_print_res(device_get_ivars(child));
577160690Ssam	rv += bus_print_child_footer(dev, child);
578160690Ssam	return (rv);
579160690Ssam}
580160690Ssam
581160690Ssamstatic void
582160690Ssamsbus_probe_nomatch(device_t dev, device_t child)
583160690Ssam{
584160690Ssam	const char *type;
585160690Ssam
586160690Ssam	device_printf(dev, "<%s>", ofw_bus_get_name(child));
587160690Ssam	sbus_print_res(device_get_ivars(child));
588160690Ssam	type = ofw_bus_get_type(child);
589160690Ssam	printf(" type %s (no driver attached)\n",
590160690Ssam	    type != NULL ? type : "unknown");
591160690Ssam}
592160690Ssam
593160690Ssamstatic int
594160690Ssamsbus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
595160690Ssam{
596160690Ssam	struct sbus_softc *sc;
597160690Ssam	struct sbus_devinfo *dinfo;
598160690Ssam
599138568Ssam	sc = device_get_softc(dev);
600	if ((dinfo = device_get_ivars(child)) == NULL)
601		return (ENOENT);
602	switch (which) {
603	case SBUS_IVAR_BURSTSZ:
604		*result = dinfo->sdi_burstsz;
605		break;
606	case SBUS_IVAR_CLOCKFREQ:
607		*result = dinfo->sdi_clockfreq;
608		break;
609	case SBUS_IVAR_IGN:
610		*result = sc->sc_ign;
611		break;
612	case SBUS_IVAR_SLOT:
613		*result = dinfo->sdi_slot;
614		break;
615	default:
616		return (ENOENT);
617	}
618	return (0);
619}
620
621static struct resource_list *
622sbus_get_resource_list(device_t dev, device_t child)
623{
624	struct sbus_devinfo *sdi;
625
626	sdi = device_get_ivars(child);
627	return (&sdi->sdi_rl);
628}
629
630/* Write to the correct clr register, and call the actual handler. */
631static int
632sbus_filter_stub(void *arg)
633{
634	struct sbus_clr *scl;
635	int res;
636
637	scl = (struct sbus_clr *)arg;
638	if (scl->scl_filter != NULL) {
639		res = scl->scl_filter(scl->scl_arg);
640		SYSIO_WRITE8(scl->scl_sc, scl->scl_clr, 0);
641	} else
642		res = FILTER_SCHEDULE_THREAD;
643	return (res);
644}
645
646static void
647sbus_intr_stub(void *arg)
648{
649	struct sbus_clr *scl;
650
651	scl = (struct sbus_clr *)arg;
652	scl->scl_handler(scl->scl_arg);
653	if (scl->scl_filter == NULL)
654		SYSIO_WRITE8(scl->scl_sc, scl->scl_clr, 0);
655}
656
657static int
658sbus_setup_intr(device_t dev, device_t child, struct resource *ires, int flags,
659    driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep)
660{
661	struct sbus_softc *sc;
662	struct sbus_clr *scl;
663	bus_addr_t intrmapptr, intrclrptr, intrptr;
664	u_int64_t intrmap;
665	u_int32_t inr, slot;
666	int error, i;
667	long vec;
668
669	if (filt != NULL && intr != NULL)
670		return (EINVAL);
671	sc = device_get_softc(dev);
672	scl = (struct sbus_clr *)malloc(sizeof(*scl), M_DEVBUF, M_NOWAIT);
673	if (scl == NULL)
674		return (ENOMEM);
675	intrptr = intrmapptr = intrclrptr = 0;
676	intrmap = 0;
677	vec = rman_get_start(ires);
678	inr = INTVEC(vec);
679	if ((inr & INTMAP_OBIO_MASK) == 0) {
680		/*
681		 * We're in an SBus slot, register the map and clear
682		 * intr registers.
683		 */
684		slot = INTSLOT(vec);
685		intrmapptr = SBR_SLOT0_INT_MAP + slot * 8;
686		intrclrptr = SBR_SLOT0_INT_CLR +
687		    (slot * 8 * 8) + (INTPRI(vec) * 8);
688		/* Enable the interrupt, insert IGN. */
689		intrmap = inr | (sc->sc_ign << INTMAP_IGN_SHIFT);
690	} else {
691		intrptr = SBR_SCSI_INT_MAP;
692		/* Insert IGN */
693		inr |= sc->sc_ign << INTMAP_IGN_SHIFT;
694		for (i = 0; intrptr <= SBR_RESERVED_INT_MAP &&
695		    INTVEC(intrmap = SYSIO_READ8(sc, intrptr)) != inr;
696		    intrptr += 8, i++)
697			;
698		if (INTVEC(intrmap) == inr) {
699			/* Register the map and clear intr registers */
700			intrmapptr = intrptr;
701			intrclrptr = SBR_SCSI_INT_CLR + i * 8;
702			/* Enable the interrupt */
703		} else
704			panic("%s: IRQ not found!", __func__);
705	}
706
707	scl->scl_sc = sc;
708	scl->scl_arg = arg;
709	scl->scl_filter = filt;
710	scl->scl_handler = intr;
711	scl->scl_clr = intrclrptr;
712	/* Disable the interrupt while we fiddle with it */
713	SYSIO_WRITE8(sc, intrmapptr, intrmap & ~INTMAP_V);
714	error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags,
715	    sbus_filter_stub, sbus_intr_stub, scl, cookiep);
716	if (error != 0) {
717		free(scl, M_DEVBUF);
718		return (error);
719	}
720	scl->scl_cookie = *cookiep;
721	*cookiep = scl;
722
723	/*
724	 * Clear the interrupt, it might have been triggered before it was
725	 * set up.
726	 */
727	SYSIO_WRITE8(sc, intrclrptr, 0);
728	/*
729	 * Enable the interrupt and program the target module now we have the
730	 * handler installed.
731	 */
732	SYSIO_WRITE8(sc, intrmapptr, INTMAP_ENABLE(intrmap, PCPU_GET(mid)));
733	return (error);
734}
735
736static int
737sbus_teardown_intr(device_t dev, device_t child, struct resource *vec,
738    void *cookie)
739{
740	struct sbus_clr *scl;
741	int error;
742
743	scl = (struct sbus_clr *)cookie;
744	error = BUS_TEARDOWN_INTR(device_get_parent(dev), child, vec,
745	    scl->scl_cookie);
746	/*
747	 * Don't disable the interrupt for now, so that stray interrupts get
748	 * detected...
749	 */
750	if (error != 0)
751		free(scl, M_DEVBUF);
752	return (error);
753}
754
755static struct resource *
756sbus_alloc_resource(device_t bus, device_t child, int type, int *rid,
757    u_long start, u_long end, u_long count, u_int flags)
758{
759	struct sbus_softc *sc;
760	struct rman *rm;
761	struct resource *rv;
762	struct resource_list *rl;
763	struct resource_list_entry *rle;
764	device_t schild;
765	bus_space_handle_t bh;
766	bus_addr_t toffs;
767	bus_size_t tend;
768	int i, slot;
769	int isdefault, needactivate, passthrough;
770
771	isdefault = (start == 0UL && end == ~0UL);
772	needactivate = flags & RF_ACTIVE;
773	passthrough = (device_get_parent(child) != bus);
774	rle = NULL;
775	sc = device_get_softc(bus);
776	rl = BUS_GET_RESOURCE_LIST(bus, child);
777	switch (type) {
778	case SYS_RES_IRQ:
779		return (resource_list_alloc(rl, bus, child, type, rid, start,
780		    end, count, flags));
781	case SYS_RES_MEMORY:
782		if (!passthrough) {
783			rle = resource_list_find(rl, type, *rid);
784			if (rle == NULL)
785				return (NULL);
786			if (rle->res != NULL)
787				panic("%s: resource entry is busy", __func__);
788			if (isdefault) {
789				start = rle->start;
790				count = ulmax(count, rle->count);
791				end = ulmax(rle->end, start + count - 1);
792			}
793		}
794		rm = NULL;
795		bh = toffs = tend = 0;
796		schild = child;
797		while (device_get_parent(schild) != bus)
798			schild = device_get_parent(child);
799		slot = sbus_get_slot(schild);
800		for (i = 0; i < sc->sc_nrange; i++) {
801			if (sc->sc_rd[i].rd_slot != slot ||
802			    start < sc->sc_rd[i].rd_coffset ||
803			    start > sc->sc_rd[i].rd_cend)
804				continue;
805			/* Disallow cross-range allocations. */
806			if (end > sc->sc_rd[i].rd_cend)
807				return (NULL);
808			/* We've found the connection to the parent bus */
809			toffs = start - sc->sc_rd[i].rd_coffset;
810			tend = end - sc->sc_rd[i].rd_coffset;
811			rm = &sc->sc_rd[i].rd_rman;
812			bh = sc->sc_rd[i].rd_bushandle;
813			break;
814		}
815		if (rm == NULL)
816			return (NULL);
817		flags &= ~RF_ACTIVE;
818		rv = rman_reserve_resource(rm, toffs, tend, count, flags,
819		    child);
820		if (rv == NULL)
821			return (NULL);
822		rman_set_rid(rv, *rid);
823		rman_set_bustag(rv, sc->sc_cbustag);
824		rman_set_bushandle(rv, bh + rman_get_start(rv));
825		if (needactivate) {
826			if (bus_activate_resource(child, type, *rid, rv)) {
827				rman_release_resource(rv);
828				return (NULL);
829			}
830		}
831		if (!passthrough)
832			rle->res = rv;
833		return (rv);
834	default:
835		return (NULL);
836	}
837}
838
839static int
840sbus_activate_resource(device_t bus, device_t child, int type, int rid,
841    struct resource *r)
842{
843	void *p;
844	int error;
845
846	if (type == SYS_RES_IRQ) {
847		return (BUS_ACTIVATE_RESOURCE(device_get_parent(bus),
848		    child, type, rid, r));
849	}
850	if (type == SYS_RES_MEMORY) {
851		/*
852		 * Need to memory-map the device space, as some drivers depend
853		 * on the virtual address being set and useable.
854		 */
855		error = sparc64_bus_mem_map(rman_get_bustag(r),
856		    rman_get_bushandle(r), rman_get_size(r), 0, 0, &p);
857		if (error != 0)
858			return (error);
859		rman_set_virtual(r, p);
860	}
861	return (rman_activate_resource(r));
862}
863
864static int
865sbus_deactivate_resource(device_t bus, device_t child, int type, int rid,
866    struct resource *r)
867{
868
869	if (type == SYS_RES_IRQ) {
870		return (BUS_DEACTIVATE_RESOURCE(device_get_parent(bus),
871		    child, type, rid, r));
872	}
873	if (type == SYS_RES_MEMORY) {
874		sparc64_bus_mem_unmap(rman_get_virtual(r), rman_get_size(r));
875		rman_set_virtual(r, NULL);
876	}
877	return (rman_deactivate_resource(r));
878}
879
880static int
881sbus_release_resource(device_t bus, device_t child, int type, int rid,
882    struct resource *r)
883{
884	struct resource_list *rl;
885	struct resource_list_entry *rle;
886	int error, passthrough;
887
888	passthrough = (device_get_parent(child) != bus);
889	rl = BUS_GET_RESOURCE_LIST(bus, child);
890	if (type == SYS_RES_IRQ)
891		return (resource_list_release(rl, bus, child, type, rid, r));
892	if ((rman_get_flags(r) & RF_ACTIVE) != 0) {
893		error = bus_deactivate_resource(child, type, rid, r);
894		if (error != 0)
895			return (error);
896	}
897	error = rman_release_resource(r);
898	if (error != 0 || passthrough)
899		return (error);
900	rle = resource_list_find(rl, type, rid);
901	if (rle == NULL)
902		panic("%s: cannot find resource", __func__);
903	if (rle->res == NULL)
904		panic("%s: resource entry is not busy", __func__);
905	rle->res = NULL;
906	return (0);
907}
908
909static bus_dma_tag_t
910sbus_get_dma_tag(device_t bus, device_t child)
911{
912	struct sbus_softc *sc;
913
914	sc = device_get_softc(bus);
915	return (sc->sc_cdmatag);
916}
917
918static const struct ofw_bus_devinfo *
919sbus_get_devinfo(device_t bus, device_t child)
920{
921	struct sbus_devinfo *sdi;
922
923	sdi = device_get_ivars(child);
924	return (&sdi->sdi_obdinfo);
925}
926
927/*
928 * Handle an overtemp situation.
929 *
930 * SPARCs have temperature sensors which generate interrupts
931 * if the machine's temperature exceeds a certain threshold.
932 * This handles the interrupt and powers off the machine.
933 * The same needs to be done to PCI controller drivers.
934 */
935static int
936sbus_overtemp(void *arg)
937{
938
939	printf("DANGER: OVER TEMPERATURE detected\nShutting down NOW.\n");
940	shutdown_nice(RB_POWEROFF);
941	return (FILTER_HANDLED);
942}
943
944/* Try to shut down in time in case of power failure. */
945static int
946sbus_pwrfail(void *arg)
947{
948
949	printf("Power failure detected\nShutting down NOW.\n");
950	shutdown_nice(0);
951	return (FILTER_HANDLED);
952}
953
954static bus_space_tag_t
955sbus_alloc_bustag(struct sbus_softc *sc)
956{
957	bus_space_tag_t sbt;
958
959	sbt = (bus_space_tag_t)malloc(sizeof(struct bus_space_tag), M_DEVBUF,
960	    M_NOWAIT | M_ZERO);
961	if (sbt == NULL)
962		panic("%s: out of memory", __func__);
963
964	sbt->bst_cookie = sc;
965	sbt->bst_parent = sc->sc_bustag;
966	sbt->bst_type = SBUS_BUS_SPACE;
967	return (sbt);
968}
969
970static int
971sbus_print_res(struct sbus_devinfo *sdi)
972{
973	int rv;
974
975	rv = 0;
976	rv += resource_list_print_type(&sdi->sdi_rl, "mem", SYS_RES_MEMORY,
977	    "%#lx");
978	rv += resource_list_print_type(&sdi->sdi_rl, "irq", SYS_RES_IRQ,
979	    "%ld");
980	return (rv);
981}
982