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