Annotation of sys/arch/mvme68k/dev/vme.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: vme.c,v 1.24 2005/11/27 14:19:09 miod Exp $ */
2:
3: /*
4: * Copyright (c) 1995 Theo de Raadt
5: * Copyright (c) 2000 Steve Murphree, Jr.
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: *
17: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27: */
28:
29: #include <sys/param.h>
30: #include <sys/conf.h>
31: #include <sys/ioctl.h>
32: #include <sys/proc.h>
33: #include <sys/user.h>
34: #include <sys/tty.h>
35: #include <sys/uio.h>
36: #include <sys/systm.h>
37: #include <sys/kernel.h>
38: #include <sys/syslog.h>
39: #include <sys/fcntl.h>
40: #include <sys/device.h>
41: #include <machine/autoconf.h>
42: #include <machine/cpu.h>
43: #include <mvme68k/dev/vme.h>
44:
45: #include "pcc.h"
46: #include "mc.h"
47: #include "pcctwo.h"
48:
49: #if NPCC > 0
50: #include <mvme68k/dev/pccreg.h>
51: #endif
52: #if NMC > 0
53: #include <mvme68k/dev/mcreg.h>
54: #endif
55: #if NPCCTWO > 0
56: #include <mvme68k/dev/pcctworeg.h>
57: #endif
58:
59: int vmematch(struct device *, void *, void *);
60: void vmeattach(struct device *, struct device *, void *);
61:
62: void vme1chip_init(struct vmesoftc *sc);
63: void vme2chip_init(struct vmesoftc *sc);
64: paddr_t vme2chip_map(u_long base, int len, int dwidth);
65: int vme2abort(void *);
66:
67: void vmeunmap(vaddr_t, int);
68: int vmeprint(void *, const char *);
69:
70: static int vmebustype;
71:
72: struct vme2reg *sys_vme2;
73:
74: struct cfattach vme_ca = {
75: sizeof(struct vmesoftc), vmematch, vmeattach
76: };
77:
78: struct cfdriver vme_cd = {
79: NULL, "vme", DV_DULL
80: };
81:
82: int
83: vmematch(parent, cf, args)
84: struct device *parent;
85: void *cf;
86: void *args;
87: {
88: #if NMC > 0
89: struct confargs *ca = args;
90:
91: if (ca->ca_bustype == BUS_MC) {
92: if (sys_mc->mc_ver & MC_VER_NOVME)
93: return (0);
94: }
95: #endif
96: return (1);
97: }
98:
99: #if defined(MVME162) || defined(MVME167) || defined(MVME177)
100: /*
101: * make local addresses 1G-2G correspond to VME addresses 3G-4G,
102: * as D32
103: */
104: #define VME2_D32STARTPHYS (1*1024*1024*1024UL)
105: #define VME2_D32ENDPHYS (2*1024*1024*1024UL)
106: #define VME2_D32STARTVME (3*1024*1024*1024UL)
107: #define VME2_D32BITSVME (3*1024*1024*1024UL)
108:
109: /*
110: * make local addresses 3G-3.75G correspond to VME addresses 3G-3.75G,
111: * as D16
112: */
113: #define VME2_D16STARTPHYS (3*1024*1024*1024UL)
114: #define VME2_D16ENDPHYS (3*1024*1024*1024UL + 768*1024*1024UL)
115: #endif
116:
117: /*
118: * Returns a physical address mapping for a VME address & length.
119: * Note: on some hardware it is not possible to create certain
120: * mappings, ie. the MVME147 cannot do 32 bit accesses to VME bus
121: * addresses from 0 to physmem.
122: */
123: paddr_t
124: vmepmap(sc, vmeaddr, len, bustype)
125: struct vmesoftc *sc;
126: paddr_t vmeaddr;
127: int len;
128: int bustype;
129: {
130: paddr_t base = vmeaddr;
131:
132: len = roundup(len, NBPG);
133: switch (vmebustype) {
134: #if NPCC > 0
135: case BUS_PCC:
136: switch (bustype) {
137: case BUS_VMES:
138: #ifdef DEBUG
139: printf("base %8p/0x%8x len 0x%x\n",
140: vmeaddr, base, len);
141: #endif
142: if (base > VME1_A16BASE &&
143: (base+len - VME1_A16BASE) < VME1_A16D16LEN) {
144: base = base - VME1_A16BASE + VME1_A16D16BASE;
145: #ifdef DEBUG
146: printf("vmes1: base = 0x%8x\n", base); /* 1:1 */
147: #endif
148: } else if (base > VME1_A32D16BASE &&
149: base+len < VME1_A16BASE) {
150: /* 1:1 mapped */
151: #ifdef DEBUG
152: printf("vmes2: base = 0x%8x\n", base);
153: #endif
154: } else {
155: printf("%s: cannot map pa 0x%x len 0x%x\n",
156: sc->sc_dev.dv_xname, base, len);
157: return (0);
158: }
159: break;
160: case BUS_VMEL:
161: if (base >= physmem && (base+len) < VME1_A32D32LEN)
162: base = base + VME1_A32D32BASE;
163: else if (base+len < VME1_A32D16LEN) /* HACK! */
164: base = base + VME1_A32D16BASE;
165: else {
166: printf("%s: cannot map pa 0x%x len 0x%x\n",
167: sc->sc_dev.dv_xname, base, len);
168: return (0);
169: }
170: break;
171: }
172: break;
173: #endif
174: #if NMC > 0 || NPCCTWO > 0
175: case BUS_MC:
176: case BUS_PCCTWO:
177: switch (bustype) {
178: case BUS_VMES:
179: #ifdef DEBUG
180: printf("base %x len %d\n", base, len);
181: #endif
182: if (base > VME2_A16BASE &&
183: (base+len-VME2_A16BASE) < VME2_A16D16LEN) {
184: /* XXX busted? */
185: base = base - VME2_A16BASE + VME2_A16D16BASE;
186: } else if (base > VME2_A24BASE &&
187: (base+len-VME2_A24BASE) < VME2_A24D16LEN) {
188: base = base - VME2_A24BASE + VME2_D16STARTPHYS;
189: } else if ((base+len) < VME2_A32D16LEN) {
190: /* XXX busted? */
191: base = base + VME2_A32D16BASE;
192: } else {
193: #ifdef DEBUG
194: printf("vme2chip_map\n");
195: #endif
196: base = vme2chip_map(base, len, 16);
197: }
198: break;
199: case BUS_VMEL:
200: #if 0
201: if (base > VME2_A16BASE &&
202: (base+len-VME2_A16BASE) < VME2_A16D32LEN)
203: base = base - VME2_A16BASE + VME2_A16D32BASE;
204: #endif
205: base = vme2chip_map(base, len, 32);
206: break;
207: }
208: break;
209: #endif
210: }
211: return (base);
212: }
213:
214: /* if successful, returns the va of a vme bus mapping */
215: vaddr_t
216: vmemap(sc, vmeaddr, len, bustype)
217: struct vmesoftc *sc;
218: paddr_t vmeaddr;
219: int len;
220: int bustype;
221: {
222: paddr_t pa;
223: vaddr_t va;
224:
225: pa = vmepmap(sc, vmeaddr, len, bustype);
226: if (pa == 0)
227: return (0);
228: va = mapiodev(pa, len);
229: return (va);
230: }
231:
232: void
233: vmeunmap(va, len)
234: vaddr_t va;
235: int len;
236: {
237: unmapiodev(va, len);
238: }
239:
240: int
241: vmerw(sc, uio, flags, bus)
242: struct vmesoftc *sc;
243: struct uio *uio;
244: int flags;
245: int bus;
246: {
247: vaddr_t v;
248: int c;
249: struct iovec *iov;
250: vaddr_t vme;
251: int error = 0;
252:
253: while (uio->uio_resid > 0 && error == 0) {
254: iov = uio->uio_iov;
255: if (iov->iov_len == 0) {
256: uio->uio_iov++;
257: uio->uio_iovcnt--;
258: if (uio->uio_iovcnt < 0)
259: panic("vmerw");
260: continue;
261: }
262:
263: v = uio->uio_offset;
264: c = min(iov->iov_len, MAXPHYS);
265: if ((v & PGOFSET) + c > NBPG) /* max NBPG at a time */
266: c = NBPG - (v & PGOFSET);
267: if (c == 0)
268: return (0);
269: vme = vmemap(sc, trunc_page(v), NBPG, BUS_VMES);
270: if (vme == 0) {
271: error = EFAULT; /* XXX? */
272: continue;
273: }
274: error = uiomove((void *)vme + (v & PGOFSET), c, uio);
275: vmeunmap(vme, NBPG);
276: }
277: return (error);
278: }
279:
280: int
281: vmeprint(args, bus)
282: void *args;
283: const char *bus;
284: {
285: struct confargs *ca = args;
286:
287: printf(" addr 0x%x", ca->ca_offset);
288: if (ca->ca_vec > 0)
289: printf(" vec 0x%x", ca->ca_vec);
290: if (ca->ca_ipl > 0)
291: printf(" ipl %d", ca->ca_ipl);
292: return (UNCONF);
293: }
294:
295: int
296: vmescan(parent, child, args, bustype)
297: struct device *parent;
298: void *child, *args;
299: int bustype;
300: {
301: struct cfdata *cf = child;
302: struct vmesoftc *sc = (struct vmesoftc *)parent;
303: struct confargs oca;
304:
305: bzero(&oca, sizeof oca);
306: oca.ca_bustype = bustype;
307: oca.ca_paddr = cf->cf_loc[0];
308: oca.ca_vec = cf->cf_loc[1];
309: oca.ca_ipl = cf->cf_loc[2];
310: if (oca.ca_ipl > 0 && oca.ca_vec == -1)
311: oca.ca_vec = intr_findvec(255, 0);
312:
313: oca.ca_offset = oca.ca_paddr;
314: oca.ca_vaddr = vmemap(sc, oca.ca_paddr, PAGE_SIZE, oca.ca_bustype);
315: if (oca.ca_vaddr == 0)
316: oca.ca_vaddr = (vaddr_t)-1;
317: oca.ca_name = cf->cf_driver->cd_name;
318: if ((*cf->cf_attach->ca_match)(parent, cf, &oca) == 0) {
319: if (oca.ca_vaddr != (vaddr_t)-1)
320: vmeunmap(oca.ca_vaddr, PAGE_SIZE);
321: return (0);
322: }
323: /*
324: * If match works, the driver is responsible for
325: * vmunmap()ing if it does not need the mapping.
326: */
327: config_attach(parent, cf, &oca, vmeprint);
328: return (1);
329: }
330:
331: void
332: vmeattach(parent, self, args)
333: struct device *parent, *self;
334: void *args;
335: {
336: struct vmesoftc *sc = (struct vmesoftc *)self;
337: struct confargs *ca = args;
338: #if NPCC > 0
339: struct vme1reg *vme1;
340: #endif
341: #if NMC > 0 || NPCCTWO > 0
342: struct vme2reg *vme2;
343: #endif
344:
345: sc->sc_vaddr = ca->ca_vaddr;
346:
347: vmebustype = ca->ca_bustype;
348: switch (ca->ca_bustype) {
349: #if NPCC > 0
350: case BUS_PCC:
351: vme1 = (struct vme1reg *)sc->sc_vaddr;
352: if (vme1->vme1_scon & VME1_SCON_SWITCH)
353: printf(": system controller");
354: printf("\n");
355: vme1chip_init(sc);
356: break;
357: #endif
358: #if NMC > 0 || NPCCTWO > 0
359: case BUS_MC:
360: case BUS_PCCTWO:
361: vme2 = (struct vme2reg *)sc->sc_vaddr;
362: if (vme2->vme2_tctl & VME2_TCTL_SCON)
363: printf(": system controller");
364: printf("\n");
365: vme2chip_init(sc);
366: break;
367: #endif
368: }
369:
370: while (config_found(self, NULL, NULL))
371: ;
372: }
373:
374: /*
375: * On the VMEbus, only one cpu may be configured to respond to any
376: * particular vme ipl. Therefore, it wouldn't make sense to globally
377: * enable all the interrupts all the time -- it would not be possible
378: * to put two cpu's and one vme card into a single cage. Rather, we
379: * enable each vme interrupt only when we are attaching a device that
380: * uses it. This makes it easier (though not trivial) to put two cpu
381: * cards in one VME cage, and both can have some limited access to vme
382: * interrupts (just can't share the same irq).
383: * Obviously no check is made to see if another cpu is using that
384: * interrupt. If you share you will lose.
385: */
386: int
387: vmeintr_establish(vec, ih, name)
388: int vec;
389: struct intrhand *ih;
390: const char *name;
391: {
392: struct vmesoftc *sc = (struct vmesoftc *) vme_cd.cd_devs[0];
393: #if NPCC > 0
394: struct vme1reg *vme1;
395: #endif
396: #if NMC > 0 || NPCCTWO > 0
397: struct vme2reg *vme2;
398: #endif
399: int x;
400:
401: x = intr_establish(vec, ih, name);
402:
403: switch (vmebustype) {
404: #if NPCC > 0
405: case BUS_PCC:
406: vme1 = (struct vme1reg *)sc->sc_vaddr;
407: vme1->vme1_irqen = vme1->vme1_irqen |
408: VME1_IRQ_VME(ih->ih_ipl);
409: break;
410: #endif
411: #if NMC > 0 || NPCCTWO > 0
412: case BUS_MC:
413: case BUS_PCCTWO:
414: vme2 = (struct vme2reg *)sc->sc_vaddr;
415: vme2->vme2_irqen = vme2->vme2_irqen |
416: VME2_IRQ_VME(ih->ih_ipl);
417: break;
418: #endif
419: }
420: return (x);
421: }
422:
423: #if defined(MVME147)
424: void
425: vme1chip_init(sc)
426: struct vmesoftc *sc;
427: {
428: struct vme1reg *vme1 = (struct vme1reg *)sc->sc_vaddr;
429:
430: vme1->vme1_scon &= ~VME1_SCON_SYSFAIL; /* XXX doesn't work */
431: }
432: #endif
433:
434:
435: #if defined(MVME162) || defined(MVME167) || defined(MVME177)
436:
437: /*
438: * XXX what AM bits should be used for the D32/D16 mappings?
439: */
440: void
441: vme2chip_init(sc)
442: struct vmesoftc *sc;
443: {
444: struct vme2reg *vme2 = (struct vme2reg *)sc->sc_vaddr;
445: u_long ctl;
446:
447: sys_vme2 = vme2;
448:
449: /* turn off SYSFAIL LED */
450: vme2->vme2_tctl &= ~VME2_TCTL_SYSFAIL;
451:
452: /*
453: * Display the VMEChip2 decoder status.
454: */
455: printf("%s: using BUG parameters\n", sc->sc_dev.dv_xname);
456: ctl = vme2->vme2_gcsrctl;
457: if (ctl & VME2_GCSRCTL_MDEN1) {
458: printf("%s: 1phys 0x%08lx-0x%08lx to VME 0x%08lx-0x%08lx\n",
459: sc->sc_dev.dv_xname,
460: vme2->vme2_master1 << 16, vme2->vme2_master1 & 0xffff0000,
461: vme2->vme2_master1 << 16, vme2->vme2_master1 & 0xffff0000);
462: }
463: if (ctl & VME2_GCSRCTL_MDEN2) {
464: printf("%s: 2phys 0x%08lx-0x%08lx to VME 0x%08lx-0x%08lx\n",
465: sc->sc_dev.dv_xname,
466: vme2->vme2_master2 << 16, vme2->vme2_master2 & 0xffff0000,
467: vme2->vme2_master2 << 16, vme2->vme2_master2 & 0xffff0000);
468: }
469: if (ctl & VME2_GCSRCTL_MDEN3) {
470: printf("%s: 3phys 0x%08lx-0x%08lx to VME 0x%08lx-0x%08lx\n",
471: sc->sc_dev.dv_xname,
472: vme2->vme2_master3 << 16, vme2->vme2_master3 & 0xffff0000,
473: vme2->vme2_master3 << 16, vme2->vme2_master3 & 0xffff0000);
474: }
475: if (ctl & VME2_GCSRCTL_MDEN4) {
476: printf("%s: 4phys 0x%08lx-0x%08lx to VME 0x%08lx-0x%08lx\n",
477: sc->sc_dev.dv_xname,
478: vme2->vme2_master4 << 16, vme2->vme2_master4 & 0xffff0000,
479: (vme2->vme2_master4 << 16) + (vme2->vme2_master4mod << 16),
480: (vme2->vme2_master4 & 0xffff0000) +
481: (vme2->vme2_master4mod & 0xffff0000));
482: }
483:
484: /*
485: * Map the VME irq levels to the cpu levels 1:1.
486: * This is rather inflexible, but much easier.
487: */
488: vme2->vme2_irql4 = (7 << VME2_IRQL4_VME7SHIFT) |
489: (6 << VME2_IRQL4_VME6SHIFT) | (5 << VME2_IRQL4_VME5SHIFT) |
490: (4 << VME2_IRQL4_VME4SHIFT) | (3 << VME2_IRQL4_VME3SHIFT) |
491: (2 << VME2_IRQL4_VME2SHIFT) | (1 << VME2_IRQL4_VME1SHIFT);
492: printf("%s: vme to cpu irq level 1:1\n",sc->sc_dev.dv_xname);
493:
494: #if NPCCTWO > 0
495: if (vmebustype == BUS_PCCTWO) {
496: /*
497: * pseudo driver, abort interrupt handler
498: */
499: sc->sc_abih.ih_fn = vme2abort;
500: sc->sc_abih.ih_ipl = 7;
501: sc->sc_abih.ih_wantframe = 1;
502:
503: intr_establish(110, &sc->sc_abih, sc->sc_dev.dv_xname); /* XXX 110 */
504: vme2->vme2_irqen |= VME2_IRQ_AB;
505: }
506: #endif
507: /*
508: * Enable ACFAIL interrupt, but disable Timer 1 interrupt - we
509: * prefer it without for delay().
510: */
511: vme2->vme2_irqen = (vme2->vme2_irqen | VME2_IRQ_ACF) & ~VME2_IRQ_TIC1;
512: }
513:
514: /*
515: * A32 accesses on the MVME1[67]x require setting up mappings in
516: * the VME2 chip.
517: * XXX VME address must be between 2G and 4G
518: * XXX We only support D32 at the moment..
519: */
520: u_long
521: vme2chip_map(base, len, dwidth)
522: u_long base;
523: int len, dwidth;
524: {
525: switch (dwidth) {
526: case 16:
527: if (base < VME2_D16STARTPHYS ||
528: base + (u_long)len > VME2_D16ENDPHYS)
529: return (NULL);
530: return (base);
531: case 32:
532: if (base < VME2_D32STARTVME)
533: return (NULL);
534: return (base - VME2_D32STARTVME + VME2_D32STARTPHYS);
535: default:
536: return (NULL);
537: }
538: }
539:
540: #if NPCCTWO > 0
541: int
542: vme2abort(frame)
543: void *frame;
544: {
545: struct vmesoftc *sc = (struct vmesoftc *)vme_cd.cd_devs[0];
546: struct vme2reg *vme2 = (struct vme2reg *)sc->sc_vaddr;
547:
548: if ((vme2->vme2_irqstat & VME2_IRQ_AB) == 0) {
549: printf("%s: abort irq not set\n", sc->sc_dev.dv_xname);
550: return (0);
551: }
552: vme2->vme2_irqclr = VME2_IRQ_AB;
553: nmihand(frame);
554: return (1);
555: }
556: #endif
557: #endif
CVSweb