[PATCH] regmap: debugfs: Fix reading in register field units

2013-02-07 Thread Dimitris Papastamos
At the moment, if the length of the register field format is
N bytes, we can only get anything meaningful back to userspace
by providing a buffer that is N + 2 bytes large.  Fix this
so we that we only need to provide a buffer of N bytes.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regmap-debugfs.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index 0445f2f..96990d2 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -187,7 +187,7 @@ static ssize_t regmap_map_read_file(struct file *file, char 
__user *user_buf,
/* If we're in the region the user is trying to read */
if (p >= *ppos) {
/* ...but not beyond it */
-   if (buf_pos + 1 + map->debugfs_tot_len >= count)
+   if (buf_pos + map->debugfs_tot_len > count)
break;
 
/* Format the register */
-- 
1.8.1.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/2] regmap: debugfs: Add a `max_reg' member in struct regmap_debugfs_off_cache

2013-02-07 Thread Dimitris Papastamos
We are keeping track of the maximum register as well, this will make
things easier for us in sharing this code with the code implementing
the register ranges functionality.  It also simplifies a bit the
calculations when looking for the relevant block:offset from within
the cache.

Change-Id: I961320c4a56fdd25d74f1a6cc1b470ff22d8dbca
Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/internal.h   | 1 +
 drivers/base/regmap/regmap-debugfs.c | 6 ++
 2 files changed, 7 insertions(+)

diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index ef61b24..71d9b0a 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -25,6 +25,7 @@ struct regmap_debugfs_off_cache {
off_t min;
off_t max;
unsigned int base_reg;
+   unsigned int max_reg;
 };
 
 struct regmap_format {
diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index 96990d2..c2c51f7 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -93,6 +93,9 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
regmap_precious(map, i)) {
if (c) {
c->max = p - 1;
+   fpos_offset = c->max - c->min;
+   reg_offset = fpos_offset / 
map->debugfs_tot_len;
+   c->max_reg = c->base_reg + reg_offset;
list_add_tail(&c->list,
  &map->debugfs_off_cache);
c = NULL;
@@ -119,6 +122,9 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
/* Close the last entry off if we didn't scan beyond it */
if (c) {
c->max = p - 1;
+   fpos_offset = c->max - c->min;
+   reg_offset = fpos_offset / map->debugfs_tot_len;
+   c->max_reg = c->base_reg + reg_offset;
list_add_tail(&c->list,
  &map->debugfs_off_cache);
}
-- 
1.8.1.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/2] regmap: debugfs: Optimize seeking within blocks of registers

2013-02-07 Thread Dimitris Papastamos
Optimize this so that we can better guess where to start scanning
from.  We know the length of the register field format, therefore
given the file pointer position align to the nearest register
field and scan from there onwards.  We round down in this calculation
and we let the rest of the code figure out where to start scanning
from.

Change-Id: I2515e0981ef6b17f784dd0e389d0d4a13d47123c
Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regmap-debugfs.c | 14 +-
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index c2c51f7..1525f39 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -81,6 +81,8 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
struct regmap_debugfs_off_cache *c = NULL;
loff_t p = 0;
unsigned int i, ret;
+   unsigned int fpos_offset;
+   unsigned int reg_offset;
 
/*
 * If we don't have a cache build one so we don't have to do a
@@ -139,15 +141,17 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
return base;
}
 
-   /* Find the relevant block */
+   /* Find the relevant block:offset */
list_for_each_entry(c, &map->debugfs_off_cache, list) {
if (from >= c->min && from <= c->max) {
-   *pos = c->min;
-   return c->base_reg;
+   fpos_offset = from - c->min;
+   reg_offset = fpos_offset / map->debugfs_tot_len;
+   *pos = c->min + (reg_offset * map->debugfs_tot_len);
+   return c->base_reg + reg_offset;
}
 
-   *pos = c->min;
-   ret = c->base_reg;
+   *pos = c->max;
+   ret = c->max_reg;
}
 
return ret;
-- 
1.8.1.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/2 v2] regmap: debugfs: Add a `max_reg' member in struct regmap_debugfs_off_cache

2013-02-08 Thread Dimitris Papastamos
We are keeping track of the maximum register as well, this will make
things easier for us in sharing this code with the code implementing
the register ranges functionality.  It also simplifies a bit the
calculations when looking for the relevant block:offset from within
the cache.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/internal.h   | 1 +
 drivers/base/regmap/regmap-debugfs.c | 8 
 2 files changed, 9 insertions(+)

diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 0ae5b78..5a22bd3 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -26,6 +26,7 @@ struct regmap_debugfs_off_cache {
off_t min;
off_t max;
unsigned int base_reg;
+   unsigned int max_reg;
 };
 
 struct regmap_format {
diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index faa93cc..5fa2e6d 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -81,6 +81,8 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
struct regmap_debugfs_off_cache *c = NULL;
loff_t p = 0;
unsigned int i, ret;
+   unsigned int fpos_offset;
+   unsigned int reg_offset;
 
/*
 * If we don't have a cache build one so we don't have to do a
@@ -93,6 +95,9 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
regmap_precious(map, i)) {
if (c) {
c->max = p - 1;
+   fpos_offset = c->max - c->min;
+   reg_offset = fpos_offset / 
map->debugfs_tot_len;
+   c->max_reg = c->base_reg + reg_offset;
list_add_tail(&c->list,
  &map->debugfs_off_cache);
c = NULL;
@@ -119,6 +124,9 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
/* Close the last entry off if we didn't scan beyond it */
if (c) {
c->max = p - 1;
+   fpos_offset = c->max - c->min;
+   reg_offset = fpos_offset / map->debugfs_tot_len;
+   c->max_reg = c->base_reg + reg_offset;
list_add_tail(&c->list,
  &map->debugfs_off_cache);
}
-- 
1.8.1.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/2 v2] regmap: debugfs: Optimize seeking within blocks of registers

2013-02-08 Thread Dimitris Papastamos
Optimize this so that we can better guess where to start scanning
from.  We know the length of the register field format, therefore
given the file pointer position align to the nearest register
field and scan from there onwards.  We round down in this calculation
and we let the rest of the code figure out where to start scanning
from.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regmap-debugfs.c | 12 +++-
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index 5fa2e6d..8584fac 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -139,15 +139,17 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
WARN_ON(list_empty(&map->debugfs_off_cache));
ret = base;
 
-   /* Find the relevant block */
+   /* Find the relevant block:offset */
list_for_each_entry(c, &map->debugfs_off_cache, list) {
if (from >= c->min && from <= c->max) {
-   *pos = c->min;
-   return c->base_reg;
+   fpos_offset = from - c->min;
+   reg_offset = fpos_offset / map->debugfs_tot_len;
+   *pos = c->min + (reg_offset * map->debugfs_tot_len);
+   return c->base_reg + reg_offset;
}
 
-   *pos = c->min;
-   ret = c->base_reg;
+   *pos = c->max;
+   ret = c->max_reg;
}
 
return ret;
-- 
1.8.1.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v3] regmap: debugfs: Add a registers `range' file

2013-02-08 Thread Dimitris Papastamos
On Fri, Feb 08, 2013 at 11:46:55AM +, Mark Brown wrote:
> On Fri, Feb 01, 2013 at 12:05:39PM +0000, Dimitris Papastamos wrote:
> 
> > +struct regmap_reg_range  {
> > +   unsigned int start;
> > +   unsigned int end;
> > +   unsigned int attr;
> > +};
> 
> > +   i = start_reg;
> > +   while (i <= map->max_register) {
> > +   reg_attr = regmap_attr_bitmap(map, i);
> > +   switch (state) {
> 
> We're doing a linear scan through the entire register map here in order
> to build up a list of which registers exist, doing it every time the
> file is read.  This data structure looks *very* like the one we have for
> the reads themselves, it seems like we should be sharing the work here
> and using the same cache.

Yea that's true.  Will fix this and re-send.

Thanks,
Dimitris
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] regmap: debugfs: Factor out debugfs_tot_len calc into a function

2013-02-11 Thread Dimitris Papastamos
In preparation to support the regmap debugfs ranges functionality
factor this code out to a separate function.  We'll need to ensure
that the value has been correctly calculated from two separate places
in the code.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regmap-debugfs.c | 22 ++
 1 file changed, 14 insertions(+), 8 deletions(-)

diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index 246f459..78d5f20 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -155,6 +155,19 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
return ret;
 }
 
+static inline void regmap_calc_tot_len(struct regmap *map,
+  void *buf, size_t count)
+{
+   /* Calculate the length of a fixed format  */
+   if (!map->debugfs_tot_len) {
+   map->debugfs_reg_len = regmap_calc_reg_len(map->max_register,
+  buf, count);
+   map->debugfs_val_len = 2 * map->format.val_bytes;
+   map->debugfs_tot_len = map->debugfs_reg_len +
+   map->debugfs_val_len + 3;  /* : \n */
+   }
+}
+
 static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from,
   unsigned int to, char __user *user_buf,
   size_t count, loff_t *ppos)
@@ -173,14 +186,7 @@ static ssize_t regmap_read_debugfs(struct regmap *map, 
unsigned int from,
if (!buf)
return -ENOMEM;
 
-   /* Calculate the length of a fixed format  */
-   if (!map->debugfs_tot_len) {
-   map->debugfs_reg_len = regmap_calc_reg_len(map->max_register,
-  buf, count);
-   map->debugfs_val_len = 2 * map->format.val_bytes;
-   map->debugfs_tot_len = map->debugfs_reg_len +
-   map->debugfs_val_len + 3;  /* : \n */
-   }
+   regmap_calc_tot_len(map, buf, count);
 
/* Work out which register we're starting at */
start_reg = regmap_debugfs_get_dump_start(map, from, *ppos, &p);
-- 
1.8.1.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] regmap: debugfs: Add a registers `range' file

2013-02-11 Thread Dimitris Papastamos
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 
---
 Hi,

 This is applied on top of commit fea5ecc
 `regmap: debugfs: Optimize seeking within blocks of registers'

 drivers/base/regmap/internal.h   |   1 +
 drivers/base/regmap/regmap-debugfs.c | 128 ++-
 2 files changed, 128 insertions(+), 1 deletion(-)

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 78d5f20..fe3b6aa 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;
@@ -98,6 +118,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
fpos_offset = c->max - c->min;
reg_offset = fpos_offset / 
map->debugfs_tot_len;
c->max_reg = c->base_reg + reg_offset;
+   c->reg_attr = regmap_attr_bitmap(map, 
c->max_reg);
list_add_tail(&c->list,
  &map->debugfs_off_cache);
c = NULL;
@@ -127,6 +148,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
fpos_offset = c->max - c->min;
reg_offset = fpos_offset / map->debugfs_tot_len;
c->max_reg = c->base_reg + reg_offset;
+   c->reg_attr = regmap_attr_bitmap(map, c->max_reg);
list_add_tail(&c->list,
  &map->debugfs_off_cache);
}
@@ -305,12 +327,113 @@ static ssize_t regmap_range_read_file(struct file *file, 
char __user *user_buf,
   user_buf, count, ppos);
 }
 
-static const struct file_operations regmap_range_fops = {
+static const struct file_operations regmap_reg_ranges_fops = {
.open = simple_open,
.read = regmap_range_read_file,
.llseek = default_llseek,
 };
 
+struct regmap_reg_range  {
+   unsigned int start;
+   unsigned int end;
+   unsigned int attr;
+};
+
+static void regmap_range_format_line(struct regmap *map,
+struct regmap_reg_range *r,
+char *buf, size_t len)
+{
+   ssize_t buf_offset;
+
+   buf_offset = snprintf(buf, PAGE_SIZE, "%x-%x ",
+ r->start, r->end);
+   buf_offset += snprintf(buf + buf_offset,
+  PAGE_SIZE - buf_offset, "(");
+   if (r->attr & READABLE)
+   buf_offset += snprintf(buf + buf_offset,
+  PAGE_SIZE - buf_offset,
+  "read, ");
+   if (r->attr & WRITEABLE)
+   buf_offset += snprintf(buf + buf_offset,
+  PAGE_SIZE - buf_offset,
+  "write, ");
+   if (r->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,
+ 

Re: [PATCH] regmap: debugfs: Add a registers `range' file

2013-02-11 Thread Dimitris Papastamos
On Mon, Feb 11, 2013 at 01:16:41PM +, Mark Brown wrote:
> On Mon, Feb 11, 2013 at 10:52:23AM +0000, Dimitris Papastamos wrote:
> 
> > +struct regmap_reg_range  {
> > +   unsigned int start;
> > +   unsigned int end;
> > +   unsigned int attr;
> > +};
> 
> All we ever do with this struct is
> 
> > +   r.start = c->base_reg;
> > +   r.end = c->max_reg;
> > +   r.attr = c->reg_attr;
> 
> pack it with the contents of a cache entry.  Why not just use the cache
> entry directly?

Yea, will fix and re-send.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2] regmap: debugfs: Add a registers `range' file

2013-02-11 Thread Dimitris Papastamos
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 
---
 drivers/base/regmap/internal.h   |   1 +
 drivers/base/regmap/regmap-debugfs.c | 116 +++
 2 files changed, 117 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 78d5f20..e19359f 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;
@@ -98,6 +118,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
fpos_offset = c->max - c->min;
reg_offset = fpos_offset / 
map->debugfs_tot_len;
c->max_reg = c->base_reg + reg_offset;
+   c->reg_attr = regmap_attr_bitmap(map, 
c->max_reg);
list_add_tail(&c->list,
  &map->debugfs_off_cache);
c = NULL;
@@ -127,6 +148,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
fpos_offset = c->max - c->min;
reg_offset = fpos_offset / map->debugfs_tot_len;
c->max_reg = c->base_reg + reg_offset;
+   c->reg_attr = regmap_attr_bitmap(map, c->max_reg);
list_add_tail(&c->list,
  &map->debugfs_off_cache);
}
@@ -311,6 +333,97 @@ 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);
+ 

[PATCH] regmap: debugfs: Add a registers `range' file

2013-01-30 Thread Dimitris Papastamos
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 
---
 drivers/base/regmap/regmap-debugfs.c | 179 +++
 1 file changed, 179 insertions(+)

diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index faa93cc..4ed7503 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -295,6 +295,182 @@ static const struct file_operations regmap_range_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;
+}
+
+enum range_state {
+   RANGE_START,
+   RANGE_END,
+   RANGE_WITHIN,
+   RANGE_DONE,
+};
+
+struct regmap_reg_range  {
+   unsigned int start;
+   unsigned int end;
+   unsigned int attr;
+};
+
+static void regmap_range_format_line(struct regmap *map,
+struct regmap_reg_range *r,
+char *buf, size_t len)
+{
+   int reg_len;
+   ssize_t buf_offset;
+
+   reg_len = regmap_calc_reg_len(map->max_register, buf, len);
+
+   buf_offset = snprintf(buf, PAGE_SIZE, "%.*x-%.*x ",
+ reg_len, r->start,
+ reg_len, r->end);
+   buf_offset += snprintf(buf + buf_offset,
+  PAGE_SIZE - buf_offset, "(");
+   if (r->attr & READABLE)
+   buf_offset += snprintf(buf + buf_offset,
+  PAGE_SIZE - buf_offset,
+  "read, ");
+   if (r->attr & WRITEABLE)
+   buf_offset += snprintf(buf + buf_offset,
+  PAGE_SIZE - buf_offset,
+  "write, ");
+   if (r->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_range_read_file(struct file *file,
+ char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+   struct regmap *map = file->private_data;
+   int ret;
+   char *buf;
+   size_t buf_pos = 0;
+   loff_t p = 0;
+   unsigned int start_reg;
+   int i;
+   unsigned int reg_attr;
+   unsigned int block_start, block_end, block_attr;
+   enum range_state state;
+   struct list_head range_head;
+   struct regmap_reg_range r;
+   char *entry;
+   bool scanning = true;
+
+   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;
+   }
+
+   INIT_LIST_HEAD(&range_head);
+
+   start_reg = 0;
+   block_attr = regmap_attr_bitmap(map, start_reg);
+   block_start = block_end = start_reg;
+   state = RANGE_START;
+
+   i = start_reg;
+   while (i <= map->max_register && scanning) {
+   reg_attr = regmap_attr_bitmap(map, i);
+   switch (state) {
+   case RANGE_START:
+   block_start = i;
+   block_attr = reg_attr;
+   state = RANGE_WITHIN;
+   break;
+   case RANGE_END:
+   r.start = block_start;
+   r.end = block_end;
+   r.attr = block_attr;
+   /* Only care about regions with any of the 3 register
+  attributes */
+   if (r.attr) {
+   regmap_range_format_line(map, &r, entry, 
PAGE_SIZE);
+   if (p >= *ppos) {
+   if (buf_pos + 1 + strlen(entry) >= 
count)

[PATCH v2] regmap: debugfs: Add a registers `range' file

2013-01-30 Thread Dimitris Papastamos
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 
---
 drivers/base/regmap/regmap-debugfs.c | 177 +++
 1 file changed, 177 insertions(+)

diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index 0866c42..00db799 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -240,6 +240,180 @@ static const struct file_operations regmap_map_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;
+}
+
+enum range_state {
+   RANGE_START,
+   RANGE_END,
+   RANGE_WITHIN,
+   RANGE_DONE,
+};
+
+struct regmap_reg_range  {
+   unsigned int start;
+   unsigned int end;
+   unsigned int attr;
+};
+
+static void regmap_range_format_line(struct regmap *map,
+struct regmap_reg_range *r,
+char *buf, size_t len)
+{
+   int reg_len;
+   ssize_t buf_offset;
+
+   buf_offset = snprintf(buf, PAGE_SIZE, "%x-%x ",
+ r->start, r->end);
+   buf_offset += snprintf(buf + buf_offset,
+  PAGE_SIZE - buf_offset, "(");
+   if (r->attr & READABLE)
+   buf_offset += snprintf(buf + buf_offset,
+  PAGE_SIZE - buf_offset,
+  "read, ");
+   if (r->attr & WRITEABLE)
+   buf_offset += snprintf(buf + buf_offset,
+  PAGE_SIZE - buf_offset,
+  "write, ");
+   if (r->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_range_read_file(struct file *file,
+ char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+   struct regmap *map = file->private_data;
+   int ret;
+   char *buf;
+   size_t buf_pos = 0;
+   loff_t p = 0;
+   unsigned int start_reg;
+   int i;
+   unsigned int reg_attr;
+   unsigned int block_start, block_end, block_attr;
+   enum range_state state;
+   struct regmap_reg_range r;
+   char *entry;
+   bool scanning = true;
+
+   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;
+   }
+
+   start_reg = 0;
+   block_attr = regmap_attr_bitmap(map, start_reg);
+   block_start = block_end = start_reg;
+   state = RANGE_START;
+
+   i = start_reg;
+   while (i <= map->max_register && scanning) {
+   reg_attr = regmap_attr_bitmap(map, i);
+   switch (state) {
+   case RANGE_START:
+   block_start = i;
+   block_attr = reg_attr;
+   state = RANGE_WITHIN;
+   break;
+   case RANGE_END:
+   r.start = block_start;
+   r.end = block_end;
+   r.attr = block_attr;
+   /* Only care about regions where any of the 3 register
+  attributes are set */
+   if (r.attr) {
+   regmap_range_format_line(map, &r, entry, 
PAGE_SIZE);
+   if (p >= *ppos) {
+   /* We can't fit any more data into this 
buf
+* so no use to loop around anymore, 
just
+* give the data back to user */
+   if (buf_pos + 1 + strlen(entry

[PATCH v3] regmap: debugfs: Add a registers `range' file

2013-02-01 Thread Dimitris Papastamos
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 
---
 Simplified the code a bit, removed the `scanning' flag which was
 indeed unnecessary.

 This should be the final version of the patch.

 drivers/base/regmap/regmap-debugfs.c | 175 +++
 1 file changed, 175 insertions(+)

diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index 0866c42..2c8fd4e 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -240,6 +240,178 @@ static const struct file_operations regmap_map_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;
+}
+
+enum range_state {
+   RANGE_START,
+   RANGE_END,
+   RANGE_WITHIN,
+   RANGE_DONE,
+};
+
+struct regmap_reg_range  {
+   unsigned int start;
+   unsigned int end;
+   unsigned int attr;
+};
+
+static void regmap_range_format_line(struct regmap *map,
+struct regmap_reg_range *r,
+char *buf, size_t len)
+{
+   ssize_t buf_offset;
+
+   buf_offset = snprintf(buf, PAGE_SIZE, "%x-%x ",
+ r->start, r->end);
+   buf_offset += snprintf(buf + buf_offset,
+  PAGE_SIZE - buf_offset, "(");
+   if (r->attr & READABLE)
+   buf_offset += snprintf(buf + buf_offset,
+  PAGE_SIZE - buf_offset,
+  "read, ");
+   if (r->attr & WRITEABLE)
+   buf_offset += snprintf(buf + buf_offset,
+  PAGE_SIZE - buf_offset,
+  "write, ");
+   if (r->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_range_read_file(struct file *file,
+ char __user *user_buf, size_t count,
+ loff_t *ppos)
+{
+   struct regmap *map = file->private_data;
+   int ret;
+   char *buf;
+   size_t buf_pos = 0;
+   loff_t p = 0;
+   unsigned int start_reg;
+   int i;
+   unsigned int reg_attr;
+   unsigned int block_start, block_end, block_attr;
+   enum range_state state;
+   struct regmap_reg_range r;
+   char *entry;
+
+   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;
+   }
+
+   start_reg = 0;
+   block_attr = regmap_attr_bitmap(map, start_reg);
+   block_start = block_end = start_reg;
+   state = RANGE_START;
+
+   i = start_reg;
+   while (i <= map->max_register) {
+   reg_attr = regmap_attr_bitmap(map, i);
+   switch (state) {
+   case RANGE_START:
+   block_start = i;
+   block_attr = reg_attr;
+   state = RANGE_WITHIN;
+   break;
+   case RANGE_END:
+   r.start = block_start;
+   r.end = block_end;
+   r.attr = block_attr;
+   /* Only care about regions where any of the 3 register
+  attributes are set */
+   if (r.attr) {
+   regmap_range_format_line(map, &r, entry, 
PAGE_SIZE);
+   if (p >= *ppos) {
+   /* We can't fit any more data into this 
buf
+* so no use to loop around anymore, 
just
+   

[PATCH 1/2 v2] regmap: debugfs: Simplify calculation of `c->max_reg'

2013-02-20 Thread Dimitris Papastamos
We don't need to use any of the file position information
to calculate the base and max register of each block.  Just
use the counter directly.

Set `i = base' at the top to avoid GCC flow analysis bugs.  The
value of `i' can never be undefined or 0 in the if (c) { ... }.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regmap-debugfs.c | 11 ---
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index 78d5f20..e14cb2d 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -88,16 +88,15 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
 * If we don't have a cache build one so we don't have to do a
 * linear scan each time.
 */
+   i = base;
if (list_empty(&map->debugfs_off_cache)) {
-   for (i = base; i <= map->max_register; i += map->reg_stride) {
+   for (; i <= map->max_register; i += map->reg_stride) {
/* Skip unprinted registers, closing off cache entry */
if (!regmap_readable(map, i) ||
regmap_precious(map, i)) {
if (c) {
c->max = p - 1;
-   fpos_offset = c->max - c->min;
-   reg_offset = fpos_offset / 
map->debugfs_tot_len;
-   c->max_reg = c->base_reg + reg_offset;
+   c->max_reg = i - map->reg_stride;
list_add_tail(&c->list,
  &map->debugfs_off_cache);
c = NULL;
@@ -124,9 +123,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
/* Close the last entry off if we didn't scan beyond it */
if (c) {
c->max = p - 1;
-   fpos_offset = c->max - c->min;
-   reg_offset = fpos_offset / map->debugfs_tot_len;
-   c->max_reg = c->base_reg + reg_offset;
+   c->max_reg = i - map->reg_stride;
list_add_tail(&c->list,
  &map->debugfs_off_cache);
}
-- 
1.8.1.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/2 v2] regmap: debugfs: Add a registers `range' file

2013-02-20 Thread Dimitris Papastamos
This file lists the register ranges in the register map.  The condition
to split the range is based on whether the block is readable or not.

Ensure that we lock the `debugfs_off_cache' list whenever we access
and modify the list.  There is a possible race otherwise between the
read() operations of the `registers' file and the `range' file.

Signed-off-by: Dimitris Papastamos 
---
 Hi,

 Moved the locking of the `debugfs_off_cache' list over to this patch.
 I think this should be the final version of the patch.

 drivers/base/regmap/internal.h   |  1 +
 drivers/base/regmap/regmap-debugfs.c | 83 
 2 files changed, 84 insertions(+)

diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 5a22bd3..dc23508 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -76,6 +76,7 @@ struct regmap {
unsigned int debugfs_tot_len;
 
struct list_head debugfs_off_cache;
+   struct mutex cache_lock;
 #endif
 
unsigned int max_register;
diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index e14cb2d..61e2c52 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -88,6 +88,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
 * If we don't have a cache build one so we don't have to do a
 * linear scan each time.
 */
+   mutex_lock(&map->cache_lock);
i = base;
if (list_empty(&map->debugfs_off_cache)) {
for (; i <= map->max_register; i += map->reg_stride) {
@@ -110,6 +111,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c) {
regmap_debugfs_free_dump_cache(map);
+   mutex_unlock(&map->cache_lock);
return base;
}
c->min = p;
@@ -142,12 +144,14 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
fpos_offset = from - c->min;
reg_offset = fpos_offset / map->debugfs_tot_len;
*pos = c->min + (reg_offset * map->debugfs_tot_len);
+   mutex_unlock(&map->cache_lock);
return c->base_reg + reg_offset;
}
 
*pos = c->max;
ret = c->max_reg;
}
+   mutex_unlock(&map->cache_lock);
 
return ret;
 }
@@ -308,6 +312,79 @@ static const struct file_operations regmap_range_fops = {
.llseek = default_llseek,
 };
 
+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;
+   mutex_lock(&map->cache_lock);
+   list_for_each_entry(c, &map->debugfs_off_cache, list) {
+   snprintf(entry, PAGE_SIZE, "%x-%x",
+c->base_reg, c->max_reg);
+   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;
+   }
+   mutex_unlock(&map->cache_lock);
+
+   kfree(entry)

[PATCH v2] regmap: Expose total memory consumption in the rbtree debugfs entry

2013-03-12 Thread Dimitris Papastamos
Provide a feel of how much overhead the rbtree cache adds to
the game.

Signed-off-by: Dimitris Papastamos 
---
 Print the size in bytes instead of kB.

 drivers/base/regmap/regcache-rbtree.c | 9 +++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/drivers/base/regmap/regcache-rbtree.c 
b/drivers/base/regmap/regcache-rbtree.c
index 461cff8..11011ec 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -138,15 +138,20 @@ static int rbtree_show(struct seq_file *s, void *ignored)
struct regcache_rbtree_node *n;
struct rb_node *node;
unsigned int base, top;
+   size_t mem_size;
int nodes = 0;
int registers = 0;
int this_registers, average;
 
map->lock(map);
 
+   mem_size = sizeof(*rbtree_ctx);
+
for (node = rb_first(&rbtree_ctx->root); node != NULL;
 node = rb_next(node)) {
n = container_of(node, struct regcache_rbtree_node, node);
+   mem_size += sizeof(*n);
+   mem_size += (n->blklen * map->cache_word_size);
 
regcache_rbtree_get_base_top_reg(map, n, &base, &top);
this_registers = ((top - base) / map->reg_stride) + 1;
@@ -161,8 +166,8 @@ static int rbtree_show(struct seq_file *s, void *ignored)
else
average = 0;
 
-   seq_printf(s, "%d nodes, %d registers, average %d registers\n",
-  nodes, registers, average);
+   seq_printf(s, "%d nodes, %d registers, average %d registers, memory 
overhead %zuB\n",
+  nodes, registers, average, mem_size);
 
map->unlock(map);
 
-- 
1.8.1.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2] regmap: Expose total memory consumption in the rbtree debugfs entry

2013-03-12 Thread Dimitris Papastamos
On Tue, Mar 12, 2013 at 06:12:47PM +, Mark Brown wrote:
> On Tue, Mar 12, 2013 at 05:26:49PM +0000, Dimitris Papastamos wrote:
> 
> > +   mem_size = sizeof(*rbtree_ctx);
> > +
> > for (node = rb_first(&rbtree_ctx->root); node != NULL;
> >  node = rb_next(node)) {
> > n = container_of(node, struct regcache_rbtree_node, node);
> > +   mem_size += sizeof(*n);
> > +   mem_size += (n->blklen * map->cache_word_size);
> 
> This appears to ignore the size of the node structure and only have the
> root context and the data.

I've got mem_size += sizeof(*n) which is the size of the rbnode.  That
contains the underlying rbtree node links.

Thanks,
Dimitris
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] regmap: Cut down on the average # of nodes in the rbtree cache

2013-03-13 Thread Dimitris Papastamos
This patch aims to bring down the average number of nodes
in the rbtree cache and increase the average number of registers
per node.  This should improve general lookup and traversal times.
This is achieved by setting the minimum size of a block within the
rbnode to the size of the rbnode itself.  This will essentially
cache possibly non-existent registers so to combat this scenario,
we keep a separate bitmap in memory which keeps track of which register
exists.  The memory overhead of this change is likely in the order of
~5-10%, possibly less depending on the register file layout.  On my test
system with a bitmap of ~4300 bits and a relatively sparse register
layout, the memory requirements for the entire cache did not increase
(the cutting down of nodes which was about 50% of the original number
compensated the situation).

A second patch that can be built on top of this can look at the
ratio `sizeof(*rbnode) / map->cache_word_size' in order to suitably
adjust the block length of each block.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regcache-rbtree.c | 42 +--
 1 file changed, 40 insertions(+), 2 deletions(-)

diff --git a/drivers/base/regmap/regcache-rbtree.c 
b/drivers/base/regmap/regcache-rbtree.c
index 11011ec..acd63cd 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -36,6 +36,8 @@ struct regcache_rbtree_node {
 struct regcache_rbtree_ctx {
struct rb_root root;
struct regcache_rbtree_node *cached_rbnode;
+   unsigned long *reg_bitmap;
+   unsigned int reg_bitmap_nbits;
 };
 
 static inline void regcache_rbtree_get_base_top_reg(
@@ -146,6 +148,7 @@ static int rbtree_show(struct seq_file *s, void *ignored)
map->lock(map);
 
mem_size = sizeof(*rbtree_ctx);
+   mem_size += BITS_TO_LONGS(rbtree_ctx->reg_bitmap_nbits) * sizeof(long);
 
for (node = rb_first(&rbtree_ctx->root); node != NULL;
 node = rb_next(node)) {
@@ -199,6 +202,8 @@ static void rbtree_debugfs_init(struct regmap *map)
 static int regcache_rbtree_init(struct regmap *map)
 {
struct regcache_rbtree_ctx *rbtree_ctx;
+   void *reg_bitmap;
+   unsigned int bitmap_size;
int i;
int ret;
 
@@ -210,18 +215,36 @@ static int regcache_rbtree_init(struct regmap *map)
rbtree_ctx->root = RB_ROOT;
rbtree_ctx->cached_rbnode = NULL;
 
+   for (bitmap_size = 0, i = 0; i < map->num_reg_defaults; i++)
+   if (map->reg_defaults[i].reg > bitmap_size)
+   bitmap_size = map->reg_defaults[i].reg;
+   bitmap_size++;
+
+   reg_bitmap = kmalloc(BITS_TO_LONGS(bitmap_size) * sizeof(long),
+GFP_KERNEL);
+   if (!reg_bitmap) {
+   ret = -ENOMEM;
+   goto err;
+   }
+   bitmap_zero(reg_bitmap, bitmap_size);
+   rbtree_ctx->reg_bitmap = reg_bitmap;
+   rbtree_ctx->reg_bitmap_nbits = bitmap_size;
+
for (i = 0; i < map->num_reg_defaults; i++) {
ret = regcache_rbtree_write(map,
map->reg_defaults[i].reg,
map->reg_defaults[i].def);
if (ret)
-   goto err;
+   goto err_bitmap;
+   set_bit(map->reg_defaults[i].reg, reg_bitmap);
}
 
rbtree_debugfs_init(map);
 
return 0;
 
+err_bitmap:
+   kfree(reg_bitmap);
 err:
regcache_rbtree_exit(map);
return ret;
@@ -238,6 +261,8 @@ static int regcache_rbtree_exit(struct regmap *map)
if (!rbtree_ctx)
return 0;
 
+   kfree(rbtree_ctx->reg_bitmap);
+
/* free up the rbtree */
next = rb_first(&rbtree_ctx->root);
while (next) {
@@ -258,11 +283,17 @@ static int regcache_rbtree_exit(struct regmap *map)
 static int regcache_rbtree_read(struct regmap *map,
unsigned int reg, unsigned int *value)
 {
+   struct regcache_rbtree_ctx *rbtree_ctx = map->cache;
struct regcache_rbtree_node *rbnode;
+   unsigned long *bitmap;
unsigned int reg_tmp;
 
+   bitmap = rbtree_ctx->reg_bitmap;
rbnode = regcache_rbtree_lookup(map, reg);
if (rbnode) {
+   /* Does this register exist?  If not bail out. */
+   if (!(bitmap[BIT_WORD(reg)] & BIT_MASK(reg)))
+   return -ENOENT;
reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
*value = regcache_rbtree_get_register(map, rbnode, reg_tmp);
} else {
@@ -354,7 +385,7 @@ static int regcache_rbtree_write(struct regmap *map, 
unsigned int reg,
rbnode = kzalloc(sizeof *rbnode, GFP_KERNEL);
if (!rbnode)
return -ENOMEM;
-   rbn

Re: [PATCH v2] regmap: Expose total memory consumption in the rbtree debugfs entry

2013-03-13 Thread Dimitris Papastamos
On Wed, Mar 13, 2013 at 11:13:26AM +, Mark Brown wrote:
> On Tue, Mar 12, 2013 at 05:26:49PM +0000, Dimitris Papastamos wrote:
> > Provide a feel of how much overhead the rbtree cache adds to
> > the game.
> 
> Applied, with a tweak to the log to say "used X bytes" for clarity (it's
> arguable if the cached data itself is overhead, depends on what you're
> comparing to).

Aha yes, it makes sense.

Thanks,
Dimitris
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2] regmap: Cut down on the average # of nodes in the rbtree cache

2013-03-14 Thread Dimitris Papastamos
This patch aims to bring down the average number of nodes
in the rbtree cache and increase the average number of registers
per node.  This should improve general lookup and traversal times.
This is achieved by setting the minimum size of a block within the
rbnode to the size of the rbnode itself.  This will essentially
cache possibly non-existent registers so to combat this scenario,
we keep a separate bitmap in memory which keeps track of which registers
exist.  The memory overhead of this change is likely in the order of
~5-10%, possibly less depending on the register file layout.  On my test
system with a bitmap of ~4300 bits and a relatively sparse register
layout, the memory requirements for the entire cache did not increase
(the cutting down of nodes which was about 50% of the original number
compensated the situation).

A second patch that can be built on top of this can look at the
ratio `sizeof(*rbnode) / map->cache_word_size' in order to suitably
adjust the block length of each block.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regcache-rbtree.c | 63 ++-
 1 file changed, 62 insertions(+), 1 deletion(-)

diff --git a/drivers/base/regmap/regcache-rbtree.c 
b/drivers/base/regmap/regcache-rbtree.c
index 11011ec..dd5ed6c 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -36,6 +36,8 @@ struct regcache_rbtree_node {
 struct regcache_rbtree_ctx {
struct rb_root root;
struct regcache_rbtree_node *cached_rbnode;
+   unsigned long *reg_present;
+   unsigned int reg_present_nbits;
 };
 
 static inline void regcache_rbtree_get_base_top_reg(
@@ -146,6 +148,7 @@ static int rbtree_show(struct seq_file *s, void *ignored)
map->lock(map);
 
mem_size = sizeof(*rbtree_ctx);
+   mem_size += BITS_TO_LONGS(rbtree_ctx->reg_present_nbits) * sizeof(long);
 
for (node = rb_first(&rbtree_ctx->root); node != NULL;
 node = rb_next(node)) {
@@ -196,6 +199,44 @@ static void rbtree_debugfs_init(struct regmap *map)
 }
 #endif
 
+static int enlarge_reg_present_bitmap(struct regmap *map, unsigned int reg)
+{
+   struct regcache_rbtree_ctx *rbtree_ctx;
+   unsigned long *reg_present;
+   unsigned int reg_present_size;
+   unsigned int nregs;
+   int i;
+
+   rbtree_ctx = map->cache;
+   nregs = reg + 1;
+   reg_present_size = BITS_TO_LONGS(nregs);
+   reg_present_size *= sizeof(long);
+
+   if (!rbtree_ctx->reg_present) {
+   reg_present = kmalloc(reg_present_size, GFP_KERNEL);
+   if (!reg_present)
+   return -ENOMEM;
+   bitmap_zero(reg_present, nregs);
+   rbtree_ctx->reg_present = reg_present;
+   rbtree_ctx->reg_present_nbits = nregs;
+   return 0;
+   }
+
+   if (nregs > rbtree_ctx->reg_present_nbits) {
+   reg_present = krealloc(rbtree_ctx->reg_present,
+  reg_present_size, GFP_KERNEL);
+   if (!reg_present)
+   return -ENOMEM;
+   for (i = 0; i < nregs; i++)
+   if (i >= rbtree_ctx->reg_present_nbits)
+   clear_bit(i, reg_present);
+   rbtree_ctx->reg_present = reg_present;
+   rbtree_ctx->reg_present_nbits = nregs;
+   }
+
+   return 0;
+}
+
 static int regcache_rbtree_init(struct regmap *map)
 {
struct regcache_rbtree_ctx *rbtree_ctx;
@@ -209,6 +250,8 @@ static int regcache_rbtree_init(struct regmap *map)
rbtree_ctx = map->cache;
rbtree_ctx->root = RB_ROOT;
rbtree_ctx->cached_rbnode = NULL;
+   rbtree_ctx->reg_present = NULL;
+   rbtree_ctx->reg_present_nbits = 0;
 
for (i = 0; i < map->num_reg_defaults; i++) {
ret = regcache_rbtree_write(map,
@@ -238,6 +281,8 @@ static int regcache_rbtree_exit(struct regmap *map)
if (!rbtree_ctx)
return 0;
 
+   kfree(rbtree_ctx->reg_present);
+
/* free up the rbtree */
next = rb_first(&rbtree_ctx->root);
while (next) {
@@ -258,12 +303,17 @@ static int regcache_rbtree_exit(struct regmap *map)
 static int regcache_rbtree_read(struct regmap *map,
unsigned int reg, unsigned int *value)
 {
+   struct regcache_rbtree_ctx *rbtree_ctx;
struct regcache_rbtree_node *rbnode;
unsigned int reg_tmp;
 
+   rbtree_ctx = map->cache;
rbnode = regcache_rbtree_lookup(map, reg);
if (rbnode) {
reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
+   /* Does this register exist?  If not bail out. */
+   if (!(rbtree_ctx->reg_present[BIT_WORD(reg)] & BIT_MASK(reg)))
+   return -ENOENT;

[PATCH] regmap: Remove __attribute__ ((packed))

2013-03-14 Thread Dimitris Papastamos
There is no point having this.  The space gains are trivial if there
are any at all.

Change-Id: Ib4b1320420f780dcf5b9a1e4b05f5805691c4d9f
Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regcache-rbtree.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/base/regmap/regcache-rbtree.c 
b/drivers/base/regmap/regcache-rbtree.c
index dd5ed6c..383fc00 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -31,7 +31,7 @@ struct regcache_rbtree_node {
void *block;
/* number of registers available in the block */
unsigned int blklen;
-} __attribute__ ((packed));
+};
 
 struct regcache_rbtree_ctx {
struct rb_root root;
-- 
1.8.1.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2] regmap: Cut down on the average # of nodes in the rbtree cache

2013-03-15 Thread Dimitris Papastamos
On Fri, Mar 15, 2013 at 01:35:34AM +, Mark Brown wrote:
> On Thu, Mar 14, 2013 at 02:52:35PM +0000, Dimitris Papastamos wrote:
> 
> > if (rbnode) {
> > reg_tmp = (reg - rbnode->base_reg) / map->reg_stride;
> > +   /* Does this register exist?  If not bail out. */
> > +   if (!(rbtree_ctx->reg_present[BIT_WORD(reg)] & BIT_MASK(reg)))
> > +   return -ENOENT;
> > *value = regcache_rbtree_get_register(map, rbnode, reg_tmp);
> 
> This means that every caller is going to need to have a check added to
> see if the register is present which doesn't seem great, we should at
> least have a function to do the check.  The check is fiddly enough.

Yea makes sense, will factor it out.

Thanks,
Dimitris
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] regmap: Remove __attribute__ ((packed))

2013-03-15 Thread Dimitris Papastamos
On Fri, Mar 15, 2013 at 01:36:40AM +, Mark Brown wrote:
> On Thu, Mar 14, 2013 at 03:26:19PM +0000, Dimitris Papastamos wrote:
> > There is no point having this.  The space gains are trivial if there
> > are any at all.
> 
> Applied, but numbers would have been nice and...
> 
> > Change-Id: Ib4b1320420f780dcf5b9a1e4b05f5805691c4d9f
> 
> ...this shouldn't be in upstream submissions.

Oops, sorry for the Change-Id.

On my system there was no benefit of using it, it just happens
that the struct is aligned properly and needs no padding.

Thanks,
Dimitris
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v3] regmap: Cut down on the average # of nodes in the rbtree cache

2013-03-15 Thread Dimitris Papastamos
This patch aims to bring down the average number of nodes
in the rbtree cache and increase the average number of registers
per node.  This should improve general lookup and traversal times.
This is achieved by setting the minimum size of a block within the
rbnode to the size of the rbnode itself.  This will essentially
cache possibly non-existent registers so to combat this scenario,
we keep a separate bitmap in memory which keeps track of which register
exists.  The memory overhead of this change is likely in the order of
~5-10%, possibly less depending on the register file layout.  On my test
system with a bitmap of ~4300 bits and a relatively sparse register
layout, the memory requirements for the entire cache did not increase
(the cutting down of nodes which was about 50% of the original number
compensated the situation).

A second patch that can be built on top of this can look at the
ratio `sizeof(*rbnode) / map->cache_word_size' in order to suitably
adjust the block length of each block.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regcache-rbtree.c | 70 ++-
 1 file changed, 69 insertions(+), 1 deletion(-)

diff --git a/drivers/base/regmap/regcache-rbtree.c 
b/drivers/base/regmap/regcache-rbtree.c
index 11011ec..fe59b40 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -36,6 +36,8 @@ struct regcache_rbtree_node {
 struct regcache_rbtree_ctx {
struct rb_root root;
struct regcache_rbtree_node *cached_rbnode;
+   unsigned long *reg_present;
+   unsigned int reg_present_nbits;
 };
 
 static inline void regcache_rbtree_get_base_top_reg(
@@ -146,6 +148,7 @@ static int rbtree_show(struct seq_file *s, void *ignored)
map->lock(map);
 
mem_size = sizeof(*rbtree_ctx);
+   mem_size += BITS_TO_LONGS(rbtree_ctx->reg_present_nbits) * sizeof(long);
 
for (node = rb_first(&rbtree_ctx->root); node != NULL;
 node = rb_next(node)) {
@@ -196,6 +199,44 @@ static void rbtree_debugfs_init(struct regmap *map)
 }
 #endif
 
+static int enlarge_reg_present_bitmap(struct regmap *map, unsigned int reg)
+{
+   struct regcache_rbtree_ctx *rbtree_ctx;
+   unsigned long *reg_present;
+   unsigned int reg_present_size;
+   unsigned int nregs;
+   int i;
+
+   rbtree_ctx = map->cache;
+   nregs = reg + 1;
+   reg_present_size = BITS_TO_LONGS(nregs);
+   reg_present_size *= sizeof(long);
+
+   if (!rbtree_ctx->reg_present) {
+   reg_present = kmalloc(reg_present_size, GFP_KERNEL);
+   if (!reg_present)
+   return -ENOMEM;
+   bitmap_zero(reg_present, nregs);
+   rbtree_ctx->reg_present = reg_present;
+   rbtree_ctx->reg_present_nbits = nregs;
+   return 0;
+   }
+
+   if (nregs > rbtree_ctx->reg_present_nbits) {
+   reg_present = krealloc(rbtree_ctx->reg_present,
+  reg_present_size, GFP_KERNEL);
+   if (!reg_present)
+   return -ENOMEM;
+   for (i = 0; i < nregs; i++)
+   if (i >= rbtree_ctx->reg_present_nbits)
+   clear_bit(i, reg_present);
+   rbtree_ctx->reg_present = reg_present;
+   rbtree_ctx->reg_present_nbits = nregs;
+   }
+
+   return 0;
+}
+
 static int regcache_rbtree_init(struct regmap *map)
 {
struct regcache_rbtree_ctx *rbtree_ctx;
@@ -209,6 +250,8 @@ static int regcache_rbtree_init(struct regmap *map)
rbtree_ctx = map->cache;
rbtree_ctx->root = RB_ROOT;
rbtree_ctx->cached_rbnode = NULL;
+   rbtree_ctx->reg_present = NULL;
+   rbtree_ctx->reg_present_nbits = 0;
 
for (i = 0; i < map->num_reg_defaults; i++) {
ret = regcache_rbtree_write(map,
@@ -238,6 +281,8 @@ static int regcache_rbtree_exit(struct regmap *map)
if (!rbtree_ctx)
return 0;
 
+   kfree(rbtree_ctx->reg_present);
+
/* free up the rbtree */
next = rb_first(&rbtree_ctx->root);
while (next) {
@@ -255,6 +300,17 @@ static int regcache_rbtree_exit(struct regmap *map)
return 0;
 }
 
+static int regcache_reg_present(struct regmap *map, unsigned int reg)
+{
+   struct regcache_rbtree_ctx *rbtree_ctx;
+
+   rbtree_ctx = map->cache;
+   if (!(rbtree_ctx->reg_present[BIT_WORD(reg)] & BIT_MASK(reg)))
+   return 0;
+   return 1;
+
+}
+
 static int regcache_rbtree_read(struct regmap *map,
unsigned int reg, unsigned int *value)
 {
@@ -264,6 +320,8 @@ static int regcache_rbtree_read(struct regmap *map,
rbnode = regcache_rbtree_lookup(map, reg);
if (rbnode) {
reg_tmp = (reg - rbnode->base_reg) /

Re: [PATCH] regmap: Remove __attribute__ ((packed))

2013-03-15 Thread Dimitris Papastamos
On Fri, Mar 15, 2013 at 04:53:51PM +, Mark Brown wrote:
> On Fri, Mar 15, 2013 at 11:16:02AM +0000, Dimitris Papastamos wrote:
> 
> > On my system there was no benefit of using it, it just happens
> > that the struct is aligned properly and needs no padding.
> 
> OK, so which system was that and is it not possible that other systems
> will get something useful from this?

Well I guess it has to do with the gcc cross compiler version that
I've got and the actual data layout of the linking rbtree node.
The data seems to be aligned on a 4-byte boundary anyhow and
that should be ok for many systems.

Thanks,
Dimitris
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 1/2] firmware: Convert firmware path setup from an array to a list

2012-10-23 Thread Dimitris Papastamos
On Mon, Oct 22, 2012 at 08:42:02AM -0700, Greg Kroah-Hartman wrote:
> On Wed, Oct 10, 2012 at 11:56:24AM +0100, Dimitris Papastamos wrote:
> > In preparation to support dynamic listing/updating of firmware
> > paths via procfs, this patch converts the firmware path configuration
> > from an array to a list.
> > 
> > Signed-off-by: Dimitris Papastamos 
> 
> This series doesn't apply anymore due to changes in this code from Ming.
> Can you redo it against the my staging-linus branch, or the next
> linux-next release, so that I can apply them?
> 
> thanks,
> 
> greg k-h

Hi, I've not had time to implement this properly as discussed in the thread.
Should the current changes on top of Ming's changes nevertheless?

Thanks,
Dimitris
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/3 v2] firmware: Add /proc/firmware_path entry to list the firmware paths

2012-10-23 Thread Dimitris Papastamos
This patch provides the aforementioned procfs file that lists
the default firmware paths that are used during firmware lookup.

The file contains a white space separated list of paths.

There will be another patch on top of this that adds the functionality
to modify the paths at runtime.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/firmware_class.c | 55 +++
 1 file changed, 55 insertions(+)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index d76152b..322fff3 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -27,6 +27,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #include 
 
@@ -1468,6 +1470,56 @@ err_fwp_alloc:
return -ENOMEM;
 }
 
+static void *fw_path_seq_start(struct seq_file *seq, loff_t *pos)
+{
+   return seq_list_start_head(&fw_path_list, *pos);
+}
+
+static void *fw_path_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+   return seq_list_next(v, &fw_path_list, pos);
+}
+
+static int fw_path_seq_show(struct seq_file *seq, void *v)
+{
+   const struct fw_path_rec *fwp;
+   struct list_head *l = v;
+
+   if (l == &fw_path_list)
+   return 0;
+   fwp = list_entry(v, struct fw_path_rec, list);
+   seq_puts(seq, fwp->name);
+   if (l->next != &fw_path_list)
+   seq_putc(seq, ' ');
+   else
+   seq_putc(seq, '\n');
+   return 0;
+}
+
+static void fw_path_seq_stop(struct seq_file *seq, void *v)
+{
+}
+
+static const struct seq_operations fw_path_ops = {
+   .start = fw_path_seq_start,
+   .next = fw_path_seq_next,
+   .stop = fw_path_seq_stop,
+   .show = fw_path_seq_show,
+};
+
+static int fw_path_open(struct inode *inode, struct file *file)
+{
+   return seq_open(file, &fw_path_ops);
+}
+
+static const struct file_operations fw_path_seq_fops = {
+   .owner = THIS_MODULE,
+   .open = fw_path_open,
+   .read = seq_read,
+   .llseek = seq_lseek,
+   .release = seq_release,
+};
+
 static void __init fw_cache_init(void)
 {
spin_lock_init(&fw_cache.lock);
@@ -1501,6 +1553,8 @@ static int __init firmware_class_init(void)
return ret;
}
 
+   proc_create("firmware_path", S_IRUGO, NULL, &fw_path_seq_fops);
+
return class_register(&firmware_class);
 }
 
@@ -1510,6 +1564,7 @@ static void __exit firmware_class_exit(void)
unregister_syscore_ops(&fw_syscore_ops);
unregister_pm_notifier(&fw_cache.pm_notify);
 #endif
+   remove_proc_entry("firmware_path", NULL);
fw_free_path_list();
class_unregister(&firmware_class);
 }
-- 
1.8.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 0/3 v2] Expose firmware paths via procfs

2012-10-23 Thread Dimitris Papastamos
Hi Greg, I've rebased these on top of linux-next as you requested.

Dimitris Papastamos (3):
  firmware: Convert firmware path setup from an array to a list
  firmware: Add /proc/firmware_path entry to list the firmware paths
  firmware: Factor out code to add paths to the firmware path list

 drivers/base/firmware_class.c | 137 +++---
 1 file changed, 128 insertions(+), 9 deletions(-)

-- 
1.8.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 3/3 v2] firmware: Factor out code to add paths to the firmware path list

2012-10-23 Thread Dimitris Papastamos
Signed-off-by: Dimitris Papastamos 
---
 drivers/base/firmware_class.c | 36 ++--
 1 file changed, 22 insertions(+), 14 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 322fff3..cf4aa5f 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -1426,6 +1426,22 @@ static int fw_cache_piggyback_on_request(const char 
*name)
 }
 #endif
 
+static int fw_add_path_to_list(const char *path)
+{
+   struct fw_path_rec *fwp;
+
+   fwp = kmalloc(sizeof(*fwp), GFP_KERNEL);
+   if (!fwp)
+   return -ENOMEM;
+   fwp->name = kstrdup(path, GFP_KERNEL);
+   if (!fwp->name) {
+   kfree(fwp);
+   return -ENOMEM;
+   }
+   list_add_tail(&fwp->list, &fw_path_list);
+   return 0;
+}
+
 static void fw_free_path_list(void)
 {
struct fw_path_rec *fwp;
@@ -1443,7 +1459,7 @@ static void fw_free_path_list(void)
 static int fw_populate_path_list(void)
 {
int i;
-   struct fw_path_rec *fwp;
+   int ret;
static const char *fw_path[] = {
"/lib/firmware/updates/" UTS_RELEASE,
"/lib/firmware/updates",
@@ -1452,22 +1468,14 @@ static int fw_populate_path_list(void)
};
 
for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
-   fwp = kmalloc(sizeof(*fwp), GFP_KERNEL);
-   if (!fwp)
-   goto err_fwp_alloc;
-   fwp->name = kstrdup(fw_path[i], GFP_KERNEL);
-   if (!fwp->name)
-   goto err_fwp_name_alloc;
-   list_add_tail(&fwp->list, &fw_path_list);
+   ret = fw_add_path_to_list(fw_path[i]);
+   if (ret < 0) {
+   fw_free_path_list();
+   return ret;
+   }
}
 
return 0;
-
-err_fwp_name_alloc:
-   kfree(fwp);
-err_fwp_alloc:
-   fw_free_path_list();
-   return -ENOMEM;
 }
 
 static void *fw_path_seq_start(struct seq_file *seq, loff_t *pos)
-- 
1.8.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/3 v2] firmware: Convert firmware path setup from an array to a list

2012-10-23 Thread Dimitris Papastamos
In preparation to support dynamic listing/updating of firmware
paths via procfs, this patch converts the firmware path configuration
from an array to a list.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/firmware_class.c | 74 +--
 1 file changed, 65 insertions(+), 9 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 8945f4e..d76152b 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -36,6 +36,13 @@ MODULE_AUTHOR("Manuel Estrada Sainz");
 MODULE_DESCRIPTION("Multi purpose firmware loading support");
 MODULE_LICENSE("GPL");
 
+struct fw_path_rec {
+   const char *name;
+   struct list_head list;
+};
+
+static LIST_HEAD(fw_path_list);
+
 /* Builtin firmware support */
 
 #ifdef CONFIG_FW_LOADER
@@ -267,12 +274,6 @@ static void fw_free_buf(struct firmware_buf *buf)
 }
 
 /* direct firmware loading support */
-static const char *fw_path[] = {
-   "/lib/firmware/updates/" UTS_RELEASE,
-   "/lib/firmware/updates",
-   "/lib/firmware/" UTS_RELEASE,
-   "/lib/firmware"
-};
 
 /* Don't inline this: 'struct kstat' is biggish */
 static noinline long fw_file_size(struct file *file)
@@ -309,13 +310,13 @@ static bool fw_read_file_contents(struct file *file, 
struct firmware_buf *fw_buf
 
 static bool fw_get_filesystem_firmware(struct firmware_buf *buf)
 {
-   int i;
bool success = false;
char *path = __getname();
+   struct fw_path_rec *fwp;
 
-   for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
+   list_for_each_entry(fwp, &fw_path_list, list) {
struct file *file;
-   snprintf(path, PATH_MAX, "%s/%s", fw_path[i], buf->fw_id);
+   snprintf(path, PATH_MAX, "%s/%s", fwp->name, buf->fw_id);
 
file = filp_open(path, O_RDONLY, 0);
if (IS_ERR(file))
@@ -1423,6 +1424,50 @@ static int fw_cache_piggyback_on_request(const char 
*name)
 }
 #endif
 
+static void fw_free_path_list(void)
+{
+   struct fw_path_rec *fwp;
+
+   while (!list_empty(&fw_path_list)) {
+   fwp = list_first_entry(&fw_path_list,
+  struct fw_path_rec,
+  list);
+   kfree(fwp->name);
+   list_del(&fwp->list);
+   kfree(fwp);
+   }
+}
+
+static int fw_populate_path_list(void)
+{
+   int i;
+   struct fw_path_rec *fwp;
+   static const char *fw_path[] = {
+   "/lib/firmware/updates/" UTS_RELEASE,
+   "/lib/firmware/updates",
+   "/lib/firmware/" UTS_RELEASE,
+   "/lib/firmware"
+   };
+
+   for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
+   fwp = kmalloc(sizeof(*fwp), GFP_KERNEL);
+   if (!fwp)
+   goto err_fwp_alloc;
+   fwp->name = kstrdup(fw_path[i], GFP_KERNEL);
+   if (!fwp->name)
+   goto err_fwp_name_alloc;
+   list_add_tail(&fwp->list, &fw_path_list);
+   }
+
+   return 0;
+
+err_fwp_name_alloc:
+   kfree(fwp);
+err_fwp_alloc:
+   fw_free_path_list();
+   return -ENOMEM;
+}
+
 static void __init fw_cache_init(void)
 {
spin_lock_init(&fw_cache.lock);
@@ -1445,7 +1490,17 @@ static void __init fw_cache_init(void)
 
 static int __init firmware_class_init(void)
 {
+   int ret;
+
fw_cache_init();
+
+   ret = fw_populate_path_list();
+   if (ret < 0) {
+   pr_err("%s: Failed to populate firmware path list: %d\n",
+  __func__, ret);
+   return ret;
+   }
+
return class_register(&firmware_class);
 }
 
@@ -1455,6 +1510,7 @@ static void __exit firmware_class_exit(void)
unregister_syscore_ops(&fw_syscore_ops);
unregister_pm_notifier(&fw_cache.pm_notify);
 #endif
+   fw_free_path_list();
class_unregister(&firmware_class);
 }
 
-- 
1.8.0

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 1/3 v2] firmware: Convert firmware path setup from an array to a list

2012-10-23 Thread Dimitris Papastamos
On Tue, Oct 23, 2012 at 09:08:50PM +0800, Ming Lei wrote:
> On Tue, Oct 23, 2012 at 8:52 PM, Dimitris Papastamos
>  wrote:
> > In preparation to support dynamic listing/updating of firmware
> > paths via procfs, this patch converts the firmware path configuration
> > from an array to a list.
> 
> I remembered that I have questioned on dynamic listing/updating of
> firmware via procfs, looks you don't reply, :-(
> 
>   http://marc.info/?l=linux-kernel&m=134988208617179&w=2
> 
> IMO, it is not a good idea to update firmware path dynamically via proc
> because it may be too late to update a dynamic search path via /proc
> and drivers need request firmware just after rootfs is mounted.
> 
> kernel parameter should be a good way to pass one customerized
> path.
> 
> Thanks,
> -- 
> Ming Lei

Hi sorry for being unclear, I mentioned in the old thread that
I've not had time to fix this properly (or think about a proper
fix), Greg requested a rebase on top of linux-next, however, at
least for firmware path listing.

Should I amend the commit description so it is not misleading and
remove the 'updating' part?

Thanks,
Dimitris
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 1/3 v2] firmware: Convert firmware path setup from an array to a list

2012-10-23 Thread Dimitris Papastamos
On Tue, Oct 23, 2012 at 09:37:24PM +0800, Ming Lei wrote:
> On Tue, Oct 23, 2012 at 9:29 PM, Dimitris Papastamos
>  wrote:
> 
> >
> > Hi sorry for being unclear, I mentioned in the old thread that
> > I've not had time to fix this properly (or think about a proper
> > fix), Greg requested a rebase on top of linux-next, however, at
> > least for firmware path listing.
> >
> > Should I amend the commit description so it is not misleading and
> > remove the 'updating' part?
> 
> In fact, I also questioned on path listing too in last thread too.

I don't currently have a use-case for this, so not sure how useful
it is to list the default fw paths.

Thanks,
Dimitris
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/3 v2] firmware: Add /proc/firmware_path entry to list the firmware paths

2012-10-26 Thread Dimitris Papastamos
On Thu, Oct 25, 2012 at 11:48:33AM -0700, Greg Kroah-Hartman wrote:
> On Tue, Oct 23, 2012 at 01:52:55PM +0100, Dimitris Papastamos wrote:
> > This patch provides the aforementioned procfs file that lists
> > the default firmware paths that are used during firmware lookup.
> > 
> > The file contains a white space separated list of paths.
> 
> Paths can have whitespaces :(
> 
> How about using the "universal" path seperator of ':' that shells are
> used to using?  Yeah, it gets messy if you have a ':' in a path, but
> from what I can tell, only the openSUSE build system does looney things
> like that.

Sure I can do that, however, could you comment on Ming's comments?  Is
this patchset something we find useful at the moment as regards listing
and/or updating the firmware path list.

> > There will be another patch on top of this that adds the functionality
> > to modify the paths at runtime.
> 
> Did I miss that patch somewhere?

That patch is here:

http://opensource.wolfsonmicro.com/~dp/patches/firmware/0004-firmware-Add-write-support-to-proc-fw_path.patch

However I've not rebased that patch on top of linux-next and I did not
send it for review as it seems that it may be a more sensible solution
to pass this as a kernel parameter.

Let me know what you think and I'll squeeze some time this weekend
to look at this.

Thanks,
Dimitris
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] regmap: Don't lock in regmap_reinit_cache()

2012-07-26 Thread Dimitris Papastamos
When bus->fast_io is set, the locking here is done with spinlocks.
This is currently true for the regmap-mmio bus implementation.

While holding a spinlock we can't go to sleep, various operations
like removing the debugfs entries or re-initializing the cache will
sleep, therefore, shift the locking up to the user.

Change-Id: I766bdce4ea3415ed87116a937576aa4812aad508
Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regmap.c | 13 -
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index c241ae2..52069d2 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -659,13 +659,12 @@ EXPORT_SYMBOL_GPL(devm_regmap_init);
  * new cache.  This can be used to restore the cache to defaults or to
  * update the cache configuration to reflect runtime discovery of the
  * hardware.
+ *
+ * No explicit locking is done here, the user needs to ensure that
+ * this function will not race with other calls to regmap.
  */
 int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
 {
-   int ret;
-
-   map->lock(map);
-
regcache_exit(map);
regmap_debugfs_exit(map);
 
@@ -681,11 +680,7 @@ int regmap_reinit_cache(struct regmap *map, const struct 
regmap_config *config)
map->cache_bypass = false;
map->cache_only = false;
 
-   ret = regcache_init(map, config);
-
-   map->unlock(map);
-
-   return ret;
+   return regcache_init(map, config);
 }
 EXPORT_SYMBOL_GPL(regmap_reinit_cache);
 
-- 
1.7.11.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] regmap: Add regmap dummy driver

2012-07-27 Thread Dimitris Papastamos
Add a pseudo-driver for debugging and stress-testing the
regmap/regcache APIs.  A standard set of tools for working
with this driver (mainly sh scripts) will be put in a repo
at https://github.com/quantumdream/regmap-tools.

Change-Id: Ie6498f18d6f9a1f7a7cf813240e87ffed0d6f047
Signed-off-by: Dimitris Papastamos 
---
 This is an initial implementation of the regdummy driver for regmap.

 This is mainly useful for debugging/stress-testing regcache as it
 removes the need for real hardware and can be done in an emulated
 environment very easily.

 There'll be incremental patches adding more features such as,
 support for configurable volatile/readable/etc. registers via
 debugfs entries.

 drivers/base/regmap/Kconfig|   8 +
 drivers/base/regmap/Makefile   |   1 +
 drivers/base/regmap/regmap-dummy.c | 599 +
 3 files changed, 608 insertions(+)
 create mode 100644 drivers/base/regmap/regmap-dummy.c

diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index 6be390b..5a1ab02 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -20,3 +20,11 @@ config REGMAP_MMIO
 
 config REGMAP_IRQ
bool
+
+config REGMAP_DUMMY
+   tristate
+   select REGMAP_MMIO
+   help
+ Say Y or M if you want to add the regdummy driver for regmap.
+ This is a pseudo-driver used for debugging and stress-testing
+ the regmap/regcache APIs.
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index 5e75d1b..c5d70f1 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
 obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
 obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o
 obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o
+obj-$(CONFIG_REGMAP_DUMMY) += regmap-dummy.o
diff --git a/drivers/base/regmap/regmap-dummy.c 
b/drivers/base/regmap/regmap-dummy.c
new file mode 100644
index 000..76310db
--- /dev/null
+++ b/drivers/base/regmap/regmap-dummy.c
@@ -0,0 +1,599 @@
+/*
+ * Register map access API - Dummy regmap driver
+ *
+ * Copyright 2012 Wolfson Microelectronics PLC.
+ *
+ * Author: Dimitris Papastamos 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define DEFAULT_REGS_SIZE 1024
+
+struct regdummy_dev {
+   struct device *dev;
+   struct mutex lock;
+
+   /* Set when regdummy defaults have been modified.
+* This is useful to know so we don't reinit the
+* cache if there is no reason to do so. */
+   unsigned int dirty:1;
+
+   void *regs;
+   unsigned int regs_size;
+   unsigned int regs_size_new;
+
+   struct regmap *map;
+   struct regmap_config *config;
+   struct reg_default *regdef;
+};
+
+static struct dentry *regdummy_debugfs_root;
+
+/* Default volatile register callback, this should
+ * normally be configured by the user via a debugfs
+ * entry */
+static bool regdummy_volatile_reg(struct device *dev,
+ unsigned int reg)
+{
+   return false;
+}
+
+/* Default readable register callback, this should
+ * normally be configured by the user via a debugfs
+ * entry */
+static bool regdummy_readable_reg(struct device *dev,
+ unsigned int reg)
+{
+   return true;
+}
+
+/* Default precious register callback, this should
+ * normally be configured by the user via a debugfs
+ * entry */
+static bool regdummy_precious_reg(struct device *dev,
+ unsigned int reg)
+{
+   return false;
+}
+
+/* Calculate the length of a fixed format  */
+static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size)
+{
+   snprintf(buf, buf_size, "%x", max_val);
+   return strlen(buf);
+}
+
+static ssize_t regdummy_defaults_read_file(struct file *file, char __user 
*user_buf,
+  size_t count, loff_t *ppos)
+{
+   int reg_len, val_len, tot_len;
+   size_t buf_pos = 0;
+   loff_t p = 0;
+   ssize_t ret;
+   int i;
+   struct regdummy_dev *rdevp = file->private_data;
+   struct regmap_config *config;
+   struct reg_default *regdef;
+   unsigned int val;
+   unsigned int j;
+   unsigned int regdef_num;
+   char *buf;
+
+   if (*ppos < 0 || !count)
+   return -EINVAL;
+
+   buf = kmalloc(count, GFP_KERNEL);
+   if (!buf)
+   return -ENOMEM;
+
+   mutex_lock(&rdevp->lock);
+
+   config = rdevp->config;
+   regdef = rdevp->regdef;
+   regdef_num = rdevp->regs_size / config->reg_stride;
+
+   /* Calculate the length of a fixed format  */

[PATCH v2] regmap: Don't lock in regmap_reinit_cache()

2012-07-27 Thread Dimitris Papastamos
When bus->fast_io is set, the locking here is done with spinlocks.
This is currently true for the regmap-mmio bus implementation.

While holding a spinlock we can't go to sleep, various operations
like removing the debugfs entries or re-initializing the cache will
sleep, therefore, shift the locking up to the user.

Signed-off-by: Dimitris Papastamos 
---
 V2, removed the change id that was automatically.

 drivers/base/regmap/regmap.c | 13 -
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index c241ae2..52069d2 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -659,13 +659,12 @@ EXPORT_SYMBOL_GPL(devm_regmap_init);
  * new cache.  This can be used to restore the cache to defaults or to
  * update the cache configuration to reflect runtime discovery of the
  * hardware.
+ *
+ * No explicit locking is done here, the user needs to ensure that
+ * this function will not race with other calls to regmap.
  */
 int regmap_reinit_cache(struct regmap *map, const struct regmap_config *config)
 {
-   int ret;
-
-   map->lock(map);
-
regcache_exit(map);
regmap_debugfs_exit(map);
 
@@ -681,11 +680,7 @@ int regmap_reinit_cache(struct regmap *map, const struct 
regmap_config *config)
map->cache_bypass = false;
map->cache_only = false;
 
-   ret = regcache_init(map, config);
-
-   map->unlock(map);
-
-   return ret;
+   return regcache_init(map, config);
 }
 EXPORT_SYMBOL_GPL(regmap_reinit_cache);
 
-- 
1.7.11.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2] regmap: Add regmap dummy driver

2012-07-27 Thread Dimitris Papastamos
Add a pseudo-driver for debugging and stress-testing the
regmap/regcache APIs.  A standard set of tools for working
with this driver (mainly sh scripts) will be put in a repo
at https://github.com/quantumdream/regmap-tools

Some of these tests will require one to build with
REGMAP_ALLOW_WRITE_DEBUGFS defined.

Signed-off-by: Dimitris Papastamos 
---
 This is an initial implementation of the regdummy driver for regmap.
 This is mainly useful for debugging/stress-testing regcache as it
 removes the need for real hardware and can be done in an emulated
 environment very easily.

 There'll be incremental patches adding more features such as,
 support for configurable volatile/readable/etc. registers via
 debugfs entries.

 v2 updates:
 - Factored out the access to the MMIO region into a separate
 function.
 - Removed bogus Change-Id

 drivers/base/regmap/Kconfig|   8 +
 drivers/base/regmap/Makefile   |   1 +
 drivers/base/regmap/regmap-dummy.c | 609 +
 3 files changed, 618 insertions(+)
 create mode 100644 drivers/base/regmap/regmap-dummy.c

diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index 6be390b..5a1ab02 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -20,3 +20,11 @@ config REGMAP_MMIO
 
 config REGMAP_IRQ
bool
+
+config REGMAP_DUMMY
+   tristate
+   select REGMAP_MMIO
+   help
+ Say Y or M if you want to add the regdummy driver for regmap.
+ This is a pseudo-driver used for debugging and stress-testing
+ the regmap/regcache APIs.
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index 5e75d1b..c5d70f1 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
 obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
 obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o
 obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o
+obj-$(CONFIG_REGMAP_DUMMY) += regmap-dummy.o
diff --git a/drivers/base/regmap/regmap-dummy.c 
b/drivers/base/regmap/regmap-dummy.c
new file mode 100644
index 000..078e090
--- /dev/null
+++ b/drivers/base/regmap/regmap-dummy.c
@@ -0,0 +1,609 @@
+/*
+ * Register map access API - Dummy regmap driver
+ *
+ * Copyright 2012 Wolfson Microelectronics PLC.
+ *
+ * Author: Dimitris Papastamos 
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define DEFAULT_REGS_SIZE 1024
+
+struct regdummy_dev {
+   struct device *dev;
+   struct mutex lock;
+
+   /* Set when regdummy defaults have been modified.
+* This is useful to know so we don't reinit the
+* cache if there is no reason to do so. */
+   unsigned int dirty:1;
+
+   void *regs;
+   unsigned int regs_size;
+   unsigned int regs_size_new;
+
+   struct regmap *map;
+   struct regmap_config *config;
+   struct reg_default *regdef;
+};
+
+static struct dentry *regdummy_debugfs_root;
+
+/* Default volatile register callback, this should
+ * normally be configured by the user via a debugfs
+ * entry */
+static bool regdummy_volatile_reg(struct device *dev,
+ unsigned int reg)
+{
+   return false;
+}
+
+/* Default readable register callback, this should
+ * normally be configured by the user via a debugfs
+ * entry */
+static bool regdummy_readable_reg(struct device *dev,
+ unsigned int reg)
+{
+   return true;
+}
+
+/* Default precious register callback, this should
+ * normally be configured by the user via a debugfs
+ * entry */
+static bool regdummy_precious_reg(struct device *dev,
+ unsigned int reg)
+{
+   return false;
+}
+
+/* Calculate the length of a fixed format  */
+static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size)
+{
+   snprintf(buf, buf_size, "%x", max_val);
+   return strlen(buf);
+}
+
+static ssize_t regdummy_defaults_read_file(struct file *file, char __user 
*user_buf,
+  size_t count, loff_t *ppos)
+{
+   int reg_len, val_len, tot_len;
+   size_t buf_pos = 0;
+   loff_t p = 0;
+   ssize_t ret;
+   int i;
+   struct regdummy_dev *rdevp = file->private_data;
+   struct regmap_config *config;
+   struct reg_default *regdef;
+   unsigned int val;
+   unsigned int j;
+   unsigned int regdef_num;
+   char *buf;
+
+   if (*ppos < 0 || !count)
+   return -EINVAL;
+
+   buf = kmalloc(count, GFP_KERNEL);
+   if (!buf)
+   return -ENOMEM;
+
+   mutex_lock(&rdevp->lock);
+
+   config = rdevp->config;
+   regdef

[PATCH 1/2] firmware: Convert firmware path setup from an array to a list

2012-10-09 Thread Dimitris Papastamos
In preparation to support dynamic listing/updating of firmware
paths via procfs, this patch converts the firmware path configuration
from an array to a list.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/firmware_class.c | 72 ++-
 1 file changed, 64 insertions(+), 8 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 8154145..2153eab 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -36,13 +36,13 @@ MODULE_AUTHOR("Manuel Estrada Sainz");
 MODULE_DESCRIPTION("Multi purpose firmware loading support");
 MODULE_LICENSE("GPL");
 
-static const char *fw_path[] = {
-   "/lib/firmware/updates/" UTS_RELEASE,
-   "/lib/firmware/updates",
-   "/lib/firmware/" UTS_RELEASE,
-   "/lib/firmware"
+struct fw_path_rec {
+   const char *name;
+   struct list_head list;
 };
 
+static LIST_HEAD(fw_path_list);
+
 /* Don't inline this: 'struct kstat' is biggish */
 static noinline long fw_file_size(struct file *file)
 {
@@ -78,13 +78,14 @@ static bool fw_read_file_contents(struct file *file, struct 
firmware *fw)
 
 static bool fw_get_filesystem_firmware(struct firmware *fw, const char *name)
 {
-   int i;
bool success = false;
char *path = __getname();
+   struct fw_path_rec *fwp;
 
-   for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
+   list_for_each_entry(fwp, &fw_path_list, list) {
struct file *file;
-   snprintf(path, PATH_MAX, "%s/%s", fw_path[i], name);
+   snprintf(path, PATH_MAX, "%s/%s", fwp->name,
+name);
 
file = filp_open(path, O_RDONLY, 0);
if (IS_ERR(file))
@@ -1385,6 +1386,50 @@ static int fw_cache_piggyback_on_request(const char 
*name)
 }
 #endif
 
+static void fw_free_path_list(void)
+{
+   struct fw_path_rec *fwp;
+
+   while (!list_empty(&fw_path_list)) {
+   fwp = list_first_entry(&fw_path_list,
+  struct fw_path_rec,
+  list);
+   kfree(fwp->name);
+   list_del(&fwp->list);
+   kfree(fwp);
+   }
+}
+
+static int fw_populate_path_list(void)
+{
+   int i;
+   struct fw_path_rec *fwp;
+   static const char *fw_path[] = {
+   "/lib/firmware/updates/" UTS_RELEASE,
+   "/lib/firmware/updates",
+   "/lib/firmware/" UTS_RELEASE,
+   "/lib/firmware"
+   };
+
+   for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
+   fwp = kmalloc(sizeof(*fwp), GFP_KERNEL);
+   if (!fwp)
+   goto err_fwp_alloc;
+   fwp->name = kstrdup(fw_path[i], GFP_KERNEL);
+   if (!fwp->name)
+   goto err_fwp_name_alloc;
+   list_add_tail(&fwp->list, &fw_path_list);
+   }
+
+   return 0;
+
+err_fwp_name_alloc:
+   kfree(fwp);
+err_fwp_alloc:
+   fw_free_path_list();
+   return -ENOMEM;
+}
+
 static void __init fw_cache_init(void)
 {
spin_lock_init(&fw_cache.lock);
@@ -1409,7 +1454,17 @@ static void __init fw_cache_init(void)
 
 static int __init firmware_class_init(void)
 {
+   int ret;
+
fw_cache_init();
+
+   ret = fw_populate_path_list();
+   if (ret < 0) {
+   pr_err("%s: Failed to populate firmware path list: %d\n",
+  __func__, ret);
+   return ret;
+   }
+
return class_register(&firmware_class);
 }
 
@@ -1419,6 +1474,7 @@ static void __exit firmware_class_exit(void)
unregister_syscore_ops(&fw_syscore_ops);
unregister_pm_notifier(&fw_cache.pm_notify);
 #endif
+   fw_free_path_list();
class_unregister(&firmware_class);
 }
 
-- 
1.7.12.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/2] firmware: Add /proc/fw_path entry to list the firmware paths

2012-10-09 Thread Dimitris Papastamos
This patch provides the aforementioned procfs file that lists
the default firmware paths that are used during firmware lookup.

The file contains a white space separated list of paths.

There will be another patch on top of this that adds the functionality
to modify the paths at runtime.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/firmware_class.c | 55 +++
 1 file changed, 55 insertions(+)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 2153eab..22cef4d 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -27,6 +27,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #include 
 
@@ -1430,6 +1432,56 @@ err_fwp_alloc:
return -ENOMEM;
 }
 
+static void *fw_path_seq_start(struct seq_file *seq, loff_t *pos)
+{
+   return seq_list_start_head(&fw_path_list, *pos);
+}
+
+static void *fw_path_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+   return seq_list_next(v, &fw_path_list, pos);
+}
+
+static int fw_path_seq_show(struct seq_file *seq, void *v)
+{
+   const struct fw_path_rec *fwp;
+   struct list_head *l = v;
+
+   if (l == &fw_path_list)
+   return 0;
+   fwp = list_entry(v, struct fw_path_rec, list);
+   seq_puts(seq, fwp->name);
+   if (l->next != &fw_path_list)
+   seq_putc(seq, ' ');
+   else
+   seq_putc(seq, '\n');
+   return 0;
+}
+
+static void fw_path_seq_stop(struct seq_file *seq, void *v)
+{
+}
+
+static const struct seq_operations fw_path_ops = {
+   .start = fw_path_seq_start,
+   .next = fw_path_seq_next,
+   .stop = fw_path_seq_stop,
+   .show = fw_path_seq_show,
+};
+
+static int fw_path_open(struct inode *inode, struct file *file)
+{
+   return seq_open(file, &fw_path_ops);
+}
+
+static const struct file_operations fw_path_seq_fops = {
+   .owner = THIS_MODULE,
+   .open = fw_path_open,
+   .read = seq_read,
+   .llseek = seq_lseek,
+   .release = seq_release,
+};
+
 static void __init fw_cache_init(void)
 {
spin_lock_init(&fw_cache.lock);
@@ -1465,6 +1517,8 @@ static int __init firmware_class_init(void)
return ret;
}
 
+   proc_create("fw_path", S_IRUGO, NULL, &fw_path_seq_fops);
+
return class_register(&firmware_class);
 }
 
@@ -1474,6 +1528,7 @@ static void __exit firmware_class_exit(void)
unregister_syscore_ops(&fw_syscore_ops);
unregister_pm_notifier(&fw_cache.pm_notify);
 #endif
+   remove_proc_entry("fw_path", NULL);
fw_free_path_list();
class_unregister(&firmware_class);
 }
-- 
1.7.12.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/2] firmware: Convert firmware path setup from an array to a list

2012-10-10 Thread Dimitris Papastamos
In preparation to support dynamic listing/updating of firmware
paths via procfs, this patch converts the firmware path configuration
from an array to a list.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/firmware_class.c | 72 ++-
 1 file changed, 64 insertions(+), 8 deletions(-)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 8154145..2153eab 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -36,13 +36,13 @@ MODULE_AUTHOR("Manuel Estrada Sainz");
 MODULE_DESCRIPTION("Multi purpose firmware loading support");
 MODULE_LICENSE("GPL");
 
-static const char *fw_path[] = {
-   "/lib/firmware/updates/" UTS_RELEASE,
-   "/lib/firmware/updates",
-   "/lib/firmware/" UTS_RELEASE,
-   "/lib/firmware"
+struct fw_path_rec {
+   const char *name;
+   struct list_head list;
 };
 
+static LIST_HEAD(fw_path_list);
+
 /* Don't inline this: 'struct kstat' is biggish */
 static noinline long fw_file_size(struct file *file)
 {
@@ -78,13 +78,14 @@ static bool fw_read_file_contents(struct file *file, struct 
firmware *fw)
 
 static bool fw_get_filesystem_firmware(struct firmware *fw, const char *name)
 {
-   int i;
bool success = false;
char *path = __getname();
+   struct fw_path_rec *fwp;
 
-   for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
+   list_for_each_entry(fwp, &fw_path_list, list) {
struct file *file;
-   snprintf(path, PATH_MAX, "%s/%s", fw_path[i], name);
+   snprintf(path, PATH_MAX, "%s/%s", fwp->name,
+name);
 
file = filp_open(path, O_RDONLY, 0);
if (IS_ERR(file))
@@ -1385,6 +1386,50 @@ static int fw_cache_piggyback_on_request(const char 
*name)
 }
 #endif
 
+static void fw_free_path_list(void)
+{
+   struct fw_path_rec *fwp;
+
+   while (!list_empty(&fw_path_list)) {
+   fwp = list_first_entry(&fw_path_list,
+  struct fw_path_rec,
+  list);
+   kfree(fwp->name);
+   list_del(&fwp->list);
+   kfree(fwp);
+   }
+}
+
+static int fw_populate_path_list(void)
+{
+   int i;
+   struct fw_path_rec *fwp;
+   static const char *fw_path[] = {
+   "/lib/firmware/updates/" UTS_RELEASE,
+   "/lib/firmware/updates",
+   "/lib/firmware/" UTS_RELEASE,
+   "/lib/firmware"
+   };
+
+   for (i = 0; i < ARRAY_SIZE(fw_path); i++) {
+   fwp = kmalloc(sizeof(*fwp), GFP_KERNEL);
+   if (!fwp)
+   goto err_fwp_alloc;
+   fwp->name = kstrdup(fw_path[i], GFP_KERNEL);
+   if (!fwp->name)
+   goto err_fwp_name_alloc;
+   list_add_tail(&fwp->list, &fw_path_list);
+   }
+
+   return 0;
+
+err_fwp_name_alloc:
+   kfree(fwp);
+err_fwp_alloc:
+   fw_free_path_list();
+   return -ENOMEM;
+}
+
 static void __init fw_cache_init(void)
 {
spin_lock_init(&fw_cache.lock);
@@ -1409,7 +1454,17 @@ static void __init fw_cache_init(void)
 
 static int __init firmware_class_init(void)
 {
+   int ret;
+
fw_cache_init();
+
+   ret = fw_populate_path_list();
+   if (ret < 0) {
+   pr_err("%s: Failed to populate firmware path list: %d\n",
+  __func__, ret);
+   return ret;
+   }
+
return class_register(&firmware_class);
 }
 
@@ -1419,6 +1474,7 @@ static void __exit firmware_class_exit(void)
unregister_syscore_ops(&fw_syscore_ops);
unregister_pm_notifier(&fw_cache.pm_notify);
 #endif
+   fw_free_path_list();
class_unregister(&firmware_class);
 }
 
-- 
1.7.12.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 0/2] Expose firmware paths via procfs

2012-10-10 Thread Dimitris Papastamos
Hi all, sorry missed the relevant CCs before.  This patch set
adds support for exposing the firmware paths via procfs.  I've added
an entry named /proc/fw_path which is a whitespace separated list
of firmware paths.

Once I have some time I hope to also send out a patch that allows
the user to dynamically configure these paths.

Dimitris Papastamos (2):
  firmware: Convert firmware path setup from an array to a list
  firmware: Add /proc/fw_path entry to list the firmware paths

 drivers/base/firmware_class.c | 127 +++---
 1 file changed, 119 insertions(+), 8 deletions(-)

-- 
1.7.12.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/2] firmware: Add /proc/fw_path entry to list the firmware paths

2012-10-10 Thread Dimitris Papastamos
This patch provides the aforementioned procfs file that lists
the default firmware paths that are used during firmware lookup.

The file contains a white space separated list of paths.

There will be another patch on top of this that adds the functionality
to modify the paths at runtime.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/firmware_class.c | 55 +++
 1 file changed, 55 insertions(+)

diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 2153eab..22cef4d 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -27,6 +27,8 @@
 #include 
 #include 
 #include 
+#include 
+#include 
 
 #include 
 
@@ -1430,6 +1432,56 @@ err_fwp_alloc:
return -ENOMEM;
 }
 
+static void *fw_path_seq_start(struct seq_file *seq, loff_t *pos)
+{
+   return seq_list_start_head(&fw_path_list, *pos);
+}
+
+static void *fw_path_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+   return seq_list_next(v, &fw_path_list, pos);
+}
+
+static int fw_path_seq_show(struct seq_file *seq, void *v)
+{
+   const struct fw_path_rec *fwp;
+   struct list_head *l = v;
+
+   if (l == &fw_path_list)
+   return 0;
+   fwp = list_entry(v, struct fw_path_rec, list);
+   seq_puts(seq, fwp->name);
+   if (l->next != &fw_path_list)
+   seq_putc(seq, ' ');
+   else
+   seq_putc(seq, '\n');
+   return 0;
+}
+
+static void fw_path_seq_stop(struct seq_file *seq, void *v)
+{
+}
+
+static const struct seq_operations fw_path_ops = {
+   .start = fw_path_seq_start,
+   .next = fw_path_seq_next,
+   .stop = fw_path_seq_stop,
+   .show = fw_path_seq_show,
+};
+
+static int fw_path_open(struct inode *inode, struct file *file)
+{
+   return seq_open(file, &fw_path_ops);
+}
+
+static const struct file_operations fw_path_seq_fops = {
+   .owner = THIS_MODULE,
+   .open = fw_path_open,
+   .read = seq_read,
+   .llseek = seq_lseek,
+   .release = seq_release,
+};
+
 static void __init fw_cache_init(void)
 {
spin_lock_init(&fw_cache.lock);
@@ -1465,6 +1517,8 @@ static int __init firmware_class_init(void)
return ret;
}
 
+   proc_create("fw_path", S_IRUGO, NULL, &fw_path_seq_fops);
+
return class_register(&firmware_class);
 }
 
