qdio_debug.c revision 2c78091405d6f54748b1fac78c45f2a799e3073a
1/* 2 * drivers/s390/cio/qdio_debug.c 3 * 4 * Copyright IBM Corp. 2008 5 * 6 * Author: Jan Glauber (jang@linux.vnet.ibm.com) 7 */ 8#include <linux/proc_fs.h> 9#include <linux/seq_file.h> 10#include <linux/debugfs.h> 11#include <asm/qdio.h> 12#include <asm/debug.h> 13#include "qdio_debug.h" 14#include "qdio.h" 15 16debug_info_t *qdio_dbf_setup; 17debug_info_t *qdio_dbf_trace; 18 19static struct dentry *debugfs_root; 20#define MAX_DEBUGFS_QUEUES 32 21static struct dentry *debugfs_queues[MAX_DEBUGFS_QUEUES] = { NULL }; 22static DEFINE_MUTEX(debugfs_mutex); 23#define QDIO_DEBUGFS_NAME_LEN 40 24 25void qdio_allocate_do_dbf(struct qdio_initialize *init_data) 26{ 27 char dbf_text[20]; 28 29 sprintf(dbf_text, "qfmt:%x", init_data->q_format); 30 QDIO_DBF_TEXT0(0, setup, dbf_text); 31 QDIO_DBF_HEX0(0, setup, init_data->adapter_name, 8); 32 sprintf(dbf_text, "qpff%4x", init_data->qib_param_field_format); 33 QDIO_DBF_TEXT0(0, setup, dbf_text); 34 QDIO_DBF_HEX0(0, setup, &init_data->qib_param_field, sizeof(void *)); 35 QDIO_DBF_HEX0(0, setup, &init_data->input_slib_elements, sizeof(void *)); 36 QDIO_DBF_HEX0(0, setup, &init_data->output_slib_elements, sizeof(void *)); 37 sprintf(dbf_text, "niq:%4x", init_data->no_input_qs); 38 QDIO_DBF_TEXT0(0, setup, dbf_text); 39 sprintf(dbf_text, "noq:%4x", init_data->no_output_qs); 40 QDIO_DBF_TEXT0(0, setup, dbf_text); 41 QDIO_DBF_HEX0(0, setup, &init_data->input_handler, sizeof(void *)); 42 QDIO_DBF_HEX0(0, setup, &init_data->output_handler, sizeof(void *)); 43 QDIO_DBF_HEX0(0, setup, &init_data->int_parm, sizeof(long)); 44 QDIO_DBF_HEX0(0, setup, &init_data->flags, sizeof(long)); 45 QDIO_DBF_HEX0(0, setup, &init_data->input_sbal_addr_array, sizeof(void *)); 46 QDIO_DBF_HEX0(0, setup, &init_data->output_sbal_addr_array, sizeof(void *)); 47} 48 49static void qdio_unregister_dbf_views(void) 50{ 51 if (qdio_dbf_setup) 52 debug_unregister(qdio_dbf_setup); 53 if (qdio_dbf_trace) 54 debug_unregister(qdio_dbf_trace); 55} 56 57static int qdio_register_dbf_views(void) 58{ 59 qdio_dbf_setup = debug_register("qdio_setup", QDIO_DBF_SETUP_PAGES, 60 QDIO_DBF_SETUP_NR_AREAS, 61 QDIO_DBF_SETUP_LEN); 62 if (!qdio_dbf_setup) 63 goto oom; 64 debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view); 65 debug_set_level(qdio_dbf_setup, QDIO_DBF_SETUP_LEVEL); 66 67 qdio_dbf_trace = debug_register("qdio_trace", QDIO_DBF_TRACE_PAGES, 68 QDIO_DBF_TRACE_NR_AREAS, 69 QDIO_DBF_TRACE_LEN); 70 if (!qdio_dbf_trace) 71 goto oom; 72 debug_register_view(qdio_dbf_trace, &debug_hex_ascii_view); 73 debug_set_level(qdio_dbf_trace, QDIO_DBF_TRACE_LEVEL); 74 return 0; 75oom: 76 qdio_unregister_dbf_views(); 77 return -ENOMEM; 78} 79 80static int qstat_show(struct seq_file *m, void *v) 81{ 82 unsigned char state; 83 struct qdio_q *q = m->private; 84 int i; 85 86 if (!q) 87 return 0; 88 89 seq_printf(m, "device state indicator: %d\n", *q->irq_ptr->dsci); 90 seq_printf(m, "nr_used: %d\n", atomic_read(&q->nr_buf_used)); 91 seq_printf(m, "ftc: %d\n", q->first_to_check); 92 seq_printf(m, "last_move_ftc: %d\n", q->last_move_ftc); 93 seq_printf(m, "polling: %d\n", q->u.in.polling); 94 seq_printf(m, "slsb buffer states:\n"); 95 96 qdio_siga_sync_q(q); 97 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { 98 get_buf_state(q, i, &state); 99 switch (state) { 100 case SLSB_P_INPUT_NOT_INIT: 101 case SLSB_P_OUTPUT_NOT_INIT: 102 seq_printf(m, "N"); 103 break; 104 case SLSB_P_INPUT_PRIMED: 105 case SLSB_CU_OUTPUT_PRIMED: 106 seq_printf(m, "+"); 107 break; 108 case SLSB_P_INPUT_ACK: 109 seq_printf(m, "A"); 110 break; 111 case SLSB_P_INPUT_ERROR: 112 case SLSB_P_OUTPUT_ERROR: 113 seq_printf(m, "x"); 114 break; 115 case SLSB_CU_INPUT_EMPTY: 116 case SLSB_P_OUTPUT_EMPTY: 117 seq_printf(m, "-"); 118 break; 119 case SLSB_P_INPUT_HALTED: 120 case SLSB_P_OUTPUT_HALTED: 121 seq_printf(m, "."); 122 break; 123 default: 124 seq_printf(m, "?"); 125 } 126 if (i == 63) 127 seq_printf(m, "\n"); 128 } 129 seq_printf(m, "\n"); 130 return 0; 131} 132 133static ssize_t qstat_seq_write(struct file *file, const char __user *buf, 134 size_t count, loff_t *off) 135{ 136 struct seq_file *seq = file->private_data; 137 struct qdio_q *q = seq->private; 138 139 if (!q) 140 return 0; 141 142 if (q->is_input_q) 143 xchg(q->irq_ptr->dsci, 1); 144 local_bh_disable(); 145 tasklet_schedule(&q->tasklet); 146 local_bh_enable(); 147 return count; 148} 149 150static int qstat_seq_open(struct inode *inode, struct file *filp) 151{ 152 return single_open(filp, qstat_show, 153 filp->f_path.dentry->d_inode->i_private); 154} 155 156static void remove_debugfs_entry(struct qdio_q *q) 157{ 158 int i; 159 160 for (i = 0; i < MAX_DEBUGFS_QUEUES; i++) { 161 if (!debugfs_queues[i]) 162 continue; 163 if (debugfs_queues[i]->d_inode->i_private == q) { 164 debugfs_remove(debugfs_queues[i]); 165 debugfs_queues[i] = NULL; 166 } 167 } 168} 169 170static struct file_operations debugfs_fops = { 171 .owner = THIS_MODULE, 172 .open = qstat_seq_open, 173 .read = seq_read, 174 .write = qstat_seq_write, 175 .llseek = seq_lseek, 176 .release = single_release, 177}; 178 179static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev) 180{ 181 int i = 0; 182 char name[QDIO_DEBUGFS_NAME_LEN]; 183 184 while (debugfs_queues[i] != NULL) { 185 i++; 186 if (i >= MAX_DEBUGFS_QUEUES) 187 return; 188 } 189 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%s_%d", 190 dev_name(&cdev->dev), 191 q->is_input_q ? "input" : "output", 192 q->nr); 193 debugfs_queues[i] = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR, 194 debugfs_root, q, &debugfs_fops); 195} 196 197void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) 198{ 199 struct qdio_q *q; 200 int i; 201 202 mutex_lock(&debugfs_mutex); 203 for_each_input_queue(irq_ptr, q, i) 204 setup_debugfs_entry(q, cdev); 205 for_each_output_queue(irq_ptr, q, i) 206 setup_debugfs_entry(q, cdev); 207 mutex_unlock(&debugfs_mutex); 208} 209 210void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) 211{ 212 struct qdio_q *q; 213 int i; 214 215 mutex_lock(&debugfs_mutex); 216 for_each_input_queue(irq_ptr, q, i) 217 remove_debugfs_entry(q); 218 for_each_output_queue(irq_ptr, q, i) 219 remove_debugfs_entry(q); 220 mutex_unlock(&debugfs_mutex); 221} 222 223int __init qdio_debug_init(void) 224{ 225 debugfs_root = debugfs_create_dir("qdio_queues", NULL); 226 return qdio_register_dbf_views(); 227} 228 229void qdio_debug_exit(void) 230{ 231 debugfs_remove(debugfs_root); 232 qdio_unregister_dbf_views(); 233} 234