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_irq *irq_ptr) 62 { 63 char text[QDIO_DBF_NAME_LEN]; 64 struct qdio_dbf_entry *new_entry; 65 66 DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr); 67 68 /* allocate trace view for the interface */ 69 snprintf(text, QDIO_DBF_NAME_LEN, "qdio_%s", 70 dev_name(&irq_ptr->cdev->dev)); 71 irq_ptr->debug_area = qdio_get_dbf_entry(text); 72 if (irq_ptr->debug_area) 73 DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf reused"); 74 else { 75 irq_ptr->debug_area = debug_register(text, 2, 1, 16); 76 if (!irq_ptr->debug_area) 77 return -ENOMEM; 78 if (debug_register_view(irq_ptr->debug_area, 79 &debug_hex_ascii_view)) { 80 debug_unregister(irq_ptr->debug_area); 81 return -ENOMEM; 82 } 83 debug_set_level(irq_ptr->debug_area, DBF_WARN); 84 DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created"); 85 new_entry = kzalloc(sizeof(struct qdio_dbf_entry), GFP_KERNEL); 86 if (!new_entry) { 87 debug_unregister(irq_ptr->debug_area); 88 return -ENOMEM; 89 } 90 strlcpy(new_entry->dbf_name, text, QDIO_DBF_NAME_LEN); 91 new_entry->dbf_info = irq_ptr->debug_area; 92 mutex_lock(&qdio_dbf_list_mutex); 93 list_add(&new_entry->dbf_list, &qdio_dbf_list); 94 mutex_unlock(&qdio_dbf_list_mutex); 95 } 96 return 0; 97 } 98 99 static int qstat_show(struct seq_file *m, void *v) 100 { 101 unsigned char state; 102 struct qdio_q *q = m->private; 103 int i; 104 105 if (!q) 106 return 0; 107 108 seq_printf(m, "Timestamp: %llx\n", q->timestamp); 109 seq_printf(m, "Last Data IRQ: %llx Last AI: %llx\n", 110 q->irq_ptr->last_data_irq_time, last_ai_time); 111 seq_printf(m, "nr_used: %d ftc: %d\n", 112 atomic_read(&q->nr_buf_used), q->first_to_check); 113 if (q->is_input_q) { 114 seq_printf(m, "batch start: %u batch count: %u\n", 115 q->u.in.batch_start, q->u.in.batch_count); 116 seq_printf(m, "DSCI: %x IRQs disabled: %u\n", 117 *(u8 *)q->irq_ptr->dsci, 118 test_bit(QDIO_IRQ_DISABLED, 119 &q->irq_ptr->poll_state)); 120 } 121 seq_printf(m, "SBAL states:\n"); 122 seq_printf(m, "|0 |8 |16 |24 |32 |40 |48 |56 63|\n"); 123 124 for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) { 125 debug_get_buf_state(q, i, &state); 126 switch (state) { 127 case SLSB_P_INPUT_NOT_INIT: 128 case SLSB_P_OUTPUT_NOT_INIT: 129 seq_printf(m, "N"); 130 break; 131 case SLSB_P_OUTPUT_PENDING: 132 seq_printf(m, "P"); 133 break; 134 case SLSB_P_INPUT_PRIMED: 135 case SLSB_CU_OUTPUT_PRIMED: 136 seq_printf(m, "+"); 137 break; 138 case SLSB_P_INPUT_ACK: 139 seq_printf(m, "A"); 140 break; 141 case SLSB_P_INPUT_ERROR: 142 case SLSB_P_OUTPUT_ERROR: 143 seq_printf(m, "x"); 144 break; 145 case SLSB_CU_INPUT_EMPTY: 146 case SLSB_P_OUTPUT_EMPTY: 147 seq_printf(m, "-"); 148 break; 149 case SLSB_P_INPUT_HALTED: 150 case SLSB_P_OUTPUT_HALTED: 151 seq_printf(m, "."); 152 break; 153 default: 154 seq_printf(m, "?"); 155 } 156 if (i == 63) 157 seq_printf(m, "\n"); 158 } 159 seq_printf(m, "\n"); 160 seq_printf(m, "|64 |72 |80 |88 |96 |104 |112 | 127|\n"); 161 162 seq_printf(m, "\nSBAL statistics:"); 163 if (!q->irq_ptr->perf_stat_enabled) { 164 seq_printf(m, " disabled\n"); 165 return 0; 166 } 167 168 seq_printf(m, "\n1 2.. 4.. 8.. " 169 "16.. 32.. 64.. 128\n"); 170 for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++) 171 seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]); 172 seq_printf(m, "\nError NOP Total\n%-10u %-10u %-10u\n\n", 173 q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop, 174 q->q_stats.nr_sbal_total); 175 return 0; 176 } 177 178 DEFINE_SHOW_ATTRIBUTE(qstat); 179 180 static int ssqd_show(struct seq_file *m, void *v) 181 { 182 struct ccw_device *cdev = m->private; 183 struct qdio_ssqd_desc ssqd; 184 int rc; 185 186 rc = qdio_get_ssqd_desc(cdev, &ssqd); 187 if (rc) 188 return rc; 189 190 seq_hex_dump(m, "", DUMP_PREFIX_NONE, 16, 4, &ssqd, sizeof(ssqd), 191 false); 192 return 0; 193 } 194 195 DEFINE_SHOW_ATTRIBUTE(ssqd); 196 197 static char *qperf_names[] = { 198 "Assumed adapter interrupts", 199 "QDIO interrupts", 200 "Requested PCIs", 201 "Outbound tasklet runs", 202 "SIGA read", 203 "SIGA write", 204 "SIGA sync", 205 "Inbound calls", 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 dentry *parent, 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 debugfs_create_file(name, 0444, parent, q, &qstat_fops); 295 } 296 297 void qdio_setup_debug_entries(struct qdio_irq *irq_ptr) 298 { 299 struct qdio_q *q; 300 int i; 301 302 irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&irq_ptr->cdev->dev), 303 debugfs_root); 304 debugfs_create_file("statistics", S_IFREG | S_IRUGO | S_IWUSR, 305 irq_ptr->debugfs_dev, irq_ptr, &debugfs_perf_fops); 306 debugfs_create_file("ssqd", 0444, irq_ptr->debugfs_dev, irq_ptr->cdev, 307 &ssqd_fops); 308 309 for_each_input_queue(irq_ptr, q, i) 310 setup_debugfs_entry(irq_ptr->debugfs_dev, q); 311 for_each_output_queue(irq_ptr, q, i) 312 setup_debugfs_entry(irq_ptr->debugfs_dev, q); 313 } 314 315 void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr) 316 { 317 debugfs_remove_recursive(irq_ptr->debugfs_dev); 318 } 319 320 int __init qdio_debug_init(void) 321 { 322 debugfs_root = debugfs_create_dir("qdio", NULL); 323 324 qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16); 325 debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view); 326 debug_set_level(qdio_dbf_setup, DBF_INFO); 327 DBF_EVENT("dbf created\n"); 328 329 qdio_dbf_error = debug_register("qdio_error", 4, 1, 16); 330 debug_register_view(qdio_dbf_error, &debug_hex_ascii_view); 331 debug_set_level(qdio_dbf_error, DBF_INFO); 332 DBF_ERROR("dbf created\n"); 333 return 0; 334 } 335 336 void qdio_debug_exit(void) 337 { 338 qdio_clear_dbf_list(); 339 debugfs_remove_recursive(debugfs_root); 340 debug_unregister(qdio_dbf_setup); 341 debug_unregister(qdio_dbf_error); 342 } 343