Submit #2883 ยป dma_4gb.patch
sys/platform/pc64/x86_64/busdma_machdep.c | ||
---|---|---|
#define BUS_DMA_COULD_BOUNCE (BUS_DMA_BOUNCE_LOWADDR | BUS_DMA_BOUNCE_ALIGN)
|
||
#define BUS_DMAMEM_KMALLOC(dmat) \
|
||
((dmat)->maxsize <= PAGE_SIZE && \
|
||
(dmat)->alignment <= PAGE_SIZE && \
|
||
(dmat)->lowaddr >= ptoa(Maxmem))
|
||
struct bounce_page {
|
||
vm_offset_t vaddr; /* kva of bounce buffer */
|
||
bus_addr_t busaddr; /* Physical address */
|
||
... | ... | |
return (0);
|
||
}
|
||
static __inline bus_size_t
|
||
check_kmalloc(bus_dma_tag_t dmat, const void *vaddr0, int verify)
|
||
{
|
||
bus_size_t maxsize = 0;
|
||
uintptr_t vaddr = (uintptr_t)vaddr0;
|
||
if ((vaddr ^ (vaddr + dmat->maxsize - 1)) & ~PAGE_MASK) {
|
||
if (verify)
|
||
panic("boundary check failed\n");
|
||
if (bootverbose)
|
||
kprintf("boundary check failed\n");
|
||
maxsize = dmat->maxsize;
|
||
}
|
||
if (vaddr & (dmat->alignment - 1)) {
|
||
if (verify)
|
||
panic("alignment check failed\n");
|
||
if (bootverbose)
|
||
kprintf("alignment check failed\n");
|
||
if (dmat->maxsize < dmat->alignment)
|
||
maxsize = dmat->alignment;
|
||
else
|
||
maxsize = dmat->maxsize;
|
||
}
|
||
return maxsize;
|
||
}
|
||
/*
|
||
* Allocate a piece of memory that can be efficiently mapped into
|
||
* bus device space based on the constraints lited in the dma tag.
|
||
... | ... | |
else
|
||
attr = VM_MEMATTR_DEFAULT;
|
||
/* XXX must alloc with correct mem attribute here */
|
||
if (BUS_DMAMEM_KMALLOC(dmat)) {
|
||
bus_size_t maxsize;
|
||
*vaddr = kmalloc(dmat->maxsize, M_DEVBUF, mflags);
|
||
/*
|
||
* XXX must alloc with correct mem attribute here.
|
||
* Until we get proper IOMMU support, we have to keep buffer in first 4GB.
|
||
*/
|
||
*vaddr = contigmalloc(dmat->maxsize, M_DEVBUF, mflags,
|
||
0ul, 0xfffffffful, dmat->alignment, dmat->boundary);
|
||
/*
|
||
* XXX
|
||
* Check whether the allocation
|
||
* - crossed a page boundary
|
||
* - was not aligned
|
||
* Retry with power-of-2 alignment in the above cases.
|
||
*/
|
||
maxsize = check_kmalloc(dmat, *vaddr, 0);
|
||
if (maxsize) {
|
||
kfree(*vaddr, M_DEVBUF);
|
||
*vaddr = kmalloc(maxsize, M_DEVBUF,
|
||
mflags | M_POWEROF2);
|
||
check_kmalloc(dmat, *vaddr, 1);
|
||
}
|
||
} else {
|
||
/*
|
||
* XXX Use Contigmalloc until it is merged into this facility
|
||
* and handles multi-seg allocations. Nobody is doing
|
||
* multi-seg allocations yet though.
|
||
*/
|
||
*vaddr = contigmalloc(dmat->maxsize, M_DEVBUF, mflags,
|
||
0ul, dmat->lowaddr, dmat->alignment, dmat->boundary);
|
||
}
|
||
if (*vaddr == NULL)
|
||
return (ENOMEM);
|
||
... | ... | |
/*
|
||
* Free a piece of memory and it's allociated dmamap, that was allocated
|
||
* via bus_dmamem_alloc. Make the same choice for free/contigfree.
|
||
* via bus_dmamem_alloc.
|
||
*/
|
||
void
|
||
bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map)
|
||
... | ... | |
*/
|
||
if (map != NULL)
|
||
panic("bus_dmamem_free: Invalid map freed");
|
||
if (BUS_DMAMEM_KMALLOC(dmat))
|
||
kfree(vaddr, M_DEVBUF);
|
||
else
|
||
contigfree(vaddr, dmat->maxsize, M_DEVBUF);
|
||
contigfree(vaddr, dmat->maxsize, M_DEVBUF);
|
||
}
|
||
static __inline vm_paddr_t
|