diff --git a/tools/cma/cma_test.c b/tools/cma/cma_test.c
index 3ee89f3..3d3b074 100644
--- a/tools/cma/cma_test.c
+++ b/tools/cma/cma_test.c
@@ -6,66 +6,96 @@
   * Licensed under GPLv2 or later.
   */

-#include <linux/module.h>
  #include <linux/device.h>
+#include <linux/dma-mapping.h>
  #include <linux/fs.h>
+#include <linux/list.h>
  #include <linux/miscdevice.h>
-#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+
+struct cma_allocation {
+	struct list_head list;
+	unsigned long size;
+	dma_addr_t dma;
+	void *virt;
+};

-#define CMA_NUM  10
  static struct device *cma_dev;
-static dma_addr_t dma_phys[CMA_NUM];
-static void *dma_virt[CMA_NUM];
+static LIST_HEAD(cma_allocations);
+static DEFINE_SPINLOCK(cma_lock);

-/* any read request will free coherent memory, eg.
+/*
+ * Any read request will free a single coherent memory, eg.
   * cat /dev/cma_test
   */
  static ssize_t
  cma_test_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
  {
-	int i;
-
-	for (i = 0; i < CMA_NUM; i++) {
-		if (dma_virt[i]) {
-			dma_free_coherent(cma_dev, (i + 1) * SZ_1M, dma_virt[i], dma_phys[i]);
-			_dev_info(cma_dev, "free virt: %p phys: %p\n", dma_virt[i], (void *)dma_phys[i]);
-			dma_virt[i] = NULL;
-			break;
-		}
+	struct cma_allocation *alloc = NULL;
+
+	spin_lock(&cma_lock);
+	if (!list_empty(&cma_allocations)) {
+		alloc = list_first_entry(&cma_allocations,
+					 struct cma_allocation, list);
+		list_del(&alloc->list);
  	}
+	spin_unlock(&cma_lock);
+
+	if (alloc) {
+		dma_free_coherent(cma_dev, alloc->size, alloc->virt,
+				  alloc->dma);
+		_dev_info(cma_dev, "free virt: %p phys: %p\n",
+			  alloc->phys, (void *)alloc->dma);
+		kfree(alloc);
+	}
+
  	return 0;
  }

  /*
- * any write request will alloc coherent memory, eg.
- * echo 0 > /dev/cma_test
+ * Writes request specified number of pages, eg.
+ * echo 1024 > /dev/cma_test
   */
  static ssize_t
-cma_test_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+cma_test_write(struct file *file, const char __user *buf, size_t count,
+	       loff_t *ppos)
  {
-	int i;
+	struct cma_allocation *alloc;
  	int ret;

-	for (i = 0; i < CMA_NUM; i++) {
-		if (!dma_virt[i]) {
-			dma_virt[i] = dma_alloc_coherent(cma_dev, (i + 1) * SZ_1M, &dma_phys[i], GFP_KERNEL);
-
-			if (dma_virt[i]) {
-				void *p;
-				/* touch every page in the allocated memory */
-				for (p = dma_virt[i]; p <  dma_virt[i] + (i + 1) * SZ_1M; p += PAGE_SIZE)
-					*(u32 *)p = 0;
-
-				_dev_info(cma_dev, "alloc virt: %p phys: %p\n", dma_virt[i], (void *)dma_phys[i]);
-			} else {
-				dev_err(cma_dev, "no mem in CMA area\n");
-				ret = -ENOMEM;
-			}
-			break;
-		}
-	}
+	alloc = kmalloc(sizeof *alloc, GFP_KERNEL);
+	if (!alloc)
+		return -ENOMEM;
+
+	ret = kstrtouint_from_user(buf, count, 0, &alloc->size);
+	if (ret)
+		return ret;
+
+	if (!alloc->size)
+		return -EINVAL;
+
+	if (alloc->size > (ULONG_MAX << PAGE_SHIFT))
+		return -EOVERFLOW;

-	return count;
+	alloc->size >>= PAGE_SHIFT;
+	alloc->virt = dma_alloc_coherent(cma_dev, alloc->size,
+					 &alloc->dma, GFP_KERNEL);
+
+	if (alloc->virt) {
+		_dev_info(cma_dev, "alloc virt: %p phys: %p\n", alloc->virt,
+			  (void *)alloc->dma);
+
+		spin_lock(&cma_lock);
+		list_add_tail(&alloc->list, &cma_allocations);
+		spin_unlock(&cma_lock);
+
+		return count;
+	} else {
+		dev_err(cma_dev, "no mem in CMA area\n");
+		kfree(alloc);
+		return -ENOSPC;
+	}
  }

  static const struct file_operations cma_test_fops = {
