Prettify to make the code easier to follow.

While here remove the XXX comments I added for lastaddr
initialization, now that I can see what's going on.
This commit is contained in:
uwe 2008-05-03 23:45:40 +00:00
parent 7a18a3a01f
commit 83c6d7c82f
1 changed files with 106 additions and 121 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: bus_dma.c,v 1.3 2008/05/03 22:07:07 uwe Exp $ */ /* $NetBSD: bus_dma.c,v 1.4 2008/05/03 23:45:40 uwe Exp $ */
/* /*
* Copyright (c) 2005 NONAKA Kimihiro * Copyright (c) 2005 NONAKA Kimihiro
@ -26,7 +26,7 @@
*/ */
#include <sys/cdefs.h> #include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.3 2008/05/03 22:07:07 uwe Exp $"); __KERNEL_RCSID(0, "$NetBSD: bus_dma.c,v 1.4 2008/05/03 23:45:40 uwe Exp $");
#include <sys/param.h> #include <sys/param.h>
#include <sys/systm.h> #include <sys/systm.h>
@ -79,47 +79,42 @@ _bus_dmamap_create(bus_dma_tag_t t, bus_size_t size, int nsegments,
bus_dmamap_t map; bus_dmamap_t map;
void *mapstore; void *mapstore;
size_t mapsize; size_t mapsize;
int error;
DPRINTF(("%s: t = %p, size = %ld, nsegments = %d, maxsegsz = %ld," DPRINTF(("%s: t = %p, size = %ld, nsegments = %d, maxsegsz = %ld,"
" boundary = %ld, flags = %x\n", " boundary = %ld, flags = %x\n",
__func__, t, size, nsegments, maxsegsz, boundary, flags)); __func__, t, size, nsegments, maxsegsz, boundary, flags));
/* /*
* Allocate and initialize the DMA map. The end of the map * Allocate and initialize the DMA map. The end of the map is
* is a variable-sized array of segments, so we allocate enough * a variable-sized array of segments, so we allocate enough
* room for them in one shot. * room for them in one shot. bus_dmamap_t includes one
* bus_dma_segment_t already, hence the (nsegments - 1).
* *
* Note we don't preserve the WAITOK or NOWAIT flags. Preservation * Note that we don't preserve WAITOK and NOWAIT flags.
* of ALLOCNOW notifies others that we've reserved these resources, * Preservation of ALLOCNOW notifies others that we've
* and they are not to be freed. * reserved these resources, and they are not to be freed.
*
* The bus_dmamap_t includes one bus_dma_segment_t, hence
* the (nsegments - 1).
*/ */
error = 0; mapsize = sizeof(struct _bus_dmamap)
mapsize = sizeof(struct _bus_dmamap) + + (sizeof(bus_dma_segment_t) * (nsegments - 1));
(sizeof(bus_dma_segment_t) * (nsegments - 1)); mapstore = malloc(mapsize, M_DMAMAP, M_ZERO
if ((mapstore = malloc(mapsize, M_DMAMAP, | (flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK);
(flags & BUS_DMA_NOWAIT) ? M_NOWAIT : M_WAITOK)) == NULL) if (mapstore == NULL)
return (ENOMEM); return ENOMEM;
DPRINTF(("%s: dmamp = %p\n", __func__, mapstore)); DPRINTF(("%s: dmamp = %p\n", __func__, mapstore));
memset(mapstore, 0, mapsize);
map = (bus_dmamap_t)mapstore; map = (bus_dmamap_t)mapstore;
map->_dm_size = size; map->_dm_size = size;
map->_dm_segcnt = nsegments; map->_dm_segcnt = nsegments;
map->_dm_maxsegsz = maxsegsz; map->_dm_maxsegsz = maxsegsz;
map->_dm_boundary = boundary; map->_dm_boundary = boundary;
map->_dm_flags = flags & ~(BUS_DMA_WAITOK|BUS_DMA_NOWAIT); map->_dm_flags = flags & ~(BUS_DMA_WAITOK | BUS_DMA_NOWAIT);
map->dm_mapsize = 0; /* no valid mappings */ map->dm_mapsize = 0; /* no valid mappings */
map->dm_nsegs = 0; map->dm_nsegs = 0;
*dmamp = map; *dmamp = map;
return 0;
return (0);
} }
/* /*
@ -171,40 +166,41 @@ _bus_dmamap_load_paddr(bus_dma_tag_t t, bus_dmamap_t map,
DPRINTF(("%s: sgsize = %d\n", __func__, sgsize)); DPRINTF(("%s: sgsize = %d\n", __func__, sgsize));
/* /*
* Insert chunk into a segment, coalescing with * Insert chunk coalescing with previous segment if possible.
* previous segment if possible.
*/ */
if (first) { if (first) {
/* first segment */
DPRINTF(("%s: first\n", __func__)); DPRINTF(("%s: first\n", __func__));
first = 0;
segs[nseg].ds_addr = SH3_PHYS_TO_P2SEG(paddr); segs[nseg].ds_addr = SH3_PHYS_TO_P2SEG(paddr);
segs[nseg].ds_len = sgsize; segs[nseg].ds_len = sgsize;
segs[nseg]._ds_vaddr = vaddr; segs[nseg]._ds_vaddr = vaddr;
first = 0; }
} else { else if ((paddr == lastaddr)
if ((paddr == lastaddr)
&& (segs[nseg].ds_len + sgsize <= map->_dm_maxsegsz) && (segs[nseg].ds_len + sgsize <= map->_dm_maxsegsz)
&& (map->_dm_boundary == 0 || && (map->_dm_boundary == 0 ||
(segs[nseg].ds_addr & bmask) == (paddr & bmask))) { (segs[nseg].ds_addr & bmask) == (paddr & bmask)))
/* coalesce */ {
DPRINTF(("%s: coalesce\n", __func__)); DPRINTF(("%s: coalesce\n", __func__));
segs[nseg].ds_len += sgsize;
} else { segs[nseg].ds_len += sgsize;
if (++nseg >= map->_dm_segcnt) { }
break; else {
} DPRINTF(("%s: new\n", __func__));
/* new segment */
DPRINTF(("%s: new\n", __func__)); ++nseg;
segs[nseg].ds_addr = SH3_PHYS_TO_P2SEG(paddr); if (nseg >= map->_dm_segcnt)
segs[nseg].ds_len = sgsize; break;
segs[nseg]._ds_vaddr = vaddr;
} segs[nseg].ds_addr = SH3_PHYS_TO_P2SEG(paddr);
segs[nseg].ds_len = sgsize;
segs[nseg]._ds_vaddr = vaddr;
} }
lastaddr = paddr + sgsize;
paddr += sgsize; paddr += sgsize;
vaddr += sgsize; vaddr += sgsize;
size -= sgsize; size -= sgsize;
lastaddr = paddr;
DPRINTF(("%s: lastaddr = 0x%08lx, paddr = 0x%08lx," DPRINTF(("%s: lastaddr = 0x%08lx, paddr = 0x%08lx,"
" vaddr = 0x%08lx, size = %d\n", " vaddr = 0x%08lx, size = %d\n",
@ -216,13 +212,10 @@ _bus_dmamap_load_paddr(bus_dma_tag_t t, bus_dmamap_t map,
*segp = nseg; *segp = nseg;
*lastaddrp = lastaddr; *lastaddrp = lastaddr;
/*
* Did we fit?
*/
if (size != 0) { if (size != 0) {
/* /*
* If there is a chained window, we will automatically * It didn't fit. If there is a chained window, we
* fall back to it. * will automatically fall back to it.
*/ */
return (EFBIG); /* XXX better return value here? */ return (EFBIG); /* XXX better return value here? */
} }
@ -252,34 +245,32 @@ _bus_bus_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
else else
pmap = pmap_kernel(); pmap = pmap_kernel();
*segp = 0;
first = 1; first = 1;
len = buflen; lastaddr = 0;
lastaddr = 0; /* XXX: uwe: gag gcc4, but this is WRONG!!! */
while (len > 0) {
/*
* Get the physical address for this segment.
*/
(void)pmap_extract(pmap, vaddr, &curaddr);
/* len = buflen;
* Compute the segment size, and adjust counts. while (len > 0) {
*/ bool mapped;
sgsize = PAGE_SIZE - ((u_long)vaddr & PGOFSET);
mapped = pmap_extract(pmap, vaddr, &curaddr);
if (!mapped)
return EFAULT;
sgsize = PAGE_SIZE - (vaddr & PGOFSET);
if (len < sgsize) if (len < sgsize)
sgsize = len; sgsize = len;
error = _bus_dmamap_load_paddr(t, map, curaddr, vaddr, sgsize, error = _bus_dmamap_load_paddr(t, map, curaddr, vaddr, sgsize,
segp, &lastaddr, first); segp, &lastaddr, first);
if (error) if (error)
return (error); return error;
vaddr += sgsize; vaddr += sgsize;
len -= sgsize; len -= sgsize;
first = 0; first = 0;
} }
return (0); return 0;
} }
/* /*
@ -299,26 +290,25 @@ _bus_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
" p = %p, flags = %x\n", " p = %p, flags = %x\n",
__func__, t, map, buf, buflen, p, flags)); __func__, t, map, buf, buflen, p, flags));
/* /* make sure that on error condition we return "no valid mappings" */
* Make sure on error condition we return "no valid mappings."
*/
map->dm_mapsize = 0; map->dm_mapsize = 0;
map->dm_nsegs = 0; map->dm_nsegs = 0;
if (buflen > map->_dm_size) if (buflen > map->_dm_size)
return (EINVAL); return (EINVAL);
lastaddr = 0; /* XXX: uwe: gag gcc4, but this is WRONG!!! */ seg = 0;
if ((addr >= SH3_P1SEG_BASE) && (addr + buflen <= SH3_P2SEG_END)) { if (SH3_P1SEG_BASE <= addr && addr + buflen <= SH3_P2SEG_END) {
bus_addr_t curaddr; bus_addr_t curaddr;
bus_size_t sgsize; bus_size_t sgsize;
bus_size_t len = buflen; bus_size_t len = buflen;
DPRINTF(("%s: P[12]SEG (0x%08lx)\n", __func__, addr)); DPRINTF(("%s: P[12]SEG (0x%08lx)\n", __func__, addr));
seg = 0;
first = 1; first = 1;
lastaddr = 0;
while (len > 0) { while (len > 0) {
curaddr = SH3_P1SEG_TO_PHYS(addr); curaddr = SH3_P1SEG_TO_PHYS(addr);
@ -326,30 +316,28 @@ _bus_dmamap_load(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
if (len < sgsize) if (len < sgsize)
sgsize = len; sgsize = len;
error = _bus_dmamap_load_paddr(t, map, curaddr, addr, error = _bus_dmamap_load_paddr(t, map,
sgsize, &seg, &lastaddr, first); curaddr, addr, sgsize,
&seg, &lastaddr, first);
if (error) if (error)
return (error); break;
addr += sgsize; addr += sgsize;
len -= sgsize; len -= sgsize;
first = 0; first = 0;
} }
}
map->dm_nsegs = seg + 1; else {
map->dm_mapsize = buflen; error = _bus_bus_dmamap_load_buffer(t, map, buf, buflen,
return (0); p, flags, &seg);
} }
error = _bus_bus_dmamap_load_buffer(t, map, buf, buflen, p, flags, if (error)
&seg); return (error);
if (error == 0) {
map->dm_nsegs = seg + 1;
map->dm_mapsize = buflen;
return (0);
}
return (error); map->dm_nsegs = seg + 1;
map->dm_mapsize = buflen;
return 0;
} }
/* /*
@ -368,9 +356,7 @@ _bus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m0,
DPRINTF(("%s: t = %p, map = %p, m0 = %p, flags = %x\n", DPRINTF(("%s: t = %p, map = %p, m0 = %p, flags = %x\n",
__func__, t, map, m0, flags)); __func__, t, map, m0, flags));
/* /* make sure that on error condition we return "no valid mappings" */
* Make sure on error condition we return "no valid mappings."
*/
map->dm_nsegs = 0; map->dm_nsegs = 0;
map->dm_mapsize = 0; map->dm_mapsize = 0;
@ -384,9 +370,9 @@ _bus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m0,
seg = 0; seg = 0;
first = 1; first = 1;
error = 0; lastaddr = 0;
lastaddr = 0; /* XXX: uwe: gag gcc4, but this is WRONG!!! */
for (m = m0; m != NULL && error == 0; m = m->m_next) { for (m = m0; m != NULL; m = m->m_next) {
paddr_t paddr; paddr_t paddr;
vaddr_t vaddr; vaddr_t vaddr;
int size; int size;
@ -398,17 +384,15 @@ _bus_dmamap_load_mbuf(bus_dma_tag_t t, bus_dmamap_t map, struct mbuf *m0,
paddr = (paddr_t)(PMAP_UNMAP_POOLPAGE(vaddr)); paddr = (paddr_t)(PMAP_UNMAP_POOLPAGE(vaddr));
size = m->m_len; size = m->m_len;
error = _bus_dmamap_load_paddr(t, map, paddr, vaddr, size, error = _bus_dmamap_load_paddr(t, map, paddr, vaddr, size,
&seg, &lastaddr, first); &seg, &lastaddr, first);
if (error)
return error;
first = 0; first = 0;
} }
if (error == 0) { map->dm_nsegs = seg + 1;
map->dm_nsegs = seg + 1; map->dm_mapsize = m0->m_pkthdr.len;
map->dm_mapsize = m0->m_pkthdr.len; return 0;
return (0);
}
return (error);
} }
/* /*
@ -624,8 +608,9 @@ _bus_dmamem_free(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs)
segs[curseg].ds_addr, segs[curseg].ds_len)); segs[curseg].ds_addr, segs[curseg].ds_len));
for (addr = segs[curseg].ds_addr; for (addr = segs[curseg].ds_addr;
addr < (segs[curseg].ds_addr + segs[curseg].ds_len); addr < (segs[curseg].ds_addr + segs[curseg].ds_len);
addr += PAGE_SIZE) { addr += PAGE_SIZE)
{
m = PHYS_TO_VM_PAGE(addr); m = PHYS_TO_VM_PAGE(addr);
DPRINTF(("%s: m = %p\n", __func__, m)); DPRINTF(("%s: m = %p\n", __func__, m));
TAILQ_INSERT_TAIL(&mlist, m, pageq); TAILQ_INSERT_TAIL(&mlist, m, pageq);
@ -640,7 +625,6 @@ int
_bus_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs, _bus_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs,
size_t size, void **kvap, int flags) size_t size, void **kvap, int flags)
{ {
const uvm_flag_t kmflags = (flags & BUS_DMA_NOWAIT) ? UVM_KMF_NOWAIT:0;
vaddr_t va; vaddr_t va;
bus_addr_t addr; bus_addr_t addr;
int curseg; int curseg;
@ -650,28 +634,29 @@ _bus_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs,
__func__, t, segs, nsegs, size, kvap, flags)); __func__, t, segs, nsegs, size, kvap, flags));
/* /*
* If we're only mapping 1 segment, use P2SEG, to avoid * If we're mapping only a single segment, use direct-mapped
* TLB thrashing. * va, to avoid thrashing the TLB.
*/ */
if (nsegs == 1) { if (nsegs == 1) {
if (flags & BUS_DMA_COHERENT) { if (flags & BUS_DMA_COHERENT)
*kvap = (void *)SH3_PHYS_TO_P2SEG(segs[0].ds_addr); *kvap = (void *)SH3_PHYS_TO_P2SEG(segs[0].ds_addr);
} else { else
*kvap = (void *)SH3_PHYS_TO_P1SEG(segs[0].ds_addr); *kvap = (void *)SH3_PHYS_TO_P1SEG(segs[0].ds_addr);
}
DPRINTF(("%s: addr = 0x%08lx, kva = %p\n", DPRINTF(("%s: addr = 0x%08lx, kva = %p\n",
__func__, segs[0].ds_addr, *kvap)); __func__, segs[0].ds_addr, *kvap));
return 0; return 0;
} }
/* Always round the size. */ /* Always round the size. */
size = round_page(size); size = round_page(size);
va = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_VAONLY | kmflags); va = uvm_km_alloc(kernel_map, size, 0, UVM_KMF_VAONLY
| (flags & BUS_DMA_NOWAIT) ? UVM_KMF_NOWAIT : 0);
if (va == 0) if (va == 0)
return (ENOMEM); return (ENOMEM);
*kvap = (void *)va;
for (curseg = 0; curseg < nsegs; curseg++) { for (curseg = 0; curseg < nsegs; curseg++) {
DPRINTF(("%s: segs[%d]: ds_addr = 0x%08lx, ds_len = %ld\n", DPRINTF(("%s: segs[%d]: ds_addr = 0x%08lx, ds_len = %ld\n",
__func__, curseg, __func__, curseg,
@ -679,42 +664,42 @@ _bus_dmamem_map(bus_dma_tag_t t, bus_dma_segment_t *segs, int nsegs,
for (addr = segs[curseg].ds_addr; for (addr = segs[curseg].ds_addr;
addr < segs[curseg].ds_addr + segs[curseg].ds_len; addr < segs[curseg].ds_addr + segs[curseg].ds_len;
addr += PAGE_SIZE, va += PAGE_SIZE, size -= PAGE_SIZE) { addr += PAGE_SIZE, va += PAGE_SIZE, size -= PAGE_SIZE)
if (size == 0) {
if (__predict_false(size == 0))
panic("_bus_dmamem_map: size botch"); panic("_bus_dmamem_map: size botch");
pmap_kenter_pa(va, addr, pmap_kenter_pa(va, addr,
VM_PROT_READ | VM_PROT_WRITE); VM_PROT_READ | VM_PROT_WRITE);
} }
} }
pmap_update(pmap_kernel());
pmap_update(pmap_kernel());
*kvap = (void *)va;
return (0); return (0);
} }
void void
_bus_dmamem_unmap(bus_dma_tag_t t, void *kva, size_t size) _bus_dmamem_unmap(bus_dma_tag_t t, void *kva, size_t size)
{ {
vaddr_t vaddr = (vaddr_t)kva;
DPRINTF(("%s: t = %p, kva = %p, size = %d\n", DPRINTF(("%s: t = %p, kva = %p, size = %d\n",
__func__, t, kva, size)); __func__, t, kva, size));
#ifdef DIAGNOSTIC #ifdef DIAGNOSTIC
if ((u_long)kva & PAGE_MASK) if (vaddr & PAGE_MASK)
panic("_bus_dmamem_unmap"); panic("_bus_dmamem_unmap");
#endif #endif
/* /* nothing to do if we mapped it via P1SEG or P2SEG */
* Nothing to do if we mapped it with P[12]SEG. if (SH3_P1SEG_BASE <= vaddr && vaddr <= SH3_P2SEG_END)
*/
if ((kva >= (void *)SH3_P1SEG_BASE)
&& (kva <= (void *)SH3_P2SEG_END)) {
return; return;
}
size = round_page(size); size = round_page(size);
pmap_kremove((vaddr_t)kva, size); pmap_kremove(vaddr, size);
pmap_update(pmap_kernel()); pmap_update(pmap_kernel());
uvm_km_free(kernel_map, (vaddr_t)kva, size, UVM_KMF_VAONLY); uvm_km_free(kernel_map, vaddr, size, UVM_KMF_VAONLY);
} }
paddr_t paddr_t