diff options
author | Dale S. Rahn <rahnds@cvs.openbsd.org> | 2000-03-31 04:12:59 +0000 |
---|---|---|
committer | Dale S. Rahn <rahnds@cvs.openbsd.org> | 2000-03-31 04:12:59 +0000 |
commit | c80b972a2eed5cc93d8669d251affb741e773ba3 (patch) | |
tree | 73cfdbca61376fbe7a3fad4079fa9407d76e6aba /sys | |
parent | a39e0144860cb9b8c85274568d2d45db7a45825e (diff) |
implement dmamap_load (stolen from i386) for powerpc.
This is required for USB support.
(with this a a bit more the root hub configures).
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/powerpc/powerpc/dma.c | 101 |
1 files changed, 94 insertions, 7 deletions
diff --git a/sys/arch/powerpc/powerpc/dma.c b/sys/arch/powerpc/powerpc/dma.c index faba6dd7f78..cb7d5c74f37 100644 --- a/sys/arch/powerpc/powerpc/dma.c +++ b/sys/arch/powerpc/powerpc/dma.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dma.c,v 1.1 2000/03/20 07:05:52 rahnds Exp $ */ +/* $OpenBSD: dma.c,v 1.2 2000/03/31 04:12:58 rahnds Exp $ */ /* * Copyright (c) 1998 Michael Shalayeff @@ -92,16 +92,99 @@ _dmamap_destroy(v, 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 -_dmamap_load(v, map, addr, size, p, flags) - void *v; +_dmamap_load(t, map, buf, buflen, p, flags) + void * t; bus_dmamap_t map; - void *addr; - bus_size_t size; + void *buf; + bus_size_t buflen; struct proc *p; int flags; { - panic("_dmamap_load: not implemented"); + bus_size_t sgsize; + bus_addr_t curaddr, lastaddr, baddr, bmask; + 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); + + if (p != NULL) + pmap = p->p_vmspace->vm_map.pmap; + else + pmap = pmap_kernel(); + + lastaddr = ~0; /* XXX gcc */ + bmask = ~(map->_dm_boundary - 1); + + for (first = 1, seg = 0; buflen > 0; ) { + /* + * 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; + + /* + * Make sure we don't cross any boundaries. + */ + if (map->_dm_boundary > 0) { + baddr = (curaddr + map->_dm_boundary) & bmask; + if (sgsize > (baddr - curaddr)) + sgsize = (baddr - curaddr); + } + + /* + * 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_boundary == 0 || + (map->dm_segs[seg].ds_addr & bmask) == + (curaddr & bmask))) + map->dm_segs[seg].ds_len += sgsize; + else { + if (++seg >= map->_dm_segcnt) + break; + 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); } int @@ -173,16 +256,20 @@ _dmamem_alloc(v, size, alignment, boundary, segs, nsegs, rsegs, flags) va = uvm_pagealloc_contig(size, VM_MIN_KERNEL_ADDRESS, VM_MAX_KERNEL_ADDRESS, NBPG); #else +# if 0 vm_page_alloc_memory(size, VM_MIN_KERNEL_ADDRESS, VM_MAX_KERNEL_ADDRESS, alignment, boundary, (void *)&va, nsegs, (flags & BUS_DMA_NOWAIT)); +# else + va = kmem_alloc_wait(phys_map, NBPG); /* XXX */ +# endif #endif if (va == NULL) return (ENOMEM); segs[0].ds_addr = va; segs[0].ds_len = size; - *rsegs = 1; + *rsegs = nsegs; #if 0 /* XXX for now */ |