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