diff options
author | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1998-01-20 18:40:37 +0000 |
---|---|---|
committer | Niklas Hallqvist <niklas@cvs.openbsd.org> | 1998-01-20 18:40:37 +0000 |
commit | e4232757b30346a182214fb65da8a76f2edb7b24 (patch) | |
tree | 5c1b89b92ef8c67dfa2d0f3a078804042a1555ee /sys | |
parent | 0a8f2cc87f99deec610ef91696850a249bd8fb81 (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.h | 6 | ||||
-rw-r--r-- | sys/arch/arc/include/bus.h | 6 | ||||
-rw-r--r-- | sys/arch/i386/eisa/eisa_machdep.c | 63 | ||||
-rw-r--r-- | sys/arch/i386/eisa/eisa_machdep.h | 6 | ||||
-rw-r--r-- | sys/arch/i386/i386/machdep.c | 484 | ||||
-rw-r--r-- | sys/arch/i386/i386/mainbus.c | 13 | ||||
-rw-r--r-- | sys/arch/i386/i386/pmap.c | 16 | ||||
-rw-r--r-- | sys/arch/i386/i386/pmap.old.c | 16 | ||||
-rw-r--r-- | sys/arch/i386/include/bus.h | 210 | ||||
-rw-r--r-- | sys/arch/i386/isa/isa_machdep.c | 844 | ||||
-rw-r--r-- | sys/arch/i386/isa/isa_machdep.h | 67 | ||||
-rw-r--r-- | sys/arch/i386/pci/pchb.c | 3 | ||||
-rw-r--r-- | sys/arch/i386/pci/pci_machdep.c | 65 | ||||
-rw-r--r-- | sys/arch/i386/pci/pci_machdep.h | 6 | ||||
-rw-r--r-- | sys/arch/powerpc/include/bus.h | 6 | ||||
-rw-r--r-- | sys/dev/eisa/eisavar.h | 6 | ||||
-rw-r--r-- | sys/dev/isa/isa.c | 105 | ||||
-rw-r--r-- | sys/dev/isa/isadma.c | 795 | ||||
-rw-r--r-- | sys/dev/isa/isadmareg.h | 26 | ||||
-rw-r--r-- | sys/dev/isa/isadmavar.h | 115 | ||||
-rw-r--r-- | sys/dev/isa/isapnp.c | 4 | ||||
-rw-r--r-- | sys/dev/isa/isavar.h | 112 | ||||
-rw-r--r-- | sys/dev/pci/pci.c | 5 | ||||
-rw-r--r-- | sys/dev/pci/pcivar.h | 6 | ||||
-rw-r--r-- | sys/dev/pci/ppb.c | 5 |
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; |