Home | History | Annotate | Line # | Download | only in dev
obio.c revision 1.31
      1 /*	$NetBSD: obio.c,v 1.31 1997/04/08 20:08:20 pk Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1993, 1994 Theo de Raadt
      5  * Copyright (c) 1995 Paul Kranenburg
      6  * All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by Theo de Raadt.
     19  * 4. The name of the author may not be used to endorse or promote products
     20  *    derived from this software without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     27  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     31  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     32  */
     33 
     34 #include <sys/param.h>
     35 #include <sys/systm.h>
     36 #include <sys/device.h>
     37 #include <sys/malloc.h>
     38 
     39 #ifdef DEBUG
     40 #include <sys/proc.h>
     41 #include <sys/syslog.h>
     42 #endif
     43 
     44 #include <vm/vm.h>
     45 
     46 #include <machine/autoconf.h>
     47 #include <machine/pmap.h>
     48 #include <machine/oldmon.h>
     49 #include <machine/cpu.h>
     50 #include <machine/ctlreg.h>
     51 #include <sparc/sparc/asm.h>
     52 #include <sparc/sparc/vaddrs.h>
     53 #include <sparc/sparc/cpuvar.h>
     54 #include <sparc/dev/sbusvar.h>
     55 
     56 struct bus_softc {
     57 	union {
     58 		struct	device scu_dev;		/* base device */
     59 		struct	sbus_softc scu_sbus;	/* obio is another sbus slot */
     60 	} bu;
     61 #define sc_dev	bu.scu_dev
     62 };
     63 
     64 /* autoconfiguration driver */
     65 static int	busmatch __P((struct device *, struct cfdata *, void *));
     66 static void	obioattach __P((struct device *, struct device *, void *));
     67 static void	vmesattach __P((struct device *, struct device *, void *));
     68 static void	vmelattach __P((struct device *, struct device *, void *));
     69 
     70 int		busprint __P((void *, const char *));
     71 static int	busattach __P((struct device *, struct cfdata *, void *, int));
     72 void *		bus_map __P((struct rom_reg *, int, int));
     73 int		obio_scan __P((struct device *, struct cfdata *, void *));
     74 int 		vmes_scan __P((struct device *, struct cfdata *, void *));
     75 int 		vmel_scan __P((struct device *, struct cfdata *, void *));
     76 int 		vmeintr __P((void *));
     77 
     78 struct cfattach obio_ca = {
     79 	sizeof(struct bus_softc), busmatch, obioattach
     80 };
     81 
     82 struct cfdriver obio_cd = {
     83 	NULL, "obio", DV_DULL
     84 };
     85 
     86 struct cfattach vmel_ca = {
     87 	sizeof(struct bus_softc), busmatch, vmelattach
     88 };
     89 
     90 struct cfdriver vmel_cd = {
     91 	NULL, "vmel", DV_DULL
     92 };
     93 
     94 struct cfattach vmes_ca = {
     95 	sizeof(struct bus_softc), busmatch, vmesattach
     96 };
     97 
     98 struct cfdriver vmes_cd = {
     99 	NULL, "vmes", DV_DULL
    100 };
    101 
    102 struct intrhand **vmeints;
    103 
    104 
    105 int
    106 busmatch(parent, cf, aux)
    107 	struct device *parent;
    108 	struct cfdata *cf;
    109 	void *aux;
    110 {
    111 	register struct confargs *ca = aux;
    112 	register struct romaux *ra = &ca->ca_ra;
    113 
    114 	if (CPU_ISSUN4M)
    115 		return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0);
    116 
    117 	if (!CPU_ISSUN4)
    118 		return (0);
    119 
    120 	return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0);
    121 }
    122 
    123 int
    124 busprint(args, obio)
    125 	void *args;
    126 	const char *obio;
    127 {
    128 	register struct confargs *ca = args;
    129 
    130 	if (ca->ca_ra.ra_name == NULL)
    131 		ca->ca_ra.ra_name = "<unknown>";
    132 
    133 	if (obio)
    134 		printf("[%s at %s]", ca->ca_ra.ra_name, obio);
    135 
    136 	printf(" addr %p", ca->ca_ra.ra_paddr);
    137 
    138 	if (CPU_ISSUN4 && ca->ca_ra.ra_intr[0].int_vec != -1)
    139 		printf(" vec 0x%x", ca->ca_ra.ra_intr[0].int_vec);
    140 
    141 	return (UNCONF);
    142 }
    143 
    144 
    145 void
    146 obioattach(parent, self, args)
    147 	struct device *parent, *self;
    148 	void *args;
    149 {
    150 #if defined(SUN4M)
    151 	register struct bus_softc *sc = (struct bus_softc *)self;
    152 	struct confargs oca, *ca = args;
    153 	register struct romaux *ra = &ca->ca_ra;
    154 	register int node0, node;
    155 	register char *name;
    156 	register const char *sp;
    157 	const char *const *ssp;
    158 	int rlen;
    159 	extern int autoconf_nzs;
    160 
    161 	static const char *const special4m[] = {
    162 		/* find these first */
    163 		"eeprom",
    164 		"counter",
    165 #if 0 /* Not all sun4m's have an `auxio' */
    166 		"auxio",
    167 #endif
    168 		"",
    169 		/* place device to ignore here */
    170 		"interrupt",
    171 		NULL
    172 	};
    173 #endif
    174 
    175 	if (CPU_ISSUN4) {
    176 		if (self->dv_unit > 0) {
    177 			printf(" unsupported\n");
    178 			return;
    179 		}
    180 		printf("\n");
    181 
    182 		(void)config_search(obio_scan, self, args);
    183 		bus_untmp();
    184 	}
    185 
    186 #if defined(SUN4M)
    187 	if (!CPU_ISSUN4M)
    188 		return;
    189 
    190 	/*
    191 	 * There is only one obio bus (it is in fact one of the Sbus slots)
    192 	 * How about VME?
    193 	 */
    194 	if (sc->sc_dev.dv_unit > 0) {
    195 		printf(" unsupported\n");
    196 		return;
    197 	}
    198 
    199 	printf("\n");
    200 
    201 	if (ra->ra_bp != NULL && strcmp(ra->ra_bp->name, "obio") == 0)
    202 		oca.ca_ra.ra_bp = ra->ra_bp + 1;
    203 	else
    204 		oca.ca_ra.ra_bp = NULL;
    205 
    206 	node = ra->ra_node;
    207 	rlen = getproplen(node, "ranges");
    208 	if (rlen > 0) {
    209 		sc->bu.scu_sbus.sc_nrange = rlen / sizeof(struct rom_range);
    210 		sc->bu.scu_sbus.sc_range =
    211 			(struct rom_range *)malloc(rlen, M_DEVBUF, M_NOWAIT);
    212 		if (sc->bu.scu_sbus.sc_range == 0)
    213 			panic("obio: PROM ranges too large: %d", rlen);
    214 		(void)getprop(node, "ranges", sc->bu.scu_sbus.sc_range, rlen);
    215 	}
    216 
    217 	/*
    218 	 * Loop through ROM children, fixing any relative addresses
    219 	 * and then configuring each device.
    220 	 * We first do the crucial ones, such as eeprom, etc.
    221 	 */
    222 	node0 = firstchild(ra->ra_node);
    223 	for (ssp = special4m ; *(sp = *ssp) != 0; ssp++) {
    224 		if ((node = findnode(node0, sp)) == 0) {
    225 			printf("could not find %s amongst obio devices\n", sp);
    226 			panic(sp);
    227 		}
    228 		if (!romprop(&oca.ca_ra, sp, node))
    229 			continue;
    230 
    231 		sbus_translate(self, &oca);
    232 		oca.ca_bustype = BUS_OBIO;
    233 		(void) config_found(&sc->sc_dev, (void *)&oca, busprint);
    234 	}
    235 
    236 	for (node = node0; node; node = nextsibling(node)) {
    237 		name = getpropstring(node, "name");
    238 		for (ssp = special4m ; (sp = *ssp) != NULL; ssp++)
    239 			if (strcmp(name, sp) == 0)
    240 				break;
    241 
    242 		if (sp != NULL || !romprop(&oca.ca_ra, name, node))
    243 			continue;
    244 
    245 		if (strcmp(name, "zs") == 0)
    246 			/* XXX - see autoconf.c for this hack */
    247 			autoconf_nzs++;
    248 
    249 		/* Translate into parent address spaces */
    250 		sbus_translate(self, &oca);
    251 		oca.ca_bustype = BUS_OBIO;
    252 		(void) config_found(&sc->sc_dev, (void *)&oca, busprint);
    253 	}
    254 #endif
    255 }
    256 
    257 void
    258 vmesattach(parent, self, args)
    259 	struct device *parent, *self;
    260 	void *args;
    261 {
    262 	if (CPU_ISSUN4M || self->dv_unit > 0) {
    263 		printf(" unsupported\n");
    264 		return;
    265 	}
    266 	printf("\n");
    267 
    268 	if (vmeints == NULL) {
    269 		vmeints = (struct intrhand **)malloc(256 *
    270 		    sizeof(struct intrhand *), M_TEMP, M_NOWAIT);
    271 		bzero(vmeints, 256 * sizeof(struct intrhand *));
    272 	}
    273 	(void)config_search(vmes_scan, self, args);
    274 	bus_untmp();
    275 }
    276 
    277 void
    278 vmelattach(parent, self, args)
    279 	struct device *parent, *self;
    280 	void *args;
    281 {
    282 	if (CPU_ISSUN4M || self->dv_unit > 0) {
    283 		printf(" unsupported\n");
    284 		return;
    285 	}
    286 	printf("\n");
    287 
    288 	if (vmeints == NULL) {
    289 		vmeints = (struct intrhand **)malloc(256 *
    290 		    sizeof(struct intrhand *), M_TEMP, M_NOWAIT);
    291 		bzero(vmeints, 256 * sizeof(struct intrhand *));
    292 	}
    293 	(void)config_search(vmel_scan, self, args);
    294 	bus_untmp();
    295 }
    296 
    297 int
    298 busattach(parent, cf, args, bustype)
    299 	struct device *parent;
    300 	struct cfdata *cf;
    301 	void *args;
    302 	int bustype;
    303 {
    304 #if defined(SUN4)
    305 	register struct confargs *ca = args;
    306 	struct confargs oca;
    307 	caddr_t tmp;
    308 
    309 	if (bustype == BUS_OBIO && CPU_ISSUN4) {
    310 
    311 		/*
    312 		 * avoid sun4m entries which don't have valid PA's.
    313 		 * no point in even probing them.
    314 		 */
    315 		if (cf->cf_loc[0] == -1) return 0;
    316 
    317 		/*
    318 		 * On the 4/100 obio addresses must be mapped at
    319 		 * 0x0YYYYYYY, but alias higher up (we avoid the
    320 		 * alias condition because it causes pmap difficulties)
    321 		 * XXX: We also assume that 4/[23]00 obio addresses
    322 		 * must be 0xZYYYYYYY, where (Z != 0)
    323 		 */
    324 		if (cpuinfo.cpu_type == CPUTYP_4_100 &&
    325 		    (cf->cf_loc[0] & 0xf0000000))
    326 			return 0;
    327 		if (cpuinfo.cpu_type != CPUTYP_4_100 &&
    328 		    !(cf->cf_loc[0] & 0xf0000000))
    329 			return 0;
    330 	}
    331 
    332 	oca.ca_ra.ra_iospace = -1;
    333 	oca.ca_ra.ra_paddr = (void *)cf->cf_loc[0];
    334 	oca.ca_ra.ra_len = 0;
    335 	oca.ca_ra.ra_nreg = 1;
    336 	if (oca.ca_ra.ra_paddr)
    337 		tmp = (caddr_t)bus_tmp(oca.ca_ra.ra_paddr,
    338 		    bustype);
    339 	else
    340 		tmp = NULL;
    341 	oca.ca_ra.ra_vaddr = tmp;
    342 	oca.ca_ra.ra_intr[0].int_pri = cf->cf_loc[1];
    343 	if (bustype == BUS_VME16 || bustype == BUS_VME32)
    344 		oca.ca_ra.ra_intr[0].int_vec = cf->cf_loc[2];
    345 	else
    346 		oca.ca_ra.ra_intr[0].int_vec = -1;
    347 	oca.ca_ra.ra_nintr = 1;
    348 	oca.ca_ra.ra_name = cf->cf_driver->cd_name;
    349 	if (ca->ca_ra.ra_bp != NULL &&
    350 	  ((bustype == BUS_VME16 && strcmp(ca->ca_ra.ra_bp->name,"vmes") ==0) ||
    351 	   (bustype == BUS_VME32 && strcmp(ca->ca_ra.ra_bp->name,"vmel") ==0) ||
    352 	   (bustype == BUS_OBIO && strcmp(ca->ca_ra.ra_bp->name,"obio") == 0)))
    353 		oca.ca_ra.ra_bp = ca->ca_ra.ra_bp + 1;
    354 	else
    355 		oca.ca_ra.ra_bp = NULL;
    356 	oca.ca_bustype = bustype;
    357 
    358 	if ((*cf->cf_attach->ca_match)(parent, cf, &oca) == 0)
    359 		return 0;
    360 
    361 	/*
    362 	 * check if XXmatch routine replaced the temporary mapping with
    363 	 * a real mapping.   If not, then make sure we don't pass the
    364 	 * tmp mapping to the attach routine.
    365 	 */
    366 	if (oca.ca_ra.ra_vaddr == tmp)
    367 		oca.ca_ra.ra_vaddr = NULL; /* wipe out tmp address */
    368 	/*
    369 	 * the match routine will set "ra_len" if it wants us to
    370 	 * establish a mapping for it.
    371 	 * (which won't be seen on future XXmatch calls,
    372 	 * so not as useful as it seems.)
    373 	 */
    374 	if (oca.ca_ra.ra_len)
    375 		oca.ca_ra.ra_vaddr =
    376 		    bus_map(oca.ca_ra.ra_reg,
    377 		    oca.ca_ra.ra_len, oca.ca_bustype);
    378 
    379 	config_attach(parent, cf, &oca, busprint);
    380 	return 1;
    381 #else
    382 	return 0;
    383 #endif
    384 }
    385 
    386 int
    387 obio_scan(parent, child, args)
    388 	struct device *parent;
    389 	struct cfdata *child;
    390 	void *args;
    391 {
    392 	return busattach(parent, child, args, BUS_OBIO);
    393 }
    394 
    395 int
    396 vmes_scan(parent, child, args)
    397 	struct device *parent;
    398 	struct cfdata *child;
    399 	void *args;
    400 {
    401 	return busattach(parent, child, args, BUS_VME16);
    402 }
    403 
    404 int
    405 vmel_scan(parent, child, args)
    406 	struct device *parent;
    407 	struct cfdata *child;
    408 	void *args;
    409 {
    410 	return busattach(parent, child, args, BUS_VME32);
    411 }
    412 
    413 int pil_to_vme[] = {
    414 	-1,	/* pil 0 */
    415 	-1,	/* pil 1 */
    416 	1,	/* pil 2 */
    417 	2,	/* pil 3 */
    418 	-1,	/* pil 4 */
    419 	3,	/* pil 5 */
    420 	-1,	/* pil 6 */
    421 	4,	/* pil 7 */
    422 	-1,	/* pil 8 */
    423 	5,	/* pil 9 */
    424 	-1,	/* pil 10 */
    425 	6,	/* pil 11 */
    426 	-1,	/* pil 12 */
    427 	7,	/* pil 13 */
    428 	-1,	/* pil 14 */
    429 	-1,	/* pil 15 */
    430 };
    431 
    432 int
    433 vmeintr(arg)
    434 	void *arg;
    435 {
    436 	int level = (int)arg, vec;
    437 	struct intrhand *ih;
    438 	int i = 0;
    439 
    440 #ifdef DIAGNOSTIC
    441 	if (!CPU_ISSUN4) {
    442 		panic("vme: spurious interrupt");
    443 	}
    444 #endif
    445 
    446 	vec = ldcontrolb((caddr_t)
    447 	    (AC_VMEINTVEC | (pil_to_vme[level] << 1) | 1));
    448 	if (vec == -1) {
    449 		printf("vme: spurious interrupt\n");
    450 		return 0;
    451 	}
    452 
    453 	for (ih = vmeints[vec]; ih; ih = ih->ih_next)
    454 		if (ih->ih_fun)
    455 			i += (ih->ih_fun)(ih->ih_arg);
    456 	return (i);
    457 }
    458 
    459 void
    460 vmeintr_establish(vec, level, ih)
    461 	int vec, level;
    462 	struct intrhand *ih;
    463 {
    464 	struct intrhand *ihs;
    465 
    466 	if (!CPU_ISSUN4) {
    467 		panic("vmeintr_establish: not supported on cpu-type %d",
    468 		      cputyp);
    469 	}
    470 
    471 	if (vec == -1)
    472 		panic("vmeintr_establish: uninitialized vec\n");
    473 
    474 	if (vmeints[vec] == NULL)
    475 		vmeints[vec] = ih;
    476 	else {
    477 		for (ihs = vmeints[vec]; ihs->ih_next; ihs = ihs->ih_next)
    478 			;
    479 		ihs->ih_next = ih;
    480 	}
    481 
    482 	/* ensure the interrupt subsystem will call us at this level */
    483 	for (ihs = intrhand[level]; ihs; ihs = ihs->ih_next)
    484 		if (ihs->ih_fun == vmeintr)
    485 			return;
    486 
    487 	ihs = (struct intrhand *)malloc(sizeof(struct intrhand),
    488 	    M_TEMP, M_NOWAIT);
    489 	if (ihs == NULL)
    490 		panic("vme_addirq");
    491 	bzero(ihs, sizeof *ihs);
    492 	ihs->ih_fun = vmeintr;
    493 	ihs->ih_arg = (void *)level;
    494 	intr_establish(level, ihs);
    495 }
    496 
    497 #define	getpte(va)		lda(va, ASI_PTE)
    498 
    499 /*
    500  * If we can find a mapping that was established by the rom, use it.
    501  * Else, create a new mapping.
    502  */
    503 void *
    504 bus_map(pa, len, bustype)
    505 	struct rom_reg *pa;
    506 	int len;
    507 	int bustype;
    508 {
    509 	u_long	pf = (u_long)(pa->rr_paddr) >> PGSHIFT;
    510 	u_long	va, pte;
    511 	int pgtype = -1;
    512 
    513 	switch (bt2pmt[bustype]) {
    514 	case PMAP_OBIO:
    515 		pgtype = PG_OBIO;
    516 		break;
    517 	case PMAP_VME32:
    518 		pgtype = PG_VME32;
    519 		break;
    520 	case PMAP_VME16:
    521 		pgtype = PG_VME16;
    522 		break;
    523 	}
    524 
    525 	if (len <= NBPG) {
    526 		for (va = OLDMON_STARTVADDR; va < OLDMON_ENDVADDR; va += NBPG) {
    527 			pte = getpte(va);
    528 			if ((pte & PG_V) != 0 && (pte & PG_TYPE) == pgtype &&
    529 			    (pte & PG_PFNUM) == pf)
    530 				return ((void *)
    531 				    (va | ((u_long)pa->rr_paddr & PGOFSET)) );
    532 					/* note: preserve page offset */
    533 		}
    534 	}
    535 	return mapiodev(pa, 0, len, bustype);
    536 }
    537 
    538 void *
    539 bus_tmp(pa, bustype)
    540 	void *pa;
    541 	int bustype;
    542 {
    543 	vm_offset_t addr = (vm_offset_t)pa & ~PGOFSET;
    544 	int pmtype = bt2pmt[bustype];
    545 
    546 	pmap_enter(pmap_kernel(), TMPMAP_VA,
    547 		   addr | pmtype | PMAP_NC,
    548 		   VM_PROT_READ | VM_PROT_WRITE, 1);
    549 	return ((void *)(TMPMAP_VA | ((u_long) pa & PGOFSET)) );
    550 }
    551 
    552 void
    553 bus_untmp()
    554 {
    555 	pmap_remove(pmap_kernel(), TMPMAP_VA, TMPMAP_VA+NBPG);
    556 }
    557