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