From 9f9597c965054d778e2dd84575e29b32ba1e3e07 Mon Sep 17 00:00:00 2001
From: benjamin gaignard <benjamin.gaignard@linaro.org>
Date: Wed, 9 Nov 2011 17:57:20 +0100
Subject: [PATCH 1/2] add debug info to CMA
  use debugfs to dump CMA bitmap status

Signed-off-by: benjamin gaignard <benjamin.gaignard@linaro.org>
---
 drivers/base/dma-contiguous.c |   74 +++++++++++++++++++++++++++++++++++++++-
 1 files changed, 72 insertions(+), 2 deletions(-)

diff --git a/drivers/base/dma-contiguous.c b/drivers/base/dma-contiguous.c
index e54bb76..1a57203 100644
--- a/drivers/base/dma-contiguous.c
+++ b/drivers/base/dma-contiguous.c
@@ -31,6 +31,9 @@
 #include <linux/swap.h>
 #include <linux/mm_types.h>
 #include <linux/dma-contiguous.h>
+#ifdef CONFIG_DEBUG_FS
+#include <linux/debugfs.h>
+#endif
 
 #ifndef SZ_1M
 #define SZ_1M (1 << 20)
@@ -46,6 +49,8 @@
 #  error phys_to_pfn implementation needed
 #endif
 
+static DEFINE_MUTEX(cma_mutex);
+
 struct cma {
 	unsigned long	base_pfn;
 	unsigned long	count;
@@ -62,6 +67,71 @@ struct cma *dma_contiguous_default_area;
 #define CONFIG_CMA_SIZE_PERCENTAGE 0
 #endif
 
+/* debugfs related functions */
+#ifdef CONFIG_DEBUG_FS
+/* when using debugfs_create_file private data field is set on inode
+ * copy data pointer to file private data */
+static int cma_debugfs_open(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+static ssize_t cma_debugfs_read(struct file *file, char __user *user_buf,
+			 size_t size, loff_t *ppos)
+{
+	struct cma *cma = file->private_data;
+	char *buf;
+	unsigned int len = 0, count = 0;
+	/* bitmap_scnprintf() produces one hex-digit per 4 bits of the
+	 * bitmap and one comma per every 8 hex-digits meaning par every
+	 * 32 bits, add 64 bytes for the additional characters
+	 */
+	unsigned int buffer_size = (cma->count/4) + (cma->count/32) + 64;
+	int bitmap_size = BITS_TO_LONGS(cma->count) * sizeof(long);
+
+	buf = kmalloc(buffer_size, GFP_KERNEL);
+	if (!buf)
+		return 0;
+
+	len +=
+	    snprintf(buf + len, buffer_size - len,
+		     "CMA base 0x%08lx, count %lx\n", cma->base_pfn,
+		     cma->count);
+	len += snprintf(buf + len, buffer_size - len, "CMA bitmap : ");
+
+	mutex_lock(&cma_mutex);
+	len +=
+	    bitmap_scnprintf(buf + len, buffer_size - len, cma->bitmap,
+			     bitmap_size);
+	mutex_unlock(&cma_mutex);
+
+	len += snprintf(buf + len, buffer_size - len, "\n");
+
+	if (len > buffer_size)
+		len = buffer_size;
+
+	count = simple_read_from_buffer(user_buf, size, ppos, buf, len);
+	kfree(buf);
+
+	return count;
+}
+
+static const struct file_operations cma_debugfs_fops = {
+	.open = cma_debugfs_open,
+	.read = cma_debugfs_read,
+	.llseek = default_llseek,
+	.owner = THIS_MODULE,
+};
+
+static void cma_debugfs_create_file(struct cma *cma)
+{
+	debugfs_create_file("cma", S_IRUSR, NULL, cma, &cma_debugfs_fops);
+}
+#else
+static inline void cma_debugfs_create_file(struct cma *cma) { }
+#endif
+
 static unsigned long size_abs = CONFIG_CMA_SIZE_ABSOLUTE * SZ_1M;
 static unsigned long size_percent = CONFIG_CMA_SIZE_PERCENTAGE;
 static long size_cmdline = -1;
@@ -133,8 +203,6 @@ void __init dma_contiguous_reserve(phys_addr_t limit)
 	dma_declare_contiguous(NULL, selected_size, 0, limit);
 };
 
-static DEFINE_MUTEX(cma_mutex);
-
 static void __cma_activate_area(unsigned long base_pfn, unsigned long count)
 {
 	unsigned long pfn = base_pfn;
@@ -176,6 +244,8 @@ static struct cma *__cma_create_area(unsigned long base_pfn,
 
 	__cma_activate_area(base_pfn, count);
 
+	cma_debugfs_create_file(cma);
+
 	pr_debug("%s: returned %p\n", __func__, (void *)cma);
 	return cma;
 
-- 
1.7.0.4

