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
|
||