sbus.c revision 119338
1/*-
2 * Copyright (c) 1998 The NetBSD Foundation, Inc.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to The NetBSD Foundation
6 * by Paul Kranenburg.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *        This product includes software developed by the NetBSD
19 *        Foundation, Inc. and its contributors.
20 * 4. Neither the name of The NetBSD Foundation nor the names of its
21 *    contributors may be used to endorse or promote products derived
22 *    from this software without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
27 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34 * POSSIBILITY OF SUCH DAMAGE.
35 */
36/*
37 * Copyright (c) 1992, 1993
38 *	The Regents of the University of California.  All rights reserved.
39 *
40 * This software was developed by the Computer Systems Engineering group
41 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
42 * contributed to Berkeley.
43 *
44 * All advertising materials mentioning features or use of this software
45 * must display the following acknowledgement:
46 *	This product includes software developed by the University of
47 *	California, Lawrence Berkeley Laboratory.
48 *
49 * Redistribution and use in source and binary forms, with or without
50 * modification, are permitted provided that the following conditions
51 * are met:
52 * 1. Redistributions of source code must retain the above copyright
53 *    notice, this list of conditions and the following disclaimer.
54 * 2. Redistributions in binary form must reproduce the above copyright
55 *    notice, this list of conditions and the following disclaimer in the
56 *    documentation and/or other materials provided with the distribution.
57 * 3. All advertising materials mentioning features or use of this software
58 *    must display the following acknowledgement:
59 *	This product includes software developed by the University of
60 *	California, Berkeley and its contributors.
61 * 4. Neither the name of the University nor the names of its contributors
62 *    may be used to endorse or promote products derived from this software
63 *    without specific prior written permission.
64 *
65 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
66 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
67 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
68 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
69 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
70 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
71 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
72 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
73 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
74 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
75 * SUCH DAMAGE.
76 */
77/*
78 * Copyright (c) 1999 Eduardo Horvath
79 * Copyright (c) 2002 by Thomas Moestl <tmm@FreeBSD.org>.
80 * All rights reserved.
81 *
82 * Redistribution and use in source and binary forms, with or without
83 * modification, are permitted provided that the following conditions
84 * are met:
85 * 1. Redistributions of source code must retain the above copyright
86 *    notice, this list of conditions and the following disclaimer.
87 *
88 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR  ``AS IS'' AND
89 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
90 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
91 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR  BE LIABLE
92 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
93 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
94 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
95 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
96 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
97 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
98 * SUCH DAMAGE.
99 *
100 *	from: @(#)sbus.c	8.1 (Berkeley) 6/11/93
101 *	from: NetBSD: sbus.c,v 1.46 2001/10/07 20:30:41 eeh Exp
102 *
103 * $FreeBSD: head/sys/sparc64/sbus/sbus.c 119338 2003-08-23 00:11:16Z imp $
104 */
105
106/*
107 * Sbus support.
108 */
109#include <sys/param.h>
110#include <sys/systm.h>
111#include <sys/bus.h>
112#include <sys/kernel.h>
113#include <sys/malloc.h>
114#include <sys/pcpu.h>
115#include <sys/reboot.h>
116
117#include <dev/ofw/openfirm.h>
118
119#include <machine/bus.h>
120#include <machine/bus_private.h>
121#include <machine/iommureg.h>
122#include <machine/bus_common.h>
123#include <machine/frame.h>
124#include <machine/intr_machdep.h>
125#include <machine/nexusvar.h>
126#include <machine/ofw_upa.h>
127#include <machine/resource.h>
128
129#include <sys/rman.h>
130
131#include <machine/iommuvar.h>
132
133#include <sparc64/sbus/ofw_sbus.h>
134#include <sparc64/sbus/sbusreg.h>
135#include <sparc64/sbus/sbusvar.h>
136
137
138#ifdef DEBUG
139#define SDB_DVMA	0x1
140#define SDB_INTR	0x2
141int sbus_debug = 0;
142#define DPRINTF(l, s)   do { if (sbus_debug & l) printf s; } while (0)
143#else
144#define DPRINTF(l, s)
145#endif
146
147struct sbus_devinfo {
148	int			sdi_burstsz;
149	char			*sdi_compat;
150	char			*sdi_name;	/* PROM name */
151	phandle_t		sdi_node;	/* PROM node */
152	int			sdi_slot;
153	char			*sdi_type;	/* PROM name */
154
155	struct resource_list	sdi_rl;
156};
157
158/* Range descriptor, allocated for each sc_range. */
159struct sbus_rd {
160	bus_addr_t		rd_poffset;
161	bus_addr_t		rd_pend;
162	int			rd_slot;
163	bus_addr_t		rd_coffset;
164	bus_addr_t		rd_cend;
165	struct rman		rd_rman;
166	bus_space_handle_t	rd_bushandle;
167	struct resource		*rd_res;
168};
169
170struct sbus_softc {
171	bus_space_tag_t		sc_bustag;
172	bus_space_handle_t	sc_bushandle;
173	bus_dma_tag_t		sc_dmatag;
174	bus_dma_tag_t		sc_cdmatag;
175	bus_space_tag_t		sc_cbustag;
176	int			sc_clockfreq;	/* clock frequency (in Hz) */
177	struct upa_regs		*sc_reg;
178	int			sc_nreg;
179	int			sc_nrange;
180	struct sbus_rd		*sc_rd;
181	int			sc_burst;	/* burst transfer sizes supported */
182	int			*sc_intr_compat;/* `intr' property to sbus compat */
183
184	struct resource		*sc_sysio_res;
185	int			sc_ign;		/* Interrupt group number for this sysio */
186	struct iommu_state	sc_is;		/* IOMMU state, see iommureg.h */
187
188	struct resource		*sc_ot_ires;
189	void			*sc_ot_ihand;
190	struct resource		*sc_pf_ires;
191	void			*sc_pf_ihand;
192};
193
194struct sbus_clr {
195	struct sbus_softc	*scl_sc;
196	bus_addr_t	scl_clr;		/* clear register */
197	driver_intr_t	*scl_handler;		/* handler to call */
198	void		*scl_arg;		/* argument for the handler */
199	void		*scl_cookie;		/* interrupt cookie of parent bus */
200};
201
202#define	SYSIO_READ8(sc, off) \
203	bus_space_read_8((sc)->sc_bustag, (sc)->sc_bushandle, (off))
204#define	SYSIO_WRITE8(sc, off, v) \
205	bus_space_write_8((sc)->sc_bustag, (sc)->sc_bushandle, (off), (v))
206
207static int sbus_probe(device_t dev);
208static int sbus_print_child(device_t dev, device_t child);
209static void sbus_probe_nomatch(device_t dev, device_t child);
210static int sbus_read_ivar(device_t, device_t, int, u_long *);
211static struct resource_list *sbus_get_resource_list(device_t dev,
212    device_t child);
213static int sbus_setup_intr(device_t, device_t, struct resource *, int,
214    driver_intr_t *, void *, void **);
215static int sbus_teardown_intr(device_t, device_t, struct resource *, void *);
216static struct resource *sbus_alloc_resource(device_t, device_t, int, int *,
217    u_long, u_long, u_long, u_int);
218static int sbus_activate_resource(device_t, device_t, int, int,
219    struct resource *);
220static int sbus_deactivate_resource(device_t, device_t, int, int,
221    struct resource *);
222static int sbus_release_resource(device_t, device_t, int, int,
223    struct resource *);
224
225static struct sbus_devinfo * sbus_setup_dinfo(struct sbus_softc *sc,
226    phandle_t node, char *name);
227static void sbus_destroy_dinfo(struct sbus_devinfo *dinfo);
228static void sbus_intr_stub(void *);
229static bus_space_tag_t sbus_alloc_bustag(struct sbus_softc *);
230static void sbus_overtemp(void *);
231static void sbus_pwrfail(void *);
232
233static device_method_t sbus_methods[] = {
234	/* Device interface */
235	DEVMETHOD(device_probe,		sbus_probe),
236	DEVMETHOD(device_attach,	bus_generic_attach),
237
238	/* Bus interface */
239	DEVMETHOD(bus_print_child,	sbus_print_child),
240	DEVMETHOD(bus_probe_nomatch,	sbus_probe_nomatch),
241	DEVMETHOD(bus_read_ivar,	sbus_read_ivar),
242	DEVMETHOD(bus_setup_intr, 	sbus_setup_intr),
243	DEVMETHOD(bus_teardown_intr,	sbus_teardown_intr),
244	DEVMETHOD(bus_alloc_resource,	sbus_alloc_resource),
245	DEVMETHOD(bus_activate_resource,	sbus_activate_resource),
246	DEVMETHOD(bus_deactivate_resource,	sbus_deactivate_resource),
247	DEVMETHOD(bus_release_resource,	sbus_release_resource),
248	DEVMETHOD(bus_get_resource_list, sbus_get_resource_list),
249	DEVMETHOD(bus_get_resource,	bus_generic_rl_get_resource),
250
251	{ 0, 0 }
252};
253
254static driver_t sbus_driver = {
255	"sbus",
256	sbus_methods,
257	sizeof(struct sbus_softc),
258};
259
260static devclass_t sbus_devclass;
261
262DRIVER_MODULE(sbus, nexus, sbus_driver, sbus_devclass, 0, 0);
263
264#define	OFW_SBUS_TYPE	"sbus"
265#define	OFW_SBUS_NAME	"sbus"
266
267static int
268sbus_probe(device_t dev)
269{
270	struct sbus_softc *sc = device_get_softc(dev);
271	struct sbus_devinfo *sdi;
272	struct sbus_ranges *range;
273	struct resource *res;
274	device_t cdev;
275	bus_addr_t phys;
276	bus_size_t size;
277	char *name, *cname, *t;
278	phandle_t child, node = nexus_get_node(dev);
279	u_int64_t mr;
280	int intr, clock, rid, vec, i;
281
282	t = nexus_get_device_type(dev);
283	if (((t == NULL || strcmp(t, OFW_SBUS_TYPE) != 0)) &&
284	    strcmp(nexus_get_name(dev), OFW_SBUS_NAME) != 0)
285		return (ENXIO);
286	device_set_desc(dev, "U2S UPA-SBus bridge");
287
288	if ((sc->sc_nreg = OF_getprop_alloc(node, "reg", sizeof(*sc->sc_reg),
289	    (void **)&sc->sc_reg)) == -1) {
290		panic("sbus_probe: error getting reg property");
291	}
292	if (sc->sc_nreg < 1)
293		panic("sbus_probe: bogus properties");
294	phys = UPA_REG_PHYS(&sc->sc_reg[0]);
295	size = UPA_REG_SIZE(&sc->sc_reg[0]);
296	rid = 0;
297	sc->sc_sysio_res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, phys,
298	    phys + size - 1, size, RF_ACTIVE);
299	if (sc->sc_sysio_res == NULL ||
300	    rman_get_start(sc->sc_sysio_res) != phys)
301		panic("sbus_probe: can't allocate device memory");
302	sc->sc_bustag = rman_get_bustag(sc->sc_sysio_res);
303	sc->sc_bushandle = rman_get_bushandle(sc->sc_sysio_res);
304
305	if (OF_getprop(node, "interrupts", &intr, sizeof(intr)) == -1)
306		panic("sbus_probe: cannot get IGN");
307	sc->sc_ign = intr & INTMAP_IGN_MASK;	/* Find interrupt group no */
308	sc->sc_cbustag = sbus_alloc_bustag(sc);
309
310	/*
311	 * Record clock frequency for synchronous SCSI.
312	 * IS THIS THE CORRECT DEFAULT??
313	 */
314	if (OF_getprop(node, "clock-frequency", &clock, sizeof(clock)) == -1)
315		clock = 25000000;
316	sc->sc_clockfreq = clock;
317	clock /= 1000;
318	device_printf(dev, "clock %d.%03d MHz\n", clock / 1000, clock % 1000);
319
320	/*
321	 * Collect address translations from the OBP.
322	 */
323	if ((sc->sc_nrange = OF_getprop_alloc(node, "ranges",
324	    sizeof(*range), (void **)&range)) == -1) {
325		panic("%s: error getting ranges property",
326		    device_get_name(dev));
327	}
328	sc->sc_rd = (struct sbus_rd *)malloc(sizeof(*sc->sc_rd) * sc->sc_nrange,
329	    M_DEVBUF, M_NOWAIT);
330	if (sc->sc_rd == NULL)
331		panic("sbus_probe: could not allocate rmans");
332	/*
333	 * Preallocate all space that the SBus bridge decodes, so that nothing
334	 * else gets in the way; set up rmans etc.
335	 */
336	for (i = 0; i < sc->sc_nrange; i++) {
337		phys = range[i].poffset | ((bus_addr_t)range[i].pspace << 32);
338		size = range[i].size;
339		sc->sc_rd[i].rd_slot = range[i].cspace;
340		sc->sc_rd[i].rd_coffset = range[i].coffset;
341		sc->sc_rd[i].rd_cend = sc->sc_rd[i].rd_coffset + size;
342		rid = 0;
343		if ((res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid, phys,
344		    phys + size - 1, size, RF_ACTIVE)) == NULL)
345			panic("sbus_probe: could not allocate decoded range");
346		sc->sc_rd[i].rd_bushandle = rman_get_bushandle(res);
347		sc->sc_rd[i].rd_rman.rm_type = RMAN_ARRAY;
348		sc->sc_rd[i].rd_rman.rm_descr = "SBus Device Memory";
349		if (rman_init(&sc->sc_rd[i].rd_rman) != 0 ||
350		    rman_manage_region(&sc->sc_rd[i].rd_rman, 0, size) != 0)
351			panic("sbus_probe: failed to set up memory rman");
352		sc->sc_rd[i].rd_poffset = phys;
353		sc->sc_rd[i].rd_pend = phys + size;
354		sc->sc_rd[i].rd_res = res;
355	}
356	free(range, M_OFWPROP);
357
358	/*
359	 * Get the SBus burst transfer size if burst transfers are supported.
360	 * XXX: is the default correct?
361	 */
362	if (OF_getprop(node, "burst-sizes", &sc->sc_burst,
363	    sizeof(sc->sc_burst)) == -1 || sc->sc_burst == 0)
364		sc->sc_burst = SBUS_BURST_DEF;
365
366	/* initalise the IOMMU */
367
368	/* punch in our copies */
369	sc->sc_is.is_bustag = sc->sc_bustag;
370	sc->sc_is.is_bushandle = sc->sc_bushandle;
371	sc->sc_is.is_iommu = SBR_IOMMU;
372	sc->sc_is.is_dtag = SBR_IOMMU_TLB_TAG_DIAG;
373	sc->sc_is.is_ddram = SBR_IOMMU_TLB_DATA_DIAG;
374	sc->sc_is.is_dqueue = SBR_IOMMU_QUEUE_DIAG;
375	sc->sc_is.is_dva = SBR_IOMMU_SVADIAG;
376	sc->sc_is.is_dtcmp = 0;
377	sc->sc_is.is_sb[0] = SBR_STRBUF;
378	sc->sc_is.is_sb[1] = NULL;
379
380	/* give us a nice name.. */
381	name = (char *)malloc(32, M_DEVBUF, M_NOWAIT);
382	if (name == 0)
383		panic("sbus_probe: couldn't malloc iommu name");
384	snprintf(name, 32, "%s dvma", device_get_name(dev));
385
386	/*
387	 * Note: the SBus IOMMU ignores the high bits of an address, so a NULL
388	 * DMA pointer will be translated by the first page of the IOTSB.
389	 * To detect bugs we'll allocate and ignore the first entry.
390	 */
391	iommu_init(name, &sc->sc_is, 3, -1, 1);
392
393	/* Create the DMA tag. */
394	sc->sc_dmatag = nexus_get_dmatag(dev);
395	if (bus_dma_tag_create(sc->sc_dmatag, 8, 1, 0, 0x3ffffffff, NULL, NULL,
396	    0x3ffffffff, 0xff, 0xffffffff, 0, NULL, NULL, &sc->sc_cdmatag) != 0)
397		panic("bus_dma_tag_create failed");
398	/* Customize the tag. */
399	sc->sc_cdmatag->dt_cookie = &sc->sc_is;
400	sc->sc_cdmatag->dt_mt = &iommu_dma_methods;
401	/* XXX: register as root dma tag (kludge). */
402	sparc64_root_dma_tag = sc->sc_cdmatag;
403
404	/* Enable the over-temperature and power-fail intrrupts. */
405	rid = 0;
406	mr = SYSIO_READ8(sc, SBR_THERM_INT_MAP);
407	vec = INTVEC(mr);
408	if ((sc->sc_ot_ires = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, vec,
409	    vec, 1, RF_ACTIVE)) == NULL)
410		panic("sbus_probe: failed to get temperature interrupt");
411	bus_setup_intr(dev, sc->sc_ot_ires, INTR_TYPE_MISC | INTR_FAST,
412	    sbus_overtemp, sc, &sc->sc_ot_ihand);
413	SYSIO_WRITE8(sc, SBR_THERM_INT_MAP, INTMAP_ENABLE(mr, PCPU_GET(mid)));
414	rid = 0;
415	mr = SYSIO_READ8(sc, SBR_POWER_INT_MAP);
416	vec = INTVEC(mr);
417	if ((sc->sc_pf_ires = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, vec,
418	    vec, 1, RF_ACTIVE)) == NULL)
419		panic("sbus_probe: failed to get power fail interrupt");
420	bus_setup_intr(dev, sc->sc_pf_ires, INTR_TYPE_MISC | INTR_FAST,
421	    sbus_pwrfail, sc, &sc->sc_pf_ihand);
422	SYSIO_WRITE8(sc, SBR_POWER_INT_MAP, INTMAP_ENABLE(mr, PCPU_GET(mid)));
423
424	/* Initialize the counter-timer. */
425	sparc64_counter_init(sc->sc_bustag, sc->sc_bushandle, SBR_TC0);
426
427	/*
428	 * Loop through ROM children, fixing any relative addresses
429	 * and then configuring each device.
430	 * `specials' is an array of device names that are treated
431	 * specially:
432	 */
433	for (child = OF_child(node); child != 0; child = OF_peer(child)) {
434		if ((OF_getprop_alloc(child, "name", 1, (void **)&cname)) == -1)
435			continue;
436
437		if ((sdi = sbus_setup_dinfo(sc, child, cname)) == NULL) {
438			device_printf(dev, "<%s>: incomplete\n", cname);
439			free(cname, M_OFWPROP);
440			continue;
441		}
442		if ((cdev = device_add_child(dev, NULL, -1)) == NULL)
443			panic("sbus_probe: device_add_child failed");
444		device_set_ivars(cdev, sdi);
445	}
446	return (0);
447}
448
449static struct sbus_devinfo *
450sbus_setup_dinfo(struct sbus_softc *sc, phandle_t node, char *name)
451{
452	struct sbus_devinfo *sdi;
453	struct sbus_regs *reg;
454	u_int32_t base, iv, *intr;
455	int i, nreg, nintr, slot, rslot;
456
457	sdi = malloc(sizeof(*sdi), M_DEVBUF, M_ZERO | M_WAITOK);
458	if (sdi == NULL)
459		return (NULL);
460	resource_list_init(&sdi->sdi_rl);
461	sdi->sdi_name = name;
462	sdi->sdi_node = node;
463	OF_getprop_alloc(node, "compat", 1, (void **)&sdi->sdi_compat);
464	OF_getprop_alloc(node, "device_type", 1, (void **)&sdi->sdi_type);
465	slot = -1;
466	nreg = OF_getprop_alloc(node, "reg", sizeof(*reg), (void **)&reg);
467	if (nreg == -1) {
468		if (sdi->sdi_type == NULL ||
469		    strcmp(sdi->sdi_type, "hierarchical") != 0) {
470			sbus_destroy_dinfo(sdi);
471			return (NULL);
472		}
473	} else {
474		for (i = 0; i < nreg; i++) {
475			base = reg[i].sbr_offset;
476			if (SBUS_ABS(base)) {
477				rslot = SBUS_ABS_TO_SLOT(base);
478				base = SBUS_ABS_TO_OFFSET(base);
479			} else
480				rslot = reg[i].sbr_slot;
481			if (slot != -1 && slot != rslot)
482				panic("sbus_setup_dinfo: multiple slots");
483			slot = rslot;
484
485			resource_list_add(&sdi->sdi_rl, SYS_RES_MEMORY, i,
486			    base, base + reg[i].sbr_size, reg[i].sbr_size);
487		}
488		free(reg, M_OFWPROP);
489	}
490	sdi->sdi_slot = slot;
491
492	/*
493	 * The `interrupts' property contains the Sbus interrupt level.
494	 */
495	nintr = OF_getprop_alloc(node, "interrupts", sizeof(*intr), (void **)&intr);
496	if (nintr != -1) {
497		for (i = 0; i < nintr; i++) {
498			iv = intr[i];
499			/*
500			 * Sbus card devices need the slot number encoded into
501			 * the vector as this is generally not done.
502			 */
503			if ((iv & INTMAP_OBIO_MASK) == 0)
504				iv |= slot << 3;
505			/* Set the ign as appropriate. */
506			iv |= sc->sc_ign;
507			resource_list_add(&sdi->sdi_rl, SYS_RES_IRQ, i,
508			    iv, iv, 1);
509		}
510		free(intr, M_OFWPROP);
511	}
512	if (OF_getprop(node, "burst-sizes", &sdi->sdi_burstsz,
513	    sizeof(sdi->sdi_burstsz)) == -1)
514		sdi->sdi_burstsz = sc->sc_burst;
515	else
516		sdi->sdi_burstsz &= sc->sc_burst;
517
518	return (sdi);
519}
520
521/* Free everything except sdi_name, which is handled separately. */
522static void
523sbus_destroy_dinfo(struct sbus_devinfo *dinfo)
524{
525
526	resource_list_free(&dinfo->sdi_rl);
527	if (dinfo->sdi_compat != NULL)
528		free(dinfo->sdi_compat, M_OFWPROP);
529	if (dinfo->sdi_type != NULL)
530		free(dinfo->sdi_type, M_OFWPROP);
531	free(dinfo, M_DEVBUF);
532}
533
534static int
535sbus_print_child(device_t dev, device_t child)
536{
537	struct sbus_devinfo *dinfo;
538	struct resource_list *rl;
539	int rv;
540
541	dinfo = device_get_ivars(child);
542	rl = &dinfo->sdi_rl;
543	rv = bus_print_child_header(dev, child);
544	rv += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx");
545	rv += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld");
546	rv += bus_print_child_footer(dev, child);
547	return (rv);
548}
549
550static void
551sbus_probe_nomatch(device_t dev, device_t child)
552{
553	char *name;
554	char *type;
555
556	if (BUS_READ_IVAR(dev, child, SBUS_IVAR_NAME,
557	    (uintptr_t *)&name) != 0 ||
558	    BUS_READ_IVAR(dev, child, SBUS_IVAR_DEVICE_TYPE,
559	    (uintptr_t *)&type) != 0)
560		return;
561
562	if (type == NULL)
563		type = "(unknown)";
564	device_printf(dev, "<%s>, type %s (no driver attached)\n",
565	    name, type);
566}
567
568static int
569sbus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
570{
571	struct sbus_softc *sc = device_get_softc(dev);
572	struct sbus_devinfo *dinfo;
573
574	if ((dinfo = device_get_ivars(child)) == NULL)
575		return (ENOENT);
576	switch (which) {
577	case SBUS_IVAR_BURSTSZ:
578		*result = dinfo->sdi_burstsz;
579		break;
580	case SBUS_IVAR_CLOCKFREQ:
581		*result = sc->sc_clockfreq;
582		break;
583	case SBUS_IVAR_COMPAT:
584		*result = (uintptr_t)dinfo->sdi_compat;
585		break;
586	case SBUS_IVAR_NAME:
587		*result = (uintptr_t)dinfo->sdi_name;
588		break;
589	case SBUS_IVAR_NODE:
590		*result = dinfo->sdi_node;
591		break;
592	case SBUS_IVAR_SLOT:
593		*result = dinfo->sdi_slot;
594		break;
595	case SBUS_IVAR_DEVICE_TYPE:
596		*result = (uintptr_t)dinfo->sdi_type;
597		break;
598	default:
599		return (ENOENT);
600	}
601	return 0;
602}
603
604static struct resource_list *
605sbus_get_resource_list(device_t dev, device_t child)
606{
607	struct sbus_devinfo *sdi;
608
609	sdi = device_get_ivars(child);
610	return (&sdi->sdi_rl);
611}
612
613/* Write to the correct clr register, and call the actual handler. */
614static void
615sbus_intr_stub(void *arg)
616{
617	struct sbus_clr *scl;
618
619	scl = (struct sbus_clr *)arg;
620	scl->scl_handler(scl->scl_arg);
621	SYSIO_WRITE8(scl->scl_sc, scl->scl_clr, 0);
622}
623
624static int
625sbus_setup_intr(device_t dev, device_t child,
626    struct resource *ires,  int flags, driver_intr_t *intr, void *arg,
627    void **cookiep)
628{
629	struct sbus_softc *sc;
630	struct sbus_clr *scl;
631	bus_addr_t intrmapptr, intrclrptr, intrptr;
632	u_int64_t intrmap;
633	u_int32_t inr, slot;
634	int error, i;
635	long vec = rman_get_start(ires);
636
637	sc = (struct sbus_softc *)device_get_softc(dev);
638	scl = (struct sbus_clr *)malloc(sizeof(*scl), M_DEVBUF, M_NOWAIT);
639	if (scl == NULL)
640		return (NULL);
641	intrptr = intrmapptr = intrclrptr = 0;
642	intrmap = 0;
643	inr = INTVEC(vec);
644	if ((inr & INTMAP_OBIO_MASK) == 0) {
645		/*
646		 * We're in an SBUS slot, register the map and clear
647		 * intr registers.
648		 */
649		slot = INTSLOT(vec);
650		intrmapptr = SBR_SLOT0_INT_MAP + slot * 8;
651		intrclrptr = SBR_SLOT0_INT_CLR +
652		    (slot * 8 * 8) + (INTPRI(vec) * 8);
653		/* Enable the interrupt, insert IGN. */
654		intrmap = inr | sc->sc_ign;
655	} else {
656		intrptr = SBR_SCSI_INT_MAP;
657		/* Insert IGN */
658		inr |= sc->sc_ign;
659		for (i = 0; intrptr <= SBR_RESERVED_INT_MAP &&
660			 INTVEC(intrmap = SYSIO_READ8(sc, intrptr)) !=
661			 INTVEC(inr); intrptr += 8, i++)
662			;
663		if (INTVEC(intrmap) == INTVEC(inr)) {
664			/* Register the map and clear intr registers */
665			intrmapptr = intrptr;
666			intrclrptr = SBR_SCSI_INT_CLR + i * 8;
667			/* Enable the interrupt */
668		} else
669			panic("sbus_setup_intr: IRQ not found!");
670	}
671
672	scl->scl_sc = sc;
673	scl->scl_arg = arg;
674	scl->scl_handler = intr;
675	scl->scl_clr = intrclrptr;
676	/* Disable the interrupt while we fiddle with it */
677	SYSIO_WRITE8(sc, intrmapptr, intrmap);
678	error = BUS_SETUP_INTR(device_get_parent(dev), child, ires, flags,
679	    sbus_intr_stub, scl, cookiep);
680	if (error != 0) {
681		free(scl, M_DEVBUF);
682		return (error);
683	}
684	scl->scl_cookie = *cookiep;
685	*cookiep = scl;
686
687	/*
688	 * Clear the interrupt, it might have been triggered before it was
689	 * set up.
690	 */
691	SYSIO_WRITE8(sc, intrclrptr, 0);
692	/*
693	 * Enable the interrupt and program the target module now we have the
694	 * handler installed.
695	 */
696	SYSIO_WRITE8(sc, intrmapptr, INTMAP_ENABLE(intrmap, PCPU_GET(mid)));
697	return (error);
698}
699
700static int
701sbus_teardown_intr(device_t dev, device_t child,
702    struct resource *vec, void *cookie)
703{
704	struct sbus_clr *scl;
705	int error;
706
707	scl = (struct sbus_clr *)cookie;
708	error = BUS_TEARDOWN_INTR(device_get_parent(dev), child, vec,
709	    scl->scl_cookie);
710	/*
711	 * Don't disable the interrupt for now, so that stray interupts get
712	 * detected...
713	 */
714	if (error != 0)
715		free(scl, M_DEVBUF);
716	return (error);
717}
718
719/*
720 * There is no need to handle pass-throughs here; there are no bridges to
721 * SBuses.
722 */
723static struct resource *
724sbus_alloc_resource(device_t bus, device_t child, int type, int *rid,
725    u_long start, u_long end, u_long count, u_int flags)
726{
727	struct sbus_softc *sc;
728	struct sbus_devinfo *sdi;
729	struct rman *rm;
730	struct resource *rv;
731	struct resource_list *rl;
732	struct resource_list_entry *rle;
733	bus_space_handle_t bh;
734	bus_addr_t toffs;
735	bus_size_t tend;
736	int i;
737	int isdefault = (start == 0UL && end == ~0UL);
738	int needactivate = flags & RF_ACTIVE;
739
740	sc = (struct sbus_softc *)device_get_softc(bus);
741	sdi = device_get_ivars(child);
742	rl = &sdi->sdi_rl;
743	rle = resource_list_find(rl, type, *rid);
744	if (rle == NULL)
745		return (NULL);
746	if (rle->res != NULL)
747		panic("sbus_alloc_resource: resource entry is busy");
748	if (isdefault) {
749		start = rle->start;
750		count = ulmax(count, rle->count);
751		end = ulmax(rle->end, start + count - 1);
752	}
753	switch (type) {
754	case SYS_RES_IRQ:
755		rv = BUS_ALLOC_RESOURCE(device_get_parent(bus), child, type,
756		    rid, start, end, count, flags);
757		if (rv == NULL)
758			return (NULL);
759		break;
760	case SYS_RES_MEMORY:
761		rm = NULL;
762		bh = toffs = tend = 0;
763		for (i = 0; i < sc->sc_nrange; i++) {
764			if (sc->sc_rd[i].rd_slot != sdi->sdi_slot ||
765			    start < sc->sc_rd[i].rd_coffset ||
766			    start > sc->sc_rd[i].rd_cend)
767				continue;
768			/* Disallow cross-range allocations. */
769			if (end > sc->sc_rd[i].rd_cend)
770				return (NULL);
771			/* We've found the connection to the parent bus */
772			toffs = start - sc->sc_rd[i].rd_coffset;
773			tend = end - sc->sc_rd[i].rd_coffset;
774			rm = &sc->sc_rd[i].rd_rman;
775			bh = sc->sc_rd[i].rd_bushandle;
776		}
777		if (toffs == NULL)
778			return (NULL);
779		flags &= ~RF_ACTIVE;
780		rv = rman_reserve_resource(rm, toffs, tend, count, flags,
781		    child);
782		if (rv == NULL)
783			return (NULL);
784		rman_set_bustag(rv, sc->sc_cbustag);
785		rman_set_bushandle(rv, bh + rman_get_start(rv));
786		if (needactivate) {
787			if (bus_activate_resource(child, type, *rid, rv)) {
788				rman_release_resource(rv);
789				return (NULL);
790			}
791		}
792		break;
793	default:
794		return (NULL);
795	}
796	rle->res = rv;
797	return (rv);
798}
799
800static int
801sbus_activate_resource(device_t bus, device_t child, int type, int rid,
802    struct resource *r)
803{
804
805	if (type == SYS_RES_IRQ) {
806		return (BUS_ACTIVATE_RESOURCE(device_get_parent(bus),
807		    child, type, rid, r));
808	}
809	return (rman_activate_resource(r));
810}
811
812static int
813sbus_deactivate_resource(device_t bus, device_t child, int type, int rid,
814    struct resource *r)
815{
816
817	if (type == SYS_RES_IRQ) {
818		return (BUS_DEACTIVATE_RESOURCE(device_get_parent(bus),
819		    child, type, rid, r));
820	}
821	return (rman_deactivate_resource(r));
822}
823
824static int
825sbus_release_resource(device_t bus, device_t child, int type, int rid,
826    struct resource *r)
827{
828	struct sbus_devinfo *sdi;
829	struct resource_list_entry *rle;
830	int error = 0;
831
832	if (type == SYS_RES_IRQ)
833		error = BUS_RELEASE_RESOURCE(device_get_parent(bus), child,
834		    type, rid, r);
835	else {
836		if ((rman_get_flags(r) & RF_ACTIVE) != 0)
837			error = bus_deactivate_resource(child, type, rid, r);
838		if (error != 0)
839			return (error);
840		error = rman_release_resource(r);
841	}
842	if (error != 0)
843		return (error);
844	sdi = device_get_ivars(child);
845	rle = resource_list_find(&sdi->sdi_rl, type, rid);
846	if (rle == NULL)
847		panic("sbus_release_resource: can't find resource");
848	if (rle->res == NULL)
849		panic("sbus_release_resource: resource entry is not busy");
850	rle->res = NULL;
851	return (0);
852}
853
854/*
855 * Handle an overtemp situation.
856 *
857 * SPARCs have temperature sensors which generate interrupts
858 * if the machine's temperature exceeds a certain threshold.
859 * This handles the interrupt and powers off the machine.
860 * The same needs to be done to PCI controller drivers.
861 */
862static void
863sbus_overtemp(void *arg)
864{
865
866	printf("DANGER: OVER TEMPERATURE detected\nShutting down NOW.\n");
867	shutdown_nice(RB_POWEROFF);
868}
869
870/* Try to shut down in time in case of power failure. */
871static void
872sbus_pwrfail(void *arg)
873{
874
875	printf("Power failure detected\nShutting down NOW.\n");
876	shutdown_nice(0);
877}
878
879static bus_space_tag_t
880sbus_alloc_bustag(struct sbus_softc *sc)
881{
882	bus_space_tag_t sbt;
883
884	sbt = (bus_space_tag_t)malloc(sizeof(struct bus_space_tag), M_DEVBUF,
885	    M_NOWAIT | M_ZERO);
886	if (sbt == NULL)
887		panic("sbus_alloc_bustag: out of memory");
888
889	bzero(sbt, sizeof *sbt);
890	sbt->bst_cookie = sc;
891	sbt->bst_parent = sc->sc_bustag;
892	sbt->bst_type = SBUS_BUS_SPACE;
893	return (sbt);
894}
895