regmap-debugfs.c 12.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
 * Register map access API - debugfs
 *
 * Copyright 2011 Wolfson Microelectronics plc
 *
 * Author: Mark Brown <broonie@opensource.wolfsonmicro.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#include <linux/slab.h>
#include <linux/mutex.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
17
#include <linux/device.h>
18
19
20
21
22

#include "internal.h"

static struct dentry *regmap_debugfs_root;

23
24
25
26
27
28
29
/* Calculate the length of a fixed format  */
static size_t regmap_calc_reg_len(int max_val, char *buf, size_t buf_size)
{
	snprintf(buf, buf_size, "%x", max_val);
	return strlen(buf);
}

30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
static ssize_t regmap_name_read_file(struct file *file,
				     char __user *user_buf, size_t count,
				     loff_t *ppos)
{
	struct regmap *map = file->private_data;
	int ret;
	char *buf;

	buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	ret = snprintf(buf, PAGE_SIZE, "%s\n", map->dev->driver->name);
	if (ret < 0) {
		kfree(buf);
		return ret;
	}

	ret = simple_read_from_buffer(user_buf, count, ppos, buf, ret);
	kfree(buf);
	return ret;
}

static const struct file_operations regmap_name_fops = {
54
	.open = simple_open,
55
56
57
58
	.read = regmap_name_read_file,
	.llseek = default_llseek,
};

59
60
61
62
63
64
65
66
67
68
69
70
71
static void regmap_debugfs_free_dump_cache(struct regmap *map)
{
	struct regmap_debugfs_off_cache *c;

	while (!list_empty(&map->debugfs_off_cache)) {
		c = list_first_entry(&map->debugfs_off_cache,
				     struct regmap_debugfs_off_cache,
				     list);
		list_del(&c->list);
		kfree(c);
	}
}

72
73
74
75
76
77
78
79
80
/*
 * Work out where the start offset maps into register numbers, bearing
 * in mind that we suppress hidden registers.
 */
static unsigned int regmap_debugfs_get_dump_start(struct regmap *map,
						  unsigned int base,
						  loff_t from,
						  loff_t *pos)
{
81
82
83
	struct regmap_debugfs_off_cache *c = NULL;
	loff_t p = 0;
	unsigned int i, ret;
84
85
	unsigned int fpos_offset;
	unsigned int reg_offset;
86

87
88
89
90
	/* Suppress the cache if we're using a subrange */
	if (from)
		return from;

91
92
93
94
	/*
	 * If we don't have a cache build one so we don't have to do a
	 * linear scan each time.
	 */
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
100
101
102
103
			/* Skip unprinted registers, closing off cache entry */
			if (!regmap_readable(map, i) ||
			    regmap_precious(map, i)) {
				if (c) {
					c->max = p - 1;
104
					c->max_reg = i - map->reg_stride;
105
106
107
108
109
110
111
112
113
114
115
					list_add_tail(&c->list,
						      &map->debugfs_off_cache);
					c = NULL;
				}

				continue;
			}

			/* No cache entry?  Start a new one */
			if (!c) {
				c = kzalloc(sizeof(*c), GFP_KERNEL);
116
117
				if (!c) {
					regmap_debugfs_free_dump_cache(map);
118
					mutex_unlock(&map->cache_lock);
119
120
					return base;
				}
121
122
123
124
125
126
127
				c->min = p;
				c->base_reg = i;
			}

			p += map->debugfs_tot_len;
		}
	}
128

129
130
131
	/* Close the last entry off if we didn't scan beyond it */
	if (c) {
		c->max = p - 1;
132
		c->max_reg = i - map->reg_stride;
133
134
135
136
		list_add_tail(&c->list,
			      &map->debugfs_off_cache);
	}

137
138
139
140
141
	/*
	 * This should never happen; we return above if we fail to
	 * allocate and we should never be in this code if there are
	 * no registers at all.
	 */
