OSDN Git Service

regmap: improve debugfs interface to dump specific addresses
authorAbhijeet Dharmapurikar <adharmap@codeaurora.org>
Thu, 21 Jan 2016 18:58:22 +0000 (10:58 -0800)
committerJeevan Shriram <jshriram@codeaurora.org>
Thu, 12 May 2016 00:44:12 +0000 (17:44 -0700)
The current method of cat-ing register file dumps the entire
address space. One can use dd command to dump a subrange within
the address space. However one needs to know the string length
of each line which is derived from max address, the character
length of each register entry and the format.

Provide simple means to dump a range by allowing user to specify
the start address and the count of registers. When the data is read
convert the dump address to a starting position in the file. Similarly
if the file offset goes beyond the dump range return 0 to indicate
that the data is already dumped.

Also provide means to write to a register address.

CRs-Fixed: 1001770
Change-Id: I3466ce89007d127151f6760328edad116d679db8
Signed-off-by: Abhijeet Dharmapurikar <adharmap@codeaurora.org>
drivers/base/regmap/internal.h
drivers/base/regmap/regmap-debugfs.c

index 32ded9b..61cdbaa 100644 (file)
@@ -85,6 +85,9 @@ struct regmap {
 
        struct list_head debugfs_off_cache;
        struct mutex cache_lock;
+
+       unsigned int dump_address;
+       unsigned int dump_count;
 #endif
 
        unsigned int max_register;
index 2437186..f16fa6c 100644 (file)
@@ -310,6 +310,67 @@ static const struct file_operations regmap_map_fops = {
        .llseek = default_llseek,
 };
 
+static ssize_t regmap_data_read_file(struct file *file, char __user *user_buf,
+                                   size_t count, loff_t *ppos)
+{
+       struct regmap *map = file->private_data;
+       int new_count;
+
+       regmap_calc_tot_len(map, NULL, 0);
+       new_count = map->dump_count * map->debugfs_tot_len;
+       if (new_count > count)
+               new_count = count;
+
+       if (*ppos == 0)
+               *ppos = map->dump_address * map->debugfs_tot_len;
+       else if (*ppos >= map->dump_address * map->debugfs_tot_len
+                       + map->dump_count * map->debugfs_tot_len)
+               return 0;
+       return regmap_read_debugfs(map, 0, map->max_register, user_buf,
+                       new_count, ppos);
+}
+
+#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
+static ssize_t regmap_data_write_file(struct file *file,
+                                    const char __user *user_buf,
+                                    size_t count, loff_t *ppos)
+{
+       char buf[32];
+       size_t buf_size;
+       char *start = buf;
+       unsigned long value;
+       struct regmap *map = file->private_data;
+       int ret;
+
+       buf_size = min(count, (sizeof(buf)-1));
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+       buf[buf_size] = 0;
+
+       while (*start == ' ')
+               start++;
+       if (kstrtoul(start, 16, &value))
+               return -EINVAL;
+
+       /* Userspace has been fiddling around behind the kernel's back */
+       add_taint(TAINT_USER, LOCKDEP_STILL_OK);
+
+       ret = regmap_write(map, map->dump_address, value);
+       if (ret < 0)
+               return ret;
+       return buf_size;
+}
+#else
+#define regmap_data_write_file NULL
+#endif
+
+static const struct file_operations regmap_data_fops = {
+       .open = simple_open,
+       .read = regmap_data_read_file,
+       .write = regmap_data_write_file,
+       .llseek = default_llseek,
+};
+
 static ssize_t regmap_range_read_file(struct file *file, char __user *user_buf,
                                      size_t count, loff_t *ppos)
 {
@@ -603,6 +664,14 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
 
                debugfs_create_file("registers", registers_mode, map->debugfs,
                                    map, &regmap_map_fops);
+
+               debugfs_create_x32("address", 0600, map->debugfs,
+                                   &map->dump_address);
+               debugfs_create_u32("count", 0600, map->debugfs,
+                                   &map->dump_count);
+               debugfs_create_file("data", registers_mode, map->debugfs,
+                                   map, &regmap_data_fops);
+
                debugfs_create_file("access", 0400, map->debugfs,
                                    map, &regmap_access_fops);
        }