|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1988 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * This code is derived from software contributed to Berkeley by ! 6: * Computer Consoles Inc. ! 7: * ! 8: * Redistribution is only permitted until one year after the first shipment ! 9: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 10: * binary forms are permitted provided that: (1) source distributions retain ! 11: * this entire copyright notice and comment, and (2) distributions including ! 12: * binaries display the following acknowledgement: This product includes ! 13: * software developed by the University of California, Berkeley and its ! 14: * contributors'' in the documentation or other materials provided with the ! 15: * distribution and in all advertising materials mentioning features or use ! 16: * of this software. Neither the name of the University nor the names of ! 17: * its contributors may be used to endorse or promote products derived from ! 18: * this software without specific prior written permission. ! 19: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 20: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 21: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 22: * ! 23: * @(#)dr.c 7.8 (Berkeley) 6/28/90 ! 24: */ ! 25: ! 26: #include "dr.h" ! 27: #if NDR > 0 ! 28: /* ! 29: * DRV11-W DMA interface driver. ! 30: * ! 31: * UNTESTED WITH 4.3 ! 32: */ ! 33: #include "machine/mtpr.h" ! 34: #include "machine/pte.h" ! 35: ! 36: #include "param.h" ! 37: #include "conf.h" ! 38: #include "user.h" ! 39: #include "proc.h" ! 40: #include "map.h" ! 41: #include "ioctl.h" ! 42: #include "buf.h" ! 43: #include "vm.h" ! 44: #include "kernel.h" ! 45: ! 46: #include "../tahoevba/vbavar.h" ! 47: #include "../tahoevba/drreg.h" ! 48: ! 49: #define YES 1 ! 50: #define NO 0 ! 51: ! 52: struct vba_device *drinfo[NDR]; ! 53: struct dr_aux dr_aux[NDR]; ! 54: ! 55: unsigned drminphys(); ! 56: int drprobe(), drintr(), drattach(), drtimo(), drrwtimo(); ! 57: int drstrategy(); ! 58: extern struct vba_device *drinfo[]; ! 59: static long drstd[] = { 0 }; ! 60: struct vba_driver drdriver = ! 61: { drprobe, 0, drattach, 0, drstd, "rs", drinfo }; ! 62: ! 63: #define RSUNIT(dev) (minor(dev) & 7) ! 64: #define SPL_UP spl5 ! 65: ! 66: /* -------- Per-unit data -------- */ ! 67: ! 68: extern struct dr_aux dr_aux[]; ! 69: ! 70: #ifdef DR_DEBUG ! 71: long DR11 = 0; ! 72: #endif ! 73: ! 74: drprobe(reg, vi) ! 75: caddr_t reg; ! 76: struct vba_device *vi; ! 77: { ! 78: register int br, cvec; /* must be r12, r11 */ ! 79: struct rsdevice *dr; ! 80: ! 81: #ifdef lint ! 82: br = 0; cvec = br; br = cvec; ! 83: drintr(0); ! 84: #endif ! 85: if (badaddr(reg, 2)) ! 86: return (0); ! 87: dr = (struct rsdevice *)reg; ! 88: dr->dr_intvect = --vi->ui_hd->vh_lastiv; ! 89: #ifdef DR_DEBUG ! 90: printf("dprobe: Set interrupt vector %lx and init\n",dr->dr_intvec); ! 91: #endif ! 92: /* generate interrupt here for autoconfig */ ! 93: dr->dr_cstat = MCLR; /* init board and device */ ! 94: #ifdef DR_DEBUG ! 95: printf("drprobe: Initial status %lx\n", dr->dr_cstat); ! 96: #endif ! 97: br = 0x18, cvec = dr->dr_intvect; /* XXX */ ! 98: return (sizeof (struct rsdevice)); /* DR11 exist */ ! 99: } ! 100: ! 101: /* ARGSUSED */ ! 102: drattach(ui) ! 103: struct vba_device *ui; ! 104: { ! 105: register struct dr_aux *rsd; ! 106: ! 107: rsd = &dr_aux[ui->ui_unit]; ! 108: rsd->dr_flags = DR_PRES; /* This dr11 is present */ ! 109: rsd->dr_addr = (struct rsdevice *)ui->ui_addr; /* Save addr of this dr11 */ ! 110: rsd->dr_istat = 0; ! 111: rsd->dr_bycnt = 0; ! 112: rsd->dr_cmd = 0; ! 113: rsd->currenttimo = 0; ! 114: } ! 115: ! 116: /*ARGSUSED*/ ! 117: dropen(dev, flag) ! 118: dev_t dev; ! 119: int flag; ! 120: { ! 121: register int unit = RSUNIT(dev); ! 122: register struct rsdevice *dr; ! 123: register struct dr_aux *rsd; ! 124: ! 125: if (drinfo[unit] == 0 || !drinfo[unit]->ui_alive) ! 126: return (ENXIO); ! 127: dr = RSADDR(unit); ! 128: rsd = &dr_aux[unit]; ! 129: if (rsd->dr_flags & DR_OPEN) { ! 130: #ifdef DR_DEBUG ! 131: printf("\ndropen: dr11 unit %ld already open",unit); ! 132: #endif ! 133: return (ENXIO); /* DR11 already open */ ! 134: } ! 135: rsd->dr_flags |= DR_OPEN; /* Mark it OPEN */ ! 136: rsd->dr_istat = 0; /* Clear status of previous interrupt */ ! 137: rsd->rtimoticks = hz; /* Set read no stall timout to 1 sec */ ! 138: rsd->wtimoticks = hz*60; /* Set write no stall timout to 1 min */ ! 139: dr->dr_cstat = DR_ZERO; /* Clear function & latches */ ! 140: dr->dr_pulse = (RDMA | RATN); /* clear leftover attn & e-o-r flags */ ! 141: drtimo(dev); /* start the self kicker */ ! 142: return (0); ! 143: } ! 144: ! 145: drclose (dev) ! 146: dev_t dev; ! 147: { ! 148: register int unit = RSUNIT(dev); ! 149: register struct dr_aux *dra; ! 150: register struct rsdevice *rs; ! 151: register short s; ! 152: ! 153: dra = &dr_aux[unit]; ! 154: if ((dra->dr_flags & DR_OPEN) == 0) { ! 155: #ifdef DR_DEBUG ! 156: printf("\ndrclose: DR11 device %ld not open",unit); ! 157: #endif ! 158: return; ! 159: } ! 160: dra->dr_flags &= ~(DR_OPEN|DR_ACTV); ! 161: rs = dra->dr_addr; ! 162: s = SPL_UP(); ! 163: rs->dr_cstat = DR_ZERO; ! 164: if (dra->dr_buf.b_flags & B_BUSY) { ! 165: dra->dr_buf.b_flags &= ~B_BUSY; ! 166: wakeup((caddr_t)&dra->dr_buf.b_flags); ! 167: } ! 168: splx(s); ! 169: return (0); ! 170: } ! 171: ! 172: ! 173: /* drread() works exactly like drwrite() except that the ! 174: B_READ flag is used when physio() is called ! 175: */ ! 176: drread (dev, uio) ! 177: dev_t dev; ! 178: struct uio *uio; ! 179: { register struct dr_aux *dra; ! 180: register struct buf *bp; ! 181: register int spl, err; ! 182: register int unit = RSUNIT(dev); ! 183: ! 184: if (uio->uio_iov->iov_len <= 0 || /* Negative count */ ! 185: uio->uio_iov->iov_len & 1 || /* odd count */ ! 186: (int)uio->uio_iov->iov_base & 1) /* odd destination address */ ! 187: return (EINVAL); ! 188: #ifdef DR_DEBUG ! 189: if (DR11 & 8) ! 190: printf("\ndrread: (len:%ld)(base:%lx)", ! 191: uio->uio_iov->iov_len,(int)uio->uio_iov->iov_base); ! 192: #endif ! 193: dra = &dr_aux[RSUNIT(dev)]; ! 194: dra->dr_op = DR_READ; ! 195: bp = &dra->dr_buf; ! 196: bp->b_resid = 0; ! 197: if (dra->dr_flags & DR_NORSTALL) { ! 198: /* ! 199: * We are in no stall mode, start the timer, ! 200: * raise IPL so nothing can stop us once the ! 201: * timer's running ! 202: */ ! 203: spl = SPL_UP(); ! 204: timeout(drrwtimo, (caddr_t)((dra->currenttimo<<8) | unit), ! 205: (int)dra->rtimoticks); ! 206: err = physio(drstrategy, bp, dev,B_READ, drminphys, uio); ! 207: splx(spl); ! 208: if (err) ! 209: return (err); ! 210: dra->currenttimo++; /* Update current timeout number */ ! 211: /* Did we timeout */ ! 212: if (dra->dr_flags & DR_TMDM) ! 213: dra->dr_flags &= ~DR_TMDM; /* Clear timeout flag */ ! 214: return (err); ! 215: } ! 216: return (physio(drstrategy, bp, dev,B_READ, drminphys, uio)); ! 217: } ! 218: ! 219: drwrite(dev, uio) ! 220: dev_t dev; ! 221: struct uio *uio; ! 222: { register struct dr_aux *dra; ! 223: register struct buf *bp; ! 224: register int unit = RSUNIT(dev); ! 225: int spl, err; ! 226: ! 227: if (uio->uio_iov->iov_len <= 0 || uio->uio_iov->iov_len & 1 || ! 228: (int)uio->uio_iov->iov_base & 1) ! 229: return (EINVAL); ! 230: #ifdef DR_DEBUG ! 231: if (DR11 & 4) ! 232: printf("\ndrwrite: (len:%ld)(base:%lx)", ! 233: uio->uio_iov->iov_len,(int)uio->uio_iov->iov_base); ! 234: #endif ! 235: dra = &dr_aux[RSUNIT(dev)]; ! 236: dra->dr_op = DR_WRITE; ! 237: bp = &dra->dr_buf; ! 238: bp->b_resid = 0; ! 239: if (dra->dr_flags & DR_NOWSTALL) { ! 240: /* ! 241: * We are in no stall mode, start the timer, ! 242: * raise IPL so nothing can stop us once the ! 243: * timer's running ! 244: */ ! 245: spl = SPL_UP(); ! 246: timeout(drrwtimo,(caddr_t)((dra->currenttimo<<8) | unit), ! 247: (int)dra->wtimoticks); ! 248: err = physio (drstrategy, bp, dev,B_WRITE, drminphys, uio); ! 249: splx(spl); ! 250: if (err) ! 251: return (err); ! 252: dra->currenttimo++; /* Update current timeout number */ ! 253: /* Did we timeout */ ! 254: if (dra->dr_flags & DR_TMDM) ! 255: dra->dr_flags &= ~DR_TMDM; /* Clear timeout flag */ ! 256: return (err); ! 257: } ! 258: return (physio(drstrategy, bp, dev,B_WRITE, drminphys, uio)); ! 259: } ! 260: ! 261: /* ! 262: * Routine used by calling program to issue commands to dr11 driver and ! 263: * through it to the device. ! 264: * It is also used to read status from the device and driver and to wait ! 265: * for attention interrupts. ! 266: * Status is returned in an 8 elements unsigned short integer array, the ! 267: * first two elements of the array are also used to pass arguments to ! 268: * drioctl() if required. ! 269: * The function bits to be written to the dr11 are included in the cmd ! 270: * argument. Even if they are not being written to the dr11 in a particular ! 271: * drioctl() call, they will update the copy of cmd that is stored in the ! 272: * driver. When drstrategy() is called, this updated copy is used if a ! 273: * deferred function bit write has been specified. The "side effect" of ! 274: * calls to the drioctl() requires that the last call prior to a read or ! 275: * write has an appropriate copy of the function bits in cmd if they are ! 276: * to be used in drstrategy(). ! 277: * When used as command value, the contents of data[0] is the command ! 278: * parameter. ! 279: */ ! 280: drioctl(dev, cmd, data) ! 281: dev_t dev; ! 282: int cmd; ! 283: long *data; ! 284: { ! 285: register int unit = RSUNIT(dev); ! 286: register struct dr_aux *dra; ! 287: register struct rsdevice *rsaddr = RSADDR(unit); ! 288: int s, error = 0; ! 289: u_short status; ! 290: long temp; ! 291: ! 292: #ifdef DR_DEBUG ! 293: if (DR11 & 0x10) ! 294: printf("\ndrioctl: (dev:%lx)(cmd:%lx)(data:%lx)(data[0]:%lx)", ! 295: dev,cmd,data,data[0]); ! 296: #endif ! 297: dra = &dr_aux[unit]; ! 298: dra->dr_cmd = 0; /* Fresh copy; clear all previous flags */ ! 299: switch (cmd) { ! 300: ! 301: case DRWAIT: /* Wait for attention interrupt */ ! 302: #ifdef DR_DEBUG ! 303: printf("\ndrioctl: wait for attention interrupt"); ! 304: #endif ! 305: s = SPL_UP(); ! 306: /* ! 307: * If the attention flag in dr_flags is set, it probably ! 308: * means that an attention has arrived by the time a ! 309: * previous DMA end-of-range interrupt was serviced. If ! 310: * ATRX is set, we will return with out sleeping, since ! 311: * we have received an attention since the last call to ! 312: * wait on attention. This may not be appropriate for ! 313: * some applications. ! 314: */ ! 315: if ((dra->dr_flags & DR_ATRX) == 0) { ! 316: dra->dr_flags |= DR_ATWT; /* Set waiting flag */ ! 317: /* ! 318: * Enable interrupt; use pulse reg. ! 319: * so function bits are not changed ! 320: */ ! 321: rsaddr->dr_pulse = IENB; ! 322: error = tsleep((caddr_t)&dra->dr_cmd, DRPRI | PCATCH, ! 323: devio, 0); ! 324: } ! 325: splx(s); ! 326: break; ! 327: ! 328: case DRPIOW: /* Write to p-i/o register */ ! 329: rsaddr->dr_data = data[0]; ! 330: break; ! 331: ! 332: case DRPACL: /* Send pulse to device */ ! 333: rsaddr->dr_pulse = FCN2; ! 334: break; ! 335: ! 336: case DRDACL: /* Defer alco pulse until go */ ! 337: dra->dr_cmd |= DR_DACL; ! 338: break; ! 339: ! 340: case DRPCYL: /* Set cycle with next go */ ! 341: dra->dr_cmd |= DR_PCYL; ! 342: break; ! 343: ! 344: case DRDFCN: /* Update function with next go */ ! 345: dra->dr_cmd |= DR_DFCN; ! 346: break; ! 347: ! 348: case DRRATN: /* Reset attention flag */ ! 349: rsaddr->dr_pulse = RATN; ! 350: break; ! 351: ! 352: case DRRDMA: /* Reset DMA e-o-r flag */ ! 353: rsaddr->dr_pulse = RDMA; ! 354: break; ! 355: ! 356: case DRSFCN: /* Set function bits */ ! 357: temp = data[0] & DR_FMSK; ! 358: /* ! 359: * This has a very important side effect -- It clears ! 360: * the interrupt enable flag. That is fine for this driver, ! 361: * but if it is desired to leave interrupt enable at all ! 362: * times, it will be necessary to read the status register ! 363: * first to get IENB, or carry a software flag that indicates ! 364: * whether interrupts are set, and or this into the control ! 365: * register value being written. ! 366: */ ! 367: rsaddr->dr_cstat = temp; ! 368: break; ! 369: ! 370: case DRRPER: /* Clear parity flag */ ! 371: rsaddr->dr_pulse = RPER; ! 372: break; ! 373: ! 374: case DRSETRSTALL: /* Set read stall mode. */ ! 375: dra->dr_flags &= (~DR_NORSTALL); ! 376: break; ! 377: ! 378: case DRSETNORSTALL: /* Set no stall read mode. */ ! 379: dra->dr_flags |= DR_NORSTALL; ! 380: break; ! 381: ! 382: case DRGETRSTALL: /* Returns true if in read stall mode */ ! 383: data[0] = (dra->dr_flags & DR_NORSTALL)? 0 : 1; ! 384: break; ! 385: ! 386: case DRSETRTIMEOUT: /* Set read stall timeout (1/10 secs) */ ! 387: if (data[0] < 1) ! 388: error = EINVAL; ! 389: dra->rtimoticks = (data[0] * hz )/10; ! 390: break; ! 391: ! 392: case DRGETRTIMEOUT: /* Return read stall timeout */ ! 393: data[0] = ((dra->rtimoticks)*10)/hz; ! 394: break; ! 395: ! 396: case DRSETWSTALL: /* Set write stall mode. */ ! 397: dra->dr_flags &= (~DR_NOWSTALL); ! 398: break; ! 399: ! 400: case DRSETNOWSTALL: /* Set write stall mode. */ ! 401: dra->dr_flags |= DR_NOWSTALL; ! 402: break; ! 403: ! 404: case DRGETWSTALL: /* Return true if in write stall mode */ ! 405: data[0] = (dra->dr_flags & DR_NOWSTALL)? 0 : 1; ! 406: break; ! 407: ! 408: case DRSETWTIMEOUT: /* Set write stall timeout (1/10's) */ ! 409: if (data[0] < 1) ! 410: error = EINVAL; ! 411: dra->wtimoticks = (data[0] * hz )/10; ! 412: break; ! 413: ! 414: case DRGETWTIMEOUT: /* Return write stall timeout */ ! 415: data[0] = ((dra->wtimoticks)*10)/hz; ! 416: break; ! 417: ! 418: case DRWRITEREADY: /* Return true if can write data */ ! 419: data[0] = (rsaddr->dr_cstat & STTA)? 1 : 0; ! 420: break; ! 421: ! 422: case DRREADREADY: /* Return true if data to be read */ ! 423: data[0] = (rsaddr->dr_cstat & STTB)? 1 : 0; ! 424: break; ! 425: ! 426: case DRBUSY: /* Return true if device busy */ ! 427: /* ! 428: * Internally this is the DR11-W ! 429: * STAT C bit, but there is a bug in the Omega 500/FIFO ! 430: * interface board that it cannot drive this signal low ! 431: * for certain DR11-W ctlr such as the Ikon. We use the ! 432: * REDY signal of the CSR on the Ikon DR11-W instead. ! 433: */ ! 434: #ifdef notdef ! 435: data[0] = (rsaddr->dr_cstat & STTC)? 1 : 0; ! 436: #else ! 437: data[0] = ((rsaddr->dr_cstat & REDY)? 0 : 1); ! 438: #endif ! 439: break; ! 440: ! 441: case DRRESET: /* Reset device */ ! 442: /* Reset DMA ATN RPER flag */ ! 443: rsaddr->dr_pulse = (MCLR|RDMA|RATN|RPER); ! 444: DELAY(0x1f000); ! 445: while ((rsaddr->dr_cstat & REDY) == 0 && error == 0) ! 446: /* Wakeup by drtimo() */ ! 447: error = tsleep((caddr_t)dra, DRPRI | PCATCH, devio, 0); ! 448: dra->dr_istat = 0; ! 449: dra->dr_cmd = 0; ! 450: dra->currenttimo = 0; ! 451: break; ! 452: ! 453: case DR11STAT: { /* Copy back dr11 status to user */ ! 454: register struct dr11io *dr = (struct dr11io *)data; ! 455: dr->arg[0] = dra->dr_flags; ! 456: dr->arg[1] = rsaddr->dr_cstat; ! 457: dr->arg[2] = dra->dr_istat; /* Status at last interrupt */ ! 458: dr->arg[3] = rsaddr->dr_data; /* P-i/o input data */ ! 459: status = (u_short)((rsaddr->dr_addmod << 8) & 0xff00); ! 460: dr->arg[4] = status | (u_short)(rsaddr->dr_intvect & 0xff); ! 461: dr->arg[5] = rsaddr->dr_range; ! 462: dr->arg[6] = rsaddr->dr_rahi; ! 463: dr->arg[7] = rsaddr->dr_ralo; ! 464: break; ! 465: } ! 466: case DR11LOOP: /* Perform loopback test */ ! 467: /* ! 468: * NB: MUST HAVE LOOPBACK CABLE ATTACHED -- ! 469: * Test results are printed on system console ! 470: */ ! 471: if (error = suser(u.u_cred, &u.u_acflag)) ! 472: break; ! 473: dr11loop(rsaddr, dra, unit); ! 474: break; ! 475: ! 476: default: ! 477: return (EINVAL); ! 478: } ! 479: #ifdef DR_DEBUG ! 480: if (DR11 & 0x10) ! 481: printf("**** (data[0]:%lx)",data[0]); ! 482: #endif ! 483: return (error); ! 484: } ! 485: ! 486: #define NPAT 2 ! 487: #define DMATBL 20 ! 488: u_short tstpat[DMATBL] = { 0xAAAA, 0x5555}; ! 489: long DMAin = 0; ! 490: ! 491: /* ! 492: * Perform loopback test -- MUST HAVE LOOPBACK CABLE ATTACHED ! 493: * Test results are printed on system console ! 494: */ ! 495: dr11loop(dr, dra, unit) ! 496: struct rsdevice *dr; ! 497: struct dr_aux *dra; ! 498: int unit; ! 499: { ! 500: register long result, ix; ! 501: long addr, wait; ! 502: ! 503: dr->dr_cstat = MCLR; /* Clear board & device, disable intr */ ! 504: printf("\n\t ----- DR11 unit %ld loopback test -----", unit); ! 505: printf("\n\t Program I/O ..."); ! 506: for (ix=0;ix<NPAT;ix++) { ! 507: dr->dr_data = tstpat[ix]; /* Write to Data out register */ ! 508: result = dr->dr_data & 0xFFFF; /* Read it back */ ! 509: if (result != tstpat[ix]) { ! 510: printf("Failed, expected : %lx --- actual : %lx", ! 511: tstpat[ix], result); ! 512: return; ! 513: } ! 514: } ! 515: printf("OK\n\t Functions & Status Bits ..."); ! 516: dr->dr_cstat = (FCN1 | FCN3); ! 517: result = dr->dr_cstat & 0xffff; /* Read them back */ ! 518: if ((result & (STTC | STTA)) != (STTC |STTA)) { ! 519: printf("Failed, expected : %lx --- actual : %lx, ISR:%lx", ! 520: (STTA|STTC), (result & (STTA|STTC)), result); ! 521: return; ! 522: } ! 523: dr->dr_cstat = FCN2; ! 524: result = dr->dr_cstat & 0xffff; /* Read them back */ ! 525: if ((result & STTB) != STTB) { ! 526: printf("Failed, expected : %lx --- actual : %lx, ISR:%lx", ! 527: STTB, (result & STTB), result); ! 528: return; ! 529: } ! 530: printf("OK\n\t DMA output ..."); ! 531: if (DMAin) ! 532: goto dmain; ! 533: /* Initialize DMA data buffer */ ! 534: for (ix=0; ix<DMATBL; ix++) ! 535: tstpat[ix] = 0xCCCC + ix; ! 536: tstpat[DMATBL-1] = 0xCCCC; /* Last word output */ ! 537: /* Setup normal DMA */ ! 538: addr = (long)vtoph((struct proc *)0, (unsigned)tstpat); ! 539: dr->dr_walo = (addr >> 1) & 0xffff; ! 540: dr->dr_wahi = (addr >> 17) & 0x7fff; ! 541: /* Set DMA range count: (number of words - 1) */ ! 542: dr->dr_range = DMATBL - 1; ! 543: /* Set address modifier code to be used for DMA access to memory */ ! 544: dr->dr_addmod = DRADDMOD; ! 545: ! 546: /* ! 547: * Clear dmaf and attf to assure a clean dma start, also disable ! 548: * attention interrupt ! 549: */ ! 550: dr->dr_pulse = RDMA|RATN|RMSK; /* Use pulse register */ ! 551: dr->dr_cstat = GO|CYCL; /* GO...... */ ! 552: ! 553: /* Wait for DMA complete; REDY and DMAF are true in ISR */ ! 554: wait = 0; ! 555: while ((result=(dr->dr_cstat & (REDY|DMAF))) != (REDY|DMAF)) { ! 556: printf("\n\tWait for DMA complete...ISR : %lx", result); ! 557: if (++wait > 5) { ! 558: printf("\n\t DMA output fails...timeout!!, ISR:%lx", ! 559: result); ! 560: return; ! 561: } ! 562: } ! 563: result = dr->dr_data & 0xffff; /* Read last word output */ ! 564: if (result != 0xCCCC) { ! 565: printf("\n\t Fails, expected : %lx --- actual : %lx", ! 566: 0xCCCC, result); ! 567: return; ! 568: } ! 569: printf("OK\n\t DMA input ..."); ! 570: dmain: ! 571: dr->dr_data = 0x1111; /* DMA input data */ ! 572: /* Setup normal DMA */ ! 573: addr = (long)vtoph((struct proc *)0, (unsigned)tstpat); ! 574: dr->dr_walo = (addr >> 1) & 0xffff; ! 575: dr->dr_wahi = (addr >> 17) & 0x7fff; ! 576: dr->dr_range = DMATBL - 1; ! 577: dr->dr_addmod = (char)DRADDMOD; ! 578: dr->dr_cstat = FCN1; /* Set FCN1 in ICR to DMA in*/ ! 579: if ((dra->dr_flags & DR_LOOPTST) == 0) { ! 580: /* Use pulse reg */ ! 581: dr->dr_pulse = RDMA|RATN|RMSK|CYCL|GO; ! 582: /* Wait for DMA complete; REDY and DMAF are true in ISR */ ! 583: wait = 0; ! 584: while ((result=(dr->dr_cstat & (REDY|DMAF))) != (REDY|DMAF)) { ! 585: printf("\n\tWait for DMA to complete...ISR:%lx",result); ! 586: if (++wait > 5) { ! 587: printf("\n\t DMA input timeout!!, ISR:%lx", ! 588: result); ! 589: return; ! 590: } ! 591: } ! 592: } else { ! 593: /* Enable DMA e-o-r interrupt */ ! 594: dr->dr_pulse = IENB|RDMA|RATN|CYCL|GO; ! 595: /* Wait for DMA complete; DR_LOOPTST is false in dra->dr_flags*/ ! 596: wait = 0; ! 597: while (dra->dr_flags & DR_LOOPTST) { ! 598: result = dr->dr_cstat & 0xffff; ! 599: printf("\n\tWait for DMA e-o-r intr...ISR:%lx", result); ! 600: if (++wait > 7) { ! 601: printf("\n\t DMA e-o-r timeout!!, ISR:%lx", ! 602: result); ! 603: dra->dr_flags &= ~DR_LOOPTST; ! 604: return; ! 605: } ! 606: } ! 607: dra->dr_flags |= DR_LOOPTST; ! 608: } ! 609: mtpr(P1DC, tstpat); /* Purge cache */ ! 610: mtpr(P1DC, 0x3ff+tstpat); ! 611: for (ix=0; ix<DMATBL; ix++) { ! 612: if (tstpat[ix] != 0x1111) { ! 613: printf("\n\t Fails, ix:%d, expected:%x --- actual:%x", ! 614: ix, 0x1111, tstpat[ix]); ! 615: return; ! 616: } ! 617: } ! 618: if ((dra->dr_flags & DR_LOOPTST) == 0) { ! 619: dra->dr_flags |= DR_LOOPTST; ! 620: printf(" OK..\n\tDMA end of range interrupt..."); ! 621: goto dmain; ! 622: } ! 623: printf(" OK..\n\tAttention interrupt...."); ! 624: dr->dr_pulse = IENB|RDMA; ! 625: dr->dr_pulse = FCN2; ! 626: /* Wait for ATTN interrupt; DR_LOOPTST is false in dra->dr_flags*/ ! 627: wait = 0; ! 628: while (dra->dr_flags & DR_LOOPTST) { ! 629: result = dr->dr_cstat & 0xffff; ! 630: printf("\n\tWait for Attention intr...ISR:%lx",result); ! 631: if (++wait > 7) { ! 632: printf("\n\t Attention interrupt timeout!!, ISR:%lx", ! 633: result); ! 634: dra->dr_flags &= ~DR_LOOPTST; ! 635: return; ! 636: } ! 637: } ! 638: dra->dr_flags &= ~DR_LOOPTST; ! 639: printf(" OK..\n\tDone..."); ! 640: } ! 641: ! 642: /* Reset state on Unibus reset */ ! 643: /*ARGSUSED*/ ! 644: drreset(uban) ! 645: int uban; ! 646: { ! 647: ! 648: } ! 649: ! 650: /* ! 651: * An interrupt is caused either by an error, ! 652: * base address overflow, or transfer complete ! 653: */ ! 654: drintr(dr11) ! 655: int dr11; ! 656: { ! 657: register struct dr_aux *dra = &dr_aux[dr11]; ! 658: register struct rsdevice *rsaddr = RSADDR(dr11); ! 659: register struct buf *bp; ! 660: register short status; ! 661: ! 662: status = rsaddr->dr_cstat & 0xffff; /* get board status register */ ! 663: dra->dr_istat = status; ! 664: #ifdef DR_DEBUG ! 665: if (DR11 & 2) ! 666: printf("\ndrintr: dr11 status : %lx",status & 0xffff); ! 667: #endif ! 668: if (dra->dr_flags & DR_LOOPTST) { /* doing loopback test */ ! 669: dra->dr_flags &= ~DR_LOOPTST; ! 670: return; ! 671: } ! 672: /* ! 673: * Make sure this is not a stray interrupt; at least one of dmaf or attf ! 674: * must be set. Note that if the dr11 interrupt enable latch is reset ! 675: * during a hardware interrupt ack sequence, and by the we get to this ! 676: * point in the interrupt code it will be 0. This is done to give the ! 677: * programmer some control over how the two more-or-less independent ! 678: * interrupt sources on the board are handled. ! 679: * If the attention flag is set when drstrategy() is called to start a ! 680: * dma read or write an interrupt will be generated as soon as the ! 681: * strategy routine enables interrupts for dma end-of-range. This will ! 682: * cause execution of the interrupt routine (not necessarily bad) and ! 683: * will cause the interrupt enable mask to be reset (very bad since the ! 684: * dma end-of-range condition will not be able to generate an interrupt ! 685: * when it occurs) causing the dma operation to time-out (even though ! 686: * the dma transfer will be done successfully) or hang the process if a ! 687: * software time-out capability is not implemented. One way to avoid ! 688: * this situation is to check for a pending attention interrupt (attf ! 689: * set) by calling drioctl() before doing a read or a write. For the ! 690: * time being this driver will solve the problem by clearing the attf ! 691: * flag in the status register before enabling interrupts in ! 692: * drstrategy(). ! 693: * ! 694: * **** The IKON 10084 for which this driver is written will set both ! 695: * attf and dmaf if dma is terminated by an attention pulse. This will ! 696: * cause a wakeup(&dr_aux), which will be ignored since it is not being ! 697: * waited on, and an iodone(bp) which is the desired action. Some other ! 698: * dr11 emulators, in particular the IKON 10077 for the Multibus, donot ! 699: * dmaf in this case. This may require some addtional code in the inter- ! 700: * rupt routine to ensure that en iodone(bp) is issued when dma is term- ! 701: * inated by attention. ! 702: */ ! 703: bp = dra->dr_actf; ! 704: if ((status & (ATTF | DMAF)) == 0) { ! 705: printf("dr%d: stray interrupt, status=%x", dr11, status); ! 706: return; ! 707: } ! 708: if (status & DMAF) { /* End-of-range interrupt */ ! 709: dra->dr_flags |= DR_DMAX; ! 710: ! 711: #ifdef DR_DEBUG ! 712: if (DR11 & 2) ! 713: printf("\ndrintr: e-o-r interrupt,cstat:%lx,dr_flags:%lx", ! 714: status&0xffff, dra->dr_flags & DR_ACTV); ! 715: #endif ! 716: if ((dra->dr_flags & DR_ACTV) == 0) { ! 717: /* We are not doing DMA !! */ ! 718: bp->b_flags |= B_ERROR; ! 719: } else { ! 720: if (dra->dr_op == DR_READ) ! 721: mtpr(P1DC, bp->b_un.b_addr); ! 722: dra->dr_bycnt -= bp->b_bcount; ! 723: if (dra->dr_bycnt >0) { ! 724: bp->b_un.b_addr += bp->b_bcount; ! 725: bp->b_bcount = (dra->dr_bycnt > NBPG) ? NBPG: ! 726: dra->dr_bycnt; ! 727: drstart(rsaddr, dra, bp); ! 728: return; ! 729: } ! 730: } ! 731: dra->dr_flags &= ~DR_ACTV; ! 732: wakeup((caddr_t)dra); /* Wakeup waiting in drwait() */ ! 733: rsaddr->dr_pulse = (RPER|RDMA|RATN); /* reset dma e-o-r flag */ ! 734: } ! 735: /* ! 736: * Now test for attention interrupt -- It may be set in addition to ! 737: * the dma e-o-r interrupt. If we get one we will issue a wakeup to ! 738: * the drioctl() routine which is presumable waiting for one. ! 739: * The program may have to monitor the attention interrupt received ! 740: * flag in addition to doing waits for the interrupt. Futhermore, ! 741: * interrupts are not enabled unless dma is in progress or drioctl() ! 742: * has been called to wait for attention -- this may produce some ! 743: * strange results if attf is set on the dr11 when a read or a write ! 744: * is initiated, since that will enables interrupts. ! 745: * **** The appropriate code for this interrupt routine will probably ! 746: * be rather application dependent. ! 747: */ ! 748: if (status & ATTF) { ! 749: dra->dr_flags |= DR_ATRX; ! 750: dra->dr_flags &= ~DR_ATWT; ! 751: rsaddr->dr_cstat = RATN; /* reset attention flag */ ! 752: /* ! 753: * Some applications which use attention to terminate ! 754: * dma may also want to issue an iodone() here to ! 755: * wakeup physio(). ! 756: */ ! 757: wakeup((caddr_t)&dra->dr_cmd); ! 758: } ! 759: } ! 760: ! 761: unsigned ! 762: drminphys(bp) ! 763: struct buf *bp; ! 764: { ! 765: ! 766: if (bp->b_bcount > 65536) ! 767: bp->b_bcount = 65536; ! 768: } ! 769: ! 770: /* ! 771: * This routine performs the device unique operations on the DR11W ! 772: * it is passed as an argument to and invoked by physio ! 773: */ ! 774: drstrategy (bp) ! 775: register struct buf *bp; ! 776: { ! 777: register int s; ! 778: int unit = RSUNIT(bp->b_dev); ! 779: register struct rsdevice *rsaddr = RSADDR(unit); ! 780: register struct dr_aux *dra = &dr_aux[unit]; ! 781: register int ok; ! 782: #ifdef DR_DEBUG ! 783: register char *caddr; ! 784: long drva(); ! 785: #endif ! 786: ! 787: if ((dra->dr_flags & DR_OPEN) == 0) { /* Device not open */ ! 788: bp->b_error = ENXIO; ! 789: bp->b_flags |= B_ERROR; ! 790: iodone (bp); ! 791: return; ! 792: } ! 793: while (dra->dr_flags & DR_ACTV) ! 794: /* Device is active; should never be in here... */ ! 795: (void) tsleep((caddr_t)&dra->dr_flags, DRPRI, devio, 0); ! 796: dra->dr_actf = bp; ! 797: #ifdef DR_DEBUG ! 798: drva(dra, bp->b_proc, bp->b_un.b_addr, bp->b_bcount); ! 799: #endif ! 800: dra->dr_oba = bp->b_un.b_addr; /* Save original addr, count */ ! 801: dra->dr_obc = bp->b_bcount; ! 802: dra->dr_bycnt = bp->b_bcount; /* Save xfer count used by drintr() */ ! 803: if ((((long)bp->b_un.b_addr & 0x3fffffff) >> PGSHIFT) != ! 804: ((((long)bp->b_un.b_addr & 0x3fffffff) + bp->b_bcount) >> PGSHIFT)) ! 805: bp->b_bcount = NBPG - (((long)bp->b_un.b_addr) & PGOFSET); ! 806: dra->dr_flags |= DR_ACTV; /* Mark active (use in intr handler) */ ! 807: s = SPL_UP(); ! 808: drstart(rsaddr,dra,bp); ! 809: splx(s); ! 810: ok = drwait(rsaddr,dra); ! 811: #ifdef DR_DEBUG ! 812: if (DR11 & 0x40) { ! 813: caddr = (char *)dra->dr_oba; ! 814: if (dra->dr_op == DR_READ) ! 815: printf("\nAfter read: (%lx)(%lx)", ! 816: caddr[0]&0xff, caddr[1]&0xff); ! 817: } ! 818: #endif ! 819: dra->dr_flags &= ~DR_ACTV; /* Clear active flag */ ! 820: bp->b_un.b_addr = dra->dr_oba; /* Restore original addr, count */ ! 821: bp->b_bcount = dra->dr_obc; ! 822: if (!ok) ! 823: bp->b_flags |= B_ERROR; ! 824: /* Mark buffer B_DONE,so physstrat() in ml/machdep.c won't sleep */ ! 825: iodone(bp); ! 826: wakeup((caddr_t)&dra->dr_flags); ! 827: /* ! 828: * Return to the calling program (physio()). Physio() will sleep ! 829: * until awaken by a call to iodone() in the interupt handler -- ! 830: * which will be called by the dispatcher when it receives dma ! 831: * end-of-range interrupt. ! 832: */ ! 833: } ! 834: ! 835: drwait(rs, dr) ! 836: register struct rsdevice *rs; ! 837: register struct dr_aux *dr; ! 838: { ! 839: int s; ! 840: ! 841: s = SPL_UP(); ! 842: while (dr->dr_flags & DR_ACTV) ! 843: (void) tsleep((caddr_t)dr, DRPRI, devio, 0); ! 844: splx(s); ! 845: if (dr->dr_flags & DR_TMDM) { /* DMA timed out */ ! 846: dr->dr_flags &= ~DR_TMDM; ! 847: return (0); ! 848: } ! 849: if (rs->dr_cstat & (PERR|BERR|TERR)) { ! 850: dr->dr_actf->b_flags |= B_ERROR; ! 851: return (0); ! 852: } ! 853: dr->dr_flags &= ~DR_DMAX; ! 854: return (1); ! 855: } ! 856: ! 857: /* ! 858: * ! 859: * The lower 8-bit of tinfo is the minor device number, the ! 860: * remaining higher 8-bit is the current timout number ! 861: */ ! 862: drrwtimo(tinfo) ! 863: register u_long tinfo; ! 864: { ! 865: register long unit = tinfo & 0xff; ! 866: register struct dr_aux *dr = &dr_aux[unit]; ! 867: register struct rsdevice *rs = dr->dr_addr; ! 868: ! 869: /* ! 870: * If this is not the timeout that drwrite/drread is waiting ! 871: * for then we should just go away ! 872: */ ! 873: if ((tinfo &~ 0xff) != (dr->currenttimo << 8)) ! 874: return; ! 875: /* Mark the device timed out */ ! 876: dr->dr_flags |= DR_TMDM; ! 877: dr->dr_flags &= ~DR_ACTV; ! 878: rs->dr_pulse = RMSK; /* Inihibit interrupt */ ! 879: rs->dr_pulse = (RPER|RDMA|RATN|IENB); /* Clear DMA logic */ ! 880: /* ! 881: * Some applications will not issue a master after dma timeout, ! 882: * since doing so sends an INIT H pulse to the external device, ! 883: * which may produce undesirable side-effects. ! 884: */ ! 885: /* Wake up process waiting in drwait() and flag the error */ ! 886: dr->dr_actf->b_flags |= B_ERROR; ! 887: wakeup((caddr_t)dr->dr_cmd); ! 888: } ! 889: ! 890: /* ! 891: * Kick the driver every second ! 892: */ ! 893: drtimo(dev) ! 894: dev_t dev; ! 895: { ! 896: register int unit = RSUNIT(dev); ! 897: register struct dr_aux *dr; ! 898: ! 899: dr = &dr_aux[unit]; ! 900: if (dr->dr_flags & DR_OPEN) ! 901: timeout(drtimo, (caddr_t)dev, hz); ! 902: wakeup((caddr_t)dr); /* Wakeup any process waiting for interrupt */ ! 903: } ! 904: ! 905: #ifdef DR_DEBUG ! 906: drva(dra, p, va, bcnt) ! 907: struct dr_aux *dra; ! 908: struct proc *p; ! 909: char *va; ! 910: long bcnt; ! 911: { ! 912: register long first, last , np; ! 913: ! 914: if (DR11 & 0x20) { ! 915: first = ((long)(vtoph(p, (unsigned)va))) >> 10; ! 916: last = ((long)(vtoph(p, (unsigned)va+bcnt))) >> 10; ! 917: np = bcnt / 0x3ff; ! 918: printf("\ndrva: (op:%ld)(first:%ld)(last:%ld)(np:%ld)(cnt:%ld)", ! 919: dra->dr_op,first,last,np,bcnt); ! 920: } ! 921: } ! 922: #endif ! 923: ! 924: drstart(rsaddr, dra, bp) ! 925: register struct rsdevice *rsaddr; ! 926: register struct dr_aux *dra; ! 927: register struct buf *bp; ! 928: { ! 929: register long addr; ! 930: u_short go; ! 931: ! 932: #ifdef DR_DEBUG ! 933: if (dra->dr_op == DR_READ && (DR11 & 8)) { ! 934: char *caddr = (char *)bp->b_un.b_addr; ! 935: printf("\ndrstart: READ, bcnt:%ld",bp->b_bcount); ! 936: printf(",(%lx)(%lx)",caddr[0]&0xff,caddr[1]&0xff); ! 937: } ! 938: #endif ! 939: /* we are doing raw IO, bp->b_un.b_addr is user's address */ ! 940: addr = (long)vtoph(bp->b_proc, (unsigned)bp->b_un.b_addr); ! 941: /* ! 942: * Set DMA address into DR11 interace registers: DR11 requires that ! 943: * the address be right shifted 1 bit position before it is written ! 944: * to the board (The board will left shift it one bit position before ! 945: * it places the address on the bus ! 946: */ ! 947: rsaddr->dr_walo = (addr >> 1) & 0xffff; ! 948: rsaddr->dr_wahi = (addr >> 17) & 0x7fff; ! 949: /* Set DMA range count: (number of words - 1) */ ! 950: rsaddr->dr_range = (bp->b_bcount >> 1) - 1; ! 951: /* Set address modifier code to be used for DMA access to memory */ ! 952: rsaddr->dr_addmod = DRADDMOD; ! 953: /* ! 954: * Now determine whether this is a read or a write. ***** This is ! 955: * probably only usefull for link mode operation, since dr11 doesnot ! 956: * controll the direction of data transfer. The C1 control input ! 957: * controls whether the hardware is doing a read or a write. In link ! 958: * mode this is controlled by function 1 latch (looped back by the ! 959: * cable) and could be set the program. In the general case, the dr11 ! 960: * doesnot know in advance what the direction of transfer is - although ! 961: * the program and protocol logic probably is ! 962: */ ! 963: #ifdef DR_DEBUG ! 964: if (DR11 & 1) ! 965: printf( ! 966: "\ndrstrat: about to GO..,dr_cmd:%lx,drstat:%lx,drcnt:%ld,cdata:%lx,OP:%ld", ! 967: dra->dr_cmd, rsaddr->dr_cstat, rsaddr->dr_range, ! 968: rsaddr->dr_data, dra->dr_op); ! 969: #endif ! 970: /* ! 971: * Update function latches may have been done already by drioctl() if ! 972: * request from drioctl() ! 973: */ ! 974: if (dra->dr_cmd & DR_DFCN) { /* deferred function write */ ! 975: dra->dr_cmd &= ~DR_DFCN; /* Clear request */ ! 976: go = dra->dr_cmd & DR_FMSK; /* mask out fcn bits */ ! 977: rsaddr->dr_cstat = go; /* Write it to the board */ ! 978: } ! 979: /* Clear dmaf and attf to assure a clean dma start */ ! 980: rsaddr->dr_pulse = RATN|RDMA|RPER; ! 981: rsaddr->dr_cstat = IENB|GO|CYCL|dra->dr_op; /* GO...... */ ! 982: /* ! 983: * Now check for software cycle request -- usually ! 984: * by transmitter in link mode. ! 985: */ ! 986: if (dra->dr_cmd & DR_PCYL) { ! 987: dra->dr_cmd &= ~DR_PCYL; /* Clear request */ ! 988: rsaddr->dr_pulse = CYCL; /* Use pulse register again */ ! 989: } ! 990: /* ! 991: * Now check for deferred ACLO FCNT2 pulse request -- usually to tell ! 992: * the transmitter (via its attention) that we have enabled dma. ! 993: */ ! 994: if (dra->dr_cmd & DR_DACL) { ! 995: dra->dr_cmd &= ~DR_DACL; /* Clear request */ ! 996: rsaddr->dr_pulse = FCN2; /* Use pulse register again */ ! 997: } ! 998: } ! 999: #endif NDR
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.