142
143
	WARN_ON(list_empty(&map->debugfs_off_cache));
	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
149
150
			fpos_offset = from - c->min;
			reg_offset = fpos_offset / map->debugfs_tot_len;
			*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
156
		*pos = c->max;
		ret = c->max_reg;
157
	}
158
	mutex_unlock(&map->cache_lock);
159

160
	return ret;
161
162
}

163
164
165
166
167
168
169
170
171
172
173
174
175
static inline void regmap_calc_tot_len(struct regmap *map,
				       void *buf, size_t count)
{
	/* Calculate the length of a fixed format  */
	if (!map->debugfs_tot_len) {
		map->debugfs_reg_len = regmap_calc_reg_len(map->max_register,
							   buf, count);
		map->debugfs_val_len = 2 * map->format.val_bytes;
		map->debugfs_tot_len = map->debugfs_reg_len +
			map->debugfs_val_len + 3;      /* : \n */
	}
}

176
177
178
static ssize_t regmap_read_debugfs(struct regmap *map, unsigned int from,
				   unsigned int to, char __user *user_buf,
				   size_t count, loff_t *ppos)
179
180
{
	size_t buf_pos = 0;
181
	loff_t p = *ppos;
182
183
184
	ssize_t ret;
	int i;
	char *buf;
185
	unsigned int val, start_reg;
186
187
188
189
190
191
192
193

	if (*ppos < 0 || !count)
		return -EINVAL;

	buf = kmalloc(count, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

194
	regmap_calc_tot_len(map, buf, count);
195

196
197
198
199
	/* Work out which register we're starting at */
	start_reg = regmap_debugfs_get_dump_start(map, from, *ppos, &p);

	for (i = start_reg; i <= to; i += map->reg_stride) {
200
		if (!regmap_readable(map, i))
201
202
			continue;

203
		if (regmap_precious(map, i))
204
205
			continue;

206
207
208
		/* If we're in the region the user is trying to read */
		if (p >= *ppos) {
			/* ...but not beyond it */
209
			if (buf_pos + map->debugfs_tot_len > count)
210
211
212
213
				break;

			/* Format the register */
			snprintf(buf + buf_pos, count - buf_pos, "%.*x: ",
214
215
				 map->debugfs_reg_len, i - from);
			buf_pos += map->debugfs_reg_len + 2;
216
217
218
219
220

			/* Format the value, write all X if we can't read */
			ret = regmap_read(map, i, &val);
			if (ret == 0)
				snprintf(buf + buf_pos, count - buf_pos,
221
					 "%.*x", map->debugfs_val_len, val);
222
			else
223
224
				memset(buf + buf_pos, 'X',
				       map->debugfs_val_len);
225
226
227
228
			buf_pos += 2 * map->format.val_bytes;

			buf[buf_pos++] = '\n';
		}
229
		p += map->debugfs_tot_len;
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
	}

	ret = buf_pos;

	if (copy_to_user(user_buf, buf, buf_pos)) {
		ret = -EFAULT;
		goto out;
	}

	*ppos += buf_pos;

out:
	kfree(buf);
	return ret;
}

246
247
248
249
250
251
252
253
254
static ssize_t regmap_map_read_file(struct file *file, char __user *user_buf,
				    size_t count, loff_t *ppos)
{
	struct regmap *map = file->private_data;

	return regmap_read_debugfs(map, 0, map->max_register, user_buf,
				   count, ppos);
}

255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
#undef REGMAP_ALLOW_WRITE_DEBUGFS
#ifdef REGMAP_ALLOW_WRITE_DEBUGFS
/*
 * This can be dangerous especially when we have clients such as
 * PMICs, therefore don't provide any real compile time configuration option
 * for this feature, people who want to use this will need to modify
 * the source code directly.
 */
static ssize_t regmap_map_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 reg, value;
	struct regmap *map = file->private_data;
272
	int ret;
273
274
275
276
277
278
279
280
281
282
283

	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++;
	reg = simple_strtoul(start, &start, 16);
	while (*start == ' ')
		start++;
284
	if (kstrtoul(start, 16, &value))
285
286
287
		return -EINVAL;

	/* Userspace has been fiddling around behind the kernel's back */
288
	add_taint(TAINT_USER, LOCKDEP_STILL_OK);
289

290
291
292
	ret = regmap_write(map, reg, value);
	if (ret < 0)
		return ret;
293
294
295
296
297
298
	return buf_size;
}
#else
#define regmap_map_write_file NULL
#endif

