summaryrefslogtreecommitdiff
path: root/sys/arch/hp300/dev/dma.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/hp300/dev/dma.c')
-rw-r--r--sys/arch/hp300/dev/dma.c572
1 files changed, 0 insertions, 572 deletions
diff --git a/sys/arch/hp300/dev/dma.c b/sys/arch/hp300/dev/dma.c
deleted file mode 100644
index 33a9551ba68..00000000000
--- a/sys/arch/hp300/dev/dma.c
+++ /dev/null
@@ -1,572 +0,0 @@
-/* $OpenBSD: dma.c,v 1.20 2008/10/15 19:12:19 blambert Exp $ */
-/* $NetBSD: dma.c,v 1.19 1997/05/05 21:02:39 thorpej Exp $ */
-
-/*
- * Copyright (c) 1995, 1996, 1997
- * Jason R. Thorpe. All rights reserved.
- * Copyright (c) 1982, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * @(#)dma.c 8.1 (Berkeley) 6/10/93
- */
-
-/*
- * DMA driver
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/time.h>
-#include <sys/kernel.h>
-#include <sys/proc.h>
-#include <sys/device.h>
-#include <sys/timeout.h>
-
-#include <machine/frame.h>
-#include <machine/cpu.h>
-#include <machine/intr.h>
-
-#include <hp300/dev/dmareg.h>
-#include <hp300/dev/dmavar.h>
-
-#include <uvm/uvm_extern.h>
-
-/*
- * The largest single request will be MAXPHYS bytes which will require
- * at most MAXPHYS/NBPG+1 chain elements to describe, i.e. if none of
- * the buffer pages are physically contiguous (MAXPHYS/NBPG) and the
- * buffer is not page aligned (+1).
- */
-#define DMAMAXIO (MAXPHYS/NBPG+1)
-
-struct dma_chain {
- u_int dc_count;
- paddr_t dc_addr;
-};
-
-struct dma_channel {
- struct dmaqueue *dm_job; /* current job */
- struct dmadevice *dm_hwaddr; /* registers if DMA_C */
- struct dmaBdevice *dm_Bhwaddr; /* registers if not DMA_C */
- char dm_flags; /* misc. flags */
- u_short dm_cmd; /* DMA controller command */
- u_int dm_cur; /* current segment */
- u_int dm_last; /* last segment */
- struct dma_chain dm_chain[DMAMAXIO]; /* all segments */
-};
-
-struct dma_softc {
- struct dmareg *sc_dmareg; /* pointer to our hardware */
- struct isr sc_isr;
- struct dma_channel sc_chan[NDMACHAN]; /* 2 channels */
-#ifdef DEBUG
- struct timeout sc_timeout; /* DMA timeout */
-#endif
- TAILQ_HEAD(, dmaqueue) sc_queue; /* job queue */
- char sc_type; /* A, B, or C */
-} dma_softc;
-
-/* types */
-#define DMA_B 0
-#define DMA_C 1
-
-/* flags */
-#define DMAF_PCFLUSH 0x01
-#define DMAF_VCFLUSH 0x02
-#define DMAF_NOINTR 0x04
-
-void dmacflush(struct dma_channel *);
-int dmaintr(void *);
-
-#ifdef DEBUG
-int dmadebug = 0;
-#define DDB_WORD 0x01 /* same as DMAGO_WORD */
-#define DDB_LWORD 0x02 /* same as DMAGO_LWORD */
-#define DDB_FOLLOW 0x04
-#define DDB_IO 0x08
-
-void dmatimeout(void *);
-int dmatimo[NDMACHAN];
-
-long dmahits[NDMACHAN];
-long dmamisses[NDMACHAN];
-long dmabyte[NDMACHAN];
-long dmaword[NDMACHAN];
-long dmalword[NDMACHAN];
-#endif
-
-/*
- * Initialize the DMA engine, called by dioattach()
- */
-void
-dmainit()
-{
- struct dma_softc *sc = &dma_softc;
- struct dmareg *dma;
- struct dma_channel *dc;
- int i;
- char rev;
-
- /* There's just one. */
- sc->sc_dmareg = (struct dmareg *)DMA_BASE;
- dma = sc->sc_dmareg;
-
- /*
- * Determine the DMA type. A DMA_A or DMA_B will fail the
- * following probe.
- *
- * XXX Don't know how to easily differentiate the A and B cards,
- * so we just hope nobody has an A card (A cards will work if
- * splbio works out to ipl 3).
- */
- if (badbaddr((char *)&dma->dma_id[2])) {
- rev = 'B';
-#if !defined(HP320)
- panic("dmainit: DMA card requires hp320 support");
-#endif
- } else
- rev = dma->dma_id[2];
-
- sc->sc_type = (rev == 'B') ? DMA_B : DMA_C;
-
- TAILQ_INIT(&sc->sc_queue);
-
- for (i = 0; i < NDMACHAN; i++) {
- dc = &sc->sc_chan[i];
- dc->dm_job = NULL;
- switch (i) {
- case 0:
- dc->dm_hwaddr = &dma->dma_chan0;
- dc->dm_Bhwaddr = &dma->dma_Bchan0;
- break;
-
- case 1:
- dc->dm_hwaddr = &dma->dma_chan1;
- dc->dm_Bhwaddr = &dma->dma_Bchan1;
- break;
-
- default:
- panic("dmainit: more than 2 channels?");
- /* NOTREACHED */
- }
- }
-
-#ifdef DEBUG
- /* make sure timeout is really not needed */
- timeout_set(&sc->sc_timeout, dmatimeout, sc);
- timeout_add_sec(&sc->sc_timeout, 30);
-#endif
-
- printf("98620%c, 2 channels, %d bit DMA\n",
- rev, (rev == 'B') ? 16 : 32);
-
- /*
- * Defer hooking up our interrupt until the first
- * DMA-using controller has hooked up theirs.
- */
- sc->sc_isr.isr_func = NULL;
- sc->sc_isr.isr_arg = sc;
- sc->sc_isr.isr_priority = IPL_BIO;
-}
-
-/*
- * Compute the ipl and (re)establish the interrupt handler
- * for the DMA controller.
- */
-void
-dmacomputeipl()
-{
- struct dma_softc *sc = &dma_softc;
-
- if (sc->sc_isr.isr_func != NULL)
- intr_disestablish(&sc->sc_isr);
-
- /*
- * Our interrupt level must be as high as the highest
- * device using DMA (i.e. splbio).
- */
- sc->sc_isr.isr_ipl = PSLTOIPL(hp300_varpsl[IPL_BIO]);
-
- sc->sc_isr.isr_func = dmaintr;
- intr_establish(&sc->sc_isr, "dma");
-}
-
-int
-dmareq(struct dmaqueue *dq)
-{
- struct dma_softc *sc = &dma_softc;
- int i, chan, s;
-
- s = splvm();
-
- chan = dq->dq_chan;
- for (i = NDMACHAN - 1; i >= 0; i--) {
- /*
- * Can we use this channel?
- */
- if ((chan & (1 << i)) == 0)
- continue;
-
- /*
- * We can use it; is it busy?
- */
- if (sc->sc_chan[i].dm_job != NULL)
- continue;
-
- /*
- * Not busy; give the caller this channel.
- */
- sc->sc_chan[i].dm_job = dq;
- dq->dq_chan = i;
- splx(s);
- return (1);
- }
-
- /*
- * Couldn't get a channel now; put this in the queue.
- */
- TAILQ_INSERT_TAIL(&sc->sc_queue, dq, dq_list);
- splx(s);
- return (0);
-}
-
-void
-dmacflush(struct dma_channel *dc)
-{
-#if defined(CACHE_HAVE_PAC) || defined(M68040)
- if (dc->dm_flags & DMAF_PCFLUSH) {
- PCIA();
- dc->dm_flags &= ~DMAF_PCFLUSH;
- }
-#endif
-
-#if defined(CACHE_HAVE_VAC)
- if (dc->dm_flags & DMAF_VCFLUSH) {
- /*
- * 320/350s have VACs that may also need flushing.
- * In our case we only flush the supervisor side
- * because we know that if we are DMAing to user
- * space, the physical pages will also be mapped
- * in kernel space (via vmapbuf) and hence cache-
- * inhibited by the pmap module due to the multiple
- * mapping.
- */
- DCIS();
- dc->dm_flags &= ~DMAF_VCFLUSH;
- }
-#endif
-}
-
-void
-dmafree(struct dmaqueue *dq)
-{
- int unit = dq->dq_chan;
- struct dma_softc *sc = &dma_softc;
- struct dma_channel *dc = &sc->sc_chan[unit];
- struct dmaqueue *dn;
- int chan, s;
-
- s = splvm();
-
-#ifdef DEBUG
- dmatimo[unit] = 0;
-#endif
-
- DMA_CLEAR(dc);
-
- /*
- * XXX we may not always go through the flush code in dmastop()
- */
- dmacflush(dc);
-
- /*
- * Channel is now free. Look for another job to run on this
- * channel.
- */
- dc->dm_job = NULL;
- chan = 1 << unit;
- TAILQ_FOREACH(dn, &sc->sc_queue, dq_list) {
- if (dn->dq_chan & chan) {
- /* Found one... */
- TAILQ_REMOVE(&sc->sc_queue, dn, dq_list);
- dc->dm_job = dn;
- dn->dq_chan = dq->dq_chan;
- splx(s);
-
- /* Start the initiator. */
- (*dn->dq_start)(dn->dq_softc);
- return;
- }
- }
- splx(s);
-}
-
-void
-dmago(int unit, char *addr, u_int count, int flags)
-{
- struct dma_softc *sc = &dma_softc;
- struct dma_channel *dc = &sc->sc_chan[unit];
- paddr_t dmaend = 0;
- u_int seg, tcount;
-
-#ifdef DIAGNOSTIC
- if (count > MAXPHYS)
- panic("dmago: count > MAXPHYS");
-#endif
-
-#if defined(HP320)
- if (sc->sc_type == DMA_B && (flags & DMAGO_LWORD))
- panic("dmago: no can do 32-bit DMA");
-#endif
-
-#ifdef DEBUG
- if (dmadebug & DDB_FOLLOW)
- printf("dmago(%d, %p, %x, %x)\n",
- unit, addr, count, flags);
- if (flags & DMAGO_LWORD)
- dmalword[unit]++;
- else if (flags & DMAGO_WORD)
- dmaword[unit]++;
- else
- dmabyte[unit]++;
-#endif
- /*
- * Build the DMA chain
- */
- for (seg = 0; count > 0; seg++) {
- if (pmap_extract(pmap_kernel(), (vaddr_t)addr,
- &dc->dm_chain[seg].dc_addr) == FALSE)
- panic("dmago: pmap_extract(%x) failed", addr);
-#if defined(M68040)
- /*
- * Push back dirty cache lines
- */
- if (mmutype == MMU_68040)
- DCFP(dc->dm_chain[seg].dc_addr);
-#endif
- if (count < (tcount = PAGE_SIZE - ((int)addr & PAGE_MASK)))
- tcount = count;
- dc->dm_chain[seg].dc_count = tcount;
- addr += tcount;
- count -= tcount;
- if (flags & DMAGO_LWORD)
- tcount >>= 2;
- else if (flags & DMAGO_WORD)
- tcount >>= 1;
-
- /*
- * Try to compact the DMA transfer if the pages are adjacent.
- * Note: this will never happen on the first iteration.
- */
- if (dc->dm_chain[seg].dc_addr == dmaend
-#if defined(HP320)
- /* only 16-bit count on 98620B */
- && (sc->sc_type != DMA_B ||
- dc->dm_chain[seg - 1].dc_count + tcount <= 65536)
-#endif
- ) {
-#ifdef DEBUG
- dmahits[unit]++;
-#endif
- dmaend += dc->dm_chain[seg].dc_count;
- dc->dm_chain[--seg].dc_count += tcount;
- } else {
-#ifdef DEBUG
- dmamisses[unit]++;
-#endif
- dmaend = dc->dm_chain[seg].dc_addr +
- dc->dm_chain[seg].dc_count;
- dc->dm_chain[seg].dc_count = tcount;
- }
- }
- dc->dm_cur = 0;
- dc->dm_last = --seg;
- dc->dm_flags = 0;
- /*
- * Set up the command word based on flags
- */
- dc->dm_cmd = DMA_ENAB | DMA_IPL(sc->sc_isr.isr_ipl) | DMA_START;
- if ((flags & DMAGO_READ) == 0)
- dc->dm_cmd |= DMA_WRT;
- if (flags & DMAGO_LWORD)
- dc->dm_cmd |= DMA_LWORD;
- else if (flags & DMAGO_WORD)
- dc->dm_cmd |= DMA_WORD;
- if (flags & DMAGO_PRI)
- dc->dm_cmd |= DMA_PRI;
-
- if (flags & DMAGO_READ) {
-#if defined(M68040)
- /*
- * On the 68040 we need to flush (push) the data cache before a
- * DMA (already done above) and flush again after DMA completes.
- * In theory we should only need to flush prior to a write DMA
- * and purge after a read DMA but if the entire page is not
- * involved in the DMA we might purge some valid data.
- */
- if (mmutype == MMU_68040)
- dc->dm_flags |= DMAF_PCFLUSH;
-#endif
-
-#if defined(CACHE_HAVE_PAC)
- /*
- * Remember if we need to flush external physical cache when
- * DMA is done. We only do this if we are reading
- * (writing memory).
- */
- if (ectype == EC_PHYS)
- dc->dm_flags |= DMAF_PCFLUSH;
-#endif
-
-#if defined(CACHE_HAVE_VAC)
- if (ectype == EC_VIRT)
- dc->dm_flags |= DMAF_VCFLUSH;
-#endif
- }
-
- /*
- * Remember if we can skip the dma completion interrupt on
- * the last segment in the chain.
- */
- if (flags & DMAGO_NOINT) {
- if (dc->dm_cur == dc->dm_last)
- dc->dm_cmd &= ~DMA_ENAB;
- else
- dc->dm_flags |= DMAF_NOINTR;
- }
-#ifdef DEBUG
- if (dmadebug & DDB_IO) {
- if (((dmadebug&DDB_WORD) && (dc->dm_cmd&DMA_WORD)) ||
- ((dmadebug&DDB_LWORD) && (dc->dm_cmd&DMA_LWORD))) {
- printf("dmago: cmd %x, flags %x\n",
- dc->dm_cmd, dc->dm_flags);
- for (seg = 0; seg <= dc->dm_last; seg++)
- printf(" %d: %d@%p\n", seg,
- dc->dm_chain[seg].dc_count,
- dc->dm_chain[seg].dc_addr);
- }
- }
- dmatimo[unit] = 1;
-#endif
- DMA_ARM(sc, dc);
-}
-
-void
-dmastop(int unit)
-{
- struct dma_softc *sc = &dma_softc;
- struct dma_channel *dc = &sc->sc_chan[unit];
-
-#ifdef DEBUG
- if (dmadebug & DDB_FOLLOW)
- printf("dmastop(%d)\n", unit);
- dmatimo[unit] = 0;
-#endif
- DMA_CLEAR(dc);
-
- dmacflush(dc);
-
- /*
- * We may get this interrupt after a device service routine
- * has freed the dma channel. So, ignore the intr if there's
- * nothing on the queue.
- */
- if (dc->dm_job != NULL)
- (*dc->dm_job->dq_done)(dc->dm_job->dq_softc);
-}
-
-int
-dmaintr(void *arg)
-{
- struct dma_softc *sc = arg;
- struct dma_channel *dc;
- int i, stat;
- int found = 0;
-
-#ifdef DEBUG
- if (dmadebug & DDB_FOLLOW)
- printf("dmaintr\n");
-#endif
- for (i = 0; i < NDMACHAN; i++) {
- dc = &sc->sc_chan[i];
- stat = DMA_STAT(dc);
- if ((stat & DMA_INTR) == 0)
- continue;
- found++;
-#ifdef DEBUG
- if (dmadebug & DDB_IO) {
- if (((dmadebug&DDB_WORD) && (dc->dm_cmd&DMA_WORD)) ||
- ((dmadebug&DDB_LWORD) && (dc->dm_cmd&DMA_LWORD)))
- printf("dmaintr: flags %x unit %d stat %x next %d\n",
- dc->dm_flags, i, stat, dc->dm_cur + 1);
- }
- if (stat & DMA_ARMED)
- printf("dma channel %d: intr when armed\n", i);
-#endif
- /*
- * Load the next segment, or finish up if we're done.
- */
- dc->dm_cur++;
- if (dc->dm_cur <= dc->dm_last) {
-#ifdef DEBUG
- dmatimo[i] = 1;
-#endif
- /*
- * If we're the last segment, disable the
- * completion interrupt, if necessary.
- */
- if (dc->dm_cur == dc->dm_last &&
- (dc->dm_flags & DMAF_NOINTR))
- dc->dm_cmd &= ~DMA_ENAB;
- DMA_CLEAR(dc);
- DMA_ARM(sc, dc);
- } else
- dmastop(i);
- }
- return(found);
-}
-
-#ifdef DEBUG
-void
-dmatimeout(void *arg)
-{
- int i, s;
- struct dma_softc *sc = arg;
-
- for (i = 0; i < NDMACHAN; i++) {
- s = splvm();
- if (dmatimo[i]) {
- if (dmatimo[i] > 1)
- printf("dma channel %d timeout #%d\n",
- i, dmatimo[i]-1);
- dmatimo[i]++;
- }
- splx(s);
- }
- timeout_add_sec(&sc->sc_timeout, 30);
-}
-#endif