linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] regmap: debugfs: Add a registers `range' file
@ 2013-02-14 12:31 Dimitris Papastamos
  2013-02-14 14:43 ` Mark Brown
  0 siblings, 1 reply; 3+ messages in thread
From: Dimitris Papastamos @ 2013-02-14 12:31 UTC (permalink / raw)
  To: Mark Brown; +Cc: linux-kernel, patches

This file lists the register ranges in the register map.  The condition
to split the range is based on the actual register attributes.  A range
is a contiguous block of registers with the same register attributes.

Signed-off-by: Dimitris Papastamos <dp@opensource.wolfsonmicro.com>
---
 drivers/base/regmap/internal.h       |   1 +
 drivers/base/regmap/regmap-debugfs.c | 122 +++++++++++++++++++++++++++++++++++
 2 files changed, 123 insertions(+)

diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 5a22bd3..b4e55a0 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -27,6 +27,7 @@ struct regmap_debugfs_off_cache {
 	off_t max;
 	unsigned int base_reg;
 	unsigned int max_reg;
+	unsigned int reg_attr;
 };
 
 struct regmap_format {
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 5fb23cb..5843eb1 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -56,6 +56,26 @@ static const struct file_operations regmap_name_fops = {
 	.llseek = default_llseek,
 };
 
+enum reg_attributes {
+	READABLE = 0x1,
+	WRITEABLE = 0x2,
+	VOLATILE = 0x4,
+};
+
+static inline unsigned int regmap_attr_bitmap(struct regmap *map,
+					      unsigned int reg)
+{
+	unsigned int reg_attr = 0;
+
+	if (regmap_readable(map, reg))
+		reg_attr |= READABLE;
+	if (regmap_writeable(map, reg))
+		reg_attr |= WRITEABLE;
+	if (regmap_volatile(map, reg))
+		reg_attr |= VOLATILE;
+	return reg_attr;
+}
+
 static void regmap_debugfs_free_dump_cache(struct regmap *map)
 {
 	struct regmap_debugfs_off_cache *c;
@@ -96,6 +116,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
 				if (c) {
 					c->max = p - 1;
 					c->max_reg = i - 1;
+					c->reg_attr = regmap_attr_bitmap(map, c->max_reg);
 					list_add_tail(&c->list,
 						      &map->debugfs_off_cache);
 					c = NULL;
@@ -123,6 +144,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
 	if (c) {
 		c->max = p - 1;
 		c->max_reg = i - 1;
+		c->reg_attr = regmap_attr_bitmap(map, c->max_reg);
 		list_add_tail(&c->list,
 			      &map->debugfs_off_cache);
 	}
@@ -307,6 +329,103 @@ static const struct file_operations regmap_range_fops = {
 	.llseek = default_llseek,
 };
 
+static void regmap_range_format_line(struct regmap *map,
+				     struct regmap_debugfs_off_cache *c,
+				     char *buf, size_t len)
+{
+	ssize_t buf_offset;
+
+	buf_offset = snprintf(buf, PAGE_SIZE, "%x-%x ",
+			      c->base_reg, c->max_reg);
+	buf_offset += snprintf(buf + buf_offset,
+			       PAGE_SIZE - buf_offset, "(");
+	if (c->reg_attr & READABLE)
+		buf_offset += snprintf(buf + buf_offset,
+				       PAGE_SIZE - buf_offset,
+				       "read, ");
+	if (c->reg_attr & WRITEABLE)
+		buf_offset += snprintf(buf + buf_offset,
+				       PAGE_SIZE - buf_offset,
+				       "write, ");
+	if (c->reg_attr & VOLATILE)
+		buf_offset += snprintf(buf + buf_offset,
+				       PAGE_SIZE - buf_offset,
+				       "volatile, ");
+	/* Rewind the last ", " as well */
+	buf_offset += snprintf(buf + buf_offset - 2,
+			       PAGE_SIZE - buf_offset, ")");
+}
+
+static ssize_t regmap_reg_ranges_read_file(struct file *file,
+					   char __user *user_buf, size_t count,
+					   loff_t *ppos)
+{
+	struct regmap *map = file->private_data;
+	struct regmap_debugfs_off_cache *c;
+	loff_t p = 0;
+	size_t buf_pos = 0;
+	char *buf;
+	char *entry;
+	int ret;
+
+	if (*ppos < 0 || !count)
+		return -EINVAL;
+
+	buf = kmalloc(count, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	entry = kmalloc(PAGE_SIZE, GFP_KERNEL);
+	if (!entry) {
+		kfree(buf);
+		return -ENOMEM;
+	}
+
+	/* While we are at it, build the register dump cache
+	 * now so the read() operation on the `registers' file
+	 * can benefit from using the cache.  We do not care
+	 * about the file position information that is contained
+	 * in the cache, just about the actual register blocks */
+	regmap_calc_tot_len(map, buf, count);
+	regmap_debugfs_get_dump_start(map, 0, *ppos, &p);
+
+	/* Reset file pointer as the fixed-format of the `registers'
+	 * file is not compatible with the `range' file */
+	p = 0;
+	list_for_each_entry(c, &map->debugfs_off_cache, list) {
+		regmap_range_format_line(map, c, entry, PAGE_SIZE);
+		if (p >= *ppos) {
+			if (buf_pos + 1 + strlen(entry) > count)
+				break;
+			snprintf(buf + buf_pos, count - buf_pos,
+				 "%s", entry);
+			buf_pos += strlen(entry);
+			buf[buf_pos] = '\n';
+			buf_pos++;
+		}
+		p += strlen(entry) + 1;
+	}
+
+	kfree(entry);
+	ret = buf_pos;
+
+	if (copy_to_user(user_buf, buf, buf_pos)) {
+		ret = -EFAULT;
+		goto out_buf;
+	}
+
+	*ppos += buf_pos;
+out_buf:
+	kfree(buf);
+	return ret;
+}
+
+static const struct file_operations regmap_reg_ranges_fops = {
+	.open = simple_open,
+	.read = regmap_reg_ranges_read_file,
+	.llseek = default_llseek,
+};
+
 static ssize_t regmap_access_read_file(struct file *file,
 				       char __user *user_buf, size_t count,
 				       loff_t *ppos)
@@ -399,6 +518,9 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
 	debugfs_create_file("name", 0400, map->debugfs,
 			    map, &regmap_name_fops);
 
+	debugfs_create_file("range", 0400, map->debugfs,
+			    map, &regmap_reg_ranges_fops);
+
 	if (map->max_register) {
 		debugfs_create_file("registers", 0400, map->debugfs,
 				    map, &regmap_map_fops);
-- 
1.8.1.3


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH 1/2] regmap: debugfs: Add a registers `range' file
  2013-02-14 12:31 [PATCH 1/2] regmap: debugfs: Add a registers `range' file Dimitris Papastamos
@ 2013-02-14 14:43 ` Mark Brown
  2013-02-14 15:00   ` Dimitris Papastamos
  0 siblings, 1 reply; 3+ messages in thread
From: Mark Brown @ 2013-02-14 14:43 UTC (permalink / raw)
  To: Dimitris Papastamos; +Cc: linux-kernel, patches

[-- Attachment #1: Type: text/plain, Size: 589 bytes --]

On Thu, Feb 14, 2013 at 12:31:44PM +0000, Dimitris Papastamos wrote:

> @@ -96,6 +116,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
>  				if (c) {
>  					c->max = p - 1;
>  					c->max_reg = i - 1;
> +					c->reg_attr = regmap_attr_bitmap(map, c->max_reg);
>  					list_add_tail(&c->list,
>  						      &map->debugfs_off_cache);
>  					c = NULL;

What happens if we have three registers like below?

   X:   read, write
   X+1: read, write, volatile
   X+2: read, write

It looks like we'll not flag X+1 as volatile, we'll just take the last
value we saw.

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH 1/2] regmap: debugfs: Add a registers `range' file
  2013-02-14 14:43 ` Mark Brown
@ 2013-02-14 15:00   ` Dimitris Papastamos
  0 siblings, 0 replies; 3+ messages in thread
From: Dimitris Papastamos @ 2013-02-14 15:00 UTC (permalink / raw)
  To: Mark Brown; +Cc: linux-kernel, patches

On Thu, Feb 14, 2013 at 02:43:06PM +0000, Mark Brown wrote:
> On Thu, Feb 14, 2013 at 12:31:44PM +0000, Dimitris Papastamos wrote:
> 
> > @@ -96,6 +116,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
> >  				if (c) {
> >  					c->max = p - 1;
> >  					c->max_reg = i - 1;
> > +					c->reg_attr = regmap_attr_bitmap(map, c->max_reg);
> >  					list_add_tail(&c->list,
> >  						      &map->debugfs_off_cache);
> >  					c = NULL;
> 
> What happens if we have three registers like below?
> 
>    X:   read, write
>    X+1: read, write, volatile
>    X+2: read, write
> 
> It looks like we'll not flag X+1 as volatile, we'll just take the last
> value we saw.

Hm yes, right.  So the problem here is that we split on the condition that
is something is printable or not.  We do not actually split on any of the
possible changes of the register attributes.  Any of the blocks of registers
should have registers that have exactly the same set of attributes.

I will look into this to fix.

Thanks,
Dimitris

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2013-02-14 15:00 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-02-14 12:31 [PATCH 1/2] regmap: debugfs: Add a registers `range' file Dimitris Papastamos
2013-02-14 14:43 ` Mark Brown
2013-02-14 15:00   ` Dimitris Papastamos

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).