xref: /netbsd/sys/arch/sparc64/dev/upa.c (revision bf9ec67e)
1 /*	$NetBSD: upa.c,v 1.9 2002/05/16 20:05:39 wiz Exp $ */
2 
3 /*-
4  * Copyright (c) 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Paul Kranenburg.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Copyright (c) 1992, 1993
41  *	The Regents of the University of California.  All rights reserved.
42  *
43  * This software was developed by the Computer Systems Engineering group
44  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
45  * contributed to Berkeley.
46  *
47  * All advertising materials mentioning features or use of this software
48  * must display the following acknowledgement:
49  *	This product includes software developed by the University of
50  *	California, Lawrence Berkeley Laboratory.
51  *
52  * Redistribution and use in source and binary forms, with or without
53  * modification, are permitted provided that the following conditions
54  * are met:
55  * 1. Redistributions of source code must retain the above copyright
56  *    notice, this list of conditions and the following disclaimer.
57  * 2. Redistributions in binary form must reproduce the above copyright
58  *    notice, this list of conditions and the following disclaimer in the
59  *    documentation and/or other materials provided with the distribution.
60  * 3. All advertising materials mentioning features or use of this software
61  *    must display the following acknowledgement:
62  *	This product includes software developed by the University of
63  *	California, Berkeley and its contributors.
64  * 4. Neither the name of the University nor the names of its contributors
65  *    may be used to endorse or promote products derived from this software
66  *    without specific prior written permission.
67  *
68  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
69  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
70  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
71  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
72  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
73  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
74  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
75  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
76  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
77  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
78  * SUCH DAMAGE.
79  *
80  *	@(#)sbus.c	8.1 (Berkeley) 6/11/93
81  */
82 
83 /* #define DEBUG_1 */
84 
85 /*
86  * UPA bus stuff.
87  */
88 
89 #include <sys/param.h>
90 #include <sys/malloc.h>
91 #include <sys/systm.h>
92 #include <sys/device.h>
93 
94 #include <machine/bus.h>
95 #include <sparc64/dev/upavar.h>
96 
97 #include <machine/autoconf.h>
98 #include <machine/ctlreg.h>
99 #include <machine/cpu.h>
100 
101 
102 void upareset __P((int));
103 
104 static bus_space_tag_t upa_alloc_bustag __P((struct upa_softc *));
105 static int upa_get_intr __P((struct upa_softc *, int, int *));
106 static int upa_bus_mmap __P((bus_space_tag_t, bus_type_t, bus_addr_t,
107 			      int, bus_space_handle_t *));
108 static int _upa_bus_map __P((
109 		bus_space_tag_t,
110 		bus_type_t,		/*slot*/
111 		bus_addr_t,		/*offset*/
112 		bus_size_t,		/*size*/
113 		int,			/*flags*/
114 		vaddr_t,		/*preferred virtual address */
115 		bus_space_handle_t *));
116 static void *upa_intr_establish __P((
117 		bus_space_tag_t,
118 		int,			/*level*/
119 		int,			/*flags*/
120 		int (*) __P((void *)),	/*handler*/
121 		void *));		/*handler arg*/
122 
123 
124 /* autoconfiguration driver */
125 int	upa_match_mainbus __P((struct device *, struct cfdata *, void *));
126 void	upa_attach_mainbus __P((struct device *, struct device *, void *));
127 
128 struct cfattach upa_ca = {
129 	sizeof(struct upa_softc), upa_match, upa_attach
130 };
131 
132 extern struct cfdriver upa_cd;
133 
134 
135 /*
136  * Print the location of some upa-attached device (called just
137  * before attaching that device).  If `upa' is not NULL, the
138  * device was found but not configured; print the upa as well.
139  * Return UNCONF (config_find ignores this if the device was configured).
140  */
141 int
142 upa_print(args, busname)
143 	void *args;
144 	const char *busname;
145 {
146 	struct upa_attach_args *ua = args;
147 
148 	if (busname)
149 		printf("%s at %s", ua->ua_name, busname);
150 	if (ua->ua_interrupts) {
151 		int level = ua->ua_pri;
152 		struct upa_softc *sc =
153 			(struct upa_softc *) ua->ua_bustag->cookie;
154 
155 		printf(" interrupt %x", ua->ua_interrupts);
156 	}
157 	return (UNCONF);
158 }
159 
160 int
161 upa_match(parent, cf, aux)
162 	struct device *parent;
163 	struct cfdata *cf;
164 	void *aux;
165 {
166 	struct mainbus_attach_args *ma = aux;
167 
168 	return (strcmp(cf->cf_driver->cd_name, ma->ma_name) == 0);
169 }
170 
171 int
172 upa_match_iommu(parent, cf, aux)
173 	struct device *parent;
174 	struct cfdata *cf;
175 	void *aux;
176 {
177 	struct iommu_attach_args *ia = aux;
178 
179 	if (CPU_ISSUN4)
180 		return (0);
181 
182 	return (strcmp(cf->cf_driver->cd_name, ia->iom_name) == 0);
183 }
184 
185 int
186 upa_match_xbox(parent, cf, aux)
187 	struct device *parent;
188 	struct cfdata *cf;
189 	void *aux;
190 {
191 	struct xbox_attach_args *xa = aux;
192 
193 	if (CPU_ISSUN4)
194 		return (0);
195 
196 	return (strcmp(cf->cf_driver->cd_name, xa->xa_name) == 0);
197 }
198 
199 /*
200  * Attach an Upa.
201  */
202 void
203 upa_attach_mainbus(parent, self, aux)
204 	struct device *parent;
205 	struct device *self;
206 	void *aux;
207 {
208 	struct upa_softc *sc = (struct upa_softc *)self;
209 	struct mainbus_attach_args *ma = aux;
210 	int node = ma->ma_node;
211 
212 	/*
213 	 * XXX there is only one Upa, for now -- do not know how to
214 	 * address children on others
215 	 */
216 	if (sc->sc_dev.dv_unit > 0) {
217 		printf(" unsupported\n");
218 		return;
219 	}
220 
221 	sc->sc_bustag = ma->ma_bustag;
222 	sc->sc_dmatag = ma->ma_dmatag;
223 
224 	/* Setup interrupt translation tables */
225 	sc->sc_intr2ipl = CPU_ISSUN4C
226 				? intr_upa2ipl_4c
227 				: intr_upa2ipl_4m;
228 
229 	/*
230 	 * Record clock frequency for synchronous SCSI.
231 	 * IS THIS THE CORRECT DEFAULT??
232 	 */
233 	sc->sc_clockfreq = PROM_getpropint(node, "clock-frequency", 25*1000*1000);
234 	printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq));
235 
236 	upa_attach(sc, "upa", node, NULL);
237 }
238 
239 void
240 upa_attach_iommu(parent, self, aux)
241 	struct device *parent;
242 	struct device *self;
243 	void *aux;
244 {
245 	struct upa_softc *sc = (struct upa_softc *)self;
246 	struct iommu_attach_args *ia = aux;
247 	int node = ia->iom_node;
248 
249 	sc->sc_bustag = ia->iom_bustag;
250 	sc->sc_dmatag = ia->iom_dmatag;
251 
252 	/* Setup interrupt translation tables */
253 	sc->sc_intr2ipl = CPU_ISSUN4C ? intr_upa2ipl_4c : intr_upa2ipl_4m;
254 
255 	/*
256 	 * Record clock frequency for synchronous SCSI.
257 	 * IS THIS THE CORRECT DEFAULT??
258 	 */
259 	sc->sc_clockfreq = PROM_getpropint(node, "clock-frequency", 25*1000*1000);
260 	printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq));
261 
262 	upa_attach(sc, "upa", node, NULL);
263 }
264 
265 void
266 upa_attach_xbox(parent, self, aux)
267 	struct device *parent;
268 	struct device *self;
269 	void *aux;
270 {
271 	struct upa_softc *sc = (struct upa_softc *)self;
272 	struct xbox_attach_args *xa = aux;
273 	int node = xa->xa_node;
274 
275 	sc->sc_bustag = xa->xa_bustag;
276 	sc->sc_dmatag = xa->xa_dmatag;
277 
278 	/* Setup interrupt translation tables */
279 	sc->sc_intr2ipl = CPU_ISSUN4C ? intr_upa2ipl_4c : intr_upa2ipl_4m;
280 
281 	/*
282 	 * Record clock frequency for synchronous SCSI.
283 	 * IS THIS THE CORRECT DEFAULT??
284 	 */
285 	sc->sc_clockfreq = PROM_getpropint(node, "clock-frequency", 25*1000*1000);
286 	printf(": clock = %s MHz\n", clockfreq(sc->sc_clockfreq));
287 
288 	upa_attach(sc, "upa", node, NULL);
289 }
290 
291 void
292 upa_attach(sc, busname, busnode, specials)
293 	struct upa_softc *sc;
294 	char *busname;
295 	int busnode;
296 	const char * const *specials;
297 {
298 	int node0, node, error;
299 	const char *sp;
300 	const char *const *ssp;
301 	bus_space_tag_t sbt;
302 	struct upa_attach_args ua;
303 
304 	sbt = upa_alloc_bustag(sc);
305 
306 	/*
307 	 * Get the Upa burst transfer size if burst transfers are supported
308 	 */
309 	sc->sc_burst = PROM_getpropint(busnode, "burst-sizes", 0);
310 
311 	/*
312 	 * Collect address translations from the OBP.
313 	 */
314 	error = PROM_getprop(busnode, "ranges", sizeof(struct rom_range),
315 			 &sc->sc_nrange, (void **)&sc->sc_range);
316 	switch (error) {
317 	case 0:
318 		break;
319 	case ENOENT:
320 		/* Fall back to our own `range' construction */
321 		sc->sc_range = upa_translations;
322 		sc->sc_nrange =
323 			sizeof(upa_translations)/sizeof(upa_translations[0]);
324 		break;
325 	default:
326 		panic("%s: error getting ranges property", sc->sc_dev.dv_xname);
327 	}
328 
329 /* WARNING -- this stuff needs to be set somewhere */
330 	sc->sc_sysio = (struct sysioreg*) ra->ra_vaddr;		/* Use prom mapping for sysio. */
331 	sc->sc_ign = ra->ra_interrupt[0] & INTMAP_IGN;		/* Find interrupt group no */
332 
333 
334 	/*
335 	 * Setup the iommu.
336 	 *
337 	 * The sun4u iommu is part of the UPA controller so we will
338 	 * deal with it here.  We could try to fake a device node so
339 	 * we can eventually share it with the PCI bus run by psyco,
340 	 * but I don't want to get into that sort of cruft.
341 	 */
342 #ifdef NOTDEF_DEBUG
343 	{
344 		/* Probe the iommu */
345 		int64_t cr, tsb;
346 
347 		printf("\niommu regs at: cr=%x tsb=%x flush=%x\n", &sc->sc_sysio->sys_iommu.iommu_cr,
348 		       &sc->sc_sysio->sys_iommu.iommu_tsb, &sc->sc_sysio->sys_iommu.iommu_flush);
349 		cr = sc->sc_sysio->sys_iommu.iommu_cr;
350 		tsb = sc->sc_sysio->sys_iommu.iommu_tsb;
351 		printf("iommu cr=%x:%x tsb=%x:%x\n", (long)(cr>>32), (long)cr, (long)(tsb>>32), (long)tsb);
352 		delay(1000000); /* 1 s */
353 	}
354 #endif
355 
356 	/*
357 	 * All IOMMUs will share the same TSB which is allocated in pmap_bootstrap.
358 	 *
359 	 * This makes device management easier.
360 	 */
361 	sc->sc_tsbsize = iotsbsize;
362 	sc->sc_tsb = iotsb;
363 	sc->sc_ptsb = iotsbp;
364 #if 0
365 	/* Need to do 64-bit stores */
366 	sc->sc_sysio->sys_iommu.iommu_cr = (IOMMUCR_TSB1K|IOMMUCR_8KPG|IOMMUCR_EN);
367 	sc->sc_sysio->sys_iommu.iommu_tsb = sc->sc_ptsb;
368 #else
369 	stxa(&sc->sc_sysio->sys_iommu.iommu_cr,ASI_NUCLEUS,(IOMMUCR_TSB1K|IOMMUCR_8KPG|IOMMUCR_EN));
370 	stxa(&sc->sc_sysio->sys_iommu.iommu_tsb,ASI_NUCLEUS,sc->sc_ptsb);
371 #endif
372 	/*
373 	 * Loop through ROM children, fixing any relative addresses
374 	 * and then configuring each device.
375 	 * `specials' is an array of device names that are treated
376 	 * specially:
377 	 */
378 	node0 = firstchild(busnode);
379 	for (ssp = specials ; ssp != NULL && *(sp = *ssp) != 0; ssp++) {
380 		if ((node = findnode(node0, sp)) == 0) {
381 			panic("could not find %s amongst %s devices",
382 				sp, busname);
383 		}
384 
385 		if (upa_setup_attach_args(sc, sbt, sc->sc_dmatag,
386 					   node, &ua) != 0) {
387 			panic("upa_attach: %s: incomplete", sp);
388 		}
389 		(void) config_found(&sc->sc_dev, (void *)&ua, upa_print);
390 	}
391 
392 	for (node = node0; node; node = nextsibling(node)) {
393 		char *name = PROM_getpropstring(node, "name");
394 		for (ssp = specials, sp = NULL;
395 		     ssp != NULL && (sp = *ssp) != NULL;
396 		     ssp++)
397 			if (strcmp(name, sp) == 0)
398 				break;
399 
400 		if (sp != NULL)
401 			/* Already configured as an "early" device */
402 			continue;
403 
404 <<<<<<<<<<<<<< variant A
405 		upa_translate(self, &oca);
406 		oca.ca_bustype = BUS_UPA;
407 		/* Now we need to enable this interrupt if a handler has been registered */
408 		if( config_found(&sc->sc_dev, (void *)&oca, upa_print) != NULL )
409 			for( i=0; i<oca.ca_ra.ra_ninterrupt; i++) {
410 #ifdef IRQEN_DEBUG
411 				printf("\nupa: intr[%d]%x: %x\n", i, oca.ca_ra.ra_interrupt[i],
412 				       intrlev[oca.ca_ra.ra_interrupt[i]]);
413 #endif
414 				if( intrlev[oca.ca_ra.ra_interrupt[i]] ) {
415 					/* Hunt for proper register UGH! */
416 #ifdef IRQEN_DEBUG
417 					printf("Hunting for IRQ...\n");
418 #endif
419 					for( intrptr=&sc->sc_sysio->scsi_int_map;
420 					     intrptr < &sc->sc_sysio->reserved_int_map &&
421 						     ((intrmap=*intrptr)&INTMAP_INR)
422 						     != oca.ca_ra.ra_interrupt[i];
423 					     intrptr++);
424 					if((intrmap&INTMAP_INR) ==
425 					   oca.ca_ra.ra_interrupt[i]) {
426 #ifdef IRQEN_DEBUG
427 						printf("Found %x IRQ as %x:%x in slot\n",
428 						       oca.ca_ra.ra_interrupt[i], (int)(intrmap>>32), (int)intrmap,
429 						       intrptr - &sc->sc_sysio->scsi_int_map);
430 #endif
431 						/* Enable the interrupt */
432 						intrmap |= INTMAP_V;
433 						stxa(intrptr, ASI_NUCLEUS, intrmap);
434 						/* Register the map and clear intr registers */
435 						intrlev[oca.ca_ra.ra_interrupt[i]]->ih_map = intrptr;
436 						intrlev[oca.ca_ra.ra_interrupt[i]]->ih_clr =
437 							&sc->sc_sysio->scsi_clr_int +
438 							(intrptr - &sc->sc_sysio->scsi_int_map);
439 					}
440 				}
441 			}
442 #ifdef IRQEN_DEBUG
443 		for( i=0; i<140000000; i++);
444 #endif
445 >>>>>>>>>>>>>> variant B
446 		if (upa_setup_attach_args(sc, sbt, sc->sc_dmatag,
447 					   node, bp, &ua) != 0) {
448 			printf("upa_attach: %s: incomplete\n", name);
449 			continue;
450 		}
451 		(void) config_found(&sc->sc_dev, (void *)&ua, upa_print);
452 ======= end of combination
453 	}
454 }
455 
456 int
457 upa_setup_attach_args(sc, bustag, dmatag, node, ua)
458 	struct upa_softc	*sc;
459 	bus_space_tag_t		bustag;
460 	bus_dma_tag_t		dmatag;
461 	int			node;
462 	struct upa_attach_args	*ua;
463 {
464 	struct	rom_reg romreg;
465 	int	base;
466 	int	error;
467 
468 	bzero(ua, sizeof(struct upa_attach_args));
469 	ua->ua_name = PROM_getpropstring(node, "name");
470 	ua->ua_bustag = bustag;
471 	ua->ua_dmatag = dmatag;
472 	ua->ua_node = node;
473 
474 	if ((error = PROM_getprop_reg1(node, &romreg)) != 0)
475 		return (error);
476 
477 	/* We pass only the first "reg" property */
478 	base = (int)romreg.rr_paddr;
479 	if (UPA_ABS(base)) {
480 		ua->ua_slot = UPA_ABS_TO_SLOT(base);
481 		ua->ua_offset = UPA_ABS_TO_OFFSET(base);
482 	} else {
483 		ua->ua_slot = romreg.rr_iospace;
484 		ua->ua_offset = base;
485 	}
486 	ua->ua_size = romreg.rr_len;
487 
488 	if ((error = upa_get_intr(sc, node, &ua->ua_pri)) != 0)
489 		return (error);
490 
491 	if ((error = PROM_getprop_address1(node, &ua->ua_promvaddr)) != 0)
492 		return (error);
493 
494 	return (0);
495 }
496 
497 int
498 _upa_bus_map(t, btype, offset, size, flags, vaddr, hp)
499 	bus_space_tag_t t;
500 	bus_type_t btype;
501 	bus_addr_t offset;
502 	bus_size_t size;
503 	int	flags;
504 	vaddr_t vaddr;
505 	bus_space_handle_t *hp;
506 {
507 	struct upa_softc *sc = t->cookie;
508 	int slot = btype;
509 	int i;
510 
511 	for (i = 0; i < sc->sc_nrange; i++) {
512 		bus_addr_t paddr;
513 		bus_type_t iospace;
514 
515 		if (sc->sc_range[i].cspace != slot)
516 			continue;
517 
518 		/* We've found the connection to the parent bus */
519 		paddr = sc->sc_range[i].poffset + offset;
520 		iospace = sc->sc_range[i].pspace;
521 		return (bus_space_map2(sc->sc_bustag, iospace, paddr,
522 					size, flags, vaddr, hp));
523 	}
524 
525 	return (EINVAL);
526 }
527 
528 int
529 upa_bus_mmap(t, btype, paddr, flags, hp)
530 	bus_space_tag_t t;
531 	bus_type_t btype;
532 	bus_addr_t paddr;
533 	int flags;
534 	bus_space_handle_t *hp;
535 {
536 	int slot = (int)btype;
537 	int offset = (int)paddr;
538 	struct upa_softc *sc = t->cookie;
539 	int i;
540 
541 	for (i = 0; i < sc->sc_nrange; i++) {
542 		bus_addr_t paddr;
543 		bus_addr_t iospace;
544 
545 		if (sc->sc_range[i].cspace != slot)
546 			continue;
547 
548 		paddr = sc->sc_range[i].poffset + offset;
549 		iospace = (bus_addr_t)sc->sc_range[i].pspace;
550 		return (bus_space_mmap(sc->sc_bustag, iospace, paddr,
551 				       flags, hp));
552 	}
553 
554 	return (-1);
555 }
556 
557 
558 /*
559  * Each attached device calls upa_establish after it initializes
560  * its upadev portion.
561  */
562 void
563 upa_establish(sd, dev)
564 	register struct upadev *sd;
565 	register struct device *dev;
566 {
567 	register struct upa_softc *sc;
568 	register struct device *curdev;
569 
570 	/*
571 	 * We have to look for the upa by name, since it is not necessarily
572 	 * our immediate parent (i.e. sun4m /iommu/upa/espdma/esp)
573 	 * We don't just use the device structure of the above-attached
574 	 * upa, since we might (in the future) support multiple upa's.
575 	 */
576 	for (curdev = dev->dv_parent; ; curdev = curdev->dv_parent) {
577 		if (!curdev || !curdev->dv_xname)
578 			panic("upa_establish: can't find upa parent for %s",
579 			      sd->sd_dev->dv_xname
580 					? sd->sd_dev->dv_xname
581 					: "<unknown>" );
582 
583 		if (strncmp(curdev->dv_xname, "upa", 4) == 0)
584 			break;
585 	}
586 	sc = (struct upa_softc *) curdev;
587 
588 	sd->sd_dev = dev;
589 	sd->sd_bchain = sc->sc_sbdev;
590 	sc->sc_sbdev = sd;
591 }
592 
593 /*
594  * Reset the given upa. (???)
595  */
596 void
597 upareset(upa)
598 	int upa;
599 {
600 	register struct upadev *sd;
601 	struct upa_softc *sc = upa_cd.cd_devs[upa];
602 	struct device *dev;
603 
604 	printf("reset %s:", sc->sc_dev.dv_xname);
605 	for (sd = sc->sc_sbdev; sd != NULL; sd = sd->sd_bchain) {
606 		if (sd->sd_reset) {
607 			dev = sd->sd_dev;
608 			(*sd->sd_reset)(dev);
609 			printf(" %s", dev->dv_xname);
610 		}
611 	}
612 #if 0
613 	/* Reload iommu regs */
614 	sc->sc_sysio->sys_iommu.iommu_cr = (IOMMUCR_TSB1K|IOMMUCR_8KPG|IOMMUCR_EN);
615 	sc->sc_sysio->sys_iommu.iommu_tsb = sc->sc_ptsb;
616 #else
617 	/* Reload iommu regs */
618 	stxa(&sc->sc_sysio->sys_iommu.iommu_cr,ASI_NUCLEUS,(IOMMUCR_TSB1K|IOMMUCR_8KPG|IOMMUCR_EN));
619 	stxa(&sc->sc_sysio->sys_iommu.iommu_tsb,ASI_NUCLEUS,sc->sc_ptsb);
620 #endif
621 }
622 
623 /*
624  * Here are the iommu control routines.
625  */
626 void
627 upa_enter(va, pa)
628 	vaddr_t va;
629 	paddr_t pa;
630 {
631 	struct upa_softc *sc = upa_sc;
632 	int64_t tte;
633 
634 #ifdef DIAGNOSTIC
635 	if (va < sc->sc_dvmabase)
636 		panic("upa_enter: va 0x%x not in DVMA space",va);
637 #endif
638 
639 #if 1
640 	/* Streaming */
641 	tte = MAKEIOTTE(pa, 1, 1, 1);
642 #else
643 	/* Consistent */
644 	tte = MAKEIOTTE(pa, 1, 1, 0);
645 #endif
646 
647 	sc->sc_tsb[IOTSBSLOT(va,sc->sc_tsbsize)] = tte;
648 #if 0
649 	sc->sc_sysio->sys_iommu.iommu_flush = va;
650 #else
651 	stxa(&sc->sc_sysio->sys_iommu.iommu_flush,ASI_NUCLEUS,va);
652 #endif
653 #ifdef DEBUG_1
654 	printf("upa_enter: added xlation va %x pa %x:%x TSB[%x]=%x:%x\n",
655 	       va, (int)(pa>>32), (int)pa, IOTSBSLOT(va,sc->sc_tsbsize), (int)(tte>>32), (int)tte);
656 #endif
657 }
658 /*
659  * upa_clear: clears mappings created by upa_enter
660  */
661 void
662 upa_remove(va, len)
663 	register vaddr_t va;
664 	register u_int len;
665 {
666 	register struct upa_softc *sc = upa_sc;
667 
668 #ifdef DIAGNOSTIC
669 	if (va < sc->sc_dvmabase)
670 		panic("upa_remove: va 0x%x not in DVMA space", va);
671 #endif
672 
673 	while (len > 0) {
674 		static volatile int flushdone;
675 		int flushtimeout;
676 		extern u_int ksegv;
677 		extern u_int64_t ksegp;
678 
679 		/*
680 		 * Streaming buffer flushes:
681 		 *
682 		 *   1 Tell strbuf to flush by storing va to strbuf_pgflush
683 		 * If we're not on a cache line boundary (64-bits):
684 		 *   2 Store 0 in flag
685 		 *   3 Store pointer to flag in flushsync
686 		 *   4 wait till flushsync becomes 0x1
687 		 *
688 		 * If it takes more than .5 sec, something went wrong.
689 		 */
690 #if 0
691 		sc->sc_sysio->sys_strbuf.strbuf_pgflush = va;
692 #else
693 		stxa(&(sc->sc_sysio->sys_strbuf.strbuf_pgflush), ASI_NUCLEUS, va);
694 #endif
695 		if( len < NBPG && ((va+len) & 0x3f) ) {
696 			flushdone = 0;
697 			/*
698 			 * KLUGE ALERT KLUGE ALERT
699 			 *
700 			 * In order not to bother with pmap_extract() to do the vtop
701 			 * translation, flushdone is a static variable that resides in
702 			 * the kernel's 4MB locked TTE.  This means that this routine
703 			 * is NOT re-entrant.  Since we're single-threaded and poll
704 			 * on this value, this is currently not a problem.
705 			 */
706 #ifdef DEBUG_1
707 			printf("upa_remove: flush = %x at va = %x pa = %x\n", flushdone, &flushdone, (long)(((long)&flushdone) - ksegv + ksegp));
708 #endif
709 #if 0
710 			sc->sc_sysio->sys_strbuf.strbuf_flushsync = (long)(((long)&flushdone) - ksegv + ksegp);
711 #else
712 			stxa(&sc->sc_sysio->sys_strbuf.strbuf_flushsync, ASI_NUCLEUS, (long)(((long)&flushdone) - ksegv + ksegp));
713 #endif
714 			flushtimeout = 250000000; /* 1 sec on a 250MHz machine */
715 			while( !flushdone && flushtimeout--) membar_sync();
716 #ifdef DIAGNOSTIC
717 			if( !flushdone )
718 				printf("upa_remove: flush timeout %x at %x\n", flushdone, (long)(((long)&flushdone) - ksegv + ksegp)); /* panic? */
719 #endif
720 		}
721 		sc->sc_tsb[IOTSBSLOT(va,sc->sc_tsbsize)] = 0;
722 #if 0
723 		sc->sc_sysio->sys_iommu.iommu_flush = va;
724 #else
725 		stxa(&sc->sc_sysio->sys_iommu.iommu_flush, ASI_NUCLEUS, va);
726 #endif
727 		len -= NBPG;
728 		va += NBPG;
729 	}
730 }
731 
732 
733 /*
734  * Get interrupt attributes for an Upa device.
735  */
736 int
737 upa_get_intr(sc, node, ip)
738 	struct upa_softc *sc;
739 	int node;
740 	int *ip;
741 {
742 	struct rom_intr *rip;
743 	int *ipl;
744 	int n;
745 
746 	/*
747 	 * The `interrupts' property contains the Upa interrupt level.
748 	 */
749 	ipl = NULL;
750 	if (PROM_getprop(node, "interrupts", sizeof(int), &n, (void **)&ipl) == 0) {
751 		*ip = ipl[0];
752 		free(ipl, M_DEVBUF);
753 		return (0);
754 	}
755 
756 	/*
757 	 * Fall back on `intr' property.
758 	 */
759 	rip = NULL;
760 	switch (PROM_getprop(node, "intr", sizeof(*rip), &n, (void **)&rip)) {
761 	case 0:
762 		*ip = (rip[0].int_pri & 0xf) | UPA_INTR_COMPAT;
763 		free(rip, M_DEVBUF);
764 		return (0);
765 	case ENOENT:
766 		*ip = 0;
767 		return (0);
768 	}
769 
770 	return (-1);
771 }
772 
773 
774 /*
775  * Install an interrupt handler for an Upa device.
776  */
777 void *
778 upa_intr_establish(t, level, flags, handler, arg)
779 	bus_space_tag_t t;
780 	int level;
781 	int flags;
782 	int (*handler) __P((void *));
783 	void *arg;
784 {
785 	struct upa_softc *sc = t->cookie;
786 	struct intrhand *ih;
787 	int ipl;
788 
789 	ih = (struct intrhand *)
790 		malloc(sizeof(struct intrhand), M_DEVBUF, M_NOWAIT);
791 	if (ih == NULL)
792 		return (NULL);
793 
794 	if ((flags & BUS_INTR_ESTABLISH_SOFTINTR) != 0)
795 		ipl = level;
796 	else if ((level & UPA_INTR_COMPAT) != 0)
797 		ipl = level & ~UPA_INTR_COMPAT;
798 	else
799 		ipl = sc->sc_intr2ipl[level];
800 
801 	ih->ih_fun = handler;
802 	ih->ih_arg = arg;
803 	intr_establish(ipl, ih);
804 	return (ih);
805 }
806 
807 static bus_space_tag_t
808 upa_alloc_bustag(sc)
809 	struct upa_softc *sc;
810 {
811 	bus_space_tag_t sbt;
812 
813 	sbt = (bus_space_tag_t)
814 		malloc(sizeof(struct sparc_bus_space_tag), M_DEVBUF, M_NOWAIT);
815 	if (sbt == NULL)
816 		return (NULL);
817 
818 	bzero(sbt, sizeof *sbt);
819 	sbt->cookie = sc;
820 	sbt->parent = sc->sc_bustag;
821 	sbt->sparc_bus_map = _upa_bus_map;
822 	sbt->sparc_bus_mmap = upa_bus_mmap;
823 	sbt->sparc_intr_establish = upa_intr_establish;
824 	return (sbt);
825 }
826