obio.c revision 1.19
1/* $NetBSD: obio.c,v 1.19 1996/01/12 21:44:16 chuck Exp $ */ 2 3/* 4 * Copyright (c) 1993, 1994 Theo de Raadt 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Theo de Raadt. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33#include <sys/param.h> 34#include <sys/device.h> 35#include <sys/malloc.h> 36 37#ifdef DEBUG 38#include <sys/proc.h> 39#include <sys/syslog.h> 40#endif 41 42#include <vm/vm.h> 43 44#include <machine/autoconf.h> 45#include <machine/pmap.h> 46#include <machine/oldmon.h> 47#include <machine/cpu.h> 48#include <machine/ctlreg.h> 49#include <sparc/sparc/asm.h> 50#include <sparc/sparc/vaddrs.h> 51 52struct bus_softc { 53 struct device sc_dev; /* base device */ 54 int nothing; 55}; 56 57/* autoconfiguration driver */ 58static int busmatch __P((struct device *, void *, void *)); 59static void obioattach __P((struct device *, struct device *, void *)); 60#if defined(SUN4) 61static void vmesattach __P((struct device *, struct device *, void *)); 62static void vmelattach __P((struct device *, struct device *, void *)); 63static int busattach __P((struct device *, void *, void *, int)); 64void * bus_map __P((struct rom_reg *, int, int)); 65void * bus_tmp __P((void *, int)); 66void bus_untmp __P((void)); 67#endif 68 69struct cfdriver obiocd = { NULL, "obio", busmatch, obioattach, 70 DV_DULL, sizeof(struct bus_softc) 71}; 72#if defined(SUN4) 73struct cfdriver vmelcd = { NULL, "vmel", busmatch, vmelattach, 74 DV_DULL, sizeof(struct bus_softc) 75}; 76struct cfdriver vmescd = { NULL, "vmes", busmatch, vmesattach, 77 DV_DULL, sizeof(struct bus_softc) 78}; 79#endif 80 81 82int 83busmatch(parent, vcf, aux) 84 struct device *parent; 85 void *vcf, *aux; 86{ 87 struct cfdata *cf = vcf; 88 register struct confargs *ca = aux; 89 register struct romaux *ra = &ca->ca_ra; 90 91 if (cputyp != CPU_SUN4) 92 return (0); 93 return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0); 94} 95 96int 97busprint(args, obio) 98 void *args; 99 char *obio; 100{ 101 register struct confargs *ca = args; 102 103 if (ca->ca_ra.ra_name == NULL) 104 ca->ca_ra.ra_name = "<unknown>"; 105 if (obio) 106 printf("[%s at %s]", ca->ca_ra.ra_name, obio); 107 printf(" addr 0x%x", ca->ca_ra.ra_paddr); 108 if (ca->ca_ra.ra_intr[0].int_vec != -1) 109 printf(" vec 0x%x", ca->ca_ra.ra_intr[0].int_vec); 110 return (UNCONF); 111} 112 113 114int 115busattach(parent, child, args, bustype) 116 struct device *parent; 117 void *args, *child; 118 int bustype; 119{ 120 struct cfdata *cf = child; 121 register struct bus_softc *sc = (struct bus_softc *)parent; 122 register struct confargs *ca = args; 123 struct confargs oca; 124 caddr_t tmp; 125 126 if (bustype == BUS_OBIO && cputyp == CPU_SUN4) { 127 /* 128 * On the 4/100 obio addresses must be mapped at 129 * 0x0YYYYYYY, but alias higher up (we avoid the 130 * alias condition because it causes pmap difficulties) 131 * XXX: We also assume that 4/[23]00 obio addresses 132 * must be 0xZYYYYYYY, where (Z != 0) 133 */ 134 if (cpumod==SUN4_100 && (cf->cf_loc[0] & 0xf0000000)) 135 return 0; 136 if (cpumod!=SUN4_100 && !(cf->cf_loc[0] & 0xf0000000)) 137 return 0; 138 } 139 140 if (parent->dv_cfdata->cf_driver->cd_indirect) { 141 printf(" indirect devices not supported\n"); 142 return 0; 143 } 144 145 oca.ca_ra.ra_iospace = -1; 146 oca.ca_ra.ra_paddr = (void *)cf->cf_loc[0]; 147 oca.ca_ra.ra_len = 0; 148 oca.ca_ra.ra_nreg = 1; 149 tmp = NULL; 150 if (oca.ca_ra.ra_paddr) 151 tmp = bus_tmp(oca.ca_ra.ra_paddr, 152 bustype); 153 oca.ca_ra.ra_vaddr = tmp; 154 oca.ca_ra.ra_intr[0].int_pri = cf->cf_loc[1]; 155 if (bustype == BUS_VME16 || bustype == BUS_VME32) 156 oca.ca_ra.ra_intr[0].int_vec = cf->cf_loc[2]; 157 else 158 oca.ca_ra.ra_intr[0].int_vec = -1; 159 oca.ca_ra.ra_nintr = 1; 160 oca.ca_ra.ra_name = cf->cf_driver->cd_name; 161 if (ca->ca_ra.ra_bp != NULL && 162 ((bustype == BUS_VME16 && strcmp(ca->ca_ra.ra_bp->name,"vmes") ==0) || 163 (bustype == BUS_VME32 && strcmp(ca->ca_ra.ra_bp->name,"vmel") ==0) || 164 (bustype == BUS_OBIO && strcmp(ca->ca_ra.ra_bp->name,"obio") == 0))) 165 oca.ca_ra.ra_bp = ca->ca_ra.ra_bp + 1; 166 else 167 oca.ca_ra.ra_bp = NULL; 168 oca.ca_bustype = bustype; 169 170 if ((*cf->cf_driver->cd_match)(parent, cf, &oca) == 0) 171 return 0; 172 173 /* 174 * check if XXmatch routine replaced the temporary mapping with 175 * a real mapping. If not, then make sure we don't pass the 176 * tmp mapping to the attach routine. 177 */ 178 if (oca.ca_ra.ra_vaddr == tmp) 179 oca.ca_ra.ra_vaddr = NULL; /* wipe out tmp address */ 180 /* 181 * the match routine will set "ra_len" if it wants us to 182 * establish a mapping for it. 183 * (which won't be seen on future XXmatch calls, 184 * so not as useful as it seems.) 185 */ 186 if (oca.ca_ra.ra_len) 187 oca.ca_ra.ra_vaddr = 188 bus_map(oca.ca_ra.ra_reg, 189 oca.ca_ra.ra_len, oca.ca_bustype); 190 191 config_attach(parent, cf, &oca, busprint); 192 return 1; 193} 194 195#if defined(SUN4) 196int 197obio_scan(parent, child, args) 198 struct device *parent; 199 void *child, *args; 200{ 201 return busattach(parent, child, args, BUS_OBIO); 202} 203#endif 204 205void 206obioattach(parent, self, args) 207 struct device *parent, *self; 208 void *args; 209{ 210#if defined(SUN4) 211 if (cputyp == CPU_SUN4) { 212 if (self->dv_unit > 0) { 213 printf(" unsupported\n"); 214 return; 215 } 216 printf("\n"); 217 218 (void)config_search(obio_scan, self, args); 219 bus_untmp(); 220 } 221#endif 222} 223 224#if defined(SUN4) 225struct intrhand **vmeints; 226 227int 228vmes_scan(parent, child, args) 229 struct device *parent; 230 void *child, *args; 231{ 232 return busattach(parent, child, args, BUS_VME16); 233} 234 235void 236vmesattach(parent, self, args) 237 struct device *parent, *self; 238 void *args; 239{ 240 if (self->dv_unit > 0) { 241 printf(" unsupported\n"); 242 return; 243 } 244 printf("\n"); 245 246 if (vmeints == NULL) { 247 vmeints = (struct intrhand **)malloc(256 * 248 sizeof(struct intrhand *), M_TEMP, M_NOWAIT); 249 bzero(vmeints, 256 * sizeof(struct intrhand *)); 250 } 251 (void)config_search(vmes_scan, self, args); 252 bus_untmp(); 253} 254 255int 256vmel_scan(parent, child, args) 257 struct device *parent; 258 void *child, *args; 259{ 260 return busattach(parent, child, args, BUS_VME32); 261} 262 263void 264vmelattach(parent, self, args) 265 struct device *parent, *self; 266 void *args; 267{ 268 if (self->dv_unit > 0) { 269 printf(" unsupported\n"); 270 return; 271 } 272 printf("\n"); 273 274 if (vmeints == NULL) { 275 vmeints = (struct intrhand **)malloc(256 * 276 sizeof(struct intrhand *), M_TEMP, M_NOWAIT); 277 bzero(vmeints, 256 * sizeof(struct intrhand *)); 278 } 279 (void)config_search(vmel_scan, self, args); 280 bus_untmp(); 281} 282 283int pil_to_vme[] = { 284 -1, /* pil 0 */ 285 -1, /* pil 1 */ 286 1, /* pil 2 */ 287 2, /* pil 3 */ 288 -1, /* pil 4 */ 289 3, /* pil 5 */ 290 -1, /* pil 6 */ 291 4, /* pil 7 */ 292 -1, /* pil 8 */ 293 5, /* pil 9 */ 294 -1, /* pil 10 */ 295 6, /* pil 11 */ 296 -1, /* pil 12 */ 297 7, /* pil 13 */ 298 -1, /* pil 14 */ 299 -1, /* pil 15 */ 300}; 301 302int 303vmeintr(arg) 304 void *arg; 305{ 306 int level = (int)arg, vec; 307 struct intrhand *ih; 308 int i = 0; 309 310 vec = ldcontrolb(AC_VMEINTVEC | (pil_to_vme[level] << 1) | 1); 311 if (vec == -1) { 312 printf("vme: spurious interrupt\n"); 313 return 0; 314 } 315 316 for (ih = vmeints[vec]; ih; ih = ih->ih_next) 317 if (ih->ih_fun) 318 i += (ih->ih_fun)(ih->ih_arg); 319 return (i); 320} 321 322void 323vmeintr_establish(vec, level, ih) 324 int vec, level; 325 struct intrhand *ih; 326{ 327 struct intrhand *ihs; 328 329 if (vec == -1) 330 panic("vmeintr_establish: uninitialized vec\n"); 331 332 if (vmeints[vec] == NULL) 333 vmeints[vec] = ih; 334 else { 335 for (ihs = vmeints[vec]; ihs->ih_next; ihs = ihs->ih_next) 336 ; 337 ihs->ih_next = ih; 338 } 339 340 /* ensure the interrupt subsystem will call us at this level */ 341 for (ihs = intrhand[level]; ihs; ihs = ihs->ih_next) 342 if (ihs->ih_fun == vmeintr) 343 return; 344 345 ihs = (struct intrhand *)malloc(sizeof(struct intrhand), 346 M_TEMP, M_NOWAIT); 347 if (ihs == NULL) 348 panic("vme_addirq"); 349 bzero(ihs, sizeof *ihs); 350 ihs->ih_fun = vmeintr; 351 ihs->ih_arg = (void *)level; 352 intr_establish(level, ihs); 353} 354 355#define getpte(va) lda(va, ASI_PTE) 356 357/* 358 * If we can find a mapping that was established by the rom, use it. 359 * Else, create a new mapping. 360 */ 361void * 362bus_map(pa, len, bustype) 363 struct rom_reg *pa; 364 int len; 365 int bustype; 366{ 367 u_long pf = (u_long)(pa->rr_paddr) >> PGSHIFT; 368 u_long va, pte; 369 int pgtype; 370 371 switch (bt2pmt[bustype]) { 372 case PMAP_OBIO: 373 pgtype = PG_OBIO; 374 break; 375 case PMAP_VME32: 376 pgtype = PG_VME32; 377 break; 378 case PMAP_VME16: 379 pgtype = PG_VME16; 380 break; 381 } 382 383 if (len <= NBPG) { 384 for (va = OLDMON_STARTVADDR; va < OLDMON_ENDVADDR; va += NBPG) { 385 pte = getpte(va); 386 if ((pte & PG_V) != 0 && (pte & PG_TYPE) == pgtype && 387 (pte & PG_PFNUM) == pf) 388 return ((void *) 389 (va | ((u_long)pa->rr_paddr & PGOFSET)) ); 390 /* note: preserve page offset */ 391 } 392 } 393 return mapiodev(pa, 0, len, bustype); 394} 395 396void * 397bus_tmp(pa, bustype) 398 void *pa; 399 int bustype; 400{ 401 vm_offset_t addr = (vm_offset_t)pa & ~PGOFSET; 402 int pmtype = bt2pmt[bustype]; 403 404 pmap_enter(pmap_kernel(), TMPMAP_VA, 405 addr | pmtype | PMAP_NC, 406 VM_PROT_READ | VM_PROT_WRITE, 1); 407 return ((void *)(TMPMAP_VA | ((u_long) pa & PGOFSET)) ); 408} 409 410void 411bus_untmp() 412{ 413 pmap_remove(pmap_kernel(), TMPMAP_VA, TMPMAP_VA+NBPG); 414} 415#endif 416