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