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, "polling: %d ack start: %d ack count: %d\n", 128 q->u.in.polling, q->u.in.ack_start, 129 q->u.in.ack_count); 130 seq_printf(m, "DSCI: %x IRQs disabled: %u\n", 131 *(u8 *)q->irq_ptr->dsci, 132 test_bit(QDIO_QUEUE_IRQS_DISABLED, 133 &q->u.in.queue_irq_state)); 134 } 135 seq_printf(m, "SBAL states:\n"); 136 seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n"); 137 138 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { 139 debug_get_buf_state(q, i, &state); 140 switch (state) { 141 case SLSB_P_INPUT_NOT_INIT: 142 case SLSB_P_OUTPUT_NOT_INIT: 143 seq_printf(m, "N"); 144 break; 145 case SLSB_P_OUTPUT_PENDING: 146 seq_printf(m, "P"); 147 break; 148 case SLSB_P_INPUT_PRIMED: 149 case SLSB_CU_OUTPUT_PRIMED: 150 seq_printf(m, "+"); 151 break; 152 case SLSB_P_INPUT_ACK: 153 seq_printf(m, "A"); 154 break; 155 case SLSB_P_INPUT_ERROR: 156 case SLSB_P_OUTPUT_ERROR: 157 seq_printf(m, "x"); 158 break; 159 case SLSB_CU_INPUT_EMPTY: 160 case SLSB_P_OUTPUT_EMPTY: 161 seq_printf(m, "-"); 162 break; 163 case SLSB_P_INPUT_HALTED: 164 case SLSB_P_OUTPUT_HALTED: 165 seq_printf(m, "."); 166 break; 167 default: 168 seq_printf(m, "?"); 169 } 170 if (i == 63) 171 seq_printf(m, "\n"); 172 } 173 seq_printf(m, "\n"); 174 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n"); 175 176 seq_printf(m, "\nSBAL statistics:"); 177 if (!q->irq_ptr->perf_stat_enabled) { 178 seq_printf(m, " disabled\n"); 179 return 0; 180 } 181 182 seq_printf(m, "\n1 2.. 4.. 8.. " 183 "16.. 32.. 64.. 127\n"); 184 for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++) 185 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]); 186 seq_printf(m, "\nError NOP Total\n%-10u %-10u %-10u\n\n", 187 q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop, 188 q->q_stats.nr_sbal_total); 189 return 0; 190 } 191 192 DEFINE_SHOW_ATTRIBUTE(qstat); 193 194 static char *qperf_names[] = { 195 "Assumed adapter interrupts", 196 "QDIO interrupts", 197 "Requested PCIs", 198 "Inbound tasklet runs", 199 "Inbound tasklet resched", 200 "Inbound tasklet resched2", 201 "Outbound tasklet runs", 202 "SIGA read", 203 "SIGA write", 204 "SIGA sync", 205 "Inbound calls", 206 "Inbound handler", 207 "Inbound stop_polling", 208 "Inbound queue full", 209 "Outbound calls", 210 "Outbound handler", 211 "Outbound queue full", 212 "Outbound fast_requeue", 213 "Outbound target_full", 214 "QEBSM eqbs", 215 "QEBSM eqbs partial", 216 "QEBSM sqbs", 217 "QEBSM sqbs partial", 218 "Discarded interrupts" 219 }; 220 221 static int qperf_show(struct seq_file *m, void *v) 222 { 223 struct qdio_irq *irq_ptr = m->private; 224 unsigned int *stat; 225 int i; 226 227 if (!irq_ptr) 228 return 0; 229 if (!irq_ptr->perf_stat_enabled) { 230 seq_printf(m, "disabled\n"); 231 return 0; 232 } 233 stat = (unsigned int *)&irq_ptr->perf_stat; 234 235 for (i = 0; i < ARRAY_SIZE(qperf_names); i++) 236 seq_printf(m, "%26s:\t%u\n", 237 qperf_names[i], *(stat + i)); 238 return 0; 239 } 240 241 static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf, 242 size_t count, loff_t *off) 243 { 244 struct seq_file *seq = file->private_data; 245 struct qdio_irq *irq_ptr = seq->private; 246 struct qdio_q *q; 247 unsigned long val; 248 int ret, i; 249 250 if (!irq_ptr) 251 return 0; 252 253 ret = kstrtoul_from_user(ubuf, count, 10, &val); 254 if (ret) 255 return ret; 256 257 switch (val) { 258 case 0: 259 irq_ptr->perf_stat_enabled = 0; 260 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat)); 261 for_each_input_queue(irq_ptr, q, i) 262 memset(&q->q_stats, 0, sizeof(q->q_stats)); 263 for_each_output_queue(irq_ptr, q, i) 264 memset(&q->q_stats, 0, sizeof(q->q_stats)); 265 break; 266 case 1: 267 irq_ptr->perf_stat_enabled = 1; 268 break; 269 } 270 return count; 271 } 272 273 static int qperf_seq_open(struct inode *inode, struct file *filp) 274 { 275 return single_open(filp, qperf_show, 276 file_inode(filp)->i_private); 277 } 278 279 static const struct file_operations debugfs_perf_fops = { 280 .owner = THIS_MODULE, 281 .open = qperf_seq_open, 282 .read = seq_read, 283 .write = qperf_seq_write, 284 .llseek = seq_lseek, 285 .release = single_release, 286 }; 287 288 static void setup_debugfs_entry(struct qdio_q *q) 289 { 290 char name[QDIO_DEBUGFS_NAME_LEN]; 291 292 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d", 293 q->is_input_q ? "input" : "output", 294 q->nr); 295 q->debugfs_q = debugfs_create_file(name, 0444, 296 q->irq_ptr->debugfs_dev, q, &qstat_fops); 297 if (IS_ERR(q->debugfs_q)) 298 q->debugfs_q = NULL; 299 } 300 301 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev) 302 { 303 struct qdio_q *q; 304 int i; 305 306 irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev), 307 debugfs_root); 308 if (IS_ERR(irq_ptr->debugfs_dev)) 309 irq_ptr->debugfs_dev = NULL; 310 311 irq_ptr->debugfs_perf = debugfs_create_file("statistics", 312 S_IFREG | S_IRUGO | S_IWUSR, 313 irq_ptr->debugfs_dev, irq_ptr, 314 &debugfs_perf_fops); 315 if (IS_ERR(irq_ptr->debugfs_perf)) 316 irq_ptr->debugfs_perf = NULL; 317 318 for_each_input_queue(irq_ptr, q, i) 319 setup_debugfs_entry(q); 320 for_each_output_queue(irq_ptr, q, i) 321 setup_debugfs_entry(q); 322 } 323 324 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr) 325 { 326 struct qdio_q *q; 327 int i; 328 329 for_each_input_queue(irq_ptr, q, i) 330 debugfs_remove(q->debugfs_q); 331 for_each_output_queue(irq_ptr, q, i) 332 debugfs_remove(q->debugfs_q); 333 debugfs_remove(irq_ptr->debugfs_perf); 334 debugfs_remove(irq_ptr->debugfs_dev); 335 } 336 337 int __init qdio_debug_init(void) 338 { 339 debugfs_root = debugfs_create_dir("qdio", NULL); 340 341 qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16); 342 debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view); 343 debug_set_level(qdio_dbf_setup, DBF_INFO); 344 DBF_EVENT("dbf created\n"); 345 346 qdio_dbf_error = debug_register("qdio_error", 4, 1, 16); 347 debug_register_view(qdio_dbf_error, &debug_hex_ascii_view); 348 debug_set_level(qdio_dbf_error, DBF_INFO); 349 DBF_ERROR("dbf created\n"); 350 return 0; 351 } 352 353 void qdio_debug_exit(void) 354 { 355 qdio_clear_dbf_list(); 356 debugfs_remove(debugfs_root); 357 debug_unregister(qdio_dbf_setup); 358 debug_unregister(qdio_dbf_error); 359 } 360