- Try to avoid calling malloc() in bus_dmamap_create() and bus_dmamem_alloc()
for the dmamap by using static dmamaps. - Don't do anything for BUS_DMASYNC_PREREAD and BUS_DMASYNC_POSTWRITE in bus_dmamap_sync(), it's not needed anymore.
This commit is contained in:
parent
734781d7b2
commit
c29fa0b7e5
@ -47,6 +47,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/mbuf.h>
|
#include <sys/mbuf.h>
|
||||||
#include <sys/uio.h>
|
#include <sys/uio.h>
|
||||||
#include <sys/ktr.h>
|
#include <sys/ktr.h>
|
||||||
|
#include <sys/kernel.h>
|
||||||
|
|
||||||
#include <vm/vm.h>
|
#include <vm/vm.h>
|
||||||
#include <vm/vm_page.h>
|
#include <vm/vm_page.h>
|
||||||
@ -85,6 +86,8 @@ struct bus_dma_tag {
|
|||||||
#define DMAMAP_LINEAR 0x1
|
#define DMAMAP_LINEAR 0x1
|
||||||
#define DMAMAP_MBUF 0x2
|
#define DMAMAP_MBUF 0x2
|
||||||
#define DMAMAP_UIO 0x4
|
#define DMAMAP_UIO 0x4
|
||||||
|
#define DMAMAP_ALLOCATED 0x10
|
||||||
|
#define DMAMAP_STATIC_BUSY 0x20
|
||||||
#define DMAMAP_TYPE_MASK (DMAMAP_LINEAR|DMAMAP_MBUF|DMAMAP_UIO)
|
#define DMAMAP_TYPE_MASK (DMAMAP_LINEAR|DMAMAP_MBUF|DMAMAP_UIO)
|
||||||
#define DMAMAP_COHERENT 0x8
|
#define DMAMAP_COHERENT 0x8
|
||||||
struct bus_dmamap {
|
struct bus_dmamap {
|
||||||
@ -94,6 +97,13 @@ struct bus_dmamap {
|
|||||||
int len;
|
int len;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define BUSDMA_STATIC_MAPS 500
|
||||||
|
static struct bus_dmamap map_pool[BUSDMA_STATIC_MAPS];
|
||||||
|
|
||||||
|
static struct mtx busdma_mtx;
|
||||||
|
|
||||||
|
MTX_SYSINIT(busdma_mtx, &busdma_mtx, "busdma lock", MTX_DEF);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check to see if the specified page is in an allowed DMA range.
|
* Check to see if the specified page is in an allowed DMA range.
|
||||||
*/
|
*/
|
||||||
@ -158,6 +168,39 @@ dflt_lock(void *arg, bus_dma_lock_op_t op)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bus_dmamap_t
|
||||||
|
_busdma_alloc_dmamap(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
bus_dmamap_t map;
|
||||||
|
|
||||||
|
mtx_lock(&busdma_mtx);
|
||||||
|
for (i = 0; i < BUSDMA_STATIC_MAPS; i++)
|
||||||
|
if (!(map_pool[i].flags & DMAMAP_STATIC_BUSY)) {
|
||||||
|
bzero(&map_pool[i], sizeof(map_pool[i]));
|
||||||
|
map_pool[i].flags |= DMAMAP_STATIC_BUSY;
|
||||||
|
mtx_unlock(&busdma_mtx);
|
||||||
|
return (&map_pool[i]);
|
||||||
|
}
|
||||||
|
mtx_unlock(&busdma_mtx);
|
||||||
|
map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT | M_ZERO);
|
||||||
|
if (map)
|
||||||
|
map->flags |= DMAMAP_ALLOCATED;
|
||||||
|
return (map);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
_busdma_free_dmamap(bus_dmamap_t map)
|
||||||
|
{
|
||||||
|
if (map->flags & DMAMAP_ALLOCATED)
|
||||||
|
free(map, M_DEVBUF);
|
||||||
|
else {
|
||||||
|
mtx_lock(&busdma_mtx);
|
||||||
|
map->flags &= ~DMAMAP_STATIC_BUSY;
|
||||||
|
mtx_unlock(&busdma_mtx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate a device specific dma_tag.
|
* Allocate a device specific dma_tag.
|
||||||
*/
|
*/
|
||||||
@ -282,14 +325,13 @@ bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp)
|
|||||||
int error = 0;
|
int error = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
newmap = malloc(sizeof(*newmap), M_DEVBUF, M_NOWAIT | M_ZERO);
|
newmap = _busdma_alloc_dmamap();
|
||||||
if (newmap == NULL) {
|
if (newmap == NULL) {
|
||||||
CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, ENOMEM);
|
CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, ENOMEM);
|
||||||
return (ENOMEM);
|
return (ENOMEM);
|
||||||
}
|
}
|
||||||
*mapp = newmap;
|
*mapp = newmap;
|
||||||
newmap->dmat = dmat;
|
newmap->dmat = dmat;
|
||||||
newmap->flags = 0;
|
|
||||||
dmat->map_count++;
|
dmat->map_count++;
|
||||||
|
|
||||||
CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
|
CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
|
||||||
@ -306,7 +348,7 @@ int
|
|||||||
bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map)
|
bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map)
|
||||||
{
|
{
|
||||||
|
|
||||||
free(map, M_DEVBUF);
|
_busdma_free_dmamap(map);
|
||||||
dmat->map_count--;
|
dmat->map_count--;
|
||||||
CTR2(KTR_BUSDMA, "%s: tag %p error 0", __func__, dmat);
|
CTR2(KTR_BUSDMA, "%s: tag %p error 0", __func__, dmat);
|
||||||
return (0);
|
return (0);
|
||||||
@ -332,14 +374,13 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
|
|||||||
if (flags & BUS_DMA_ZERO)
|
if (flags & BUS_DMA_ZERO)
|
||||||
mflags |= M_ZERO;
|
mflags |= M_ZERO;
|
||||||
|
|
||||||
newmap = malloc(sizeof(*newmap), M_DEVBUF, M_NOWAIT | M_ZERO);
|
newmap = _busdma_alloc_dmamap();
|
||||||
if (newmap == NULL) {
|
if (newmap == NULL) {
|
||||||
CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
|
CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d",
|
||||||
__func__, dmat, dmat->flags, ENOMEM);
|
__func__, dmat, dmat->flags, ENOMEM);
|
||||||
return (ENOMEM);
|
return (ENOMEM);
|
||||||
}
|
}
|
||||||
dmat->map_count++;
|
dmat->map_count++;
|
||||||
newmap->flags = 0;
|
|
||||||
*mapp = newmap;
|
*mapp = newmap;
|
||||||
newmap->dmat = dmat;
|
newmap->dmat = dmat;
|
||||||
|
|
||||||
@ -357,7 +398,7 @@ bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddr, int flags,
|
|||||||
}
|
}
|
||||||
if (*vaddr == NULL) {
|
if (*vaddr == NULL) {
|
||||||
if (newmap != NULL) {
|
if (newmap != NULL) {
|
||||||
free(newmap, M_DEVBUF);
|
_busdma_free_dmamap(newmap);
|
||||||
dmat->map_count--;
|
dmat->map_count--;
|
||||||
}
|
}
|
||||||
*mapp = NULL;
|
*mapp = NULL;
|
||||||
@ -379,7 +420,7 @@ bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
|
|||||||
contigfree(vaddr, dmat->maxsize, M_DEVBUF);
|
contigfree(vaddr, dmat->maxsize, M_DEVBUF);
|
||||||
}
|
}
|
||||||
dmat->map_count--;
|
dmat->map_count--;
|
||||||
free(map, M_DEVBUF);
|
_busdma_free_dmamap(map);
|
||||||
CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat, dmat->flags);
|
CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat, dmat->flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -416,7 +457,7 @@ bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dma_segment_t *segs,
|
|||||||
* XXX Don't support checking for coherent mappings
|
* XXX Don't support checking for coherent mappings
|
||||||
* XXX in user address space.
|
* XXX in user address space.
|
||||||
*/
|
*/
|
||||||
if (__predict_true(pmap == pmap_kernel())) {
|
if (0 && __predict_true(pmap == pmap_kernel())) {
|
||||||
(void) pmap_get_pde_pte(pmap, vaddr, &pde, &ptep);
|
(void) pmap_get_pde_pte(pmap, vaddr, &pde, &ptep);
|
||||||
if (__predict_false(pmap_pde_section(pde))) {
|
if (__predict_false(pmap_pde_section(pde))) {
|
||||||
curaddr = (*pde & L1_S_FRAME) |
|
curaddr = (*pde & L1_S_FRAME) |
|
||||||
@ -574,15 +615,18 @@ bus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0,
|
|||||||
map->flags &= ~DMAMAP_TYPE_MASK;
|
map->flags &= ~DMAMAP_TYPE_MASK;
|
||||||
map->flags |= DMAMAP_MBUF | DMAMAP_COHERENT;
|
map->flags |= DMAMAP_MBUF | DMAMAP_COHERENT;
|
||||||
map->buffer = m0;
|
map->buffer = m0;
|
||||||
|
map->len = 0;
|
||||||
if (m0->m_pkthdr.len <= dmat->maxsize) {
|
if (m0->m_pkthdr.len <= dmat->maxsize) {
|
||||||
vm_offset_t lastaddr = 0;
|
vm_offset_t lastaddr = 0;
|
||||||
struct mbuf *m;
|
struct mbuf *m;
|
||||||
|
|
||||||
for (m = m0; m != NULL && error == 0; m = m->m_next) {
|
for (m = m0; m != NULL && error == 0; m = m->m_next) {
|
||||||
if (m->m_len > 0)
|
if (m->m_len > 0) {
|
||||||
error = bus_dmamap_load_buffer(dmat,
|
error = bus_dmamap_load_buffer(dmat,
|
||||||
dm_segments, map, m->m_data, m->m_len,
|
dm_segments, map, m->m_data, m->m_len,
|
||||||
pmap_kernel(), flags, &lastaddr, &nsegs);
|
pmap_kernel(), flags, &lastaddr, &nsegs);
|
||||||
|
map->len += m->m_len;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
error = EINVAL;
|
error = EINVAL;
|
||||||
@ -616,6 +660,7 @@ bus_dmamap_load_mbuf_sg(bus_dma_tag_t dmat, bus_dmamap_t map,
|
|||||||
map->flags &= ~DMAMAP_TYPE_MASK;
|
map->flags &= ~DMAMAP_TYPE_MASK;
|
||||||
map->flags |= DMAMAP_MBUF | DMAMAP_COHERENT;
|
map->flags |= DMAMAP_MBUF | DMAMAP_COHERENT;
|
||||||
map->buffer = m0;
|
map->buffer = m0;
|
||||||
|
map->len = 0;
|
||||||
if (m0->m_pkthdr.len <= dmat->maxsize) {
|
if (m0->m_pkthdr.len <= dmat->maxsize) {
|
||||||
vm_offset_t lastaddr = 0;
|
vm_offset_t lastaddr = 0;
|
||||||
struct mbuf *m;
|
struct mbuf *m;
|
||||||
@ -626,6 +671,7 @@ bus_dmamap_load_mbuf_sg(bus_dma_tag_t dmat, bus_dmamap_t map,
|
|||||||
m->m_data, m->m_len,
|
m->m_data, m->m_len,
|
||||||
pmap_kernel(), flags, &lastaddr,
|
pmap_kernel(), flags, &lastaddr,
|
||||||
nsegs);
|
nsegs);
|
||||||
|
map->len += m->m_len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -663,6 +709,7 @@ bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio,
|
|||||||
map->flags &= ~DMAMAP_TYPE_MASK;
|
map->flags &= ~DMAMAP_TYPE_MASK;
|
||||||
map->flags |= DMAMAP_UIO|DMAMAP_COHERENT;
|
map->flags |= DMAMAP_UIO|DMAMAP_COHERENT;
|
||||||
map->buffer = uio;
|
map->buffer = uio;
|
||||||
|
map->len = 0;
|
||||||
|
|
||||||
if (uio->uio_segflg == UIO_USERSPACE) {
|
if (uio->uio_segflg == UIO_USERSPACE) {
|
||||||
KASSERT(uio->uio_td != NULL,
|
KASSERT(uio->uio_td != NULL,
|
||||||
@ -686,6 +733,7 @@ bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio,
|
|||||||
error = bus_dmamap_load_buffer(dmat, dm_segments, map,
|
error = bus_dmamap_load_buffer(dmat, dm_segments, map,
|
||||||
addr, minlen, pmap, flags, &lastaddr, &nsegs);
|
addr, minlen, pmap, flags, &lastaddr, &nsegs);
|
||||||
|
|
||||||
|
map->len += minlen;
|
||||||
resid -= minlen;
|
resid -= minlen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -719,18 +767,14 @@ static void
|
|||||||
bus_dmamap_sync_buf(void *buf, int len, bus_dmasync_op_t op)
|
bus_dmamap_sync_buf(void *buf, int len, bus_dmasync_op_t op)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (op & BUS_DMASYNC_POSTREAD ||
|
|
||||||
op == (BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE)) {
|
|
||||||
cpu_dcache_wbinv_range((vm_offset_t)buf, len);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (op & BUS_DMASYNC_PREWRITE)
|
if (op & BUS_DMASYNC_PREWRITE)
|
||||||
cpu_dcache_wb_range((vm_offset_t)buf, len);
|
cpu_dcache_wb_range((vm_offset_t)buf, len);
|
||||||
if (op & BUS_DMASYNC_PREREAD) {
|
if (op & BUS_DMASYNC_POSTREAD) {
|
||||||
if ((((vm_offset_t)buf | len) & arm_dcache_align_mask) == 0)
|
if ((((vm_offset_t)buf | len) & arm_dcache_align_mask) == 0)
|
||||||
cpu_dcache_inv_range((vm_offset_t)buf, len);
|
cpu_dcache_inv_range((vm_offset_t)buf, len);
|
||||||
else
|
else
|
||||||
cpu_dcache_wbinv_range((vm_offset_t)buf, len);
|
cpu_dcache_wbinv_range((vm_offset_t)buf, len);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -742,10 +786,14 @@ _bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op)
|
|||||||
int resid;
|
int resid;
|
||||||
struct iovec *iov;
|
struct iovec *iov;
|
||||||
|
|
||||||
if (op == BUS_DMASYNC_POSTWRITE)
|
if (!(op & (BUS_DMASYNC_PREWRITE | BUS_DMASYNC_POSTREAD)))
|
||||||
return;
|
return;
|
||||||
if (map->flags & DMAMAP_COHERENT)
|
if (map->flags & DMAMAP_COHERENT)
|
||||||
return;
|
return;
|
||||||
|
if (map->len > PAGE_SIZE) {
|
||||||
|
cpu_dcache_wbinv_all();
|
||||||
|
return;
|
||||||
|
}
|
||||||
CTR3(KTR_BUSDMA, "%s: op %x flags %x", __func__, op, map->flags);
|
CTR3(KTR_BUSDMA, "%s: op %x flags %x", __func__, op, map->flags);
|
||||||
switch(map->flags & DMAMAP_TYPE_MASK) {
|
switch(map->flags & DMAMAP_TYPE_MASK) {
|
||||||
case DMAMAP_LINEAR:
|
case DMAMAP_LINEAR:
|
||||||
|
Loading…
Reference in New Issue
Block a user