Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F157307915
D888.id2585.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
27 KB
Referenced Files
None
Subscribers
None
D888.id2585.diff
View Options
Index: sys/kern/subr_bus_dma.c
===================================================================
--- sys/kern/subr_bus_dma.c
+++ sys/kern/subr_bus_dma.c
@@ -54,6 +54,41 @@
#include <machine/bus.h>
/*
+ * Load a virtual addresses.
+ */
+static int
+_bus_dmamap_load_virt(bus_dma_tag_t dmat, bus_dmamap_t map,
+ void *addr, bus_size_t size, pmap_t pmap, int *nsegs,
+ int flags)
+{
+ bus_dma_segment_t seg;
+ struct memdesc mem;
+
+ seg.ds_addr = (bus_addr_t) addr;
+ seg.ds_len = size;
+ mem = memdesc_vlist(&seg, 1);
+
+ return (_bus_dmamap_load(dmat, map, &mem, pmap, flags, NULL, nsegs));
+}
+
+/*
+ * Load a physical addresses.
+ */
+static int
+_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map,
+ vm_paddr_t addr, bus_size_t size, int *nsegs, int flags)
+{
+ bus_dma_segment_t seg;
+ struct memdesc mem;
+
+ seg.ds_addr = addr;
+ seg.ds_len = size;
+ mem = memdesc_plist(&seg, 1);
+
+ return (_bus_dmamap_load(dmat, map, &mem, NULL, flags, NULL, nsegs));
+}
+
+/*
* Load a list of virtual addresses.
*/
static int
@@ -61,17 +96,11 @@
bus_dma_segment_t *list, int sglist_cnt, struct pmap *pmap, int *nsegs,
int flags)
{
- int error;
+ struct memdesc mem;
- error = 0;
- for (; sglist_cnt > 0; sglist_cnt--, list++) {
- error = _bus_dmamap_load_buffer(dmat, map,
- (void *)(uintptr_t)list->ds_addr, list->ds_len, pmap,
- flags, NULL, nsegs);
- if (error)
- break;
- }
- return (error);
+ mem = memdesc_vlist(list, sglist_cnt);
+
+ return (_bus_dmamap_load(dmat, map, &mem, pmap, flags, NULL, nsegs));
}
/*
@@ -81,17 +110,11 @@
_bus_dmamap_load_plist(bus_dma_tag_t dmat, bus_dmamap_t map,
bus_dma_segment_t *list, int sglist_cnt, int *nsegs, int flags)
{
- int error;
+ struct memdesc mem;
- error = 0;
- for (; sglist_cnt > 0; sglist_cnt--, list++) {
- error = _bus_dmamap_load_phys(dmat, map,
- (vm_paddr_t)list->ds_addr, list->ds_len, flags, NULL,
- nsegs);
- if (error)
- break;
- }
- return (error);
+ mem = memdesc_plist(list, sglist_cnt);
+
+ return (_bus_dmamap_load(dmat, map, &mem, NULL, flags, NULL, nsegs));
}
/*
@@ -101,15 +124,19 @@
_bus_dmamap_load_mbuf_sg(bus_dma_tag_t dmat, bus_dmamap_t map,
struct mbuf *m0, bus_dma_segment_t *segs, int *nsegs, int flags)
{
+ bus_dma_segment_t seg;
+ struct memdesc mem;
struct mbuf *m;
int error;
error = 0;
for (m = m0; m != NULL && error == 0; m = m->m_next) {
if (m->m_len > 0) {
- error = _bus_dmamap_load_buffer(dmat, map, m->m_data,
- m->m_len, kernel_pmap, flags | BUS_DMA_LOAD_MBUF,
- segs, nsegs);
+ seg.ds_addr = (bus_addr_t) m->m_data;
+ seg.ds_len = m->m_len;
+ mem = memdesc_vlist(&seg, 1);
+ error = _bus_dmamap_load(dmat, map, &mem, kernel_pmap,
+ flags | BUS_DMA_LOAD_MBUF, segs, nsegs);
}
}
CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
@@ -124,37 +151,53 @@
_bus_dmamap_load_bio(bus_dma_tag_t dmat, bus_dmamap_t map, struct bio *bio,
int *nsegs, int flags)
{
- int error;
+ struct memdesc mem;
+ bus_dma_segment_t *seg;
+ bus_size_t tlen, len;
+ int error, ma_offs, i;
+ size_t array_size;
+ pmap_t pmap;
+
+ error = 0;
if ((bio->bio_flags & BIO_UNMAPPED) == 0) {
- error = _bus_dmamap_load_buffer(dmat, map, bio->bio_data,
- bio->bio_bcount, kernel_pmap, flags, NULL, nsegs);
+ array_size = 1;
} else {
- error = _bus_dmamap_load_ma(dmat, map, bio->bio_ma,
- bio->bio_bcount, bio->bio_ma_offset, flags, NULL, nsegs);
+ array_size = (bio->bio_bcount/PAGE_SIZE + 2);
}
- return (error);
-}
-int
-bus_dmamap_load_ma_triv(bus_dma_tag_t dmat, bus_dmamap_t map,
- struct vm_page **ma, bus_size_t tlen, int ma_offs, int flags,
- bus_dma_segment_t *segs, int *segp)
-{
- vm_paddr_t paddr;
- bus_size_t len;
- int error, i;
+ seg = malloc(sizeof(bus_dma_segment_t) * array_size, M_DEVBUF,
+ (flags & BUS_DMA_NOWAIT) == 0 ? M_WAITOK : M_NOWAIT);
+ if (__predict_false(seg == NULL)) {
+ error = ENOMEM;
+ goto out;
+ }
- error = 0;
- for (i = 0; tlen > 0; i++, tlen -= len) {
- len = min(PAGE_SIZE - ma_offs, tlen);
- paddr = VM_PAGE_TO_PHYS(ma[i]) + ma_offs;
- error = _bus_dmamap_load_phys(dmat, map, paddr, len,
- flags, segs, segp);
- if (error != 0)
- break;
- ma_offs = 0;
+ pmap = NULL;
+ if ((bio->bio_flags & BIO_UNMAPPED) == 0) {
+ seg[0].ds_addr = (bus_addr_t) bio->bio_data;
+ seg[0].ds_len = bio->bio_bcount;
+ mem = memdesc_vlist(seg, 1);
+ pmap = kernel_pmap;
+ } else {
+ tlen = bio->bio_bcount;
+ ma_offs = bio->bio_ma_offset;
+ for (i = 0; tlen > 0; i++, tlen -= len) {
+ KASSERT(i < array_size,
+ ("Calculated array size doesn't match"));
+ len = min(PAGE_SIZE - ma_offs, tlen);
+ seg[i].ds_addr =
+ VM_PAGE_TO_PHYS(bio->bio_ma[i]) + ma_offs;
+ seg[i].ds_len = len;
+ ma_offs = 0;
+ }
+ mem = memdesc_plist(seg, i);
}
+
+ error = _bus_dmamap_load(dmat, map, &mem, pmap, flags, NULL, nsegs);
+ free(seg, M_DEVBUF);
+
+out:
return (error);
}
@@ -208,13 +251,12 @@
switch ((ccb_h->flags & CAM_DATA_MASK)) {
case CAM_DATA_VADDR:
- error = _bus_dmamap_load_buffer(dmat, map, data_ptr, dxfer_len,
- kernel_pmap, flags, NULL, nsegs);
+ error = _bus_dmamap_load_virt(dmat, map, data_ptr, dxfer_len,
+ kernel_pmap, nsegs, flags);
break;
case CAM_DATA_PADDR:
- error = _bus_dmamap_load_phys(dmat, map,
- (vm_paddr_t)(uintptr_t)data_ptr, dxfer_len, flags, NULL,
- nsegs);
+ error = _bus_dmamap_load_phys(dmat, map, (vm_paddr_t)data_ptr,
+ dxfer_len, nsegs, flags);
break;
case CAM_DATA_SG:
error = _bus_dmamap_load_vlist(dmat, map,
@@ -243,12 +285,13 @@
_bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio,
int *nsegs, int flags)
{
+ struct memdesc mem;
+ bus_dma_segment_t *seg;
bus_size_t resid;
- bus_size_t minlen;
+ bus_size_t len;
struct iovec *iov;
pmap_t pmap;
- caddr_t addr;
- int error, i;
+ int error, i, j;
if (uio->uio_segflg == UIO_USERSPACE) {
KASSERT(uio->uio_td != NULL,
@@ -256,25 +299,35 @@
pmap = vmspace_pmap(uio->uio_td->td_proc->p_vmspace);
} else
pmap = kernel_pmap;
+
+ seg = malloc(uio->uio_iovcnt * sizeof(bus_dma_segment_t), M_DEVBUF,
+ (flags & BUS_DMA_NOWAIT) == 0 ? M_WAITOK : M_NOWAIT);
+ if (__predict_false(seg == NULL)) {
+ error = ENOMEM;
+ goto out;
+ }
+
resid = uio->uio_resid;
iov = uio->uio_iov;
- error = 0;
-
- for (i = 0; i < uio->uio_iovcnt && resid != 0 && !error; i++) {
+ for (i = 0, j= 0; i < uio->uio_iovcnt && resid != 0; i++) {
/*
* Now at the first iovec to load. Load each iovec
* until we have exhausted the residual count.
*/
-
- addr = (caddr_t) iov[i].iov_base;
- minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len;
- if (minlen > 0) {
- error = _bus_dmamap_load_buffer(dmat, map, addr,
- minlen, pmap, flags, NULL, nsegs);
- resid -= minlen;
- }
+ len = min(resid, iov[i].iov_len);
+ if (len == 0)
+ continue;
+ seg[j].ds_addr = (bus_addr_t) iov[i].iov_base;
+ seg[j].ds_len = len;
+ resid -= len;
+ j++;
}
+ mem = memdesc_vlist(seg, j);
+
+ error = _bus_dmamap_load(dmat, map, &mem, pmap, flags, NULL, nsegs);
+ free(seg, M_DEVBUF);
+out:
return (error);
}
@@ -297,8 +350,8 @@
}
nsegs = -1;
- error = _bus_dmamap_load_buffer(dmat, map, buf, buflen, kernel_pmap,
- flags, NULL, &nsegs);
+ error = _bus_dmamap_load_virt(dmat, map, buf, buflen, kernel_pmap,
+ &nsegs, flags);
nsegs++;
CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
@@ -475,8 +528,7 @@
void *callback_arg, int flags)
{
bus_dma_segment_t *segs;
- int error;
- int nsegs;
+ int error, nsegs;
if ((flags & BUS_DMA_NOWAIT) == 0)
_bus_dmamap_waitok(dmat, map, mem, callback, callback_arg);
@@ -485,12 +537,12 @@
error = 0;
switch (mem->md_type) {
case MEMDESC_VADDR:
- error = _bus_dmamap_load_buffer(dmat, map, mem->u.md_vaddr,
- mem->md_opaque, kernel_pmap, flags, NULL, &nsegs);
+ error = _bus_dmamap_load_virt(dmat, map, mem->u.md_vaddr,
+ mem->md_opaque, kernel_pmap, &nsegs, flags);
break;
case MEMDESC_PADDR:
error = _bus_dmamap_load_phys(dmat, map, mem->u.md_paddr,
- mem->md_opaque, flags, NULL, &nsegs);
+ mem->md_opaque, &nsegs, flags);
break;
case MEMDESC_VLIST:
error = _bus_dmamap_load_vlist(dmat, map, mem->u.md_list,
Index: sys/sys/bus_dma.h
===================================================================
--- sys/sys/bus_dma.h
+++ sys/sys/bus_dma.h
@@ -240,15 +240,6 @@
void *callback_arg, int flags);
/*
- * Placeholder for use by busdma implementations which do not benefit
- * from optimized procedure to load an array of vm_page_t. Falls back
- * to do _bus_dmamap_load_phys() in loop.
- */
-int bus_dmamap_load_ma_triv(bus_dma_tag_t dmat, bus_dmamap_t map,
- struct vm_page **ma, bus_size_t tlen, int ma_offs, int flags,
- bus_dma_segment_t *segs, int *segp);
-
-/*
* XXX sparc64 uses the same interface, but a much different implementation.
* <machine/bus_dma.h> for the sparc64 arch contains the equivalent
* declarations.
@@ -318,17 +309,9 @@
callback_arg); \
} while (0);
-int _bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map,
- void *buf, bus_size_t buflen, struct pmap *pmap,
- int flags, bus_dma_segment_t *segs, int *segp);
-
-int _bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map,
- vm_paddr_t paddr, bus_size_t buflen,
- int flags, bus_dma_segment_t *segs, int *segp);
-
-int _bus_dmamap_load_ma(bus_dma_tag_t dmat, bus_dmamap_t map,
- struct vm_page **ma, bus_size_t tlen, int ma_offs, int flags,
- bus_dma_segment_t *segs, int *segp);
+int _bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, struct memdesc *mem,
+ struct pmap *pmap, int flags, bus_dma_segment_t *segs,
+ int *segp);
bus_dma_segment_t *_bus_dmamap_complete(bus_dma_tag_t dmat,
bus_dmamap_t map,
Index: sys/x86/include/busdma_impl.h
===================================================================
--- sys/x86/include/busdma_impl.h
+++ sys/x86/include/busdma_impl.h
@@ -63,14 +63,8 @@
int (*mem_alloc)(bus_dma_tag_t dmat, void** vaddr, int flags,
bus_dmamap_t *mapp);
void (*mem_free)(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map);
- int (*load_ma)(bus_dma_tag_t dmat, bus_dmamap_t map,
- struct vm_page **ma, bus_size_t tlen, int ma_offs, int flags,
- bus_dma_segment_t *segs, int *segp);
- int (*load_phys)(bus_dma_tag_t dmat, bus_dmamap_t map,
- vm_paddr_t buf, bus_size_t buflen, int flags,
- bus_dma_segment_t *segs, int *segp);
- int (*load_buffer)(bus_dma_tag_t dmat, bus_dmamap_t map,
- void *buf, bus_size_t buflen, pmap_t pmap, int flags,
+ int (*load)(bus_dma_tag_t dmat, bus_dmamap_t map,
+ struct memdesc *mem, pmap_t pmap, int flags,
bus_dma_segment_t *segs, int *segp);
void (*map_waitok)(bus_dma_tag_t dmat, bus_dmamap_t map,
struct memdesc *mem, bus_dmamap_callback_t *callback,
Index: sys/x86/iommu/busdma_dmar.c
===================================================================
--- sys/x86/iommu/busdma_dmar.c
+++ sys/x86/iommu/busdma_dmar.c
@@ -571,6 +571,7 @@
return (error);
}
+#if 0
static int
dmar_bus_dmamap_load_ma(bus_dma_tag_t dmat, bus_dmamap_t map1,
struct vm_page **ma, bus_size_t tlen, int ma_offs, int flags,
@@ -674,6 +675,17 @@
free(fma, M_DEVBUF);
return (error);
}
+#endif
+
+static int
+dmar_bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map,
+ struct memdesc *mem, pmap_t pmap, int flags, bus_dma_segment_t *segs,
+ int *segp)
+{
+
+ panic("Not implemented");
+ return (0);
+}
static void
dmar_bus_dmamap_waitok(bus_dma_tag_t dmat, bus_dmamap_t map1,
@@ -772,9 +784,12 @@
.map_destroy = dmar_bus_dmamap_destroy,
.mem_alloc = dmar_bus_dmamem_alloc,
.mem_free = dmar_bus_dmamem_free,
+ .load = dmar_bus_dmamap_load,
+#if 0
.load_phys = dmar_bus_dmamap_load_phys,
.load_buffer = dmar_bus_dmamap_load_buffer,
.load_ma = dmar_bus_dmamap_load_ma,
+#endif
.map_waitok = dmar_bus_dmamap_waitok,
.map_complete = dmar_bus_dmamap_complete,
.map_unload = dmar_bus_dmamap_unload,
Index: sys/x86/x86/busdma_bounce.c
===================================================================
--- sys/x86/x86/busdma_bounce.c
+++ sys/x86/x86/busdma_bounce.c
@@ -78,9 +78,8 @@
struct bounce_page {
vm_offset_t vaddr; /* kva of bounce buffer */
bus_addr_t busaddr; /* Physical address */
- vm_offset_t datavaddr; /* kva of client data */
- bus_addr_t dataaddr; /* client physical address */
- bus_size_t datacount; /* client data count */
+ bus_dma_segment_t data[2]; /* Store client data */
+ boolean_t physical; /* Is client data a physical address? */
STAILQ_ENTRY(bounce_page) links;
};
@@ -134,16 +133,12 @@
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_addr_t addr,
- bus_size_t size);
+ bus_dma_segment_t *segs, boolean_t physical);
static void free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage);
int run_filter(bus_dma_tag_t dmat, bus_addr_t paddr);
static void _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map,
- pmap_t pmap, void *buf, bus_size_t buflen,
- int flags);
-static void _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map,
- vm_paddr_t buf, bus_size_t buflen,
- int flags);
+ pmap_t pmap, struct memdesc *mem,
+ bus_size_t buflen, int flags);
static int _bus_dmamap_reserve_pages(bus_dma_tag_t dmat, bus_dmamap_t map,
int flags);
@@ -464,40 +459,51 @@
dmat->bounce_flags);
}
-static void
-_bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf,
- bus_size_t buflen, int flags)
+static inline vm_paddr_t
+_bus_dmamap_seg_paddr(struct memdesc *mem, int index, pmap_t pmap,
+ bus_size_t offset)
{
- bus_addr_t curaddr;
- bus_size_t sgsize;
+ vm_paddr_t paddr;
+ vm_offset_t vaddr;
- if ((map != &nobounce_dmamap && map->pagesneeded == 0)) {
- /*
- * Count the number of bounce pages
- * needed in order to complete this transfer
- */
- curaddr = buf;
- while (buflen != 0) {
- sgsize = MIN(buflen, dmat->common.maxsegsz);
- if (bus_dma_run_filter(&dmat->common, curaddr)) {
- sgsize = MIN(sgsize, PAGE_SIZE);
- map->pagesneeded++;
- }
- curaddr += sgsize;
- buflen -= sgsize;
- }
- CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded);
+ KASSERT(mem->md_type == MEMDESC_PLIST || mem->md_type == MEMDESC_VLIST,
+ ("Provided memdesc is not compatible"));
+ KASSERT(index < mem->md_opaque,
+ ("Index overruns bus_dma_segment array"));
+ if (mem->md_type == MEMDESC_PLIST) {
+ paddr = mem->u.md_list[index].ds_addr + offset;
+ } else {
+ KASSERT(pmap != NULL, ("No valid pmap provided"));
+ vaddr = mem->u.md_list[index].ds_addr + offset;
+ if (pmap == kernel_pmap)
+ paddr = pmap_kextract(vaddr);
+ else
+ paddr = pmap_extract(pmap, vaddr);
}
+
+ return (paddr);
+}
+
+static inline vm_offset_t
+_bus_dmamap_seg_vaddr(struct memdesc *mem, int index, bus_size_t offset)
+{
+
+ KASSERT(mem->md_type == MEMDESC_VLIST,
+ ("Provided memdesc is not compatible"));
+ KASSERT(index < mem->md_opaque,
+ ("Index overruns bus_dma_segment array"));
+
+ return (mem->u.md_list[index].ds_addr + offset);
}
static void
_bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, pmap_t pmap,
- void *buf, bus_size_t buflen, int flags)
+ struct memdesc *mem, bus_size_t buflen, int flags)
{
- vm_offset_t vaddr;
- vm_offset_t vendaddr;
- bus_addr_t paddr;
- bus_size_t sg_len;
+ bus_size_t sg_len, max_sgsize;
+ vm_paddr_t paddr, offset;
+ bus_dma_segment_t *seg;
+ int i;
if ((map != &nobounce_dmamap && map->pagesneeded == 0)) {
CTR4(KTR_BUSDMA, "lowaddr= %d Maxmem= %d, boundary= %d, "
@@ -506,25 +512,39 @@
dmat->common.boundary, dmat->common.alignment);
CTR3(KTR_BUSDMA, "map= %p, nobouncemap= %p, pagesneeded= %d",
map, &nobounce_dmamap, map->pagesneeded);
+
/*
* Count the number of bounce pages
* needed in order to complete this transfer
*/
- vaddr = (vm_offset_t)buf;
- vendaddr = (vm_offset_t)buf + buflen;
-
- while (vaddr < vendaddr) {
- sg_len = PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK);
- if (pmap == kernel_pmap)
- paddr = pmap_kextract(vaddr);
- else
- paddr = pmap_extract(pmap, vaddr);
+ i = 0;
+ offset = 0;
+ seg = mem->u.md_list;
+ while (buflen > 0) {
+ paddr = _bus_dmamap_seg_paddr(mem, i, pmap, offset);
+ sg_len = MIN(PAGE_SIZE - (paddr & PAGE_MASK),
+ seg[i].ds_len - offset);
+ max_sgsize = MIN(buflen, dmat->common.maxsegsz);
+ sg_len = MIN(sg_len, max_sgsize);
if (bus_dma_run_filter(&dmat->common, paddr) != 0) {
sg_len = roundup2(sg_len,
dmat->common.alignment);
+ sg_len = MIN(sg_len, max_sgsize);
+ KASSERT((sg_len & (dmat->common.alignment - 1))
+ == 0, ("Segment size is not aligned"));
map->pagesneeded++;
}
- vaddr += sg_len;
+ KASSERT(buflen >= sg_len,
+ ("Segment length overruns original buffer"));
+ buflen -= sg_len;
+ if (offset + sg_len >= seg[i].ds_len) {
+ offset = (offset + sg_len) % seg[i].ds_len;
+ i++;
+ KASSERT(buflen == 0 || offset < seg[i].ds_len,
+ ("Offset overruns next segment"));
+ } else {
+ offset += sg_len;
+ }
}
CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded);
}
@@ -600,71 +620,18 @@
return (sgsize);
}
-/*
- * Utility function to load a physical buffer. segp contains
- * the starting segment on entrace, and the ending segment on exit.
- */
static int
-bounce_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map,
- vm_paddr_t buf, bus_size_t buflen, int flags, bus_dma_segment_t *segs,
+bounce_bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map,
+ struct memdesc *mem, pmap_t pmap, int flags, bus_dma_segment_t *segs,
int *segp)
{
- bus_size_t sgsize;
- bus_addr_t curaddr;
- int error;
-
- if (map == NULL)
- map = &nobounce_dmamap;
+ bus_size_t buflen, offset, max_sgsize, sgsize;
+ bus_dma_segment_t *seg, bounce[2];
+ vm_paddr_t paddr;
+ int i, error;
+ boolean_t phys_addr;
- if (segs == NULL)
- segs = dmat->segments;
-
- if ((dmat->bounce_flags & BUS_DMA_COULD_BOUNCE) != 0) {
- _bus_dmamap_count_phys(dmat, map, buf, buflen, flags);
- if (map->pagesneeded != 0) {
- error = _bus_dmamap_reserve_pages(dmat, map, flags);
- if (error)
- return (error);
- }
- }
-
- while (buflen > 0) {
- curaddr = buf;
- sgsize = MIN(buflen, dmat->common.maxsegsz);
- if (((dmat->bounce_flags & BUS_DMA_COULD_BOUNCE) != 0) &&
- map->pagesneeded != 0 &&
- bus_dma_run_filter(&dmat->common, curaddr)) {
- sgsize = MIN(sgsize, PAGE_SIZE);
- curaddr = add_bounce_page(dmat, map, 0, curaddr,
- sgsize);
- }
- sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
- segp);
- if (sgsize == 0)
- break;
- buf += sgsize;
- buflen -= sgsize;
- }
-
- /*
- * Did we fit?
- */
- return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */
-}
-
-/*
- * Utility function to load a linear buffer. segp contains
- * the starting segment on entrace, and the ending segment on exit.
- */
-static int
-bounce_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
- bus_size_t buflen, pmap_t pmap, int flags, bus_dma_segment_t *segs,
- int *segp)
-{
- bus_size_t sgsize, max_sgsize;
- bus_addr_t curaddr;
- vm_offset_t vaddr;
- int error;
+ phys_addr = mem->md_type == MEMDESC_PLIST ? TRUE : FALSE;
if (map == NULL)
map = &nobounce_dmamap;
@@ -672,8 +639,13 @@
if (segs == NULL)
segs = dmat->segments;
+ /* Calculate total buffer length. */
+ seg = mem->u.md_list;
+ for (i = 0, buflen = 0; i < mem->md_opaque; i++)
+ buflen += seg[i].ds_len;
+
if ((dmat->bounce_flags & BUS_DMA_COULD_BOUNCE) != 0) {
- _bus_dmamap_count_pages(dmat, map, pmap, buf, buflen, flags);
+ _bus_dmamap_count_pages(dmat, map, pmap, mem, buflen, flags);
if (map->pagesneeded != 0) {
error = _bus_dmamap_reserve_pages(dmat, map, flags);
if (error)
@@ -681,43 +653,72 @@
}
}
- vaddr = (vm_offset_t)buf;
+ i = 0;
+ offset = 0;
while (buflen > 0) {
/*
- * Get the physical address for this segment.
- */
- if (pmap == kernel_pmap)
- curaddr = pmap_kextract(vaddr);
- else
- curaddr = pmap_extract(pmap, vaddr);
-
- /*
* Compute the segment size, and adjust counts.
*/
+ paddr = _bus_dmamap_seg_paddr(mem, i, pmap, offset);
max_sgsize = MIN(buflen, dmat->common.maxsegsz);
- sgsize = PAGE_SIZE - ((vm_offset_t)curaddr & PAGE_MASK);
+ sgsize = MIN(PAGE_SIZE - (paddr & PAGE_MASK),
+ seg[i].ds_len - offset);
if (((dmat->bounce_flags & BUS_DMA_COULD_BOUNCE) != 0) &&
map->pagesneeded != 0 &&
- bus_dma_run_filter(&dmat->common, curaddr)) {
+ bus_dma_run_filter(&dmat->common, paddr)) {
sgsize = roundup2(sgsize, dmat->common.alignment);
sgsize = MIN(sgsize, max_sgsize);
- curaddr = add_bounce_page(dmat, map, vaddr, curaddr,
- sgsize);
+ KASSERT((sgsize & (dmat->common.alignment - 1)) == 0,
+ ("Segment size is not aligned"));
+
+ bzero(bounce, sizeof(bounce));
+ bounce[0].ds_addr = phys_addr ? paddr :
+ _bus_dmamap_seg_vaddr(mem, i, offset);
+ bounce[0].ds_len = sgsize;
+
+ /*
+ * Check if two pages of the user provided buffer
+ * are used.
+ */
+ if ((offset + sgsize) > seg[i].ds_len) {
+ KASSERT(offset + sgsize <
+ seg[i].ds_len + seg[i+1].ds_len,
+ ("Cannot bounce more than two segments"));
+ bounce[1].ds_addr = phys_addr ?
+ _bus_dmamap_seg_paddr(mem, i + 1, pmap, 0) :
+ _bus_dmamap_seg_vaddr(mem, i + 1, 0);
+ bounce[1].ds_len = (offset + sgsize) %
+ seg[i].ds_len;
+ bounce[0].ds_len -= bounce[1].ds_len;
+ }
+ paddr = add_bounce_page(dmat, map, bounce, phys_addr);
} else {
sgsize = MIN(sgsize, max_sgsize);
}
- sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs,
+
+ sgsize = _bus_dmamap_addseg(dmat, map, paddr, sgsize, segs,
segp);
if (sgsize == 0)
break;
- vaddr += sgsize;
+
+ KASSERT(buflen >= sgsize,
+ ("Segment length overruns original buffer"));
buflen -= sgsize;
+
+ if (offset + sgsize >= seg[i].ds_len) {
+ offset = (offset + sgsize) % seg[i].ds_len;
+ i++;
+ KASSERT(buflen == 0 || offset < seg[i].ds_len,
+ ("Offset overruns next segment"));
+ } else {
+ offset += sgsize;
+ }
}
/*
* Did we fit?
*/
- return (buflen != 0 ? EFBIG : 0); /* XXX better return value here? */
+ return (buflen != 0 ? EFBIG : 0);
}
static void
@@ -757,6 +758,43 @@
}
}
+static inline void
+_bus_dmamap_copyout(struct bounce_page *bpage)
+{
+ bus_dma_segment_t *seg;
+
+ seg = bpage->data;
+ if (bpage->physical) {
+ physcopyout(seg[0].ds_addr, (void *)bpage->vaddr,
+ seg[0].ds_len);
+ physcopyout(seg[1].ds_addr,
+ (void *)(bpage->vaddr + seg[0].ds_len), seg[1].ds_len);
+ } else {
+ bcopy((void *) seg[0].ds_addr, (void *) bpage->vaddr,
+ seg[0].ds_len);
+ bcopy((void *)(bpage->vaddr + seg[0].ds_len),
+ (void *)seg[1].ds_addr, seg[1].ds_len);
+ }
+}
+
+static inline void
+_bus_dmamap_copyin(struct bounce_page *bpage)
+{
+ bus_dma_segment_t *seg;
+
+ seg = bpage->data;
+ if (bpage->physical) {
+ physcopyin((void *)bpage->vaddr, seg[0].ds_addr, seg[0].ds_len);
+ physcopyin((void *)(bpage->vaddr + seg[0].ds_len),
+ seg[1].ds_addr, seg[1].ds_len);
+ } else {
+ bcopy((void *)bpage->vaddr, (void *)seg[0].ds_addr,
+ seg[0].ds_len);
+ bcopy((void *)seg[1].ds_addr,
+ (void *)(bpage->vaddr + seg[0].ds_len), seg[1].ds_len);
+ }
+}
+
static void
bounce_bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map,
bus_dmasync_op_t op)
@@ -775,15 +813,7 @@
if ((op & BUS_DMASYNC_PREWRITE) != 0) {
while (bpage != NULL) {
- if (bpage->datavaddr != 0) {
- bcopy((void *)bpage->datavaddr,
- (void *)bpage->vaddr,
- bpage->datacount);
- } else {
- physcopyout(bpage->dataaddr,
- (void *)bpage->vaddr,
- bpage->datacount);
- }
+ _bus_dmamap_copyout(bpage);
bpage = STAILQ_NEXT(bpage, links);
}
dmat->bounce_zone->total_bounced++;
@@ -791,15 +821,7 @@
if ((op & BUS_DMASYNC_POSTREAD) != 0) {
while (bpage != NULL) {
- if (bpage->datavaddr != 0) {
- bcopy((void *)bpage->vaddr,
- (void *)bpage->datavaddr,
- bpage->datacount);
- } else {
- physcopyin((void *)bpage->vaddr,
- bpage->dataaddr,
- bpage->datacount);
- }
+ _bus_dmamap_copyin(bpage);
bpage = STAILQ_NEXT(bpage, links);
}
dmat->bounce_zone->total_bounced++;
@@ -963,8 +985,8 @@
}
static bus_addr_t
-add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr,
- bus_addr_t addr, bus_size_t size)
+add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dma_segment_t *segs,
+ boolean_t physical)
{
struct bounce_zone *bz;
struct bounce_page *bpage;
@@ -994,12 +1016,12 @@
if (dmat->common.flags & BUS_DMA_KEEP_PG_OFFSET) {
/* Page offset needs to be preserved. */
- bpage->vaddr |= vaddr & PAGE_MASK;
- bpage->busaddr |= vaddr & PAGE_MASK;
+ bpage->vaddr |= segs[0].ds_addr & PAGE_MASK;
+ bpage->busaddr |= segs[0].ds_addr & PAGE_MASK;
}
- bpage->datavaddr = vaddr;
- bpage->dataaddr = addr;
- bpage->datacount = size;
+ bpage->physical = physical;
+ bcopy(segs, bpage->data, sizeof(bpage->data));
+
STAILQ_INSERT_TAIL(&(map->bpages), bpage, links);
return (bpage->busaddr);
}
@@ -1011,8 +1033,8 @@
struct bounce_zone *bz;
bz = dmat->bounce_zone;
- bpage->datavaddr = 0;
- bpage->datacount = 0;
+ bzero(bpage->data, sizeof(bpage->data));
+
if (dmat->common.flags & BUS_DMA_KEEP_PG_OFFSET) {
/*
* Reset the bounce page to start at offset 0. Other uses
@@ -1068,9 +1090,7 @@
.map_destroy = bounce_bus_dmamap_destroy,
.mem_alloc = bounce_bus_dmamem_alloc,
.mem_free = bounce_bus_dmamem_free,
- .load_phys = bounce_bus_dmamap_load_phys,
- .load_buffer = bounce_bus_dmamap_load_buffer,
- .load_ma = bus_dmamap_load_ma_triv,
+ .load = bounce_bus_dmamap_load,
.map_waitok = bounce_bus_dmamap_waitok,
.map_complete = bounce_bus_dmamap_complete,
.map_unload = bounce_bus_dmamap_unload,
Index: sys/x86/x86/busdma_machdep.c
===================================================================
--- sys/x86/x86/busdma_machdep.c
+++ sys/x86/x86/busdma_machdep.c
@@ -275,47 +275,18 @@
}
/*
- * Utility function to load a physical buffer. segp contains
- * the starting segment on entrace, and the ending segment on exit.
+ * Utility function to load a memdesc.
*/
int
-_bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf,
- bus_size_t buflen, int flags, bus_dma_segment_t *segs, int *segp)
+_bus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, struct memdesc *mem,
+ pmap_t pmap, int flags, bus_dma_segment_t *segs, int *segp)
{
struct bus_dma_tag_common *tc;
tc = (struct bus_dma_tag_common *)dmat;
- return (tc->impl->load_phys(dmat, map, buf, buflen, flags, segs,
- segp));
+ return (tc->impl->load(dmat, map, mem, pmap, flags, segs, segp));
}
-int
-_bus_dmamap_load_ma(bus_dma_tag_t dmat, bus_dmamap_t map, struct vm_page **ma,
- bus_size_t tlen, int ma_offs, int flags, bus_dma_segment_t *segs,
- int *segp)
-{
- struct bus_dma_tag_common *tc;
-
- tc = (struct bus_dma_tag_common *)dmat;
- return (tc->impl->load_ma(dmat, map, ma, tlen, ma_offs, flags,
- segs, segp));
-}
-
-/*
- * Utility function to load a linear buffer. segp contains
- * the starting segment on entrace, and the ending segment on exit.
- */
-int
-_bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
- bus_size_t buflen, pmap_t pmap, int flags, bus_dma_segment_t *segs,
- int *segp)
-{
- struct bus_dma_tag_common *tc;
-
- tc = (struct bus_dma_tag_common *)dmat;
- return (tc->impl->load_buffer(dmat, map, buf, buflen, pmap, flags, segs,
- segp));
-}
void
__bus_dmamap_waitok(bus_dma_tag_t dmat, bus_dmamap_t map,
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, May 21, 5:03 AM (18 h, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
33374777
Default Alt Text
D888.id2585.diff (27 KB)
Attached To
Mode
D888: x86/dma_bounce: rework _bus_dmamap_load_ma implementation
Attached
Detach File
Event Timeline
Log In to Comment