@@ -1474,6 +1528,7 @@ static void __exit firmware_class_exit(void)
unregister_syscore_ops(&fw_syscore_ops);
unregister_pm_notifier(&fw_cache.pm_notify);
 #endif
+   remove_proc_entry("fw_path", NULL);
fw_free_path_list();
class_unregister(&firmware_class);
 }
-- 
1.7.12.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/2] firmware: Add /proc/fw_path entry to list the firmware paths

2012-10-10 Thread Dimitris Papastamos
On Wed, Oct 10, 2012 at 10:36:55PM +0900, Greg Kroah-Hartman wrote:
> On Wed, Oct 10, 2012 at 11:56:25AM +0100, Dimitris Papastamos wrote:
> > This patch provides the aforementioned procfs file that lists
> > the default firmware paths that are used during firmware lookup.
> > 
> > The file contains a white space separated list of paths.
> > 
> > There will be another patch on top of this that adds the functionality
> > to modify the paths at runtime.
> > 
> > Signed-off-by: Dimitris Papastamos 
> 
> What about /proc/sys/kernel/firmware_path instead?  Isn't that a better
> place for this?
> 
> greg k-h

Yes that makes more sense to me.

Thanks,
Dimitris
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/2] firmware: Add /proc/fw_path entry to list the firmware paths

