Annotation of sys/arch/sparc/dev/fga.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: fga.c,v 1.15 2006/02/22 22:32:12 miod Exp $ */
2:
3: /*
4: * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
5: * All rights reserved.
6: *
7: * This software was developed by Jason L. Wright under contract with
8: * RTMX Incorporated (http://www.rtmx.com).
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22: * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
23: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24: * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25: * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27: * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28: * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29: * POSSIBILITY OF SUCH DAMAGE.
30: */
31:
32: /*
33: * Driver for the Force Gate Array 5000 (VME/SBus bridge) found
34: * on FORCE CPU-5V boards.
35: */
36:
37: #include <sys/param.h>
38: #include <sys/systm.h>
39: #include <sys/kernel.h>
40: #include <sys/errno.h>
41: #include <sys/ioctl.h>
42: #include <sys/syslog.h>
43: #include <sys/device.h>
44: #include <sys/malloc.h>
45: #include <uvm/uvm_extern.h>
46: #include <machine/pmap.h>
47:
48: #include <machine/autoconf.h>
49: #include <sparc/cpu.h>
50: #include <sparc/sparc/cpuvar.h>
51: #include <sparc/dev/sbusvar.h>
52: #include <sparc/dev/dmareg.h> /* for SBUS_BURST_* */
53:
54: #include <sparc/dev/fgareg.h>
55: #include <sparc/dev/fgavar.h>
56: #include <machine/fgaio.h>
57:
58: int fgamatch(struct device *, void *, void *);
59: void fgaattach(struct device *, struct device *, void *);
60: int fvmematch(struct device *, void *, void *);
61: void fvmeattach(struct device *, struct device *, void *);
62: int fgaprint(void *, const char *);
63: int fvmeprint(void *, const char *);
64: int fvmescan(struct device *parent, void *, void *);
65:
66: struct fga_softc {
67: struct device sc_dev; /* base device */
68: int sc_node; /* prom node */
69: struct fga_regs *sc_regs; /* registers */
70: struct intrhand sc_ih1; /* level 1 handler */
71: struct intrhand sc_ih2; /* level 2 handler */
72: struct intrhand sc_ih3; /* level 3 handler */
73: struct intrhand sc_ih4; /* level 4 handler */
74: struct intrhand sc_ih5; /* level 5 handler */
75: struct intrhand sc_ih6; /* level 6 handler */
76: struct intrhand sc_ih7; /* level 7 handler */
77: struct intrhand **sc_vmevec; /* vectored handlers */
78: #ifdef DDB
79: int sc_abort; /* abort switch enabled? */
80: #endif
81: int sc_nrange; /* number of sbus ranges */
82: struct rom_range *sc_range; /* sbus range data */
83: u_int8_t sc_established; /* which hw intrs installed */
84: };
85:
86: int fgaopen(dev_t, int, int, struct proc *);
87: int fgaclose(dev_t, int, int, struct proc *);
88: int fgaioctl(dev_t, u_long, caddr_t, int, struct proc *);
89:
90: int fga_vmerangemap(struct fga_softc *, u_int32_t, u_int32_t,
91: int, int, u_int32_t, struct confargs *);
92: int fga_intr_establish(struct fga_softc *, int, int,
93: struct intrhand *, const char *);
94: int fga_hwintr_establish(struct fga_softc *, u_int8_t);
95:
96: int fga_hwintr1(void *);
97: int fga_hwintr2(void *);
98: int fga_hwintr3(void *);
99: int fga_hwintr4(void *);
100: int fga_hwintr5(void *);
101: int fga_hwintr6(void *);
102: int fga_hwintr7(void *);
103: int fga_intrvec(struct fga_softc *, int);
104:
105: struct cfattach fga_ca = {
106: sizeof (struct fga_softc), fgamatch, fgaattach
107: };
108:
109: struct cfdriver fga_cd = {
110: NULL, "fga", DV_DULL
111: };
112:
113: struct fvme_softc {
114: struct device sc_dv;
115: u_int32_t sc_vmeoffset; /* vme range offset */
116: u_int32_t sc_len; /* length of range */
117: u_int32_t sc_sbusoffset; /* sbus phys address */
118: u_int32_t sc_type; /* amcode type */
119: };
120:
121: struct cfattach fvme_ca = {
122: sizeof (struct fvme_softc), fvmematch, fvmeattach
123: };
124:
125: struct cfdriver fvme_cd = {
126: NULL, "fvme", DV_DULL
127: };
128:
129: int
130: fgamatch(parent, vcf, aux)
131: struct device *parent;
132: void *vcf, *aux;
133: {
134: struct confargs *ca = aux;
135: struct romaux *ra = &ca->ca_ra;
136:
137: if (strcmp("VME", ra->ra_name))
138: return (0);
139: return (1);
140: }
141:
142: void
143: fgaattach(parent, self, aux)
144: struct device *parent, *self;
145: void *aux;
146: {
147: struct confargs *ca = aux, oca;
148: struct fga_softc *sc = (struct fga_softc *)self;
149: char *s;
150: int i, rlen;
151:
152: if (sc->sc_dev.dv_unit > 0) {
153: printf(" unsupported\n");
154: return;
155: }
156:
157: /* map registers */
158: if (ca->ca_ra.ra_nreg != 1) {
159: printf(": expected 1 register, got %d\n", ca->ca_ra.ra_nreg);
160: return;
161: }
162: sc->sc_regs = mapiodev(&(ca->ca_ra.ra_reg[0]), 0,
163: ca->ca_ra.ra_reg[0].rr_len);
164:
165: sc->sc_node = ca->ca_ra.ra_node;
166:
167: i = opennode("/iommu/sbus");
168: if (i == 0) {
169: printf(": no iommu or sbus found, unconfigured\n");
170: return;
171: }
172: rlen = getproplen(i, "ranges");
173: sc->sc_range =
174: (struct rom_range *)malloc(rlen, M_DEVBUF, M_NOWAIT);
175: if (sc->sc_range == NULL) {
176: printf(": PROM ranges too large: %d\n", rlen);
177: return;
178: }
179: sc->sc_nrange = rlen / sizeof(struct rom_range);
180: (void)getprop(i, "ranges", sc->sc_range, rlen);
181:
182: s = getpropstring(sc->sc_node, "model");
183: printf(": model %s id %c%c%c\n", s,
184: sc->sc_regs->id[0], sc->sc_regs->id[1], sc->sc_regs->id[2]);
185:
186: /*
187: * The prom leaves at least one of the ranges "on", so make sure
188: * they are all off.
189: */
190: for (i = 0; i < 16; i++)
191: sc->sc_regs->vme_range[i] |= VME_RANGE_DECEN;
192:
193: sc->sc_regs->sbus_ssel[0] &= ~(SBUS_SSEL_Y);
194: sc->sc_regs->sbus_ssel[0] |= SBUS_SSEL_Y_SLOT4;
195: sc->sc_regs->sbus_ssel[1] &= ~(SBUS_SSEL_X | SBUS_SSEL_Y);
196: sc->sc_regs->sbus_ssel[1] |= SBUS_SSEL_X_SLOT5 | SBUS_SSEL_Y_SLOT5;
197: sc->sc_regs->sbus_ssel[2] &= ~(SBUS_SSEL_X | SBUS_SSEL_Y);
198: sc->sc_regs->sbus_ssel[2] |= SBUS_SSEL_X_SLOT5 | SBUS_SSEL_Y_SLOT1;
199: sc->sc_regs->sbus_ssel[3] &= ~(SBUS_SSEL_X | SBUS_SSEL_Y);
200: sc->sc_regs->sbus_ssel[3] |= SBUS_SSEL_X_SLOT1 | SBUS_SSEL_Y_SLOT1;
201:
202: /*
203: * Map and attach vme<->sbus master ranges
204: */
205: fga_vmerangemap(sc, 0xf0000000, 0x10000000,
206: VME_MASTER_CAP_D32 | VME_MASTER_CAP_A32, 1, 0, &oca);
207: fga_vmerangemap(sc, 0xf0000000, 0x10000000,
208: VME_MASTER_CAP_D16 | VME_MASTER_CAP_A32, 4, 0, &oca);
209: fga_vmerangemap(sc, 0x00000000, 0x01000000,
210: VME_MASTER_CAP_D16 | VME_MASTER_CAP_A24, 5, 0xe000000, &oca);
211: fga_vmerangemap(sc, 0x00000000, 0x00010000,
212: VME_MASTER_CAP_D8 | VME_MASTER_CAP_A16, 5, 0x0ffc0000, &oca);
213: fga_vmerangemap(sc, 0x00000000, 0x00010000,
214: VME_MASTER_CAP_D16 | VME_MASTER_CAP_A16, 5, 0x0ffd0000, &oca);
215: fga_vmerangemap(sc, 0x00000000, 0x00010000,
216: VME_MASTER_CAP_D32 | VME_MASTER_CAP_A16, 5, 0x0ffe0000, &oca);
217:
218: #ifdef DDB
219: s = getpropstring(optionsnode, "abort-ena?");
220: if (s && strcmp(s, "true") == 0) {
221: sc->sc_abort = 1;
222: fga_hwintr_establish(sc, IRQ_MAP_SINT7);
223: sc->sc_regs->abort_irq_map &= ~IRQ_MAP_INT_MASK;
224: sc->sc_regs->abort_irq_map |= IRQ_MAP_SINT7;
225: sc->sc_regs->abort_irq_map &= ~IRQ_MAP_ENABLE;
226: }
227: #endif
228: }
229:
230: int
231: fgaprint(args, name)
232: void *args;
233: const char *name;
234: {
235: struct confargs *ca = args;
236:
237: if (name)
238: printf("%s at %s", ca->ca_ra.ra_name, name);
239: printf(" slot %d addr 0x%x", ca->ca_slot, ca->ca_offset);
240: return (UNCONF);
241: }
242:
243: /*
244: * Map a region of VME space to a sbus slot/offset.
245: */
246: int
247: fga_vmerangemap(sc, vmebase, vmelen, vmecap, sbusslot, sbusoffset, oca)
248: struct fga_softc *sc;
249: u_int32_t vmebase, vmelen;
250: int vmecap;
251: int sbusslot;
252: u_int32_t sbusoffset;
253: struct confargs *oca;
254: {
255: struct fga_regs *regs = sc->sc_regs;
256: u_int32_t rval;
257: u_int8_t sval;
258: int range, i, srange;
259:
260: for (i = 0; i < FVME_MAX_RANGES; i++) {
261: if (regs->vme_range[i] & VME_RANGE_DECEN)
262: break;
263: }
264: if (i == FVME_MAX_RANGES)
265: return (-1);
266: range = i;
267:
268: for (srange = 0; srange < sc->sc_nrange; srange++) {
269: if (sbusslot == sc->sc_range[srange].cspace)
270: break;
271: }
272: if (srange == sc->sc_nrange)
273: return (-1);
274:
275: bzero(oca, sizeof(*oca));
276: oca->ca_bustype = BUS_FGA;
277: oca->ca_slot = sbusslot;
278: oca->ca_offset = sc->sc_range[srange].poffset | sbusoffset;
279: oca->ca_ra.ra_name = "fvme";
280: oca->ca_ra.ra_nreg = 2;
281: oca->ca_ra.ra_reg[0].rr_len = vmelen;
282: oca->ca_ra.ra_reg[0].rr_paddr =
283: (void *)(sc->sc_range[srange].poffset | sbusoffset);
284: oca->ca_ra.ra_reg[0].rr_iospace = sbusslot;
285: oca->ca_ra.ra_reg[1].rr_iospace = vmecap;
286: oca->ca_ra.ra_reg[1].rr_paddr = (void *)vmebase;
287: oca->ca_ra.ra_reg[1].rr_len = vmelen;
288:
289: /* 1. Setup slot select register for this range. */
290: switch (sbusslot) {
291: case 1:
292: sval = SBUS_SSEL_Y_SLOT1;
293: break;
294: case 2:
295: sval = SBUS_SSEL_Y_SLOT2;
296: break;
297: case 3:
298: sval = SBUS_SSEL_Y_SLOT3;
299: break;
300: case 4:
301: sval = SBUS_SSEL_Y_SLOT4;
302: break;
303: case 5:
304: sval = SBUS_SSEL_Y_SLOT5;
305: break;
306: default:
307: return (-1);
308: }
309:
310: if (range & 1) {
311: regs->sbus_ssel[range >> 1] &= ~SBUS_SSEL_Y;
312: regs->sbus_ssel[range >> 1] |= sval;
313: } else {
314: regs->sbus_ssel[range >> 1] &= ~SBUS_SSEL_X;
315: regs->sbus_ssel[range >> 1] |= sval << 4;
316: }
317:
318: /* 2. Setup and enable the VME master range. */
319: rval = regs->vme_range[range];
320: rval &= ~(VME_RANGE_VMAE | VME_RANGE_VMAT);
321: rval |= (vmebase >> 13) & (VME_RANGE_VMAE | VME_RANGE_VMAT);
322: rval &= ~VME_RANGE_VMRCC;
323: rval |= ((sbusoffset << 4) | (vmelen << 3)) & VME_RANGE_VMRCC;
324: rval &= ~VME_RANGE_DECEN;
325: regs->vme_range[range] = rval;
326:
327: /* 3. Setup addr/data capabilities for the range. */
328: regs->vme_master_cap[range] &=
329: ~(VME_MASTER_CAP_DATA | VME_MASTER_CAP_ADDR);
330: regs->vme_master_cap[range] |= vmecap;
331:
332: (void)config_found(&sc->sc_dev, oca, fgaprint);
333:
334: return (0);
335: }
336:
337: int
338: fga_hwintr1(v)
339: void *v;
340: {
341: struct fga_softc *sc = v;
342: struct fga_regs *regs = sc->sc_regs;
343: u_int32_t bits = 0, stat;
344: int r = 0, s;
345:
346: s = splhigh();
347: stat = regs->intr_stat;
348: splx(s);
349:
350: if ((stat & INTR_STAT_VMEIRQ1) == 0) {
351: bits |= INTR_STAT_VMEIRQ1;
352: r |= fga_intrvec(sc, regs->viack_emu1);
353: }
354:
355: s = splhigh();
356: regs->intr_stat &= ~bits;
357: splx(s);
358:
359: return (r);
360: }
361:
362: int
363: fga_hwintr2(v)
364: void *v;
365: {
366: struct fga_softc *sc = v;
367: struct fga_regs *regs = sc->sc_regs;
368: int r = 0;
369:
370: if ((regs->intr_stat & INTR_STAT_VMEIRQ2) == 0)
371: r |= fga_intrvec(sc, regs->viack_emu2);
372:
373: return (r);
374: }
375:
376: int
377: fga_hwintr3(v)
378: void *v;
379: {
380: struct fga_softc *sc = v;
381: struct fga_regs *regs = sc->sc_regs;
382: int r = 0;
383:
384: /* vme irq 3 */
385: if ((regs->intr_stat & INTR_STAT_VMEIRQ3) == 0)
386: r |= fga_intrvec(sc, regs->viack_emu3);
387:
388: return (r);
389: }
390:
391: int
392: fga_hwintr4(v)
393: void *v;
394: {
395: struct fga_softc *sc = v;
396: struct fga_regs *regs = sc->sc_regs;
397: int r = 0;
398:
399: if ((regs->intr_stat & INTR_STAT_VMEIRQ4) == 0)
400: r |= fga_intrvec(sc, regs->viack_emu4);
401:
402: return (r);
403: }
404:
405: int
406: fga_hwintr5(v)
407: void *v;
408: {
409: struct fga_softc *sc = v;
410: struct fga_regs *regs = sc->sc_regs;
411: int r = 0;
412:
413: if ((regs->intr_stat & INTR_STAT_VMEIRQ5) == 0)
414: r |= fga_intrvec(sc, regs->viack_emu5);
415:
416: return (r);
417: }
418:
419: int
420: fga_hwintr6(v)
421: void *v;
422: {
423: struct fga_softc *sc = v;
424: struct fga_regs *regs = sc->sc_regs;
425: int r = 0;
426:
427: if ((regs->intr_stat & INTR_STAT_VMEIRQ6) == 0)
428: r |= fga_intrvec(sc, regs->viack_emu6);
429:
430: return (r);
431: }
432:
433: int
434: fga_hwintr7(v)
435: void *v;
436: {
437: struct fga_softc *sc = v;
438: struct fga_regs *regs = sc->sc_regs;
439: int r = 0, s;
440: u_int32_t bits = 0, stat;
441:
442: s = splhigh();
443: stat = regs->intr_stat;
444: splx(s);
445:
446: #ifdef DDB
447: if (sc->sc_abort && (stat & INTR_STAT_ABORT) == 0) {
448: bits |= INTR_STAT_ABORT;
449: r |= 1;
450: Debugger();
451: }
452: #endif
453:
454: if ((regs->intr_stat & INTR_STAT_VMEIRQ7) == 0) {
455: bits |= INTR_STAT_VMEIRQ7;
456: r |= fga_intrvec(sc, regs->viack_emu7);
457: }
458:
459: s = splhigh();
460: regs->intr_stat &= ~bits;
461: splx(s);
462:
463: return (r);
464: }
465:
466: /*
467: * Handle a VME vectored interrupt.
468: */
469: int
470: fga_intrvec(sc, vec)
471: struct fga_softc *sc;
472: u_int8_t vec;
473: {
474: struct intrhand *ih;
475: int r, s = 0;
476:
477: if (sc->sc_vmevec == NULL)
478: return (0);
479:
480: for (ih = sc->sc_vmevec[vec]; ih; ih = ih->ih_next) {
481: r = (*ih->ih_fun)(ih->ih_arg);
482: if (r > 0) {
483: ih->ih_count.ec_count++;
484: return (r);
485: }
486: s |= r;
487: }
488:
489: return (s);
490: }
491:
492: /*
493: * Establish a VME level/vector interrupt.
494: */
495: int
496: fga_intr_establish(sc, vec, level, ih, name)
497: struct fga_softc *sc;
498: int vec, level;
499: struct intrhand *ih;
500: const char *name;
501: {
502: struct intrhand *ihs;
503: const u_int8_t level_to_sint[] = {
504: IRQ_MAP_INT,
505: IRQ_MAP_SINT1,
506: IRQ_MAP_SINT2,
507: IRQ_MAP_SINT3,
508: IRQ_MAP_SINT4,
509: IRQ_MAP_SINT5,
510: IRQ_MAP_SINT6,
511: IRQ_MAP_SINT7
512: };
513: const u_int8_t level_to_irqmap[] = {0xff, 6, 5, 4, 3, 2, 1, 0};
514:
515: #ifdef DIAGNOSTIC
516: if (level < 1 || level > 7)
517: panic("fga_level");
518: #endif
519:
520: /* setup vector handler */
521: if (sc->sc_vmevec == NULL) {
522: sc->sc_vmevec = (struct intrhand **)malloc(256 *
523: sizeof(struct intrhand *), M_DEVBUF, M_NOWAIT);
524: if (sc->sc_vmevec == NULL)
525: panic("fga_addirq");
526: bzero(sc->sc_vmevec, 256 * sizeof(struct intrhand *));
527: }
528: if (sc->sc_vmevec[vec] == NULL)
529: sc->sc_vmevec[vec] = ih;
530: else {
531: ihs = sc->sc_vmevec[vec];
532: while (ihs->ih_next)
533: ihs = ihs->ih_next;
534: ih->ih_next = ih;
535: }
536:
537: ih->ih_vec = level;
538: evcount_attach(&ih->ih_count, name, &ih->ih_vec, &evcount_intr);
539:
540: /* setup hardware handler */
541: fga_hwintr_establish(sc, level_to_sint[level]);
542:
543: /* setup/enable vme -> sbus irq mapping */
544: sc->sc_regs->virq_map[level_to_irqmap[level]] &= ~IRQ_MAP_INT_MASK;
545: sc->sc_regs->virq_map[level_to_irqmap[level]] |= level_to_sint[level];
546: sc->sc_regs->virq_map[level_to_irqmap[level]] &= ~IRQ_MAP_ENABLE;
547:
548: return (0);
549: }
550:
551: /*
552: * Establish a hardware interrupt, making sure we're not there already.
553: */
554: int
555: fga_hwintr_establish(sc, sint)
556: struct fga_softc *sc;
557: u_int8_t sint;
558: {
559: const int sint_to_pri[] = {0, 2, 3, 5, 6, 7, 8, 9};
560:
561: if (sc->sc_established & (1 << sint))
562: return (0);
563:
564: switch (sint) {
565: case 1:
566: sc->sc_ih1.ih_fun = fga_hwintr1;
567: sc->sc_ih1.ih_arg = sc;
568: intr_establish(sint_to_pri[sint], &sc->sc_ih1, -1, NULL);
569: break;
570: case 2:
571: sc->sc_ih2.ih_fun = fga_hwintr2;
572: sc->sc_ih2.ih_arg = sc;
573: intr_establish(sint_to_pri[sint], &sc->sc_ih2, -1, NULL);
574: break;
575: case 3:
576: sc->sc_ih3.ih_fun = fga_hwintr3;
577: sc->sc_ih3.ih_arg = sc;
578: intr_establish(sint_to_pri[sint], &sc->sc_ih3, -1, NULL);
579: break;
580: case 4:
581: sc->sc_ih4.ih_fun = fga_hwintr4;
582: sc->sc_ih4.ih_arg = sc;
583: intr_establish(sint_to_pri[sint], &sc->sc_ih4, -1, NULL);
584: break;
585: case 5:
586: sc->sc_ih5.ih_fun = fga_hwintr5;
587: sc->sc_ih5.ih_arg = sc;
588: intr_establish(sint_to_pri[sint], &sc->sc_ih5, -1, NULL);
589: break;
590: case 6:
591: sc->sc_ih6.ih_fun = fga_hwintr6;
592: sc->sc_ih6.ih_arg = sc;
593: intr_establish(sint_to_pri[sint], &sc->sc_ih6, -1, NULL);
594: break;
595: case 7:
596: sc->sc_ih7.ih_fun = fga_hwintr7;
597: sc->sc_ih7.ih_arg = sc;
598: intr_establish(sint_to_pri[sint], &sc->sc_ih7, -1, NULL);
599: break;
600: #ifdef DIAGNOSTIC
601: default:
602: panic("fga_sint");
603: #endif
604: }
605:
606: sc->sc_established |= 1 << sint;
607: return (0);
608: }
609:
610: int
611: fgaopen(dev, flags, mode, p)
612: dev_t dev;
613: int flags, mode;
614: struct proc *p;
615: {
616: struct fga_softc *sc;
617:
618: if (fga_cd.cd_ndevs == 0)
619: return (ENXIO);
620: sc = fga_cd.cd_devs[0];
621: if (sc == NULL)
622: return (ENXIO);
623: return (0);
624: }
625:
626: int
627: fgaclose(dev, flags, mode, p)
628: dev_t dev;
629: int flags, mode;
630: struct proc *p;
631: {
632: return (0);
633: }
634:
635: int
636: fgaioctl(dev, cmd, data, flags, p)
637: dev_t dev;
638: u_long cmd;
639: caddr_t data;
640: int flags;
641: struct proc *p;
642: {
643: struct fga_softc *sc = fga_cd.cd_devs[0];
644: struct fga_sem *fsem = (struct fga_sem *)data;
645: int error = 0;
646:
647: switch (cmd) {
648: case FGAIOCSEM:
649: if (fsem->fgasem_num >= 48) {
650: error = ENOENT;
651: break;
652: }
653: sc->sc_regs->sem[fsem->fgasem_num] = 0xff;
654: break;
655: case FGAIOGSEM:
656: if (fsem->fgasem_num >= 48) {
657: error = ENOENT;
658: break;
659: }
660: fsem->fgasem_val =
661: (sc->sc_regs->sem[fsem->fgasem_num] & MBOX_SEM) ? 0 : 1;
662: break;
663: case FGAIOCMBX:
664: if (fsem->fgasem_num >= 16) {
665: error = ENOENT;
666: break;
667: }
668: sc->sc_regs->mbox[fsem->fgasem_num] = 0xff;
669: break;
670: case FGAIOGMBX:
671: if (fsem->fgasem_num >= 16) {
672: error = ENOENT;
673: break;
674: }
675: fsem->fgasem_val =
676: sc->sc_regs->mbox[fsem->fgasem_num] ? 0 : 1;
677: break;
678: default:
679: error = EINVAL;
680: }
681:
682: return (error);
683: }
684:
685: int
686: fvmematch(parent, vcf, aux)
687: struct device *parent;
688: void *vcf, *aux;
689: {
690: struct confargs *ca = aux;
691: struct romaux *ra = &ca->ca_ra;
692:
693: if (strcmp("fvme", ra->ra_name) || ca->ca_bustype != BUS_FGA)
694: return (0);
695:
696: return (1);
697: }
698:
699: const struct fvme_types {
700: int data_cap;
701: int addr_cap;
702: const char *name;
703: int bustype;
704: } fvme_types[] = {
705: {0, 0, "a16d8", BUS_FGA_A16D8},
706: {0, 1, "a24d8", BUS_FGA_A24D8},
707: {0, 2, "a32d8", BUS_FGA_A32D8},
708: {1, 0, "a16d16", BUS_FGA_A16D16},
709: {1, 1, "a24d16", BUS_FGA_A24D16},
710: {1, 2, "a32d16", BUS_FGA_A32D16},
711: {2, 0, "a16d32", BUS_FGA_A16D32},
712: {2, 1, "a24d32", BUS_FGA_A24D32},
713: {2, 2, "a32d32", BUS_FGA_A32D32},
714: {3, 0, "a16blt", -1},
715: {3, 1, "a24blt", -1},
716: {3, 2, "a32blt", -1},
717: {4, 0, "a16mblt", -1},
718: {4, 1, "a24mblt", -1},
719: {4, 2, "a32mblt", -1},
720: {-1, -1, "", -1},
721: };
722:
723: void
724: fvmeattach(parent, self, aux)
725: struct device *parent, *self;
726: void *aux;
727: {
728: struct confargs *ca = aux;
729: const struct fvme_types *p;
730: int dtype, atype;
731:
732: atype = (ca->ca_ra.ra_reg[1].rr_iospace & VME_MASTER_CAP_ADDR) >> 2;
733: dtype = (ca->ca_ra.ra_reg[1].rr_iospace & VME_MASTER_CAP_DATA) >> 5;
734: for (p = fvme_types; p->data_cap != -1; p++) {
735: if (p->data_cap == dtype && p->addr_cap == atype)
736: break;
737: }
738: if (p->data_cap == -1) {
739: printf(" unknown addr/data capability\n");
740: return;
741: }
742: printf(": %s", p->name);
743: if (p->bustype == -1) {
744: printf(" unsupported\n");
745: return;
746: }
747: ca->ca_ra.ra_reg[1].rr_iospace = p->bustype;
748:
749: printf(" offset 0x%x len 0x%x\n", ca->ca_ra.ra_reg[1].rr_paddr,
750: ca->ca_ra.ra_reg[1].rr_len);
751:
752: (void)config_search(fvmescan, self, aux);
753: }
754:
755: int
756: fvmescan(parent, child, aux)
757: struct device *parent;
758: void *child, *aux;
759: {
760: struct cfdata *cf = child;
761: struct confargs *ca = aux, oca;
762: int plen, paddr;
763:
764: if (cf->cf_loc[0] == -1)
765: return (0);
766:
767: if ((unsigned)cf->cf_loc[0] < (unsigned)ca->ca_ra.ra_reg[1].rr_paddr)
768: return (0);
769:
770: paddr = cf->cf_loc[0] - (int)ca->ca_ra.ra_reg[1].rr_paddr;
771: paddr = (int)ca->ca_ra.ra_reg[0].rr_paddr + paddr;
772: plen = cf->cf_loc[0] - (int)ca->ca_ra.ra_reg[1].rr_paddr;
773: plen = ca->ca_ra.ra_reg[1].rr_len - plen;
774:
775: oca.ca_bustype = ca->ca_ra.ra_reg[1].rr_iospace;
776: oca.ca_offset = cf->cf_loc[0];
777:
778: oca.ca_ra.ra_nintr = 1;
779: oca.ca_ra.ra_intr[0].int_pri = cf->cf_loc[1];
780: oca.ca_ra.ra_intr[0].int_vec = cf->cf_loc[2];
781: oca.ca_ra.ra_name = cf->cf_driver->cd_name;
782:
783: oca.ca_ra.ra_nreg = 1;
784: oca.ca_ra.ra_reg[0].rr_paddr = (void *)paddr;
785: oca.ca_ra.ra_reg[0].rr_iospace = ca->ca_ra.ra_reg[0].rr_iospace;
786: oca.ca_ra.ra_reg[0].rr_len = plen;
787: oca.ca_ra.ra_reg[0].rr_paddr =
788: mapdev(&oca.ca_ra.ra_reg[0], TMPMAP_VA, 0, NBPG);
789:
790: if ((*cf->cf_attach->ca_match)(parent, cf, &oca) == 0) {
791: bus_untmp();
792: return (0);
793: }
794: bus_untmp();
795:
796: oca.ca_ra.ra_reg[0].rr_paddr = (void *)paddr;
797: config_attach(parent, cf, &oca, fvmeprint);
798: return (1);
799: }
800:
801: int
802: fvmeprint(args, name)
803: void *args;
804: const char *name;
805: {
806: struct confargs *ca = args;
807:
808: if (name)
809: printf("%s at %s", ca->ca_ra.ra_name, name);
810: printf(" addr 0x%x", ca->ca_offset);
811: return (UNCONF);
812: }
813:
814: int
815: fvmeintrestablish(dsc, vec, level, ih, name)
816: struct device *dsc;
817: int vec, level;
818: struct intrhand *ih;
819: const char *name;
820: {
821: struct fga_softc *fsc = (struct fga_softc *)dsc->dv_parent;
822:
823: return (fga_intr_establish(fsc, vec, level, ih, name));
824: }
CVSweb