* Use _bus_dmamap_load_buffer() and respect maxsegsz in bus_dmamap_load().

Ignoring maxsegsz may lead to fatal data corruption for some devices.
ex. SBP-2/FireWire
We should apply this change to other platforms except for sparc64.

MFC after: 1 week
This commit is contained in:
Hidetoshi Shimokawa 2003-04-14 04:19:42 +00:00
parent de5ef10142
commit f5270431be
2 changed files with 60 additions and 238 deletions

View file

@ -406,125 +406,6 @@ bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
bus_dmamem_free_size(dmat, vaddr, map, dmat->maxsize);
}
#define BUS_DMAMAP_NSEGS ((64 * 1024) / PAGE_SIZE + 1)
/*
* Map the buffer buf into bus space using the dmamap map.
*/
int
bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
bus_size_t buflen, bus_dmamap_callback_t *callback,
void *callback_arg, int flags)
{
vm_offset_t vaddr;
vm_paddr_t paddr;
#ifdef __GNUC__
bus_dma_segment_t dm_segments[dmat->nsegments];
#else
bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS];
#endif
bus_dma_segment_t *sg;
int seg;
int error;
vm_paddr_t nextpaddr;
if (map == NULL)
map = &nobounce_dmamap;
error = 0;
/*
* If we are being called during a callback, pagesneeded will
* be non-zero, so we can avoid doing the work twice.
*/
if (dmat->lowaddr < ptoa((vm_paddr_t)Maxmem) &&
map->pagesneeded == 0) {
vm_offset_t vendaddr;
/*
* Count the number of bounce pages
* needed in order to complete this transfer
*/
vaddr = trunc_page((vm_offset_t)buf);
vendaddr = (vm_offset_t)buf + buflen;
while (vaddr < vendaddr) {
paddr = pmap_kextract(vaddr);
if (run_filter(dmat, paddr) != 0) {
map->pagesneeded++;
}
vaddr += PAGE_SIZE;
}
}
/* Reserve Necessary Bounce Pages */
if (map->pagesneeded != 0) {
mtx_lock(&bounce_lock);
if (reserve_bounce_pages(dmat, map, 1) != 0) {
/* Queue us for resources */
map->dmat = dmat;
map->buf = buf;
map->buflen = buflen;
map->callback = callback;
map->callback_arg = callback_arg;
STAILQ_INSERT_TAIL(&bounce_map_waitinglist, map, links);
mtx_unlock(&bounce_lock);
return (EINPROGRESS);
}
mtx_unlock(&bounce_lock);
}
vaddr = (vm_offset_t)buf;
sg = &dm_segments[0];
seg = 1;
sg->ds_len = 0;
nextpaddr = 0;
do {
bus_size_t size;
paddr = pmap_kextract(vaddr);
size = PAGE_SIZE - (paddr & PAGE_MASK);
if (size > buflen)
size = buflen;
if (map->pagesneeded != 0 && run_filter(dmat, paddr)) {
paddr = add_bounce_page(dmat, map, vaddr, size);
}
if (sg->ds_len == 0) {
sg->ds_addr = paddr;
sg->ds_len = size;
} else if (paddr == nextpaddr) {
sg->ds_len += size;
} else {
/* Go to the next segment */
sg++;
seg++;
if (seg > dmat->nsegments)
break;
sg->ds_addr = paddr;
sg->ds_len = size;
}
vaddr += size;
nextpaddr = paddr + size;
buflen -= size;
} while (buflen > 0);
if (buflen != 0) {
printf("bus_dmamap_load: Too many segs! buf_len = 0x%lx\n",
(u_long)buflen);
error = EFBIG;
}
(*callback)(callback_arg, dm_segments, seg, error);
return (0);
}
/*
* Utility function to load a linear buffer. lastaddrp holds state
* between invocations (for multiple-buffer loads). segp contains
@ -657,6 +538,36 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dmat,
return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */
}
#define BUS_DMAMAP_NSEGS ((64 * 1024) / PAGE_SIZE + 1)
/*
* Map the buffer buf into bus space using the dmamap map.
*/
int
bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
bus_size_t buflen, bus_dmamap_callback_t *callback,
void *callback_arg, int flags)
{
#ifdef __GNUC__
bus_dma_segment_t dm_segments[dmat->nsegments];
#else
bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS];
#endif
bus_addr_t lastaddr = 0;
int error, nsegs = 0;
error = _bus_dmamap_load_buffer(dmat, map, dm_segments, buf, buflen,
NULL, flags, &lastaddr, &nsegs, 1);
if (error)
(*callback)(callback_arg, dm_segments, 0, error);
else
(*callback)(callback_arg, dm_segments, nsegs + 1, 0);
return (0);
}
/*
* Like _bus_dmamap_load(), but for mbufs.
*/

