linux/drivers/base/regmap/regmap-debugfs.c
<<
>>
Prefs
   1/*
   2 * Register map access API - debugfs
   3 *
   4 * Copyright 2011 Wolfson Microelectronics plc
   5 *
   6 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12
  13#include <linux/slab.h>
  14#include <linux/mutex.h>
  15#include <linux/debugfs.h>
  16#include <linux/uaccess.h>
  17#include <linux/device.h>
  18
  19#include "internal.h"
  20
  21static struct dentry *regmap_debugfs_root;
  22
  23/* Calculate the length of a fixed format  */
  24static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size)
  25{
  26        snprintf(buf, buf_size, "%x", max_val);
  27        return strlen(buf);
  28}
  29
  30static ssize_t regmap_name_read_file(struct file *file,
  31                                     char __user *user_buf, size_t count,
  32                                     loff_t *ppos)
  33{
  34        struct regmap *map = file->private_data;
  35        int ret;
  36        char *buf;
  37
  38        buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
  39        if (!buf)
  40                return -ENOMEM;
  41
  42        ret = snprintf(buf, PAGE_SIZE, "%s\n", map->dev->driver->name);
  43        if (ret < 0) {
  44                kfree(buf);
  45                return ret;
  46        }
  47
  48        ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
  49        kfree(buf);
  50        return ret;
  51}
  52
  53static const struct file_operations regmap_name_fops = {
  54        .open = simple_open,
  55        .read = regmap_name_read_file,
  56        .llseek = default_llseek,
  57};
  58
  59static void regmap_debugfs_free_dump_cache(struct regmap *map)
  60{
  61        struct regmap_debugfs_off_cache *c;
  62
  63        while (!list_empty(&map->debugfs_off_cache)) {
  64                c = list_first_entry(&map->debugfs_off_cache,
  65                                     struct regmap_debugfs_off_cache,
  66                                     list);
  67                list_del(&c->list);
  68                kfree(c);
  69        }
  70}
  71
  72/*
  73 * Work out where the start offset maps into register numbers, bearing
  74 * in mind that we suppress hidden registers.
  75 */
  76static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
  77                                                  unsigned int base,
  78                                                  loff_t from,
  79                                                  loff_t *pos)
  80{
  81        struct regmap_debugfs_off_cache *c = NULL;
  82        loff_t p = 0;
  83        unsigned int i, ret;
  84        unsigned int fpos_offset;
  85        unsigned int reg_offset;
  86
  87        /* Suppress the cache if we're using a subrange */
  88        if (base)
  89                return base;
  90
  91        /*
  92         * If we don't have a cache build one so we don't have to do a
  93         * linear scan each time.
  94         */
  95        mutex_lock(&map->cache_lock);
  96        i = base;
  97        if (list_empty(&map->debugfs_off_cache)) {
  98                for (; i <= map->max_register; i += map->reg_stride) {
  99                        /* Skip unprinted registers, closing off cache entry */
 100                        if (!regmap_readable(map, i) ||
 101                            regmap_precious(map, i)) {
 102                                if (c) {
 103                                        c->max = p - 1;
 104                                        c->max_reg = i - map->reg_stride;
 105                                        list_add_tail(&c->list,
 106                                                      &map->debugfs_off_cache);
 107                                        c = NULL;
 108                                }
 109
 110                                continue;
 111                        }
 112
 113                        /* No cache entry?  Start a new one */
 114                        if (!c) {
 115                                c = kzalloc(sizeof(*c), GFP_KERNEL);
 116                                if (!c) {
 117                                        regmap_debugfs_free_dump_cache(map);
 118                                        mutex_unlock(&map->cache_lock);
 119                                        return base;
 120                                }
 121                                c->min = p;
 122                                c->base_reg = i;
 123                        }
 124
 125                        p += map->debugfs_tot_len;
 126                }
 127        }
 128
 129        /* Close the last entry off if we didn't scan beyond it */
 130        if (c) {
 131                c->max = p - 1;
 132                c->max_reg = i - map->reg_stride;
 133                list_add_tail(&c->list,
 134                              &map->debugfs_off_cache);
 135        }
 136
 137        /*
 138         * This should never happen; we return above if we fail to
 139         * allocate and we should never be in this code if there are
 140         * no registers at all.
 141         */
 142        WARN_ON(list_empty(&map->debugfs_off_cache));
 143        ret = base;
 144
 145        /* Find the relevant block:offset */
 146        list_for_each_entry(c, &map->debugfs_off_cache, list) {
 147                if (from >= c->min && from <= c->max) {
 148                        fpos_offset = from - c->min;
 149                        reg_offset = fpos_offset / map->debugfs_tot_len;
 150                        *pos = c->min + (reg_offset * map->debugfs_tot_len);
 151                        mutex_unlock(&map->cache_lock);
 152                        return c->base_reg + (reg_offset * map->reg_stride);
 153                }
 154
 155                *pos = c->max;
 156                ret = c->max_reg;
 157        }
 158        mutex_unlock(&map->cache_lock);
 159
 160        return ret;
 161}
 162
 163static inline void regmap_calc_tot_len(struct regmap *map,
 164                                       void *buf, size_t count)
 165{
 166        /* Calculate the length of a fixed format  */
 167        if (!map->debugfs_tot_len) {
 168                map->debugfs_reg_len = regmap_calc_reg_len(map->max_register,
 169                                                           buf, count);
 170                map->debugfs_val_len = 2 * map->format.val_bytes;
 171                map->debugfs_tot_len = map->debugfs_reg_len +
 172                        map->debugfs_val_len + 3;      /* : \n */
 173        }
 174}
 175
 176static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from,
 177                                   unsigned int to, char __user *user_buf,
 178                                   size_t count, loff_t *ppos)
 179{
 180        size_t buf_pos = 0;
 181        loff_t p = *ppos;
 182        ssize_t ret;
 183        int i;
 184        char *buf;
 185        unsigned int val, start_reg;
 186
 187        if (*ppos < 0 || !count)
 188                return -EINVAL;
 189
 190        buf = kmalloc(count, GFP_KERNEL);
 191        if (!buf)
 192                return -ENOMEM;
 193
 194        regmap_calc_tot_len(map, buf, count);
 195
 196        /* Work out which register we're starting at */
 197        start_reg = regmap_debugfs_get_dump_start(map, from, *ppos, &p);
 198
 199        for (i = start_reg; i <= to; i += map->reg_stride) {
 200                if (!regmap_readable(map, i))
 201                        continue;
 202
 203                if (regmap_precious(map, i))
 204                        continue;
 205
 206                /* If we're in the region the user is trying to read */
 207                if (p >= *ppos) {
 208                        /* ...but not beyond it */
 209                        if (buf_pos + map->debugfs_tot_len > count)
 210                                break;
 211
 212                        /* Format the register */
 213                        snprintf(buf + buf_pos, count - buf_pos, "%.*x: ",
 214                                 map->debugfs_reg_len, i - from);
 215                        buf_pos += map->debugfs_reg_len + 2;
 216
 217                        /* Format the value, write all X if we can't read */
 218                        ret = regmap_read(map, i, &val);
 219                        if (ret == 0)
 220                                snprintf(buf + buf_pos, count - buf_pos,
 221                                         "%.*x", map->debugfs_val_len, val);
 222                        else
 223                                memset(buf + buf_pos, 'X',
 224                                       map->debugfs_val_len);
 225                        buf_pos += 2 * map->format.val_bytes;
 226
 227                        buf[buf_pos++] = '\n';
 228                }
 229                p += map->debugfs_tot_len;
 230        }
 231
 232        ret = buf_pos;
 233
 234        if (copy_to_user(user_buf, buf, buf_pos)) {
 235                ret = -EFAULT;
 236                goto out;
 237        }
 238
 239        *ppos += buf_pos;
 240
 241out:
 242        kfree(buf);
 243        return ret;
 244}
 245
 246static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
 247                                    size_t count, loff_t *ppos)
 248{
 249        struct regmap *map = file->private_data;
 250
 251        return regmap_read_debugfs(map, 0, map->max_register, user_buf,
 252                                   count, ppos);
 253}
 254
 255#undef REGMAP_ALLOW_WRITE_DEBUGFS
 256#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
 257/*
 258 * This can be dangerous especially when we have clients such as
 259 * PMICs, therefore don't provide any real compile time configuration option
 260 * for this feature, people who want to use this will need to modify
 261 * the source code directly.
 262 */
 263static ssize_t regmap_map_write_file(struct file *file,
 264                                     const char __user *user_buf,
 265                                     size_t count, loff_t *ppos)
 266{
 267        char buf[32];
 268        size_t buf_size;
 269        char *start = buf;
 270        unsigned long reg, value;
 271        struct regmap *map = file->private_data;
 272        int ret;
 273
 274        buf_size = min(count, (sizeof(buf)-1));
 275        if (copy_from_user(buf, user_buf, buf_size))
 276                return -EFAULT;
 277        buf[buf_size] = 0;
 278
 279        while (*start == ' ')
 280                start++;
 281        reg = simple_strtoul(start, &start, 16);
 282        while (*start == ' ')
 283                start++;
 284        if (kstrtoul(start, 16, &value))
 285                return -EINVAL;
 286
 287        /* Userspace has been fiddling around behind the kernel's back */
 288        add_taint(TAINT_USER, LOCKDEP_STILL_OK);
 289
 290        ret = regmap_write(map, reg, value);
 291        if (ret < 0)
 292                return ret;
 293        return buf_size;
 294}
 295#else
 296#define regmap_map_write_file NULL
 297#endif
 298
 299static const struct file_operations regmap_map_fops = {
 300        .open = simple_open,
 301        .read = regmap_map_read_file,
 302        .write = regmap_map_write_file,
 303        .llseek = default_llseek,
 304};
 305
 306static ssize_t regmap_range_read_file(struct file *file, char __user *user_buf,
 307                                      size_t count, loff_t *ppos)
 308{
 309        struct regmap_range_node *range = file->private_data;
 310        struct regmap *map = range->map;
 311
 312        return regmap_read_debugfs(map, range->range_min, range->range_max,
 313                                   user_buf, count, ppos);
 314}
 315
 316static const struct file_operations regmap_range_fops = {
 317        .open = simple_open,
 318        .read = regmap_range_read_file,
 319        .llseek = default_llseek,
 320};
 321
 322static ssize_t regmap_reg_ranges_read_file(struct file *file,
 323                                           char __user *user_buf, size_t count,
 324                                           loff_t *ppos)
 325{
 326        struct regmap *map = file->private_data;
 327        struct regmap_debugfs_off_cache *c;
 328        loff_t p = 0;
 329        size_t buf_pos = 0;
 330        char *buf;
 331        char *entry;
 332        int ret;
 333
 334        if (*ppos < 0 || !count)
 335                return -EINVAL;
 336
 337        buf = kmalloc(count, GFP_KERNEL);
 338        if (!buf)
 339                return -ENOMEM;
 340
 341        entry = kmalloc(PAGE_SIZE, GFP_KERNEL);
 342        if (!entry) {
 343                kfree(buf);
 344                return -ENOMEM;
 345        }
 346
 347        /* While we are at it, build the register dump cache
 348         * now so the read() operation on the `registers' file
 349         * can benefit from using the cache.  We do not care
 350         * about the file position information that is contained
 351         * in the cache, just about the actual register blocks */
 352        regmap_calc_tot_len(map, buf, count);
 353        regmap_debugfs_get_dump_start(map, 0, *ppos, &p);
 354
 355        /* Reset file pointer as the fixed-format of the `registers'
 356         * file is not compatible with the `range' file */
 357        p = 0;
 358        mutex_lock(&map->cache_lock);
 359        list_for_each_entry(c, &map->debugfs_off_cache, list) {
 360                snprintf(entry, PAGE_SIZE, "%x-%x",
 361                         c->base_reg, c->max_reg);
 362                if (p >= *ppos) {
 363                        if (buf_pos + 1 + strlen(entry) > count)
 364                                break;
 365                        snprintf(buf + buf_pos, count - buf_pos,
 366                                 "%s", entry);
 367                        buf_pos += strlen(entry);
 368                        buf[buf_pos] = '\n';
 369                        buf_pos++;
 370                }
 371                p += strlen(entry) + 1;
 372        }
 373        mutex_unlock(&map->cache_lock);
 374
 375        kfree(entry);
 376        ret = buf_pos;
 377
 378        if (copy_to_user(user_buf, buf, buf_pos)) {
 379                ret = -EFAULT;
 380                goto out_buf;
 381        }
 382
 383        *ppos += buf_pos;
 384out_buf:
 385        kfree(buf);
 386        return ret;
 387}
 388
 389static const struct file_operations regmap_reg_ranges_fops = {
 390        .open = simple_open,
 391        .read = regmap_reg_ranges_read_file,
 392        .llseek = default_llseek,
 393};
 394
 395static ssize_t regmap_access_read_file(struct file *file,
 396                                       char __user *user_buf, size_t count,
 397                                       loff_t *ppos)
 398{
 399        int reg_len, tot_len;
 400        size_t buf_pos = 0;
 401        loff_t p = 0;
 402        ssize_t ret;
 403        int i;
 404        struct regmap *map = file->private_data;
 405        char *buf;
 406
 407        if (*ppos < 0 || !count)
 408                return -EINVAL;
 409
 410        buf = kmalloc(count, GFP_KERNEL);
 411        if (!buf)
 412                return -ENOMEM;
 413
 414        /* Calculate the length of a fixed format  */
 415        reg_len = regmap_calc_reg_len(map->max_register, buf, count);
 416        tot_len = reg_len + 10; /* ': R W V P\n' */
 417
 418        for (i = 0; i <= map->max_register; i += map->reg_stride) {
 419                /* Ignore registers which are neither readable nor writable */
 420                if (!regmap_readable(map, i) && !regmap_writeable(map, i))
 421                        continue;
 422
 423                /* If we're in the region the user is trying to read */
 424                if (p >= *ppos) {
 425                        /* ...but not beyond it */
 426                        if (buf_pos >= count - 1 - tot_len)
 427                                break;
 428
 429                        /* Format the register */
 430                        snprintf(buf + buf_pos, count - buf_pos,
 431                                 "%.*x: %c %c %c %c\n",
 432                                 reg_len, i,
 433                                 regmap_readable(map, i) ? 'y' : 'n',
 434                                 regmap_writeable(map, i) ? 'y' : 'n',
 435                                 regmap_volatile(map, i) ? 'y' : 'n',
 436                                 regmap_precious(map, i) ? 'y' : 'n');
 437
 438                        buf_pos += tot_len;
 439                }
 440                p += tot_len;
 441        }
 442
 443        ret = buf_pos;
 444
 445        if (copy_to_user(user_buf, buf, buf_pos)) {
 446                ret = -EFAULT;
 447                goto out;
 448        }
 449
 450        *ppos += buf_pos;
 451
 452out:
 453        kfree(buf);
 454        return ret;
 455}
 456
 457static const struct file_operations regmap_access_fops = {
 458        .open = simple_open,
 459        .read = regmap_access_read_file,
 460        .llseek = default_llseek,
 461};
 462
 463void regmap_debugfs_init(struct regmap *map, const char *name)
 464{
 465        struct rb_node *next;
 466        struct regmap_range_node *range_node;
 467
 468        INIT_LIST_HEAD(&map->debugfs_off_cache);
 469        mutex_init(&map->cache_lock);
 470
 471        if (name) {
 472                map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
 473                                              dev_name(map->dev), name);
 474                name = map->debugfs_name;
 475        } else {
 476                name = dev_name(map->dev);
 477        }
 478
 479        map->debugfs = debugfs_create_dir(name, regmap_debugfs_root);
 480        if (!map->debugfs) {
 481                dev_warn(map->dev, "Failed to create debugfs directory\n");
 482                return;
 483        }
 484
 485        debugfs_create_file("name", 0400, map->debugfs,
 486                            map, &regmap_name_fops);
 487
 488        debugfs_create_file("range", 0400, map->debugfs,
 489                            map, &regmap_reg_ranges_fops);
 490
 491        if (map->max_register) {
 492                debugfs_create_file("registers", 0400, map->debugfs,
 493                                    map, &regmap_map_fops);
 494                debugfs_create_file("access", 0400, map->debugfs,
 495                                    map, &regmap_access_fops);
 496        }
 497
 498        if (map->cache_type) {
 499                debugfs_create_bool("cache_only", 0400, map->debugfs,
 500                                    &map->cache_only);
 501                debugfs_create_bool("cache_dirty", 0400, map->debugfs,
 502                                    &map->cache_dirty);
 503                debugfs_create_bool("cache_bypass", 0400, map->debugfs,
 504                                    &map->cache_bypass);
 505        }
 506
 507        next = rb_first(&map->range_tree);
 508        while (next) {
 509                range_node = rb_entry(next, struct regmap_range_node, node);
 510
 511                if (range_node->name)
 512                        debugfs_create_file(range_node->name, 0400,
 513                                            map->debugfs, range_node,
 514                                            &regmap_range_fops);
 515
 516                next = rb_next(&range_node->node);
 517        }
 518}
 519
 520void regmap_debugfs_exit(struct regmap *map)
 521{
 522        debugfs_remove_recursive(map->debugfs);
 523        mutex_lock(&map->cache_lock);
 524        regmap_debugfs_free_dump_cache(map);
 525        mutex_unlock(&map->cache_lock);
 526        kfree(map->debugfs_name);
 527}
 528
 529void regmap_debugfs_initcall(void)
 530{
 531        regmap_debugfs_root = debugfs_create_dir("regmap", NULL);
 532        if (!regmap_debugfs_root) {
 533                pr_warn("regmap: Failed to create debugfs root\n");
 534                return;
 535        }
 536}
 537