aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/regmap/internal.h1
-rw-r--r--drivers/base/regmap/regmap-debugfs.c94
2 files changed, 88 insertions, 7 deletions
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 01fbe48e8155..c130536e0ab0 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -77,6 +77,7 @@ struct regmap {
77 unsigned int debugfs_tot_len; 77 unsigned int debugfs_tot_len;
78 78
79 struct list_head debugfs_off_cache; 79 struct list_head debugfs_off_cache;
80 struct mutex cache_lock;
80#endif 81#endif
81 82
82 unsigned int max_register; 83 unsigned int max_register;
diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c
index 81d6f605c92e..23b701f5fd2f 100644
--- a/drivers/base/regmap/regmap-debugfs.c
+++ b/drivers/base/regmap/regmap-debugfs.c
@@ -88,16 +88,16 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
88 * If we don't have a cache build one so we don't have to do a 88 * If we don't have a cache build one so we don't have to do a
89 * linear scan each time. 89 * linear scan each time.
90 */ 90 */
91 mutex_lock(&map->cache_lock);
92 i = base;
91 if (list_empty(&map->debugfs_off_cache)) { 93 if (list_empty(&map->debugfs_off_cache)) {
92 for (i = base; i <= map->max_register; i += map->reg_stride) { 94 for (; i <= map->max_register; i += map->reg_stride) {
93 /* Skip unprinted registers, closing off cache entry */ 95 /* Skip unprinted registers, closing off cache entry */
94 if (!regmap_readable(map, i) || 96 if (!regmap_readable(map, i) ||
95 regmap_precious(map, i)) { 97 regmap_precious(map, i)) {
96 if (c) { 98 if (c) {
97 c->max = p - 1; 99 c->max = p - 1;
98 fpos_offset = c->max - c->min; 100 c->max_reg = i - map->reg_stride;
99 reg_offset = fpos_offset / map->debugfs_tot_len;
100 c->max_reg = c->base_reg + reg_offset;
101 list_add_tail(&c->list, 101 list_add_tail(&c->list,
102 &map->debugfs_off_cache); 102 &map->debugfs_off_cache);
103 c = NULL; 103 c = NULL;
@@ -111,6 +111,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
111 c = kzalloc(sizeof(*c), GFP_KERNEL); 111 c = kzalloc(sizeof(*c), GFP_KERNEL);
112 if (!c) { 112 if (!c) {
113 regmap_debugfs_free_dump_cache(map); 113 regmap_debugfs_free_dump_cache(map);
114 mutex_unlock(&map->cache_lock);
114 return base; 115 return base;
115 } 116 }
116 c->min = p; 117 c->min = p;
@@ -124,9 +125,7 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
124 /* Close the last entry off if we didn't scan beyond it */ 125 /* Close the last entry off if we didn't scan beyond it */
125 if (c) { 126 if (c) {
126 c->max = p - 1; 127 c->max = p - 1;
127 fpos_offset = c->max - c->min; 128 c->max_reg = i - map->reg_stride;
128 reg_offset = fpos_offset / map->debugfs_tot_len;
129 c->max_reg = c->base_reg + reg_offset;
130 list_add_tail(&c->list, 129 list_add_tail(&c->list,
131 &map->debugfs_off_cache); 130 &map->debugfs_off_cache);
132 } 131 }
@@ -145,12 +144,14 @@ static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
145 fpos_offset = from - c->min; 144 fpos_offset = from - c->min;
146 reg_offset = fpos_offset / map->debugfs_tot_len; 145 reg_offset = fpos_offset / map->debugfs_tot_len;
147 *pos = c->min + (reg_offset * map->debugfs_tot_len); 146 *pos = c->min + (reg_offset * map->debugfs_tot_len);
147 mutex_unlock(&map->cache_lock);
148 return c->base_reg + reg_offset; 148 return c->base_reg + reg_offset;
149 } 149 }
150 150
151 *pos = c->max; 151 *pos = c->max;
152 ret = c->max_reg; 152 ret = c->max_reg;
153 } 153 }
154 mutex_unlock(&map->cache_lock);
154 155
155 return ret; 156 return ret;
156} 157}
@@ -311,6 +312,79 @@ static const struct file_operations regmap_range_fops = {
311 .llseek = default_llseek, 312 .llseek = default_llseek,
312}; 313};
313 314
315static ssize_t regmap_reg_ranges_read_file(struct file *file,
316 char __user *user_buf, size_t count,
317 loff_t *ppos)
318{
319 struct regmap *map = file->private_data;
320 struct regmap_debugfs_off_cache *c;
321 loff_t p = 0;
322 size_t buf_pos = 0;
323 char *buf;
324 char *entry;
325 int ret;
326
327 if (*ppos < 0 || !count)
328 return -EINVAL;
329
330 buf = kmalloc(count, GFP_KERNEL);
331 if (!buf)
332 return -ENOMEM;
333
334 entry = kmalloc(PAGE_SIZE, GFP_KERNEL);
335 if (!entry) {
336 kfree(buf);
337 return -ENOMEM;
338 }
339
340 /* While we are at it, build the register dump cache
341 * now so the read() operation on the `registers' file
342 * can benefit from using the cache. We do not care
343 * about the file position information that is contained
344 * in the cache, just about the actual register blocks */
345 regmap_calc_tot_len(map, buf, count);
346 regmap_debugfs_get_dump_start(map, 0, *ppos, &p);
347
348 /* Reset file pointer as the fixed-format of the `registers'
349 * file is not compatible with the `range' file */
350 p = 0;
351 mutex_lock(&map->cache_lock);
352 list_for_each_entry(c, &map->debugfs_off_cache, list) {
353 snprintf(entry, PAGE_SIZE, "%x-%x",
354 c->base_reg, c->max_reg);
355 if (p >= *ppos) {
356 if (buf_pos + 1 + strlen(entry) > count)
357 break;
358 snprintf(buf + buf_pos, count - buf_pos,
359 "%s", entry);
360 buf_pos += strlen(entry);
361 buf[buf_pos] = '\n';
362 buf_pos++;
363 }
364 p += strlen(entry) + 1;
365 }
366 mutex_unlock(&map->cache_lock);
367
368 kfree(entry);
369 ret = buf_pos;
370
371 if (copy_to_user(user_buf, buf, buf_pos)) {
372 ret = -EFAULT;
373 goto out_buf;
374 }
375
376 *ppos += buf_pos;
377out_buf:
378 kfree(buf);
379 return ret;
380}
381
382static const struct file_operations regmap_reg_ranges_fops = {
383 .open = simple_open,
384 .read = regmap_reg_ranges_read_file,
385 .llseek = default_llseek,
386};
387
314static ssize_t regmap_access_read_file(struct file *file, 388static ssize_t regmap_access_read_file(struct file *file,
315 char __user *user_buf, size_t count, 389 char __user *user_buf, size_t count,
316 loff_t *ppos) 390 loff_t *ppos)
@@ -385,6 +459,7 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
385 struct regmap_range_node *range_node; 459 struct regmap_range_node *range_node;
386 460
387 INIT_LIST_HEAD(&map->debugfs_off_cache); 461 INIT_LIST_HEAD(&map->debugfs_off_cache);
462 mutex_init(&map->cache_lock);
388 463
389 if (name) { 464 if (name) {
390 map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s", 465 map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
@@ -403,6 +478,9 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
403 debugfs_create_file("name", 0400, map->debugfs, 478 debugfs_create_file("name", 0400, map->debugfs,
404 map, &regmap_name_fops); 479 map, &regmap_name_fops);
405 480
481 debugfs_create_file("range", 0400, map->debugfs,
482 map, &regmap_reg_ranges_fops);
483
406 if (map->max_register) { 484 if (map->max_register) {
407 debugfs_create_file("registers", 0400, map->debugfs, 485 debugfs_create_file("registers", 0400, map->debugfs,
408 map, &regmap_map_fops); 486 map, &regmap_map_fops);
@@ -435,7 +513,9 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
435void regmap_debugfs_exit(struct regmap *map) 513void regmap_debugfs_exit(struct regmap *map)
436{ 514{
437 debugfs_remove_recursive(map->debugfs); 515 debugfs_remove_recursive(map->debugfs);
516 mutex_lock(&map->cache_lock);
438 regmap_debugfs_free_dump_cache(map); 517 regmap_debugfs_free_dump_cache(map);
518 mutex_unlock(&map->cache_lock);
439 kfree(map->debugfs_name); 519 kfree(map->debugfs_name);
440} 520}
441 521