xref: /openbsd/sys/arch/sparc64/dev/sbus.c (revision 73471bf0)
1 /*	$OpenBSD: sbus.c,v 1.46 2021/10/24 17:05:04 mpi 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 const struct cfattach sbus_mb_ca = {
162 	sizeof(struct sbus_softc), sbus_mb_match, sbus_mb_attach
163 };
164 
165 const 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, &iommu_hw_default, &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 	free(sa->sa_name, M_DEVBUF, 0);
489 	free(sa->sa_reg, M_DEVBUF, 0);
490 	free(sa->sa_intr, M_DEVBUF, 0);
491 	free((void *)sa->sa_promvaddrs, M_DEVBUF, 0);
492 
493 	bzero(sa, sizeof(struct sbus_attach_args)); /*DEBUG*/
494 }
495 
496 
497 int
498 _sbus_bus_map(bus_space_tag_t t, bus_space_tag_t t0, bus_addr_t addr,
499     bus_size_t size, int flags, bus_space_handle_t *hp)
500 {
501 	struct sbus_softc *sc = t->cookie;
502 	int64_t slot = BUS_ADDR_IOSPACE(addr);
503 	int64_t offset = BUS_ADDR_PADDR(addr);
504 	int i;
505 
506 	if (t->parent == NULL || t->parent->sparc_bus_map == NULL) {
507 		printf("\n_psycho_bus_map: invalid parent");
508 		return (EINVAL);
509 	}
510 
511 	if (flags & BUS_SPACE_MAP_PROMADDRESS) {
512 		return ((*t->parent->sparc_bus_map)(t, t0, addr,
513 					size, flags, hp));
514 	}
515 
516 	for (i = 0; i < sc->sc_nrange; i++) {
517 		bus_addr_t paddr;
518 
519 		if (sc->sc_range[i].cspace != slot)
520 			continue;
521 
522 		/* We've found the connection to the parent bus */
523 		paddr = sc->sc_range[i].poffset + offset;
524 		paddr |= ((bus_addr_t)sc->sc_range[i].pspace << 32);
525 		DPRINTF(SDB_DVMA, ("_sbus_bus_map: mapping paddr "
526 			"slot %lx offset %lx poffset %lx paddr %lx\n",
527 		    (long)slot, (long)offset, (long)sc->sc_range[i].poffset,
528 		    (long)paddr));
529 		return ((*t->parent->sparc_bus_map)(t, t0, paddr,
530 					size, flags, hp));
531 	}
532 
533 	return (EINVAL);
534 }
535 
536 bus_addr_t
537 sbus_bus_addr(bus_space_tag_t t, u_int btype, u_int offset)
538 {
539 	bus_addr_t baddr = ~(bus_addr_t)0;
540 	int slot = btype;
541 	struct sbus_softc *sc = t->cookie;
542 	int i;
543 
544 	for (i = 0; i < sc->sc_nrange; i++) {
545 		if (sc->sc_range[i].cspace != slot)
546 			continue;
547 
548 		baddr = sc->sc_range[i].poffset + offset;
549 		baddr |= (bus_addr_t)sc->sc_range[i].pspace << 32;
550 	}
551 
552 	return (baddr);
553 }
554 
555 /*
556  * Handle an overtemp situation.
557  *
558  * SPARCs have temperature sensors which generate interrupts
559  * if the machine's temperature exceeds a certain threshold.
560  * This handles the interrupt and powers off the machine.
561  * The same needs to be done to PCI controller drivers.
562  */
563 int
564 sbus_overtemp(void *arg)
565 {
566 	/* Should try a clean shutdown first */
567 	printf("DANGER: OVER TEMPERATURE detected\nShutting down...\n");
568 	delay(20);
569 	prsignal(initprocess, SIGUSR2);
570 	return (1);
571 }
572 
573 /*
574  * Get interrupt attributes for an SBus device.
575  */
576 int
577 sbus_get_intr(struct sbus_softc *sc, int node, struct sbus_intr **ipp, int *np,
578     int slot)
579 {
580 	int *ipl;
581 	int n, i;
582 	char buf[32];
583 
584 	/*
585 	 * The `interrupts' property contains the SBus interrupt level.
586 	 */
587 	ipl = NULL;
588 	if (getprop(node, "interrupts", sizeof(int), np, (void **)&ipl) == 0) {
589 		struct sbus_intr *ip;
590 		int pri;
591 
592 		/* Default to interrupt level 2 -- otherwise unused */
593 		pri = INTLEVENCODE(2);
594 
595 		/* Change format to an `struct sbus_intr' array */
596 		ip = mallocarray(*np, sizeof(struct sbus_intr), M_DEVBUF,
597 		    M_NOWAIT);
598 		if (ip == NULL)
599 			return (ENOMEM);
600 
601 		/*
602 		 * Now things get ugly.  We need to take this value which is
603 		 * the interrupt vector number and encode the IPL into it
604 		 * somehow. Luckily, the interrupt vector has lots of free
605 		 * space and we can easily stuff the IPL in there for a while.
606 		 */
607 		getpropstringA(node, "device_type", buf);
608 		if (!buf[0])
609 			getpropstringA(node, "name", buf);
610 
611 		for (i = 0; intrmap[i].in_class; i++)
612 			if (strcmp(intrmap[i].in_class, buf) == 0) {
613 				pri = INTLEVENCODE(intrmap[i].in_lev);
614 				break;
615 			}
616 
617 		/*
618 		 * SBus card devices need the slot number encoded into
619 		 * the vector as this is generally not done.
620 		 */
621 		if ((ipl[0] & INTMAP_OBIO) == 0)
622 			pri |= slot << 3;
623 
624 		for (n = 0; n < *np; n++) {
625 			/*
626 			 * We encode vector and priority into sbi_pri so we
627 			 * can pass them as a unit.  This will go away if
628 			 * sbus_establish ever takes an sbus_intr instead
629 			 * of an integer level.
630 			 * Stuff the real vector in sbi_vec.
631 			 */
632 
633 			ip[n].sbi_pri = pri | ipl[n];
634 			ip[n].sbi_vec = ipl[n];
635 		}
636 		free(ipl, M_DEVBUF, 0);
637 		*ipp = ip;
638 	}
639 
640 	return (0);
641 }
642 
643 
644 /*
645  * Install an interrupt handler for an SBus device.
646  */
647 void *
648 sbus_intr_establish(bus_space_tag_t t, bus_space_tag_t t0, int pri, int level,
649     int flags, int (*handler)(void *), void *arg, const char *what)
650 {
651 	struct sbus_softc *sc = t->cookie;
652 	struct sysioreg *sysio;
653 	struct intrhand *ih;
654 	volatile u_int64_t *map = NULL;
655 	volatile u_int64_t *clr = NULL;
656 	int ipl;
657 	long vec = pri;
658 
659 	/* Pick the master SBus as all do not have IOMMU registers */
660 	sc = sc->sc_master;
661 
662 	sysio = bus_space_vaddr(sc->sc_bustag, sc->sc_bh);
663 
664 	if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) != 0)
665 		ipl = 1 << vec;
666 	else if ((vec & SBUS_INTR_COMPAT) != 0)
667 		ipl = 1 << (vec & ~SBUS_INTR_COMPAT);
668 	else {
669 		/* Decode and remove IPL */
670 		ipl = level;
671 		if (ipl == IPL_NONE)
672 			ipl = 1 << INTLEV(vec);
673 		if (ipl == IPL_NONE) {
674 			printf("ERROR: no IPL, setting IPL 2.\n");
675 			ipl = 2;
676 		}
677 		vec = INTVEC(vec);
678 		DPRINTF(SDB_INTR,
679 		    ("\nsbus: intr[%ld]%lx: %lx\nHunting for IRQ...\n",
680 		    (long)ipl, (long)vec, (u_long)intrlev[vec]));
681 		if ((vec & INTMAP_OBIO) == 0) {
682 			/* We're in an SBus slot */
683 			/* Register the map and clear intr registers */
684 			bus_space_handle_t maph;
685 			int slot = INTSLOT(pri);
686 
687 			map = &(&sysio->sbus_slot0_int)[slot];
688 			clr = &sysio->sbus0_clr_int[vec];
689 #ifdef DEBUG
690 			if (sbus_debug & SDB_INTR) {
691 				int64_t intrmap = *map;
692 
693 				printf("SBus %lx IRQ as %llx in slot %d\n",
694 				       (long)vec, (long long)intrmap, slot);
695 				printf("\tmap addr %p clr addr %p\n",
696 				    map, clr);
697 			}
698 #endif
699 			/* Enable the interrupt */
700 			vec |= INTMAP_V;
701 			/* Insert IGN */
702 			vec |= sc->sc_ign;
703 			/*
704 			 * This would be cleaner if the underlying interrupt
705 			 * infrastructure took a bus tag/handle pair.  Even
706 			 * if not, the following could be done with a write
707 			 * to the appropriate offset from sc->sc_bustag and
708 			 * sc->sc_bh.
709 			 */
710 			bus_space_map(sc->sc_bustag, (bus_addr_t)map, 8,
711 			    BUS_SPACE_MAP_PROMADDRESS, &maph);
712 			bus_space_write_8(sc->sc_bustag, maph, 0, vec);
713 		} else {
714 			bus_space_handle_t maph;
715 			volatile int64_t *intrptr = &sysio->scsi_int_map;
716 			int64_t intrmap = 0;
717 			int i;
718 
719 			/* Insert IGN */
720 			vec |= sc->sc_ign;
721 			for (i = 0; &intrptr[i] <=
722 			    (int64_t *)&sysio->reserved_int_map &&
723 			    INTVEC(intrmap = intrptr[i]) != INTVEC(vec); i++)
724 				;
725 			if (INTVEC(intrmap) == INTVEC(vec)) {
726 				DPRINTF(SDB_INTR,
727 				    ("OBIO %lx IRQ as %lx in slot %d\n",
728 				    vec, (long)intrmap, i));
729 				/* Register the map and clear intr registers */
730 				map = &intrptr[i];
731 				intrptr = (int64_t *)&sysio->scsi_clr_int;
732 				clr = &intrptr[i];
733 				/* Enable the interrupt */
734 				intrmap |= INTMAP_V;
735 				/*
736 				 * This would be cleaner if the underlying
737 				 * interrupt infrastructure took a bus tag/
738 				 * handle pair.  Even if not, the following
739 				 * could be done with a write to the
740 				 * appropriate offset from sc->sc_bustag and
741 				 * sc->sc_bh.
742 				 */
743 				bus_space_map(sc->sc_bustag,
744 				    (bus_addr_t)map, 8,
745 				    BUS_SPACE_MAP_PROMADDRESS, &maph);
746 				bus_space_write_8(sc->sc_bustag, maph, 0,
747 				    (u_long)intrmap);
748 			} else
749 				panic("IRQ not found!");
750 		}
751 	}
752 #ifdef DEBUG
753 	if (sbus_debug & SDB_INTR) { long i; for (i = 0; i < 400000000; i++); }
754 #endif
755 
756 	ih = bus_intr_allocate(t0, handler, arg, vec, ipl, map, clr, what);
757 	if (ih == NULL)
758 		return (ih);
759 
760 	intr_establish(ih->ih_pil, ih);
761 
762 	return (ih);
763 }
764 
765 bus_space_tag_t
766 sbus_alloc_bustag(struct sbus_softc *sc, int indirect)
767 {
768 	struct sparc_bus_space_tag *sbt;
769 
770 	sbt = malloc(sizeof(*sbt), M_DEVBUF, M_NOWAIT | M_ZERO);
771 	if (sbt == NULL)
772 		return (NULL);
773 
774 	strlcpy(sbt->name, sc->sc_dev.dv_xname, sizeof(sbt->name));
775 	sbt->cookie = sc;
776 	if (indirect)
777 		sbt->parent = sc->sc_bustag->parent;
778 	else
779 		sbt->parent = sc->sc_bustag;
780 	sbt->default_type = SBUS_BUS_SPACE;
781 	sbt->asi = ASI_PRIMARY;
782 	sbt->sasi = ASI_PRIMARY;
783 	sbt->sparc_bus_map = _sbus_bus_map;
784 	sbt->sparc_bus_mmap = sc->sc_bustag->sparc_bus_mmap;
785 	sbt->sparc_intr_establish = sbus_intr_establish;
786 	return (sbt);
787 }
788 
789 
790 bus_dma_tag_t
791 sbus_alloc_dma_tag(struct sbus_softc *sc, bus_dma_tag_t psdt)
792 {
793 	bus_dma_tag_t sdt;
794 
795 	sdt = (bus_dma_tag_t)malloc(sizeof(struct sparc_bus_dma_tag),
796 	    M_DEVBUF, M_NOWAIT | M_ZERO);
797 	if (sdt == NULL)
798 		/* Panic? */
799 		return (psdt);
800 
801 	sdt->_cookie = sc;
802 	sdt->_parent = psdt;
803 	sdt->_dmamap_create	= sbus_dmamap_create;
804 	sdt->_dmamap_destroy	= iommu_dvmamap_destroy;
805 	sdt->_dmamap_load	= iommu_dvmamap_load;
806 	sdt->_dmamap_load_raw	= iommu_dvmamap_load_raw;
807 	sdt->_dmamap_unload	= iommu_dvmamap_unload;
808 	sdt->_dmamap_sync	= iommu_dvmamap_sync;
809 	sdt->_dmamem_alloc	= iommu_dvmamem_alloc;
810 	sdt->_dmamem_free	= iommu_dvmamem_free;
811 	return (sdt);
812 }
813 
814 int
815 sbus_dmamap_create(bus_dma_tag_t t, bus_dma_tag_t t0, bus_size_t size,
816     int nsegments, bus_size_t maxsegsz, bus_size_t boundary, int flags,
817     bus_dmamap_t *dmamp)
818 {
819 	struct sbus_softc *sc = t->_cookie;
820 
821 	/* Disallow DMA on secondary SBuses for now */
822 	if (sc != sc->sc_master)
823 		return (EINVAL);
824 
825         return (iommu_dvmamap_create(t, t0, &sc->sc_sb, size, nsegments,
826 	    maxsegsz, boundary, flags, dmamp));
827 }
828