2012-10-10 Thread Dimitris Papastamos
On Wed, Oct 10, 2012 at 10:36:55PM +0900, Greg Kroah-Hartman wrote:
> On Wed, Oct 10, 2012 at 11:56:25AM +0100, Dimitris Papastamos wrote:
> > This patch provides the aforementioned procfs file that lists
> > the default firmware paths that are used during firmware lookup.
> > 
> > The file contains a white space separated list of paths.
> > 
> > There will be another patch on top of this that adds the functionality
> > to modify the paths at runtime.
> > 
> > Signed-off-by: Dimitris Papastamos 
> 
> What about /proc/sys/kernel/firmware_path instead?  Isn't that a better
> place for this?
> 
> greg k-h

Btw, a primitive set of patches along with write support are stashed
at http://opensource.wolfsonmicro.com/~dp/patches/firmware/ - will clean
these up and place the file at /proc/sys/kernel/firmware_path and
will send out a new version of the patch set.

Thanks,
Dimitris
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH] drivers: regmap: bugfix in regcache-rbtree.c

2013-08-21 Thread Dimitris Papastamos
On Wed, Aug 21, 2013 at 04:28:23PM +0100, Mark Brown wrote:
> On Wed, Aug 21, 2013 at 05:08:46PM +0200, David Jander wrote:
> 
> > This looks better. Not ideal still, but at least the codec works!
> 
> > Should I re-send a patch with this fix?
> 
> Yes, it's not the fix we actually want (we want to be merging blocks)
> isn't going to be suitable for a bug fix - ideally I'll get this to
> Linus for v3.11.

