aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/regmap
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2012-12-10 11:24:29 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-12-10 11:29:47 -0500
commit5166b7c006eeb4f6becc0822974d8da259484ba1 (patch)
treeb28c4098a5b75a34efd8262efcc99fdf8d586365 /drivers/base/regmap
parentafab2f7b21b042bcbffb1e82f78243382a122d70 (diff)
regmap: debugfs: Cache offsets of valid regions for dump
Avoid doing a linear scan of the entire register map for each read() of the debugfs register dump by recording the offsets where valid registers exist when we first read the registers file. This assumes the set of valid registers never changes, if this is not the case invalidation of the cache will be required. This could be further improved for large blocks of contiguous registers by calculating the register we will read from within the block - currently we do a linear scan of the block. An rbtree may also be worthwhile. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
Diffstat (limited to 'drivers/base/regmap')
-rw-r--r--drivers/base/regmap/internal.h10
-rw-r--r--drivers/base/regmap/regmap-debugfs.c67
2 files changed, 63 insertions, 14 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 1abcd27e2d0f..9c3b0e7a6c7d 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -15,10 +15,18 @@
15 15
16#include <linux/regmap.h> 16#include <linux/regmap.h>
17#include <linux/fs.h> 17#include <linux/fs.h>
18#include <linux/list.h>
18 19
19struct regmap; 20struct regmap;
20struct regcache_ops; 21struct regcache_ops;
21 22
23struct regmap_debugfs_off_cache {
24 struct list_head list;
25 off_t min;
26 off_t max;
27 unsigned int base_reg;
28};
29
22struct regmap_format { 30struct regmap_format {
23 size_t buf_size; 31 size_t buf_size;
24 size_t reg_bytes; 32 size_t reg_bytes;
@@ -54,6 +62,8 @@ struct regmap {
54 unsigned int debugfs_reg_len; 62 unsigned int debugfs_reg_len;
55 unsigned int debugfs_val_len; 63 unsigned int debugfs_val_len;
56 unsigned int debugfs_tot_len; 64 unsigned int debugfs_tot_len;
65
66 struct list_head debugfs_off_cache;
57#endif 67#endif
58 68
59 unsigned int max_register; 69 unsigned int max_register;
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 749a1dc5bbfb..07aad786f817 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -65,25 +65,53 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
65 loff_t from, 65 loff_t from,
66 loff_t *pos) 66 loff_t *pos)
67{ 67{
68 loff_t p = *pos; 68 struct regmap_debugfs_off_cache *c = NULL;
69 unsigned int i; 69 loff_t p = 0;
70 70 unsigned int i, ret;
71 for (i = base; i <= map->max_register; i += map->reg_stride) { 71
72 if (!regmap_readable(map, i)) 72 /*
73 continue; 73 * If we don't have a cache build one so we don't have to do a
74 74 * linear scan each time.
75 if (regmap_precious(map, i)) 75 */
76 continue; 76 if (list_empty(&map->debugfs_off_cache)) {
77 for (i = base; i <= map->max_register; i += map->reg_stride) {
78 /* Skip unprinted registers, closing off cache entry */
79 if (!regmap_readable(map, i) ||
80 regmap_precious(map, i)) {
81 if (c) {
82 c->max = p - 1;
83 list_add_tail(&c->list,
84 &map->debugfs_off_cache);
85 c = NULL;
86 }
87
88 continue;
89 }
90
91 /* No cache entry? Start a new one */
92 if (!c) {
93 c = kzalloc(sizeof(*c), GFP_KERNEL);
94 if (!c)
95 break;
96 c->min = p;
97 c->base_reg = i;
98 }
99
100 p += map->debugfs_tot_len;
101 }
102 }
77 103
78 if (i >= from) { 104 /* Find the relevant block */
79 *pos = p; 105 list_for_each_entry(c, &map->debugfs_off_cache, list) {
80 return i; 106 if (*pos >= c->min && *pos <= c->max) {
107 *pos = c->min;
108 return c->base_reg;
81 } 109 }
82 110
83 p += map->debugfs_tot_len; 111 ret = c->max;
84 } 112 }
85 113
86 return base; 114 return ret;
87} 115}
88 116
89static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from, 117static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from,
@@ -309,6 +337,8 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
309 struct rb_node *next; 337 struct rb_node *next;
310 struct regmap_range_node *range_node; 338 struct regmap_range_node *range_node;
311 339
340 INIT_LIST_HEAD(&map->debugfs_off_cache);
341
312 if (name) { 342 if (name) {
313 map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s", 343 map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
314 dev_name(map->dev), name); 344 dev_name(map->dev), name);
@@ -357,7 +387,16 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
357 387
358void regmap_debugfs_exit(struct regmap *map) 388void regmap_debugfs_exit(struct regmap *map)
359{ 389{
390 struct regmap_debugfs_off_cache *c;
391
360 debugfs_remove_recursive(map->debugfs); 392 debugfs_remove_recursive(map->debugfs);
393 while (!list_empty(&map->debugfs_off_cache)) {
394 c = list_first_entry(&map->debugfs_off_cache,
395 struct regmap_debugfs_off_cache,
396 list);
397 list_del(&c->list);
398 kfree(c);
399 }
361 kfree(map->debugfs_name); 400 kfree(map->debugfs_name);
362} 401}
363 402