diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index 1abcd27e2d0ff707cd20caba5238b63ef5eb89ae..9c3b0e7a6c7d2b551b84775bd351aab939d2c049 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -15,10 +15,18 @@ #include #include +#include struct regmap; struct regcache_ops; +struct regmap_debugfs_off_cache { + struct list_head list; + off_t min; + off_t max; + unsigned int base_reg; +}; + struct regmap_format { size_t buf_size; size_t reg_bytes; @@ -54,6 +62,8 @@ struct regmap { unsigned int debugfs_reg_len; unsigned int debugfs_val_len; unsigned int debugfs_tot_len; + + struct list_head debugfs_off_cache; #endif unsigned int max_register; diff --git a/drivers/base/regmap/regmap-debugfs.c b/drivers/base/regmap/regmap-debugfs.c index 749a1dc5bbfbbbf5e371ac712979b6c8e422a500..07aad786f817e88300af9c4d6d685391f41b3471 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, loff_t from, loff_t *pos) { - loff_t p = *pos; - unsigned int i; - - for (i = base; i <= map->max_register; i += map->reg_stride) { - if (!regmap_readable(map, i)) - continue; - - if (regmap_precious(map, i)) - continue; + struct regmap_debugfs_off_cache *c = NULL; + loff_t p = 0; + unsigned int i, ret; + + /* + * If we don't have a cache build one so we don't have to do a + * linear scan each time. + */ + 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 */ + if (!regmap_readable(map, i) || + regmap_precious(map, i)) { + if (c) { + c->max = p - 1; + list_add_tail(&c->list, + &map->debugfs_off_cache); + c = NULL; + } + + continue; + } + + /* No cache entry? Start a new one */ + if (!c) { + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + break; + c->min = p; + c->base_reg = i; + } + + p += map->debugfs_tot_len; + } + } - if (i >= from) { - *pos = p; - return i; + /* Find the relevant block */ + list_for_each_entry(c, &map->debugfs_off_cache, list) { + if (*pos >= c->min && *pos <= c->max) { + *pos = c->min; + return c->base_reg; } - p += map->debugfs_tot_len; + ret = c->max; } - return base; + return ret; } static 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) struct rb_node *next; struct regmap_range_node *range_node; + INIT_LIST_HEAD(&map->debugfs_off_cache); + if (name) { map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s", dev_name(map->dev), name); @@ -357,7 +387,16 @@ void regmap_debugfs_init(struct regmap *map, const char *name) void regmap_debugfs_exit(struct regmap *map) { + struct regmap_debugfs_off_cache *c; + debugfs_remove_recursive(map->debugfs); + while (!list_empty(&map->debugfs_off_cache)) { + c = list_first_entry(&map->debugfs_off_cache, + struct regmap_debugfs_off_cache, + list); + list_del(&c->list); + kfree(c); + } kfree(map->debugfs_name); }