qdio_debug.c (8502B)
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 16debug_info_t *qdio_dbf_setup; 17debug_info_t *qdio_dbf_error; 18 19static struct dentry *debugfs_root; 20#define QDIO_DEBUGFS_NAME_LEN 10 21#define QDIO_DBF_NAME_LEN 20 22 23struct 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 29static LIST_HEAD(qdio_dbf_list); 30static DEFINE_MUTEX(qdio_dbf_list_mutex); 31 32static 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 48static 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 61int 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 99static 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 178DEFINE_SHOW_ATTRIBUTE(qstat); 179 180static 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 195DEFINE_SHOW_ATTRIBUTE(ssqd); 196 197static char *qperf_names[] = { 198 "Assumed adapter interrupts", 199 "QDIO interrupts", 200 "SIGA read", 201 "SIGA write", 202 "SIGA sync", 203 "Inbound calls", 204 "Inbound stop_polling", 205 "Inbound queue full", 206 "Outbound calls", 207 "Outbound queue full", 208 "Outbound fast_requeue", 209 "Outbound target_full", 210 "QEBSM eqbs", 211 "QEBSM eqbs partial", 212 "QEBSM sqbs", 213 "QEBSM sqbs partial", 214 "Discarded interrupts" 215}; 216 217static int qperf_show(struct seq_file *m, void *v) 218{ 219 struct qdio_irq *irq_ptr = m->private; 220 unsigned int *stat; 221 int i; 222 223 if (!irq_ptr) 224 return 0; 225 if (!irq_ptr->perf_stat_enabled) { 226 seq_printf(m, "disabled\n"); 227 return 0; 228 } 229 stat = (unsigned int *)&irq_ptr->perf_stat; 230 231 for (i = 0; i < ARRAY_SIZE(qperf_names); i++) 232 seq_printf(m, "%26s:\t%u\n", 233 qperf_names[i], *(stat + i)); 234 return 0; 235} 236 237static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf, 238 size_t count, loff_t *off) 239{ 240 struct seq_file *seq = file->private_data; 241 struct qdio_irq *irq_ptr = seq->private; 242 struct qdio_q *q; 243 unsigned long val; 244 int ret, i; 245 246 if (!irq_ptr) 247 return 0; 248 249 ret = kstrtoul_from_user(ubuf, count, 10, &val); 250 if (ret) 251 return ret; 252 253 switch (val) { 254 case 0: 255 irq_ptr->perf_stat_enabled = 0; 256 memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat)); 257 for_each_input_queue(irq_ptr, q, i) 258 memset(&q->q_stats, 0, sizeof(q->q_stats)); 259 for_each_output_queue(irq_ptr, q, i) 260 memset(&q->q_stats, 0, sizeof(q->q_stats)); 261 break; 262 case 1: 263 irq_ptr->perf_stat_enabled = 1; 264 break; 265 } 266 return count; 267} 268 269static int qperf_seq_open(struct inode *inode, struct file *filp) 270{ 271 return single_open(filp, qperf_show, 272 file_inode(filp)->i_private); 273} 274 275static const struct file_operations debugfs_perf_fops = { 276 .owner = THIS_MODULE, 277 .open = qperf_seq_open, 278 .read = seq_read, 279 .write = qperf_seq_write, 280 .llseek = seq_lseek, 281 .release = single_release, 282}; 283 284static void setup_debugfs_entry(struct dentry *parent, struct qdio_q *q) 285{ 286 char name[QDIO_DEBUGFS_NAME_LEN]; 287 288 snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d", 289 q->is_input_q ? "input" : "output", 290 q->nr); 291 debugfs_create_file(name, 0444, parent, q, &qstat_fops); 292} 293 294void qdio_setup_debug_entries(struct qdio_irq *irq_ptr) 295{ 296 struct qdio_q *q; 297 int i; 298 299 irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&irq_ptr->cdev->dev), 300 debugfs_root); 301 debugfs_create_file("statistics", S_IFREG | S_IRUGO | S_IWUSR, 302 irq_ptr->debugfs_dev, irq_ptr, &debugfs_perf_fops); 303 debugfs_create_file("ssqd", 0444, irq_ptr->debugfs_dev, irq_ptr->cdev, 304 &ssqd_fops); 305 306 for_each_input_queue(irq_ptr, q, i) 307 setup_debugfs_entry(irq_ptr->debugfs_dev, q); 308 for_each_output_queue(irq_ptr, q, i) 309 setup_debugfs_entry(irq_ptr->debugfs_dev, q); 310} 311 312void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr) 313{ 314 debugfs_remove_recursive(irq_ptr->debugfs_dev); 315} 316 317int __init qdio_debug_init(void) 318{ 319 debugfs_root = debugfs_create_dir("qdio", NULL); 320 321 qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16); 322 debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view); 323 debug_set_level(qdio_dbf_setup, DBF_INFO); 324 DBF_EVENT("dbf created\n"); 325 326 qdio_dbf_error = debug_register("qdio_error", 4, 1, 16); 327 debug_register_view(qdio_dbf_error, &debug_hex_ascii_view); 328 debug_set_level(qdio_dbf_error, DBF_INFO); 329 DBF_ERROR("dbf created\n"); 330 return 0; 331} 332 333void qdio_debug_exit(void) 334{ 335 qdio_clear_dbf_list(); 336 debugfs_remove_recursive(debugfs_root); 337 debug_unregister(qdio_dbf_setup); 338 debug_unregister(qdio_dbf_error); 339}