dma: rewrite DMA allocations with arenas and KMCs
authorBarret Rhoden <brho@cs.berkeley.edu>
Tue, 1 Oct 2019 14:04:34 +0000 (10:04 -0400)
committerBarret Rhoden <brho@cs.berkeley.edu>
Tue, 8 Oct 2019 21:11:11 +0000 (17:11 -0400)
A dma_pool is now just a slab allocator on top of a struct dma_arena.
These allocators provide device-accessible memory *allocations*.  You
can still 'DMA-map' kernel memory for drivers.  This is just for the
Linux DMA alloc APIs, for now.

The reason for some of the kpages->paddr->kaddr acrobatics is I want to
support address spaces other than physical and kernel virtual.
Specifically, I'd like to try to keep a driver in the kernel, but with
the device operating in the user's address space, i.e. behind an IOMMU.
In that sense, the driver *code* is like a syscall in the user's address
space, and the device is like a processor in Ring 3.  We'll see.

Eventually, we could make all of our drivers use these, and perhaps sort
out how to do DMA pinning with the same sense of device addresses.

If it turns out this is a horrible idea, we can make the dma_pool just
pull from kpages and be done with all the to_cpu_addr() translations.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
kern/include/dma.h [new file with mode: 0644]
kern/include/linux/compat_todo.h
kern/include/linux_compat.h
kern/src/Kbuild
kern/src/dma.c [new file with mode: 0644]
kern/src/dmapool.c [deleted file]
kern/src/init.c
kern/src/ktest/kt_arena.c

diff --git a/kern/include/dma.h b/kern/include/dma.h
new file mode 100644 (file)
index 0000000..8343dec
--- /dev/null
@@ -0,0 +1,39 @@
+/* Copyright (c) 2019 Google Inc
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * An arena for DMA-able memory and a 'pool' (slab/KC) for smaller objects.
+ * See dma.c for details.
+ */
+
+#pragma once
+
+#include <arena.h>
+
+typedef physaddr_t dma_addr_t;
+
+struct dma_arena {
+       struct arena            arena;
+       void *(*to_cpu_addr)(struct dma_arena *da, dma_addr_t dev_addr);
+       void                    *data;
+};
+
+/* Default arena: basically just physical pages */
+extern struct dma_arena dma_phys_pages;
+
+void dma_arena_init(void);
+
+void *dma_arena_alloc(struct dma_arena *da, size_t size, dma_addr_t *dma_handle,
+                     int mem_flags);
+void *dma_arena_zalloc(struct dma_arena *da, size_t size,
+                      dma_addr_t *dma_handle, int mem_flags);
+void dma_arena_free(struct dma_arena *da, void *cpu_addr, dma_addr_t dma_handle,
+                   size_t size);
+
+/* Compatible with Linux's DMA pool */
+struct dma_pool *dma_pool_create(const char *name, void *dev,
+                                size_t size, size_t align, size_t allocation);
+void dma_pool_destroy(struct dma_pool *pool);
+void *dma_pool_alloc(struct dma_pool *pool, int mem_flags, dma_addr_t *handle);
+void *dma_pool_zalloc(struct dma_pool *pool, int mem_flags, dma_addr_t *handle);
+void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t addr);
index c69e070..c05b71b 100644 (file)
@@ -20,6 +20,7 @@
 #include <string.h>
 #include <taskqueue.h>
 #include <rbtree.h>
+#include <linux_compat.h>
 
 #define ETH_ALEN       6               /* Octets in one ethernet addr   */
 #define ETH_ZLEN       60              /* Min. octets in frame sans FCS */
@@ -668,13 +669,6 @@ enum pci_bus_speed {
 typedef uint64_t phys_addr_t;
 typedef phys_addr_t resource_size_t;
 
-struct dma_pool *dma_pool_create(const char *name, void *dev,
-                                size_t size, size_t align, size_t allocation);
-void dma_pool_destroy(struct dma_pool *pool);
-void *dma_pool_alloc(struct dma_pool *pool, int mem_flags, dma_addr_t *handle);
-void *dma_pool_zalloc(struct dma_pool *pool, int mem_flags, dma_addr_t *handle);
-void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t addr);
-
 /* This leaks memory, but we don't do driver detach yet. */
 #define dmam_pool_create dma_pool_create
 