View file

@ -406,125 +406,6 @@ bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
bus_dmamem_free_size(dmat, vaddr, map, dmat->maxsize);
}
#define BUS_DMAMAP_NSEGS ((64 * 1024) / PAGE_SIZE + 1)
/*
* Map the buffer buf into bus space using the dmamap map.
*/
int
bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
bus_size_t buflen, bus_dmamap_callback_t *callback,
void *callback_arg, int flags)
{
vm_offset_t vaddr;
vm_paddr_t paddr;
#ifdef __GNUC__
bus_dma_segment_t dm_segments[dmat->nsegments];
#else
bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS];
#endif
bus_dma_segment_t *sg;
int seg;
int error;
vm_paddr_t nextpaddr;
if (map == NULL)
map = &nobounce_dmamap;
error = 0;
/*
* If we are being called during a callback, pagesneeded will
* be non-zero, so we can avoid doing the work twice.
*/
if (dmat->lowaddr < ptoa((vm_paddr_t)Maxmem) &&
map->pagesneeded == 0) {
vm_offset_t vendaddr;
/*
* Count the number of bounce pages
* needed in order to complete this transfer
*/
vaddr = trunc_page((vm_offset_t)buf);
vendaddr = (vm_offset_t)buf + buflen;
while (vaddr < vendaddr) {
paddr = pmap_kextract(vaddr);
if (run_filter(dmat, paddr) != 0) {
map->pagesneeded++;
}
vaddr += PAGE_SIZE;
}
}
/* Reserve Necessary Bounce Pages */
if (map->pagesneeded != 0) {
mtx_lock(&bounce_lock);
if (reserve_bounce_pages(dmat, map, 1) != 0) {
/* Queue us for resources */
map->dmat = dmat;
map->buf = buf;
map->buflen = buflen;
map->callback = callback;
map->callback_arg = callback_arg;
STAILQ_INSERT_TAIL(&bounce_map_waitinglist, map, links);
mtx_unlock(&bounce_lock);
return (EINPROGRESS);
}
mtx_unlock(&bounce_lock);
}
vaddr = (vm_offset_t)buf;
sg = &dm_segments[0];
seg = 1;
sg->ds_len = 0;
nextpaddr = 0;
do {
bus_size_t size;
paddr = pmap_kextract(vaddr);
size = PAGE_SIZE - (paddr & PAGE_MASK);
if (size > buflen)
size = buflen;
if (map->pagesneeded != 0 && run_filter(dmat, paddr)) {
paddr = add_bounce_page(dmat, map, vaddr, size);
}
if (sg->ds_len == 0) {
sg->ds_addr = paddr;
sg->ds_len = size;
} else if (paddr == nextpaddr) {
sg->ds_len += size;
} else {
/* Go to the next segment */
sg++;
seg++;
if (seg > dmat->nsegments)
break;
sg->ds_addr = paddr;
sg->ds_len = size;
}
vaddr += size;
nextpaddr = paddr + size;
buflen -= size;
} while (buflen > 0);
if (buflen != 0) {
printf("bus_dmamap_load: Too many segs! buf_len = 0x%lx\n",
(u_long)buflen);
error = EFBIG;
}
(*callback)(callback_arg, dm_segments, seg, error);
return (0);
}
/*
* Utility function to load a linear buffer. lastaddrp holds state
* between invocations (for multiple-buffer loads). segp contains
@ -657,6 +538,36 @@ _bus_dmamap_load_buffer(bus_dma_tag_t dmat,
return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */
}
#define BUS_DMAMAP_NSEGS ((64 * 1024) / PAGE_SIZE + 1)
/*
* Map the buffer buf into bus space using the dmamap map.
*/
int
bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
bus_size_t buflen, bus_dmamap_callback_t *callback,
void *callback_arg, int flags)
{
#ifdef __GNUC__
bus_dma_segment_t dm_segments[dmat->nsegments];
#else
bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS];
#endif
bus_addr_t lastaddr = 0;
int error, nsegs = 0;
error = _bus_dmamap_load_buffer(dmat, map, dm_segments, buf, buflen,
NULL, flags, &lastaddr, &nsegs, 1);
if (error)
(*callback)(callback_arg, dm_segments, 0, error);
else
(*callback)(callback_arg, dm_segments, nsegs + 1, 0);
return (0);
}
/*
* Like _bus_dmamap_load(), but for mbufs.
*/