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