Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1a113794 authored by Abhijeet Dharmapurikar's avatar Abhijeet Dharmapurikar Committed by David Collins
Browse files

regmap: improve debugfs interface to dump specific addresses



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 a means to write to a register address.  Use
CONFIG_REGMAP_QTI_DEBUG to enable this new fine-grained
register read/write interface.

Change-Id: I3466ce89007d127151f6760328edad116d679db8
Signed-off-by: default avatarAbhijeet Dharmapurikar <adharmap@codeaurora.org>
Signed-off-by: default avatarDavid Collins <collinsd@codeaurora.org>
parent 891c257d
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -53,3 +53,12 @@ config REGMAP_SCCB
config REGMAP_I3C
	tristate
	depends on I3C

config REGMAP_QTI_DEBUG
	bool "Regmap QTI debug feature support"
	depends on REGMAP && DEBUG_FS && QGKI
	help
	  Say yes to enable QTI debug features.  This provides a runtime debugfs
	  interface to read and write a subset of regmap registers.  This
	  interface is more performant and easier to use than the traditional
	  method which dumps all registers defined in a given regmap.
+5 −0
Original line number Diff line number Diff line
@@ -84,6 +84,11 @@ struct regmap {

	struct list_head debugfs_off_cache;
	struct mutex cache_lock;

#ifdef CONFIG_REGMAP_QTI_DEBUG
	unsigned int dump_address;
	unsigned int dump_count;
#endif
#endif

	unsigned int max_register;
+73 −0
Original line number Diff line number Diff line
@@ -339,6 +339,69 @@ static const struct file_operations regmap_map_fops = {
	.llseek = default_llseek,
};

#ifdef CONFIG_REGMAP_QTI_DEBUG
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,
};
#endif

static ssize_t regmap_range_read_file(struct file *file, char __user *user_buf,
				      size_t count, loff_t *ppos)
{
@@ -608,6 +671,16 @@ void regmap_debugfs_init(struct regmap *map, const char *name)
				    map, &regmap_map_fops);
		debugfs_create_file("access", 0400, map->debugfs,
				    map, &regmap_access_fops);

#ifdef CONFIG_REGMAP_QTI_DEBUG
		debugfs_create_x32("address", 0600, map->debugfs,
				    &map->dump_address);
		map->dump_count = 1;
		debugfs_create_u32("count", 0600, map->debugfs,
				    &map->dump_count);
		debugfs_create_file("data", registers_mode, map->debugfs,
				    map, &regmap_data_fops);
#endif
	}

	if (map->cache_type) {