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