Project

General

Profile

Submit #2883 ยป dma_4gb.patch

xenu, 01/17/2016 06:54 AM

View differences:

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
    (1-1/1)