Commit 38a817965d2d624b0db68f3bf5ae783ad7f2087a

Authored by Mark Brown

Merge remote-tracking branch 'regmap/topic/range' into regmap-next

Showing 2 changed files Side-by-side Diff

drivers/base/regmap/internal.h
... ... @@ -77,6 +77,7 @@
77 77 unsigned int debugfs_tot_len;
78 78  
79 79 struct list_head debugfs_off_cache;
  80 + struct mutex cache_lock;
80 81 #endif
81 82  
82 83 unsigned int max_register;
drivers/base/regmap/regmap-debugfs.c
... ... @@ -88,16 +88,16 @@
88 88 * If we don't have a cache build one so we don't have to do a
89 89 * linear scan each time.
90 90 */
  91 + mutex_lock(&map->cache_lock);
  92 + i = base;
91 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 95 /* Skip unprinted registers, closing off cache entry */
94 96 if (!regmap_readable(map, i) ||
95 97 regmap_precious(map, i)) {
96 98 if (c) {
97 99 c->max = p - 1;
98   - fpos_offset = c->max - c->min;
99   - reg_offset = fpos_offset / map->debugfs_tot_len;
100   - c->max_reg = c->base_reg + reg_offset;
  100 + c->max_reg = i - map->reg_stride;
101 101 list_add_tail(&c->list,
102 102 &map->debugfs_off_cache);
103 103 c = NULL;
... ... @@ -111,6 +111,7 @@
111 111 c = kzalloc(sizeof(*c), GFP_KERNEL);
112 112 if (!c) {
113 113 regmap_debugfs_free_dump_cache(map);
  114 + mutex_unlock(&map->cache_lock);
114 115 return base;
115 116 }
116 117 c->min = p;
... ... @@ -124,9 +125,7 @@
124 125 /* Close the last entry off if we didn't scan beyond it */
125 126 if (c) {
126 127 c->max = p - 1;
127   - fpos_offset = c->max - c->min;
128   - reg_offset = fpos_offset / map->debugfs_tot_len;
129   - c->max_reg = c->base_reg + reg_offset;
  128 + c->max_reg = i - map->reg_stride;
130 129 list_add_tail(&c->list,
131 130 &map->debugfs_off_cache);
132 131 }
133 132  
... ... @@ -145,12 +144,14 @@
145 144 fpos_offset = from - c->min;
146 145 reg_offset = fpos_offset / map->debugfs_tot_len;
147 146 *pos = c->min + (reg_offset * map->debugfs_tot_len);
  147 + mutex_unlock(&map->cache_lock);
148 148 return c->base_reg + reg_offset;
149 149 }
150 150  
151 151 *pos = c->max;
152 152 ret = c->max_reg;
153 153 }
  154 + mutex_unlock(&map->cache_lock);
154 155  
155 156 return ret;
156 157 }
... ... @@ -311,6 +312,79 @@
311 312 .llseek = default_llseek,
312 313 };
313 314  
  315 +static 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;
  377 +out_buf:
  378 + kfree(buf);
  379 + return ret;
  380 +}
  381 +
  382 +static 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 +
314 388 static ssize_t regmap_access_read_file(struct file *file,
315 389 char __user *user_buf, size_t count,
316 390 loff_t *ppos)
... ... @@ -385,6 +459,7 @@
385 459 struct regmap_range_node *range_node;
386 460  
387 461 INIT_LIST_HEAD(&map->debugfs_off_cache);
  462 + mutex_init(&map->cache_lock);
388 463  
389 464 if (name) {
390 465 map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
... ... @@ -403,6 +478,9 @@
403 478 debugfs_create_file("name", 0400, map->debugfs,
404 479 map, &regmap_name_fops);
405 480  
  481 + debugfs_create_file("range", 0400, map->debugfs,
  482 + map, &regmap_reg_ranges_fops);
  483 +
406 484 if (map->max_register) {
407 485 debugfs_create_file("registers", 0400, map->debugfs,
408 486 map, &regmap_map_fops);
409 487  
... ... @@ -435,7 +513,9 @@
435 513 void regmap_debugfs_exit(struct regmap *map)
436 514 {
437 515 debugfs_remove_recursive(map->debugfs);
  516 + mutex_lock(&map->cache_lock);
438 517 regmap_debugfs_free_dump_cache(map);
  518 + mutex_unlock(&map->cache_lock);
439 519 kfree(map->debugfs_name);
440 520 }
441 521