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