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