Index: sys/i386/i386/busdma_machdep.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/busdma_machdep.c,v retrieving revision 1.46 diff -u -r1.46 busdma_machdep.c --- sys/i386/i386/busdma_machdep.c 2 Jun 2003 06:43:14 -0000 1.46 +++ sys/i386/i386/busdma_machdep.c 18 Jun 2003 14:17:27 -0000 @@ -71,6 +71,7 @@ bus_addr_t busaddr; /* Physical address */ vm_offset_t datavaddr; /* kva of client data */ bus_size_t datacount; /* client data count */ + bus_addr_t offset; /* offset in the map */ STAILQ_ENTRY(bounce_page) links; }; @@ -104,7 +105,8 @@ static int reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, int commit); static bus_addr_t add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, - vm_offset_t vaddr, bus_size_t size); + vm_offset_t vaddr, bus_size_t size, + bus_addr_t offset); static void free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage); static __inline int run_filter(bus_dma_tag_t dmat, bus_addr_t paddr); @@ -207,10 +209,10 @@ panic("bus_dma_tag_create: page reallocation " "not implemented"); } - if (ptoa(total_bpages) < maxsize) { + if (ptoa(total_bpages) < round_page(maxsize)) { int pages; - pages = atop(maxsize) - total_bpages; + pages = atop(round_page(maxsize)) - total_bpages; /* Add pages to our bounce pool */ if (alloc_bounce_pages(newtag, pages) < pages) @@ -297,8 +299,9 @@ panic("bus_dmamap_create: page reallocation " "not implemented"); } - pages = MAX(atop(dmat->maxsize), 1); + pages = atop(round_page(dmat->maxsize)); pages = MIN(maxpages - total_bpages, pages); + if (alloc_bounce_pages(dmat, pages) < pages) error = ENOMEM; @@ -406,7 +409,8 @@ int flags, bus_addr_t *lastaddrp, int *segp, - int first) + int first, + bus_addr_t *offsetp) { bus_size_t sgsize; bus_addr_t curaddr, lastaddr, baddr, bmask; @@ -498,7 +502,8 @@ } if (map->pagesneeded != 0 && run_filter(dmat, curaddr)) - curaddr = add_bounce_page(dmat, map, vaddr, sgsize); + curaddr = add_bounce_page(dmat, map, vaddr, sgsize, + *offsetp); /* * Insert chunk into a segment, coalescing with @@ -522,6 +527,7 @@ } } + *offsetp += sgsize; lastaddr = curaddr + sgsize; vaddr += sgsize; buflen -= sgsize; @@ -551,7 +557,7 @@ #else bus_dma_segment_t dm_segments[BUS_DMAMAP_NSEGS]; #endif - bus_addr_t lastaddr = 0; + bus_addr_t lastaddr = 0, offset = 0; int error, nsegs = 0; if (map != NULL) { @@ -561,7 +567,7 @@ } error = _bus_dmamap_load_buffer(dmat, map, dm_segments, buf, buflen, - NULL, flags, &lastaddr, &nsegs, 1); + NULL, flags, &lastaddr, &nsegs, 1, &offset); if (error == EINPROGRESS) return (error); @@ -571,7 +577,7 @@ else (*callback)(callback_arg, dm_segments, nsegs + 1, 0); - return (0); + return (error); } @@ -600,6 +606,7 @@ if (m0->m_pkthdr.len <= dmat->maxsize) { int first = 1; bus_addr_t lastaddr = 0; + bus_addr_t offset = 0; struct mbuf *m; for (m = m0; m != NULL && error == 0; m = m->m_next) { @@ -608,7 +615,7 @@ dm_segments, m->m_data, m->m_len, NULL, flags, &lastaddr, - &nsegs, first); + &nsegs, first, &offset); first = 0; } } @@ -636,6 +643,7 @@ int flags) { bus_addr_t lastaddr; + bus_addr_t offset; #ifdef __GNUC__ bus_dma_segment_t dm_segments[dmat->nsegments]; #else @@ -659,6 +667,7 @@ nsegs = 0; error = 0; first = 1; + offset = 0; for (i = 0; i < uio->uio_iovcnt && resid != 0 && !error; i++) { /* * Now at the first iovec to load. Load each iovec @@ -672,7 +681,8 @@ error = _bus_dmamap_load_buffer(dmat, map, dm_segments, addr, minlen, - td, flags, &lastaddr, &nsegs, first); + td, flags, &lastaddr, &nsegs, first, + &offset); first = 0; resid -= minlen; @@ -734,6 +744,75 @@ } } +/* + * Synchronize the part of the map starting at "offset" with length "len". + */ +void +_bus_dmamap_sync_size(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t offset, + bus_size_t len, bus_dmasync_op_t op) +{ + struct bounce_page *bpage; + bus_size_t slen; + bus_addr_t bend; + bus_addr_t end = offset + len; + bus_addr_t coff = 0; /* silence gcc */ + +#define bcopy_off(F, T, S, O) bcopy((void *)((char *)(F) + (O)), \ + (void *)((char *)(T) + (O)), (S)) + + if ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) { + /* + * Handle data bouncing. We might also + * want to add support for invalidating + * the caches on broken hardware + */ + + while (bpage != NULL) { + bend = bpage->offset + bpage->datacount; + if (bpage->offset <= offset) { + /* bpage starts below sync area */ + coff = offset - bpage->offset; + if (bend <= offset) + /* bpage entirly below */ + slen = 0; + else if (bend > end) + /* bpage larger */ + slen = len; + else + /* bpage ends in sync area */ + slen = bend - offset; + + } else if (bpage->offset < end) { + /* bpage starts in sync area */ + coff = 0; + if (bend <= end) + /* entirly within */ + slen = bpage->datacount; + else + /* bpage ends behind area */ + slen = end - bpage->offset; + } else + /* bpage entirely behind area */ + slen = 0; + + if (slen != 0) { + if (op & BUS_DMASYNC_PREWRITE) + bcopy_off(bpage->datavaddr, + bpage->vaddr, + slen, coff); + else if (op & BUS_DMASYNC_POSTREAD) + bcopy_off(bpage->vaddr, + bpage->datavaddr, + slen, coff); + } + + bpage = STAILQ_NEXT(bpage, links); + } + } + +#undef bcopy_off +} + static void init_bounce_pages(void *dummy __unused) { @@ -805,7 +884,7 @@ static bus_addr_t add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr, - bus_size_t size) + bus_size_t size, bus_addr_t offset) { struct bounce_page *bpage; @@ -832,6 +911,7 @@ bpage->datavaddr = vaddr; bpage->datacount = size; + bpage->offset = offset; STAILQ_INSERT_TAIL(&(map->bpages), bpage, links); return (bpage->busaddr); } Index: sys/i386/include/bus_dma.h =================================================================== RCS file: /home/ncvs/src/sys/i386/include/bus_dma.h,v retrieving revision 1.21 diff -u -r1.21 bus_dma.h --- sys/i386/include/bus_dma.h 30 May 2003 20:40:33 -0000 1.21 +++ sys/i386/include/bus_dma.h 18 Jun 2003 14:17:27 -0000 @@ -229,6 +229,11 @@ #define bus_dmamap_sync(dmat, dmamap, op) \ if ((dmamap) != NULL) \ _bus_dmamap_sync(dmat, dmamap, op) +void _bus_dmamap_sync_size(bus_dma_tag_t, bus_dmamap_t, + bus_addr_t, bus_size_t, bus_dmasync_op_t); +#define bus_dmamap_sync_size(dmat, dmamap, offset, len, op) \ + if ((dmamap) != NULL) \ + _bus_dmamap_sync_size(dmat, dmamap, offset, len, op) /* * Release the mapping held by map.