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