Annotation of Net2/arch/tahoe/vba/dr.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.