DF-5227 / fix.diff
--- a/sys/dev/drm/linux_dma.c +++ b/sys/dev/drm/linux_dma.c @@ -26,51 +26,35 @@ #include <linux/dma-mapping.h> +#include <sys/malloc.h> +#include <vm/vm_kern.h> #include <vm/vm_extern.h> void * dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag) { -#if 1 - vm_paddr_t high; - size_t align; void *mem; -#if 0 /* XXX swildner */ - if (dev->dma_mask) - high = *dev->dma_mask; - else -#endif - high = BUS_SPACE_MAXADDR_32BIT; - align = PAGE_SIZE << get_order(size); - mem = (void *)kmem_alloc_contig(size, 0, high, align); + /* + * The Linux DMA API requires dma_alloc_coherent() to return + * zeroed memory (all in-tree callers currently carry manual + * memset() workarounds for this). kmem_alloc_contig() cannot + * zero, so use contigmalloc_map() with M_ZERO. + * + * dma_free_coherent() must release the wired pages and remove + * the pmap_kenter() mappings: bare kmem_free() orphans the + * kernel PTEs and leaks every physical page (they stay wired + * forever). The matching free is contigfree(). + */ + mem = contigmalloc_map(size, M_DEVBUF, M_NOWAIT | M_ZERO, 0, + BUS_SPACE_MAXADDR_32BIT, PAGE_SIZE << get_order(size), 0ul, + kernel_map); if (mem) *dma_handle = vtophys(mem); else *dma_handle = 0; return (mem); -#endif - -#if 0 - size_t align = PAGE_SIZE << get_order(size); - int error; - drm_dma_handle_t *dmah; - - dmah = kmalloc(sizeof(drm_dma_handle_t), M_DRM, M_ZERO | M_NOWAIT); - if (dmah == NULL) - return NULL; - - error = bus_dmamem_coherent_any( - bus_get_dma_tag(dev->dev->bsddev), - align, size, BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_NOCACHE, - &dmah->tag, &dmah->map, &dmah->vaddr); - if (error != 0) { - kfree(dmah); - return NULL; - } - return dmah; -#endif } void @@ -78,5 +62,5 @@ dma_addr_t dma_handle) { - kmem_free(kernel_map, (vm_offset_t)cpu_addr, size); + contigfree(cpu_addr, size, M_DEVBUF); } |