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>
This commit is contained in:
parent
fe7484834b
commit
1a087c6ad9
|
@ -97,7 +97,8 @@ A read on the resulting file will yield either Y (for non-zero values) or
|
||||||
N, followed by a newline. If written to, it will accept either upper- or
|
N, followed by a newline. If written to, it will accept either upper- or
|
||||||
lower-case values, or 1 or 0. Any other input will be silently ignored.
|
lower-case values, or 1 or 0. Any other input will be silently ignored.
|
||||||
|
|
||||||
Finally, a block of arbitrary binary data can be exported with:
|
Another option is exporting a block of arbitrary binary data, with
|
||||||
|
this structure and function:
|
||||||
|
|
||||||
struct debugfs_blob_wrapper {
|
struct debugfs_blob_wrapper {
|
||||||
void *data;
|
void *data;
|
||||||
|
@ -115,6 +116,35 @@ can be used to export binary information, but there does not appear to be
|
||||||
any code which does so in the mainline. Note that all files created with
|
any code which does so in the mainline. Note that all files created with
|
||||||
debugfs_create_blob() are read-only.
|
debugfs_create_blob() are read-only.
|
||||||
|
|
||||||
|
If you want to dump a block of registers (something that happens quite
|
||||||
|
often during development, even if little such code reaches mainline.
|
||||||
|
Debugfs offers two functions: one to make a registers-only file, and
|
||||||
|
another to insert a register block in the middle of another sequential
|
||||||
|
file.
|
||||||
|
|
||||||
|
struct debugfs_reg32 {
|
||||||
|
char *name;
|
||||||
|
unsigned long offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct debugfs_regset32 {
|
||||||
|
struct debugfs_reg32 *regs;
|
||||||
|
int nregs;
|
||||||
|
void __iomem *base;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct dentry *debugfs_create_regset32(const char *name, mode_t mode,
|
||||||
|
struct dentry *parent,
|
||||||
|
struct debugfs_regset32 *regset);
|
||||||
|
|
||||||
|
int debugfs_print_regs32(struct seq_file *s, struct debugfs_reg32 *regs,
|
||||||
|
int nregs, void __iomem *base, char *prefix);
|
||||||
|
|
||||||
|
The "base" argument may be 0, but you may want to build the reg32 array
|
||||||
|
using __stringify, and a number of register names (macros) are actually
|
||||||
|
byte offsets over a base for the register block.
|
||||||
|
|
||||||
|
|
||||||
There are a couple of other directory-oriented helper functions:
|
There are a couple of other directory-oriented helper functions:
|
||||||
|
|
||||||
struct dentry *debugfs_rename(struct dentry *old_dir,
|
struct dentry *debugfs_rename(struct dentry *old_dir,
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
|
#include <linux/seq_file.h>
|
||||||
#include <linux/pagemap.h>
|
#include <linux/pagemap.h>
|
||||||
#include <linux/namei.h>
|
#include <linux/namei.h>
|
||||||
#include <linux/debugfs.h>
|
#include <linux/debugfs.h>
|
||||||
|
@ -525,3 +526,92 @@ struct dentry *debugfs_create_blob(const char *name, mode_t mode,
|
||||||
return debugfs_create_file(name, mode, parent, blob, &fops_blob);
|
return debugfs_create_file(name, mode, parent, blob, &fops_blob);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(debugfs_create_blob);
|
EXPORT_SYMBOL_GPL(debugfs_create_blob);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The regset32 stuff is used to print 32-bit registers using the
|
||||||
|
* seq_file utilities. We offer printing a register set in an already-opened
|
||||||
|
* sequential file or create a debugfs file that only prints a regset32.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* debugfs_print_regs32 - use seq_print to describe a set of registers
|
||||||
|
* @s: the seq_file structure being used to generate output
|
||||||
|
* @regs: an array if struct debugfs_reg32 structures
|
||||||
|
* @mregs: the length of the above array
|
||||||
|
* @base: the base address to be used in reading the registers
|
||||||
|
* @prefix: a string to be prefixed to every output line
|
||||||
|
*
|
||||||
|
* This function outputs a text block describing the current values of
|
||||||
|
* some 32-bit hardware registers. It is meant to be used within debugfs
|
||||||
|
* files based on seq_file that need to show registers, intermixed with other
|
||||||
|
* information. The prefix argument may be used to specify a leading string,
|
||||||
|
* because some peripherals have several blocks of identical registers,
|
||||||
|
* for example configuration of dma channels
|
||||||
|
*/
|
||||||
|
int debugfs_print_regs32(struct seq_file *s, struct debugfs_reg32 *regs,
|
||||||
|
int nregs, void __iomem *base, char *prefix)
|
||||||
|
{
|
||||||
|
int i, ret = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < nregs; i++, regs++) {
|
||||||
|
if (prefix)
|
||||||
|
ret += seq_printf(s, "%s", prefix);
|
||||||
|
ret += seq_printf(s, "%s = 0x%08x\n", regs->name,
|
||||||
|
readl((void *)(base + regs->offset)));
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(debugfs_print_regs32);
|
||||||
|
|
||||||
|
static int debugfs_show_regset32(struct seq_file *s, void *data)
|
||||||
|
{
|
||||||
|
struct debugfs_regset32 *regset = s->private;
|
||||||
|
|
||||||
|
debugfs_print_regs32(s, regset->regs, regset->nregs, regset->base, "");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int debugfs_open_regset32(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return single_open(file, debugfs_show_regset32, inode->i_private);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations fops_regset32 = {
|
||||||
|
.open = debugfs_open_regset32,
|
||||||
|
.read = seq_read,
|
||||||
|
.llseek = seq_lseek,
|
||||||
|
.release = single_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* debugfs_create_regset32 - create a debugfs file that returns register values
|
||||||
|
* @name: a pointer to a string containing the name of the file to create.
|
||||||
|
* @mode: the permission that the file should have
|
||||||
|
* @parent: a pointer to the parent dentry for this file. This should be a
|
||||||
|
* directory dentry if set. If this parameter is %NULL, then the
|
||||||
|
* file will be created in the root of the debugfs filesystem.
|
||||||
|
* @regset: a pointer to a struct debugfs_regset32, which contains a pointer
|
||||||
|
* to an array of register definitions, the array size and the base
|
||||||
|
* address where the register bank is to be found.
|
||||||
|
*
|
||||||
|
* This function creates a file in debugfs with the given name that reports
|
||||||
|
* the names and values of a set of 32-bit registers. If the @mode variable
|
||||||
|
* is so set it can be read from. Writing is not supported.
|
||||||
|
*
|
||||||
|
* This function will return a pointer to a dentry if it succeeds. This
|
||||||
|
* pointer must be passed to the debugfs_remove() function when the file is
|
||||||
|
* to be removed (no automatic cleanup happens if your module is unloaded,
|
||||||
|
* you are responsible here.) If an error occurs, %NULL will be returned.
|
||||||
|
*
|
||||||
|
* If debugfs is not enabled in the kernel, the value -%ENODEV will be
|
||||||
|
* returned. It is not wise to check for this value, but rather, check for
|
||||||
|
* %NULL or !%NULL instead as to eliminate the need for #ifdef in the calling
|
||||||
|
* code.
|
||||||
|
*/
|
||||||
|
struct dentry *debugfs_create_regset32(const char *name, mode_t mode,
|
||||||
|
struct dentry *parent,
|
||||||
|
struct debugfs_regset32 *regset)
|
||||||
|
{
|
||||||
|
return debugfs_create_file(name, mode, parent, regset, &fops_regset32);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(debugfs_create_regset32);
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#define _DEBUGFS_H_
|
#define _DEBUGFS_H_
|
||||||
|
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
|
#include <linux/seq_file.h>
|
||||||
|
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
@ -26,6 +27,17 @@ struct debugfs_blob_wrapper {
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct debugfs_reg32 {
|
||||||
|
char *name;
|
||||||
|
unsigned long offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct debugfs_regset32 {
|
||||||
|
struct debugfs_reg32 *regs;
|
||||||
|
int nregs;
|
||||||
|
void __iomem *base;
|
||||||
|
};
|
||||||
|
|
||||||
extern struct dentry *arch_debugfs_dir;
|
extern struct dentry *arch_debugfs_dir;
|
||||||
|
|
||||||
#if defined(CONFIG_DEBUG_FS)
|
#if defined(CONFIG_DEBUG_FS)
|
||||||
|
@ -74,6 +86,13 @@ struct dentry *debugfs_create_blob(const char *name, mode_t mode,
|
||||||
struct dentry *parent,
|
struct dentry *parent,
|
||||||
struct debugfs_blob_wrapper *blob);
|
struct debugfs_blob_wrapper *blob);
|
||||||
|
|
||||||
|
struct dentry *debugfs_create_regset32(const char *name, mode_t mode,
|
||||||
|
struct dentry *parent,
|
||||||
|
struct debugfs_regset32 *regset);
|
||||||
|
|
||||||
|
int debugfs_print_regs32(struct seq_file *s, struct debugfs_reg32 *regs,
|
||||||
|
int nregs, void __iomem *base, char *prefix);
|
||||||
|
|
||||||
bool debugfs_initialized(void);
|
bool debugfs_initialized(void);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -188,6 +207,13 @@ static inline struct dentry *debugfs_create_blob(const char *name, mode_t mode,
|
||||||
return ERR_PTR(-ENODEV);
|
return ERR_PTR(-ENODEV);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline struct dentry *debugfs_create_regset32(const char *name,
|
||||||
|
mode_t mode, struct dentry *parent,
|
||||||
|
struct debugfs_regset32 *regset)
|
||||||
|
{
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool debugfs_initialized(void)
|
static inline bool debugfs_initialized(void)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
Loading…
Reference in New Issue