Annotation of sys/arch/mvme68k/dev/vme.c, Revision 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