|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.