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