summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorNiklas Hallqvist <niklas@cvs.openbsd.org>1998-01-20 18:40:37 +0000
committerNiklas Hallqvist <niklas@cvs.openbsd.org>1998-01-20 18:40:37 +0000
commite4232757b30346a182214fb65da8a76f2edb7b24 (patch)
tree5c1b89b92ef8c67dfa2d0f3a078804042a1555ee /sys
parent0a8f2cc87f99deec610ef91696850a249bd8fb81 (diff)
Merge bus_dma support from NetBSD, mostly by Jason Thorpe. Only i386 uses it
so far, the other archs gets placeholders for now. I wrote a compatibility layer for OpenBSD's old isadma code so we can still use our old driver sources. They will however get changed to native bus_dma use, on a case by case basis. Oh yes, I almost forgot, I kept our notion of isadma being a device so DMA-less ISA-busses still work
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/alpha/include/bus.h6
-rw-r--r--sys/arch/arc/include/bus.h6
-rw-r--r--sys/arch/i386/eisa/eisa_machdep.c63
-rw-r--r--sys/arch/i386/eisa/eisa_machdep.h6
-rw-r--r--sys/arch/i386/i386/machdep.c484
-rw-r--r--sys/arch/i386/i386/mainbus.c13
-rw-r--r--sys/arch/i386/i386/pmap.c16
-rw-r--r--sys/arch/i386/i386/pmap.old.c16
-rw-r--r--sys/arch/i386/include/bus.h210
-rw-r--r--sys/arch/i386/isa/isa_machdep.c844
-rw-r--r--sys/arch/i386/isa/isa_machdep.h67
-rw-r--r--sys/arch/i386/pci/pchb.c3
-rw-r--r--sys/arch/i386/pci/pci_machdep.c65
-rw-r--r--sys/arch/i386/pci/pci_machdep.h6
-rw-r--r--sys/arch/powerpc/include/bus.h6
-rw-r--r--sys/dev/eisa/eisavar.h6
-rw-r--r--sys/dev/isa/isa.c105
-rw-r--r--sys/dev/isa/isadma.c795
-rw-r--r--sys/dev/isa/isadmareg.h26
-rw-r--r--sys/dev/isa/isadmavar.h115
-rw-r--r--sys/dev/isa/isapnp.c4
-rw-r--r--sys/dev/isa/isavar.h112
-rw-r--r--sys/dev/pci/pci.c5
-rw-r--r--sys/dev/pci/pcivar.h6
-rw-r--r--sys/dev/pci/ppb.c5
25 files changed, 2417 insertions, 573 deletions
diff --git a/sys/arch/alpha/include/bus.h b/sys/arch/alpha/include/bus.h
index a3ead3a2bf5..27f67558de3 100644
--- a/sys/arch/alpha/include/bus.h
+++ b/sys/arch/alpha/include/bus.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bus.h,v 1.9 1997/06/05 23:21:30 deraadt Exp $ */
+/* $OpenBSD: bus.h,v 1.10 1998/01/20 18:40:09 niklas Exp $ */
/* $NetBSD: bus.h,v 1.10 1996/12/02 22:19:32 cgd Exp $ */
/*
@@ -380,4 +380,8 @@ struct alpha_bus_space {
#define bus_space_copy_8(t, h1, o1, h2, o2, c) \
__abs_copy(8, t, h1, o1, h2, o2, c)
+/* XXX placeholders */
+typedef void *bus_dma_tag_t;
+typedef void *bus_dmamap_t;
+
#endif /* _ALPHA_BUS_H_ */
diff --git a/sys/arch/arc/include/bus.h b/sys/arch/arc/include/bus.h
index b9f6739ce26..5251a510c4c 100644
--- a/sys/arch/arc/include/bus.h
+++ b/sys/arch/arc/include/bus.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bus.h,v 1.13 1997/04/19 17:19:56 pefo Exp $ */
+/* $OpenBSD: bus.h,v 1.14 1998/01/20 18:40:11 niklas Exp $ */
/*
* Copyright (c) 1997 Per Fogelstrom. All rights reserved.
@@ -158,4 +158,8 @@ bus_space_write_raw_multi(4,32,2)
#define bus_space_write_raw_multi_8 \
!!! bus_space_write_raw_multi_8 not implemented !!!
+/* XXX placeholders */
+typedef void *bus_dma_tag_t;
+typedef void *bus_dmamap_t;
+
#endif /* _ARC_BUS_H_ */
diff --git a/sys/arch/i386/eisa/eisa_machdep.c b/sys/arch/i386/eisa/eisa_machdep.c
index fd1e28c11a3..766b3a0cb45 100644
--- a/sys/arch/i386/eisa/eisa_machdep.c
+++ b/sys/arch/i386/eisa/eisa_machdep.c
@@ -1,4 +1,41 @@
-/* $NetBSD: eisa_machdep.c,v 1.2 1996/04/11 22:15:08 cgd Exp $ */
+/* $NetBSD: eisa_machdep.c,v 1.6 1997/06/06 23:12:52 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
@@ -41,10 +78,34 @@
#include <sys/errno.h>
#include <sys/device.h>
+#define _I386_BUS_DMA_PRIVATE
+#include <machine/bus.h>
+
#include <i386/isa/icu.h>
#include <dev/isa/isavar.h>
#include <dev/eisa/eisavar.h>
+/*
+ * EISA doesn't have any special needs; just use the generic versions
+ * of these funcions.
+ */
+struct i386_bus_dma_tag eisa_bus_dma_tag = {
+ NULL, /* _cookie */
+ _bus_dmamap_create,
+ _bus_dmamap_destroy,
+ _bus_dmamap_load,
+ _bus_dmamap_load_mbuf,
+ _bus_dmamap_load_uio,
+ _bus_dmamap_load_raw,
+ _bus_dmamap_unload,
+ NULL, /* _dmamap_sync */
+ _bus_dmamem_alloc,
+ _bus_dmamem_free,
+ _bus_dmamem_map,
+ _bus_dmamem_unmap,
+ _bus_dmamem_mmap,
+};
+
void
eisa_attach_hook(parent, self, eba)
struct device *parent, *self;
diff --git a/sys/arch/i386/eisa/eisa_machdep.h b/sys/arch/i386/eisa/eisa_machdep.h
index 2e4f1019e2f..2ac1f5810c3 100644
--- a/sys/arch/i386/eisa/eisa_machdep.h
+++ b/sys/arch/i386/eisa/eisa_machdep.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: eisa_machdep.h,v 1.2 1996/04/21 22:16:19 deraadt Exp $ */
-/* $NetBSD: eisa_machdep.h,v 1.2 1996/04/09 23:00:27 cgd Exp $ */
+/* $OpenBSD: eisa_machdep.h,v 1.3 1998/01/20 18:40:13 niklas Exp $ */
+/* $NetBSD: eisa_machdep.h,v 1.4 1997/06/06 23:12:52 thorpej Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
@@ -43,6 +43,8 @@
#define EISA_ID_LEN (sizeof(EISA_ID) - 1)
#define EISA_ID_PADDR 0xfffd9
+extern struct i386_bus_dma_tag eisa_bus_dma_tag;
+
/*
* Types provided to machine-independent EISA code.
*/
diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c
index 04ad65d6059..c4b01b7534f 100644
--- a/sys/arch/i386/i386/machdep.c
+++ b/sys/arch/i386/i386/machdep.c
@@ -1,7 +1,44 @@
-/* $OpenBSD: machdep.c,v 1.75 1998/01/17 09:57:05 niklas Exp $ */
+/* $OpenBSD: machdep.c,v 1.76 1998/01/20 18:40:14 niklas Exp $ */
/* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */
/*-
+ * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*-
* Copyright (c) 1993, 1994, 1995, 1996 Charles M. Hannum. All rights reserved.
* Copyright (c) 1992 Terrence R. Lambert.
* Copyright (c) 1982, 1987, 1990 The Regents of the University of California.
@@ -82,6 +119,9 @@
#include <sys/sysctl.h>
+#define _I386_BUS_DMA_PRIVATE
+#include <machine/bus.h>
+
#include <machine/cpu.h>
#include <machine/cpufunc.h>
#include <machine/gdt.h>
@@ -116,6 +156,7 @@
#endif
#include "isa.h"
+#include "isadma.h"
#include "npx.h"
#if NNPX > 0
extern struct proc *npxproc;
@@ -125,6 +166,7 @@ extern struct proc *npxproc;
/* the following is used externally (sysctl_hw) */
char machine[] = "i386"; /* cpu "architecture" */
+char machine_arch[] = "i386"; /* machine == machine_arch */
/*
* Declare these as initialized data so we can patch them.
@@ -1537,6 +1579,25 @@ init386(first_avail)
printf("WARNING: CAN'T ALLOCATE EXTENDED MEMORY FROM IOMEM EXTENT MAP!\n");
}
+#if NISADMA > 0
+ /*
+ * Some motherboards/BIOSes remap the 384K of RAM that would
+ * normally be covered by the ISA hole to the end of memory
+ * so that it can be used. However, on a 16M system, this
+ * would cause bounce buffers to be allocated and used.
+ * This is not desirable behaviour, as more than 384K of
+ * bounce buffers might be allocated. As a work-around,
+ * we round memory down to the nearest 1M boundary if
+ * we're using any isadma devices and the remapped memory
+ * is what puts us over 16M.
+ */
+ if (extmem > (15*1024) && extmem < (16*1024)) {
+ printf("Warning: ignoring %dk of remapped memory\n",
+ extmem - (15*1024));
+ extmem = (15*1024);
+ }
+#endif
+
/* Round down to whole pages. */
cm = i386_round_page(cnvmem * 1024);
em = i386_round_page(extmem * 1024);
@@ -2002,3 +2063,424 @@ bus_space_subregion(t, bsh, offset, size, nbshp)
*nbshp = bsh + offset;
return (0);
}
+
+/*
+ * Common function for DMA map creation. May be called by bus-specific
+ * DMA map creation functions.
+ */
+int
+_bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, flags, dmamp)
+ bus_dma_tag_t t;
+ bus_size_t size;
+ int nsegments;
+ bus_size_t maxsegsz;
+ bus_size_t boundary;
+ int flags;
+ bus_dmamap_t *dmamp;
+{
+ struct i386_bus_dmamap *map;
+ void *mapstore;
+ size_t mapsize;
+
+ /*
+ * Allocate and initialize the DMA map. The end of the map
+ * is a variable-sized array of segments, so we allocate enough
+ * room for them in one shot.
+ *
+ * Note we don't preserve the WAITOK or NOWAIT flags. Preservation
+ * of ALLOCNOW notifies others that we've reserved these resources,
+ * and they are not to be freed.
+ *
+ * The bus_dmamap_t includes one bus_dma_segment_t, hence
+ * the (nsegments - 1).
+ */
+ mapsize = sizeof(struct i386_bus_dmamap) +
+ (sizeof(bus_dma_segment_t) * (nsegments - 1));
+ if ((mapstore = malloc(mapsize, M_DEVBUF,
+ (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL)
+ return (ENOMEM);
+
+ bzero(mapstore, mapsize);
+ map = (struct i386_bus_dmamap *)mapstore;
+ map->_dm_size = size;
+ map->_dm_segcnt = nsegments;
+ map->_dm_maxsegsz = maxsegsz;
+ map->_dm_boundary = boundary;
+ map->_dm_flags = flags & ~(BUS_DMA_WAITOK|BUS_DMA_NOWAIT);
+ map->dm_nsegs = 0; /* no valid mappings */
+
+ *dmamp = map;
+ return (0);
+}
+
+/*
+ * Common function for DMA map destruction. May be called by bus-specific
+ * DMA map destruction functions.
+ */
+void
+_bus_dmamap_destroy(t, map)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+{
+
+ free(map, M_DEVBUF);
+}
+
+/*
+ * Common function for loading a DMA map with a linear buffer. May
+ * be called by bus-specific DMA map load functions.
+ */
+int
+_bus_dmamap_load(t, map, buf, buflen, p, flags)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+ void *buf;
+ bus_size_t buflen;
+ struct proc *p;
+ int flags;
+{
+ bus_size_t sgsize;
+ bus_addr_t curaddr, lastaddr;
+ caddr_t vaddr = buf;
+ int first, seg;
+ pmap_t pmap;
+
+ /*
+ * Make sure that on error condition we return "no valid mappings".
+ */
+ map->dm_nsegs = 0;
+
+ if (buflen > map->_dm_size)
+ return (EINVAL);
+
+ /*
+ * XXX Need to implement "don't dma across this boundry".
+ */
+
+ if (p != NULL)
+ pmap = p->p_vmspace->vm_map.pmap;
+ else
+ pmap = pmap_kernel();
+
+ lastaddr = ~0; /* XXX gcc */
+ for (first = 1, seg = 0; buflen > 0 && seg < map->_dm_segcnt; ) {
+ /*
+ * Get the physical address for this segment.
+ */
+ curaddr = (bus_addr_t)pmap_extract(pmap, (vm_offset_t)vaddr);
+
+ /*
+ * Compute the segment size, and adjust counts.
+ */
+ sgsize = NBPG - ((u_long)vaddr & PGOFSET);
+ if (buflen < sgsize)
+ sgsize = buflen;
+
+ /*
+ * Insert chunk into a segment, coalescing with
+ * previous segment if possible.
+ */
+ if (first) {
+ map->dm_segs[seg].ds_addr = curaddr;
+ map->dm_segs[seg].ds_len = sgsize;
+ first = 0;
+ } else {
+ if (curaddr == lastaddr &&
+ (map->dm_segs[seg].ds_len + sgsize) <=
+ map->_dm_maxsegsz)
+ map->dm_segs[seg].ds_len += sgsize;
+ else {
+ seg++;
+ map->dm_segs[seg].ds_addr = curaddr;
+ map->dm_segs[seg].ds_len = sgsize;
+ }
+ }
+
+ lastaddr = curaddr + sgsize;
+ vaddr += sgsize;
+ buflen -= sgsize;
+ }
+
+ /*
+ * Did we fit?
+ */
+ if (buflen != 0)
+ return (EFBIG); /* XXX better return value here? */
+
+ map->dm_nsegs = seg + 1;
+ return (0);
+}
+
+/*
+ * Like _bus_dmamap_load(), but for mbufs.
+ */
+int
+_bus_dmamap_load_mbuf(t, map, m, flags)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+ struct mbuf *m;
+ int flags;
+{
+
+ panic("_bus_dmamap_load: not implemented");
+}
+
+/*
+ * Like _bus_dmamap_load(), but for uios.
+ */
+int
+_bus_dmamap_load_uio(t, map, uio, flags)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+ struct uio *uio;
+ int flags;
+{
+
+ panic("_bus_dmamap_load_uio: not implemented");
+}
+
+/*
+ * Like _bus_dmamap_load(), but for raw memory allocated with
+ * bus_dmamem_alloc().
+ */
+int
+_bus_dmamap_load_raw(t, map, segs, nsegs, size, flags)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+ bus_dma_segment_t *segs;
+ int nsegs;
+ bus_size_t size;
+ int flags;
+{
+
+ panic("_bus_dmamap_load_raw: not implemented");
+}
+
+/*
+ * Common function for unloading a DMA map. May be called by
+ * bus-specific DMA map unload functions.
+ */
+void
+_bus_dmamap_unload(t, map)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+{
+
+ /*
+ * No resources to free; just mark the mappings as
+ * invalid.
+ */
+ map->dm_nsegs = 0;
+}
+
+/*
+ * Common function for DMA map synchronization. May be called
+ * by bus-specific DMA map synchronization functions.
+ */
+void
+_bus_dmamap_sync(t, map, op)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+ bus_dmasync_op_t op;
+{
+
+ /* Nothing to do here. */
+}
+
+/*
+ * Common function for DMA-safe memory allocation. May be called
+ * by bus-specific DMA memory allocation functions.
+ */
+int
+_bus_dmamem_alloc(t, size, alignment, boundary, segs, nsegs, rsegs, flags)
+ bus_dma_tag_t t;
+ bus_size_t size, alignment, boundary;
+ bus_dma_segment_t *segs;
+ int nsegs;
+ int *rsegs;
+ int flags;
+{
+
+ return (_bus_dmamem_alloc_range(t, size, alignment, boundary,
+ segs, nsegs, rsegs, flags, 0, trunc_page(avail_end)));
+}
+
+/*
+ * Common function for freeing DMA-safe memory. May be called by
+ * bus-specific DMA memory free functions.
+ */
+void
+_bus_dmamem_free(t, segs, nsegs)
+ bus_dma_tag_t t;
+ bus_dma_segment_t *segs;
+ int nsegs;
+{
+ vm_page_t m;
+ bus_addr_t addr;
+ struct pglist mlist;
+ int curseg;
+
+ /*
+ * Build a list of pages to free back to the VM system.
+ */
+ TAILQ_INIT(&mlist);
+ for (curseg = 0; curseg < nsegs; curseg++) {
+ for (addr = segs[curseg].ds_addr;
+ addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
+ addr += PAGE_SIZE) {
+ m = PHYS_TO_VM_PAGE(addr);
+ TAILQ_INSERT_TAIL(&mlist, m, pageq);
+ }
+ }
+
+ vm_page_free_memory(&mlist);
+}
+
+/*
+ * Common function for mapping DMA-safe memory. May be called by
+ * bus-specific DMA memory map functions.
+ */
+int
+_bus_dmamem_map(t, segs, nsegs, size, kvap, flags)
+ bus_dma_tag_t t;
+ bus_dma_segment_t *segs;
+ int nsegs;
+ size_t size;
+ caddr_t *kvap;
+ int flags;
+{
+ vm_offset_t va;
+ bus_addr_t addr;
+ int curseg;
+
+ size = round_page(size);
+ va = kmem_alloc_pageable(kmem_map, size);
+ if (va == 0)
+ return (ENOMEM);
+
+ *kvap = (caddr_t)va;
+
+ for (curseg = 0; curseg < nsegs; curseg++) {
+ for (addr = segs[curseg].ds_addr;
+ addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
+ addr += NBPG, va += NBPG, size -= NBPG) {
+ if (size == 0)
+ panic("_bus_dmamem_map: size botch");
+ pmap_enter(pmap_kernel(), va, addr,
+ VM_PROT_READ | VM_PROT_WRITE, TRUE);
+#if 0
+ if (flags & BUS_DMAMEM_NOSYNC)
+ pmap_changebit(addr, PG_N, ~0);
+ else
+ pmap_changebit(addr, 0, ~PG_N);
+#endif
+ }
+ }
+
+ return (0);
+}
+
+/*
+ * Common function for unmapping DMA-safe memory. May be called by
+ * bus-specific DMA memory unmapping functions.
+ */
+void
+_bus_dmamem_unmap(t, kva, size)
+ bus_dma_tag_t t;
+ caddr_t kva;
+ size_t size;
+{
+
+#ifdef DIAGNOSTIC
+ if ((u_long)kva & PGOFSET)
+ panic("_bus_dmamem_unmap");
+#endif
+
+ size = round_page(size);
+ kmem_free(kmem_map, (vm_offset_t)kva, size);
+}
+
+/*
+ * Common functin for mmap(2)'ing DMA-safe memory. May be called by
+ * bus-specific DMA mmap(2)'ing functions.
+ */
+int
+_bus_dmamem_mmap(t, segs, nsegs, off, prot, flags)
+ bus_dma_tag_t t;
+ bus_dma_segment_t *segs;
+ int nsegs, off, prot, flags;
+{
+
+ panic("_bus_dmamem_mmap: not implemented");
+}
+
+/**********************************************************************
+ * DMA utility functions
+ **********************************************************************/
+
+/*
+ * Allocate physical memory from the given physical address range.
+ * Called by DMA-safe memory allocation methods.
+ */
+int
+_bus_dmamem_alloc_range(t, size, alignment, boundary, segs, nsegs, rsegs,
+ flags, low, high)
+ bus_dma_tag_t t;
+ bus_size_t size, alignment, boundary;
+ bus_dma_segment_t *segs;
+ int nsegs;
+ int *rsegs;
+ int flags;
+ vm_offset_t low;
+ vm_offset_t high;
+{
+ vm_offset_t curaddr, lastaddr;
+ vm_page_t m;
+ struct pglist mlist;
+ int curseg, error;
+
+ /* Always round the size. */
+ size = round_page(size);
+
+ /*
+ * Allocate pages from the VM system.
+ */
+ TAILQ_INIT(&mlist);
+ error = vm_page_alloc_memory(size, low, high,
+ alignment, boundary, &mlist, nsegs, (flags & BUS_DMA_NOWAIT) == 0);
+ if (error)
+ return (error);
+
+ /*
+ * Compute the location, size, and number of segments actually
+ * returned by the VM code.
+ */
+ m = mlist.tqh_first;
+ curseg = 0;
+ lastaddr = segs[curseg].ds_addr = VM_PAGE_TO_PHYS(m);
+ segs[curseg].ds_len = PAGE_SIZE;
+ m = m->pageq.tqe_next;
+
+ for (; m != NULL; m = m->pageq.tqe_next) {
+ curaddr = VM_PAGE_TO_PHYS(m);
+#ifdef DIAGNOSTIC
+ if (curaddr < low || curaddr >= high) {
+ printf("vm_page_alloc_memory returned non-sensical"
+ " address 0x%lx\n", curaddr);
+ panic("_bus_dmamem_alloc_range");
+ }
+#endif
+ if (curaddr == (lastaddr + PAGE_SIZE))
+ segs[curseg].ds_len += PAGE_SIZE;
+ else {
+ curseg++;
+ segs[curseg].ds_addr = curaddr;
+ segs[curseg].ds_len = PAGE_SIZE;
+ }
+ lastaddr = curaddr;
+ }
+
+ *rsegs = curseg + 1;
+
+ return (0);
+}
diff --git a/sys/arch/i386/i386/mainbus.c b/sys/arch/i386/i386/mainbus.c
index 384c7ffc7d6..fe240425ea4 100644
--- a/sys/arch/i386/i386/mainbus.c
+++ b/sys/arch/i386/i386/mainbus.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: mainbus.c,v 1.12 1997/12/25 06:09:52 downsj Exp $ */
-/* $NetBSD: mainbus.c,v 1.8 1996/04/11 22:13:37 cgd Exp $ */
+/* $OpenBSD: mainbus.c,v 1.13 1998/01/20 18:40:15 niklas Exp $ */
+/* $NetBSD: mainbus.c,v 1.21 1997/06/06 23:14:20 thorpej Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
@@ -45,6 +45,8 @@
#include <i386/isa/isa_machdep.h>
#include "pci.h"
+#include "eisa.h"
+#include "isa.h"
#include "apm.h"
#include "bios.h"
@@ -125,6 +127,7 @@ mainbus_attach(parent, self, aux)
mba.mba_pba.pba_busname = "pci";
mba.mba_pba.pba_iot = I386_BUS_SPACE_IO;
mba.mba_pba.pba_memt = I386_BUS_SPACE_MEM;
+ mba.mba_pba.pba_dmat = &pci_bus_dma_tag;
mba.mba_pba.pba_bus = 0;
config_found(self, &mba.mba_pba, mainbus_print);
}
@@ -134,6 +137,9 @@ mainbus_attach(parent, self, aux)
mba.mba_eba.eba_busname = "eisa";
mba.mba_eba.eba_iot = I386_BUS_SPACE_IO;
mba.mba_eba.eba_memt = I386_BUS_SPACE_MEM;
+#if NEISA > 0
+ mba.mba_eba.eba_dmat = &eisa_bus_dma_tag;
+#endif
config_found(self, &mba.mba_eba, mainbus_print);
}
@@ -141,6 +147,9 @@ mainbus_attach(parent, self, aux)
mba.mba_iba.iba_busname = "isa";
mba.mba_iba.iba_iot = I386_BUS_SPACE_IO;
mba.mba_iba.iba_memt = I386_BUS_SPACE_MEM;
+#if NISA > 0
+ mba.mba_iba.iba_dmat = &isa_bus_dma_tag;
+#endif
config_found(self, &mba.mba_iba, mainbus_print);
}
}
diff --git a/sys/arch/i386/i386/pmap.c b/sys/arch/i386/i386/pmap.c
index 890b6dbfdbf..bf773284dde 100644
--- a/sys/arch/i386/i386/pmap.c
+++ b/sys/arch/i386/i386/pmap.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pmap.c,v 1.22 1997/10/25 06:57:59 niklas Exp $ */
+/* $OpenBSD: pmap.c,v 1.23 1998/01/20 18:40:15 niklas Exp $ */
/* $NetBSD: pmap.c,v 1.36 1996/05/03 19:42:22 christos Exp $ */
/*
@@ -287,20 +287,6 @@ pmap_bootstrap(virtual_start)
*/
virtual_avail = reserve_dumppages(virtual_avail);
- /*
- * reserve special hunk of memory for use by bus dma as a bounce
- * buffer (contiguous virtual *and* physical memory). XXX
- */
-#if NISA > 0 && NISADMA > 0
- if (ctob(physmem) >= 0x1000000) {
- isaphysmem = pmap_steal_memory(DMA_BOUNCE * NBPG);
- isaphysmempgs = DMA_BOUNCE;
- } else {
- isaphysmem = pmap_steal_memory(DMA_BOUNCE_LOW * NBPG);
- isaphysmempgs = DMA_BOUNCE_LOW;
- }
-#endif
-
/* flawed, no mappings?? */
if (ctob(physmem) > 31*1024*1024 && MAXKPDE != NKPDE) {
vm_offset_t p;
diff --git a/sys/arch/i386/i386/pmap.old.c b/sys/arch/i386/i386/pmap.old.c
index 9ede2c1ca21..fc10b16125b 100644
--- a/sys/arch/i386/i386/pmap.old.c
+++ b/sys/arch/i386/i386/pmap.old.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: pmap.old.c,v 1.22 1997/10/25 06:57:59 niklas Exp $ */
+/* $OpenBSD: pmap.old.c,v 1.23 1998/01/20 18:40:15 niklas Exp $ */
/* $NetBSD: pmap.c,v 1.36 1996/05/03 19:42:22 christos Exp $ */
/*
@@ -287,20 +287,6 @@ pmap_bootstrap(virtual_start)
*/
virtual_avail = reserve_dumppages(virtual_avail);
- /*
- * reserve special hunk of memory for use by bus dma as a bounce
- * buffer (contiguous virtual *and* physical memory). XXX
- */
-#if NISA > 0 && NISADMA > 0
- if (ctob(physmem) >= 0x1000000) {
- isaphysmem = pmap_steal_memory(DMA_BOUNCE * NBPG);
- isaphysmempgs = DMA_BOUNCE;
- } else {
- isaphysmem = pmap_steal_memory(DMA_BOUNCE_LOW * NBPG);
- isaphysmempgs = DMA_BOUNCE_LOW;
- }
-#endif
-
/* flawed, no mappings?? */
if (ctob(physmem) > 31*1024*1024 && MAXKPDE != NKPDE) {
vm_offset_t p;
diff --git a/sys/arch/i386/include/bus.h b/sys/arch/i386/include/bus.h
index 48d8bd81201..15c457b6c90 100644
--- a/sys/arch/i386/include/bus.h
+++ b/sys/arch/i386/include/bus.h
@@ -1,6 +1,43 @@
-/* $OpenBSD: bus.h,v 1.9 1998/01/17 09:58:39 niklas Exp $ */
+/* $OpenBSD: bus.h,v 1.10 1998/01/20 18:40:17 niklas Exp $ */
/* $NetBSD: bus.h,v 1.6 1996/11/10 03:19:25 thorpej Exp $ */
+/*-
+ * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
/*
* Copyright (c) 1996 Charles M. Hannum. All rights reserved.
* Copyright (c) 1996 Jason R. Thorpe. All rights reserved.
@@ -697,4 +734,175 @@ void bus_space_free __P((bus_space_tag_t t, bus_space_handle_t bsh,
#define BUS_BARRIER_READ 0x01 /* force read barrier */
#define BUS_BARRIER_WRITE 0x02 /* force write barrier */
+/*
+ * Flags used in various bus DMA methods.
+ */
+#define BUS_DMA_WAITOK 0x00 /* safe to sleep (pseudo-flag) */
+#define BUS_DMA_NOWAIT 0x01 /* not safe to sleep */
+#define BUS_DMA_ALLOCNOW 0x02 /* perform resource allocation now */
+#define BUS_DMAMEM_NOSYNC 0x04 /* map memory to not require sync */
+#define BUS_DMA_BUS1 0x10 /* placeholders for bus functions... */
+#define BUS_DMA_BUS2 0x20
+#define BUS_DMA_BUS3 0x40
+#define BUS_DMA_BUS4 0x80
+
+/* Forwards needed by prototypes below. */
+struct mbuf;
+struct uio;
+
+/*
+ * bus_dmasync_op_t
+ *
+ * Operations performed by bus_dmamap_sync().
+ */
+typedef enum {
+ BUS_DMASYNC_PREREAD,
+ BUS_DMASYNC_POSTREAD,
+ BUS_DMASYNC_PREWRITE,
+ BUS_DMASYNC_POSTWRITE,
+} bus_dmasync_op_t;
+
+typedef struct i386_bus_dma_tag *bus_dma_tag_t;
+typedef struct i386_bus_dmamap *bus_dmamap_t;
+
+/*
+ * bus_dma_segment_t
+ *
+ * Describes a single contiguous DMA transaction. Values
+ * are suitable for programming into DMA registers.
+ */
+struct i386_bus_dma_segment {
+ bus_addr_t ds_addr; /* DMA address */
+ bus_size_t ds_len; /* length of transfer */
+};
+typedef struct i386_bus_dma_segment bus_dma_segment_t;
+
+/*
+ * bus_dma_tag_t
+ *
+ * A machine-dependent opaque type describing the implementation of
+ * DMA for a given bus.
+ */
+
+struct i386_bus_dma_tag {
+ void *_cookie; /* cookie used in the guts */
+
+ /*
+ * DMA mapping methods.
+ */
+ int (*_dmamap_create) __P((bus_dma_tag_t, bus_size_t, int,
+ bus_size_t, bus_size_t, int, bus_dmamap_t *));
+ void (*_dmamap_destroy) __P((bus_dma_tag_t, bus_dmamap_t));
+ int (*_dmamap_load) __P((bus_dma_tag_t, bus_dmamap_t, void *,
+ bus_size_t, struct proc *, int));
+ int (*_dmamap_load_mbuf) __P((bus_dma_tag_t, bus_dmamap_t,
+ struct mbuf *, int));
+ int (*_dmamap_load_uio) __P((bus_dma_tag_t, bus_dmamap_t,
+ struct uio *, int));
+ int (*_dmamap_load_raw) __P((bus_dma_tag_t, bus_dmamap_t,
+ bus_dma_segment_t *, int, bus_size_t, int));
+ void (*_dmamap_unload) __P((bus_dma_tag_t, bus_dmamap_t));
+ void (*_dmamap_sync) __P((bus_dma_tag_t, bus_dmamap_t,
+ bus_dmasync_op_t));
+
+ /*
+ * DMA memory utility functions.
+ */
+ int (*_dmamem_alloc) __P((bus_dma_tag_t, bus_size_t, bus_size_t,
+ bus_size_t, bus_dma_segment_t *, int, int *, int));
+ void (*_dmamem_free) __P((bus_dma_tag_t,
+ bus_dma_segment_t *, int));
+ int (*_dmamem_map) __P((bus_dma_tag_t, bus_dma_segment_t *,
+ int, size_t, caddr_t *, int));
+ void (*_dmamem_unmap) __P((bus_dma_tag_t, caddr_t, size_t));
+ int (*_dmamem_mmap) __P((bus_dma_tag_t, bus_dma_segment_t *,
+ int, int, int, int));
+};
+
+#define bus_dmamap_create(t, s, n, m, b, f, p) \
+ (*(t)->_dmamap_create)((t), (s), (n), (m), (b), (f), (p))
+#define bus_dmamap_destroy(t, p) \
+ (*(t)->_dmamap_destroy)((t), (p))
+#define bus_dmamap_load(t, m, b, s, p, f) \
+ (*(t)->_dmamap_load)((t), (m), (b), (s), (p), (f))
+#define bus_dmamap_load_mbuf(t, m, b, f) \
+ (*(t)->_dmamap_load_mbuf)((t), (m), (b), (f))
+#define bus_dmamap_load_uio(t, m, u, f) \
+ (*(t)->_dmamap_load_uio)((t), (m), (u), (f))
+#define bus_dmamap_load_raw(t, m, sg, n, s, f) \
+ (*(t)->_dmamap_load_raw)((t), (m), (sg), (n), (s), (f))
+#define bus_dmamap_unload(t, p) \
+ (*(t)->_dmamap_unload)((t), (p))
+#define bus_dmamap_sync(t, p, o) \
+ (void)((t)->_dmamap_sync ? \
+ (*(t)->_dmamap_sync)((t), (p), (o)) : (void)0)
+
+#define bus_dmamem_alloc(t, s, a, b, sg, n, r, f) \
+ (*(t)->_dmamem_alloc)((t), (s), (a), (b), (sg), (n), (r), (f))
+#define bus_dmamem_free(t, sg, n) \
+ (*(t)->_dmamem_free)((t), (sg), (n))
+#define bus_dmamem_map(t, sg, n, s, k, f) \
+ (*(t)->_dmamem_map)((t), (sg), (n), (s), (k), (f))
+#define bus_dmamem_unmap(t, k, s) \
+ (*(t)->_dmamem_unmap)((t), (k), (s))
+#define bus_dmamem_mmap(t, sg, n, o, p, f) \
+ (*(t)->_dmamem_mmap)((t), (sg), (n), (o), (p), (f))
+
+/*
+ * bus_dmamap_t
+ *
+ * Describes a DMA mapping.
+ */
+struct i386_bus_dmamap {
+ /*
+ * PRIVATE MEMBERS: not for use my machine-independent code.
+ */
+ bus_size_t _dm_size; /* largest DMA transfer mappable */
+ int _dm_segcnt; /* number of segs this map can map */
+ bus_size_t _dm_maxsegsz; /* largest possible segment */
+ bus_size_t _dm_boundary; /* don't cross this */
+ int _dm_flags; /* misc. flags */
+
+ void *_dm_cookie; /* cookie for bus-specific functions */
+
+ /*
+ * PUBLIC MEMBERS: these are used by machine-independent code.
+ */
+ int dm_nsegs; /* # valid segments in mapping */
+ bus_dma_segment_t dm_segs[1]; /* segments; variable length */
+};
+
+#ifdef _I386_BUS_DMA_PRIVATE
+int _bus_dmamap_create __P((bus_dma_tag_t, bus_size_t, int, bus_size_t,
+ bus_size_t, int, bus_dmamap_t *));
+void _bus_dmamap_destroy __P((bus_dma_tag_t, bus_dmamap_t));
+int _bus_dmamap_load __P((bus_dma_tag_t, bus_dmamap_t, void *,
+ bus_size_t, struct proc *, int));
+int _bus_dmamap_load_mbuf __P((bus_dma_tag_t, bus_dmamap_t,
+ struct mbuf *, int));
+int _bus_dmamap_load_uio __P((bus_dma_tag_t, bus_dmamap_t,
+ struct uio *, int));
+int _bus_dmamap_load_raw __P((bus_dma_tag_t, bus_dmamap_t,
+ bus_dma_segment_t *, int, bus_size_t, int));
+void _bus_dmamap_unload __P((bus_dma_tag_t, bus_dmamap_t));
+void _bus_dmamap_sync __P((bus_dma_tag_t, bus_dmamap_t, bus_dmasync_op_t));
+
+int _bus_dmamem_alloc __P((bus_dma_tag_t tag, bus_size_t size,
+ bus_size_t alignment, bus_size_t boundary,
+ bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags));
+void _bus_dmamem_free __P((bus_dma_tag_t tag, bus_dma_segment_t *segs,
+ int nsegs));
+int _bus_dmamem_map __P((bus_dma_tag_t tag, bus_dma_segment_t *segs,
+ int nsegs, size_t size, caddr_t *kvap, int flags));
+void _bus_dmamem_unmap __P((bus_dma_tag_t tag, caddr_t kva,
+ size_t size));
+int _bus_dmamem_mmap __P((bus_dma_tag_t tag, bus_dma_segment_t *segs,
+ int nsegs, int off, int prot, int flags));
+
+int _bus_dmamem_alloc_range __P((bus_dma_tag_t tag, bus_size_t size,
+ bus_size_t alignment, bus_size_t boundary,
+ bus_dma_segment_t *segs, int nsegs, int *rsegs, int flags,
+ vm_offset_t low, vm_offset_t high));
+#endif /* _I386_BUS_DMA_PRIVATE */
+
#endif /* _I386_BUS_H_ */
diff --git a/sys/arch/i386/isa/isa_machdep.c b/sys/arch/i386/isa/isa_machdep.c
index de30e9e4e32..c907f63e7d5 100644
--- a/sys/arch/i386/isa/isa_machdep.c
+++ b/sys/arch/i386/isa/isa_machdep.c
@@ -1,5 +1,44 @@
-/* $OpenBSD: isa_machdep.c,v 1.26 1997/12/25 12:49:04 downsj Exp $ */
-/* $NetBSD: isa_machdep.c,v 1.14 1996/05/12 23:06:18 mycroft Exp $ */
+/* $OpenBSD: isa_machdep.c,v 1.27 1998/01/20 18:40:20 niklas Exp $ */
+/* $NetBSD: isa_machdep.c,v 1.22 1997/06/12 23:57:32 thorpej Exp $ */
+
+#define ISA_DMA_STATS
+
+/*-
+ * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
/*-
* Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
@@ -87,6 +126,9 @@
#include <vm/vm.h>
+#define _I386_BUS_DMA_PRIVATE
+#include <machine/bus.h>
+
#include <machine/pio.h>
#include <machine/cpufunc.h>
@@ -96,6 +138,17 @@
#include <i386/isa/isa_machdep.h>
#include <i386/isa/icu.h>
+#include <vm/vm.h>
+
+#include "isadma.h"
+
+/*
+ * ISA can only DMA to 0-16M.
+ */
+#define ISA_DMA_BOUNCE_THRESHOLD 0x00ffffff
+
+extern vm_offset_t avail_end;
+
#define IDTVEC(name) __CONCAT(X,name)
/* default interrupt vector table entries */
typedef (*vector) __P((void));
@@ -104,13 +157,63 @@ void isa_strayintr __P((int));
void intr_calculatemasks __P((void));
int fakeintr __P((void *));
-vm_offset_t bounce_alloc __P((vm_size_t, vm_offset_t, int));
-caddr_t bounce_vaddr __P((vm_offset_t));
-void bounce_free __P((vm_offset_t, vm_size_t));
-void isadma_copyfrombuf __P((caddr_t, vm_size_t, int, struct isadma_seg *));
+#if NISADMA > 0
+int _isa_bus_dmamap_create __P((bus_dma_tag_t, bus_size_t, int,
+ bus_size_t, bus_size_t, int, bus_dmamap_t *));
+void _isa_bus_dmamap_destroy __P((bus_dma_tag_t, bus_dmamap_t));
+int _isa_bus_dmamap_load __P((bus_dma_tag_t, bus_dmamap_t, void *,
+ bus_size_t, struct proc *, int));
+int _isa_bus_dmamap_load_mbuf __P((bus_dma_tag_t, bus_dmamap_t,
+ struct mbuf *, int));
+int _isa_bus_dmamap_load_uio __P((bus_dma_tag_t, bus_dmamap_t,
+ struct uio *, int));
+int _isa_bus_dmamap_load_raw __P((bus_dma_tag_t, bus_dmamap_t,
+ bus_dma_segment_t *, int, bus_size_t, int));
+void _isa_bus_dmamap_unload __P((bus_dma_tag_t, bus_dmamap_t));
+void _isa_bus_dmamap_sync __P((bus_dma_tag_t, bus_dmamap_t,
+ bus_dmasync_op_t));
+
+int _isa_bus_dmamem_alloc __P((bus_dma_tag_t, bus_size_t, bus_size_t,
+ bus_size_t, bus_dma_segment_t *, int, int *, int));
+void _isa_bus_dmamem_free __P((bus_dma_tag_t,
+ bus_dma_segment_t *, int));
+int _isa_bus_dmamem_map __P((bus_dma_tag_t, bus_dma_segment_t *,
+ int, size_t, caddr_t *, int));
+void _isa_bus_dmamem_unmap __P((bus_dma_tag_t, caddr_t, size_t));
+int _isa_bus_dmamem_mmap __P((bus_dma_tag_t, bus_dma_segment_t *,
+ int, int, int, int));
+
+int _isa_dma_check_buffer __P((void *, bus_size_t, int, bus_size_t,
+ struct proc *));
+int _isa_dma_alloc_bouncebuf __P((bus_dma_tag_t, bus_dmamap_t,
+ bus_size_t, int));
+void _isa_dma_free_bouncebuf __P((bus_dma_tag_t, bus_dmamap_t));
/*
- * Fill in default interrupt table (in case of spuruious interrupt
+ * Entry points for ISA DMA. These are mostly wrappers around
+ * the generic functions that understand how to deal with bounce
+ * buffers, if necessary.
+ */
+struct i386_bus_dma_tag isa_bus_dma_tag = {
+ NULL, /* _cookie */
+ _isa_bus_dmamap_create,
+ _isa_bus_dmamap_destroy,
+ _isa_bus_dmamap_load,
+ _isa_bus_dmamap_load_mbuf,
+ _isa_bus_dmamap_load_uio,
+ _isa_bus_dmamap_load_raw,
+ _isa_bus_dmamap_unload,
+ _isa_bus_dmamap_sync,
+ _isa_bus_dmamem_alloc,
+ _isa_bus_dmamem_free,
+ _isa_bus_dmamem_map,
+ _isa_bus_dmamem_unmap,
+ _isa_bus_dmamem_mmap,
+};
+#endif /* NISADMA > 0 */
+
+/*
+ * Fill in default interrupt table (in case of spurious interrupt
* during configuration of kernel, setup interrupt control unit
*/
void
@@ -465,167 +568,533 @@ isa_attach_hook(parent, self, iba)
isa_has_been_seen = 1;
}
+#if NISADMA > 0
+/**********************************************************************
+ * bus.h dma interface entry points
+ **********************************************************************/
+
+#ifdef ISA_DMA_STATS
+#define STAT_INCR(v) (v)++
+#define STAT_DECR(v) do { \
+ if ((v) == 0) \
+ printf("%s:%d -- Already 0!\n", __FILE__, __LINE__); \
+ else \
+ (v)--; \
+ } while (0)
+u_long isa_dma_stats_loads;
+u_long isa_dma_stats_bounces;
+u_long isa_dma_stats_nbouncebufs;
+#else
+#define STAT_INCR(v)
+#define STAT_DECR(v)
+#endif
+
/*
- * ISA DMA and bounce buffer management
+ * Create an ISA DMA map.
*/
+int
+_isa_bus_dmamap_create(t, size, nsegments, maxsegsz, boundary, flags, dmamp)
+ bus_dma_tag_t t;
+ bus_size_t size;
+ int nsegments;
+ bus_size_t maxsegsz;
+ bus_size_t boundary;
+ int flags;
+ bus_dmamap_t *dmamp;
+{
+ struct i386_isa_dma_cookie *cookie;
+ bus_dmamap_t map;
+ int error, cookieflags;
+ void *cookiestore;
+ size_t cookiesize;
-#define MAX_CHUNK 256 /* number of low memory segments */
+ /* Call common function to create the basic map. */
+ error = _bus_dmamap_create(t, size, nsegments, maxsegsz, boundary,
+ flags, dmamp);
+ if (error)
+ return (error);
-static u_int32_t bitmap[MAX_CHUNK / 32 + 1];
+ map = *dmamp;
+ map->_dm_cookie = NULL;
-#define set(i) (bitmap[(i) >> 5] |= (1 << (i)))
-#define clr(i) (bitmap[(i) >> 5] &= ~(1 << (i)))
-#define bit(i) ((bitmap[(i) >> 5] & (1 << (i))) != 0)
+ cookiesize = sizeof(struct i386_isa_dma_cookie);
-static int bit_ptr = -1; /* last segment visited */
-static int chunk_size = 0; /* size (bytes) of one low mem segment */
-static int chunk_num = 0; /* actual number of low mem segments */
-#ifdef DIAGNOSTIC
-int bounce_alloc_cur = 0;
-int bounce_alloc_max = 0;
-#endif
+ /*
+ * ISA only has 24-bits of address space. This means
+ * we can't DMA to pages over 16M. In order to DMA to
+ * arbitrary buffers, we use "bounce buffers" - pages
+ * in memory below the 16M boundary. On DMA reads,
+ * DMA happens to the bounce buffers, and is copied into
+ * the caller's buffer. On writes, data is copied into
+ * but bounce buffer, and the DMA happens from those
+ * pages. To software using the DMA mapping interface,
+ * this looks simply like a data cache.
+ *
+ * If we have more than 16M of RAM in the system, we may
+ * need bounce buffers. We check and remember that here.
+ *
+ * There are exceptions, however. VLB devices can do
+ * 32-bit DMA, and indicate that here.
+ *
+ * ...or, there is an opposite case. The most segments
+ * a transfer will require is (maxxfer / NBPG) + 1. If
+ * the caller can't handle that many segments (e.g. the
+ * ISA DMA controller), we may have to bounce it as well.
+ */
+ cookieflags = 0;
+ if ((avail_end > ISA_DMA_BOUNCE_THRESHOLD &&
+ (flags & ISABUS_DMA_32BIT) == 0) ||
+ ((map->_dm_size / NBPG) + 1) > map->_dm_segcnt) {
+ cookieflags |= ID_MIGHT_NEED_BOUNCE;
+ cookiesize += (sizeof(bus_dma_segment_t) * map->_dm_segcnt);
+ }
+
+ /*
+ * Allocate our cookie.
+ */
+ if ((cookiestore = malloc(cookiesize, M_DEVBUF,
+ (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL) {
+ error = ENOMEM;
+ goto out;
+ }
+ bzero(cookiestore, cookiesize);
+ cookie = (struct i386_isa_dma_cookie *)cookiestore;
+ cookie->id_flags = cookieflags;
+ map->_dm_cookie = cookie;
+
+ if (cookieflags & ID_MIGHT_NEED_BOUNCE) {
+ /*
+ * Allocate the bounce pages now if the caller
+ * wishes us to do so.
+ */
+ if ((flags & BUS_DMA_ALLOCNOW) == 0)
+ goto out;
+
+ error = _isa_dma_alloc_bouncebuf(t, map, size, flags);
+ }
-vm_offset_t isaphysmem; /* base address of low mem arena */
-int isaphysmempgs; /* number of pages of low mem arena */
+ out:
+ if (error) {
+ if (map->_dm_cookie != NULL)
+ free(map->_dm_cookie, M_DEVBUF);
+ _bus_dmamap_destroy(t, map);
+ }
+ return (error);
+}
/*
- * if addr is the physical address of an allocated bounce buffer return the
- * corresponding virtual address, 0 otherwise
+ * Destroy an ISA DMA map.
*/
+void
+_isa_bus_dmamap_destroy(t, map)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+{
+ struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
+ /*
+ * Free any bounce pages this map might hold.
+ */
+ if (cookie->id_flags & ID_HAS_BOUNCE)
+ _isa_dma_free_bouncebuf(t, map);
+
+ free(cookie, M_DEVBUF);
+ _bus_dmamap_destroy(t, map);
+}
-caddr_t
-bounce_vaddr(addr)
- vm_offset_t addr;
+/*
+ * Load an ISA DMA map with a linear buffer.
+ */
+int
+_isa_bus_dmamap_load(t, map, buf, buflen, p, flags)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+ void *buf;
+ bus_size_t buflen;
+ struct proc *p;
+ int flags;
{
- int i;
+ struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
+ int error;
+
+ STAT_INCR(isa_dma_stats_loads);
- if (addr < vtophys(isaphysmem) ||
- addr >= vtophys(isaphysmem + chunk_num*chunk_size) ||
- ((i = (int)(addr-vtophys(isaphysmem))) % chunk_size) != 0 ||
- bit(i/chunk_size))
- return(0);
+ /*
+ * Check to see if we might need to bounce the transfer.
+ */
+ if (cookie->id_flags & ID_MIGHT_NEED_BOUNCE) {
+ /*
+ * Check if all pages are below the bounce
+ * threshold. If they are, don't bother bouncing.
+ */
+ if (_isa_dma_check_buffer(buf, buflen,
+ map->_dm_segcnt, map->_dm_boundary, p) == 0)
+ return (_bus_dmamap_load(t, map, buf, buflen,
+ p, flags));
+
+ STAT_INCR(isa_dma_stats_bounces);
+
+ /*
+ * Allocate bounce pages, if necessary.
+ */
+ if ((cookie->id_flags & ID_HAS_BOUNCE) == 0) {
+ error = _isa_dma_alloc_bouncebuf(t, map, buflen,
+ flags);
+ if (error)
+ return (error);
+ }
- return((caddr_t) (isaphysmem + (addr - vtophys(isaphysmem))));
+ /*
+ * Cache a pointer to the caller's buffer and
+ * load the DMA map with the bounce buffer.
+ */
+ cookie->id_origbuf = buf;
+ cookie->id_origbuflen = buflen;
+ error = _bus_dmamap_load(t, map, cookie->id_bouncebuf,
+ buflen, p, flags);
+
+ if (error) {
+ /*
+ * Free the bounce pages, unless our resources
+ * are reserved for our exclusive use.
+ */
+ if ((map->_dm_flags & BUS_DMA_ALLOCNOW) == 0)
+ _isa_dma_free_bouncebuf(t, map);
+ }
+
+ /* ...so _isa_bus_dmamap_sync() knows we're bouncing */
+ cookie->id_flags |= ID_IS_BOUNCING;
+ } else {
+ /*
+ * Just use the generic load function.
+ */
+ error = _bus_dmamap_load(t, map, buf, buflen, p, flags);
+ }
+
+ return (error);
}
/*
- * alloc a low mem segment of size nbytes. Alignment constraint is:
- * (addr & pmask) == ((addr+size-1) & pmask)
- * if waitok, call may wait for memory to become available.
- * returns 0 on failure
+ * Like _isa_bus_dmamap_load(), but for mbufs.
*/
+int
+_isa_bus_dmamap_load_mbuf(t, map, m, flags)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+ struct mbuf *m;
+ int flags;
+{
-vm_offset_t
-bounce_alloc(nbytes, pmask, waitok)
- vm_size_t nbytes;
- vm_offset_t pmask;
- int waitok;
+ panic("_isa_bus_dmamap_load_mbuf: not implemented");
+}
+
+/*
+ * Like _isa_bus_dmamap_load(), but for uios.
+ */
+int
+_isa_bus_dmamap_load_uio(t, map, uio, flags)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+ struct uio *uio;
+ int flags;
{
- int i, l;
- vm_offset_t a, b, c, r;
- vm_size_t n;
- int nunits, opri;
-
- opri = splbio();
-
- if (bit_ptr < 0) { /* initialize low mem arena */
- if ((chunk_size = isaphysmempgs*NBPG/MAX_CHUNK) & 1)
- chunk_size--;
- chunk_num = (isaphysmempgs*NBPG) / chunk_size;
- for(i = 0; i < chunk_num; i++)
- set(i);
- bit_ptr = 0;
- }
- nunits = (nbytes+chunk_size-1)/chunk_size;
+ panic("_isa_bus_dmamap_load_uio: not implemented");
+}
+
+/*
+ * Like _isa_bus_dmamap_load(), but for raw memory allocated with
+ * bus_dmamem_alloc().
+ */
+int
+_isa_bus_dmamap_load_raw(t, map, segs, nsegs, size, flags)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+ bus_dma_segment_t *segs;
+ int nsegs;
+ bus_size_t size;
+ int flags;
+{
+
+ panic("_isa_bus_dmamap_load_raw: not implemented");
+}
+
+/*
+ * Unload an ISA DMA map.
+ */
+void
+_isa_bus_dmamap_unload(t, map)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+{
+ struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
+
+ /*
+ * If we have bounce pages, free them, unless they're
+ * reserved for our exclusive use.
+ */
+ if ((cookie->id_flags & ID_HAS_BOUNCE) &&
+ (map->_dm_flags & BUS_DMA_ALLOCNOW) == 0)
+ _isa_dma_free_bouncebuf(t, map);
+
+ cookie->id_flags &= ~ID_IS_BOUNCING;
/*
- * set a=start, b=start with address constraints, c=end
- * check if this request may ever succeed.
+ * Do the generic bits of the unload.
*/
+ _bus_dmamap_unload(t, map);
+}
- a = isaphysmem;
- b = (isaphysmem + ~pmask) & pmask;
- c = isaphysmem + chunk_num*chunk_size;
- n = nunits*chunk_size;
- if (a + n >= c || (pmask != 0 && a + n >= b && b + n >= c)) {
- splx(opri);
- return(0);
+/*
+ * Synchronize an ISA DMA map.
+ */
+void
+_isa_bus_dmamap_sync(t, map, op)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+ bus_dmasync_op_t op;
+{
+ struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
+
+ switch (op) {
+ case BUS_DMASYNC_PREREAD:
+ /*
+ * Nothing to do for pre-read.
+ */
+ break;
+
+ case BUS_DMASYNC_PREWRITE:
+ /*
+ * If we're bouncing this transfer, copy the
+ * caller's buffer to the bounce buffer.
+ */
+ if (cookie->id_flags & ID_IS_BOUNCING)
+ bcopy(cookie->id_origbuf, cookie->id_bouncebuf,
+ cookie->id_origbuflen);
+ break;
+
+ case BUS_DMASYNC_POSTREAD:
+ /*
+ * If we're bouncing this transfer, copy the
+ * bounce buffer to the caller's buffer.
+ */
+ if (cookie->id_flags & ID_IS_BOUNCING)
+ bcopy(cookie->id_bouncebuf, cookie->id_origbuf,
+ cookie->id_origbuflen);
+ break;
+
+ case BUS_DMASYNC_POSTWRITE:
+ /*
+ * Nothing to do for post-write.
+ */
+ break;
}
- for (;;) {
- i = bit_ptr;
- l = -1;
- do{
- if (bit(i) && l >= 0 && (i - l + 1) >= nunits){
- r = vtophys(isaphysmem + (i - nunits + 1)*chunk_size);
- if (((r ^ (r + nbytes - 1)) & pmask) == 0) {
- for (l = i - nunits + 1; l <= i; l++)
- clr(l);
- bit_ptr = i;
-#ifdef DIAGNOSTIC
- bounce_alloc_cur += nunits*chunk_size;
- bounce_alloc_max = max(bounce_alloc_max,
- bounce_alloc_cur);
+#if 0
+ /* This is a noop anyhow, so why bother calling it? */
+ _bus_dmamap_sync(t, map, op);
#endif
- splx(opri);
- return(r);
- }
- } else if (bit(i) && l < 0)
- l = i;
- else if (!bit(i))
- l = -1;
- if (++i == chunk_num) {
- i = 0;
- l = -1;
- }
- } while(i != bit_ptr);
+}
- if (waitok)
- tsleep((caddr_t) &bit_ptr, PRIBIO, "physmem", 0);
- else {
- splx(opri);
- return(0);
- }
- }
+/*
+ * Allocate memory safe for ISA DMA.
+ */
+int
+_isa_bus_dmamem_alloc(t, size, alignment, boundary, segs, nsegs, rsegs, flags)
+ bus_dma_tag_t t;
+ bus_size_t size, alignment, boundary;
+ bus_dma_segment_t *segs;
+ int nsegs;
+ int *rsegs;
+ int flags;
+{
+ vm_offset_t high;
+
+ if (avail_end > ISA_DMA_BOUNCE_THRESHOLD)
+ high = trunc_page(ISA_DMA_BOUNCE_THRESHOLD);
+ else
+ high = trunc_page(avail_end);
+
+ return (_bus_dmamem_alloc_range(t, size, alignment, boundary,
+ segs, nsegs, rsegs, flags, 0, high));
+}
+
+/*
+ * Free memory safe for ISA DMA.
+ */
+void
+_isa_bus_dmamem_free(t, segs, nsegs)
+ bus_dma_tag_t t;
+ bus_dma_segment_t *segs;
+ int nsegs;
+{
+
+ _bus_dmamem_free(t, segs, nsegs);
}
-/*
- * return a segent of the low mem arena to the free pool
+/*
+ * Map ISA DMA-safe memory into kernel virtual address space.
*/
+int
+_isa_bus_dmamem_map(t, segs, nsegs, size, kvap, flags)
+ bus_dma_tag_t t;
+ bus_dma_segment_t *segs;
+ int nsegs;
+ size_t size;
+ caddr_t *kvap;
+ int flags;
+{
+
+ return (_bus_dmamem_map(t, segs, nsegs, size, kvap, flags));
+}
+/*
+ * Unmap ISA DMA-safe memory from kernel virtual address space.
+ */
void
-bounce_free(addr, nbytes)
- vm_offset_t addr;
- vm_size_t nbytes;
+_isa_bus_dmamem_unmap(t, kva, size)
+ bus_dma_tag_t t;
+ caddr_t kva;
+ size_t size;
+{
+
+ _bus_dmamem_unmap(t, kva, size);
+}
+
+/*
+ * mmap(2) ISA DMA-safe memory.
+ */
+int
+_isa_bus_dmamem_mmap(t, segs, nsegs, off, prot, flags)
+ bus_dma_tag_t t;
+ bus_dma_segment_t *segs;
+ int nsegs, off, prot, flags;
{
- int i, j, opri;
- vm_offset_t vaddr;
- opri = splbio();
+ return (_bus_dmamem_mmap(t, segs, nsegs, off, prot, flags));
+}
+
+/**********************************************************************
+ * ISA DMA utility functions
+ **********************************************************************/
- if ((vaddr = (vm_offset_t) bounce_vaddr(addr)) == 0)
- panic("bounce_free: bad address");
+/*
+ * Return 0 if all pages in the passed buffer lie within the DMA'able
+ * range RAM.
+ */
+int
+_isa_dma_check_buffer(buf, buflen, segcnt, boundary, p)
+ void *buf;
+ bus_size_t buflen;
+ int segcnt;
+ bus_size_t boundary;
+ struct proc *p;
+{
+ vm_offset_t vaddr = (vm_offset_t)buf;
+ vm_offset_t pa, lastpa, endva;
+ u_long pagemask = ~(boundary - 1);
+ pmap_t pmap;
+ int nsegs;
- i = (int) (vaddr - isaphysmem)/chunk_size;
- j = i + (nbytes + chunk_size - 1)/chunk_size;
+ endva = round_page(vaddr + buflen);
-#ifdef DIAGNOSTIC
- bounce_alloc_cur -= (j - i)*chunk_size;
-#endif
+ nsegs = 1;
+ lastpa = 0;
- while (i < j) {
- if (bit(i))
- panic("bounce_free: already free");
- set(i);
- i++;
+ if (p != NULL)
+ pmap = p->p_vmspace->vm_map.pmap;
+ else
+ pmap = pmap_kernel();
+
+ for (; vaddr < endva; vaddr += NBPG) {
+ /*
+ * Get physical address for this segment.
+ */
+ pa = pmap_extract(pmap, (vm_offset_t)vaddr);
+ pa = trunc_page(pa);
+
+ /*
+ * Is it below the DMA'able threshold?
+ */
+ if (pa > ISA_DMA_BOUNCE_THRESHOLD)
+ return (EINVAL);
+
+ if (lastpa) {
+ /*
+ * Check excessive segment count.
+ */
+ if (lastpa + NBPG != pa) {
+ if (++nsegs > segcnt)
+ return (EFBIG);
+ }
+
+ /*
+ * Check boundary restriction.
+ */
+ if (boundary) {
+ if ((lastpa ^ pa) & pagemask)
+ return (EINVAL);
+ }
+ }
+ lastpa = pa;
}
- wakeup((caddr_t) &bit_ptr);
- splx(opri);
+ return (0);
}
+int
+_isa_dma_alloc_bouncebuf(t, map, size, flags)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+ bus_size_t size;
+ int flags;
+{
+ struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
+ int error = 0;
+
+ cookie->id_bouncebuflen = round_page(size);
+ error = _isa_bus_dmamem_alloc(t, cookie->id_bouncebuflen,
+ NBPG, map->_dm_boundary, cookie->id_bouncesegs,
+ map->_dm_segcnt, &cookie->id_nbouncesegs, flags);
+ if (error)
+ goto out;
+ error = _isa_bus_dmamem_map(t, cookie->id_bouncesegs,
+ cookie->id_nbouncesegs, cookie->id_bouncebuflen,
+ (caddr_t *)&cookie->id_bouncebuf, flags);
+
+ out:
+ if (error) {
+ _isa_bus_dmamem_free(t, cookie->id_bouncesegs,
+ cookie->id_nbouncesegs);
+ cookie->id_bouncebuflen = 0;
+ cookie->id_nbouncesegs = 0;
+ } else {
+ cookie->id_flags |= ID_HAS_BOUNCE;
+ STAT_INCR(isa_dma_stats_nbouncebufs);
+ }
+
+ return (error);
+}
+
+void
+_isa_dma_free_bouncebuf(t, map)
+ bus_dma_tag_t t;
+ bus_dmamap_t map;
+{
+ struct i386_isa_dma_cookie *cookie = map->_dm_cookie;
+
+ STAT_DECR(isa_dma_stats_nbouncebufs);
+
+ _isa_bus_dmamem_unmap(t, cookie->id_bouncebuf,
+ cookie->id_bouncebuflen);
+ _isa_bus_dmamem_free(t, cookie->id_bouncesegs,
+ cookie->id_nbouncesegs);
+ cookie->id_bouncebuflen = 0;
+ cookie->id_nbouncesegs = 0;
+ cookie->id_flags &= ~ID_HAS_BOUNCE;
+}
+
+#ifdef __ISADMA_COMPAT
/*
* setup (addr, nbytes) for an ISA dma transfer.
* flags&ISADMA_MAP_WAITOK may wait
@@ -637,7 +1106,6 @@ bounce_free(addr, nbytes)
* returns the number of used phys entries, 0 on failure.
* if flags&ISADMA_MAP_CONTIG result is 1 on sucess!
*/
-
int
isadma_map(addr, nbytes, phys, flags)
caddr_t addr;
@@ -645,78 +1113,39 @@ isadma_map(addr, nbytes, phys, flags)
struct isadma_seg *phys;
int flags;
{
- vm_offset_t pmask, thiskv, thisphys, nextphys;
- vm_size_t datalen;
- int seg, waitok, i;
-
- if (flags & ISADMA_MAP_8BIT)
- pmask = ~((64*1024) - 1);
- else if (flags & ISADMA_MAP_16BIT)
- pmask = ~((128*1024) - 1);
- else
- pmask = 0;
-
- waitok = (flags & ISADMA_MAP_WAITOK) != 0;
-
- thiskv = (vm_offset_t) addr;
- datalen = nbytes;
- thisphys = vtophys(thiskv);
- seg = 0;
-
- while (datalen > 0 && (seg == 0 || (flags & ISADMA_MAP_CONTIG) == 0)) {
- phys[seg].length = 0;
- phys[seg].addr = thisphys;
-
- nextphys = thisphys;
- while (datalen > 0 && thisphys == nextphys) {
- nextphys = trunc_page(thisphys) + NBPG;
- phys[seg].length += min(nextphys - thisphys, datalen);
- datalen -= min(nextphys - thisphys, datalen);
- thiskv = trunc_page(thiskv) + NBPG;
- if (datalen)
- thisphys = vtophys(thiskv);
- }
-
- if (phys[seg].addr + phys[seg].length > 0xffffff) {
- if (flags & ISADMA_MAP_CONTIG) {
- phys[seg].length = nbytes;
- datalen = 0;
- }
- if ((flags & ISADMA_MAP_BOUNCE) == 0)
- phys[seg].addr = 0;
- else
- phys[seg].addr = bounce_alloc(phys[seg].length,
- pmask, waitok);
- if (phys[seg].addr == 0) {
- for (i = 0; i < seg; i++)
- if (bounce_vaddr(phys[i].addr))
- bounce_free(phys[i].addr,
- phys[i].length);
- return 0;
- }
- }
+ bus_dma_tag_t dmat = ((struct isa_softc *)isa_dev)->sc_dmat;
+ bus_dmamap_t dmam;
+ int i;
- seg++;
+/* XXX if this turns out to be too low, convert the driver to real bus_dma */
+#define ISADMA_MAX_SEGMENTS 64
+#define ISADMA_MAX_SEGSZ 0xffffff
+
+ if (bus_dmamap_create(dmat, nbytes,
+ (flags & ISADMA_MAP_CONTIG) ? 1 : ISADMA_MAX_SEGMENTS,
+ ISADMA_MAX_SEGSZ,
+ (flags & ISADMA_MAP_8BIT) ? 0xffff :
+ ((flags & ISADMA_MAP_16BIT) ? 0x1ffff : 0),
+ (flags & ISADMA_MAP_WAITOK) ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT,
+ &dmam) != 0)
+ return (0);
+ if (bus_dmamap_load(dmat, dmam, addr, nbytes, 0,
+ (flags & ISADMA_MAP_WAITOK) ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT) !=
+ 0) {
+ bus_dmamap_destroy(dmat, dmam);
+ return (0);
}
-
- /* check all constraints */
- if (datalen ||
- ((phys[0].addr ^ (phys[0].addr + phys[0].length - 1)) & pmask) != 0 ||
- ((phys[0].addr & 1) && (flags & ISADMA_MAP_16BIT))) {
- if ((flags & ISADMA_MAP_BOUNCE) == 0)
- return 0;
- if ((phys[0].addr = bounce_alloc(nbytes, pmask, waitok)) == 0)
- return 0;
- phys[0].length = nbytes;
+ for (i = 0; i < dmam->dm_nsegs; i++) {
+ phys[i].addr = dmam->dm_segs[i].ds_addr;
+ phys[i].length = dmam->dm_segs[i].ds_len;
}
-
- return seg;
+ phys[0].dmam = dmam;
+ return (dmam->dm_nsegs);
}
/*
* undo a ISA dma mapping. Simply return the bounced segments to the pool.
*/
-
void
isadma_unmap(addr, nbytes, nphys, phys)
caddr_t addr;
@@ -724,17 +1153,19 @@ isadma_unmap(addr, nbytes, nphys, phys)
int nphys;
struct isadma_seg *phys;
{
- int i;
-
- for (i = 0; i < nphys; i++)
- if (bounce_vaddr(phys[i].addr))
- bounce_free(phys[i].addr, phys[i].length);
+ bus_dma_tag_t dmat = ((struct isa_softc *)isa_dev)->sc_dmat;
+ bus_dmamap_t dmam = phys[0].dmam;
+
+ if (dmam == NULL)
+ return;
+ bus_dmamap_unload(dmat, dmam);
+ bus_dmamap_destroy(dmat, dmam);
+ phys[0].dmam = NULL;
}
/*
* copy bounce buffer to buffer where needed
*/
-
void
isadma_copyfrombuf(addr, nbytes, nphys, phys)
caddr_t addr;
@@ -742,21 +1173,15 @@ isadma_copyfrombuf(addr, nbytes, nphys, phys)
int nphys;
struct isadma_seg *phys;
{
- int i;
- caddr_t vaddr;
+ bus_dma_tag_t dmat = ((struct isa_softc *)isa_dev)->sc_dmat;
+ bus_dmamap_t dmam = phys[0].dmam;
- for (i = 0; i < nphys; i++) {
- vaddr = bounce_vaddr(phys[i].addr);
- if (vaddr)
- bcopy(vaddr, addr, phys[i].length);
- addr += phys[i].length;
- }
+ bus_dmamap_sync(dmat, dmam, BUS_DMASYNC_POSTREAD);
}
/*
* copy buffer to bounce buffer where needed
*/
-
void
isadma_copytobuf(addr, nbytes, nphys, phys)
caddr_t addr;
@@ -764,13 +1189,10 @@ isadma_copytobuf(addr, nbytes, nphys, phys)
int nphys;
struct isadma_seg *phys;
{
- int i;
- caddr_t vaddr;
+ bus_dma_tag_t dmat = ((struct isa_softc *)isa_dev)->sc_dmat;
+ bus_dmamap_t dmam = phys[0].dmam;
- for (i = 0; i < nphys; i++) {
- vaddr = bounce_vaddr(phys[i].addr);
- if (vaddr)
- bcopy(addr, vaddr, phys[i].length);
- addr += phys[i].length;
- }
+ bus_dmamap_sync(dmat, dmam, BUS_DMASYNC_PREWRITE);
}
+#endif /* __ISADMA_COMPAT */
+#endif /* NISADMA > 0 */
diff --git a/sys/arch/i386/isa/isa_machdep.h b/sys/arch/i386/isa/isa_machdep.h
index a2c8482979b..b86993cfbc6 100644
--- a/sys/arch/i386/isa/isa_machdep.h
+++ b/sys/arch/i386/isa/isa_machdep.h
@@ -1,4 +1,41 @@
-/* $NetBSD: isa_machdep.h,v 1.6 1996/05/03 19:14:56 christos Exp $ */
+/* $NetBSD: isa_machdep.h,v 1.7 1997/06/06 23:28:42 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
/*-
* Copyright (c) 1990 The Regents of the University of California.
@@ -46,6 +83,8 @@
#ifndef _I386_ISA_MACHDEP_H_ /* XXX */
#define _I386_ISA_MACHDEP_H_ /* XXX */
+#include <machine/bus.h>
+
/*
* XXX THIS FILE IS A MESS. copyright: berkeley's probably.
* contents from isavar.h and isareg.h, mostly the latter.
@@ -76,6 +115,32 @@ void isa_intr_disestablish __P((isa_chipset_tag_t ic, void *handler));
* ALL OF THE FOLLOWING ARE MACHINE-DEPENDENT, AND SHOULD NOT BE USED
* BY PORTABLE CODE.
*/
+
+extern struct i386_bus_dma_tag isa_bus_dma_tag;
+
+/*
+ * Cookie used by ISA dma. A pointer to one of these it stashed in
+ * the DMA map.
+ */
+struct i386_isa_dma_cookie {
+ int id_flags; /* flags; see below */
+
+ void *id_origbuf; /* pointer to orig buffer if
+ bouncing */
+ bus_size_t id_origbuflen; /* ...and size */
+
+ void *id_bouncebuf; /* pointer to the bounce buffer */
+ bus_size_t id_bouncebuflen; /* ...and size */
+ int id_nbouncesegs; /* number of valid bounce segs */
+ bus_dma_segment_t id_bouncesegs[0]; /* array of bounce buffer
+ physical memory segments */
+};
+
+/* id_flags */
+#define ID_MIGHT_NEED_BOUNCE 0x01 /* map could need bounce buffers */
+#define ID_HAS_BOUNCE 0x02 /* map currently has bounce buffers */
+#define ID_IS_BOUNCING 0x04 /* map is bouncing current xfer */
+
/*
* XXX Various seemingly PC-specific constants, some of which may be
* unnecessary anyway.
diff --git a/sys/arch/i386/pci/pchb.c b/sys/arch/i386/pci/pchb.c
index c6bdb77c24b..88b5cb6aea1 100644
--- a/sys/arch/i386/pci/pchb.c
+++ b/sys/arch/i386/pci/pchb.c
@@ -1,4 +1,4 @@
-/* $NetBSD: pchb.c,v 1.9 1997/10/09 08:48:33 jtc Exp $ */
+/* $NetBSD: pchb.c,v 1.6 1997/06/06 23:29:16 thorpej Exp $ */
/*-
* Copyright (c) 1996 The NetBSD Foundation, Inc.
@@ -122,6 +122,7 @@ pchbattach(parent, self, aux)
pba.pba_busname = "pci";
pba.pba_iot = pa->pa_iot;
pba.pba_memt = pa->pa_memt;
+ pba.pba_dmat = pa->pa_dmat;
pba.pba_bus = pbnum;
pba.pba_pc = pa->pa_pc;
config_found(self, &pba, pchb_print);
diff --git a/sys/arch/i386/pci/pci_machdep.c b/sys/arch/i386/pci/pci_machdep.c
index 4a66aa2632b..9146ad91640 100644
--- a/sys/arch/i386/pci/pci_machdep.c
+++ b/sys/arch/i386/pci/pci_machdep.c
@@ -1,5 +1,42 @@
-/* $OpenBSD: pci_machdep.c,v 1.10 1997/06/18 19:07:01 dm Exp $ */
-/* $NetBSD: pci_machdep.c,v 1.26 1996/10/24 12:32:29 fvdl Exp $ */
+/* $OpenBSD: pci_machdep.c,v 1.11 1998/01/20 18:40:23 niklas Exp $ */
+/* $NetBSD: pci_machdep.c,v 1.28 1997/06/06 23:29:17 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
@@ -53,6 +90,9 @@
#include <vm/vm.h>
#include <vm/vm_kern.h>
+#define _I386_BUS_DMA_PRIVATE
+#include <machine/bus.h>
+
#include <machine/pio.h>
#include <i386/isa/icu.h>
@@ -69,6 +109,27 @@ int pci_mode = -1;
#define PCI_MODE2_ENABLE_REG 0x0cf8
#define PCI_MODE2_FORWARD_REG 0x0cfa
+/*
+ * PCI doesn't have any special needs; just use the generic versions
+ * of these functions.
+ */
+struct i386_bus_dma_tag pci_bus_dma_tag = {
+ NULL, /* _cookie */
+ _bus_dmamap_create,
+ _bus_dmamap_destroy,
+ _bus_dmamap_load,
+ _bus_dmamap_load_mbuf,
+ _bus_dmamap_load_uio,
+ _bus_dmamap_load_raw,
+ _bus_dmamap_unload,
+ NULL, /* _dmamap_sync */
+ _bus_dmamem_alloc,
+ _bus_dmamem_free,
+ _bus_dmamem_map,
+ _bus_dmamem_unmap,
+ _bus_dmamem_mmap,
+};
+
void
pci_attach_hook(parent, self, pba)
struct device *parent, *self;
diff --git a/sys/arch/i386/pci/pci_machdep.h b/sys/arch/i386/pci/pci_machdep.h
index 02e02048084..35d75a09793 100644
--- a/sys/arch/i386/pci/pci_machdep.h
+++ b/sys/arch/i386/pci/pci_machdep.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: pci_machdep.h,v 1.4 1997/06/18 19:07:02 dm Exp $ */
-/* $NetBSD: pci_machdep.h,v 1.5 1996/03/27 04:01:16 cgd Exp $ */
+/* $OpenBSD: pci_machdep.h,v 1.5 1998/01/20 18:40:23 niklas Exp $ */
+/* $NetBSD: pci_machdep.h,v 1.7 1997/06/06 23:29:18 thorpej Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
@@ -55,6 +55,8 @@ union i386_pci_tag_u {
} mode2;
};
+extern struct i386_bus_dma_tag pci_bus_dma_tag;
+
/*
* Types provided to machine-independent PCI code
*/
diff --git a/sys/arch/powerpc/include/bus.h b/sys/arch/powerpc/include/bus.h
index f6b1a911760..52988bd9a6c 100644
--- a/sys/arch/powerpc/include/bus.h
+++ b/sys/arch/powerpc/include/bus.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bus.h,v 1.1 1997/10/13 10:53:42 pefo Exp $ */
+/* $OpenBSD: bus.h,v 1.2 1998/01/20 18:40:24 niklas Exp $ */
/*
* Copyright (c) 1997 Per Fogelstrom. All rights reserved.
@@ -161,4 +161,8 @@ bus_space_write_raw_multi(4,32,2)
#define bus_space_write_raw_multi_8 \
!!! bus_space_write_raw_multi_8 not implemented !!!
+/* XXX placeholders */
+typedef void *bus_dma_tag_t;
+typedef void *bus_dmamap_t;
+
#endif /* _MACHINE_BUS_H_ */
diff --git a/sys/dev/eisa/eisavar.h b/sys/dev/eisa/eisavar.h
index bb740f327ab..2115d6b5960 100644
--- a/sys/dev/eisa/eisavar.h
+++ b/sys/dev/eisa/eisavar.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: eisavar.h,v 1.7 1997/03/12 20:13:01 pefo Exp $ */
-/* $NetBSD: eisavar.h,v 1.10 1996/10/21 22:31:03 thorpej Exp $ */
+/* $OpenBSD: eisavar.h,v 1.8 1998/01/20 18:40:26 niklas Exp $ */
+/* $NetBSD: eisavar.h,v 1.11 1997/06/06 23:30:07 thorpej Exp $ */
/*
* Copyright (c) 1995, 1996 Christopher G. Demetriou
@@ -76,6 +76,7 @@ struct eisabus_attach_args {
char *eba_busname; /* XXX should be common */
bus_space_tag_t eba_iot; /* eisa i/o space tag */
bus_space_tag_t eba_memt; /* eisa mem space tag */
+ bus_dma_tag_t eba_dmat; /* DMA tag */
eisa_chipset_tag_t eba_ec;
};
@@ -85,6 +86,7 @@ struct eisabus_attach_args {
struct eisa_attach_args {
bus_space_tag_t ea_iot; /* eisa i/o space tag */
bus_space_tag_t ea_memt; /* eisa mem space tag */
+ bus_dma_tag_t ea_dmat; /* DMA tag */
eisa_chipset_tag_t ea_ec;
eisa_slot_t ea_slot;
diff --git a/sys/dev/isa/isa.c b/sys/dev/isa/isa.c
index 349dc18a665..c11c6744fb2 100644
--- a/sys/dev/isa/isa.c
+++ b/sys/dev/isa/isa.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: isa.c,v 1.27 1997/12/25 13:33:03 downsj Exp $ */
+/* $OpenBSD: isa.c,v 1.28 1998/01/20 18:40:28 niklas Exp $ */
/* $NetBSD: isa.c,v 1.85 1996/05/14 00:31:04 thorpej Exp $ */
/*
@@ -74,10 +74,13 @@
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
+#include <dev/isa/isadmareg.h>
int isamatch __P((struct device *, void *, void *));
void isaattach __P((struct device *, struct device *, void *));
+extern int autoconf_verbose;
+
struct cfattach isa_ca = {
sizeof(struct isa_softc), isamatch, isaattach
};
@@ -115,14 +118,36 @@ isaattach(parent, self, aux)
sc->sc_iot = iba->iba_iot;
sc->sc_memt = iba->iba_memt;
+#if NISADMA > 0
+ sc->sc_dmat = iba->iba_dmat;
+#endif /* NISADMA > 0 */
sc->sc_ic = iba->iba_ic;
+#if NISADMA > 0
+ /*
+ * Map the registers used by the ISA DMA controller.
+ * XXX Should be done in the isadmaattach routine.. but the delay
+ * XXX port makes it troublesome. Note that these aren't really
+ * XXX valid on ISA busses without DMA.
+ */
+ if (bus_space_map(sc->sc_iot, IO_DMA1, DMA1_IOSIZE, 0, &sc->sc_dma1h))
+ panic("isaattach: can't map DMA controller #1");
+ if (bus_space_map(sc->sc_iot, IO_DMA2, DMA2_IOSIZE, 0, &sc->sc_dma2h))
+ panic("isaattach: can't map DMA controller #2");
+ if (bus_space_map(sc->sc_iot, IO_DMAPG, 0xf, 0, &sc->sc_dmapgh))
+ panic("isaattach: can't map DMA page registers");
+
/*
- * Map port 0x84, which causes a 1.25us delay when read.
- * We do this now, since several drivers need it.
+ * Map port 0x84, which causes a 1.25us delay when read.
+ * We do this now, since several drivers need it.
* XXX this port doesn't exist on all ISA busses...
*/
- if (bus_space_map(sc->sc_iot, 0x84, 1, 0, &sc->sc_delaybah))
+ if (bus_space_subregion(sc->sc_iot, sc->sc_dmapgh, 0x04, 1,
+ &sc->sc_delaybah))
+#else /* NISADMA > 0 */
+ if (bus_space_map(sc->sc_iot, IO_DMAPG + 0x4, 0x1, 0,
+ &sc->sc_delaybah))
+#endif /* NISADMA > 0 */
panic("isaattach: can't map `delay port'"); /* XXX */
TAILQ_INIT(&sc->sc_subdevs);
@@ -163,6 +188,9 @@ isascan(parent, match)
ia.ia_iot = sc->sc_iot;
ia.ia_memt = sc->sc_memt;
+#if NISADMA > 0
+ ia.ia_dmat = sc->sc_dmat;
+#endif /* NISADMA > 0 */
ia.ia_ic = sc->sc_ic;
ia.ia_iobase = cf->cf_loc[0];
ia.ia_iosize = 0x666;
@@ -175,7 +203,14 @@ isascan(parent, match)
if (cf->cf_fstate == FSTATE_STAR) {
struct isa_attach_args ia2 = ia;
+ if (autoconf_verbose)
+ printf(">>> probing for %s*\n",
+ cf->cf_driver->cd_name);
while ((*cf->cf_attach->ca_match)(parent, dev, &ia2) > 0) {
+ if (autoconf_verbose)
+ printf(">>> probe for %s* clone into %s%d\n",
+ cf->cf_driver->cd_name,
+ cf->cf_driver->cd_name, cf->cf_unit);
if (ia2.ia_iosize == 0x666) {
printf("%s: iosize not repaired by driver\n",
sc->sc_dev.dv_xname);
@@ -185,20 +220,35 @@ isascan(parent, match)
dev = config_make_softc(parent, cf);
ia2 = ia;
+#if NISADMA > 0
if (ia.ia_drq != DRQUNK)
- isa_drq_alloc(sc, ia.ia_drq);
+ ISA_DRQ_ALLOC((struct device *)sc, ia.ia_drq);
+#endif /* NISAMDA > 0 */
}
+ if (autoconf_verbose)
+ printf(">>> probing for %s* finished\n",
+ cf->cf_driver->cd_name);
free(dev, M_DEVBUF);
return;
}
+ if (autoconf_verbose)
+ printf(">>> probing for %s%d\n", cf->cf_driver->cd_name,
+ cf->cf_unit);
if ((*cf->cf_attach->ca_match)(parent, dev, &ia) > 0) {
+ printf(">>> probing for %s%d succeeded\n",
+ cf->cf_driver->cd_name, cf->cf_unit);
config_attach(parent, dev, &ia, isaprint);
+#if NISADMA > 0
if (ia.ia_drq != DRQUNK)
- isa_drq_alloc(sc, ia.ia_drq);
- } else
+ ISA_DRQ_ALLOC((struct device *)sc, ia.ia_drq);
+#endif /* NISAMDA > 0 */
+ } else {
+ printf(">>> probing for %s%d failed\n",
+ cf->cf_driver->cd_name, cf->cf_unit);
free(dev, M_DEVBUF);
+ }
}
char *
@@ -219,44 +269,3 @@ isa_intr_typename(type)
panic("isa_intr_typename: invalid type %d", type);
}
}
-
-#ifdef DIAGNOSTIC
-void
-isa_drq_alloc(vsp, drq)
- void *vsp;
- int drq;
-{
- struct isa_softc *sc = vsp;
-
- if (drq < 0 || drq > 7)
- panic("isa_drq_alloc: drq %d out of range\n", drq);
-
- sc->sc_drq |= (1 << drq);
-}
-
-void
-isa_drq_free(vsp, drq)
- void *vsp;
- int drq;
-{
- struct isa_softc *sc = vsp;
-
- if (drq < 0 || drq > 7)
- panic("isa_drq_free: drq %d out of range\n", drq);
-
- sc->sc_drq &= ~(1 << drq);
-}
-
-int
-isa_drq_isfree(vsp, drq)
- void *vsp;
- int drq;
-{
- struct isa_softc *sc = vsp;
-
- if (drq < 0 || drq > 7)
- panic("isa_drq_isfree: drq %d out of range\n", drq);
-
- return (!((sc->sc_drq << drq) & 1));
-}
-#endif /* DIAGNOSTIC */
diff --git a/sys/dev/isa/isadma.c b/sys/dev/isa/isadma.c
index 141323ed8c8..bb09d9f4959 100644
--- a/sys/dev/isa/isadma.c
+++ b/sys/dev/isa/isadma.c
@@ -1,41 +1,86 @@
-/* $OpenBSD: isadma.c,v 1.16 1997/12/25 12:06:47 downsj Exp $ */
-/* $NetBSD: isadma.c,v 1.19 1996/04/29 20:03:26 christos Exp $ */
+/* $OpenBSD: isadma.c,v 1.17 1998/01/20 18:40:29 niklas Exp $ */
+/* $NetBSD: isadma.c,v 1.32 1997/09/05 01:48:33 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Device driver for the ISA on-board DMA controller.
+ */
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/proc.h>
#include <sys/device.h>
-#include <sys/file.h>
-#include <sys/buf.h>
-#include <sys/syslog.h>
-#include <sys/malloc.h>
-#include <sys/uio.h>
#include <vm/vm.h>
-#include <machine/pio.h>
+#include <machine/bus.h>
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <dev/isa/isadmavar.h>
#include <dev/isa/isadmareg.h>
-struct dma_info {
- int flags;
- int active;
- int inuse;
- int bounced;
- caddr_t addr;
- vm_size_t nbytes;
- struct isadma_seg phys[1];
-};
+#ifdef __ISADMA_COMPAT
+/* XXX ugly, but will go away soon... */
+struct device *isa_dev;
+
+bus_dmamap_t isadma_dmam[8];
+#endif
-static struct dma_info dma_info[8];
-static u_int8_t dma_finished;
+/* Used by isa_malloc() */
+#include <sys/malloc.h>
+struct isa_mem {
+ struct device *isadev;
+ int chan;
+ bus_size_t size;
+ bus_addr_t addr;
+ caddr_t kva;
+ struct isa_mem *next;
+} *isa_mem_head = 0;
-/* high byte of address is stored in this port for i-th dma channel */
+/*
+ * High byte of DMA address is stored in this DMAPG register for
+ * the Nth DMA channel.
+ */
static int dmapageport[2][4] = {
- {0x87, 0x83, 0x81, 0x82},
- {0x8f, 0x8b, 0x89, 0x8a}
+ {0x7, 0x3, 0x1, 0x2},
+ {0xf, 0xb, 0x9, 0xa}
};
static u_int8_t dmamode[4] = {
@@ -47,7 +92,6 @@ static u_int8_t dmamode[4] = {
int isadmamatch __P((struct device *, void *, void *));
void isadmaattach __P((struct device *, struct device *, void *));
-int isadmaprint __P((void *, const char *));
struct cfattach isadma_ca = {
sizeof(struct device), isadmamatch, isadmaattach
@@ -74,279 +118,624 @@ isadmaattach(parent, self, aux)
struct device *parent, *self;
void *aux;
{
+#ifdef __ISADMA_COMPAT
+ int i, sz;
+ struct isa_softc *sc = (struct isa_softc *)parent;
+
+ /* XXX ugly, but will go away soon... */
+ isa_dev = parent;
+
+ for (i = 0; i < 8; i++) {
+ sz = (i & 4) ? 1 << 17 : 1 << 16;
+ if ((bus_dmamap_create(sc->sc_dmat, sz, 1, sz, sz,
+ BUS_DMA_NOWAIT|BUS_DMA_ALLOCNOW, &isadma_dmam[i])) != 0)
+ panic("isa_dmastart: can not create DMA map");
+ }
+#endif
+
+ /* XXX I'd like to map the DMA ports here, see isa.c why not... */
+
printf("\n");
}
-/*
- * Register a DMA channel's usage. Usually called from a device driver
- * in open() or during it's initialization.
- */
-int
-isadma_acquire(chan)
+static inline void isa_dmaunmask __P((struct isa_softc *, int));
+static inline void isa_dmamask __P((struct isa_softc *, int));
+
+static inline void
+isa_dmaunmask(sc, chan)
+ struct isa_softc *sc;
int chan;
{
- struct dma_info *di;
-#ifdef DIAGNOSTIC
- if (chan < 0 || chan > 7)
- panic("isadma_acquire: channel out of range");
-#endif
+ int ochan = chan & 3;
+
+ /* set dma channel mode, and set dma channel mode */
+ if ((chan & 4) == 0)
+ bus_space_write_1(sc->sc_iot, sc->sc_dma1h,
+ DMA1_SMSK, ochan | DMA37SM_CLEAR);
+ else
+ bus_space_write_1(sc->sc_iot, sc->sc_dma2h,
+ DMA2_SMSK, ochan | DMA37SM_CLEAR);
+}
- di = dma_info + chan;
+static inline void
+isa_dmamask(sc, chan)
+ struct isa_softc *sc;
+ int chan;
+{
+ int ochan = chan & 3;
- if (di->inuse) {
- log(LOG_ERR, "isadma_acquire: channel %d already in use\n", chan);
- return (EBUSY);
+ /* set dma channel mode, and set dma channel mode */
+ if ((chan & 4) == 0) {
+ bus_space_write_1(sc->sc_iot, sc->sc_dma1h,
+ DMA1_SMSK, ochan | DMA37SM_SET);
+ bus_space_write_1(sc->sc_iot, sc->sc_dma1h,
+ DMA1_FFC, 0);
+ } else {
+ bus_space_write_1(sc->sc_iot, sc->sc_dma2h,
+ DMA2_SMSK, ochan | DMA37SM_SET);
+ bus_space_write_1(sc->sc_iot, sc->sc_dma2h,
+ DMA2_FFC, 0);
}
- di->inuse = 1;
-
- return (0);
}
/*
- * Unregister a DMA channel's usage. Usually called from a device driver
- * during close() or during it's shutdown.
+ * isa_dmacascade(): program 8237 DMA controller channel to accept
+ * external dma control by a board.
*/
void
-isadma_release(chan)
+isa_dmacascade(isadev, chan)
+ struct device *isadev;
int chan;
{
- struct dma_info *di;
-#ifdef DIAGNOSTIC
- if (chan < 0 || chan > 7)
- panic("isadma_release: channel out of range");
-#endif
- di = dma_info + chan;
+ struct isa_softc *sc = (struct isa_softc *)isadev;
+ int ochan = chan & 3;
- if (!di->inuse) {
- log(LOG_ERR, "isadma_release: channel %d not in use\n", chan);
- return;
+ if (chan < 0 || chan > 7) {
+ printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
+ goto lose;
+ }
+
+ if (ISA_DRQ_ISFREE(sc, chan) == 0) {
+ printf("%s: DRQ %d is not free\n", sc->sc_dev.dv_xname, chan);
+ goto lose;
}
- if (di->active)
- isadma_abort(chan);
+ ISA_DRQ_ALLOC(sc, chan);
+
+ /* set dma channel mode, and set dma channel mode */
+ if ((chan & 4) == 0)
+ bus_space_write_1(sc->sc_iot, sc->sc_dma1h,
+ DMA1_MODE, ochan | DMA37MD_CASCADE);
+ else
+ bus_space_write_1(sc->sc_iot, sc->sc_dma2h,
+ DMA2_MODE, ochan | DMA37MD_CASCADE);
+
+ isa_dmaunmask(sc, chan);
+ return;
- di->inuse = 0;
+ lose:
+ panic("isa_dmacascade");
}
-/*
- * isadma_cascade(): program 8237 DMA controller channel to accept
- * external dma control by a board.
- */
-void
-isadma_cascade(chan)
+int
+isa_dmamap_create(isadev, chan, size, flags)
+ struct device *isadev;
int chan;
+ bus_size_t size;
+ int flags;
{
- struct dma_info *di;
+ struct isa_softc *sc = (struct isa_softc *)isadev;
+ bus_size_t maxsize;
-#ifdef ISADMA_DEBUG
- if (chan < 0 || chan > 7)
- panic("isadma_cascade: impossible request");
-#endif
- di = dma_info + chan;
+ if (chan < 0 || chan > 7) {
+ printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
+ goto lose;
+ }
- /* set dma channel mode, and set dma channel mode */
- if ((chan & 4) == 0) {
- outb(DMA1_MODE, chan | DMA37MD_CASCADE);
- outb(DMA1_SMSK, chan);
- } else {
- chan &= 3;
+ if (chan & 4)
+ maxsize = (1 << 17);
+ else
+ maxsize = (1 << 16);
+
+ if (size > maxsize)
+ return (EINVAL);
+
+ if (ISA_DRQ_ISFREE(sc, chan) == 0) {
+ printf("%s: drq %d is not free\n", sc->sc_dev.dv_xname, chan);
+ goto lose;
+ }
- outb(DMA2_MODE, chan | DMA37MD_CASCADE);
- outb(DMA2_SMSK, chan);
+ ISA_DRQ_ALLOC(sc, chan);
+
+ return (bus_dmamap_create(sc->sc_dmat, size, 1, size, maxsize,
+ flags, &sc->sc_dmamaps[chan]));
+
+ lose:
+ panic("isa_dmamap_create");
+}
+
+void
+isa_dmamap_destroy(isadev, chan)
+ struct device *isadev;
+ int chan;
+{
+ struct isa_softc *sc = (struct isa_softc *)isadev;
+
+ if (chan < 0 || chan > 7) {
+ printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
+ goto lose;
+ }
+
+ if (ISA_DRQ_ISFREE(sc, chan)) {
+ printf("%s: drq %d is already free\n",
+ sc->sc_dev.dv_xname, chan);
+ goto lose;
}
- /* Mark it as in use, if needed. XXX */
- if (!di->inuse)
- di->inuse = 1;
+ ISA_DRQ_FREE(sc, chan);
+
+ bus_dmamap_destroy(sc->sc_dmat, sc->sc_dmamaps[chan]);
+ return;
+
+ lose:
+ panic("isa_dmamap_destroy");
}
/*
- * isadma_start(): program 8237 DMA controller channel, avoid page alignment
- * problems by using a bounce buffer.
+ * isa_dmastart(): program 8237 DMA controller channel and set it
+ * in motion.
*/
-void
-isadma_start(addr, nbytes, chan, flags)
- caddr_t addr;
- vm_size_t nbytes;
+int
+isa_dmastart(isadev, chan, addr, nbytes, p, flags, busdmaflags)
+ struct device *isadev;
int chan;
+ void *addr;
+ bus_size_t nbytes;
+ struct proc *p;
int flags;
+ int busdmaflags;
{
- struct dma_info *di;
+ struct isa_softc *sc = (struct isa_softc *)isadev;
+ bus_dmamap_t dmam;
+ bus_addr_t dmaaddr;
int waport;
- int mflags;
+ int ochan = chan & 3;
+ int error;
+#ifdef __ISADMA_COMPAT
+ int compat = busdmaflags & BUS_DMA_BUS1;
+
+ busdmaflags &= ~BUS_DMA_BUS1;
+#endif /* __ISADMA_COMPAT */
+
+ if (chan < 0 || chan > 7) {
+ printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
+ goto lose;
+ }
#ifdef ISADMA_DEBUG
- if (chan < 0 || chan > 7 ||
- (((flags & DMAMODE_READ) != 0) + ((flags & DMAMODE_WRITE) != 0) +
- ((flags & DMAMODE_LOOP) != 0) != 1) ||
- ((chan & 4) ? (nbytes >= (1<<17) || nbytes & 1 || (u_int)addr & 1) :
- (nbytes >= (1<<16))))
- panic("isadma_start: impossible request");
+ printf("isa_dmastart: drq %d, addr %p, nbytes 0x%lx, p %p, "
+ "flags 0x%x, dmaflags 0x%x\n",
+ chan, addr, nbytes, p, flags, busdmaflags);
#endif
- di = dma_info+chan;
- if (di->active) {
- log(LOG_ERR,"isadma_start: old request active on %d\n",chan);
- isadma_abort(chan);
+ if (chan & 4) {
+ if (nbytes > (1 << 17) || nbytes & 1 || (u_long)addr & 1) {
+ printf("%s: drq %d, nbytes 0x%lx, addr %p\n",
+ sc->sc_dev.dv_xname, chan, nbytes, addr);
+ goto lose;
+ }
+ } else {
+ if (nbytes > (1 << 16)) {
+ printf("%s: drq %d, nbytes 0x%lx\n",
+ sc->sc_dev.dv_xname, chan, nbytes);
+ goto lose;
+ }
}
- di->flags = flags;
- di->active = 1;
- di->addr = addr;
- di->nbytes = nbytes;
+ dmam = sc->sc_dmamaps[chan];
+ if (dmam == NULL)
+#ifdef __ISADMA_COMPAT
+ if (compat)
+ dmam = sc->sc_dmamaps[chan] = isadma_dmam[chan];
+ else
+#endif /* __ISADMA_COMPAT */
+ panic("isa_dmastart: no DMA map for chan %d\n", chan);
- mflags = ISADMA_MAP_WAITOK | ISADMA_MAP_CONTIG;
- mflags |= (chan & 4) ? ISADMA_MAP_16BIT : ISADMA_MAP_8BIT;
+ error = bus_dmamap_load(sc->sc_dmat, dmam, addr, nbytes, p,
+ busdmaflags);
+ if (error)
+ return (error);
- if (isadma_map(addr, nbytes, di->phys, mflags) != 1) {
- mflags |= ISADMA_MAP_BOUNCE;
+#ifdef ISADMA_DEBUG
+ __asm(".globl isa_dmastart_afterload ; isa_dmastart_afterload:");
+#endif
+
+ if (flags & DMAMODE_READ) {
+ bus_dmamap_sync(sc->sc_dmat, dmam, BUS_DMASYNC_PREREAD);
+ sc->sc_dmareads |= (1 << chan);
+ } else {
+ bus_dmamap_sync(sc->sc_dmat, dmam, BUS_DMASYNC_PREWRITE);
+ sc->sc_dmareads &= ~(1 << chan);
+ }
- if (isadma_map(addr, nbytes, di->phys, mflags) != 1)
- panic("isadma_start: cannot map");
+ dmaaddr = dmam->dm_segs[0].ds_addr;
- di->bounced = 1;
+#ifdef ISADMA_DEBUG
+ printf(" dmaaddr 0x%lx\n", dmaaddr);
- if ((flags & DMAMODE_READ) == 0)
- isadma_copytobuf(addr, nbytes, 1, di->phys);
+ __asm(".globl isa_dmastart_aftersync ; isa_dmastart_aftersync:");
+#endif
- /* XXX Will this do what we want with DMAMODE_LOOP? */
- if ((flags & DMAMODE_READ) == 0)
- isadma_copytobuf(addr, nbytes, 1, di->phys);
- }
+ sc->sc_dmalength[chan] = nbytes;
- dma_finished &= ~(1 << chan);
+ isa_dmamask(sc, chan);
+ sc->sc_dmafinished &= ~(1 << chan);
if ((chan & 4) == 0) {
- /*
- * Program one of DMA channels 0..3. These are
- * byte mode channels.
- */
- /* set dma channel mode, and reset address ff */
- outb(DMA1_MODE, chan | dmamode[flags]);
- outb(DMA1_FFC, 0);
+ /* set dma channel mode */
+ bus_space_write_1(sc->sc_iot, sc->sc_dma1h, DMA1_MODE,
+ ochan | dmamode[flags]);
/* send start address */
- waport = DMA1_CHN(chan);
- outb(dmapageport[0][chan], di->phys[0].addr>>16);
- outb(waport, di->phys[0].addr);
- outb(waport, di->phys[0].addr>>8);
+ waport = DMA1_CHN(ochan);
+ bus_space_write_1(sc->sc_iot, sc->sc_dmapgh,
+ dmapageport[0][ochan], (dmaaddr >> 16) & 0xff);
+ bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport,
+ dmaaddr & 0xff);
+ bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport,
+ (dmaaddr >> 8) & 0xff);
/* send count */
- outb(waport + 1, --nbytes);
- outb(waport + 1, nbytes>>8);
-
- /* unmask channel */
- outb(DMA1_SMSK, chan | DMA37SM_CLEAR);
+ bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport + 1,
+ (--nbytes) & 0xff);
+ bus_space_write_1(sc->sc_iot, sc->sc_dma1h, waport + 1,
+ (nbytes >> 8) & 0xff);
} else {
- /*
- * Program one of DMA channels 4..7. These are
- * word mode channels.
- */
- /* set dma channel mode, and reset address ff */
- outb(DMA2_MODE, (chan & 3) | dmamode[flags]);
- outb(DMA2_FFC, 0);
+ /* set dma channel mode */
+ bus_space_write_1(sc->sc_iot, sc->sc_dma2h, DMA2_MODE,
+ ochan | dmamode[flags]);
/* send start address */
- waport = DMA2_CHN(chan & 3);
- outb(dmapageport[1][chan & 3], di->phys[0].addr>>16);
- outb(waport, di->phys[0].addr>>1);
- outb(waport, di->phys[0].addr>>9);
+ waport = DMA2_CHN(ochan);
+ bus_space_write_1(sc->sc_iot, sc->sc_dmapgh,
+ dmapageport[1][ochan], (dmaaddr >> 16) & 0xff);
+ dmaaddr >>= 1;
+ bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport,
+ dmaaddr & 0xff);
+ bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport,
+ (dmaaddr >> 8) & 0xff);
/* send count */
nbytes >>= 1;
- outb(waport + 2, --nbytes);
- outb(waport + 2, nbytes>>8);
-
- /* unmask channel */
- outb(DMA2_SMSK, (chan & 3) | DMA37SM_CLEAR);
+ bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport + 2,
+ (--nbytes) & 0xff);
+ bus_space_write_1(sc->sc_iot, sc->sc_dma2h, waport + 2,
+ (nbytes >> 8) & 0xff);
}
+
+ isa_dmaunmask(sc, chan);
+ return (0);
+
+ lose:
+ panic("isa_dmastart");
}
void
-isadma_abort(chan)
+isa_dmaabort(isadev, chan)
+ struct device *isadev;
int chan;
{
- struct dma_info *di;
+ struct isa_softc *sc = (struct isa_softc *)isadev;
-#ifdef ISADMA_DEBUG
- if (chan < 0 || chan > 7)
- panic("isadma_abort: impossible request");
-#endif
+ if (chan < 0 || chan > 7) {
+ printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
+ panic("isa_dmaabort");
+ }
- di = dma_info+chan;
- if (! di->active) {
- log(LOG_ERR,"isadma_abort: no request active on %d\n",chan);
- return;
+ isa_dmamask(sc, chan);
+ bus_dmamap_unload(sc->sc_dmat, sc->sc_dmamaps[chan]);
+ sc->sc_dmareads &= ~(1 << chan);
+}
+
+bus_size_t
+isa_dmacount(isadev, chan)
+ struct device *isadev;
+ int chan;
+{
+ struct isa_softc *sc = (struct isa_softc *)isadev;
+ int waport;
+ bus_size_t nbytes;
+ int ochan = chan & 3;
+
+ if (chan < 0 || chan > 7) {
+ printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
+ panic("isa_dmacount");
}
- /* mask channel */
- if ((chan & 4) == 0)
- outb(DMA1_SMSK, DMA37SM_SET | chan);
- else
- outb(DMA2_SMSK, DMA37SM_SET | (chan & 3));
+ isa_dmamask(sc, chan);
- isadma_unmap(di->addr, di->nbytes, 1, di->phys);
- di->active = 0;
- di->bounced = 0;
+ /*
+ * We have to shift the byte count by 1. If we're in auto-initialize
+ * mode, the count may have wrapped around to the initial value. We
+ * can't use the TC bit to check for this case, so instead we compare
+ * against the original byte count.
+ * If we're not in auto-initialize mode, then the count will wrap to
+ * -1, so we also handle that case.
+ */
+ if ((chan & 4) == 0) {
+ waport = DMA1_CHN(ochan);
+ nbytes = bus_space_read_1(sc->sc_iot, sc->sc_dma1h,
+ waport + 1) + 1;
+ nbytes += bus_space_read_1(sc->sc_iot, sc->sc_dma1h,
+ waport + 1) << 8;
+ nbytes &= 0xffff;
+ } else {
+ waport = DMA2_CHN(ochan);
+ nbytes = bus_space_read_1(sc->sc_iot, sc->sc_dma2h,
+ waport + 2) + 1;
+ nbytes += bus_space_read_1(sc->sc_iot, sc->sc_dma2h,
+ waport + 2) << 8;
+ nbytes <<= 1;
+ nbytes &= 0x1ffff;
+ }
+
+ if (nbytes == sc->sc_dmalength[chan])
+ nbytes = 0;
+
+ isa_dmaunmask(sc, chan);
+ return (nbytes);
}
int
-isadma_finished(chan)
+isa_dmafinished(isadev, chan)
+ struct device *isadev;
int chan;
{
+ struct isa_softc *sc = (struct isa_softc *)isadev;
-#ifdef ISADMA_DEBUG
- if (chan < 0 || chan > 7)
- panic("isadma_finished: impossible request");
-#endif
+ if (chan < 0 || chan > 7) {
+ printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
+ panic("isa_dmafinished");
+ }
/* check that the terminal count was reached */
if ((chan & 4) == 0)
- dma_finished |= inb(DMA1_SR) & 0x0f;
+ sc->sc_dmafinished |= bus_space_read_1(sc->sc_iot,
+ sc->sc_dma1h, DMA1_SR) & 0x0f;
else
- dma_finished |= (inb(DMA2_SR) & 0x0f) << 4;
+ sc->sc_dmafinished |= (bus_space_read_1(sc->sc_iot,
+ sc->sc_dma2h, DMA2_SR) & 0x0f) << 4;
- return ((dma_finished & (1 << chan)) != 0);
+ return ((sc->sc_dmafinished & (1 << chan)) != 0);
}
void
-isadma_done(chan)
+isa_dmadone(isadev, chan)
+ struct device *isadev;
int chan;
{
- struct dma_info *di;
- u_char tc;
+ struct isa_softc *sc = (struct isa_softc *)isadev;
+ bus_dmamap_t dmam;
-#ifdef DIAGNOSTIC
- if (chan < 0 || chan > 7)
- panic("isadma_done: impossible request");
-#endif
+ if (chan < 0 || chan > 7) {
+ printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
+ panic("isa_dmadone");
+ }
- di = dma_info+chan;
- if (! di->active) {
- log(LOG_ERR,"isadma_done: no request active on %d\n",chan);
- return;
+ dmam = sc->sc_dmamaps[chan];
+
+ isa_dmamask(sc, chan);
+
+ if (isa_dmafinished(isadev, chan) == 0)
+ printf("%s: isa_dmadone: channel %d not finished\n",
+ sc->sc_dev.dv_xname, chan);
+
+ bus_dmamap_sync(sc->sc_dmat, dmam,
+ (sc->sc_dmareads & (1 << chan)) ? BUS_DMASYNC_POSTREAD :
+ BUS_DMASYNC_POSTWRITE);
+
+ bus_dmamap_unload(sc->sc_dmat, dmam);
+ sc->sc_dmareads &= ~(1 << chan);
+}
+
+int
+isa_dmamem_alloc(isadev, chan, size, addrp, flags)
+ struct device *isadev;
+ int chan;
+ bus_size_t size;
+ bus_addr_t *addrp;
+ int flags;
+{
+ struct isa_softc *sc = (struct isa_softc *)isadev;
+ bus_dma_segment_t seg;
+ int error, boundary, rsegs;
+
+ if (chan < 0 || chan > 7) {
+ printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
+ panic("isa_dmamem_alloc");
}
- /* check that the terminal count was reached */
- if ((chan & 4) == 0)
- tc = inb(DMA1_SR) & (1 << chan);
- else
- tc = inb(DMA2_SR) & (1 << (chan & 3));
- if (tc == 0)
- /* XXX probably should panic or something */
- log(LOG_ERR, "dma channel %d not finished\n", chan);
+ boundary = (chan & 4) ? (1 << 17) : (1 << 16);
- /* mask channel */
- if ((chan & 4) == 0)
- outb(DMA1_SMSK, DMA37SM_SET | chan);
- else
- outb(DMA2_SMSK, DMA37SM_SET | (chan & 3));
+ size = round_page(size);
+
+ error = bus_dmamem_alloc(sc->sc_dmat, size, NBPG, boundary,
+ &seg, 1, &rsegs, flags);
+ if (error)
+ return (error);
+
+ *addrp = seg.ds_addr;
+ return (0);
+}
+
+void
+isa_dmamem_free(isadev, chan, addr, size)
+ struct device *isadev;
+ int chan;
+ bus_addr_t addr;
+ bus_size_t size;
+{
+ struct isa_softc *sc = (struct isa_softc *)isadev;
+ bus_dma_segment_t seg;
+
+ if (chan < 0 || chan > 7) {
+ printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
+ panic("isa_dmamem_free");
+ }
+
+ seg.ds_addr = addr;
+ seg.ds_len = size;
- /* XXX Will this do what we want with DMAMODE_LOOP? */
- if (di->bounced & (di->flags & DMAMODE_READ))
- isadma_copyfrombuf(di->addr, di->nbytes, 1, di->phys);
+ bus_dmamem_free(sc->sc_dmat, &seg, 1);
+}
- isadma_unmap(di->addr, di->nbytes, 1, di->phys);
- di->active = 0;
- di->bounced = 0;
+int
+isa_dmamem_map(isadev, chan, addr, size, kvap, flags)
+ struct device *isadev;
+ int chan;
+ bus_addr_t addr;
+ bus_size_t size;
+ caddr_t *kvap;
+ int flags;
+{
+ struct isa_softc *sc = (struct isa_softc *)isadev;
+ bus_dma_segment_t seg;
+
+ if (chan < 0 || chan > 7) {
+ printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
+ panic("isa_dmamem_map");
+ }
+
+ seg.ds_addr = addr;
+ seg.ds_len = size;
+
+ return (bus_dmamem_map(sc->sc_dmat, &seg, 1, size, kvap, flags));
+}
+
+void
+isa_dmamem_unmap(isadev, chan, kva, size)
+ struct device *isadev;
+ int chan;
+ caddr_t kva;
+ size_t size;
+{
+ struct isa_softc *sc = (struct isa_softc *)isadev;
+
+ if (chan < 0 || chan > 7) {
+ printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
+ panic("isa_dmamem_unmap");
+ }
+
+ bus_dmamem_unmap(sc->sc_dmat, kva, size);
+}
+
+int
+isa_dmamem_mmap(isadev, chan, addr, size, off, prot, flags)
+ struct device *isadev;
+ int chan;
+ bus_addr_t addr;
+ bus_size_t size;
+ int off, prot, flags;
+{
+ struct isa_softc *sc = (struct isa_softc *)isadev;
+ bus_dma_segment_t seg;
+
+ if (chan < 0 || chan > 7) {
+ printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
+ panic("isa_dmamem_mmap");
+ }
+
+ seg.ds_addr = addr;
+ seg.ds_len = size;
+
+ return (bus_dmamem_mmap(sc->sc_dmat, &seg, 1, off, prot, flags));
+}
+
+int
+isa_drq_isfree(isadev, chan)
+ struct device *isadev;
+ int chan;
+{
+ struct isa_softc *sc = (struct isa_softc *)isadev;
+ if (chan < 0 || chan > 7) {
+ printf("%s: bogus drq %d\n", sc->sc_dev.dv_xname, chan);
+ panic("isa_drq_isfree");
+ }
+ return ISA_DRQ_ISFREE(sc, chan);
+}
+
+void *
+isa_malloc(isadev, chan, size, pool, flags)
+ struct device *isadev;
+ int chan;
+ size_t size;
+ int pool;
+ int flags;
+{
+ bus_addr_t addr;
+ caddr_t kva;
+ int bflags;
+ struct isa_mem *m;
+
+ bflags = flags & M_WAITOK ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT;
+
+ if (isa_dmamem_alloc(isadev, chan, size, &addr, bflags))
+ return 0;
+ if (isa_dmamem_map(isadev, chan, addr, size, &kva, bflags)) {
+ isa_dmamem_free(isadev, chan, addr, size);
+ return 0;
+ }
+ m = malloc(sizeof(*m), pool, flags);
+ if (m == 0) {
+ isa_dmamem_unmap(isadev, chan, kva, size);
+ isa_dmamem_free(isadev, chan, addr, size);
+ return 0;
+ }
+ m->isadev = isadev;
+ m->chan = chan;
+ m->size = size;
+ m->addr = addr;
+ m->kva = kva;
+ m->next = isa_mem_head;
+ isa_mem_head = m;
+ return (void *)kva;
+}
+
+void
+isa_free(addr, pool)
+ void *addr;
+ int pool;
+{
+ struct isa_mem **mp, *m;
+ caddr_t kva = (caddr_t)addr;
+
+ for(mp = &isa_mem_head; *mp && (*mp)->kva != kva; mp = &(*mp)->next)
+ ;
+ m = *mp;
+ if (!m) {
+ printf("isa_free: freeing unallocted memory\n");
+ return;
+ }
+ *mp = m->next;
+ isa_dmamem_unmap(m->isadev, m->chan, kva, m->size);
+ isa_dmamem_free(m->isadev, m->chan, m->addr, m->size);
+ free(m, pool);
+}
+
+int
+isa_mappage(mem, off, prot)
+ void *mem;
+ int off;
+ int prot;
+{
+ struct isa_mem *m;
+
+ for(m = isa_mem_head; m && m->kva != (caddr_t)mem; m = m->next)
+ ;
+ if (!m) {
+ printf("isa_mappage: mapping unallocted memory\n");
+ return -1;
+ }
+ return (isa_dmamem_mmap(m->isadev, m->chan, m->addr, m->size, off,
+ prot, BUS_DMA_WAITOK));
}
diff --git a/sys/dev/isa/isadmareg.h b/sys/dev/isa/isadmareg.h
index e26bf8f808d..5d9fb8dce5b 100644
--- a/sys/dev/isa/isadmareg.h
+++ b/sys/dev/isa/isadmareg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: isadmareg.h,v 1.4 1997/11/07 08:07:02 niklas Exp $ */
+/* $OpenBSD: isadmareg.h,v 1.5 1998/01/20 18:40:30 niklas Exp $ */
/* $NetBSD: isadmareg.h,v 1.4 1995/06/28 04:31:48 cgd Exp $ */
#include <dev/ic/i8237reg.h>
@@ -6,17 +6,21 @@
/*
* Register definitions for DMA controller 1 (channels 0..3):
*/
-#define DMA1_CHN(c) (IO_DMA1 + 1*(2*(c))) /* addr reg for channel c */
-#define DMA1_SR (IO_DMA1 + 1*8) /* status register */
-#define DMA1_SMSK (IO_DMA1 + 1*10) /* single mask register */
-#define DMA1_MODE (IO_DMA1 + 1*11) /* mode register */
-#define DMA1_FFC (IO_DMA1 + 1*12) /* clear first/last FF */
+#define DMA1_CHN(c) (1*(2*(c))) /* addr reg for channel c */
+#define DMA1_SR (1*8) /* status register */
+#define DMA1_SMSK (1*10) /* single mask register */
+#define DMA1_MODE (1*11) /* mode register */
+#define DMA1_FFC (1*12) /* clear first/last FF */
+
+#define DMA1_IOSIZE (1*12)
/*
* Register definitions for DMA controller 2 (channels 4..7):
*/
-#define DMA2_CHN(c) (IO_DMA2 + 2*(2*(c))) /* addr reg for channel c */
-#define DMA2_SR (IO_DMA2 + 2*8) /* status register */
-#define DMA2_SMSK (IO_DMA2 + 2*10) /* single mask register */
-#define DMA2_MODE (IO_DMA2 + 2*11) /* mode register */
-#define DMA2_FFC (IO_DMA2 + 2*12) /* clear first/last FF */
+#define DMA2_CHN(c) (2*(2*(c))) /* addr reg for channel c */
+#define DMA2_SR (2*8) /* status register */
+#define DMA2_SMSK (2*10) /* single mask register */
+#define DMA2_MODE (2*11) /* mode register */
+#define DMA2_FFC (2*12) /* clear first/last FF */
+
+#define DMA2_IOSIZE (2*12)
diff --git a/sys/dev/isa/isadmavar.h b/sys/dev/isa/isadmavar.h
index 3e8a153632b..318d85d14bb 100644
--- a/sys/dev/isa/isadmavar.h
+++ b/sys/dev/isa/isadmavar.h
@@ -1,12 +1,52 @@
-/* $OpenBSD: isadmavar.h,v 1.10 1997/12/25 12:06:48 downsj Exp $ */
-/* $NetBSD: isadmavar.h,v 1.4 1996/03/01 04:08:46 mycroft Exp $ */
+/* $OpenBSD: isadmavar.h,v 1.11 1998/01/20 18:40:31 niklas Exp $ */
+/* $NetBSD: isadmavar.h,v 1.10 1997/08/04 22:13:33 augustss Exp $ */
-#define DMAMODE_WRITE 0
-#define DMAMODE_READ 1
-#define DMAMODE_LOOP 2
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/* XXX for now... */
+#ifndef __ISADMA_COMPAT
+#define __ISADMA_COMPAT
+#endif /* __ISADMA_COMPAT */
-#define ISADMA_START_READ DMAMODE_READ /* read from device */
-#define ISADMA_START_WRITE DMAMODE_WRITE /* write to device */
+#ifdef __ISADMA_COMPAT
+
+/* XXX ugly.. but it's a deprecated API that uses it so it will go.. */
+extern struct device *isa_dev;
#define ISADMA_MAP_WAITOK 0x0001 /* OK for isadma_map to sleep */
#define ISADMA_MAP_BOUNCE 0x0002 /* use bounce buffer if necessary */
@@ -17,6 +57,7 @@
struct isadma_seg { /* a physical contiguous segment */
vm_offset_t addr; /* address of this segment */
vm_size_t length; /* length of this segment (bytes) */
+ bus_dmamap_t dmam; /* DMA handle for bus_dma routines. */
};
int isadma_map __P((caddr_t, vm_size_t, struct isadma_seg *, int));
@@ -24,22 +65,48 @@ void isadma_unmap __P((caddr_t, vm_size_t, int, struct isadma_seg *));
void isadma_copytobuf __P((caddr_t, vm_size_t, int, struct isadma_seg *));
void isadma_copyfrombuf __P((caddr_t, vm_size_t, int, struct isadma_seg *));
-int isadma_acquire __P((int));
-void isadma_release __P((int));
-void isadma_cascade __P((int));
-void isadma_start __P((caddr_t, vm_size_t, int, int));
-void isadma_abort __P((int));
-int isadma_finished __P((int));
-void isadma_done __P((int));
+#define isadma_acquire(c) isa_dma_acquire(isa_dev, (c))
+#define isadma_release(c) isa_dma_release(isa_dev, (c))
+#define isadma_cascade(c) isa_dmacascade(isa_dev, (c))
+#define isadma_start(a, s, c, f) \
+ isa_dmastart(isa_dev, (c), (a), (s), 0, (f), BUS_DMA_WAITOK|BUS_DMA_BUS1)
+#define isadma_abort(c) isa_dmaabort(isa_dev, (c))
+#define isadma_finished(c) isa_dmafinished(isa_dev, (c))
+#define isadma_done(c) isa_dmadone(isa_dev, (c))
-/*
- * XXX these are needed until all drivers have been cleaned up
- */
+#endif /* __ISADMA_COMPAT */
+
+#define MAX_ISADMA 65536
+
+#define DMAMODE_WRITE 0
+#define DMAMODE_READ 1
+#define DMAMODE_LOOP 2
+
+struct proc;
+
+void isa_dmacascade __P((struct device *, int));
+
+int isa_dmamap_create __P((struct device *, int, bus_size_t, int));
+void isa_dmamap_destroy __P((struct device *, int));
+
+int isa_dmastart __P((struct device *, int, void *, bus_size_t,
+ struct proc *, int, int));
+void isa_dmaabort __P((struct device *, int));
+bus_size_t isa_dmacount __P((struct device *, int));
+int isa_dmafinished __P((struct device *, int));
+void isa_dmadone __P((struct device *, int));
+
+int isa_dmamem_alloc __P((struct device *, int, bus_size_t,
+ bus_addr_t *, int));
+void isa_dmamem_free __P((struct device *, int, bus_addr_t, bus_size_t));
+int isa_dmamem_map __P((struct device *, int, bus_addr_t, bus_size_t,
+ caddr_t *, int));
+void isa_dmamem_unmap __P((struct device *, int, caddr_t, size_t));
+int isa_dmamem_mmap __P((struct device *, int, bus_addr_t, bus_size_t,
+ int, int, int));
+
+int isa_drq_isfree __P((struct device *, int));
-#define isa_dma_acquire(c) isadma_acquire(c)
-#define isa_dma_release(c) isadma_release(c)
-#define isa_dmacascade(c) isadma_cascade((c))
-#define isa_dmastart(f, a, s, c) isadma_start((a), (s), (c), (f))
-#define isa_dmaabort(c) isadma_abort((c))
-#define isa_dmafinished(c) isadma_finished((c))
-#define isa_dmadone(f, a, s, c) isadma_done((c))
+void *isa_malloc __P((struct device *, int, size_t, int, int));
+void isa_free __P((void *, int));
+int isa_mappage __P((void *, int, int));
diff --git a/sys/dev/isa/isapnp.c b/sys/dev/isa/isapnp.c
index 790bffde6cf..368d5669472 100644
--- a/sys/dev/isa/isapnp.c
+++ b/sys/dev/isa/isapnp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: isapnp.c,v 1.16 1997/12/30 07:00:39 deraadt Exp $ */
+/* $OpenBSD: isapnp.c,v 1.17 1998/01/20 18:40:31 niklas Exp $ */
/* $NetBSD: isapnp.c,v 1.9.4.3 1997/10/29 00:40:43 thorpej Exp $ */
/*
@@ -838,6 +838,7 @@ isapnp_attach(parent, self, aux)
sc->sc_iot = ia->ia_iot;
sc->sc_memt = ia->ia_memt;
+ sc->sc_dmat = ia->ia_dmat;
sc->sc_ncards = 0;
if (isapnp_map(sc))
@@ -888,6 +889,7 @@ isapnp_attach(parent, self, aux)
lpa->ia_ic = ia->ia_ic;
lpa->ia_iot = ia->ia_iot;
lpa->ia_memt = ia->ia_memt;
+ lpa->ia_dmat = ia->ia_dmat;
lpa->ia_delaybah = ia->ia_delaybah;
isapnp_write_reg(sc, ISAPNP_ACTIVATE, 1);
diff --git a/sys/dev/isa/isavar.h b/sys/dev/isa/isavar.h
index 98e61769981..a6ef11c2547 100644
--- a/sys/dev/isa/isavar.h
+++ b/sys/dev/isa/isavar.h
@@ -1,6 +1,42 @@
-/* $OpenBSD: isavar.h,v 1.26 1997/12/25 13:18:07 downsj Exp $ */
-/* $NetBSD: isavar.h,v 1.24 1996/10/21 22:41:11 thorpej Exp $ */
-/* $NetBSD: isapnpvar.h,v 1.5.4.2 1997/10/29 00:40:49 thorpej Exp $ */
+/* $OpenBSD: isavar.h,v 1.27 1998/01/20 18:40:33 niklas Exp $ */
+/* $NetBSD: isavar.h,v 1.26 1997/06/06 23:43:57 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1997 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
+ * NASA Ames Research Center.
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
/*
* Copyright (c) 1996 Christos Zoulas. All rights reserved.
@@ -77,6 +113,10 @@
#include <sys/queue.h>
#include <machine/bus.h>
+#ifndef NISADMA
+#include "isadma.h"
+#endif
+
/*
* Structures and definitions needed by the machine-dependent header.
*/
@@ -154,6 +194,9 @@ struct isapnp_softc {
int sc_read_port;
bus_space_tag_t sc_iot;
bus_space_tag_t sc_memt;
+#if NISADMA > 0
+ bus_dma_tag_t sc_dmat;
+#endif
bus_space_handle_t sc_addr_ioh;
bus_space_handle_t sc_wrdata_ioh;
bus_space_handle_t sc_read_ioh;
@@ -192,6 +235,9 @@ struct isabus_attach_args {
char *iba_busname; /* XXX should be common */
bus_space_tag_t iba_iot; /* isa i/o space tag */
bus_space_tag_t iba_memt; /* isa mem space tag */
+#if NISADMA > 0
+ bus_dma_tag_t iba_dmat; /* isa DMA tag */
+#endif
isa_chipset_tag_t iba_ic;
};
@@ -202,7 +248,9 @@ struct isa_attach_args {
struct device *ia_isa; /* isa device */
bus_space_tag_t ia_iot; /* isa i/o space tag */
bus_space_tag_t ia_memt; /* isa mem space tag */
-
+#if NISADMA > 0
+ bus_dma_tag_t ia_dmat; /* DMA tag */
+#endif
bus_space_handle_t ia_delaybah; /* i/o handle for `delay port' */
isa_chipset_tag_t ia_ic;
@@ -272,9 +320,34 @@ struct isa_softc {
bus_space_tag_t sc_iot; /* isa io space tag */
bus_space_tag_t sc_memt; /* isa mem space tag */
+#if NISADMA > 0
+ bus_dma_tag_t sc_dmat; /* isa DMA tag */
+#endif /* NISADMA > 0 */
isa_chipset_tag_t sc_ic;
+#if NISADMA > 0
+ /*
+ * Bitmap representing the DRQ channels available
+ * for ISA.
+ */
+ int sc_drqmap;
+#define sc_drq sc_drqmap /* XXX compatibility mode */
+
+ bus_space_handle_t sc_dma1h; /* i/o handle for DMA controller #1 */
+ bus_space_handle_t sc_dma2h; /* i/o handle for DMA controller #2 */
+ bus_space_handle_t sc_dmapgh; /* i/o handle for DMA page registers */
+
+ /*
+ * DMA maps used for the 8 DMA channels.
+ */
+ bus_dmamap_t sc_dmamaps[8];
+ vm_size_t sc_dmalength[8];
+
+ int sc_dmareads; /* state for isa_dmadone() */
+ int sc_dmafinished; /* DMA completion state */
+#endif /* NISADMA > 0 */
+
/*
* This i/o handle is used to map port 0x84, which is
* read to provide a 1.25us delay. This access handle
@@ -282,25 +355,16 @@ struct isa_softc {
* via isa_attach_args.
*/
bus_space_handle_t sc_delaybah;
-
- int8_t sc_drq; /* DRQ usage tracking */
};
-/*
- * Macros for sc_drq access.
- */
-#ifdef DIAGNOSTIC
-void isa_drq_alloc __P((void *, int));
-void isa_drq_free __P((void *, int));
-int isa_drq_isfree __P((void *, int));
-#else
-#define isa_drq_alloc(_sc, _drq) \
- (((struct isa_softc *)(_sc))->sc_drq |= (1 << (_drq)))
-#define isa_drq_free(_sc, _drq) \
- (((struct isa_softc *)(_sc))->sc_drq &= ~(1 << (_drq)))
-#define isa_drq_isfree(_sc, _drq) \
- !((((struct isa_softc *)(_sc))->sc_drq << (_drq)) & 1)
-#endif /* DIAGNOSTIC */
+#define ISA_DRQ_ISFREE(isadev, drq) \
+ ((((struct isa_softc *)(isadev))->sc_drqmap & (1 << (drq))) == 0)
+
+#define ISA_DRQ_ALLOC(isadev, drq) \
+ ((struct isa_softc *)(isadev))->sc_drqmap |= (1 << (drq))
+
+#define ISA_DRQ_FREE(isadev, drq) \
+ ((struct isa_softc *)(isadev))->sc_drqmap &= ~(1 << (drq))
#define cf_iobase cf_loc[0]
#define cf_iosize cf_loc[1]
@@ -339,6 +403,12 @@ void isa_establish __P((struct isadev *, struct device *));
#endif
/*
+ * Some ISA devices (e.g. on a VLB) can perform 32-bit DMA. This
+ * flag is passed to bus_dmamap_create() to indicate that fact.
+ */
+#define ISABUS_DMA_32BIT BUS_DMA_BUS1
+
+/*
* ISA PnP prototypes and support macros.
*/
static __inline void isapnp_write_reg __P((struct isapnp_softc *, int, u_char));
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index b0fb4771696..83b98d0e78c 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: pci.c,v 1.10 1998/01/07 11:03:32 deraadt Exp $ */
-/* $NetBSD: pci.c,v 1.26 1996/12/05 01:25:30 cgd Exp $ */
+/* $OpenBSD: pci.c,v 1.11 1998/01/20 18:40:34 niklas Exp $ */
+/* $NetBSD: pci.c,v 1.31 1997/06/06 23:48:04 thorpej Exp $ */
/*
* Copyright (c) 1995, 1996 Christopher G. Demetriou. All rights reserved.
@@ -153,6 +153,7 @@ pciattach(parent, self, aux)
pa.pa_iot = iot;
pa.pa_memt = memt;
+ pa.pa_dmat = pba->pba_dmat;
pa.pa_pc = pc;
pa.pa_device = device;
pa.pa_function = function;
diff --git a/sys/dev/pci/pcivar.h b/sys/dev/pci/pcivar.h
index 96dadfdfaf3..5a8fb8f2f62 100644
--- a/sys/dev/pci/pcivar.h
+++ b/sys/dev/pci/pcivar.h
@@ -1,5 +1,5 @@
-/* $OpenBSD: pcivar.h,v 1.12 1997/10/11 11:14:16 pefo Exp $ */
-/* $NetBSD: pcivar.h,v 1.18 1996/12/01 21:02:18 leo Exp $ */
+/* $OpenBSD: pcivar.h,v 1.13 1998/01/20 18:40:36 niklas Exp $ */
+/* $NetBSD: pcivar.h,v 1.23 1997/06/06 23:48:05 thorpej Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
@@ -80,6 +80,7 @@ struct pcibus_attach_args {
char *pba_busname; /* XXX should be common */
bus_space_tag_t pba_iot; /* pci i/o space tag */
bus_space_tag_t pba_memt; /* pci mem space tag */
+ bus_dma_tag_t pba_dmat; /* DMA tag */
pci_chipset_tag_t pba_pc;
int pba_bus; /* PCI bus number */
@@ -98,6 +99,7 @@ struct pcibus_attach_args {
struct pci_attach_args {
bus_space_tag_t pa_iot; /* pci i/o space tag */
bus_space_tag_t pa_memt; /* pci mem space tag */
+ bus_dma_tag_t pa_dmat; /* DMA tag */
pci_chipset_tag_t pa_pc;
u_int pa_device;
diff --git a/sys/dev/pci/ppb.c b/sys/dev/pci/ppb.c
index ce1aef12184..7f36d890ee2 100644
--- a/sys/dev/pci/ppb.c
+++ b/sys/dev/pci/ppb.c
@@ -1,5 +1,5 @@
-/* $OpenBSD: ppb.c,v 1.6 1998/01/05 13:35:26 deraadt Exp $ */
-/* $NetBSD: ppb.c,v 1.12 1996/10/21 22:57:00 thorpej Exp $ */
+/* $OpenBSD: ppb.c,v 1.7 1998/01/20 18:40:36 niklas Exp $ */
+/* $NetBSD: ppb.c,v 1.16 1997/06/06 23:48:05 thorpej Exp $ */
/*
* Copyright (c) 1996 Christopher G. Demetriou. All rights reserved.
@@ -120,6 +120,7 @@ ppbattach(parent, self, aux)
pba.pba_busname = "pci";
pba.pba_iot = pa->pa_iot;
pba.pba_memt = pa->pa_memt;
+ pba.pba_dmat = pa->pa_dmat;
pba.pba_pc = pc;
pba.pba_bus = PPB_BUSINFO_SECONDARY(busdata);
pba.pba_intrswiz = pa->pa_intrswiz;