Index: sys/amd64/amd64/busdma_machdep.c =================================================================== --- sys/amd64/amd64/busdma_machdep.c (revision 237444) +++ sys/amd64/amd64/busdma_machdep.c (working copy) @@ -515,6 +515,12 @@ (dmat->alignment < dmat->maxsize) && dmat->lowaddr >= ptoa((vm_paddr_t)Maxmem)) { *vaddr = malloc(dmat->maxsize, M_DEVBUF, mflags); + } else if (dmat->nsegments >= btoc(dmat->maxsize) && + dmat->alignment <= PAGE_SIZE && + (dmat->boundary == 0 || dmat->boundary >= dmat->lowaddr)) { + /* Page-based multi-segment allocations allowed */ + *vaddr = wiredmalloc(dmat->maxsize, M_DEVBUF, mflags, + 0ul, dmat->lowaddr); } else { /* * XXX Use Contigmalloc until it is merged into this facility Index: sys/sys/malloc.h =================================================================== --- sys/sys/malloc.h (revision 237444) +++ sys/sys/malloc.h (working copy) @@ -166,10 +166,18 @@ */ typedef void malloc_type_list_func_t(struct malloc_type *, void *); +/* Allocate wired, contiguous physical memory */ void contigfree(void *addr, unsigned long size, struct malloc_type *type); void *contigmalloc(unsigned long size, struct malloc_type *type, int flags, vm_paddr_t low, vm_paddr_t high, unsigned long alignment, unsigned long boundary) __malloc_like; + +/* Allocate wired physical memory */ +#define wiredfree(addr, size, type) contigfree((addr), (size), (type)) +void *wiredmalloc(unsigned long size, struct malloc_type *type, int flags, + vm_paddr_t low, vm_paddr_t high) __malloc_like; + +/* General memory allocation */ void free(void *addr, struct malloc_type *type); void *malloc(unsigned long size, struct malloc_type *type, int flags) __malloc_like; void malloc_init(void *); Index: sys/kern/kern_malloc.c =================================================================== --- sys/kern/kern_malloc.c (revision 237444) +++ sys/kern/kern_malloc.c (working copy) @@ -779,6 +779,41 @@ return (NULL); } + +/* +** The wiredmalloc() function allocates size bytes of physical memory that +** is page-aligned. If successful, the allocation will reside between +** physical addresses low and high. The returned pointer points to a wired +** kernel virtual address range of size bytes allocated from the kernel +** virtual address (KVA) map. +** +** The following flags are supported: +** M_ZERO - Allocated memory will be zero-filled +** M_NOWAIT - Return NULL rather than blocking on resource shortage +** +** This function has a similar interface and functionality to contigmalloc +** except that: +** 1) the allocated region is not guaranteed to be physically contiguous +** 2) no boundary can be specified +** 3) alignment is always PAGE_SIZE +*/ +void * +wiredmalloc( + unsigned long size, /* should be size_t here and for malloc() */ + struct malloc_type *type, + int flags, + vm_paddr_t low, + vm_paddr_t high) +{ + void *ret; + + ret = (void *)kmem_alloc_attr(kernel_map, size, flags, low, high, + VM_MEMATTR_DEFAULT); + if (ret != NULL) + malloc_type_allocated(type, round_page(size)); + return (ret); +} + static int sysctl_kern_malloc_stats(SYSCTL_HANDLER_ARGS) {