xref: /openbsd-src/sys/arch/sparc64/dev/sbus.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$OpenBSD: sbus.c,v 1.39 2010/12/26 15:37:20 kettenis Exp $	*/
2 /*	$NetBSD: sbus.c,v 1.46 2001/10/07 20:30:41 eeh Exp $ */
3 
4 /*-
5  * Copyright (c) 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Paul Kranenburg.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Copyright (c) 1992, 1993
35  *	The Regents of the University of California.  All rights reserved.
36  *
37  * This software was developed by the Computer Systems Engineering group
38  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
39  * contributed to Berkeley.
40  *
41  * All advertising materials mentioning features or use of this software
42  * must display the following acknowledgement:
43  *	This product includes software developed by the University of
44  *	California, Lawrence Berkeley Laboratory.
45  *
46  * Redistribution and use in source and binary forms, with or without
47  * modification, are permitted provided that the following conditions
48  * are met:
49  * 1. Redistributions of source code must retain the above copyright
50  *    notice, this list of conditions and the following disclaimer.
51  * 2. Redistributions in binary form must reproduce the above copyright
52  *    notice, this list of conditions and the following disclaimer in the
53  *    documentation and/or other materials provided with the distribution.
54  * 3. Neither the name of the University nor the names of its contributors
55  *    may be used to endorse or promote products derived from this software
56  *    without specific prior written permission.
57  *
58  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
59  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
60  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
61  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
62  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
63  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
64  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
65  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
66  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
67  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
68  * SUCH DAMAGE.
69  *
70  *	@(#)sbus.c	8.1 (Berkeley) 6/11/93
71  */
72 
73 /*
74  * Copyright (c) 1999 Eduardo Horvath
75  *
76  * Redistribution and use in source and binary forms, with or without
77  * modification, are permitted provided that the following conditions
78  * are met:
79  * 1. Redistributions of source code must retain the above copyright
80  *    notice, this list of conditions and the following disclaimer.
81  *
82  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR  ``AS IS'' AND
83  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
84  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
85  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR  BE LIABLE
86  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
87  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
88  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
89  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
90  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
91  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
92  * SUCH DAMAGE.
93  *
94  */
95 
96 
97 /*
98  * SBus stuff.
99  */
100 
101 #include <sys/param.h>
102 #include <sys/extent.h>
103 #include <sys/malloc.h>
104 #include <sys/systm.h>
105 #include <sys/device.h>
106 #include <sys/reboot.h>
107 
108 #include <machine/bus.h>
109 #include <sparc64/sparc64/cache.h>
110 #include <sparc64/dev/iommureg.h>
111 #include <sparc64/dev/iommuvar.h>
112 #include <sparc64/dev/sbusreg.h>
113 #include <sparc64/dev/starfire.h>
114 #include <dev/sbus/sbusvar.h>
115 #include <dev/sbus/xboxvar.h>
116 
117 #include <uvm/uvm_extern.h>
118 
119 #include <machine/autoconf.h>
120 #include <machine/cpu.h>
121 #include <machine/openfirm.h>
122 #include <machine/sparc64.h>
123 
124 #ifdef DEBUG
125 #define SDB_DVMA	0x1
126 #define SDB_INTR	0x2
127 #define SDB_CHILD	0x4
128 int sbus_debug = 0;
129 #define DPRINTF(l, s)   do { if (sbus_debug & l) printf s; } while (0)
130 #else
131 #define DPRINTF(l, s)
132 #endif
133 
134 bus_space_tag_t sbus_alloc_bustag(struct sbus_softc *, int);
135 bus_dma_tag_t sbus_alloc_dma_tag(struct sbus_softc *, bus_dma_tag_t);
136 int sbus_get_intr(struct sbus_softc *, int,
137     struct sbus_intr **, int *, int);
138 int sbus_overtemp(void *);
139 int _sbus_bus_map(bus_space_tag_t, bus_space_tag_t,
140     bus_addr_t,		/*offset*/
141     bus_size_t,		/*size*/
142     int,		/*flags*/
143     bus_space_handle_t *);
144 void *sbus_intr_establish(bus_space_tag_t, bus_space_tag_t,
145     int,		/*SBus interrupt level*/
146     int,		/*`device class' priority*/
147     int,		/*flags*/
148     int (*)(void *),	/*handler*/
149     void *,		/*handler arg*/
150     const char *);	/*what*/
151 void	sbus_attach_common(struct sbus_softc *, int, int);
152 
153 /* autoconfiguration driver */
154 void	sbus_mb_attach(struct device *, struct device *, void *);
155 void	sbus_xbox_attach(struct device *, struct device *, void *);
156 int	sbus_mb_match(struct device *, void *, void *);
157 int	sbus_xbox_match(struct device *, void *, void *);
158 
159 struct cfattach sbus_mb_ca = {
160 	sizeof(struct sbus_softc), sbus_mb_match, sbus_mb_attach
161 };
162 
163 struct cfattach sbus_xbox_ca = {
164 	sizeof(struct sbus_softc), sbus_xbox_match, sbus_xbox_attach
165 };
166 
167 struct cfdriver sbus_cd = {
168 	NULL, "sbus", DV_DULL
169 };
170 
171 /*
172  * DVMA routines
173  */
174 int sbus_dmamap_create(bus_dma_tag_t, bus_dma_tag_t, bus_size_t, int,
175     bus_size_t, bus_size_t, int, bus_dmamap_t *);
176 
177 /*
178  * Child devices receive the SBus interrupt level in their attach
179  * arguments. We translate these to CPU IPLs using the following
180  * tables. Note: obio bus interrupt levels are identical to the
181  * processor IPL.
182  *
183  * The second set of tables is used when the SBus interrupt level
184  * cannot be had from the PROM as an `interrupt' property. We then
185  * fall back on the `intr' property which contains the CPU IPL.
186  */
187 
188 /* Translate SBus interrupt level to processor IPL */
189 static int intr_sbus2ipl_4u[] = {
190 	0, 2, 3, 5, 7, 9, 11, 13
191 };
192 
193 /*
194  * This value is or'ed into the attach args' interrupt level cookie
195  * if the interrupt level comes from an `intr' property, i.e. it is
196  * not an SBus interrupt level.
197  */
198 #define SBUS_INTR_COMPAT	0x80000000
199 
200 
201 /*
202  * Print the location of some sbus-attached device (called just
203  * before attaching that device).  If `sbus' is not NULL, the
204  * device was found but not configured; print the sbus as well.
205  * Return UNCONF (config_find ignores this if the device was configured).
206  */
207 int
208 sbus_print(void *args, const char *busname)
209 {
210 	struct sbus_attach_args *sa = args;
211 	char *class;
212 	int i;
213 
214 	if (busname != NULL) {
215 		printf("\"%s\" at %s", sa->sa_name, busname);
216 		class = getpropstring(sa->sa_node, "device_type");
217 		if (*class != '\0')
218 			printf(" class %s", class);
219 	}
220 	printf(" slot %ld offset 0x%lx", (long)sa->sa_slot,
221 	       (u_long)sa->sa_offset);
222 	for (i = 0; i < sa->sa_nintr; i++) {
223 		struct sbus_intr *sbi = &sa->sa_intr[i];
224 
225 		printf(" vector %lx ipl %ld",
226 		       (u_long)sbi->sbi_vec,
227 		       (long)INTLEV(sbi->sbi_pri));
228 	}
229 	return (UNCONF);
230 }
231 
232 int
233 sbus_mb_match(struct device *parent, void *vcf, void *aux)
234 {
235 	struct cfdata *cf = vcf;
236 	struct mainbus_attach_args *ma = aux;
237 
238 	return (strcmp(cf->cf_driver->cd_name, ma->ma_name) == 0);
239 }
240 
241 int
242 sbus_xbox_match(struct device *parent, void *vcf, void *aux)
243 {
244 	struct xbox_softc *xsc = (struct xbox_softc *)parent;
245 
246 	/* Prevent multiple attachments */
247 	if (xsc->sc_attached == 0) {
248 		xsc->sc_attached = 1;
249 		return (1);
250 	}
251 
252 	return (0);
253 }
254 
255 void
256 sbus_xbox_attach(struct device *parent, struct device *self, void *aux)
257 {
258 	struct sbus_softc *sc = (struct sbus_softc *)self;
259 	struct xbox_softc *xsc = (struct xbox_softc *)parent;
260 	struct sbus_softc *sbus = (struct sbus_softc *)parent->dv_parent;
261 	struct xbox_attach_args *xa = aux;
262 	int node = xa->xa_node;
263 
264 	sc->sc_master = sbus->sc_master;
265 
266 	sc->sc_bustag = xa->xa_bustag;
267 	sc->sc_dmatag = sbus_alloc_dma_tag(sc, xa->xa_dmatag);
268 
269 	/*
270 	 * Parent has already done the address translation computations.
271 	 */
272 	sc->sc_nrange = xsc->sc_nrange;
273 	sc->sc_range = xsc->sc_range;
274 
275 	/*
276 	 * Record clock frequency for synchronous SCSI.
277 	 * IS THIS THE CORRECT DEFAULT??
278 	 */
279 	sc->sc_clockfreq = getpropint(node, "clock-frequency", 25*1000*1000);
280 	printf(": %s MHz\n", clockfreq(sc->sc_clockfreq));
281 
282 	sbus_attach_common(sc, node, 1);
283 }
284 
285 void
286 sbus_mb_attach(struct device *parent, struct device *self, void *aux)
287 {
288 	struct sbus_softc *sc = (struct sbus_softc *)self;
289 	struct mainbus_attach_args *ma = aux;
290 	int node = ma->ma_node;
291 	struct intrhand *ih;
292 	int ipl, error;
293 	struct sysioreg *sysio;
294 	char buf[32];
295 	char *name;
296 
297 	sc->sc_master = sc;
298 
299 	sc->sc_bustag = ma->ma_bustag;
300 
301 	/* Find interrupt group no */
302 	sc->sc_ign = ma->ma_interrupts[0] & INTMAP_IGN;
303 
304 	/*
305 	 * Collect address translations from the OBP.
306 	 */
307 	error = getprop(node, "ranges", sizeof(struct sbus_range),
308 			 &sc->sc_nrange, (void **)&sc->sc_range);
309 	if (error)
310 		panic("%s: error getting ranges property", sc->sc_dev.dv_xname);
311 
312 	/*
313 	 * Record clock frequency for synchronous SCSI.
314 	 * IS THIS THE CORRECT DEFAULT??
315 	 */
316 	sc->sc_clockfreq = getpropint(node, "clock-frequency", 25*1000*1000);
317 	printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq));
318 
319 	bus_space_map(sc->sc_bustag,
320 	    ma->ma_address[0], sizeof(struct sysioreg),
321 	    BUS_SPACE_MAP_PROMADDRESS, &sc->sc_bh);
322 	sysio = bus_space_vaddr(sc->sc_bustag, sc->sc_bh);
323 
324 	/* initialize the IOMMU */
325 
326 	/* punch in our copies */
327 	sc->sc_is.is_bustag = sc->sc_bustag;
328 	bus_space_subregion(sc->sc_bustag, sc->sc_bh,
329 	    offsetof(struct sysioreg, sys_iommu),
330 	    sizeof(struct iommureg), &sc->sc_is.is_iommu);
331 
332 	/* initialize our strbuf_ctl */
333 	sc->sc_is.is_sb[0] = &sc->sc_sb;
334 	if (bus_space_subregion(sc->sc_bustag, sc->sc_bh,
335 	    offsetof(struct sysioreg, sys_strbuf),
336 	    sizeof(struct iommu_strbuf), &sc->sc_sb.sb_sb) == 0) {
337 		/* point sb_flush to our flush buffer */
338 		sc->sc_sb.sb_flush = &sc->sc_flush;
339 		sc->sc_sb.sb_bustag = sc->sc_bustag;
340 	} else
341 		sc->sc_sb.sb_flush = NULL;
342 
343 	/* give us a nice name.. */
344 	name = (char *)malloc(32, M_DEVBUF, M_NOWAIT);
345 	if (name == 0)
346 		panic("couldn't malloc iommu name");
347 	snprintf(name, 32, "%s dvma", sc->sc_dev.dv_xname);
348 
349 	printf("%s: ", sc->sc_dev.dv_xname);
350 	iommu_init(name, &sc->sc_is, 0, -1);
351 
352 	/* Initialize Starfire PC interrupt translation. */
353 	if (OF_getprop(findroot(), "name", buf, sizeof(buf)) > 0 &&
354 	    strcmp(buf, "SUNW,Ultra-Enterprise-10000") == 0)
355 		starfire_pc_ittrans_init(ma->ma_upaid);
356 
357 	/* Enable the over temp intr */
358 	ih = malloc(sizeof(*ih), M_DEVBUF, M_NOWAIT | M_ZERO);
359 	if (ih == NULL)
360 		panic("couldn't malloc intrhand");
361 	ih->ih_map = &sysio->therm_int_map;
362 	ih->ih_clr = NULL; /* &sysio->therm_clr_int; */
363 	ih->ih_fun = sbus_overtemp;
364 	ipl = 1;
365 	ih->ih_pil = (1 << ipl);
366 	ih->ih_number = INTVEC(*(ih->ih_map));
367 	strlcpy(ih->ih_name, sc->sc_dev.dv_xname, sizeof(ih->ih_name));
368 	intr_establish(ipl, ih);
369 	*(ih->ih_map) |= INTMAP_V;
370 
371 	/*
372 	 * Note: the stupid SBus IOMMU ignores the high bits of an address, so a
373 	 * NULL DMA pointer will be translated by the first page of the IOTSB.
374 	 * To avoid bugs we'll alloc and ignore the first entry in the IOTSB.
375 	 */
376 	{
377 		u_long dummy;
378 
379 		if (extent_alloc_subregion(sc->sc_is.is_dvmamap,
380 		    sc->sc_is.is_dvmabase, sc->sc_is.is_dvmabase + NBPG, NBPG,
381 		    NBPG, 0, 0, EX_NOWAIT | EX_BOUNDZERO,
382 		    (u_long *)&dummy) != 0)
383 			panic("sbus iommu: can't toss first dvma page");
384 	}
385 
386 	sc->sc_dmatag = sbus_alloc_dma_tag(sc, ma->ma_dmatag);
387 
388 	sbus_attach_common(sc, node, 0);
389 }
390 
391 /*
392  * Attach an SBus (main part).
393  */
394 void
395 sbus_attach_common(struct sbus_softc *sc, int node, int indirect)
396 {
397 	bus_space_tag_t sbt;
398 	struct sbus_attach_args sa;
399 	int node0;
400 
401 	/* Setup interrupt translation tables */
402 	sc->sc_intr2ipl = intr_sbus2ipl_4u;
403 
404 	sbt = sbus_alloc_bustag(sc, indirect);
405 
406 	/*
407 	 * Get the SBus burst transfer size if burst transfers are supported
408 	 */
409 	sc->sc_burst = getpropint(node, "burst-sizes", 0);
410 
411 	/*
412 	 * Loop through ROM children, fixing any relative addresses
413 	 * and then configuring each device.
414 	 * `specials' is an array of device names that are treated
415 	 * specially:
416 	 */
417 	node0 = firstchild(node);
418 	for (node = node0; node; node = nextsibling(node)) {
419 		if (!checkstatus(node))
420 			continue;
421 
422 		if (sbus_setup_attach_args(sc, sbt, sc->sc_dmatag,
423 					   node, &sa) != 0) {
424 			DPRINTF(SDB_CHILD,
425 			    ("sbus_attach: %s: incomplete\n",
426 			    getpropstring(node, "name")));
427 			continue;
428 		}
429 		(void) config_found(&sc->sc_dev, (void *)&sa, sbus_print);
430 		sbus_destroy_attach_args(&sa);
431 	}
432 }
433 
434 int
435 sbus_setup_attach_args(struct sbus_softc *sc, bus_space_tag_t bustag,
436     bus_dma_tag_t dmatag, int node, struct sbus_attach_args *sa)
437 {
438 	int	error;
439 	int	n;
440 
441 	bzero(sa, sizeof(struct sbus_attach_args));
442 	error = getprop(node, "name", 1, &n, (void **)&sa->sa_name);
443 	if (error != 0)
444 		return (error);
445 	sa->sa_name[n] = '\0';
446 
447 	sa->sa_bustag = bustag;
448 	sa->sa_dmatag = dmatag;
449 	sa->sa_node = node;
450 	sa->sa_frequency = sc->sc_clockfreq;
451 
452 	error = getprop(node, "reg", sizeof(struct sbus_reg),
453 			 &sa->sa_nreg, (void **)&sa->sa_reg);
454 	if (error != 0) {
455 		char buf[32];
456 		if (error != ENOENT ||
457 		    !node_has_property(node, "device_type") ||
458 		    strcmp(getpropstringA(node, "device_type", buf),
459 			   "hierarchical") != 0)
460 			return (error);
461 	}
462 	for (n = 0; n < sa->sa_nreg; n++) {
463 		/* Convert to relative addressing, if necessary */
464 		u_int32_t base = sa->sa_reg[n].sbr_offset;
465 		if (SBUS_ABS(base)) {
466 			sa->sa_reg[n].sbr_slot = SBUS_ABS_TO_SLOT(base);
467 			sa->sa_reg[n].sbr_offset = SBUS_ABS_TO_OFFSET(base);
468 		}
469 	}
470 
471 	if ((error = sbus_get_intr(sc, node, &sa->sa_intr, &sa->sa_nintr,
472 	    sa->sa_slot)) != 0)
473 		return (error);
474 
475 	error = getprop(node, "address", sizeof(u_int32_t),
476 			 &sa->sa_npromvaddrs, (void **)&sa->sa_promvaddrs);
477 	if (error != 0 && error != ENOENT)
478 		return (error);
479 
480 	return (0);
481 }
482 
483 void
484 sbus_destroy_attach_args(struct sbus_attach_args *sa)
485 {
486 	if (sa->sa_name != NULL)
487 		free(sa->sa_name, M_DEVBUF);
488 
489 	if (sa->sa_nreg != 0)
490 		free(sa->sa_reg, M_DEVBUF);
491 
492 	if (sa->sa_intr)
493 		free(sa->sa_intr, M_DEVBUF);
494 
495 	if (sa->sa_promvaddrs)
496 		free((void *)sa->sa_promvaddrs, M_DEVBUF);
497 
498 	bzero(sa, sizeof(struct sbus_attach_args)); /*DEBUG*/
499 }
500 
501 
502 int
503 _sbus_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t addr,
504     bus_size_t size, int flags, bus_space_handle_t *hp)
505 {
506 	struct sbus_softc *sc = t->cookie;
507 	int64_t slot = BUS_ADDR_IOSPACE(addr);
508 	int64_t offset = BUS_ADDR_PADDR(addr);
509 	int i;
510 
511 	if (t->parent == NULL || t->parent->sparc_bus_map == NULL) {
512 		printf("\n_psycho_bus_map: invalid parent");
513 		return (EINVAL);
514 	}
515 
516 	if (flags & BUS_SPACE_MAP_PROMADDRESS) {
517 		return ((*t->parent->sparc_bus_map)(t, t0, addr,
518 					size, flags, hp));
519 	}
520 
521 	for (i = 0; i < sc->sc_nrange; i++) {
522 		bus_addr_t paddr;
523 
524 		if (sc->sc_range[i].cspace != slot)
525 			continue;
526 
527 		/* We've found the connection to the parent bus */
528 		paddr = sc->sc_range[i].poffset + offset;
529 		paddr |= ((bus_addr_t)sc->sc_range[i].pspace << 32);
530 		DPRINTF(SDB_DVMA, ("_sbus_bus_map: mapping paddr "
531 			"slot %lx offset %lx poffset %lx paddr %lx\n",
532 		    (long)slot, (long)offset, (long)sc->sc_range[i].poffset,
533 		    (long)paddr));
534 		return ((*t->parent->sparc_bus_map)(t, t0, paddr,
535 					size, flags, hp));
536 	}
537 
538 	return (EINVAL);
539 }
540 
541 bus_addr_t
542 sbus_bus_addr(bus_space_tag_t t, u_int btype, u_int offset)
543 {
544 	bus_addr_t baddr = ~(bus_addr_t)0;
545 	int slot = btype;
546 	struct sbus_softc *sc = t->cookie;
547 	int i;
548 
549 	for (i = 0; i < sc->sc_nrange; i++) {
550 		if (sc->sc_range[i].cspace != slot)
551 			continue;
552 
553 		baddr = sc->sc_range[i].poffset + offset;
554 		baddr |= (bus_addr_t)sc->sc_range[i].pspace << 32;
555 	}
556 
557 	return (baddr);
558 }
559 
560 /*
561  * Handle an overtemp situation.
562  *
563  * SPARCs have temperature sensors which generate interrupts
564  * if the machine's temperature exceeds a certain threshold.
565  * This handles the interrupt and powers off the machine.
566  * The same needs to be done to PCI controller drivers.
567  */
568 int
569 sbus_overtemp(void *arg)
570 {
571 	/* Should try a clean shutdown first */
572 	printf("DANGER: OVER TEMPERATURE detected\nShutting down...\n");
573 	delay(20);
574 	boot(RB_POWERDOWN|RB_HALT);
575 	/*NOTREACHED*/
576 	return (1);
577 }
578 
579 /*
580  * Get interrupt attributes for an SBus device.
581  */
582 int
583 sbus_get_intr(struct sbus_softc *sc, int node, struct sbus_intr **ipp, int *np,
584     int slot)
585 {
586 	int *ipl;
587 	int n, i;
588 	char buf[32];
589 
590 	/*
591 	 * The `interrupts' property contains the SBus interrupt level.
592 	 */
593 	ipl = NULL;
594 	if (getprop(node, "interrupts", sizeof(int), np, (void **)&ipl) == 0) {
595 		struct sbus_intr *ip;
596 		int pri;
597 
598 		/* Default to interrupt level 2 -- otherwise unused */
599 		pri = INTLEVENCODE(2);
600 
601 		/* Change format to an `struct sbus_intr' array */
602 		ip = malloc(*np * sizeof(struct sbus_intr), M_DEVBUF, M_NOWAIT);
603 		if (ip == NULL)
604 			return (ENOMEM);
605 
606 		/*
607 		 * Now things get ugly.  We need to take this value which is
608 		 * the interrupt vector number and encode the IPL into it
609 		 * somehow. Luckily, the interrupt vector has lots of free
610 		 * space and we can easily stuff the IPL in there for a while.
611 		 */
612 		getpropstringA(node, "device_type", buf);
613 		if (!buf[0])
614 			getpropstringA(node, "name", buf);
615 
616 		for (i = 0; intrmap[i].in_class; i++)
617 			if (strcmp(intrmap[i].in_class, buf) == 0) {
618 				pri = INTLEVENCODE(intrmap[i].in_lev);
619 				break;
620 			}
621 
622 		/*
623 		 * SBus card devices need the slot number encoded into
624 		 * the vector as this is generally not done.
625 		 */
626 		if ((ipl[0] & INTMAP_OBIO) == 0)
627 			pri |= slot << 3;
628 
629 		for (n = 0; n < *np; n++) {
630 			/*
631 			 * We encode vector and priority into sbi_pri so we
632 			 * can pass them as a unit.  This will go away if
633 			 * sbus_establish ever takes an sbus_intr instead
634 			 * of an integer level.
635 			 * Stuff the real vector in sbi_vec.
636 			 */
637 
638 			ip[n].sbi_pri = pri | ipl[n];
639 			ip[n].sbi_vec = ipl[n];
640 		}
641 		free(ipl, M_DEVBUF);
642 		*ipp = ip;
643 	}
644 
645 	return (0);
646 }
647 
648 
649 /*
650  * Install an interrupt handler for an SBus device.
651  */
652 void *
653 sbus_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int pri, int level,
654     int flags, int (*handler)(void *), void *arg, const char *what)
655 {
656 	struct sbus_softc *sc = t->cookie;
657 	struct sysioreg *sysio;
658 	struct intrhand *ih;
659 	volatile u_int64_t *map = NULL;
660 	volatile u_int64_t *clr = NULL;
661 	int ipl;
662 	long vec = pri;
663 
664 	/* Pick the master SBus as all do not have IOMMU registers */
665 	sc = sc->sc_master;
666 
667 	sysio = bus_space_vaddr(sc->sc_bustag, sc->sc_bh);
668 
669 	if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) != 0)
670 		ipl = 1 << vec;
671 	else if ((vec & SBUS_INTR_COMPAT) != 0)
672 		ipl = 1 << (vec & ~SBUS_INTR_COMPAT);
673 	else {
674 		/* Decode and remove IPL */
675 		ipl = level;
676 		if (ipl == IPL_NONE)
677 			ipl = 1 << INTLEV(vec);
678 		if (ipl == IPL_NONE) {
679 			printf("ERROR: no IPL, setting IPL 2.\n");
680 			ipl = 2;
681 		}
682 		vec = INTVEC(vec);
683 		DPRINTF(SDB_INTR,
684 		    ("\nsbus: intr[%ld]%lx: %lx\nHunting for IRQ...\n",
685 		    (long)ipl, (long)vec, (u_long)intrlev[vec]));
686 		if ((vec & INTMAP_OBIO) == 0) {
687 			/* We're in an SBus slot */
688 			/* Register the map and clear intr registers */
689 			bus_space_handle_t maph;
690 			int slot = INTSLOT(pri);
691 
692 			map = &(&sysio->sbus_slot0_int)[slot];
693 			clr = &sysio->sbus0_clr_int[vec];
694 #ifdef DEBUG
695 			if (sbus_debug & SDB_INTR) {
696 				int64_t intrmap = *map;
697 
698 				printf("SBus %lx IRQ as %llx in slot %d\n",
699 				       (long)vec, (long long)intrmap, slot);
700 				printf("\tmap addr %p clr addr %p\n",
701 				    map, clr);
702 			}
703 #endif
704 			/* Enable the interrupt */
705 			vec |= INTMAP_V;
706 			/* Insert IGN */
707 			vec |= sc->sc_ign;
708 			/*
709 			 * This would be cleaner if the underlying interrupt
710 			 * infrastructure took a bus tag/handle pair.  Even
711 			 * if not, the following could be done with a write
712 			 * to the appropriate offset from sc->sc_bustag and
713 			 * sc->sc_bh.
714 			 */
715 			bus_space_map(sc->sc_bustag, (bus_addr_t)map, 8,
716 			    BUS_SPACE_MAP_PROMADDRESS, &maph);
717 			bus_space_write_8(sc->sc_bustag, maph, 0, vec);
718 		} else {
719 			bus_space_handle_t maph;
720 			volatile int64_t *intrptr = &sysio->scsi_int_map;
721 			int64_t intrmap = 0;
722 			int i;
723 
724 			/* Insert IGN */
725 			vec |= sc->sc_ign;
726 			for (i = 0; &intrptr[i] <=
727 			    (int64_t *)&sysio->reserved_int_map &&
728 			    INTVEC(intrmap = intrptr[i]) != INTVEC(vec); i++)
729 				;
730 			if (INTVEC(intrmap) == INTVEC(vec)) {
731 				DPRINTF(SDB_INTR,
732 				    ("OBIO %lx IRQ as %lx in slot %d\n",
733 				    vec, (long)intrmap, i));
734 				/* Register the map and clear intr registers */
735 				map = &intrptr[i];
736 				intrptr = (int64_t *)&sysio->scsi_clr_int;
737 				clr = &intrptr[i];
738 				/* Enable the interrupt */
739 				intrmap |= INTMAP_V;
740 				/*
741 				 * This would be cleaner if the underlying
742 				 * interrupt infrastructure took a bus tag/
743 				 * handle pair.  Even if not, the following
744 				 * could be done with a write to the
745 				 * appropriate offset from sc->sc_bustag and
746 				 * sc->sc_bh.
747 				 */
748 				bus_space_map(sc->sc_bustag,
749 				    (bus_addr_t)map, 8,
750 				    BUS_SPACE_MAP_PROMADDRESS, &maph);
751 				bus_space_write_8(sc->sc_bustag, maph, 0,
752 				    (u_long)intrmap);
753 			} else
754 				panic("IRQ not found!");
755 		}
756 	}
757 #ifdef DEBUG
758 	if (sbus_debug & SDB_INTR) { long i; for (i = 0; i < 400000000; i++); }
759 #endif
760 
761 	ih = bus_intr_allocate(t0, handler, arg, vec, ipl, map, clr, what);
762 	if (ih == NULL)
763 		return (ih);
764 
765 	intr_establish(ih->ih_pil, ih);
766 
767 	return (ih);
768 }
769 
770 bus_space_tag_t
771 sbus_alloc_bustag(struct sbus_softc *sc, int indirect)
772 {
773 	struct sparc_bus_space_tag *sbt;
774 
775 	sbt = malloc(sizeof(*sbt), M_DEVBUF, M_NOWAIT | M_ZERO);
776 	if (sbt == NULL)
777 		return (NULL);
778 
779 	strlcpy(sbt->name, sc->sc_dev.dv_xname, sizeof(sbt->name));
780 	sbt->cookie = sc;
781 	if (indirect)
782 		sbt->parent = sc->sc_bustag->parent;
783 	else
784 		sbt->parent = sc->sc_bustag;
785 	sbt->default_type = SBUS_BUS_SPACE;
786 	sbt->asi = ASI_PRIMARY;
787 	sbt->sasi = ASI_PRIMARY;
788 	sbt->sparc_bus_map = _sbus_bus_map;
789 	sbt->sparc_bus_mmap = sc->sc_bustag->sparc_bus_mmap;
790 	sbt->sparc_intr_establish = sbus_intr_establish;
791 	return (sbt);
792 }
793 
794 
795 bus_dma_tag_t
796 sbus_alloc_dma_tag(struct sbus_softc *sc, bus_dma_tag_t psdt)
797 {
798 	bus_dma_tag_t sdt;
799 
800 	sdt = (bus_dma_tag_t)malloc(sizeof(struct sparc_bus_dma_tag),
801 	    M_DEVBUF, M_NOWAIT | M_ZERO);
802 	if (sdt == NULL)
803 		/* Panic? */
804 		return (psdt);
805 
806 	sdt->_cookie = sc;
807 	sdt->_parent = psdt;
808 	sdt->_dmamap_create	= sbus_dmamap_create;
809 	sdt->_dmamap_destroy	= iommu_dvmamap_destroy;
810 	sdt->_dmamap_load	= iommu_dvmamap_load;
811 	sdt->_dmamap_load_raw	= iommu_dvmamap_load_raw;
812 	sdt->_dmamap_unload	= iommu_dvmamap_unload;
813 	sdt->_dmamap_sync	= iommu_dvmamap_sync;
814 	sdt->_dmamem_alloc	= iommu_dvmamem_alloc;
815 	sdt->_dmamem_free	= iommu_dvmamem_free;
816 	return (sdt);
817 }
818 
819 int
820 sbus_dmamap_create(bus_dma_tag_t t, bus_dma_tag_t t0, bus_size_t size,
821     int nsegments, bus_size_t maxsegsz, bus_size_t boundary, int flags,
822     bus_dmamap_t *dmamp)
823 {
824 	struct sbus_softc *sc = t->_cookie;
825 
826 	/* Disallow DMA on secondary SBuses for now */
827 	if (sc != sc->sc_master)
828 		return (EINVAL);
829 
830         return (iommu_dvmamap_create(t, t0, &sc->sc_sb, size, nsegments,
831 	    maxsegsz, boundary, flags, dmamp));
832 }
833