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