Annotation of Net2/arch/amiga/dev/dma.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1982, 1990 The Regents of the University of California.
                      3:  * All rights reserved.
                      4:  *
                      5:  * Redistribution and use in source and binary forms, with or without
                      6:  * modification, are permitted provided that the following conditions
                      7:  * are met:
                      8:  * 1. Redistributions of source code must retain the above copyright
                      9:  *    notice, this list of conditions and the following disclaimer.
                     10:  * 2. Redistributions in binary form must reproduce the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer in the
                     12:  *    documentation and/or other materials provided with the distribution.
                     13:  * 3. All advertising materials mentioning features or use of this software
                     14:  *    must display the following acknowledgement:
                     15:  *     This product includes software developed by the University of
                     16:  *     California, Berkeley and its contributors.
                     17:  * 4. Neither the name of the University nor the names of its contributors
                     18:  *    may be used to endorse or promote products derived from this software
                     19:  *    without specific prior written permission.
                     20:  *
                     21:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     22:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     23:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     24:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     25:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     26:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     27:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     28:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     29:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     30:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     31:  * SUCH DAMAGE.
                     32:  *
                     33:  *     @(#)dma.c
                     34:  */
                     35: 
                     36: /*
                     37:  * DMA driver
                     38:  */
                     39: 
                     40: #include "param.h"
                     41: #include "systm.h"
                     42: #include "time.h"
                     43: #include "kernel.h"
                     44: #include "proc.h"
                     45: 
                     46: #include "vm/vm.h"
                     47: #include "vm/vm_kern.h"
                     48: #include "vm/vm_page.h"
                     49: #include "vm/vm_statistics.h"
                     50: #include "machine/pmap.h"
                     51: 
                     52: #include "device.h"
                     53: #include "dmareg.h"
                     54: #include "dmavar.h"
                     55: 
                     56: #include "../include/cpu.h"
                     57: 
                     58: extern void isrlink();
                     59: extern void _insque();
                     60: extern void _remque();
                     61: extern void timeout();
                     62: extern u_int kvtop();
                     63: 
                     64: /*
                     65:  * The largest single request will be MAXPHYS bytes which will require
                     66:  * at most MAXPHYS/NBPG+1 chain elements to describe, i.e. if none of
                     67:  * the buffer pages are physically contiguous (MAXPHYS/NBPG) and the
                     68:  * buffer is not page aligned (+1).
                     69:  */
                     70: #define        DMAMAXIO        (MAXPHYS/NBPG+1)
                     71: 
                     72: struct dma_chain {
                     73:        int     dc_count;
                     74:        char    *dc_addr;
                     75: };
                     76: 
                     77: struct dma_softc {
                     78:        struct  sdmac *sc_hwaddr;
                     79:        char    sc_dmaflags;
                     80:        u_short sc_cmd;
                     81:        struct  dma_chain *sc_cur;
                     82:        struct  dma_chain *sc_last;
                     83:        struct  dma_chain sc_chain[DMAMAXIO];
                     84: } dma_softc;
                     85: 
                     86: #define DMAF_NOINTR    0x01
                     87: 
                     88: struct devqueue dmachan[NDMA + 1];
                     89: int    dmaintr();
                     90: 
                     91: /* because keybord and dma share same interrupt priority... */
                     92: int dma_initialized = 0;
                     93: /* if not in int-mode, don't pay attention for possible scsi interrupts */
                     94: int scsi_int_mode = 0;
                     95: 
                     96: #ifdef DEBUG
                     97: #define        DDB_FOLLOW      0x04
                     98: #define DDB_IO         0x08
                     99: int    dmadebug = 0;
                    100: 
                    101: void   dmatimeout();
                    102: int    dmatimo;
                    103: 
                    104: long   dmahits;
                    105: long   dmamisses;
                    106: long   dmabyte;
                    107: long   dmaword;
                    108: long   dmalword;
                    109: #endif
                    110: 
                    111: /* This setup function is also used by the SCSI driver, as it shares
                    112:    the same chip */
                    113: 
                    114: struct sdmac *SDMAC_address = 0;
                    115: volatile void *SCSI_address = 0;
                    116: 
                    117: void 
                    118: SDMAC_setup ()
                    119: {
                    120:   if (! SDMAC_address)
                    121:     {
                    122:       extern u_int SCSIADDR;   /* setup in amiga_init.c. Should really be mapped here... */
                    123:       SDMAC_address = (struct sdmac *) SCSIADDR;
                    124:       SCSI_address = &SDMAC_address->SASR;
                    125:     }
                    126: }
                    127: 
                    128: 
                    129: void
                    130: dmainit()
                    131: {
                    132:   register struct sdmac *dma;
                    133:   register int i;
                    134:   char rev;
                    135: 
                    136:   SDMAC_setup ();
                    137:   dma = SDMAC_address;
                    138: 
                    139:   /* make sure interrupts are disabled while we later on reset the scsi-chip */
                    140:   dma->CNTR = CNTR_PDMD;
                    141:   dma->DAWR = DAWR_A3000;
                    142:   dma_softc.sc_dmaflags = 0;
                    143:   dma_softc.sc_cmd = 0;
                    144:   dma_softc.sc_hwaddr = dma;
                    145:   dmachan[0].dq_forw = dmachan[0].dq_back = &dmachan[0];
                    146:   dmachan[1].dq_forw = dmachan[1].dq_back = &dmachan[1];
                    147: #ifdef DEBUG
                    148:   /* make sure timeout is really not needed */
                    149:   timeout(dmatimeout, 0, 30 * hz);
                    150: #endif
                    151: 
                    152:   printf("dma: A3000 %d bit DMA\n", 32);       /* XXX */
                    153:   dma_initialized = 1;
                    154: }
                    155: 
                    156: int
                    157: dmareq(dq)
                    158:        register struct devqueue *dq;
                    159: {
                    160:   register int s = splbio();
                    161: 
                    162:   if (dmachan[0].dq_forw == &dmachan[0])
                    163:     {
                    164:       insque(dq, &dmachan[0]);
                    165:       dq->dq_ctlr = 0;
                    166:       splx(s);
                    167:       return 1;
                    168:     }
                    169: 
                    170:   insque (dq, dmachan[1].dq_back);
                    171:   splx(s);
                    172:   return(0);
                    173: }
                    174: 
                    175: void
                    176: dmafree(dq)
                    177:        register struct devqueue *dq;
                    178: {
                    179:   register struct dma_softc *dc = &dma_softc;
                    180:   register struct devqueue *dn;
                    181:   register int s;
                    182: 
                    183:   s = splbio();
                    184: #ifdef DEBUG
                    185:   dmatimo = 0;
                    186: #endif
                    187:   if (dc->sc_cmd)
                    188:     {
                    189:       if ((dc->sc_cmd & (CNTR_TCEN | CNTR_DDIR)) == 0)
                    190:         {
                    191:           /* only FLUSH if terminal count not enabled, and reading from peripheral */
                    192:           dc->sc_hwaddr->FLUSH = 1;
                    193:           while (! (dc->sc_hwaddr->ISTR & ISTR_FE_FLG)) ;
                    194:         }
                    195:       dc->sc_hwaddr->CINT = 1;         /* clear possible interrupt */
                    196:       dc->sc_hwaddr->SP_DMA = 1;       /* stop dma */
                    197:       dc->sc_cmd = 0;
                    198:     }
                    199:   dc->sc_hwaddr->CNTR = CNTR_PDMD;     /* disable interrupts from dma/scsi */
                    200:   scsi_int_mode = 0;
                    201: 
                    202:   remque(dq);
                    203:   for (dn = dmachan[1].dq_forw;
                    204:        dn != &dmachan[1]; 
                    205:        dn = dn->dq_forw) 
                    206:     {
                    207:       remque ((caddr_t) dn);
                    208:       insque ((caddr_t) dn, (caddr_t) dq->dq_back);
                    209:       splx(s);
                    210:       dn->dq_ctlr = dq->dq_ctlr;
                    211:       (dn->dq_driver->d_start)(0);
                    212:       return;
                    213:     }
                    214: 
                    215:   splx(s);
                    216: }
                    217: 
                    218: int
                    219: dmago(addr, count, flags)
                    220:        register char *addr;
                    221:        register int count;
                    222:        register int flags;
                    223: {
                    224:   register struct dma_softc *dc = &dma_softc;
                    225:   register struct dma_chain *dcp;
                    226:   register char *dmaend = NULL;
                    227:   register int tcount;
                    228: 
                    229:   if (count > MAXPHYS)
                    230:      panic("dmago: count > MAXPHYS");
                    231: #ifdef DEBUG
                    232:   if (dmadebug & DDB_FOLLOW)
                    233:      printf("dmago(%x, %x, %x)\n", addr, count, flags);
                    234: #endif
                    235:   /*
                    236:    * Build the DMA chain
                    237:    */
                    238:   for (dcp = dc->sc_chain; count > 0; dcp++) 
                    239:     {
                    240: #ifdef DEBUG
                    241:       if (! pmap_extract(pmap_kernel(), (vm_offset_t)addr))
                    242:         panic ("dmago: no physical page for address!");
                    243: #endif
                    244: 
                    245:       dcp->dc_addr = (char *) kvtop(addr);
                    246:       if (count < (tcount = NBPG - ((int)addr & PGOFSET)))
                    247:        tcount = count;
                    248:       dcp->dc_count = tcount;
                    249:       addr += tcount;
                    250:       count -= tcount;
                    251:       tcount >>= 1;    /* number of words (the sdmac wants 16bit values here) */
                    252:       if (dcp->dc_addr == dmaend) 
                    253:        {
                    254: #ifdef DEBUG
                    255:          dmahits++;
                    256: #endif
                    257:          dmaend += dcp->dc_count;
                    258:          (--dcp)->dc_count += tcount;
                    259:        } 
                    260:       else 
                    261:         {
                    262: #ifdef DEBUG
                    263:          dmamisses++;
                    264: #endif
                    265:          dmaend = dcp->dc_addr + dcp->dc_count;
                    266:          dcp->dc_count = tcount;
                    267:        }
                    268:     }
                    269: 
                    270:   dc->sc_cur = dc->sc_chain;
                    271:   dc->sc_last = --dcp;
                    272:   dc->sc_dmaflags = 0;
                    273:   /*
                    274:    * Set up the command word based on flags
                    275:    */
                    276:   dc->sc_cmd = CNTR_PDMD | CNTR_INTEN;
                    277:   if ((flags & DMAGO_READ) == 0)
                    278:     dc->sc_cmd |= CNTR_DDIR;
                    279: #ifdef DEBUG
                    280:   if (dmadebug & DDB_IO)
                    281:     {
                    282:       printf("dmago: cmd %x, flags %x\n",
                    283:             dc->sc_cmd, dc->sc_dmaflags);
                    284:       for (dcp = dc->sc_chain; dcp <= dc->sc_last; dcp++)
                    285:        printf("  %d: %d@%x\n", dcp-dc->sc_chain,
                    286:               dcp->dc_count, dcp->dc_addr);
                    287:     }
                    288:   dmatimo = 1;
                    289: #endif
                    290: 
                    291:   dc->sc_hwaddr->CNTR = dc->sc_cmd;
                    292:   scsi_int_mode = 1;
                    293:   dc->sc_hwaddr->ACR = (u_int) dc->sc_cur->dc_addr;
                    294:   dc->sc_hwaddr->ST_DMA = 1;
                    295:   
                    296:   return dc->sc_cur->dc_count << 1;
                    297: }
                    298: 
                    299: void
                    300: dmastop()
                    301: {
                    302:   register struct dma_softc *dc = &dma_softc;
                    303:   register struct devqueue *dq;
                    304:   int s;
                    305: 
                    306: #ifdef DEBUG
                    307:   if (dmadebug & DDB_FOLLOW)
                    308:     printf("dmastop()\n");
                    309:   dmatimo = 0;
                    310: #endif
                    311:   if (dc->sc_cmd)
                    312:     {
                    313:       s = splbio ();
                    314:       if ((dc->sc_cmd & (CNTR_TCEN | CNTR_DDIR)) == 0)
                    315:         {
                    316:           /* only FLUSH if terminal count not enabled, and reading from peripheral */
                    317:          dc->sc_hwaddr->FLUSH = 1;
                    318:           while (! (dc->sc_hwaddr->ISTR & ISTR_FE_FLG)) ;
                    319:         }
                    320:       dc->sc_hwaddr->CINT = 1;         /* clear possible interrupt */
                    321:       dc->sc_hwaddr->SP_DMA = 1;       /* stop dma */
                    322:       dc->sc_cmd = 0;
                    323:       splx (s);
                    324:     }
                    325: 
                    326:   /*
                    327:    * We may get this interrupt after a device service routine
                    328:    * has freed the dma channel.  So, ignore the intr if there's
                    329:    * nothing on the queue.
                    330:    */
                    331:   dq = dmachan[0].dq_forw;
                    332:   if (dq != &dmachan[0])
                    333:     (dq->dq_driver->d_done)(0);
                    334: }
                    335: 
                    336: int
                    337: dmaintr()
                    338: {
                    339:   register struct dma_softc *dc;
                    340:   register int i, stat;
                    341:   int found = 0;
                    342: 
                    343:   if (! dma_initialized)
                    344:     return 0;
                    345: 
                    346:   dc = &dma_softc;
                    347:   stat = dc->sc_hwaddr->ISTR;
                    348: 
                    349:   /* if no interrupt from this device, return quickly */
                    350:   if (! (stat & (ISTR_INT_F|ISTR_INT_P)))
                    351:     return 0;
                    352:   
                    353: #ifdef DEBUG
                    354:   if (dmadebug & DDB_FOLLOW)
                    355:      printf("dmaintr (0x%x)\n", stat);
                    356: #endif
                    357: 
                    358:   /* both, SCSI and DMA interrupts arrive here. I chose arbitrarily that
                    359:      DMA interrupts should have higher precedence than SCSI interrupts. */
                    360: 
                    361:   if (stat & ISTR_E_INT)
                    362:     {
                    363:       found++;
                    364: 
                    365: printf ("DMAINTR should no longer be entered!!\n");
                    366: 
                    367: 
                    368:       /* End-of-process interrupt, means the DMA Terminal Counter reached
                    369:          0, and we have to reload it. SCSI transfer should not be interrupted
                    370:          by this event (we'll see..) */
                    371: 
                    372: #ifdef DEBUG
                    373:       if (dmadebug & DDB_IO) 
                    374:        {
                    375:          printf("dmaintr: stat %x next %d\n",
                    376:                 stat, (dc->sc_cur-dc->sc_chain)+1);
                    377:        }
                    378: #endif
                    379:       if (++dc->sc_cur <= dc->sc_last) 
                    380:        {
                    381: #ifdef DEBUG
                    382:          dmatimo = 1;
                    383: #endif
                    384:          /*
                    385:           * Last chain segment, disable DMA interrupt.
                    386:           */
                    387:          if (dc->sc_cur == dc->sc_last && (dc->sc_dmaflags & DMAF_NOINTR))
                    388:            dc->sc_cmd &= ~CNTR_TCEN;
                    389: 
                    390:          dc->sc_hwaddr->CINT = 1;              /* clear possible interrupt */
                    391:          dc->sc_hwaddr->CNTR = dc->sc_cmd;
                    392:          dc->sc_hwaddr->ACR = (u_int) dc->sc_cur->dc_addr;
                    393: #ifndef DONT_WTC
                    394:          if (dc->sc_cmd & CNTR_TCEN)
                    395:            dc->sc_hwaddr->WTC = dc->sc_cur->dc_count;
                    396: #endif
                    397:          dc->sc_hwaddr->ST_DMA = 1;
                    398:        } 
                    399:       else
                    400:        dmastop ();
                    401:        
                    402:       /* check for SCSI ints in the same go and eventually save an interrupt */
                    403:     }
                    404: 
                    405:   if (scsi_int_mode && (stat & ISTR_INTS))
                    406:     return found + scsiintr (0);
                    407: 
                    408:   return found;
                    409: }
                    410: 
                    411: 
                    412: int
                    413: dmanext ()
                    414: {
                    415:   register struct dma_softc *dc;
                    416:   register int i, stat;
                    417:   int found = 0;
                    418: 
                    419:   dc = &dma_softc;
                    420: 
                    421: #ifdef DEBUG
                    422:   if (dmadebug & DDB_IO) 
                    423:     {
                    424:       printf("dmanext: next %d\n", (dc->sc_cur-dc->sc_chain)+1);
                    425:     }
                    426: #endif
                    427:   if (++dc->sc_cur <= dc->sc_last) 
                    428:     {
                    429: #ifdef DEBUG
                    430:       dmatimo = 1;
                    431: #endif
                    432:       if ((dc->sc_cmd & (CNTR_TCEN | CNTR_DDIR)) == 0)
                    433:         {
                    434:           /* only FLUSH if terminal count not enabled, and reading from peripheral */
                    435:           dc->sc_hwaddr->FLUSH = 1;
                    436:           while (! (dc->sc_hwaddr->ISTR & ISTR_FE_FLG)) ;
                    437:         }
                    438:       dc->sc_hwaddr->CINT = 1;         /* clear possible interrupt */
                    439:       dc->sc_hwaddr->SP_DMA = 1;       /* stop dma */
                    440:       dc->sc_hwaddr->CNTR = dc->sc_cmd;
                    441:       dc->sc_hwaddr->ACR = (u_int) dc->sc_cur->dc_addr;
                    442:       dc->sc_hwaddr->ST_DMA = 1;
                    443:       
                    444:       return dc->sc_cur->dc_count << 1;
                    445:     } 
                    446:   else
                    447:     {
                    448:       /* shouldn't happen !! */
                    449:       printf ("dmanext at end !!!\n");
                    450:       dmastop ();
                    451:       return 0;
                    452:     }
                    453: }
                    454: 
                    455: 
                    456: 
                    457: 
                    458: #ifdef DEBUG
                    459: void
                    460: dmatimeout()
                    461: {
                    462:   register int s;
                    463: 
                    464:   s = splbio();
                    465:   if (dmatimo) 
                    466:     {
                    467:       if (dmatimo > 1)
                    468:        printf("dma: timeout #%d\n", dmatimo-1);
                    469:       dmatimo++;
                    470:     }
                    471:   splx(s);
                    472:   timeout (dmatimeout, (caddr_t)0, 30 * hz);
                    473: }
                    474: #endif

unix.superglobalmegacorp.com

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