1 /* $NetBSD: obio.c,v 1.10 1994/11/25 23:10:47 deraadt 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 52 struct bus_softc { 53 struct device sc_dev; /* base device */ 54 int nothing; 55 }; 56 57 /* autoconfiguration driver */ 58 static int busmatch __P((struct device *, void *, void *)); 59 static void obioattach __P((struct device *, struct device *, void *)); 60 static void vmesattach __P((struct device *, struct device *, void *)); 61 static void vmelattach __P((struct device *, struct device *, void *)); 62 63 struct cfdriver obiocd = { NULL, "obio", busmatch, obioattach, 64 DV_DULL, sizeof(struct bus_softc) 65 }; 66 struct cfdriver vmelcd = { NULL, "vmel", busmatch, vmelattach, 67 DV_DULL, sizeof(struct bus_softc) 68 }; 69 struct cfdriver vmescd = { NULL, "vmes", busmatch, vmesattach, 70 DV_DULL, sizeof(struct bus_softc) 71 }; 72 73 static void busattach __P((struct device *, struct device *, void *, int)); 74 75 void * bus_map __P((void *, int, int)); 76 void * bus_tmp __P((void *, int)); 77 void bus_untmp __P((void)); 78 79 int 80 busmatch(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 93 int 94 busprint(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 110 void 111 busattach(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 for (p = cf->cf_parents; *p >= 0; p++) 135 if (self->dv_cfdata == &cfdata[*p]) { 136 oca.ca_ra.ra_iospace = -1; 137 oca.ca_ra.ra_paddr = (void *)cf->cf_loc[0]; 138 oca.ca_ra.ra_len = 0; 139 tmp = NULL; 140 if (oca.ca_ra.ra_paddr) 141 tmp = bus_tmp(oca.ca_ra.ra_paddr, 142 bustype); 143 oca.ca_ra.ra_vaddr = tmp; 144 oca.ca_ra.ra_intr[0].int_pri = cf->cf_loc[1]; 145 if (bustype == BUS_VME16 || bustype == BUS_VME32) 146 oca.ca_ra.ra_intr[0].int_vec = cf->cf_loc[2]; 147 else 148 oca.ca_ra.ra_intr[0].int_vec = -1; 149 oca.ca_ra.ra_nintr = 1; 150 oca.ca_ra.ra_name = cf->cf_driver->cd_name; 151 oca.ca_ra.ra_bp = ca->ca_ra.ra_bp; 152 oca.ca_bustype = bustype; 153 154 if ((*cf->cf_driver->cd_match)(self, cf, &oca) == 0) 155 continue; 156 157 /* 158 * check if XXmatch routine replaced the 159 * temporary mapping with a real mapping. 160 */ 161 if (tmp == oca.ca_ra.ra_vaddr) 162 oca.ca_ra.ra_vaddr = NULL; 163 /* 164 * or if it has asked us to create a mapping.. 165 * (which won't be seen on future XXmatch calls, 166 * so not as useful as it seems.) 167 */ 168 if (oca.ca_ra.ra_len) 169 oca.ca_ra.ra_vaddr = 170 bus_map(oca.ca_ra.ra_paddr, 171 oca.ca_ra.ra_len, oca.ca_bustype); 172 173 config_attach(self, cf, &oca, busprint); 174 } 175 } 176 bus_untmp(); 177 } 178 179 void 180 obioattach(parent, self, args) 181 struct device *parent, *self; 182 void *args; 183 { 184 busattach(parent, self, args, BUS_OBIO); 185 } 186 187 struct intrhand **vmeints; 188 189 void 190 vmesattach(parent, self, args) 191 struct device *parent, *self; 192 void *args; 193 { 194 if (vmeints == NULL) { 195 vmeints = (struct intrhand **)malloc(256 * 196 sizeof(struct intrhand *), M_TEMP, M_NOWAIT); 197 bzero(vmeints, 256 * sizeof(struct intrhand *)); 198 } 199 busattach(parent, self, args, BUS_VME16); 200 } 201 202 void 203 vmelattach(parent, self, args) 204 struct device *parent, *self; 205 void *args; 206 { 207 if (vmeints == NULL) { 208 vmeints = (struct intrhand **)malloc(256 * 209 sizeof(struct intrhand *), M_TEMP, M_NOWAIT); 210 bzero(vmeints, 256 * sizeof(struct intrhand *)); 211 } 212 busattach(parent, self, args, BUS_VME32); 213 } 214 215 int pil_to_vme[] = { 216 -1, /* pil 0 */ 217 -1, /* pil 1 */ 218 1, /* pil 2 */ 219 2, /* pil 3 */ 220 -1, /* pil 4 */ 221 3, /* pil 5 */ 222 -1, /* pil 6 */ 223 4, /* pil 7 */ 224 -1, /* pil 8 */ 225 5, /* pil 9 */ 226 -1, /* pil 10 */ 227 6, /* pil 11 */ 228 -1, /* pil 12 */ 229 7, /* pil 13 */ 230 -1, /* pil 14 */ 231 -1, /* pil 15 */ 232 }; 233 234 int 235 vmeintr(arg) 236 void *arg; 237 { 238 int level = (int)arg, vec; 239 struct intrhand *ih; 240 int i = 0; 241 242 vec = ldcontrolb(AC_VMEINTVEC | (pil_to_vme[level] << 1) | 1); 243 if (vec == -1) { 244 printf("vme: spurious interrupt\n"); 245 return 0; 246 } 247 248 for (ih = vmeints[vec]; ih; ih = ih->ih_next) 249 if (ih->ih_fun) 250 i += (ih->ih_fun)(ih->ih_arg); 251 return (i); 252 } 253 254 void 255 vmeintr_establish(vec, level, ih) 256 int vec, level; 257 struct intrhand *ih; 258 { 259 struct intrhand *ihs; 260 261 if (vec == -1) 262 panic("vmeintr_establish: uninitialized vec\n"); 263 264 if (vmeints[vec] == NULL) 265 vmeints[vec] = ih; 266 else { 267 for (ihs = vmeints[vec]; ihs->ih_next; ihs = ihs->ih_next) 268 ; 269 ihs->ih_next = ih; 270 } 271 272 /* ensure the interrupt subsystem will call us at this level */ 273 for (ihs = intrhand[level]; ihs; ihs = ihs->ih_next) 274 if (ihs->ih_fun == vmeintr) 275 return; 276 277 ihs = (struct intrhand *)malloc(sizeof(struct intrhand), 278 M_TEMP, M_NOWAIT); 279 if (ihs == NULL) 280 panic("vme_addirq"); 281 bzero(ihs, sizeof *ihs); 282 ihs->ih_fun = vmeintr; 283 ihs->ih_arg = (void *)level; 284 intr_establish(level, ihs); 285 } 286 287 #define getpte(va) lda(va, ASI_PTE) 288 289 /* 290 * If we can find a mapping that was established by the rom, use it. 291 * Else, create a new mapping. 292 */ 293 void * 294 bus_map(pa, len, bustype) 295 void *pa; 296 int len; 297 int bustype; 298 { 299 u_long pf = (u_long)pa >> PGSHIFT; 300 u_long va, pte; 301 int pgtype; 302 303 switch (bt2pmt[bustype]) { 304 case PMAP_OBIO: 305 pgtype = PG_OBIO; 306 break; 307 case PMAP_VME32: 308 pgtype = PG_VME32; 309 break; 310 case PMAP_VME16: 311 pgtype = PG_VME16; 312 break; 313 } 314 315 if (len <= NBPG) { 316 for (va = OLDMON_STARTVADDR; va < OLDMON_ENDVADDR; va += NBPG) { 317 pte = getpte(va); 318 if ((pte & PG_V) != 0 && (pte & PG_TYPE) == pgtype && 319 (pte & PG_PFNUM) == pf) 320 return ((void *)va); 321 } 322 } 323 return mapiodev(pa, len, bustype); 324 } 325 326 void * 327 bus_tmp(pa, bustype) 328 void *pa; 329 int bustype; 330 { 331 vm_offset_t addr = (vm_offset_t)pa & ~PGOFSET; 332 int pmtype = bt2pmt[bustype]; 333 334 pmap_enter(kernel_pmap, TMPMAP_VA, 335 addr | pmtype | PMAP_NC, 336 VM_PROT_READ | VM_PROT_WRITE, 1); 337 return ((void *)TMPMAP_VA); 338 } 339 340 void 341 bus_untmp() 342 { 343 pmap_remove(kernel_pmap, TMPMAP_VA, TMPMAP_VA+NBPG); 344 } 345