|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1982, 1990 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution is only permitted until one year after the first shipment ! 6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and ! 7: * binary forms are permitted provided that: (1) source distributions retain ! 8: * this entire copyright notice and comment, and (2) distributions including ! 9: * binaries display the following acknowledgement: This product includes ! 10: * software developed by the University of California, Berkeley and its ! 11: * contributors'' in the documentation or other materials provided with the ! 12: * distribution and in all advertising materials mentioning features or use ! 13: * of this software. Neither the name of the University nor the names of ! 14: * its contributors may be used to endorse or promote products derived from ! 15: * this software without specific prior written permission. ! 16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 19: * ! 20: * @(#)dma.c 7.1 (Berkeley) 5/8/90 ! 21: */ ! 22: ! 23: /* ! 24: * DMA driver ! 25: */ ! 26: ! 27: #include "param.h" ! 28: #include "systm.h" ! 29: #include "time.h" ! 30: #include "kernel.h" ! 31: #include "proc.h" ! 32: #include "dmareg.h" ! 33: #include "dmavar.h" ! 34: #include "device.h" ! 35: ! 36: #include "machine/cpu.h" ! 37: #include "machine/isr.h" ! 38: ! 39: extern void isrlink(); ! 40: extern void printf(); ! 41: extern void panic(); ! 42: extern void _insque(); ! 43: extern void _remque(); ! 44: extern void timeout(); ! 45: extern int splbio(); ! 46: extern void splx(); ! 47: extern u_int kvtop(); ! 48: extern void PCIA(); ! 49: ! 50: /* ! 51: * The largest single request will be MAXPHYS bytes which will require ! 52: * at most MAXPHYS/NBPG+1 chain elements to describe, i.e. if none of ! 53: * the buffer pages are physically contiguous (MAXPHYS/NBPG) and the ! 54: * buffer is not page aligned (+1). ! 55: */ ! 56: #define DMAMAXIO (MAXPHYS/NBPG+1) ! 57: ! 58: #define DMATIMO 15 ! 59: ! 60: struct dma_softc { ! 61: struct dmadevice *sc_hwaddr; ! 62: struct dmaBdevice *sc_Bhwaddr; ! 63: int sc_type; ! 64: int sc_cur; ! 65: int sc_cmd; ! 66: int sc_timo; ! 67: int sc_count[DMAMAXIO+1]; ! 68: char *sc_addr[DMAMAXIO+1]; ! 69: } dma_softc[NDMA]; ! 70: ! 71: /* types */ ! 72: #define DMA_B 0 ! 73: #define DMA_C 1 ! 74: ! 75: struct devqueue dmachan[NDMA + 1]; ! 76: int dmaintr(); ! 77: void dmatimo(); ! 78: ! 79: #ifdef DEBUG ! 80: int dmadebug = 0; ! 81: #define DDB_WORD 0x01 /* same as DMAGO_WORD */ ! 82: #define DDB_LWORD 0x02 /* same as DMAGO_LWORD */ ! 83: #define DDB_FOLLOW 0x04 ! 84: #define DDB_IO 0x08 ! 85: ! 86: long dmahits[NDMA]; ! 87: long dmamisses[NDMA]; ! 88: long dmabyte[NDMA]; ! 89: long dmaword[NDMA]; ! 90: long dmalword[NDMA]; ! 91: #endif ! 92: ! 93: void ! 94: dmainit() ! 95: { ! 96: register struct dmareg *dma = (struct dmareg *)DMA_BASE; ! 97: register struct dma_softc *dc; ! 98: register int i; ! 99: char rev; ! 100: ! 101: /* ! 102: * Determine the DMA type. ! 103: * Don't know how to easily differentiate the A and B cards, ! 104: * so we just hope nobody has an A card (A cards will work if ! 105: * DMAINTLVL is set to 3). ! 106: */ ! 107: if (!badbaddr((char *)&dma->dma_id[2])) ! 108: rev = dma->dma_id[2]; ! 109: else { ! 110: rev = 'B'; ! 111: #if !defined(HP320) ! 112: panic("dmainit: DMA card requires hp320 support"); ! 113: #endif ! 114: } ! 115: ! 116: dc = &dma_softc[0]; ! 117: for (i = 0; i < NDMA; i++) { ! 118: dc->sc_hwaddr = (i & 1) ? &dma->dma_chan1 : &dma->dma_chan0; ! 119: dc->sc_Bhwaddr = (i & 1) ? &dma->dma_Bchan1 : &dma->dma_Bchan0; ! 120: dc->sc_type = rev == 'B' ? DMA_B : DMA_C; ! 121: dc++; ! 122: dmachan[i].dq_forw = dmachan[i].dq_back = &dmachan[i]; ! 123: } ! 124: dmachan[i].dq_forw = dmachan[i].dq_back = &dmachan[i]; ! 125: timeout(dmatimo, (caddr_t)0, DMATIMO * hz); ! 126: ! 127: printf("dma: 98620%c with 2 channels, %d bit DMA\n", ! 128: rev, rev == 'B' ? 16 : 32); ! 129: } ! 130: ! 131: int ! 132: dmareq(dq) ! 133: register struct devqueue *dq; ! 134: { ! 135: register int i; ! 136: register int chan; ! 137: register int s = splbio(); ! 138: ! 139: chan = dq->dq_ctlr; ! 140: i = NDMA; ! 141: while (--i >= 0) { ! 142: if ((chan & (1 << i)) == 0) ! 143: continue; ! 144: if (dmachan[i].dq_forw != &dmachan[i]) ! 145: continue; ! 146: insque(dq, &dmachan[i]); ! 147: dq->dq_ctlr = i; ! 148: splx(s); ! 149: return(1); ! 150: } ! 151: insque(dq, dmachan[NDMA].dq_back); ! 152: splx(s); ! 153: return(0); ! 154: } ! 155: ! 156: void ! 157: dmafree(dq) ! 158: register struct devqueue *dq; ! 159: { ! 160: int unit = dq->dq_ctlr; ! 161: register struct dma_softc *dc = &dma_softc[unit]; ! 162: register struct devqueue *dn; ! 163: register int chan, s; ! 164: ! 165: s = splbio(); ! 166: dc->sc_timo = 0; ! 167: DMA_CLEAR(dc); ! 168: remque(dq); ! 169: chan = 1 << unit; ! 170: for (dn = dmachan[NDMA].dq_forw; ! 171: dn != &dmachan[NDMA]; dn = dn->dq_forw) { ! 172: if (dn->dq_ctlr & chan) { ! 173: remque((caddr_t)dn); ! 174: insque((caddr_t)dn, (caddr_t)dq->dq_back); ! 175: splx(s); ! 176: dn->dq_ctlr = dq->dq_ctlr; ! 177: (dn->dq_driver->d_start)(dn->dq_unit); ! 178: return; ! 179: } ! 180: } ! 181: splx(s); ! 182: } ! 183: ! 184: void ! 185: dmago(unit, addr, count, flags) ! 186: int unit; ! 187: register char *addr; ! 188: register int count; ! 189: register int flags; ! 190: { ! 191: register struct dma_softc *dc = &dma_softc[unit]; ! 192: register char *dmaend = NULL; ! 193: register int tcount, i; ! 194: ! 195: #ifdef DEBUG ! 196: if (dmadebug & DDB_FOLLOW) ! 197: printf("dmago(%d, %x, %x, %x)\n", ! 198: unit, addr, count, flags); ! 199: if (flags & DMAGO_LWORD) ! 200: dmalword[unit]++; ! 201: else if (flags & DMAGO_WORD) ! 202: dmaword[unit]++; ! 203: else ! 204: dmabyte[unit]++; ! 205: #endif ! 206: #if defined(HP320) ! 207: if (dc->sc_type == DMA_B && (flags & DMAGO_LWORD)) ! 208: panic("dmago: no can do 32-bit DMA"); ! 209: #endif ! 210: /* ! 211: * Build the DMA chain ! 212: */ ! 213: for (i = 0; i < DMAMAXIO && count; i++) { ! 214: dc->sc_addr[i] = (char *)kvtop(addr); ! 215: tcount = dc->sc_count[i] = ! 216: MIN(count, NBPG - ((int)addr & PGOFSET)); ! 217: addr += dc->sc_count[i]; ! 218: count -= tcount; ! 219: if (flags & (DMAGO_WORD|DMAGO_LWORD)) ! 220: tcount >>= (flags & DMAGO_WORD) ? 1 : 2; ! 221: if (dc->sc_addr[i] == dmaend ! 222: #if defined(HP320) ! 223: /* only 16-bit count on 98620B */ ! 224: && (dc->sc_type != DMA_B || ! 225: dc->sc_count[i-1] + tcount <= 65536) ! 226: #endif ! 227: ) { ! 228: #ifdef DEBUG ! 229: dmahits[unit]++; ! 230: #endif ! 231: dmaend += dc->sc_count[i]; ! 232: dc->sc_count[i-1] += tcount; ! 233: i--; ! 234: } else { ! 235: #ifdef DEBUG ! 236: dmamisses[unit]++; ! 237: #endif ! 238: dmaend = dc->sc_addr[i] + dc->sc_count[i]; ! 239: dc->sc_count[i] = tcount; ! 240: } ! 241: } ! 242: if (count) ! 243: panic("dmago maxphys"); ! 244: dc->sc_count[i] = 0; ! 245: dc->sc_cur = 0; ! 246: /* ! 247: * Set up the command word based on flags ! 248: */ ! 249: dc->sc_cmd = DMA_ENAB | DMA_IPL(DMAINTLVL) | DMA_START; ! 250: if ((flags & DMAGO_READ) == 0) ! 251: dc->sc_cmd |= DMA_WRT; ! 252: if (flags & DMAGO_LWORD) ! 253: dc->sc_cmd |= DMA_LWORD; ! 254: else if (flags & DMAGO_WORD) ! 255: dc->sc_cmd |= DMA_WORD; ! 256: if (flags & DMAGO_PRI) ! 257: dc->sc_cmd |= DMA_PRI; ! 258: ! 259: /* ! 260: * We should be able to skip the dma completion interrupt ! 261: * if we only have one segment in the chain since many ! 262: * devices generate their own completion interrupt. ! 263: * However, on a 370 we have to take the interrupt on ! 264: * read transfers to invalidate the external cache. ! 265: */ ! 266: if ((flags & DMAGO_NOINT) && i == 1 ! 267: #if defined(HP370) ! 268: && ((flags & DMAGO_READ) == 0 || ectype != EC_PHYS) ! 269: #endif ! 270: ) ! 271: dc->sc_cmd &= ~DMA_ENAB; ! 272: #ifdef DEBUG ! 273: #if defined(HP320) ! 274: /* would this hurt? */ ! 275: if (dc->sc_type == DMA_B) ! 276: dc->sc_cmd &= ~DMA_START; ! 277: #endif ! 278: if (dmadebug & DDB_IO) ! 279: if ((dmadebug&DDB_WORD) && (dc->sc_cmd&DMA_WORD) || ! 280: (dmadebug&DDB_LWORD) && (dc->sc_cmd&DMA_LWORD)) { ! 281: printf("dmago: cmd %x\n", dc->sc_cmd); ! 282: for (i = 0; dc->sc_count[i]; i++) ! 283: printf(" %d: %d@%x\n", ! 284: i, dc->sc_count[i], dc->sc_addr[i]); ! 285: } ! 286: #endif ! 287: ! 288: /* ! 289: * Load and arm the channel ! 290: */ ! 291: dc->sc_timo = 1; ! 292: DMA_ARM(dc, 0); ! 293: } ! 294: ! 295: void ! 296: dmastop(unit) ! 297: register int unit; ! 298: { ! 299: register struct dma_softc *dc = &dma_softc[unit]; ! 300: register struct devqueue *dq; ! 301: ! 302: #ifdef DEBUG ! 303: if (dmadebug & DDB_FOLLOW) ! 304: printf("dmastop(%d)\n", unit); ! 305: #endif ! 306: dc->sc_timo = 0; ! 307: DMA_CLEAR(dc); ! 308: ! 309: /* ! 310: * We may get this interrupt after a device service routine ! 311: * has freed the dma channel. So, ignore the intr if there's ! 312: * nothing on the queue. ! 313: */ ! 314: dq = dmachan[unit].dq_forw; ! 315: if (dq != &dmachan[unit]) { ! 316: #if defined(HP370) ! 317: /* ! 318: * The 370 has an 64k external physical address cache. ! 319: * In theory, we should only need to flush it when ! 320: * DMAing to memory. ! 321: */ ! 322: if (ectype == EC_PHYS && (dc->sc_cmd & DMA_WRT) == 0) ! 323: PCIA(); ! 324: #endif ! 325: (dq->dq_driver->d_done)(dq->dq_unit); ! 326: } ! 327: } ! 328: ! 329: int ! 330: dmaintr() ! 331: { ! 332: register struct dma_softc *dc; ! 333: register int i, j, stat; ! 334: int found = 0; ! 335: ! 336: #ifdef DEBUG ! 337: if (dmadebug & DDB_FOLLOW) ! 338: printf("dmaintr\n"); ! 339: #endif ! 340: for (i = 0, dc = dma_softc; i < NDMA; i++, dc++) { ! 341: stat = DMA_STAT(dc); ! 342: if ((stat & DMA_INTR) == 0) ! 343: continue; ! 344: found++; ! 345: #ifdef DEBUG ! 346: if (dmadebug & DDB_IO) { ! 347: if ((dmadebug&DDB_WORD) && (dc->sc_cmd&DMA_WORD) || ! 348: (dmadebug&DDB_LWORD) && (dc->sc_cmd&DMA_LWORD)) ! 349: printf("dmaintr: unit %d stat %x next %d\n", ! 350: i, stat, dc->sc_cur+1); ! 351: } ! 352: if (stat & DMA_ARMED) ! 353: printf("dma%d: intr when armed\n", i); ! 354: #endif ! 355: j = ++dc->sc_cur; ! 356: if (j < DMAMAXIO && dc->sc_count[j]) { ! 357: dc->sc_timo = 1; ! 358: DMA_CLEAR(dc); ! 359: DMA_ARM(dc, j); ! 360: } else ! 361: dmastop(i); ! 362: } ! 363: return(found); ! 364: } ! 365: ! 366: void ! 367: dmatimo() ! 368: { ! 369: register int i, s; ! 370: register struct dma_softc *dc = &dma_softc[0]; ! 371: ! 372: for (i = 0; i < NDMA; i++, dc++) { ! 373: s = splbio(); ! 374: if (dc->sc_timo) { ! 375: if (dc->sc_timo == 1) ! 376: dc->sc_timo++; ! 377: else ! 378: dmastop(i); ! 379: } ! 380: splx(s); ! 381: } ! 382: timeout(dmatimo, (caddr_t)0, DMATIMO * hz); ! 383: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.