299
static const struct file_operations regmap_map_fops = {
300
	.open = simple_open,
301
	.read = regmap_map_read_file,
302
	.write = regmap_map_write_file,
303
304
305
	.llseek = default_llseek,
};

306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
static ssize_t regmap_range_read_file(struct file *file, char __user *user_buf,
				      size_t count, loff_t *ppos)
{
	struct regmap_range_node *range = file->private_data;
	struct regmap *map = range->map;

	return regmap_read_debugfs(map, range->range_min, range->range_max,
				   user_buf, count, ppos);
}

static const struct file_operations regmap_range_fops = {
	.open = simple_open,
	.read = regmap_range_read_file,
	.llseek = default_llseek,
};

322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
static ssize_t regmap_reg_ranges_read_file(struct file *file,
					   char __user *user_buf, size_t count,
					   loff_t *ppos)
{
	struct regmap *map = file->private_data;
	struct regmap_debugfs_off_cache *c;
	loff_t p = 0;
	size_t buf_pos = 0;
	char *buf;
	char *entry;
	int ret;

	if (*ppos < 0 || !count)
		return -EINVAL;

	buf = kmalloc(count, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	entry = kmalloc(PAGE_SIZE, GFP_KERNEL);
	if (!entry) {
		kfree(buf);
		return -ENOMEM;
	}

	/* While we are at it, build the register dump cache
	 * now so the read() operation on the `registers' file
	 * can benefit from using the cache.  We do not care
	 * about the file position information that is contained
	 * in the cache, just about the actual register blocks */
	regmap_calc_tot_len(map, buf, count);
	regmap_debugfs_get_dump_start(map, 0, *ppos, &p);

	/* Reset file pointer as the fixed-format of the `registers'
	 * file is not compatible with the `range' file */
	p = 0;
	mutex_lock(&map->cache_lock);
	list_for_each_entry(c, &map->debugfs_off_cache, list) {
		snprintf(entry, PAGE_SIZE, "%x-%x",
			 c->base_reg, c->max_reg);
		if (p >= *ppos) {
			if (buf_pos + 1 + strlen(entry) > count)
				break;
			snprintf(buf + buf_pos, count - buf_pos,
				 "%s", entry);
			buf_pos += strlen(entry);
			buf[buf_pos] = '\n';
			buf_pos++;
		}
		p += strlen(entry) + 1;
	}
	mutex_unlock(&map->cache_lock);

	kfree(entry);
	ret = buf_pos;

	if (copy_to_user(user_buf, buf, buf_pos)) {
		ret = -EFAULT;
		goto out_buf;
	}

	*ppos += buf_pos;
out_buf:
	kfree(buf);
	return ret;
}

static const struct file_operations regmap_reg_ranges_fops = {
	.open = simple_open,
	.read = regmap_reg_ranges_read_file,
	.llseek = default_llseek,
};

395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
static ssize_t regmap_access_read_file(struct file *file,
				       char __user *user_buf, size_t count,
				       loff_t *ppos)
{
	int reg_len, tot_len;
	size_t buf_pos = 0;
	loff_t p = 0;
	ssize_t ret;
	int i;
	struct regmap *map = file->private_data;
	char *buf;

	if (*ppos < 0 || !count)
		return -EINVAL;

	buf = kmalloc(count, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	/* Calculate the length of a fixed format  */
	reg_len = regmap_calc_reg_len(map->max_register, buf, count);
	tot_len = reg_len + 10; /* ': R W V P\n' */

418
	for (i = 0; i <= map->max_register; i += map->reg_stride) {
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
		/* Ignore registers which are neither readable nor writable */
		if (!regmap_readable(map, i) && !regmap_writeable(map, i))
			continue;

		/* If we're in the region the user is trying to read */
		if (p >= *ppos) {
			/* ...but not beyond it */
			if (buf_pos >= count - 1 - tot_len)
				break;

			/* Format the register */
			snprintf(buf + buf_pos, count - buf_pos,
				 "%.*x: %c %c %c %c\n",
				 reg_len, i,
				 regmap_readable(map, i) ? 'y' : 'n',
				 regmap_writeable(map, i) ? 'y' : 'n',
				 regmap_volatile(map, i) ? 'y' : 'n',
				 regmap_precious(map, i) ? 'y' : 'n');

			buf_pos += tot_len;
		}
		p += tot_len;
	}

	ret = buf_pos;

	if (copy_to_user(user_buf, buf, buf_pos)) {
		ret = -EFAULT;
		goto out;
	}

	*ppos += buf_pos;

out:
	kfree(buf);
	return ret;
}

static const struct file_operations regmap_access_fops = {
458
	.open = simple_open,
459
460
461
	.read = regmap_access_read_file,
	.llseek = default_llseek,
};
462

463
void regmap_debugfs_init(struct regmap *map, const char *name)
464
{
465
466
467
	struct rb_node *next;
	struct regmap_range_node *range_node;

468
	INIT_LIST_HEAD(&map->debugfs_off_cache);
469
	mutex_init(&map->cache_lock);
470

471
472
473
474
475
476
477
478
479
	if (name) {
		map->debugfs_name = kasprintf(GFP_KERNEL, "%s-%s",
					      dev_name(map->dev), name);
		name = map->debugfs_name;
	} else {
		name = dev_name(map->dev);
	}

	map->debugfs = debugfs_create_dir(name, regmap_debugfs_root);
480
481
482
483
484
	if (!map->debugfs) {
		dev_warn(map->dev, "Failed to create debugfs directory\n");
		return;
	}

485
486
487
	debugfs_create_file("name", 0400, map->debugfs,
			    map, &regmap_name_fops);

488
489
490
	debugfs_create_file("range", 0400, map->debugfs,
			    map, &regmap_reg_ranges_fops);

491
	if (map->max_register) {
492
493
		debugfs_create_file("registers", 0400, map->debugfs,
				    map, &regmap_map_fops);
494
495
496
		debugfs_create_file("access", 0400, map->debugfs,
				    map, &regmap_access_fops);
	}
497
498
499
500
501
502
503
504
505

	if (map->cache_type) {
		debugfs_create_bool("cache_only", 0400, map->debugfs,
				    &map->cache_only);
		debugfs_create_bool("cache_dirty", 0400, map->debugfs,
				    &map->cache_dirty);
		debugfs_create_bool("cache_bypass", 0400, map->debugfs,
				    &map->cache_bypass);
	}
506
507
508
509
510
511
512
513
514
515
516
517

	next = rb_first(&map->range_tree);
	while (next) {
		range_node = rb_entry(next, struct regmap_range_node, node);

		if (range_node->name)
			debugfs_create_file(range_node->name, 0400,
					    map->debugfs, range_node,
					    &regmap_range_fops);

		next = rb_next(&range_node->node);
	}
518
519
520
521
522
}

void regmap_debugfs_exit(struct regmap *map)
{
	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
529
530
531
532
533
534
535
536
}

void regmap_debugfs_initcall(void)
{
	regmap_debugfs_root = debugfs_create_dir("regmap", NULL);
	if (!regmap_debugfs_root) {
		pr_warn("regmap: Failed to create debugfs root\n");
		return;
	}
}