
Instead of keeping the documentation inside s390dbf.rst, move them to arch/s390/include/asm/debug.h, using standard kernel-doc markups. Keeping the documentation close to the code helps to keep it updated. It also makes easier to document other stuff inside debug.h, as all it needs is to add kernel-doc markups inside it, as the file will be already be included at the produced documentation. - Those were converted to kerneldoc using this script specially designed to parse ths file, and manually editted: <script> use strict; my $mode = ""; my $parameter = ""; my $ret = ""; my $descr = ""; sub add_var($) { my $ln = shift; $ln =~ s/^\s+//; $ln =~ s/\s+$//; return if ($ln eq ""); $ln =~ s/^(\S+)\s+/$1\t/; print " * \@$ln\n"; } sub add_return($) { my $ln = shift; print " *\n * Return:\n" if ($mode ne "Return Value:"); $ln =~ s/^\s+//; $ln =~ s/\s+$//; return if ($ln eq ""); print " * - $ln\n"; } sub add_description($) { my $ln = shift; print " *\n * \n" if ($mode ne "Description:"); $ln =~ s/^\s+//; $ln =~ s/\s+$//; return if ($ln eq ""); print " * $ln\n"; } sub flush_results() { print " */\n\n"; } while (<>) { if (m/^[\-]+$/) { flush_results(); $mode = ""; $parameter = ""; $ret = ""; $descr = ""; next; } if (m/(Parameter:)(.*)/) { print " *\n" if ($mode eq "func"); add_var($2); $mode = $1; next; } if (m/(Return Value:)(.*)/) { add_return($2); $mode = $1; next; } if (m/(Description:)(.*)/) { add_description($2); $mode = $1; next; } if ($mode eq "Parameter:") { add_var($_); next; } if ($mode eq "Return Value:") { add_return($_); next; } if ($mode eq "Description:") { add_description($_); next; } next if (m/^\s*$/); if (m/^\S+.*\s\*?(\S+)\s*\(/) { if ($mode eq "") { print "/**\n * $1()\n"; } else { print " * $1()\n"; } $mode="func"; } } flush_results(); </script> Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
502 lines
14 KiB
C
502 lines
14 KiB
C
/* SPDX-License-Identifier: GPL-2.0 */
|
|
/*
|
|
* S/390 debug facility
|
|
*
|
|
* Copyright IBM Corp. 1999, 2000
|
|
*/
|
|
#ifndef DEBUG_H
|
|
#define DEBUG_H
|
|
|
|
#include <linux/string.h>
|
|
#include <linux/spinlock.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/time.h>
|
|
#include <linux/refcount.h>
|
|
#include <uapi/asm/debug.h>
|
|
|
|
#define DEBUG_MAX_LEVEL 6 /* debug levels range from 0 to 6 */
|
|
#define DEBUG_OFF_LEVEL -1 /* level where debug is switched off */
|
|
#define DEBUG_FLUSH_ALL -1 /* parameter to flush all areas */
|
|
#define DEBUG_MAX_VIEWS 10 /* max number of views in proc fs */
|
|
#define DEBUG_MAX_NAME_LEN 64 /* max length for a debugfs file name */
|
|
#define DEBUG_DEFAULT_LEVEL 3 /* initial debug level */
|
|
|
|
#define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */
|
|
|
|
#define DEBUG_DATA(entry) (char *)(entry + 1) /* data is stored behind */
|
|
/* the entry information */
|
|
|
|
typedef struct __debug_entry debug_entry_t;
|
|
|
|
struct debug_view;
|
|
|
|
typedef struct debug_info {
|
|
struct debug_info *next;
|
|
struct debug_info *prev;
|
|
refcount_t ref_count;
|
|
spinlock_t lock;
|
|
int level;
|
|
int nr_areas;
|
|
int pages_per_area;
|
|
int buf_size;
|
|
int entry_size;
|
|
debug_entry_t ***areas;
|
|
int active_area;
|
|
int *active_pages;
|
|
int *active_entries;
|
|
struct dentry *debugfs_root_entry;
|
|
struct dentry *debugfs_entries[DEBUG_MAX_VIEWS];
|
|
struct debug_view *views[DEBUG_MAX_VIEWS];
|
|
char name[DEBUG_MAX_NAME_LEN];
|
|
umode_t mode;
|
|
} debug_info_t;
|
|
|
|
typedef int (debug_header_proc_t) (debug_info_t *id,
|
|
struct debug_view *view,
|
|
int area,
|
|
debug_entry_t *entry,
|
|
char *out_buf);
|
|
|
|
typedef int (debug_format_proc_t) (debug_info_t *id,
|
|
struct debug_view *view, char *out_buf,
|
|
const char *in_buf);
|
|
typedef int (debug_prolog_proc_t) (debug_info_t *id,
|
|
struct debug_view *view,
|
|
char *out_buf);
|
|
typedef int (debug_input_proc_t) (debug_info_t *id,
|
|
struct debug_view *view,
|
|
struct file *file,
|
|
const char __user *user_buf,
|
|
size_t in_buf_size, loff_t *offset);
|
|
|
|
int debug_dflt_header_fn(debug_info_t *id, struct debug_view *view,
|
|
int area, debug_entry_t *entry, char *out_buf);
|
|
|
|
struct debug_view {
|
|
char name[DEBUG_MAX_NAME_LEN];
|
|
debug_prolog_proc_t *prolog_proc;
|
|
debug_header_proc_t *header_proc;
|
|
debug_format_proc_t *format_proc;
|
|
debug_input_proc_t *input_proc;
|
|
void *private_data;
|
|
};
|
|
|
|
extern struct debug_view debug_hex_ascii_view;
|
|
extern struct debug_view debug_raw_view;
|
|
extern struct debug_view debug_sprintf_view;
|
|
|
|
/* do NOT use the _common functions */
|
|
|
|
debug_entry_t *debug_event_common(debug_info_t *id, int level,
|
|
const void *data, int length);
|
|
|
|
debug_entry_t *debug_exception_common(debug_info_t *id, int level,
|
|
const void *data, int length);
|
|
|
|
/* Debug Feature API: */
|
|
|
|
/**
|
|
* debug_register() - allocates memory for a debug log.
|
|
*
|
|
* @name: Name of debug log (e.g. used for debugfs entry)
|
|
* @pages: Number of pages, which will be allocated per area
|
|
* @nr_areas: Number of debug areas
|
|
* @buf_size: Size of data area in each debug entry
|
|
*
|
|
* Return:
|
|
* - Handler for generated debug area
|
|
* - %NULL if register failed
|
|
*
|
|
* Must not be called within an interrupt handler.
|
|
*/
|
|
debug_info_t *debug_register(const char *name, int pages, int nr_areas,
|
|
int buf_size);
|
|
|
|
/**
|
|
* debug_register_mode() - allocates memory for a debug log.
|
|
*
|
|
* @name: Name of debug log (e.g. used for debugfs entry)
|
|
* @pages: Number of pages, which will be allocated per area
|
|
* @nr_areas: Number of debug areas
|
|
* @buf_size: Size of data area in each debug entry
|
|
* @mode: File mode for debugfs files. E.g. S_IRWXUGO
|
|
* @uid: User ID for debugfs files. Currently only 0 is supported.
|
|
* @gid: Group ID for debugfs files. Currently only 0 is supported.
|
|
*
|
|
* Return:
|
|
* - Handler for generated debug area
|
|
* - %NULL if register failed
|
|
*
|
|
* Must not be called within an interrupt handler
|
|
*/
|
|
debug_info_t *debug_register_mode(const char *name, int pages, int nr_areas,
|
|
int buf_size, umode_t mode, uid_t uid,
|
|
gid_t gid);
|
|
|
|
/**
|
|
* debug_unregister() - frees memory for a debug log and removes all
|
|
* registered debug
|
|
* views.
|
|
*
|
|
* @id: handle for debug log
|
|
*
|
|
* Return:
|
|
* none
|
|
*
|
|
* Must not be called within an interrupt handler
|
|
*/
|
|
void debug_unregister(debug_info_t *id);
|
|
|
|
/**
|
|
* debug_set_level() - Sets new actual debug level if new_level is valid.
|
|
*
|
|
* @id: handle for debug log
|
|
* @new_level: new debug level
|
|
*
|
|
* Return:
|
|
* none
|
|
*/
|
|
void debug_set_level(debug_info_t *id, int new_level);
|
|
|
|
void debug_set_critical(void);
|
|
|
|
/**
|
|
* debug_stop_all() - stops the debug feature if stopping is allowed.
|
|
*
|
|
* Return:
|
|
* - none
|
|
*/
|
|
void debug_stop_all(void);
|
|
|
|
/**
|
|
* debug_level_enabled() - Returns true if debug events for the specified
|
|
* level would be logged. Otherwise returns false.
|
|
*
|
|
* @id: handle for debug log
|
|
* @level: debug level
|
|
*
|
|
* Return:
|
|
* - %true if level is less or equal to the current debug level.
|
|
*/
|
|
static inline bool debug_level_enabled(debug_info_t *id, int level)
|
|
{
|
|
return level <= id->level;
|
|
}
|
|
|
|
/**
|
|
* debug_event() - writes debug entry to active debug area
|
|
* (if level <= actual debug level)
|
|
*
|
|
* @id: handle for debug log
|
|
* @level: debug level
|
|
* @data: pointer to data for debug entry
|
|
* @length: length of data in bytes
|
|
*
|
|
* Return:
|
|
* - Address of written debug entry
|
|
*/
|
|
static inline debug_entry_t *debug_event(debug_info_t *id, int level,
|
|
void *data, int length)
|
|
{
|
|
if ((!id) || (level > id->level) || (id->pages_per_area == 0))
|
|
return NULL;
|
|
return debug_event_common(id, level, data, length);
|
|
}
|
|
|
|
/**
|
|
* debug_int_event() - writes debug entry to active debug area
|
|
* (if level <= actual debug level)
|
|
*
|
|
* @id: handle for debug log
|
|
* @level: debug level
|
|
* @tag: integer value for debug entry
|
|
*
|
|
* Return:
|
|
* - Address of written debug entry
|
|
* - %NULL if error
|
|
*/
|
|
static inline debug_entry_t *debug_int_event(debug_info_t *id, int level,
|
|
unsigned int tag)
|
|
{
|
|
unsigned int t = tag;
|
|
|
|
if ((!id) || (level > id->level) || (id->pages_per_area == 0))
|
|
return NULL;
|
|
return debug_event_common(id, level, &t, sizeof(unsigned int));
|
|
}
|
|
|
|
/**
|
|
* debug_long_event() - writes debug entry to active debug area
|
|
* (if level <= actual debug level)
|
|
*
|
|
* @id: handle for debug log
|
|
* @level: debug level
|
|
* @tag: integer value for debug entry
|
|
*
|
|
* Return:
|
|
* - Address of written debug entry
|
|
* - %NULL if error
|
|
*/
|
|
static inline debug_entry_t *debug_long_event(debug_info_t *id, int level,
|
|
unsigned long tag)
|
|
{
|
|
unsigned long t = tag;
|
|
|
|
if ((!id) || (level > id->level) || (id->pages_per_area == 0))
|
|
return NULL;
|
|
return debug_event_common(id, level, &t, sizeof(unsigned long));
|
|
}
|
|
|
|
/**
|
|
* debug_text_event() - writes debug entry in ascii format to active
|
|
* debug area (if level <= actual debug level)
|
|
*
|
|
* @id: handle for debug log
|
|
* @level: debug level
|
|
* @txt: string for debug entry
|
|
*
|
|
* Return:
|
|
* - Address of written debug entry
|
|
* - %NULL if error
|
|
*/
|
|
static inline debug_entry_t *debug_text_event(debug_info_t *id, int level,
|
|
const char *txt)
|
|
{
|
|
if ((!id) || (level > id->level) || (id->pages_per_area == 0))
|
|
return NULL;
|
|
return debug_event_common(id, level, txt, strlen(txt));
|
|
}
|
|
|
|
/*
|
|
* IMPORTANT: Use "%s" in sprintf format strings with care! Only pointers are
|
|
* stored in the s390dbf. See Documentation/s390/s390dbf.rst for more details!
|
|
*/
|
|
extern debug_entry_t *
|
|
__debug_sprintf_event(debug_info_t *id, int level, char *string, ...)
|
|
__attribute__ ((format(printf, 3, 4)));
|
|
|
|
/**
|
|
* debug_sprintf_event() - writes debug entry with format string
|
|
* and varargs (longs) to active debug area
|
|
* (if level $<=$ actual debug level).
|
|
*
|
|
* @_id: handle for debug log
|
|
* @_level: debug level
|
|
* @_fmt: format string for debug entry
|
|
* @...: varargs used as in sprintf()
|
|
*
|
|
* Return:
|
|
* - Address of written debug entry
|
|
* - %NULL if error
|
|
*
|
|
* floats and long long datatypes cannot be used as varargs.
|
|
*/
|
|
#define debug_sprintf_event(_id, _level, _fmt, ...) \
|
|
({ \
|
|
debug_entry_t *__ret; \
|
|
debug_info_t *__id = _id; \
|
|
int __level = _level; \
|
|
\
|
|
if ((!__id) || (__level > __id->level)) \
|
|
__ret = NULL; \
|
|
else \
|
|
__ret = __debug_sprintf_event(__id, __level, \
|
|
_fmt, ## __VA_ARGS__); \
|
|
__ret; \
|
|
})
|
|
|
|
/**
|
|
* debug_exception() - writes debug entry to active debug area
|
|
* (if level <= actual debug level) and switches
|
|
* to next debug area
|
|
*
|
|
* @id: handle for debug log
|
|
* @level: debug level
|
|
* @data: pointer to data for debug entry
|
|
* @length: length of data in bytes
|
|
*
|
|
* Return:
|
|
* - Address of written debug entry
|
|
* - %NULL if error
|
|
*/
|
|
static inline debug_entry_t *debug_exception(debug_info_t *id, int level,
|
|
void *data, int length)
|
|
{
|
|
if ((!id) || (level > id->level) || (id->pages_per_area == 0))
|
|
return NULL;
|
|
return debug_exception_common(id, level, data, length);
|
|
}
|
|
|
|
/**
|
|
* debug_int_exception() - writes debug entry to active debug area
|
|
* (if level <= actual debug level)
|
|
* and switches to next debug area
|
|
*
|
|
* @id: handle for debug log
|
|
* @level: debug level
|
|
* @tag: integer value for debug entry
|
|
*
|
|
* Return:
|
|
* - Address of written debug entry
|
|
* - %NULL if error
|
|
*/
|
|
static inline debug_entry_t *debug_int_exception(debug_info_t *id, int level,
|
|
unsigned int tag)
|
|
{
|
|
unsigned int t = tag;
|
|
|
|
if ((!id) || (level > id->level) || (id->pages_per_area == 0))
|
|
return NULL;
|
|
return debug_exception_common(id, level, &t, sizeof(unsigned int));
|
|
}
|
|
|
|
/**
|
|
* debug_long_exception() - writes debug entry to active debug area
|
|
* (if level <= actual debug level)
|
|
* and switches to next debug area
|
|
*
|
|
* @id: handle for debug log
|
|
* @level: debug level
|
|
* @tag: integer value for debug entry
|
|
*
|
|
* Return:
|
|
* - Address of written debug entry
|
|
* - %NULL if error
|
|
*/
|
|
static inline debug_entry_t *debug_long_exception (debug_info_t *id, int level,
|
|
unsigned long tag)
|
|
{
|
|
unsigned long t = tag;
|
|
|
|
if ((!id) || (level > id->level) || (id->pages_per_area == 0))
|
|
return NULL;
|
|
return debug_exception_common(id, level, &t, sizeof(unsigned long));
|
|
}
|
|
|
|
/**
|
|
* debug_text_exception() - writes debug entry in ascii format to active
|
|
* debug area (if level <= actual debug level)
|
|
* and switches to next debug
|
|
* area
|
|
*
|
|
* @id: handle for debug log
|
|
* @level: debug level
|
|
* @txt: string for debug entry
|
|
*
|
|
* Return:
|
|
* - Address of written debug entry
|
|
* - %NULL if error
|
|
*/
|
|
static inline debug_entry_t *debug_text_exception(debug_info_t *id, int level,
|
|
const char *txt)
|
|
{
|
|
if ((!id) || (level > id->level) || (id->pages_per_area == 0))
|
|
return NULL;
|
|
return debug_exception_common(id, level, txt, strlen(txt));
|
|
}
|
|
|
|
/*
|
|
* IMPORTANT: Use "%s" in sprintf format strings with care! Only pointers are
|
|
* stored in the s390dbf. See Documentation/s390/s390dbf.rst for more details!
|
|
*/
|
|
extern debug_entry_t *
|
|
__debug_sprintf_exception(debug_info_t *id, int level, char *string, ...)
|
|
__attribute__ ((format(printf, 3, 4)));
|
|
|
|
|
|
/**
|
|
* debug_sprintf_exception() - writes debug entry with format string and
|
|
* varargs (longs) to active debug area
|
|
* (if level $<=$ actual debug level)
|
|
* and switches to next debug area.
|
|
*
|
|
* @_id: handle for debug log
|
|
* @_level: debug level
|
|
* @_fmt: format string for debug entry
|
|
* @...: varargs used as in sprintf()
|
|
*
|
|
* Return:
|
|
* - Address of written debug entry
|
|
* - %NULL if error
|
|
*
|
|
* floats and long long datatypes cannot be used as varargs.
|
|
*/
|
|
#define debug_sprintf_exception(_id, _level, _fmt, ...) \
|
|
({ \
|
|
debug_entry_t *__ret; \
|
|
debug_info_t *__id = _id; \
|
|
int __level = _level; \
|
|
\
|
|
if ((!__id) || (__level > __id->level)) \
|
|
__ret = NULL; \
|
|
else \
|
|
__ret = __debug_sprintf_exception(__id, __level, \
|
|
_fmt, ## __VA_ARGS__);\
|
|
__ret; \
|
|
})
|
|
|
|
/**
|
|
* debug_register_view() - registers new debug view and creates debugfs
|
|
* dir entry
|
|
*
|
|
* @id: handle for debug log
|
|
* @view: pointer to debug view struct
|
|
*
|
|
* Return:
|
|
* - 0 : ok
|
|
* - < 0: Error
|
|
*/
|
|
int debug_register_view(debug_info_t *id, struct debug_view *view);
|
|
|
|
/**
|
|
* debug_unregister_view()
|
|
*
|
|
* @id: handle for debug log
|
|
* @view: pointer to debug view struct
|
|
*
|
|
* Return:
|
|
* - 0 : ok
|
|
* - < 0: Error
|
|
*
|
|
*
|
|
* unregisters debug view and removes debugfs dir entry
|
|
*/
|
|
|
|
int debug_unregister_view(debug_info_t *id, struct debug_view *view);
|
|
|
|
/*
|
|
define the debug levels:
|
|
- 0 No debugging output to console or syslog
|
|
- 1 Log internal errors to syslog, ignore check conditions
|
|
- 2 Log internal errors and check conditions to syslog
|
|
- 3 Log internal errors to console, log check conditions to syslog
|
|
- 4 Log internal errors and check conditions to console
|
|
- 5 panic on internal errors, log check conditions to console
|
|
- 6 panic on both, internal errors and check conditions
|
|
*/
|
|
|
|
#ifndef DEBUG_LEVEL
|
|
#define DEBUG_LEVEL 4
|
|
#endif
|
|
|
|
#define INTERNAL_ERRMSG(x,y...) "E" __FILE__ "%d: " x, __LINE__, y
|
|
#define INTERNAL_WRNMSG(x,y...) "W" __FILE__ "%d: " x, __LINE__, y
|
|
#define INTERNAL_INFMSG(x,y...) "I" __FILE__ "%d: " x, __LINE__, y
|
|
#define INTERNAL_DEBMSG(x,y...) "D" __FILE__ "%d: " x, __LINE__, y
|
|
|
|
#if DEBUG_LEVEL > 0
|
|
#define PRINT_DEBUG(x...) printk(KERN_DEBUG PRINTK_HEADER x)
|
|
#define PRINT_INFO(x...) printk(KERN_INFO PRINTK_HEADER x)
|
|
#define PRINT_WARN(x...) printk(KERN_WARNING PRINTK_HEADER x)
|
|
#define PRINT_ERR(x...) printk(KERN_ERR PRINTK_HEADER x)
|
|
#define PRINT_FATAL(x...) panic(PRINTK_HEADER x)
|
|
#else
|
|
#define PRINT_DEBUG(x...) printk(KERN_DEBUG PRINTK_HEADER x)
|
|
#define PRINT_INFO(x...) printk(KERN_DEBUG PRINTK_HEADER x)
|
|
#define PRINT_WARN(x...) printk(KERN_DEBUG PRINTK_HEADER x)
|
|
#define PRINT_ERR(x...) printk(KERN_DEBUG PRINTK_HEADER x)
|
|
#define PRINT_FATAL(x...) printk(KERN_DEBUG PRINTK_HEADER x)
|
|
#endif /* DASD_DEBUG */
|
|
|
|
#endif /* DEBUG_H */
|