Allocate natural alignment with get_cont_pages()
authorBarret Rhoden <brho@cs.berkeley.edu>
Wed, 23 Nov 2016 17:08:41 +0000 (12:08 -0500)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 29 Nov 2016 16:27:40 +0000 (11:27 -0500)
Linux code, notoriously the bnx2x driver, occasionally needs naturally
aligned contiguous page allocations.  Since the only code using
get_cont_pages() is Linux code, we can just use xalloc and get the
alignment they want.  Note that xalloc() is less efficient than the regular
allocations, due mostly to bypassing the arena's qcaches.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/drivers/net/udrvr/compat.h
kern/include/linux_compat.h
kern/src/page_alloc.c

index b61dfc1..e8a0cd6 100644 (file)
@@ -95,7 +95,7 @@ extern void set_page_dirty_lock(struct page *pagep);
 static inline void free_page(unsigned long addr)
 {
        if (addr != 0)
-               free_cont_pages((void *)addr, 0);
+               kpages_free((void*)addr, PGSIZE);
 }
 
 #define        get_zeroed_page(f)              kpage_zalloc_addr()
index 7f321bb..a2ab929 100644 (file)
@@ -89,18 +89,12 @@ enum dma_data_direction {
 static inline void *__dma_alloc_coherent(size_t size, dma_addr_t *dma_handle,
                                          gfp_t flags)
 {
-       size_t order = LOG2_UP(nr_pages(size));
-       /* our shitty allocator doesn't align the higher order allocations, so we
-        * go 2x, and align manually.  we don't save the original pointer, so we
-        * can't free them later. */
-       void *vaddr = get_cont_pages(order > 0 ?  order + 1 : order,
-                                    flags);
+       void *vaddr = get_cont_pages(LOG2_UP(nr_pages(size)), flags);
+
        if (!vaddr) {
                *dma_handle = 0;
                return 0;
        }
-       /* manual alignment.  order 0 allocs are already page aligned */
-       vaddr = ALIGN(vaddr, PGSIZE << order);
        *dma_handle = PADDR(vaddr);
        return vaddr;
 }
@@ -117,12 +111,7 @@ static inline void *__dma_zalloc_coherent(size_t size, dma_addr_t *dma_handle,
 static inline void __dma_free_coherent(size_t size, void *cpu_addr,
                                        dma_addr_t dma_handle)
 {
-       size_t order = LOG2_UP(nr_pages(size));
-       if (order > 0) {
-               warn("Not freeing high order alloc!  Fix the allocator!");
-               return;
-       }
-       free_cont_pages(cpu_addr, order);
+       free_cont_pages(cpu_addr, LOG2_UP(nr_pages(size)));
 }
 
 static inline dma_addr_t __dma_map_single(void *cpu_addr, size_t size,
index 8a3814f..2a0e498 100644 (file)
@@ -95,14 +95,18 @@ void kpages_free(void *addr, size_t size)
        arena_free(kpages_arena, addr, size);
 }
 
+/* Returns naturally aligned, contiguous pages of amount PGSIZE << order.  Linux
+ * code might assume its allocations are aligned. (see dma_alloc_coherent and
+ * bnx2x). */
 void *get_cont_pages(size_t order, int flags)
 {
-       return kpages_alloc(PGSIZE << order, flags);
+       return arena_xalloc(kpages_arena, PGSIZE << order, PGSIZE << order,
+                           0, 0, NULL, NULL, flags);
 }
 
 void free_cont_pages(void *buf, size_t order)
 {
-       kpages_free(buf, PGSIZE << order);
+       arena_xfree(kpages_arena, buf, PGSIZE << order);
 }
 
 /* Frees the page */