obio.c revision 1.24
1/* $NetBSD: obio.c,v 1.24 1996/05/18 12:22:49 mrg 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/dev/sbusvar.h> 54 55struct bus_softc { 56 union { 57 struct device scu_dev; /* base device */ 58 struct sbus_softc scu_sbus; /* obio is another sbus slot */ 59 } bu; 60#define sc_dev bu.scu_dev 61}; 62 63/* autoconfiguration driver */ 64static int busmatch __P((struct device *, void *, void *)); 65static void obioattach __P((struct device *, struct device *, void *)); 66static void vmesattach __P((struct device *, struct device *, void *)); 67static void vmelattach __P((struct device *, struct device *, void *)); 68 69int busprint __P((void *, char *)); 70static int busattach __P((struct device *, void *, void *, int)); 71void * bus_map __P((struct rom_reg *, int, int)); 72int obio_scan __P((struct device *, void *, void *)); 73int vmes_scan __P((struct device *, void *, void *)); 74int vmel_scan __P((struct device *, void *, void *)); 75int vmeintr __P((void *)); 76 77struct cfattach obio_ca = { 78 sizeof(struct bus_softc), busmatch, obioattach 79}; 80 81struct cfdriver obio_cd = { 82 NULL, "obio", DV_DULL 83}; 84 85struct cfattach vmel_ca = { 86 sizeof(struct bus_softc), busmatch, vmelattach 87}; 88 89struct cfdriver vmel_cd = { 90 NULL, "vmel", DV_DULL 91}; 92 93struct cfattach vmes_ca = { 94 sizeof(struct bus_softc), busmatch, vmesattach 95}; 96 97struct cfdriver vmes_cd = { 98 NULL, "vmes", DV_DULL 99}; 100 101struct intrhand **vmeints; 102 103 104int 105busmatch(parent, vcf, aux) 106 struct device *parent; 107 void *vcf, *aux; 108{ 109 struct cfdata *cf = vcf; 110 register struct confargs *ca = aux; 111 register struct romaux *ra = &ca->ca_ra; 112 113 if (CPU_ISSUN4M) 114 return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0); 115 116 if (!CPU_ISSUN4) 117 return (0); 118 119 return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0); 120} 121 122int 123busprint(args, obio) 124 void *args; 125 char *obio; 126{ 127 register struct confargs *ca = args; 128 129 if (ca->ca_ra.ra_name == NULL) 130 ca->ca_ra.ra_name = "<unknown>"; 131 132 if (obio) 133 printf("[%s at %s]", ca->ca_ra.ra_name, obio); 134 135 printf(" addr %p", ca->ca_ra.ra_paddr); 136 137 if (CPU_ISSUN4 && ca->ca_ra.ra_intr[0].int_vec != -1) 138 printf(" vec 0x%x", ca->ca_ra.ra_intr[0].int_vec); 139 140 return (UNCONF); 141} 142 143 144void 145obioattach(parent, self, args) 146 struct device *parent, *self; 147 void *args; 148{ 149#if defined(SUN4M) 150 register struct bus_softc *sc = (struct bus_softc *)self; 151 struct confargs oca, *ca = args; 152 register struct romaux *ra = &ca->ca_ra; 153 register int node0, node; 154 register char *name; 155 register const char *sp; 156 const char *const *ssp; 157 extern int autoconf_nzs; 158 159 static const char *const special4m[] = { 160 /* find these first */ 161 "eeprom", 162 "counter", 163 "auxio", 164 "", 165 /* place device to ignore here */ 166 "interrupt", 167 NULL 168 }; 169#endif 170 171 if (CPU_ISSUN4) { 172 if (self->dv_unit > 0) { 173 printf(" unsupported\n"); 174 return; 175 } 176 printf("\n"); 177 178 (void)config_search(obio_scan, self, args); 179 bus_untmp(); 180 } 181 182#if defined(SUN4M) 183 if (!CPU_ISSUN4M) 184 return; 185 186 /* 187 * There is only one obio bus (it is in fact one of the Sbus slots) 188 * How about VME? 189 */ 190 if (sc->sc_dev.dv_unit > 0) { 191 printf(" unsupported\n"); 192 return; 193 } 194 195 printf("\n"); 196 197 if (ra->ra_bp != NULL && strcmp(ra->ra_bp->name, "obio") == 0) 198 oca.ca_ra.ra_bp = ra->ra_bp + 1; 199 else 200 oca.ca_ra.ra_bp = NULL; 201 202 sc->bu.scu_sbus.sc_range = ra->ra_range; 203 sc->bu.scu_sbus.sc_nrange = ra->ra_nrange; 204 205 /* 206 * Loop through ROM children, fixing any relative addresses 207 * and then configuring each device. 208 * We first do the crucial ones, such as eeprom, etc. 209 */ 210 node0 = firstchild(ra->ra_node); 211 for (ssp = special4m ; *(sp = *ssp) != 0; ssp++) { 212 if ((node = findnode(node0, sp)) == 0) { 213 printf("could not find %s amongst obio devices\n", sp); 214 panic(sp); 215 } 216 if (!romprop(&oca.ca_ra, sp, node)) 217 continue; 218 219 sbus_translate(self, &oca); 220 oca.ca_bustype = BUS_OBIO; 221 (void) config_found(&sc->sc_dev, (void *)&oca, busprint); 222 } 223 224 for (node = node0; node; node = nextsibling(node)) { 225 name = getpropstring(node, "name"); 226 for (ssp = special4m ; (sp = *ssp) != NULL; ssp++) 227 if (strcmp(name, sp) == 0) 228 break; 229 230 if (sp != NULL || !romprop(&oca.ca_ra, name, node)) 231 continue; 232 233 if (strcmp(name, "zs") == 0) 234 /* XXX - see autoconf.c for this hack */ 235 autoconf_nzs++; 236 237 /* Translate into parent address spaces */ 238 sbus_translate(self, &oca); 239 oca.ca_bustype = BUS_OBIO; 240 (void) config_found(&sc->sc_dev, (void *)&oca, busprint); 241 } 242#endif 243} 244 245void 246vmesattach(parent, self, args) 247 struct device *parent, *self; 248 void *args; 249{ 250 if (CPU_ISSUN4M || self->dv_unit > 0) { 251 printf(" unsupported\n"); 252 return; 253 } 254 printf("\n"); 255 256 if (vmeints == NULL) { 257 vmeints = (struct intrhand **)malloc(256 * 258 sizeof(struct intrhand *), M_TEMP, M_NOWAIT); 259 bzero(vmeints, 256 * sizeof(struct intrhand *)); 260 } 261 (void)config_search(vmes_scan, self, args); 262 bus_untmp(); 263} 264 265void 266vmelattach(parent, self, args) 267 struct device *parent, *self; 268 void *args; 269{ 270 if (CPU_ISSUN4M || self->dv_unit > 0) { 271 printf(" unsupported\n"); 272 return; 273 } 274 printf("\n"); 275 276 if (vmeints == NULL) { 277 vmeints = (struct intrhand **)malloc(256 * 278 sizeof(struct intrhand *), M_TEMP, M_NOWAIT); 279 bzero(vmeints, 256 * sizeof(struct intrhand *)); 280 } 281 (void)config_search(vmel_scan, self, args); 282 bus_untmp(); 283} 284 285int 286busattach(parent, child, args, bustype) 287 struct device *parent; 288 void *args, *child; 289 int bustype; 290{ 291#if defined(SUN4) 292 struct cfdata *cf = child; 293 register struct confargs *ca = args; 294 struct confargs oca; 295 caddr_t tmp; 296 297 if (bustype == BUS_OBIO && CPU_ISSUN4) { 298 299 /* 300 * avoid sun4m entries which don't have valid PA's. 301 * no point in even probing them. 302 */ 303 if (cf->cf_loc[0] == -1) return 0; 304 305 /* 306 * On the 4/100 obio addresses must be mapped at 307 * 0x0YYYYYYY, but alias higher up (we avoid the 308 * alias condition because it causes pmap difficulties) 309 * XXX: We also assume that 4/[23]00 obio addresses 310 * must be 0xZYYYYYYY, where (Z != 0) 311 */ 312 if (cpumod == SUN4_100 && (cf->cf_loc[0] & 0xf0000000)) 313 return 0; 314 if (cpumod != SUN4_100 && !(cf->cf_loc[0] & 0xf0000000)) 315 return 0; 316 } 317 318 if (parent->dv_cfdata->cf_driver->cd_indirect) { 319 printf(" indirect devices not supported\n"); 320 return 0; 321 } 322 323 oca.ca_ra.ra_iospace = -1; 324 oca.ca_ra.ra_paddr = (void *)cf->cf_loc[0]; 325 oca.ca_ra.ra_len = 0; 326 oca.ca_ra.ra_nreg = 1; 327 if (oca.ca_ra.ra_paddr) 328 tmp = (caddr_t)bus_tmp(oca.ca_ra.ra_paddr, 329 bustype); 330 else 331 tmp = NULL; 332 oca.ca_ra.ra_vaddr = tmp; 333 oca.ca_ra.ra_intr[0].int_pri = cf->cf_loc[1]; 334 if (bustype == BUS_VME16 || bustype == BUS_VME32) 335 oca.ca_ra.ra_intr[0].int_vec = cf->cf_loc[2]; 336 else 337 oca.ca_ra.ra_intr[0].int_vec = -1; 338 oca.ca_ra.ra_nintr = 1; 339 oca.ca_ra.ra_name = cf->cf_driver->cd_name; 340 if (ca->ca_ra.ra_bp != NULL && 341 ((bustype == BUS_VME16 && strcmp(ca->ca_ra.ra_bp->name,"vmes") ==0) || 342 (bustype == BUS_VME32 && strcmp(ca->ca_ra.ra_bp->name,"vmel") ==0) || 343 (bustype == BUS_OBIO && strcmp(ca->ca_ra.ra_bp->name,"obio") == 0))) 344 oca.ca_ra.ra_bp = ca->ca_ra.ra_bp + 1; 345 else 346 oca.ca_ra.ra_bp = NULL; 347 oca.ca_bustype = bustype; 348 349 if ((*cf->cf_attach->ca_match)(parent, cf, &oca) == 0) 350 return 0; 351 352 /* 353 * check if XXmatch routine replaced the temporary mapping with 354 * a real mapping. If not, then make sure we don't pass the 355 * tmp mapping to the attach routine. 356 */ 357 if (oca.ca_ra.ra_vaddr == tmp) 358 oca.ca_ra.ra_vaddr = NULL; /* wipe out tmp address */ 359 /* 360 * the match routine will set "ra_len" if it wants us to 361 * establish a mapping for it. 362 * (which won't be seen on future XXmatch calls, 363 * so not as useful as it seems.) 364 */ 365 if (oca.ca_ra.ra_len) 366 oca.ca_ra.ra_vaddr = 367 bus_map(oca.ca_ra.ra_reg, 368 oca.ca_ra.ra_len, oca.ca_bustype); 369 370 config_attach(parent, cf, &oca, busprint); 371 return 1; 372#else 373 return 0; 374#endif 375} 376 377int 378obio_scan(parent, child, args) 379 struct device *parent; 380 void *child, *args; 381{ 382 return busattach(parent, child, args, BUS_OBIO); 383} 384 385int 386vmes_scan(parent, child, args) 387 struct device *parent; 388 void *child, *args; 389{ 390 return busattach(parent, child, args, BUS_VME16); 391} 392 393int 394vmel_scan(parent, child, args) 395 struct device *parent; 396 void *child, *args; 397{ 398 return busattach(parent, child, args, BUS_VME32); 399} 400 401int pil_to_vme[] = { 402 -1, /* pil 0 */ 403 -1, /* pil 1 */ 404 1, /* pil 2 */ 405 2, /* pil 3 */ 406 -1, /* pil 4 */ 407 3, /* pil 5 */ 408 -1, /* pil 6 */ 409 4, /* pil 7 */ 410 -1, /* pil 8 */ 411 5, /* pil 9 */ 412 -1, /* pil 10 */ 413 6, /* pil 11 */ 414 -1, /* pil 12 */ 415 7, /* pil 13 */ 416 -1, /* pil 14 */ 417 -1, /* pil 15 */ 418}; 419 420int 421vmeintr(arg) 422 void *arg; 423{ 424 int level = (int)arg, vec; 425 struct intrhand *ih; 426 int i = 0; 427 428#ifdef DIAGNOSTIC 429 if (!CPU_ISSUN4) { 430 panic("vme: spurious interrupt"); 431 } 432#endif 433 434 vec = ldcontrolb((caddr_t) 435 (AC_VMEINTVEC | (pil_to_vme[level] << 1) | 1)); 436 if (vec == -1) { 437 printf("vme: spurious interrupt\n"); 438 return 0; 439 } 440 441 for (ih = vmeints[vec]; ih; ih = ih->ih_next) 442 if (ih->ih_fun) 443 i += (ih->ih_fun)(ih->ih_arg); 444 return (i); 445} 446 447void 448vmeintr_establish(vec, level, ih) 449 int vec, level; 450 struct intrhand *ih; 451{ 452 struct intrhand *ihs; 453 454 if (!CPU_ISSUN4) { 455 panic("vmeintr_establish: not supported on cpu-type %d", 456 cputyp); 457 } 458 459 if (vec == -1) 460 panic("vmeintr_establish: uninitialized vec\n"); 461 462 if (vmeints[vec] == NULL) 463 vmeints[vec] = ih; 464 else { 465 for (ihs = vmeints[vec]; ihs->ih_next; ihs = ihs->ih_next) 466 ; 467 ihs->ih_next = ih; 468 } 469 470 /* ensure the interrupt subsystem will call us at this level */ 471 for (ihs = intrhand[level]; ihs; ihs = ihs->ih_next) 472 if (ihs->ih_fun == vmeintr) 473 return; 474 475 ihs = (struct intrhand *)malloc(sizeof(struct intrhand), 476 M_TEMP, M_NOWAIT); 477 if (ihs == NULL) 478 panic("vme_addirq"); 479 bzero(ihs, sizeof *ihs); 480 ihs->ih_fun = vmeintr; 481 ihs->ih_arg = (void *)level; 482 intr_establish(level, ihs); 483} 484 485#define getpte(va) lda(va, ASI_PTE) 486 487/* 488 * If we can find a mapping that was established by the rom, use it. 489 * Else, create a new mapping. 490 */ 491void * 492bus_map(pa, len, bustype) 493 struct rom_reg *pa; 494 int len; 495 int bustype; 496{ 497 u_long pf = (u_long)(pa->rr_paddr) >> PGSHIFT; 498 u_long va, pte; 499 int pgtype = -1; 500 501 switch (bt2pmt[bustype]) { 502 case PMAP_OBIO: 503 pgtype = PG_OBIO; 504 break; 505 case PMAP_VME32: 506 pgtype = PG_VME32; 507 break; 508 case PMAP_VME16: 509 pgtype = PG_VME16; 510 break; 511 } 512 513 if (len <= NBPG) { 514 for (va = OLDMON_STARTVADDR; va < OLDMON_ENDVADDR; va += NBPG) { 515 pte = getpte(va); 516 if ((pte & PG_V) != 0 && (pte & PG_TYPE) == pgtype && 517 (pte & PG_PFNUM) == pf) 518 return ((void *) 519 (va | ((u_long)pa->rr_paddr & PGOFSET)) ); 520 /* note: preserve page offset */ 521 } 522 } 523 return mapiodev(pa, 0, len, bustype); 524} 525 526void * 527bus_tmp(pa, bustype) 528 void *pa; 529 int bustype; 530{ 531 vm_offset_t addr = (vm_offset_t)pa & ~PGOFSET; 532 int pmtype = bt2pmt[bustype]; 533 534 pmap_enter(pmap_kernel(), TMPMAP_VA, 535 addr | pmtype | PMAP_NC, 536 VM_PROT_READ | VM_PROT_WRITE, 1); 537 return ((void *)(TMPMAP_VA | ((u_long) pa & PGOFSET)) ); 538} 539 540void 541bus_untmp() 542{ 543 pmap_remove(pmap_kernel(), TMPMAP_VA, TMPMAP_VA+NBPG); 544} 545