1/* 2 * drivers/s390/cio/qdio_debug.c 3 * 4 * Copyright IBM Corp. 2008,2009 5 * 6 * Author: Jan Glauber (jang@linux.vnet.ibm.com) 7 */ 8#include <linux/seq_file.h> 9#include <linux/debugfs.h> 10#include <asm/debug.h> 11#include "qdio_debug.h" 12#include "qdio.h" 13 14debug_info_t *qdio_dbf_setup; 15debug_info_t *qdio_dbf_error; 16 17static struct dentry *debugfs_root; 18#define QDIO_DEBUGFS_NAME_LEN 10 19 20void qdio_allocate_dbf(struct qdio_initialize *init_data, 21 struct qdio_irq *irq_ptr) 22{ 23 char text[20]; 24 25 DBF_EVENT("qfmt:%1d", init_data->q_format); 26 DBF_HEX(init_data->adapter_name, 8); 27 DBF_EVENT("qpff%4x", init_data->qib_param_field_format); 28 DBF_HEX(&init_data->qib_param_field, sizeof(void *)); 29 DBF_HEX(&init_data->input_slib_elements, sizeof(void *)); 30 DBF_HEX(&init_data->output_slib_elements, sizeof(void *)); 31 DBF_EVENT("niq:%1d noq:%1d", init_data->no_input_qs, 32 init_data->no_output_qs); 33 DBF_HEX(&init_data->input_handler, sizeof(void *)); 34 DBF_HEX(&init_data->output_handler, sizeof(void *)); 35 DBF_HEX(&init_data->int_parm, sizeof(long)); 36 DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *)); 37 DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *)); 38 DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr); 39 40 /* allocate trace view for the interface */ 41 snprintf(text, 20, "qdio_%s", dev_name(&init_data->cdev->dev)); 42 irq_ptr->debug_area = debug_register(text, 2, 1, 16); 43 debug_register_view(irq_ptr->debug_area, &debug_hex_ascii_view); 44 debug_set_level(irq_ptr->debug_area, DBF_WARN); 45 DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created"); 46} 47 48static int qstat_show(struct seq_file *m, void *v) 49{ 50 unsigned char state; 51 struct qdio_q *q = m->private; 52 int i; 53 54 if (!q) 55 return 0; 56 57 seq_printf(m, "DSCI: %d nr_used: %d\n", 58 *(u32 *)q->irq_ptr->dsci, atomic_read(&q->nr_buf_used)); 59 seq_printf(m, "ftc: %d last_move: %d\n", q->first_to_check, q->last_move); 60 seq_printf(m, "polling: %d ack start: %d ack count: %d\n", 61 q->u.in.polling, q->u.in.ack_start, q->u.in.ack_count); 62 seq_printf(m, "SBAL states:\n"); 63 seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n"); 64 65 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { 66 debug_get_buf_state(q, i, &state); 67 switch (state) { 68 case SLSB_P_INPUT_NOT_INIT: 69 case SLSB_P_OUTPUT_NOT_INIT: 70 seq_printf(m, "N"); 71 break; 72 case SLSB_P_INPUT_PRIMED: 73 case SLSB_CU_OUTPUT_PRIMED: 74 seq_printf(m, "+"); 75 break; 76 case SLSB_P_INPUT_ACK: 77 seq_printf(m, "A"); 78 break; 79 case SLSB_P_INPUT_ERROR: 80 case SLSB_P_OUTPUT_ERROR: 81 seq_printf(m, "x"); 82 break; 83 case SLSB_CU_INPUT_EMPTY: 84 case SLSB_P_OUTPUT_EMPTY: 85 seq_printf(m, "-"); 86 break; 87 case SLSB_P_INPUT_HALTED: 88 case SLSB_P_OUTPUT_HALTED: 89 seq_printf(m, "."); 90 break; 91 default: 92 seq_printf(m, "?"); 93 } 94 if (i == 63) 95 seq_printf(m, "\n"); 96 } 97 seq_printf(m, "\n"); 98 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n"); 99 100 seq_printf(m, "\nSBAL statistics:"); 101 if (!q->irq_ptr->perf_stat_enabled) { 102 seq_printf(m, " disabled\n"); 103 return 0; 104 } 105 106 seq_printf(m, "\n1 2.. 4.. 8.. " 107 "16.. 32.. 64.. 127\n"); 108 for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++) 109 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]); 110 seq_printf(m, "\nError NOP Total\n%-10u %-10u %-10u\n\n", 111 q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop, 112 q->q_stats.nr_sbal_total); 113 return 0; 114} 115 116static ssize_t qstat_seq_write(struct file *file, const char __user *buf, 117 size_t count, loff_t *off) 118{ 119 struct seq_file *seq = file->private_data; 120 struct qdio_q *q = seq->private; 121 122 if (!q) 123 return 0; 124 if (q->is_input_q) 125 xchg(q->irq_ptr->dsci, 1); 126 local_bh_disable(); 127 tasklet_schedule(&q->tasklet); 128 local_bh_enable(); 129 return count; 130} 131 132static int qstat_seq_open(struct inode *inode, struct file *filp) 133{ 134 return single_open(filp, qstat_show, 135 filp->f_path.dentry->d_inode->i_private); 136} 137 138static const struct file_operations debugfs_fops = { 139 .owner = THIS_MODULE, 140 .open = qstat_seq_open, 141 .read = seq_read, 142 .write = qstat_seq_write, 143 .llseek = seq_lseek, 144 .release = single_release, 145}; 146 147static char *qperf_names[] = { 148 "Assumed adapter interrupts", 149 "QDIO interrupts", 150 "Requested PCIs", 151 "Inbound tasklet runs", 152 "Inbound tasklet resched", 153 "Inbound tasklet resched2", 154 "Outbound tasklet runs", 155 "SIGA read", 156 "SIGA write", 157 "SIGA sync", 158 "Inbound calls", 159 "Inbound handler", 160 "Inbound stop_polling", 161 "Inbound queue full", 162 "Outbound calls", 163 "Outbound handler", 164 "Outbound fast_requeue", 165 "Outbound target_full", 166 "QEBSM eqbs", 167 "QEBSM eqbs partial", 168 "QEBSM sqbs", 169 "QEBSM sqbs partial" 170}; 171 172static int qperf_show(struct seq_file *m, void *v) 173{ 174 struct qdio_irq *irq_ptr = m->private; 175 unsigned int *stat; 176 int i; 177 178 if (!irq_ptr) 179 return 0; 180 if (!irq_ptr->perf_stat_enabled) { 181 seq_printf(m, "disabled\n"); 182 return 0; 183 } 184 stat = (unsigned int *)&irq_ptr->perf_stat; 185 186 for (i = 0; i < ARRAY_SIZE(qperf_names); i++) 187 seq_printf(m, "%26s:\t%u\n", 188 qperf_names[i], *(stat + i)); 189 return 0; 190} 191 192static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf, 193 size_t count, loff_t *off) 194{ 195 struct seq_file *seq = file->private_data; 196 struct qdio_irq *irq_ptr = seq->private; 197 struct qdio_q *q; 198 unsigned long val; 199 char buf[8]; 200 int ret, i; 201 202 if (!irq_ptr) 203 return 0; 204 if (count >= sizeof(buf)) 205 return -EINVAL; 206 if (copy_from_user(&buf, ubuf, count)) 207 return -EFAULT; 208 buf[count] = 0; 209 210 ret = strict_strtoul(buf, 10, &val); 211 if (ret < 0) 212 return ret; 213 214 switch (val) { 215 case 0: 216 irq_ptr->perf_stat_enabled = 0; 217 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat)); 218 for_each_input_queue(irq_ptr, q, i) 219 memset(&q->q_stats, 0, sizeof(q->q_stats)); 220 for_each_output_queue(irq_ptr, q, i) 221 memset(&q->q_stats, 0, sizeof(q->q_stats)); 222 break; 223 case 1: 224 irq_ptr->perf_stat_enabled = 1; 225 break; 226 } 227 return count; 228} 229 230static int qperf_seq_open(struct inode *inode, struct file *filp) 231{ 232 return single_open(filp, qperf_show, 233 filp->f_path.dentry->d_inode->i_private); 234} 235 236static struct file_operations debugfs_perf_fops = { 237 .owner = THIS_MODULE, 238 .open = qperf_seq_open, 239 .read = seq_read, 240 .write = qperf_seq_write, 241 .llseek = seq_lseek, 242 .release = single_release, 243}; 244static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev) 245{ 246 char name[QDIO_DEBUGFS_NAME_LEN]; 247 248 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d", 249 q->is_input_q ? "input" : "output", 250 q->nr); 251 q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR, 252 q->irq_ptr->debugfs_dev, q, &debugfs_fops); 253 if (IS_ERR(q->debugfs_q)) 254 q->debugfs_q = NULL; 255} 256 257void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) 258{ 259 struct qdio_q *q; 260 int i; 261 262 irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev), 263 debugfs_root); 264 if (IS_ERR(irq_ptr->debugfs_dev)) 265 irq_ptr->debugfs_dev = NULL; 266 267 irq_ptr->debugfs_perf = debugfs_create_file("statistics", 268 S_IFREG | S_IRUGO | S_IWUSR, 269 irq_ptr->debugfs_dev, irq_ptr, 270 &debugfs_perf_fops); 271 if (IS_ERR(irq_ptr->debugfs_perf)) 272 irq_ptr->debugfs_perf = NULL; 273 274 for_each_input_queue(irq_ptr, q, i) 275 setup_debugfs_entry(q, cdev); 276 for_each_output_queue(irq_ptr, q, i) 277 setup_debugfs_entry(q, cdev); 278} 279 280void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) 281{ 282 struct qdio_q *q; 283 int i; 284 285 for_each_input_queue(irq_ptr, q, i) 286 debugfs_remove(q->debugfs_q); 287 for_each_output_queue(irq_ptr, q, i) 288 debugfs_remove(q->debugfs_q); 289 debugfs_remove(irq_ptr->debugfs_perf); 290 debugfs_remove(irq_ptr->debugfs_dev); 291} 292 293int __init qdio_debug_init(void) 294{ 295 debugfs_root = debugfs_create_dir("qdio", NULL); 296 297 qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16); 298 debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view); 299 debug_set_level(qdio_dbf_setup, DBF_INFO); 300 DBF_EVENT("dbf created\n"); 301 302 qdio_dbf_error = debug_register("qdio_error", 4, 1, 16); 303 debug_register_view(qdio_dbf_error, &debug_hex_ascii_view); 304 debug_set_level(qdio_dbf_error, DBF_INFO); 305 DBF_ERROR("dbf created\n"); 306 return 0; 307} 308 309void qdio_debug_exit(void) 310{ 311 debugfs_remove(debugfs_root); 312 if (qdio_dbf_setup) 313 debug_unregister(qdio_dbf_setup); 314 if (qdio_dbf_error) 315 debug_unregister(qdio_dbf_error); 316} 317