Annotation of sys/arch/hp300/dev/dma.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: dma.c,v 1.17 2005/11/17 23:56:02 miod Exp $ */
! 2: /* $NetBSD: dma.c,v 1.19 1997/05/05 21:02:39 thorpej Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 1995, 1996, 1997
! 6: * Jason R. Thorpe. All rights reserved.
! 7: * Copyright (c) 1982, 1990, 1993
! 8: * The Regents of the University of California. All rights reserved.
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: * 3. Neither the name of the University nor the names of its contributors
! 19: * may be used to endorse or promote products derived from this software
! 20: * without specific prior written permission.
! 21: *
! 22: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 23: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 24: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 25: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 26: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 27: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 28: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 29: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 30: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 31: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 32: * SUCH DAMAGE.
! 33: *
! 34: * @(#)dma.c 8.1 (Berkeley) 6/10/93
! 35: */
! 36:
! 37: /*
! 38: * DMA driver
! 39: */
! 40:
! 41: #include <sys/param.h>
! 42: #include <sys/systm.h>
! 43: #include <sys/time.h>
! 44: #include <sys/kernel.h>
! 45: #include <sys/proc.h>
! 46: #include <sys/device.h>
! 47: #include <sys/timeout.h>
! 48:
! 49: #include <machine/frame.h>
! 50: #include <machine/cpu.h>
! 51: #include <machine/intr.h>
! 52:
! 53: #include <hp300/dev/dmareg.h>
! 54: #include <hp300/dev/dmavar.h>
! 55:
! 56: #include <uvm/uvm_extern.h>
! 57:
! 58: /*
! 59: * The largest single request will be MAXPHYS bytes which will require
! 60: * at most MAXPHYS/NBPG+1 chain elements to describe, i.e. if none of
! 61: * the buffer pages are physically contiguous (MAXPHYS/NBPG) and the
! 62: * buffer is not page aligned (+1).
! 63: */
! 64: #define DMAMAXIO (MAXPHYS/NBPG+1)
! 65:
! 66: struct dma_chain {
! 67: u_int dc_count;
! 68: paddr_t dc_addr;
! 69: };
! 70:
! 71: struct dma_channel {
! 72: struct dmaqueue *dm_job; /* current job */
! 73: struct dmadevice *dm_hwaddr; /* registers if DMA_C */
! 74: struct dmaBdevice *dm_Bhwaddr; /* registers if not DMA_C */
! 75: char dm_flags; /* misc. flags */
! 76: u_short dm_cmd; /* DMA controller command */
! 77: u_int dm_cur; /* current segment */
! 78: u_int dm_last; /* last segment */
! 79: struct dma_chain dm_chain[DMAMAXIO]; /* all segments */
! 80: };
! 81:
! 82: struct dma_softc {
! 83: struct dmareg *sc_dmareg; /* pointer to our hardware */
! 84: struct isr sc_isr;
! 85: struct dma_channel sc_chan[NDMACHAN]; /* 2 channels */
! 86: #ifdef DEBUG
! 87: struct timeout sc_timeout; /* DMA timeout */
! 88: #endif
! 89: TAILQ_HEAD(, dmaqueue) sc_queue; /* job queue */
! 90: char sc_type; /* A, B, or C */
! 91: } dma_softc;
! 92:
! 93: /* types */
! 94: #define DMA_B 0
! 95: #define DMA_C 1
! 96:
! 97: /* flags */
! 98: #define DMAF_PCFLUSH 0x01
! 99: #define DMAF_VCFLUSH 0x02
! 100: #define DMAF_NOINTR 0x04
! 101:
! 102: void dmacflush(struct dma_channel *);
! 103: int dmaintr(void *);
! 104:
! 105: #ifdef DEBUG
! 106: int dmadebug = 0;
! 107: #define DDB_WORD 0x01 /* same as DMAGO_WORD */
! 108: #define DDB_LWORD 0x02 /* same as DMAGO_LWORD */
! 109: #define DDB_FOLLOW 0x04
! 110: #define DDB_IO 0x08
! 111:
! 112: void dmatimeout(void *);
! 113: int dmatimo[NDMACHAN];
! 114:
! 115: long dmahits[NDMACHAN];
! 116: long dmamisses[NDMACHAN];
! 117: long dmabyte[NDMACHAN];
! 118: long dmaword[NDMACHAN];
! 119: long dmalword[NDMACHAN];
! 120: #endif
! 121:
! 122: /*
! 123: * Initialize the DMA engine, called by dioattach()
! 124: */
! 125: void
! 126: dmainit()
! 127: {
! 128: struct dma_softc *sc = &dma_softc;
! 129: struct dmareg *dma;
! 130: struct dma_channel *dc;
! 131: int i;
! 132: char rev;
! 133:
! 134: /* There's just one. */
! 135: sc->sc_dmareg = (struct dmareg *)DMA_BASE;
! 136: dma = sc->sc_dmareg;
! 137:
! 138: /*
! 139: * Determine the DMA type. A DMA_A or DMA_B will fail the
! 140: * following probe.
! 141: *
! 142: * XXX Don't know how to easily differentiate the A and B cards,
! 143: * so we just hope nobody has an A card (A cards will work if
! 144: * splbio works out to ipl 3).
! 145: */
! 146: if (badbaddr((char *)&dma->dma_id[2])) {
! 147: rev = 'B';
! 148: #if !defined(HP320)
! 149: panic("dmainit: DMA card requires hp320 support");
! 150: #endif
! 151: } else
! 152: rev = dma->dma_id[2];
! 153:
! 154: sc->sc_type = (rev == 'B') ? DMA_B : DMA_C;
! 155:
! 156: TAILQ_INIT(&sc->sc_queue);
! 157:
! 158: for (i = 0; i < NDMACHAN; i++) {
! 159: dc = &sc->sc_chan[i];
! 160: dc->dm_job = NULL;
! 161: switch (i) {
! 162: case 0:
! 163: dc->dm_hwaddr = &dma->dma_chan0;
! 164: dc->dm_Bhwaddr = &dma->dma_Bchan0;
! 165: break;
! 166:
! 167: case 1:
! 168: dc->dm_hwaddr = &dma->dma_chan1;
! 169: dc->dm_Bhwaddr = &dma->dma_Bchan1;
! 170: break;
! 171:
! 172: default:
! 173: panic("dmainit: more than 2 channels?");
! 174: /* NOTREACHED */
! 175: }
! 176: }
! 177:
! 178: #ifdef DEBUG
! 179: /* make sure timeout is really not needed */
! 180: timeout_set(&sc->sc_timeout, dmatimeout, sc);
! 181: timeout_add(&sc->sc_timeout, 30 * hz);
! 182: #endif
! 183:
! 184: printf("98620%c, 2 channels, %d bit DMA\n",
! 185: rev, (rev == 'B') ? 16 : 32);
! 186:
! 187: /*
! 188: * Defer hooking up our interrupt until the first
! 189: * DMA-using controller has hooked up theirs.
! 190: */
! 191: sc->sc_isr.isr_func = NULL;
! 192: sc->sc_isr.isr_arg = sc;
! 193: sc->sc_isr.isr_priority = IPL_BIO;
! 194: }
! 195:
! 196: /*
! 197: * Compute the ipl and (re)establish the interrupt handler
! 198: * for the DMA controller.
! 199: */
! 200: void
! 201: dmacomputeipl()
! 202: {
! 203: struct dma_softc *sc = &dma_softc;
! 204:
! 205: if (sc->sc_isr.isr_func != NULL)
! 206: intr_disestablish(&sc->sc_isr);
! 207:
! 208: /*
! 209: * Our interrupt level must be as high as the highest
! 210: * device using DMA (i.e. splbio).
! 211: */
! 212: sc->sc_isr.isr_ipl = PSLTOIPL(hp300_bioipl);
! 213:
! 214: sc->sc_isr.isr_func = dmaintr;
! 215: intr_establish(&sc->sc_isr, "dma");
! 216: }
! 217:
! 218: int
! 219: dmareq(struct dmaqueue *dq)
! 220: {
! 221: struct dma_softc *sc = &dma_softc;
! 222: int i, chan, s;
! 223:
! 224: #if 1
! 225: s = splhigh(); /* XXXthorpej */
! 226: #else
! 227: s = splbio();
! 228: #endif
! 229:
! 230: chan = dq->dq_chan;
! 231: for (i = NDMACHAN - 1; i >= 0; i--) {
! 232: /*
! 233: * Can we use this channel?
! 234: */
! 235: if ((chan & (1 << i)) == 0)
! 236: continue;
! 237:
! 238: /*
! 239: * We can use it; is it busy?
! 240: */
! 241: if (sc->sc_chan[i].dm_job != NULL)
! 242: continue;
! 243:
! 244: /*
! 245: * Not busy; give the caller this channel.
! 246: */
! 247: sc->sc_chan[i].dm_job = dq;
! 248: dq->dq_chan = i;
! 249: splx(s);
! 250: return (1);
! 251: }
! 252:
! 253: /*
! 254: * Couldn't get a channel now; put this in the queue.
! 255: */
! 256: TAILQ_INSERT_TAIL(&sc->sc_queue, dq, dq_list);
! 257: splx(s);
! 258: return (0);
! 259: }
! 260:
! 261: void
! 262: dmacflush(struct dma_channel *dc)
! 263: {
! 264: #if defined(CACHE_HAVE_PAC) || defined(M68040)
! 265: if (dc->dm_flags & DMAF_PCFLUSH) {
! 266: PCIA();
! 267: dc->dm_flags &= ~DMAF_PCFLUSH;
! 268: }
! 269: #endif
! 270:
! 271: #if defined(CACHE_HAVE_VAC)
! 272: if (dc->dm_flags & DMAF_VCFLUSH) {
! 273: /*
! 274: * 320/350s have VACs that may also need flushing.
! 275: * In our case we only flush the supervisor side
! 276: * because we know that if we are DMAing to user
! 277: * space, the physical pages will also be mapped
! 278: * in kernel space (via vmapbuf) and hence cache-
! 279: * inhibited by the pmap module due to the multiple
! 280: * mapping.
! 281: */
! 282: DCIS();
! 283: dc->dm_flags &= ~DMAF_VCFLUSH;
! 284: }
! 285: #endif
! 286: }
! 287:
! 288: void
! 289: dmafree(struct dmaqueue *dq)
! 290: {
! 291: int unit = dq->dq_chan;
! 292: struct dma_softc *sc = &dma_softc;
! 293: struct dma_channel *dc = &sc->sc_chan[unit];
! 294: struct dmaqueue *dn;
! 295: int chan, s;
! 296:
! 297: #if 1
! 298: s = splhigh(); /* XXXthorpej */
! 299: #else
! 300: s = splbio();
! 301: #endif
! 302:
! 303: #ifdef DEBUG
! 304: dmatimo[unit] = 0;
! 305: #endif
! 306:
! 307: DMA_CLEAR(dc);
! 308:
! 309: /*
! 310: * XXX we may not always go through the flush code in dmastop()
! 311: */
! 312: dmacflush(dc);
! 313:
! 314: /*
! 315: * Channel is now free. Look for another job to run on this
! 316: * channel.
! 317: */
! 318: dc->dm_job = NULL;
! 319: chan = 1 << unit;
! 320: TAILQ_FOREACH(dn, &sc->sc_queue, dq_list) {
! 321: if (dn->dq_chan & chan) {
! 322: /* Found one... */
! 323: TAILQ_REMOVE(&sc->sc_queue, dn, dq_list);
! 324: dc->dm_job = dn;
! 325: dn->dq_chan = dq->dq_chan;
! 326: splx(s);
! 327:
! 328: /* Start the initiator. */
! 329: (*dn->dq_start)(dn->dq_softc);
! 330: return;
! 331: }
! 332: }
! 333: splx(s);
! 334: }
! 335:
! 336: void
! 337: dmago(int unit, char *addr, u_int count, int flags)
! 338: {
! 339: struct dma_softc *sc = &dma_softc;
! 340: struct dma_channel *dc = &sc->sc_chan[unit];
! 341: paddr_t dmaend = 0;
! 342: u_int seg, tcount;
! 343:
! 344: #ifdef DIAGNOSTIC
! 345: if (count > MAXPHYS)
! 346: panic("dmago: count > MAXPHYS");
! 347: #endif
! 348:
! 349: #if defined(HP320)
! 350: if (sc->sc_type == DMA_B && (flags & DMAGO_LWORD))
! 351: panic("dmago: no can do 32-bit DMA");
! 352: #endif
! 353:
! 354: #ifdef DEBUG
! 355: if (dmadebug & DDB_FOLLOW)
! 356: printf("dmago(%d, %p, %x, %x)\n",
! 357: unit, addr, count, flags);
! 358: if (flags & DMAGO_LWORD)
! 359: dmalword[unit]++;
! 360: else if (flags & DMAGO_WORD)
! 361: dmaword[unit]++;
! 362: else
! 363: dmabyte[unit]++;
! 364: #endif
! 365: /*
! 366: * Build the DMA chain
! 367: */
! 368: for (seg = 0; count > 0; seg++) {
! 369: if (pmap_extract(pmap_kernel(), (vaddr_t)addr,
! 370: &dc->dm_chain[seg].dc_addr) == FALSE)
! 371: panic("dmago: pmap_extract(%x) failed", addr);
! 372: #if defined(M68040)
! 373: /*
! 374: * Push back dirty cache lines
! 375: */
! 376: if (mmutype == MMU_68040)
! 377: DCFP(dc->dm_chain[seg].dc_addr);
! 378: #endif
! 379: if (count < (tcount = PAGE_SIZE - ((int)addr & PAGE_MASK)))
! 380: tcount = count;
! 381: dc->dm_chain[seg].dc_count = tcount;
! 382: addr += tcount;
! 383: count -= tcount;
! 384: if (flags & DMAGO_LWORD)
! 385: tcount >>= 2;
! 386: else if (flags & DMAGO_WORD)
! 387: tcount >>= 1;
! 388:
! 389: /*
! 390: * Try to compact the DMA transfer if the pages are adjacent.
! 391: * Note: this will never happen on the first iteration.
! 392: */
! 393: if (dc->dm_chain[seg].dc_addr == dmaend
! 394: #if defined(HP320)
! 395: /* only 16-bit count on 98620B */
! 396: && (sc->sc_type != DMA_B ||
! 397: dc->dm_chain[seg - 1].dc_count + tcount <= 65536)
! 398: #endif
! 399: ) {
! 400: #ifdef DEBUG
! 401: dmahits[unit]++;
! 402: #endif
! 403: dmaend += dc->dm_chain[seg].dc_count;
! 404: dc->dm_chain[--seg].dc_count += tcount;
! 405: } else {
! 406: #ifdef DEBUG
! 407: dmamisses[unit]++;
! 408: #endif
! 409: dmaend = dc->dm_chain[seg].dc_addr +
! 410: dc->dm_chain[seg].dc_count;
! 411: dc->dm_chain[seg].dc_count = tcount;
! 412: }
! 413: }
! 414: dc->dm_cur = 0;
! 415: dc->dm_last = --seg;
! 416: dc->dm_flags = 0;
! 417: /*
! 418: * Set up the command word based on flags
! 419: */
! 420: dc->dm_cmd = DMA_ENAB | DMA_IPL(sc->sc_isr.isr_ipl) | DMA_START;
! 421: if ((flags & DMAGO_READ) == 0)
! 422: dc->dm_cmd |= DMA_WRT;
! 423: if (flags & DMAGO_LWORD)
! 424: dc->dm_cmd |= DMA_LWORD;
! 425: else if (flags & DMAGO_WORD)
! 426: dc->dm_cmd |= DMA_WORD;
! 427: if (flags & DMAGO_PRI)
! 428: dc->dm_cmd |= DMA_PRI;
! 429:
! 430: if (flags & DMAGO_READ) {
! 431: #if defined(M68040)
! 432: /*
! 433: * On the 68040 we need to flush (push) the data cache before a
! 434: * DMA (already done above) and flush again after DMA completes.
! 435: * In theory we should only need to flush prior to a write DMA
! 436: * and purge after a read DMA but if the entire page is not
! 437: * involved in the DMA we might purge some valid data.
! 438: */
! 439: if (mmutype == MMU_68040)
! 440: dc->dm_flags |= DMAF_PCFLUSH;
! 441: #endif
! 442:
! 443: #if defined(CACHE_HAVE_PAC)
! 444: /*
! 445: * Remember if we need to flush external physical cache when
! 446: * DMA is done. We only do this if we are reading
! 447: * (writing memory).
! 448: */
! 449: if (ectype == EC_PHYS)
! 450: dc->dm_flags |= DMAF_PCFLUSH;
! 451: #endif
! 452:
! 453: #if defined(CACHE_HAVE_VAC)
! 454: if (ectype == EC_VIRT)
! 455: dc->dm_flags |= DMAF_VCFLUSH;
! 456: #endif
! 457: }
! 458:
! 459: /*
! 460: * Remember if we can skip the dma completion interrupt on
! 461: * the last segment in the chain.
! 462: */
! 463: if (flags & DMAGO_NOINT) {
! 464: if (dc->dm_cur == dc->dm_last)
! 465: dc->dm_cmd &= ~DMA_ENAB;
! 466: else
! 467: dc->dm_flags |= DMAF_NOINTR;
! 468: }
! 469: #ifdef DEBUG
! 470: if (dmadebug & DDB_IO) {
! 471: if (((dmadebug&DDB_WORD) && (dc->dm_cmd&DMA_WORD)) ||
! 472: ((dmadebug&DDB_LWORD) && (dc->dm_cmd&DMA_LWORD))) {
! 473: printf("dmago: cmd %x, flags %x\n",
! 474: dc->dm_cmd, dc->dm_flags);
! 475: for (seg = 0; seg <= dc->dm_last; seg++)
! 476: printf(" %d: %d@%p\n", seg,
! 477: dc->dm_chain[seg].dc_count,
! 478: dc->dm_chain[seg].dc_addr);
! 479: }
! 480: }
! 481: dmatimo[unit] = 1;
! 482: #endif
! 483: DMA_ARM(sc, dc);
! 484: }
! 485:
! 486: void
! 487: dmastop(int unit)
! 488: {
! 489: struct dma_softc *sc = &dma_softc;
! 490: struct dma_channel *dc = &sc->sc_chan[unit];
! 491:
! 492: #ifdef DEBUG
! 493: if (dmadebug & DDB_FOLLOW)
! 494: printf("dmastop(%d)\n", unit);
! 495: dmatimo[unit] = 0;
! 496: #endif
! 497: DMA_CLEAR(dc);
! 498:
! 499: dmacflush(dc);
! 500:
! 501: /*
! 502: * We may get this interrupt after a device service routine
! 503: * has freed the dma channel. So, ignore the intr if there's
! 504: * nothing on the queue.
! 505: */
! 506: if (dc->dm_job != NULL)
! 507: (*dc->dm_job->dq_done)(dc->dm_job->dq_softc);
! 508: }
! 509:
! 510: int
! 511: dmaintr(void *arg)
! 512: {
! 513: struct dma_softc *sc = arg;
! 514: struct dma_channel *dc;
! 515: int i, stat;
! 516: int found = 0;
! 517:
! 518: #ifdef DEBUG
! 519: if (dmadebug & DDB_FOLLOW)
! 520: printf("dmaintr\n");
! 521: #endif
! 522: for (i = 0; i < NDMACHAN; i++) {
! 523: dc = &sc->sc_chan[i];
! 524: stat = DMA_STAT(dc);
! 525: if ((stat & DMA_INTR) == 0)
! 526: continue;
! 527: found++;
! 528: #ifdef DEBUG
! 529: if (dmadebug & DDB_IO) {
! 530: if (((dmadebug&DDB_WORD) && (dc->dm_cmd&DMA_WORD)) ||
! 531: ((dmadebug&DDB_LWORD) && (dc->dm_cmd&DMA_LWORD)))
! 532: printf("dmaintr: flags %x unit %d stat %x next %d\n",
! 533: dc->dm_flags, i, stat, dc->dm_cur + 1);
! 534: }
! 535: if (stat & DMA_ARMED)
! 536: printf("dma channel %d: intr when armed\n", i);
! 537: #endif
! 538: /*
! 539: * Load the next segment, or finish up if we're done.
! 540: */
! 541: dc->dm_cur++;
! 542: if (dc->dm_cur <= dc->dm_last) {
! 543: #ifdef DEBUG
! 544: dmatimo[i] = 1;
! 545: #endif
! 546: /*
! 547: * If we're the last segment, disable the
! 548: * completion interrupt, if necessary.
! 549: */
! 550: if (dc->dm_cur == dc->dm_last &&
! 551: (dc->dm_flags & DMAF_NOINTR))
! 552: dc->dm_cmd &= ~DMA_ENAB;
! 553: DMA_CLEAR(dc);
! 554: DMA_ARM(sc, dc);
! 555: } else
! 556: dmastop(i);
! 557: }
! 558: return(found);
! 559: }
! 560:
! 561: #ifdef DEBUG
! 562: void
! 563: dmatimeout(void *arg)
! 564: {
! 565: int i, s;
! 566: struct dma_softc *sc = arg;
! 567:
! 568: for (i = 0; i < NDMACHAN; i++) {
! 569: s = splbio();
! 570: if (dmatimo[i]) {
! 571: if (dmatimo[i] > 1)
! 572: printf("dma channel %d timeout #%d\n",
! 573: i, dmatimo[i]-1);
! 574: dmatimo[i]++;
! 575: }
! 576: splx(s);
! 577: }
! 578: timeout_add(&sc->sc_timeout, 30 * hz);
! 579: }
! 580: #endif
CVSweb