Once I have some free time I will look into implementing block
merges.

Thanks,
Dimitris
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] regmap: debugfs: Check return value of regmap_write()

2013-05-09 Thread Dimitris Papastamos
Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regmap-debugfs.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index 6cd1b78a..ee81635 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -265,6 +265,7 @@ static ssize_t regmap_map_write_file(struct file *file,
char *start = buf;
unsigned long reg, value;
struct regmap *map = file->private_data;
+   int ret;
 
buf_size = min(count, (sizeof(buf)-1));
if (copy_from_user(buf, user_buf, buf_size))
@@ -282,7 +283,9 @@ static ssize_t regmap_map_write_file(struct file *file,
/* Userspace has been fiddling around behind the kernel's back */
add_taint(TAINT_USER, LOCKDEP_NOW_UNRELIABLE);
 
-   regmap_write(map, reg, value);
+   ret = regmap_write(map, reg, value);
+   if (ret < 0)
+   return ret;
return buf_size;
 }
 #else
-- 
1.8.2.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 1/4] regmap: cache: Factor out reg_present support from rbtree cache

2013-03-29 Thread Dimitris Papastamos
On Fri, Mar 29, 2013 at 09:03:42PM +, Mark Brown wrote:
> The idea of maintaining a bitmap of present registers is something that
> can usefully be used by other cache types that maintain blocks of cached
> registers so move the code out of the rbtree cache and into the generic
> regcache code.
> 
> Refactor the interface slightly as we go to wrap the set bit and enlarge
> bitmap operations (since we never do one without the other) and make it
> more robust for reads of uncached registers by bounds checking before we
> look at the bitmap.
> 
> Signed-off-by: Mark Brown 

