obio.c revision 1.13
1/* $NetBSD: obio.c,v 1.13 1995/04/10 16:48:34 mycroft 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 *)); 60static void vmesattach __P((struct device *, struct device *, void *)); 61static void vmelattach __P((struct device *, struct device *, void *)); 62 63struct cfdriver obiocd = { NULL, "obio", busmatch, obioattach, 64 DV_DULL, sizeof(struct bus_softc) 65}; 66struct cfdriver vmelcd = { NULL, "vmel", busmatch, vmelattach, 67 DV_DULL, sizeof(struct bus_softc) 68}; 69struct cfdriver vmescd = { NULL, "vmes", busmatch, vmesattach, 70 DV_DULL, sizeof(struct bus_softc) 71}; 72 73static void busattach __P((struct device *, struct device *, void *, int)); 74 75void * bus_map __P((void *, int, int)); 76void * bus_tmp __P((void *, int)); 77void bus_untmp __P((void)); 78 79int 80busmatch(parent, vcf, aux) 81 struct device *parent; 82 void *vcf, *aux; 83{ 84 struct cfdata *cf = vcf; 85 register struct confargs *ca = aux; 86 register struct romaux *ra = &ca->ca_ra; 87 88 if (cputyp != CPU_SUN4) 89 return (0); 90 return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0); 91} 92 93int 94busprint(args, obio) 95 void *args; 96 char *obio; 97{ 98 register struct confargs *ca = args; 99 100 if (ca->ca_ra.ra_name == NULL) 101 ca->ca_ra.ra_name = "<unknown>"; 102 if (obio) 103 printf("[%s at %s]", ca->ca_ra.ra_name, obio); 104 printf(" addr %x", ca->ca_ra.ra_paddr); 105 if (ca->ca_ra.ra_intr[0].int_vec != -1) 106 printf(" vec 0x%x", ca->ca_ra.ra_intr[0].int_vec); 107 return (UNCONF); 108} 109 110void 111busattach(parent, self, args, bustype) 112 struct device *parent, *self; 113 void *args; 114 int bustype; 115{ 116 register struct bus_softc *sc = (struct bus_softc *)self; 117 extern struct cfdata cfdata[]; 118 register struct confargs *ca = args; 119 struct confargs oca; 120 register short *p; 121 struct cfdata *cf; 122 caddr_t tmp; 123 124 if (sc->sc_dev.dv_unit > 0) { 125 printf(" unsupported\n"); 126 return; 127 } 128 129 printf("\n"); 130 131 for (cf = cfdata; cf->cf_driver; cf++) { 132 if (cf->cf_fstate == FSTATE_FOUND) 133 continue; 134 if (bustype == BUS_OBIO && cputyp == CPU_SUN4) { 135 /* 136 * On the 4/100 obio addresses must be mapped at 137 * 0x0YYYYYYY, but alias higher up (we avoid the 138 * alias condition because it causes pmap difficulties) 139 * XXX: We also assume that 4/[23]00 obio addresses 140 * must be 0xZYYYYYYY, where (Z != 0) 141 */ 142 if (cpumod==SUN4_100 && (cf->cf_loc[0] & 0xf0000000)) 143 continue; 144 if (cpumod!=SUN4_100 && !(cf->cf_loc[0] & 0xf0000000)) 145 continue; 146 } 147 for (p = cf->cf_parents; *p >= 0; p++) 148 if (self->dv_cfdata == &cfdata[*p]) { 149 oca.ca_ra.ra_iospace = -1; 150 oca.ca_ra.ra_paddr = (void *)cf->cf_loc[0]; 151 oca.ca_ra.ra_len = 0; 152 oca.ca_ra.ra_nreg = 1; 153 tmp = NULL; 154 if (oca.ca_ra.ra_paddr != (void *)-1) 155 tmp = bus_tmp(oca.ca_ra.ra_paddr, 156 bustype); 157 oca.ca_ra.ra_vaddr = tmp; 158 oca.ca_ra.ra_intr[0].int_pri = cf->cf_loc[1]; 159 if (bustype == BUS_VME16 || bustype == BUS_VME32) 160 oca.ca_ra.ra_intr[0].int_vec = cf->cf_loc[2]; 161 else 162 oca.ca_ra.ra_intr[0].int_vec = -1; 163 oca.ca_ra.ra_nintr = 1; 164 oca.ca_ra.ra_name = cf->cf_driver->cd_name; 165 if (ca->ca_ra.ra_bp != NULL && 166 strcmp(ca->ca_ra.ra_bp->name, "sbus") == 0) 167 oca.ca_ra.ra_bp = ca->ca_ra.ra_bp + 1; 168 else 169 oca.ca_ra.ra_bp = NULL; 170 oca.ca_bustype = bustype; 171 172 if ((*cf->cf_driver->cd_match)(self, cf, &oca) == 0) 173 continue; 174 175 /* 176 * check if XXmatch routine replaced the 177 * temporary mapping with a real mapping. 178 */ 179 if (tmp == oca.ca_ra.ra_vaddr) 180 oca.ca_ra.ra_vaddr = NULL; 181 /* 182 * or if it has asked us to create a mapping.. 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_paddr, 189 oca.ca_ra.ra_len, oca.ca_bustype); 190 191 config_attach(self, cf, &oca, busprint); 192 } 193 } 194 bus_untmp(); 195} 196 197void 198obioattach(parent, self, args) 199 struct device *parent, *self; 200 void *args; 201{ 202 busattach(parent, self, args, BUS_OBIO); 203} 204 205struct intrhand **vmeints; 206 207void 208vmesattach(parent, self, args) 209 struct device *parent, *self; 210 void *args; 211{ 212 if (vmeints == NULL) { 213 vmeints = (struct intrhand **)malloc(256 * 214 sizeof(struct intrhand *), M_TEMP, M_NOWAIT); 215 bzero(vmeints, 256 * sizeof(struct intrhand *)); 216 } 217 busattach(parent, self, args, BUS_VME16); 218} 219 220void 221vmelattach(parent, self, args) 222 struct device *parent, *self; 223 void *args; 224{ 225 if (vmeints == NULL) { 226 vmeints = (struct intrhand **)malloc(256 * 227 sizeof(struct intrhand *), M_TEMP, M_NOWAIT); 228 bzero(vmeints, 256 * sizeof(struct intrhand *)); 229 } 230 busattach(parent, self, args, BUS_VME32); 231} 232 233int pil_to_vme[] = { 234 -1, /* pil 0 */ 235 -1, /* pil 1 */ 236 1, /* pil 2 */ 237 2, /* pil 3 */ 238 -1, /* pil 4 */ 239 3, /* pil 5 */ 240 -1, /* pil 6 */ 241 4, /* pil 7 */ 242 -1, /* pil 8 */ 243 5, /* pil 9 */ 244 -1, /* pil 10 */ 245 6, /* pil 11 */ 246 -1, /* pil 12 */ 247 7, /* pil 13 */ 248 -1, /* pil 14 */ 249 -1, /* pil 15 */ 250}; 251 252int 253vmeintr(arg) 254 void *arg; 255{ 256 int level = (int)arg, vec; 257 struct intrhand *ih; 258 int i = 0; 259 260 vec = ldcontrolb(AC_VMEINTVEC | (pil_to_vme[level] << 1) | 1); 261 if (vec == -1) { 262 printf("vme: spurious interrupt\n"); 263 return 0; 264 } 265 266 for (ih = vmeints[vec]; ih; ih = ih->ih_next) 267 if (ih->ih_fun) 268 i += (ih->ih_fun)(ih->ih_arg); 269 return (i); 270} 271 272void 273vmeintr_establish(vec, level, ih) 274 int vec, level; 275 struct intrhand *ih; 276{ 277 struct intrhand *ihs; 278 279 if (vec == -1) 280 panic("vmeintr_establish: uninitialized vec\n"); 281 282 if (vmeints[vec] == NULL) 283 vmeints[vec] = ih; 284 else { 285 for (ihs = vmeints[vec]; ihs->ih_next; ihs = ihs->ih_next) 286 ; 287 ihs->ih_next = ih; 288 } 289 290 /* ensure the interrupt subsystem will call us at this level */ 291 for (ihs = intrhand[level]; ihs; ihs = ihs->ih_next) 292 if (ihs->ih_fun == vmeintr) 293 return; 294 295 ihs = (struct intrhand *)malloc(sizeof(struct intrhand), 296 M_TEMP, M_NOWAIT); 297 if (ihs == NULL) 298 panic("vme_addirq"); 299 bzero(ihs, sizeof *ihs); 300 ihs->ih_fun = vmeintr; 301 ihs->ih_arg = (void *)level; 302 intr_establish(level, ihs); 303} 304 305#define getpte(va) lda(va, ASI_PTE) 306 307/* 308 * If we can find a mapping that was established by the rom, use it. 309 * Else, create a new mapping. 310 */ 311void * 312bus_map(pa, len, bustype) 313 void *pa; 314 int len; 315 int bustype; 316{ 317 u_long pf = (u_long)pa >> PGSHIFT; 318 u_long va, pte; 319 int pgtype; 320 321 switch (bt2pmt[bustype]) { 322 case PMAP_OBIO: 323 pgtype = PG_OBIO; 324 break; 325 case PMAP_VME32: 326 pgtype = PG_VME32; 327 break; 328 case PMAP_VME16: 329 pgtype = PG_VME16; 330 break; 331 } 332 333 if (len <= NBPG) { 334 for (va = OLDMON_STARTVADDR; va < OLDMON_ENDVADDR; va += NBPG) { 335 pte = getpte(va); 336 if ((pte & PG_V) != 0 && (pte & PG_TYPE) == pgtype && 337 (pte & PG_PFNUM) == pf) 338 return ((void *)va); 339 } 340 } 341 return mapiodev(pa, len, bustype); 342} 343 344void * 345bus_tmp(pa, bustype) 346 void *pa; 347 int bustype; 348{ 349 vm_offset_t addr = (vm_offset_t)pa & ~PGOFSET; 350 int pmtype = bt2pmt[bustype]; 351 352 pmap_enter(pmap_kernel(), TMPMAP_VA, 353 addr | pmtype | PMAP_NC, 354 VM_PROT_READ | VM_PROT_WRITE, 1); 355 return ((void *)TMPMAP_VA); 356} 357 358void 359bus_untmp() 360{ 361 pmap_remove(pmap_kernel(), TMPMAP_VA, TMPMAP_VA+NBPG); 362} 363