index 37af5f9..bc92122 100644 (file)
@@ -27,6 +27,7 @@
 #include <zlib.h>
 #include <list.h>
 #include <refd_pages.h>
+#include <dma.h>
 #include <linux/errno.h>
 /* temporary dumping ground */
 #include "compat_todo.h"
@@ -71,7 +72,6 @@ static inline void synchronize_sched(void)
 #define CLAMP(val, lo, hi) MIN((typeof(val))MAX(val, lo), hi)
 #define CLAMP_T(t, val, lo, hi) CLAMP(val, lo, hi)
 
-typedef physaddr_t dma_addr_t;
 typedef int gfp_t;
 
 /* these dma funcs are empty in linux with !CONFIG_NEED_DMA_MAP_STATE */
@@ -91,35 +91,6 @@ enum dma_data_direction {
        DMA_NONE = 3,
 };
 
-static inline void *__dma_alloc_coherent(size_t size, dma_addr_t *dma_handle,
-                                         gfp_t flags)
-{
-       void *vaddr = get_cont_pages(LOG2_UP(nr_pages(size)), flags);
-
-       if (!vaddr) {
-               *dma_handle = 0;
-               return 0;
-       }
-       *dma_handle = PADDR(vaddr);
-       return vaddr;
-}
-
-static inline void *__dma_zalloc_coherent(size_t size, dma_addr_t *dma_handle,
-                                          gfp_t flags)
-{
-       void *vaddr = __dma_alloc_coherent(size, dma_handle, flags);
-
-       if (vaddr)
-               memset(vaddr, 0, size);
-       return vaddr;
-}
-
-static inline void __dma_free_coherent(size_t size, void *cpu_addr,
-                                       dma_addr_t dma_handle)
-{
-       free_cont_pages(cpu_addr, LOG2_UP(nr_pages(size)));
-}
-
 static inline dma_addr_t __dma_map_single(void *cpu_addr, size_t size,
                                           int direction)
 {
@@ -146,18 +117,29 @@ static inline int __dma_mapping_error(dma_addr_t dma_addr)
 #define dma_sync_single_for_device(...)
 
 /* Wrappers to avoid struct device.  Might want that one of these days.
+ * We're also pulling from the physical pages DMA arena - most devices will want
+ * that, unless they are running in a user's address space.
  *
  * Note dma_alloc_coherent() does a zalloc.  Some Linux drivers (r8169)
  * accidentally assume the memory is zeroed, which may be what Linux allocators
  * often do. */
-#define dma_alloc_coherent(dev, size, dma_handlep, flag)                       \
-       __dma_zalloc_coherent(size, dma_handlep, flag)
+static inline void *dma_alloc_coherent(struct device *dev, size_t size,
+                                      dma_addr_t *dma_handle, int gfp)
+{
+       return dma_arena_zalloc(&dma_phys_pages, size, dma_handle, gfp);
+}
 
-#define dma_zalloc_coherent(dev, size, dma_handlep, flag)                      \
-       __dma_zalloc_coherent(size, dma_handlep, flag)
+static inline void *dma_zalloc_coherent(struct device *dev, size_t size,
+                                       dma_addr_t *dma_handle, int gfp)
+{
+       return dma_arena_zalloc(&dma_phys_pages, size, dma_handle, gfp);
+}
 
-#define dma_free_coherent(dev, size, dma_handle, flag)                         \
-       __dma_free_coherent(size, dma_handle, flag)
+static inline void dma_free_coherent(struct device *dev, size_t size,
+                                    void *cpu_addr, dma_addr_t dma_handle)
+{
+       dma_arena_free(&dma_phys_pages, cpu_addr, dma_handle, size);
+}
 
 #define dma_map_single(dev, addr, size, direction)                             \
        __dma_map_single(addr, size, direction)
index a2af5de..3ea1fa9 100644 (file)
@@ -34,7 +34,7 @@ obj-y                                         += ceq.o
 obj-y                                          += completion.o
 obj-y                                          += coreprov.o
 obj-y                                          += ctype.o
-obj-y                                          += dmapool.o
+obj-y                                          += dma.o
 obj-y                                          += elf.o
 obj-y                                          += env.o
 obj-y                                          += err.o
diff --git a/kern/src/dma.c b/kern/src/dma.c
new file mode 100644 (file)
index 0000000..fcad42d
--- /dev/null
@@ -0,0 +1,204 @@
+/* Copyright (c) 2019 Google Inc
+ * Barret Rhoden <brho@cs.berkeley.edu>
+ * See LICENSE for details.
+ *
+ * An arena for DMA-able memory and a 'pool' (slab/KC) for smaller objects.
+ *
+ * A DMA arena is a memory allocator returning two addresses for the same
+ * memory: CPU/driver and device addresses, the later of which is returned by
+ * reference (dma_handle, below).  Driver code uses the CPU address, and the
+ * driver passes the device address to the hardware.
+ *
+ * dma_phys_pages is the default dma_arena.  This returns kernel virtual
+ * addresses for the CPU and host physical addresses for the device.  Other DMA
+ * arenas can be in other address spaces, such as with device addresses being
+ * behind an IOMMU.
+ *
+ * Each dma_arena provides a source arena which allocs the actual physical
+ * memory, mapped in the device's address space (dma_addr_t), and a function
+ * pointer to convert the dma_addr_t to a CPU address.  For example,
+ * dma_phys_pages's *arena* sources from kpages (kernel addresses for physical
+ * pages), and it uses alloc / free arena-funcs to convert those to its
+ * dma_addr_t: physical addresses.  That is its allocator for physical memory in
+ * the device's address space.  It also uses a function pointer, paddr_to_kaddr,
+ * to convert those to CPU/driver addresses.  The fact that it converts from
+ * kpages to paddrs and back to kaddrs is an internal implementation detail.
+ * (One could imagine us changing base and kpages to allocate physical
+ * addresses.  Either way, dma_arenas return device addresses.  Not a big deal.)
+ *
+ * Sizes and alignments: for now, all arenas return PGSIZE quantums, and all
+ * allocations are naturally aligned, e.g. an alloc of two 4096 pages is on an
+ * 8192-aligned boundary.  This is a convenience for Linux drivers, which expect
+ * this from their DMA API.  Some drivers don't mention that they need these
+ * sorts of guarantees, notably bnx2x.
+ *
+ * We often translate between physical and virtual addresses.  Many arena
+ * quantum / alignment guarantees go away.  We can maintain PGSIZE and lower
+ * powers-of-two alignment.  But something like an odd alignment or an alignment
+ * > PGSIZE may go away.  Odd alignments will fail because the upper bits of the
+ * address change (i.e. the page address).  > PGSIZE alignments *may* fail,
+ * depending on the mapping.  KERNBASE->PADDR will be OK (it's at the max
+ * alignment for memory), but arbitrary virtual-to-physical mappings can change
+ * the upper aligned bits.  If we want to maintain any of these alignments, the
+ * onus is on the dma_arena, not the regular arena allocator.
+ */
+
+#include <arena.h>
+#include <dma.h>
+#include <pmap.h>
+#include <kmalloc.h>
+
+/* This arena is largely a wrapper around kpages.  The arena does impose some
+ * overhead: btags and function pointers for every allocation.  In return, we
+ * get the tracking code from arenas, integration with other arena allocators,
+ * xalloc, and maybe more flexibility. */
+struct dma_arena dma_phys_pages;
+
+static void *dma_phys_a(struct arena *a, size_t amt, int flags)
+{
+       return (void*)PADDR(arena_alloc(a, amt, flags));
+}
+
+static void dma_phys_f(struct arena *a, void *obj, size_t amt)
+{
+       arena_free(a, KADDR((physaddr_t)obj), amt);
+}
+
+static void *dma_phys_pages_to_kaddr(struct dma_arena *da, physaddr_t paddr)
+{
+       return KADDR(paddr);
+}
+
+void dma_arena_init(void)
+{
+       __arena_create(&dma_phys_pages.arena, "dma_phys_pages", PGSIZE,
+                      dma_phys_a, dma_phys_f, kpages_arena, 0);
+       dma_phys_pages.to_cpu_addr = dma_phys_pages_to_kaddr;
+}
+
+void *dma_arena_alloc(struct dma_arena *da, size_t size, dma_addr_t *dma_handle,
+                     int mem_flags)
+{
+       void *paddr;
+
+       /* Linux's DMA API guarantees natural alignment, such that any
+        * page allocation is rounded up to the next highest order.  e.g. 9
+        * pages would be 16-page aligned.  The arena allocator only does
+        * quantum alignment: PGSIZE for da->arena. */
+       if (size > da->arena.quantum)
+               paddr = arena_xalloc(&da->arena, size, ROUNDUPPWR2(size), 0, 0,
+                                    NULL, NULL, mem_flags);
+       else
+               paddr = arena_alloc(&da->arena, size, mem_flags);
+       if (!paddr)
+               return NULL;
+       *dma_handle = (dma_addr_t)paddr;
+       return da->to_cpu_addr(da, (dma_addr_t)paddr);
+}
+
+void *dma_arena_zalloc(struct dma_arena *da, size_t size,
+                      dma_addr_t *dma_handle, int mem_flags)
+{
+       void *vaddr = dma_arena_alloc(da, size, dma_handle, mem_flags);
+
+       if (vaddr)
+               memset(vaddr, 0, size);
+       return vaddr;
+}
+
+void dma_arena_free(struct dma_arena *da, void *cpu_addr, dma_addr_t dma_handle,
+                   size_t size)
+{
+       if (size > da->arena.quantum)
+               arena_xfree(&da->arena, (void*)dma_handle, size);
+       else
+               arena_free(&da->arena, (void*)dma_handle, size);
+}
+
+/* DMA Pool allocator (Linux's interface), built on slabs/arenas.
+ *
+ * A dma_pool is an allocator for fixed-size objects of device memory,
+ * ultimately sourced from a dma_arena, which provides device-addresses for
+ * physical memory and cpu-addresses for driver code.
+ *
+ * It's just a slab/kmem cache allocator sourcing from the dma_arena's arena,
+ * and applying the dma_arena's device-addr to cpu-addr translation.  Alignment
+ * is trivially satisfied by the slab allocator.
+ *
+ * How do we ensure we do not cross a boundary?  I tried some crazy things, like
+ * creating an intermediate arena per dma_pool, and having that arena source
+ * with xalloc(nocross = boundary).  The issue with that was nocross <
+ * source->quantum, among other things.
+ *
+ * The simplest thing is to just waste a little memory to guarantee the nocross
+ * boundary is never crossed.  Here's the guts of it:
+ *
+ *     Any naturally aligned power-of-two allocation will not cross a
+ *     boundary of greater or equal order.
+ *
+ * To make each allocation naturally aligned, we have to round up a bit.  This
+ * could waste memory, but no more than 2x, similar to our arena free lists.
+ * Considering most users end up with a power-of-two sized object, we're not
+ * wasting anything.
+ */
+
+struct dma_pool {
+       struct kmem_cache       kc;
+       struct dma_arena        *source;
+};
+
+struct dma_pool *dma_pool_create(const char *name, void *dev,
+                                size_t size, size_t align, size_t boundary)
+{
+       struct dma_pool *dp;
+
+       if (boundary) {
+               if (!IS_PWR2(boundary) || !IS_PWR2(align))
+                       return NULL;
+               if (boundary < align)
+                       return NULL;
+               size = ALIGN(size, align);
+               size = ROUNDUPPWR2(size);
+               /* subtle.  consider s=33, a=16.  s->64.  a must be 64, not 16,
+                * to ensure natural alignment. */
+               align = size;
+       }
+       dp = kzmalloc(sizeof(struct dma_pool), MEM_WAIT);
+       /* TODO: this will be device specific.  Assuming the default. */
+       dp->source = &dma_phys_pages;
+       /* We're sourcing directly from the dma_arena's arena. */
+       __kmem_cache_create(&dp->kc, name, size, align, KMC_NOTOUCH,
+                           &dp->source->arena, NULL, NULL, NULL);
+       return dp;
+}
+
+void dma_pool_destroy(struct dma_pool *dp)
+{
+       __kmem_cache_destroy(&dp->kc);
+       kfree(dp);
+}
+
+void *dma_pool_alloc(struct dma_pool *dp, int mem_flags, dma_addr_t *handle)
+{
+       void *paddr;
+
+       paddr = kmem_cache_alloc(&dp->kc, mem_flags);
+       if (!paddr)
+               return NULL;
+       *handle = (dma_addr_t)paddr;
+       return dp->source->to_cpu_addr(dp->source, (physaddr_t)paddr);
+}
+
+void *dma_pool_zalloc(struct dma_pool *dp, int mem_flags, dma_addr_t *handle)
+{
+       void *ret = dma_pool_alloc(dp, mem_flags, handle);
+
+       if (ret)
+               memset(ret, 0, dp->kc.obj_size);
+       return ret;
+}
+
+void dma_pool_free(struct dma_pool *dp, void *cpu_addr, dma_addr_t addr)
+{
+       kmem_cache_free(&dp->kc, (void*)addr);
+}
diff --git a/kern/src/dmapool.c b/kern/src/dmapool.c
deleted file mode 100644 (file)
index b6d7f8e..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * DMA Pool allocator
- *
- * Copyright 2001 David Brownell
- * Copyright 2007 Intel Corporation
- *   Author: Matthew Wilcox <willy@linux.intel.com>
- *
- * This software may be redistributed and/or modified under the terms of
- * the GNU General Public License ("GPL") version 2 as published by the
- * Free Software Foundation.
- *
- * This allocator returns small blocks of a given size which are DMA-able by
- * the given device.  It uses the dma_alloc_coherent page allocator to get
- * new pages, then splits them up into blocks of the required size.
- * Many older drivers still have their own code to do this.
- *
- * The current design of this allocator is fairly simple.  The pool is
- * represented by the 'struct dma_pool' which keeps a doubly-linked list of
- * allocated pages.  Each page in the page_list is split into blocks of at
- * least 'size' bytes.  Free blocks are tracked in an unsorted singly-linked
- * list of free blocks within the page.  Used blocks aren't tracked, but we
- * keep a count of how many are currently allocated from each page.
- */
-
-#include <linux_compat.h>
-
-struct dma_pool {
-       struct list_head page_list;
-       spinlock_t lock;
-       size_t size;
-       void *dev;
-       size_t allocation;
-       size_t boundary;
-       char name[32];
-       struct list_head pools;
-};
-
-struct dma_page {
-       struct list_head page_list;
-       void *vaddr;
-       dma_addr_t dma;
-       unsigned int in_use;
-       unsigned int offset;
-};
-
-/**
- * dma_pool_create - Creates a pool of consistent memory blocks, for dma.
- */
-struct dma_pool *dma_pool_create(const char *name, void *dev,
-                                size_t size, size_t align, size_t boundary)
-{
-       struct dma_pool *retval;
-       size_t allocation;
-
-       if (align == 0)
-               align = 1;
-       else if (align & (align - 1))
-               return NULL;
-
-       if (size == 0)
-               return NULL;
-       else if (size < 4)
-               size = 4;
-
-       if ((size % align) != 0)
-               size = ALIGN(size, align);
-
-       allocation = MAX_T(size_t, size, PAGE_SIZE);
-
-       if (!boundary)
-               boundary = allocation;
-       else if ((boundary < size) || (boundary & (boundary - 1)))
-               return NULL;
-
-       retval = kmalloc(sizeof(*retval), MEM_WAIT);
-       if (!retval)
-               return retval;
-
-       strlcpy(retval->name, name, sizeof(retval->name));
-
-       retval->dev = dev;      /* FIXME */
-
-       INIT_LIST_HEAD(&retval->page_list);
-       spinlock_init(&retval->lock);
-       retval->size = size;
-       retval->boundary = boundary;
-       retval->allocation = allocation;
-
-       INIT_LIST_HEAD(&retval->pools);
-
-       /* TODO device_create_file */
-
-       return retval;
-}
-
-void dma_pool_destroy(struct dma_pool *pool)
-{
-       /* TODO */
-}
-
-static void pool_initialise_page(struct dma_pool *pool, struct dma_page *page)
-{
-       unsigned int offset = 0;
-       unsigned int next_boundary = pool->boundary;
-
-       do {
-               unsigned int next = offset + pool->size;
-               if (unlikely((next + pool->size) >= next_boundary)) {
-                       next = next_boundary;
-                       next_boundary += pool->boundary;
-               }
-               *(int *)(page->vaddr + offset) = next;
-               offset = next;
-       } while (offset < pool->allocation);
-}
-
-static struct dma_page *pool_alloc_page(struct dma_pool *pool, int mem_flags)
-{
-       struct dma_page *page;
-
-       page = kmalloc(sizeof(*page), mem_flags);
-       if (!page)
-               return NULL;
-       page->vaddr = dma_alloc_coherent(pool->dev, pool->allocation,
-                                        &page->dma, mem_flags);
-       if (page->vaddr) {
-               pool_initialise_page(pool, page);
-               page->in_use = 0;
-               page->offset = 0;
-       } else {
-               kfree(page);
-               page = NULL;
-       }
-       return page;
-}
-
-void *dma_pool_alloc(struct dma_pool *pool, int mem_flags, dma_addr_t *handle)
-{
-       struct dma_page *page;
-       size_t offset;
-       void *retval;
-
-       /* FIXME take care of locks */
-
-       list_for_each_entry(page, &pool->page_list, page_list) {
-               if (page->offset < pool->allocation)
-                       goto ready;
-       }
-
-       page = pool_alloc_page(pool, mem_flags);
-       if (!page)
-               return NULL;
-
-       list_add(&page->page_list, &pool->page_list);
-ready:
-       page->in_use++;
-       offset = page->offset;
-       page->offset = *(int *)(page->vaddr + offset);  /* "next" */
-       retval = offset + page->vaddr;
-       *handle = offset + page->dma;
-       return retval;
-}
-
-void *dma_pool_zalloc(struct dma_pool *pool, int mem_flags, dma_addr_t *handle)
-{
-       void *ret = dma_pool_alloc(pool, mem_flags, handle);
-
-       if (!ret)
-               return NULL;
-       memset(ret, 0, pool->size);
-       return ret;
-}
-
-void dma_pool_free(struct dma_pool *pool, void *vaddr, dma_addr_t addr)
-{
-       /* TODO */
-}
index 5205c91..a5e6349 100644 (file)
@@ -38,6 +38,7 @@
 #include <acpi.h>
 #include <coreboot_tables.h>
 #include <rcu.h>
+#include <dma.h>
 
 #define MAX_BOOT_CMDLINE_SIZE 4096
 
@@ -137,6 +138,7 @@ void kernel_init(multiboot_info_t *mboot_info)
        vmap_init();
        hashtable_init();
        radix_init();
+       dma_arena_init();
        acpiinit();
        topology_init();
        percpu_init();
index 0b0be7f..651e565 100644 (file)
@@ -1,7 +1,8 @@
 #include <arena.h>
 #include <slab.h>
 #include <ktest.h>
-#include <linker_func.h>
+#include <dma.h>
+#include <pmap.h>
 
 KTEST_SUITE("ARENA")
 
@@ -472,6 +473,27 @@ static bool test_self_source(void)
        return true;
 }
 