Looks good.

Reviewed-by: Dimitris Papastamos 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/4] regmap: cache: Factor out block sync

2013-03-29 Thread Dimitris Papastamos
On Fri, Mar 29, 2013 at 09:03:43PM +, Mark Brown wrote:
> The idea of holding blocks of registers in device format is shared between
> at least rbtree and lzo cache formats so split out the loop that does the
> sync from the rbtree code so optimisations on it can be reused.
> 
> Signed-off-by: Mark Brown 

Reviewed-by: Dimitris Papastamos 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 3/4] regmap: cache: Split raw and non-raw syncs

2013-03-29 Thread Dimitris Papastamos
On Fri, Mar 29, 2013 at 09:03:44PM +, Mark Brown wrote:
> For code clarity after implementing block writes split out the raw and
> non-raw I/O sync implementations.
> 
> Signed-off-by: Mark Brown 

Reviewed-by: Dimitris Papastamos 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 4/4] regmap: cache: Write consecutive registers in a single block write

2013-03-29 Thread Dimitris Papastamos
On Fri, Mar 29, 2013 at 09:03:45PM +, Mark Brown wrote:
> When syncing blocks of data using raw writes combine the writes into a
> single block write, saving us bus overhead for setup, addressing and
> teardown.
> 
> Currently the block write is done unconditionally as it is expected that
> hardware which has a register format which can support raw writes will
> support auto incrementing writes, this decision may need to be revised in
> future.
> 
> Signed-off-by: Mark Brown 

