diff options
author | Alessandro Rubini <rubini@gnudd.com> | 2011-11-18 08:50:21 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2011-11-18 13:31:22 -0500 |
commit | 1a087c6ad975bcc193b4bab2e9d61f9c6c547138 (patch) | |
tree | 207b0b121a2e5a48613e9225beb1c49ca67a92a7 | |
parent | fe7484834bb614c2c205726647635171ce6cc070 (diff) |
debugfs: add tools to printk 32-bit registers
Some debugfs file I deal with are mostly blocks of registers,
i.e. lines of the form "<name> = 0x<value>". Some files are only
registers, some include registers blocks among other material. This
patch introduces data structures and functions to deal with both
cases. I expect more users of this over time.
Signed-off-by: Alessandro Rubini <rubini@gnudd.com>
Acked-by: Giancarlo Asnaghi <giancarlo.asnaghi@st.com>
Cc: Felipe Balbi <balbi@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | Documentation/filesystems/debugfs.txt | 32 | ||||
-rw-r--r-- | fs/debugfs/file.c | 90 | ||||
-rw-r--r-- | include/linux/debugfs.h | 26 |
3 files changed, 147 insertions, 1 deletions
diff --git a/Documentation/filesystems/debugfs.txt b/Documentation/filesystems/debugfs.txt index 742cc06e138f..f04066a37f4c 100644 --- a/Documentation/filesystems/debugfs.txt +++ b/Documentation/filesystems/debugfs.txt | |||
@@ -97,7 +97,8 @@ A read on the resulting file will yield either Y (for non-zero values) or | |||
97 | N, followed by a newline. If written to, it will accept either upper- or | 97 | N, followed by a newline. If written to, it will accept either upper- or |
98 | lower-case values, or 1 or 0. Any other input will be silently ignored. | 98 | lower-case values, or 1 or 0. Any other input will be silently ignored. |
99 | 99 | ||
100 | Finally, a block of arbitrary binary data can be exported with: | 100 | Another option is exporting a block of arbitrary binary data, with |
101 | this structure and function: | ||
101 | 102 | ||
102 | struct debugfs_blob_wrapper { | 103 | struct debugfs_blob_wrapper { |
103 | void *data; | 104 | void *data; |
@@ -115,6 +116,35 @@ can be used to export binary information, but there does not appear to be | |||
115 | any code which does so in the mainline. Note that all files created with | 116 | any code which does so in the mainline. Note that all files created with |
116 | debugfs_create_blob() are read-only. | 117 | debugfs_create_blob() are read-only. |
117 | 118 | ||
119 | If you want to dump a block of registers (something that happens quite | ||
120 | often during development, even if little such code reaches mainline. | ||
121 | Debugfs offers two functions: one to make a registers-only file, and | ||
122 | another to insert a register block in the middle of another sequential | ||
123 | file. | ||
124 | |||
125 | struct debugfs_reg32 { | ||
126 | char *name; | ||
127 | unsigned long offset; | ||
128 | }; | ||
129 | |||
130 | struct debugfs_regset32 { | ||
131 | struct debugfs_reg32 *regs; | ||
132 | int nregs; | ||
133 | void __iomem *base; | ||
134 | }; | ||
135 | |||
136 | struct dentry *debugfs_create_regset32(const char *name, mode_t mode, | ||
137 | struct dentry *parent, | ||
138 | struct debugfs_regset32 *regset); | ||
139 | |||
140 | int debugfs_print_regs32(struct seq_file *s, struct debugfs_reg32 *regs, | ||
141 | int nregs, void __iomem *base, char *prefix); | ||
142 | |||
143 | The "base" argument may be 0, but you may want to build the reg32 array | ||
144 | using __stringify, and a number of register names (macros) are actually | ||
145 | byte offsets over a base for the register block. | ||
146 | |||
147 | |||
118 | There are a couple of other directory-oriented helper functions: | 148 | There are a couple of other directory-oriented helper functions: |
119 | 149 | ||
120 | struct dentry *debugfs_rename(struct dentry *old_dir, | 150 | struct dentry *debugfs_rename(struct dentry *old_dir, |
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index 90f76575c056..f31a27c60fc6 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c | |||
@@ -15,6 +15,7 @@ | |||
15 | 15 | ||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/fs.h> | 17 | #include <linux/fs.h> |
18 | #include <linux/seq_file.h> | ||
18 | #include <linux/pagemap.h> | 19 | #include <linux/pagemap.h> |
19 | #include <linux/namei.h> | 20 | #include <linux/namei.h> |
20 | #include <linux/debugfs.h> | 21 | #include <linux/debugfs.h> |
@@ -525,3 +526,92 @@ struct dentry *debugfs_create_blob(const char *name, mode_t mode, | |||
525 | return debugfs_create_file(name, mode, parent, blob, &fops_blob); | 526 | return debugfs_create_file(name, mode, parent, blob, &fops_blob); |
526 | } | 527 | } |
527 | EXPORT_SYMBOL_GPL(debugfs_create_blob); | 528 | EXPORT_SYMBOL_GPL(debugfs_create_blob); |
529 | |||
530 | /* | ||
531 | * The regset32 stuff is used to print 32-bit registers using the | ||
532 | * seq_file utilities. We offer printing a register set in an already-opened | ||
533 | * sequential file or create a debugfs file that only prints a regset32. | ||
534 | */ | ||
535 | |||
536 | /** | ||
537 | * debugfs_print_regs32 - use seq_print to describe a set of registers | ||
538 | * @s: the seq_file structure being used to generate output | ||
539 | * @regs: an array if struct debugfs_reg32 structures | ||
540 | * @mregs: the length of the above array | ||
541 | * @base: the base address to be used in reading the registers | ||
542 | * @prefix: a string to be prefixed to every output line | ||
543 | * | ||
544 | * This function outputs a text block describing the current values of | ||
545 | * some 32-bit hardware registers. It is meant to be used within debugfs | ||
546 | * files based on seq_file that need to show registers, intermixed with other | ||
547 | * information. The prefix argument may be used to specify a leading string, | ||
548 | * because some peripherals have several blocks of identical registers, | ||
549 | * for example configuration of dma channels | ||
550 | */ | ||
551 | int debugfs_print_regs32(struct seq_file *s, struct debugfs_reg32 *regs, | ||
552 | int nregs, void __iomem *base, char *prefix) | ||
553 | { | ||
554 | int i, ret = 0; | ||
555 | |||
556 | for (i = 0; i < nregs; i++, regs++) { | ||
557 | if (prefix) | ||
558 | ret += seq_printf(s, "%s", prefix); | ||
559 | ret += seq_printf(s, "%s = 0x%08x\n", regs->name, | ||
560 | readl((void *)(base + regs->offset))); | ||
561 | } | ||
562 | return ret; | ||
563 | } | ||
564 | EXPORT_SYMBOL_GPL(debugfs_print_regs32); | ||
565 | |||
566 | static int debugfs_show_regset32(struct seq_file *s, void *data) | ||
567 | { | ||
568 | struct debugfs_regset32 *regset = s->private; | ||
569 | |||
570 | debugfs_print_regs32(s, regset->regs, regset->nregs, regset->base, ""); | ||
571 | return 0; | ||
572 | } | ||
573 | |||
574 | static int debugfs_open_regset32(struct inode *inode, struct file *file) | ||
575 | { | ||
576 | return single_open(file, debugfs_show_regset32, inode->i_private); | ||
577 | } | ||
578 | |||
579 | static const struct file_operations fops_regset32 = { | ||
580 | .open = debugfs_open_regset32, | ||
581 | .read = seq_read, | ||
582 | .llseek = seq_lseek, | ||
583 | .release = single_release, | ||
584 | }; | ||
585 | |||
586 | /** | ||
587 | * debugfs_create_regset32 - create a debugfs file that returns register values | ||
588 | * @name: a pointer to a string containing the name of the file to create. | ||
589 | * @mode: the permission that the file should have | ||
590 | * @parent: a pointer to the parent dentry for this file. This should be a | ||
591 | * directory dentry if set. If this parameter is %NULL, then the | ||
592 | * file will be created in the root of the debugfs filesystem. | ||
593 | * @regset: a pointer to a struct debugfs_regset32, which contains a pointer | ||
594 | * to an array of register definitions, the array size and the base | ||
595 | * address where the register bank is to be found. | ||
596 | * | ||
597 | * This function creates a file in debugfs with the given name that reports | ||
598 | * the names and values of a set of 32-bit registers. If the @mode variable | ||
599 | * is so set it can be read from. Writing is not supported. | ||
600 | * | ||
601 | * This function will return a pointer to a dentry if it succeeds. This | ||
602 | * pointer must be passed to the debugfs_remove() function when the file is | ||
603 | * to be removed (no automatic cleanup happens if your module is unloaded, | ||
604 | * you are responsible here.) If an error occurs, %NULL will be returned. | ||
605 | * | ||
606 | * If debugfs is not enabled in the kernel, the value -%ENODEV will be | ||
607 | * returned. It is not wise to check for this value, but rather, check for | ||
608 | * %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling | ||
609 | * code. | ||
610 | */ | ||
611 | struct dentry *debugfs_create_regset32(const char *name, mode_t mode, | ||
612 | struct dentry *parent, | ||
613 | struct debugfs_regset32 *regset) | ||
614 | { | ||
615 | return debugfs_create_file(name, mode, parent, regset, &fops_regset32); | ||
616 | } | ||
617 | EXPORT_SYMBOL_GPL(debugfs_create_regset32); | ||
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h index e7d9b20ddc5b..5e6b01f6db4c 100644 --- a/include/linux/debugfs.h +++ b/include/linux/debugfs.h | |||
@@ -16,6 +16,7 @@ | |||
16 | #define _DEBUGFS_H_ | 16 | #define _DEBUGFS_H_ |
17 | 17 | ||
18 | #include <linux/fs.h> | 18 | #include <linux/fs.h> |
19 | #include <linux/seq_file.h> | ||
19 | 20 | ||
20 | #include <linux/types.h> | 21 | #include <linux/types.h> |
21 | 22 | ||
@@ -26,6 +27,17 @@ struct debugfs_blob_wrapper { | |||
26 | unsigned long size; | 27 | unsigned long size; |
27 | }; | 28 | }; |
28 | 29 | ||
30 | struct debugfs_reg32 { | ||
31 | char *name; | ||
32 | unsigned long offset; | ||
33 | }; | ||
34 | |||
35 | struct debugfs_regset32 { | ||
36 | struct debugfs_reg32 *regs; | ||
37 | int nregs; | ||
38 | void __iomem *base; | ||
39 | }; | ||
40 | |||
29 | extern struct dentry *arch_debugfs_dir; | 41 | extern struct dentry *arch_debugfs_dir; |
30 | 42 | ||
31 | #if defined(CONFIG_DEBUG_FS) | 43 | #if defined(CONFIG_DEBUG_FS) |
@@ -74,6 +86,13 @@ struct dentry *debugfs_create_blob(const char *name, mode_t mode, | |||
74 | struct dentry *parent, | 86 | struct dentry *parent, |
75 | struct debugfs_blob_wrapper *blob); | 87 | struct debugfs_blob_wrapper *blob); |
76 | 88 | ||
89 | struct dentry *debugfs_create_regset32(const char *name, mode_t mode, | ||
90 | struct dentry *parent, | ||
91 | struct debugfs_regset32 *regset); | ||
92 | |||
93 | int debugfs_print_regs32(struct seq_file *s, struct debugfs_reg32 *regs, | ||
94 | int nregs, void __iomem *base, char *prefix); | ||
95 | |||
77 | bool debugfs_initialized(void); | 96 | bool debugfs_initialized(void); |
78 | 97 | ||
79 | #else | 98 | #else |
@@ -188,6 +207,13 @@ static inline struct dentry *debugfs_create_blob(const char *name, mode_t mode, | |||
188 | return ERR_PTR(-ENODEV); | 207 | return ERR_PTR(-ENODEV); |
189 | } | 208 | } |
190 | 209 | ||
210 | static inline struct dentry *debugfs_create_regset32(const char *name, | ||
211 | mode_t mode, struct dentry *parent, | ||
212 | struct debugfs_regset32 *regset) | ||
213 | { | ||
214 | return ERR_PTR(-ENODEV); | ||
215 | } | ||
216 | |||
191 | static inline bool debugfs_initialized(void) | 217 | static inline bool debugfs_initialized(void) |
192 | { | 218 | { |
193 | return false; | 219 | return false; |