diff options
Diffstat (limited to 'drivers/s390/cio/qdio_debug.c')
| -rw-r--r-- | drivers/s390/cio/qdio_debug.c | 79 | 
1 files changed, 72 insertions, 7 deletions
diff --git a/drivers/s390/cio/qdio_debug.c b/drivers/s390/cio/qdio_debug.c index 4221b02085a..f1f3baa8e6e 100644 --- a/drivers/s390/cio/qdio_debug.c +++ b/drivers/s390/cio/qdio_debug.c @@ -7,6 +7,7 @@  #include <linux/debugfs.h>  #include <linux/uaccess.h>  #include <linux/export.h> +#include <linux/slab.h>  #include <asm/debug.h>  #include "qdio_debug.h"  #include "qdio.h" @@ -16,11 +17,51 @@ debug_info_t *qdio_dbf_error;  static struct dentry *debugfs_root;  #define QDIO_DEBUGFS_NAME_LEN	10 +#define QDIO_DBF_NAME_LEN	20 -void qdio_allocate_dbf(struct qdio_initialize *init_data, +struct qdio_dbf_entry { +	char dbf_name[QDIO_DBF_NAME_LEN]; +	debug_info_t *dbf_info; +	struct list_head dbf_list; +}; + +static LIST_HEAD(qdio_dbf_list); +static DEFINE_MUTEX(qdio_dbf_list_mutex); + +static debug_info_t *qdio_get_dbf_entry(char *name) +{ +	struct qdio_dbf_entry *entry; +	debug_info_t *rc = NULL; + +	mutex_lock(&qdio_dbf_list_mutex); +	list_for_each_entry(entry, &qdio_dbf_list, dbf_list) { +		if (strcmp(entry->dbf_name, name) == 0) { +			rc = entry->dbf_info; +			break; +		} +	} +	mutex_unlock(&qdio_dbf_list_mutex); +	return rc; +} + +static void qdio_clear_dbf_list(void) +{ +	struct qdio_dbf_entry *entry, *tmp; + +	mutex_lock(&qdio_dbf_list_mutex); +	list_for_each_entry_safe(entry, tmp, &qdio_dbf_list, dbf_list) { +		list_del(&entry->dbf_list); +		debug_unregister(entry->dbf_info); +		kfree(entry); +	} +	mutex_unlock(&qdio_dbf_list_mutex); +} + +int qdio_allocate_dbf(struct qdio_initialize *init_data,  		       struct qdio_irq *irq_ptr)  { -	char text[20]; +	char text[QDIO_DBF_NAME_LEN]; +	struct qdio_dbf_entry *new_entry;  	DBF_EVENT("qfmt:%1d", init_data->q_format);  	DBF_HEX(init_data->adapter_name, 8); @@ -38,11 +79,34 @@ void qdio_allocate_dbf(struct qdio_initialize *init_data,  	DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);  	/* allocate trace view for the interface */ -	snprintf(text, 20, "qdio_%s", dev_name(&init_data->cdev->dev)); -	irq_ptr->debug_area = debug_register(text, 2, 1, 16); -	debug_register_view(irq_ptr->debug_area, &debug_hex_ascii_view); -	debug_set_level(irq_ptr->debug_area, DBF_WARN); -	DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created"); +	snprintf(text, QDIO_DBF_NAME_LEN, "qdio_%s", +					dev_name(&init_data->cdev->dev)); +	irq_ptr->debug_area = qdio_get_dbf_entry(text); +	if (irq_ptr->debug_area) +		DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf reused"); +	else { +		irq_ptr->debug_area = debug_register(text, 2, 1, 16); +		if (!irq_ptr->debug_area) +			return -ENOMEM; +		if (debug_register_view(irq_ptr->debug_area, +						&debug_hex_ascii_view)) { +			debug_unregister(irq_ptr->debug_area); +			return -ENOMEM; +		} +		debug_set_level(irq_ptr->debug_area, DBF_WARN); +		DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created"); +		new_entry = kzalloc(sizeof(struct qdio_dbf_entry), GFP_KERNEL); +		if (!new_entry) { +			debug_unregister(irq_ptr->debug_area); +			return -ENOMEM; +		} +		strlcpy(new_entry->dbf_name, text, QDIO_DBF_NAME_LEN); +		new_entry->dbf_info = irq_ptr->debug_area; +		mutex_lock(&qdio_dbf_list_mutex); +		list_add(&new_entry->dbf_list, &qdio_dbf_list); +		mutex_unlock(&qdio_dbf_list_mutex); +	} +	return 0;  }  static int qstat_show(struct seq_file *m, void *v) @@ -300,6 +364,7 @@ int __init qdio_debug_init(void)  void qdio_debug_exit(void)  { +	qdio_clear_dbf_list();  	debugfs_remove(debugfs_root);  	if (qdio_dbf_setup)  		debug_unregister(qdio_dbf_setup);  | 