Reviewed-by: Dimitris Papastamos 
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] regmap: Initialize `map->debugfs' before regcache

2013-03-11 Thread Dimitris Papastamos
In the rbtree code we are exposing statistics relating to the
number of nodes/registers of the rbtree cache for each of the
devices.  Ensure that `map->debugfs' has been initialized before
we attempt to initialize the debugfs entry for the rbtree cache.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regmap.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index 3d23675..50ef277 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -710,12 +710,12 @@ skip_format_initialization:
}
}
 
+   regmap_debugfs_init(map, config->name);
+
ret = regcache_init(map, config);
if (ret != 0)
goto err_range;
 
-   regmap_debugfs_init(map, config->name);
-
/* Add a devres resource for dev_get_regmap() */
m = devres_alloc(dev_get_regmap_release, sizeof(*m), GFP_KERNEL);
if (!m) {
-- 
1.8.1.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] regmap: Expose total memory consumption in the rbtree debugfs entry

2013-03-11 Thread Dimitris Papastamos
Provide a feel of how much overhead the rbtree cache adds to
the game.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regcache-rbtree.c | 12 ++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/base/regmap/regcache-rbtree.c 
b/drivers/base/regmap/regcache-rbtree.c
index 461cff8..7b732ad 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -138,6 +138,7 @@ static int rbtree_show(struct seq_file *s, void *ignored)
struct regcache_rbtree_node *n;
struct rb_node *node;
unsigned int base, top;
+   size_t mem_size = sizeof(*rbtree_ctx);
int nodes = 0;
int registers = 0;
int this_registers, average;
@@ -147,6 +148,8 @@ static int rbtree_show(struct seq_file *s, void *ignored)
for (node = rb_first(&rbtree_ctx->root); node != NULL;
 node = rb_next(node)) {
n = container_of(node, struct regcache_rbtree_node, node);
+   mem_size += sizeof(*n);
+   mem_size += (n->blklen * map->cache_word_size);
 
regcache_rbtree_get_base_top_reg(map, n, &base, &top);
this_registers = ((top - base) / map->reg_stride) + 1;
@@ -161,8 +164,13 @@ static int rbtree_show(struct seq_file *s, void *ignored)
else
average = 0;
 
-   seq_printf(s, "%d nodes, %d registers, average %d registers\n",
-  nodes, registers, average);
+   if (mem_size > 1024)
+   mem_size /= 1024;
+   else
+   mem_size = 1;
+
+   seq_printf(s, "%d nodes, %d registers, average %d registers, memory 
overhead %zukB\n",
+  nodes, registers, average, mem_size);
 
map->unlock(map);
 
-- 
1.8.1.5

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2] regmap: Add regmap dummy driver

2012-08-04 Thread Dimitris Papastamos
On Sat, Aug 04, 2012 at 11:05:23AM +0100, Mark Brown wrote:
> On Fri, Jul 27, 2012 at 02:58:20PM +0100, Dimitris Papastamos wrote:
> > Add a pseudo-driver for debugging and stress-testing the
> > regmap/regcache APIs.  A standard set of tools for working
> 
> Overall this looks good, most of the stuff below is fairly small.  As a
> very high level comment it'd be really helpful to split this into a
> series of commits, for example adding just the dummy device then
> building out the functionality.  It'd make review much easier.
> 
> > with this driver (mainly sh scripts) will be put in a repo
> > at https://github.com/quantumdream/regmap-tools
> 
> Any reason not to put this in the tools directory?

At the moment the repo is very bare bones.  I was thinking more of
an automated testing framework written in sh or similar.  So it might
grow out into its own repository anyhow.

> > Some of these tests will require one to build with
> > REGMAP_ALLOW_WRITE_DEBUGFS defined.
> 
> Can we add a write mechanism specifically for this dummy driver?

Sure yes.

> > +   /* Set when regdummy defaults have been modified.
> > +* This is useful to know so we don't reinit the
> > +* cache if there is no reason to do so. */
> > +   unsigned int dirty:1;
> 
> Should we perhaps just reinit anyway?  It's not like this is performance
> critical...

Yea will remove it for simplicity.

> > +/* Default volatile register callback, this should
> > + * normally be configured by the user via a debugfs
> > + * entry */
> > +static bool regdummy_volatile_reg(struct device *dev,
> > + unsigned int reg)
> > +{
> > +   return false;
> > +}
> 
> All these functions just seem to be implementing the default behaviour,
> why are they needed?

Hm will remove them for now but it would be useful for these to be set by
the user via debugfs or similar.  These were mainly stubs for that sort
of thing.

> > +   /* If we're in the region the user is trying to read */
> > +   if (p >= *ppos) {
> > +   /* ...but not beyond it */
> > +   if (buf_pos >= count - 1 - tot_len)
> > +   break;
> 
> Any potential for code reuse?  This stuff does look awfully familiar!

Might factor some of these things into a separate regmap-utils.c.

> > +   /* Allocate the new register defaults */
> > +   regdef_num_new = rdevp->regs_size_new / config->reg_stride;
> > +   regdef_num_raw_new = regdef_num_new * sizeof(*regdef_new);
> > +   regdef_new = kzalloc(regdef_num_raw_new, GFP_KERNEL);
> 
> Can we factor this stuff out - there's a lot of overlap with the vanilla
> init?

Sure.

> > +static struct platform_device regdummy_device = {
> > +   .name = "regdummy",
> > +   .id = 0,
> > +};
> 
> Set id to -1 if there's only one of them.

Ok.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] regmap: debugfs: Simplify calculation of `c->max_reg'

2013-02-14 Thread Dimitris Papastamos
We don't need to use any of the file position information
to calculate the base and max register of each block.  Just
use the counter directly.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regmap-debugfs.c | 8 ++--
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index 78d5f20..5fb23cb 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -95,9 +95,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
regmap_precious(map, i)) {
if (c) {
c->max = p - 1;
-   fpos_offset = c->max - c->min;
-   reg_offset = fpos_offset / 
map->debugfs_tot_len;
-   c->max_reg = c->base_reg + reg_offset;
+   c->max_reg = i - 1;
list_add_tail(&c->list,
  &map->debugfs_off_cache);
c = NULL;
@@ -124,9 +122,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
/* Close the last entry off if we didn't scan beyond it */
if (c) {
c->max = p - 1;
-   fpos_offset = c->max - c->min;
-   reg_offset = fpos_offset / map->debugfs_tot_len;
-   c->max_reg = c->base_reg + reg_offset;
+   c->max_reg = i - 1;
list_add_tail(&c->list,
  &map->debugfs_off_cache);
}
-- 
1.8.1.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/2] regmap: debugfs: Add a registers `range' file

2013-02-14 Thread Dimitris Papastamos
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 
---
 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
+

[PATCH 2/2] regmap: debugfs: Ensure proper locking of `debugfs_off_cache' list

2013-02-14 Thread Dimitris Papastamos
There is a possible race between the read operations of the `registers'
file and the `range' file.  Close that down by taking the appropriate
locks when modifying/accessing the list.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/internal.h   |  1 +
 drivers/base/regmap/regmap-debugfs.c | 10 ++
 2 files changed, 11 insertions(+)

diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index b4e55a0..640c5a4 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -77,6 +77,7 @@ struct regmap {
unsigned int debugfs_tot_len;
 
struct list_head debugfs_off_cache;
+   struct mutex cache_lock;
 #endif
 
unsigned int max_register;
diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index 5843eb1..89a5a85 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -76,6 +76,7 @@ static inline unsigned int regmap_attr_bitmap(struct regmap 
*map,
return reg_attr;
 }
 
+/* Called with `cache_lock' held */
 static void regmap_debugfs_free_dump_cache(struct regmap *map)
 {
struct regmap_debugfs_off_cache *c;
@@ -108,6 +109,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
 * If we don't have a cache build one so we don't have to do a
 * linear scan each time.
 */
+   mutex_lock(&map->cache_lock);
if (list_empty(&map->debugfs_off_cache)) {
for (i = base; i <= map->max_register; i += map->reg_stride) {
/* Skip unprinted registers, closing off cache entry */
@@ -130,6 +132,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c) {
regmap_debugfs_free_dump_cache(map);
+   mutex_unlock(&map->cache_lock);
return base;
}
c->min = p;
@@ -163,12 +166,14 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
fpos_offset = from - c->min;
reg_offset = fpos_offset / map->debugfs_tot_len;
*pos = c->min + (reg_offset * map->debugfs_tot_len);
+   mutex_unlock(&map->cache_lock);
return c->base_reg + reg_offset;
}
 
*pos = c->max;
ret = c->max_reg;
}
+   mutex_unlock(&map->cache_lock);
 