+static bool test_dma_pool(void)
+{
+       struct dma_pool *dp;
+       #define NR_LOOPS 10
+       void *va[NR_LOOPS];
+       dma_addr_t da[NR_LOOPS];
+
+       dp = dma_pool_create(__func__, NULL, 33, 16, 64);
+       for (int i = 0; i < NR_LOOPS; i++) {
+               va[i] = dma_pool_alloc(dp, MEM_WAIT, &da[i]);
+               KT_ASSERT(ALIGNED(va[i], 16));
+               KT_ASSERT(ROUNDUP(va[i] + 1, 64) >= va[i] + 33);
+               KT_ASSERT(PADDR(va[i]) == da[i]);
+       }
+       for (int i = 0; i < NR_LOOPS; i++)
+               dma_pool_free(dp, va[i], da[i]);
+       dma_pool_destroy(dp);
+
+       return true;
+}
+
 static struct ktest ktests[] = {
        KTEST_REG(nextfit,              CONFIG_KTEST_ARENA),
        KTEST_REG(bestfit,              CONFIG_KTEST_ARENA),
@@ -490,6 +512,7 @@ static struct ktest ktests[] = {
        KTEST_REG(xalloc_minmax,        CONFIG_KTEST_ARENA),
        KTEST_REG(accounting,           CONFIG_KTEST_ARENA),
        KTEST_REG(self_source,          CONFIG_KTEST_ARENA),
+       KTEST_REG(dma_pool,             CONFIG_KTEST_ARENA),
 };
 
 static int num_ktests = sizeof(ktests) / sizeof(struct ktest);