s390/debug: add early tracing support
Debug areas can currently only be used after s390dbf initialization which occurs as a postcore_initcall. This is too late for tracing earlier code such as that related to console_init(). This patch introduces a macro for defining a statically initialized debug area that can be used to trace very early code. The macro is made available for built-in code only because modules are never running during early boot. Example usage: 1. Define static debug area: DEFINE_STATIC_DEBUG_INFO(my_debug, "my_debug", 4, 1, 16, &debug_hex_ascii_view); 2. Add trace entry: debug_event(&my_debug, 0, "DATA", 4); Note: The debug area is automatically registered in debugfs during boot. A driver must not call any of the debug_register()/_unregister() functions on a static debug_info_t! Signed-off-by: Peter Oberparleiter <oberpar@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
This commit is contained in:
parent
9372a82892
commit
d72541f945
@ -13,6 +13,7 @@
|
||||
#include <linux/time.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/init.h>
|
||||
|
||||
#define DEBUG_MAX_LEVEL 6 /* debug levels range from 0 to 6 */
|
||||
#define DEBUG_OFF_LEVEL -1 /* level where debug is switched off */
|
||||
@ -391,4 +392,99 @@ int debug_register_view(debug_info_t *id, struct debug_view *view);
|
||||
|
||||
int debug_unregister_view(debug_info_t *id, struct debug_view *view);
|
||||
|
||||
#ifndef MODULE
|
||||
|
||||
/*
|
||||
* Note: Initial page and area numbers must be fixed to allow static
|
||||
* initialization. This enables very early tracing. Changes to these values
|
||||
* must be reflected in __DEFINE_STATIC_AREA.
|
||||
*/
|
||||
#define EARLY_PAGES 8
|
||||
#define EARLY_AREAS 1
|
||||
|
||||
#define VNAME(var, suffix) __##var##_##suffix
|
||||
|
||||
/*
|
||||
* Define static areas for early trace data. During boot debug_register_static()
|
||||
* will replace these with dynamically allocated areas to allow custom page and
|
||||
* area sizes, and dynamic resizing.
|
||||
*/
|
||||
#define __DEFINE_STATIC_AREA(var) \
|
||||
static char VNAME(var, data)[EARLY_PAGES][PAGE_SIZE] __initdata; \
|
||||
static debug_entry_t *VNAME(var, pages)[EARLY_PAGES] __initdata = { \
|
||||
(debug_entry_t *)VNAME(var, data)[0], \
|
||||
(debug_entry_t *)VNAME(var, data)[1], \
|
||||
(debug_entry_t *)VNAME(var, data)[2], \
|
||||
(debug_entry_t *)VNAME(var, data)[3], \
|
||||
(debug_entry_t *)VNAME(var, data)[4], \
|
||||
(debug_entry_t *)VNAME(var, data)[5], \
|
||||
(debug_entry_t *)VNAME(var, data)[6], \
|
||||
(debug_entry_t *)VNAME(var, data)[7], \
|
||||
}; \
|
||||
static debug_entry_t **VNAME(var, areas)[EARLY_AREAS] __initdata = { \
|
||||
(debug_entry_t **)VNAME(var, pages), \
|
||||
}; \
|
||||
static int VNAME(var, active_pages)[EARLY_AREAS] __initdata; \
|
||||
static int VNAME(var, active_entries)[EARLY_AREAS] __initdata
|
||||
|
||||
#define __DEBUG_INFO_INIT(var, _name, _buf_size) { \
|
||||
.next = NULL, \
|
||||
.prev = NULL, \
|
||||
.ref_count = REFCOUNT_INIT(1), \
|
||||
.lock = __SPIN_LOCK_UNLOCKED(var.lock), \
|
||||
.level = DEBUG_DEFAULT_LEVEL, \
|
||||
.nr_areas = EARLY_AREAS, \
|
||||
.pages_per_area = EARLY_PAGES, \
|
||||
.buf_size = (_buf_size), \
|
||||
.entry_size = sizeof(debug_entry_t) + (_buf_size), \
|
||||
.areas = VNAME(var, areas), \
|
||||
.active_area = 0, \
|
||||
.active_pages = VNAME(var, active_pages), \
|
||||
.active_entries = VNAME(var, active_entries), \
|
||||
.debugfs_root_entry = NULL, \
|
||||
.debugfs_entries = { NULL }, \
|
||||
.views = { NULL }, \
|
||||
.name = (_name), \
|
||||
.mode = 0600, \
|
||||
}
|
||||
|
||||
#define __REGISTER_STATIC_DEBUG_INFO(var, name, pages, areas, view) \
|
||||
static int __init VNAME(var, reg)(void) \
|
||||
{ \
|
||||
debug_register_static(&var, (pages), (areas)); \
|
||||
debug_register_view(&var, (view)); \
|
||||
return 0; \
|
||||
} \
|
||||
arch_initcall(VNAME(var, reg))
|
||||
|
||||
/**
|
||||
* DEFINE_STATIC_DEBUG_INFO - Define static debug_info_t
|
||||
*
|
||||
* @var: Name of debug_info_t variable
|
||||
* @name: Name of debug log (e.g. used for debugfs entry)
|
||||
* @pages_per_area: Number of pages per area
|
||||
* @nr_areas: Number of debug areas
|
||||
* @buf_size: Size of data area in each debug entry
|
||||
* @view: Pointer to debug view struct
|
||||
*
|
||||
* Define a static debug_info_t for early tracing. The associated debugfs log
|
||||
* is automatically registered with the specified debug view.
|
||||
*
|
||||
* Important: Users of this macro must not call any of the
|
||||
* debug_register/_unregister() functions for this debug_info_t!
|
||||
*
|
||||
* Note: Tracing will start with a fixed number of initial pages and areas.
|
||||
* The debug area will be changed to use the specified numbers during
|
||||
* arch_initcall.
|
||||
*/
|
||||
#define DEFINE_STATIC_DEBUG_INFO(var, name, pages, nr_areas, buf_size, view) \
|
||||
__DEFINE_STATIC_AREA(var); \
|
||||
static debug_info_t __refdata var = \
|
||||
__DEBUG_INFO_INIT(var, (name), (buf_size)); \
|
||||
__REGISTER_STATIC_DEBUG_INFO(var, name, pages, nr_areas, view)
|
||||
|
||||
void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas);
|
||||
|
||||
#endif /* MODULE */
|
||||
|
||||
#endif /* DEBUG_H */
|
||||
|
@ -692,6 +692,61 @@ debug_info_t *debug_register(const char *name, int pages_per_area,
|
||||
}
|
||||
EXPORT_SYMBOL(debug_register);
|
||||
|
||||
/**
|
||||
* debug_register_static() - registers a static debug area
|
||||
*
|
||||
* @id: Handle for static debug area
|
||||
* @pages_per_area: Number of pages per area
|
||||
* @nr_areas: Number of debug areas
|
||||
*
|
||||
* Register debug_info_t defined using DEFINE_STATIC_DEBUG_INFO.
|
||||
*
|
||||
* Note: This function is called automatically via an initcall generated by
|
||||
* DEFINE_STATIC_DEBUG_INFO.
|
||||
*/
|
||||
void debug_register_static(debug_info_t *id, int pages_per_area, int nr_areas)
|
||||
{
|
||||
unsigned long flags;
|
||||
debug_info_t *copy;
|
||||
|
||||
if (!initialized) {
|
||||
pr_err("Tried to register debug feature %s too early\n",
|
||||
id->name);
|
||||
return;
|
||||
}
|
||||
|
||||
copy = debug_info_alloc("", pages_per_area, nr_areas, id->buf_size,
|
||||
id->level, ALL_AREAS);
|
||||
if (!copy) {
|
||||
pr_err("Registering debug feature %s failed\n", id->name);
|
||||
|
||||
/* Clear pointers to prevent tracing into released initdata. */
|
||||
spin_lock_irqsave(&id->lock, flags);
|
||||
id->areas = NULL;
|
||||
id->active_pages = NULL;
|
||||
id->active_entries = NULL;
|
||||
spin_unlock_irqrestore(&id->lock, flags);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Replace static trace area with dynamic copy. */
|
||||
spin_lock_irqsave(&id->lock, flags);
|
||||
debug_events_append(copy, id);
|
||||
debug_areas_swap(id, copy);
|
||||
spin_unlock_irqrestore(&id->lock, flags);
|
||||
|
||||
/* Clear pointers to initdata and discard copy. */
|
||||
copy->areas = NULL;
|
||||
copy->active_pages = NULL;
|
||||
copy->active_entries = NULL;
|
||||
debug_info_free(copy);
|
||||
|
||||
mutex_lock(&debug_mutex);
|
||||
_debug_register(id);
|
||||
mutex_unlock(&debug_mutex);
|
||||
}
|
||||
|
||||
/* Remove debugfs entries and remove from internal list. */
|
||||
static void _debug_unregister(debug_info_t *id)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user