return ret;
 }
@@ -392,6 +397,7 @@ static ssize_t regmap_reg_ranges_read_file(struct file 
*file,
/* Reset file pointer as the fixed-format of the `registers'
 * file is not compatible with the `range' file */
p = 0;
+   mutex_lock(&map->cache_lock);
list_for_each_entry(c, &map->debugfs_off_cache, list) {
regmap_range_format_line(map, c, entry, PAGE_SIZE);
if (p >= *ppos) {
@@ -405,6 +411,7 @@ static ssize_t regmap_reg_ranges_read_file(struct file 
*file,
}
p += strlen(entry) + 1;
}
+   mutex_unlock(&map->cache_lock);
 
kfree(entry);
ret = buf_pos;
@@ -500,6 +507,7 @@ void regmap_debugfs_init(struct regmap *map, const char 
*name)
struct regmap_range_node *range_node;
 
INIT_LIST_HEAD(&map->debugfs_off_cache);
+   mutex_init(&map->cache_lock);
 
if (name) {
map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
@@ -553,7 +561,9 @@ void regmap_debugfs_init(struct regmap *map, const char 
*name)
 void regmap_debugfs_exit(struct regmap *map)
 {
debugfs_remove_recursive(map->debugfs);
+   mutex_lock(&map->cache_lock);
regmap_debugfs_free_dump_cache(map);
+   mutex_unlock(&map->cache_lock);
kfree(map->debugfs_name);
 }
 
-- 
1.8.1.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v2] regmap: debugfs: Simplify calculation of `c->max_reg'

2013-02-14 Thread Dimitris Papastamos
We don't need to use any of the file position information
to calculate the base and max register of each block.  Just
use the counter directly.

Ensure that in the limiting case where there is a single
register in the register file we handle that properly in
the if (c) { ... } code after the loop without causing
an integer wrap-around.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regmap-debugfs.c | 13 ++---
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index 78d5f20..d804b74 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -80,7 +80,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
 {
struct regmap_debugfs_off_cache *c = NULL;
loff_t p = 0;
-   unsigned int i, ret;
+   unsigned int i = 0, ret;
unsigned int fpos_offset;
unsigned int reg_offset;
 
@@ -95,9 +95,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
regmap_precious(map, i)) {
if (c) {
c->max = p - 1;
-   fpos_offset = c->max - c->min;
-   reg_offset = fpos_offset / 
map->debugfs_tot_len;
-   c->max_reg = c->base_reg + reg_offset;
+   c->max_reg = i - 1;
list_add_tail(&c->list,
  &map->debugfs_off_cache);
c = NULL;
@@ -124,9 +122,10 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
/* Close the last entry off if we didn't scan beyond it */
if (c) {
c->max = p - 1;
-   fpos_offset = c->max - c->min;
-   reg_offset = fpos_offset / map->debugfs_tot_len;
-   c->max_reg = c->base_reg + reg_offset;
+   if (!i)
+   c->max_reg = 0;
+   else
+   c->max_reg = i - 1;
list_add_tail(&c->list,
  &map->debugfs_off_cache);
}
-- 
1.8.1.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v2] regmap: debugfs: Simplify calculation of `c->max_reg'

2013-02-14 Thread Dimitris Papastamos
On Thu, Feb 14, 2013 at 02:14:40PM +, Mark Brown wrote:
> On Thu, Feb 14, 2013 at 02:04:04PM +0000, Dimitris Papastamos wrote:
> 
> > -   unsigned int i, ret;
> > +   unsigned int i = 0, ret;
> 
> Coding style and are you sure this is a good default.

Hm, it doesn't really matter.  I guess the proper fix would
be to set i = base at the start, but that would not change
anything in terms of the actual code flow, it would only silence
the gcc flow analysis bug.

Thanks,
Dimitris
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v3] regmap: debugfs: Simplify calculation of `c->max_reg'

2013-02-14 Thread Dimitris Papastamos
We don't need to use any of the file position information
to calculate the base and max register of each block.  Just
use the counter directly.

The `i = base' at the top to avoid GCC flow analysis bugs.  The
value of `i' can never be undefined or 0 in the if (c) { ... }.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regmap-debugfs.c | 11 ---
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index 78d5f20..e14cb2d 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -88,16 +88,15 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
 * If we don't have a cache build one so we don't have to do a
 * linear scan each time.
 */
+   i = base;
if (list_empty(&map->debugfs_off_cache)) {
-   for (i = base; i <= map->max_register; i += map->reg_stride) {
+   for (; i <= map->max_register; i += map->reg_stride) {
/* Skip unprinted registers, closing off cache entry */
if (!regmap_readable(map, i) ||
regmap_precious(map, i)) {
if (c) {
c->max = p - 1;
-   fpos_offset = c->max - c->min;
-   reg_offset = fpos_offset / 
map->debugfs_tot_len;
-   c->max_reg = c->base_reg + reg_offset;
+   c->max_reg = i - map->reg_stride;
list_add_tail(&c->list,
  &map->debugfs_off_cache);
c = NULL;
@@ -124,9 +123,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
/* Close the last entry off if we didn't scan beyond it */
if (c) {
c->max = p - 1;
-   fpos_offset = c->max - c->min;
-   reg_offset = fpos_offset / map->debugfs_tot_len;
-   c->max_reg = c->base_reg + reg_offset;
+   c->max_reg = i - map->reg_stride;
list_add_tail(&c->list,
  &map->debugfs_off_cache);
}
-- 
1.8.1.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 2/2] regmap: debugfs: Ensure proper locking of `debugfs_off_cache' list

2013-02-14 Thread Dimitris Papastamos
On Thu, Feb 14, 2013 at 02:54:17PM +, Mark Brown wrote:
> On Thu, Feb 14, 2013 at 12:31:48PM +0000, Dimitris Papastamos wrote:
> 
> > There is a possible race between the read operations of the `registers'
> > file and the `range' file.  Close that down by taking the appropriate
> > locks when modifying/accessing the list.
> 
> This seems like an incremental fix on the previous change; the previous
> change introduced the ranges file with a race condition.  If splitting
> them up add the lock first and then add the ranges file that made it
> needed.
> 
> Please do also thread patch series together.

Aw yes, cool.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH 1/2] regmap: debugfs: Add a registers `range' file

2013-02-14 Thread Dimitris Papastamos
On Thu, Feb 14, 2013 at 02:43:06PM +, 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
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 1/3] regmap: debugfs: Simplify calculation of `c->max_reg'

2013-02-14 Thread Dimitris Papastamos
We don't need to use any of the file position information
to calculate the base and max register of each block.  Just
use the counter directly.

Set `i = base' at the top to avoid GCC flow analysis bugs.  The
value of `i' can never be undefined or 0 in the if (c) { ... }.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regmap-debugfs.c | 11 ---
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index 78d5f20..e14cb2d 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -88,16 +88,15 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
 * If we don't have a cache build one so we don't have to do a
 * linear scan each time.
 */
+   i = base;
if (list_empty(&map->debugfs_off_cache)) {
-   for (i = base; i <= map->max_register; i += map->reg_stride) {
+   for (; i <= map->max_register; i += map->reg_stride) {
/* Skip unprinted registers, closing off cache entry */
if (!regmap_readable(map, i) ||
regmap_precious(map, i)) {
if (c) {
c->max = p - 1;
-   fpos_offset = c->max - c->min;
-   reg_offset = fpos_offset / 
map->debugfs_tot_len;
-   c->max_reg = c->base_reg + reg_offset;
+   c->max_reg = i - map->reg_stride;
list_add_tail(&c->list,
  &map->debugfs_off_cache);
c = NULL;
@@ -124,9 +123,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
/* Close the last entry off if we didn't scan beyond it */
if (c) {
c->max = p - 1;
-   fpos_offset = c->max - c->min;
-   reg_offset = fpos_offset / map->debugfs_tot_len;
-   c->max_reg = c->base_reg + reg_offset;
+   c->max_reg = i - map->reg_stride;
list_add_tail(&c->list,
  &map->debugfs_off_cache);
}
-- 
1.8.1.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 3/3] regmap: debugfs: Add a registers `range' file

2013-02-14 Thread Dimitris Papastamos
This file lists the register ranges in the register map.  The condition
to split the range is based on whether the block is readable or not.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regmap-debugfs.c | 76 
 1 file changed, 76 insertions(+)

diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index a6b5606..61e2c52 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -312,6 +312,79 @@ static const struct file_operations regmap_range_fops = {
.llseek = default_llseek,
 };
 
+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;
+   mutex_lock(&map->cache_lock);
+   list_for_each_entry(c, &map->debugfs_off_cache, list) {
+   snprintf(entry, PAGE_SIZE, "%x-%x",
+c->base_reg, c->max_reg);
+   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;
+   }
+   mutex_unlock(&map->cache_lock);
+
+   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)
@@ -405,6 +478,9 @@ void regmap_debugfs_init(struct regmap *map, const char 
*name)
debugfs_create_file("name", 0400, map->debugfs,
map, ®map_name_fops);
 
+   debugfs_create_file("range", 0400, map->debugfs,
+   map, ®map_reg_ranges_fops);
+
if (map->max_register) {
debugfs_create_file("registers", 0400, map->debugfs,
map, ®map_map_fops);
-- 
1.8.1.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH 2/3] regmap: debugfs: Ensure proper locking of `debugfs_off_cache' list

2013-02-14 Thread Dimitris Papastamos
There is a possible race between the read operations of the `registers'
file and the `range' file.  Close that down by taking the appropriate
locks when modifying/accessing the list.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/internal.h   | 1 +
 drivers/base/regmap/regmap-debugfs.c | 7 +++
 2 files changed, 8 insertions(+)

diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 5a22bd3..dc23508 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -76,6 +76,7 @@ struct regmap {
unsigned int debugfs_tot_len;
 
struct list_head debugfs_off_cache;
+   struct mutex cache_lock;
 #endif
 
unsigned int max_register;
diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index e14cb2d..a6b5606 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -88,6 +88,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
 * If we don't have a cache build one so we don't have to do a
 * linear scan each time.
 */
+   mutex_lock(&map->cache_lock);
i = base;
if (list_empty(&map->debugfs_off_cache)) {
for (; i <= map->max_register; i += map->reg_stride) {
@@ -110,6 +111,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c) {
regmap_debugfs_free_dump_cache(map);
+   mutex_unlock(&map->cache_lock);
return base;
}
c->min = p;
@@ -142,12 +144,14 @@ static unsigned int regmap_debugfs_get_dump_start(struct 
regmap *map,
fpos_offset = from - c->min;
reg_offset = fpos_offset / map->debugfs_tot_len;
*pos = c->min + (reg_offset * map->debugfs_tot_len);
+   mutex_unlock(&map->cache_lock);
return c->base_reg + reg_offset;
}
 
*pos = c->max;
ret = c->max_reg;
}
+   mutex_unlock(&map->cache_lock);
 
return ret;
 }
@@ -382,6 +386,7 @@ void regmap_debugfs_init(struct regmap *map, const char 
*name)
struct regmap_range_node *range_node;
 
INIT_LIST_HEAD(&map->debugfs_off_cache);
+   mutex_init(&map->cache_lock);
 
if (name) {
map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
@@ -432,7 +437,9 @@ void regmap_debugfs_init(struct regmap *map, const char 
*name)
 void regmap_debugfs_exit(struct regmap *map)
 {
debugfs_remove_recursive(map->debugfs);
+   mutex_lock(&map->cache_lock);
regmap_debugfs_free_dump_cache(map);
+   mutex_unlock(&map->cache_lock);
kfree(map->debugfs_name);
 }
 
-- 
1.8.1.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] regmap: Fix incorrect arguments to kzalloc() call

2012-07-18 Thread Dimitris Papastamos
Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regmap-mmio.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/base/regmap/regmap-mmio.c 
b/drivers/base/regmap/regmap-mmio.c
index d64a7fc..f05fc74 100644
--- a/drivers/base/regmap/regmap-mmio.c
+++ b/drivers/base/regmap/regmap-mmio.c
@@ -172,7 +172,7 @@ static struct regmap_mmio_context 
*regmap_mmio_gen_context(void __iomem *regs,
return ERR_PTR(-EINVAL);
}
 
-   ctx = kzalloc(GFP_KERNEL, sizeof(*ctx));
+   ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
if (!ctx)
return ERR_PTR(-ENOMEM);
 
-- 
1.7.11.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH] regmap: Fallback to dev_name(map->dev) in case there is no `driver'

2012-07-19 Thread Dimitris Papastamos
This is useful when we want to use regmap with character devices.

Signed-off-by: Dimitris Papastamos 
---
 drivers/base/regmap/regmap-debugfs.c | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/base/regmap/regmap-debugfs.c 
b/drivers/base/regmap/regmap-debugfs.c
index bb1ff17..c2fbf57 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -39,7 +39,10 @@ static ssize_t regmap_name_read_file(struct file *file,
if (!buf)
return -ENOMEM;
 
-   ret = snprintf(buf, PAGE_SIZE, "%s\n", map->dev->driver->name);
+   if (map->dev->driver && map->dev->driver->name)
+   ret = snprintf(buf, PAGE_SIZE, "%s\n", map->dev->driver->name);
+   else
+   ret = snprintf(buf, PAGE_SIZE, "%s\n", dev_name(map->dev));
if (ret < 0) {
kfree(buf);
return ret;
-- 
1.7.11.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


RE: [PATCH] ASoC: wm8804: Allow control of master clock divider in PLL generation

2014-01-17 Thread Dimitris Papastamos
> Charles (or someone else from Wolfson), you commented on previous
> versions of this - are you still OK with it?

Looks good to me.

Privacy & Confidentiality Notice
-
This message and any attachments contain privileged and confidential 
information that is intended solely for the person(s) to whom it is addressed. 
If you are not an intended recipient you must not: read; copy; distribute; 
discuss; take any action in or make any reliance upon the contents of this 
message; nor open or read any attachment. If you have received this message in 
error, please notify us as soon as possible on the following telephone number 
and destroy this message including any attachments. Thank you.
-
Wolfson Microelectronics plc
Tel: +44 (0)131 272 7000
Fax: +44 (0)131 272 7001
Web: www.wolfsonmicro.com

Registered in Scotland

Company number SC089839

Registered office: 

Westfield House, 26 Westfield Road, Edinburgh, EH11 2QB, UK
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/