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