linux/drivers/s390/cio/qdio_debug.c
<<
>>
Prefs
   1/*
   2 *  Copyright IBM Corp. 2008, 2009
   3 *
   4 *  Author: Jan Glauber (jang@linux.vnet.ibm.com)
   5 */
   6#include <linux/seq_file.h>
   7#include <linux/debugfs.h>
   8#include <linux/uaccess.h>
   9#include <linux/export.h>
  10#include <asm/debug.h>
  11#include "qdio_debug.h"
  12#include "qdio.h"
  13
  14debug_info_t *qdio_dbf_setup;
  15debug_info_t *qdio_dbf_error;
  16
  17static struct dentry *debugfs_root;
  18#define QDIO_DEBUGFS_NAME_LEN   10
  19
  20void qdio_allocate_dbf(struct qdio_initialize *init_data,
  21                       struct qdio_irq *irq_ptr)
  22{
  23        char text[20];
  24
  25        DBF_EVENT("qfmt:%1d", init_data->q_format);
  26        DBF_HEX(init_data->adapter_name, 8);
  27        DBF_EVENT("qpff%4x", init_data->qib_param_field_format);
  28        DBF_HEX(&init_data->qib_param_field, sizeof(void *));
  29        DBF_HEX(&init_data->input_slib_elements, sizeof(void *));
  30        DBF_HEX(&init_data->output_slib_elements, sizeof(void *));
  31        DBF_EVENT("niq:%1d noq:%1d", init_data->no_input_qs,
  32                  init_data->no_output_qs);
  33        DBF_HEX(&init_data->input_handler, sizeof(void *));
  34        DBF_HEX(&init_data->output_handler, sizeof(void *));
  35        DBF_HEX(&init_data->int_parm, sizeof(long));
  36        DBF_HEX(&init_data->input_sbal_addr_array, sizeof(void *));
  37        DBF_HEX(&init_data->output_sbal_addr_array, sizeof(void *));
  38        DBF_EVENT("irq:%8lx", (unsigned long)irq_ptr);
  39
  40        /* allocate trace view for the interface */
  41        snprintf(text, 20, "qdio_%s", dev_name(&init_data->cdev->dev));
  42        irq_ptr->debug_area = debug_register(text, 2, 1, 16);
  43        debug_register_view(irq_ptr->debug_area, &debug_hex_ascii_view);
  44        debug_set_level(irq_ptr->debug_area, DBF_WARN);
  45        DBF_DEV_EVENT(DBF_ERR, irq_ptr, "dbf created");
  46}
  47
  48static int qstat_show(struct seq_file *m, void *v)
  49{
  50        unsigned char state;
  51        struct qdio_q *q = m->private;
  52        int i;
  53
  54        if (!q)
  55                return 0;
  56
  57        seq_printf(m, "Timestamp: %Lx  Last AI: %Lx\n",
  58                   q->timestamp, last_ai_time);
  59        seq_printf(m, "nr_used: %d  ftc: %d  last_move: %d\n",
  60                   atomic_read(&q->nr_buf_used),
  61                   q->first_to_check, q->last_move);
  62        if (q->is_input_q) {
  63                seq_printf(m, "polling: %d  ack start: %d  ack count: %d\n",
  64                           q->u.in.polling, q->u.in.ack_start,
  65                           q->u.in.ack_count);
  66                seq_printf(m, "DSCI: %d   IRQs disabled: %u\n",
  67                           *(u32 *)q->irq_ptr->dsci,
  68                           test_bit(QDIO_QUEUE_IRQS_DISABLED,
  69                           &q->u.in.queue_irq_state));
  70        }
  71        seq_printf(m, "SBAL states:\n");
  72        seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n");
  73
  74        for (i = 0; i < QDIO_MAX_BUFFERS_PER_Q; i++) {
  75                debug_get_buf_state(q, i, &state);
  76                switch (state) {
  77                case SLSB_P_INPUT_NOT_INIT:
  78                case SLSB_P_OUTPUT_NOT_INIT:
  79                        seq_printf(m, "N");
  80                        break;
  81                case SLSB_P_OUTPUT_PENDING:
  82                        seq_printf(m, "P");
  83                        break;
  84                case SLSB_P_INPUT_PRIMED:
  85                case SLSB_CU_OUTPUT_PRIMED:
  86                        seq_printf(m, "+");
  87                        break;
  88                case SLSB_P_INPUT_ACK:
  89                        seq_printf(m, "A");
  90                        break;
  91                case SLSB_P_INPUT_ERROR:
  92                case SLSB_P_OUTPUT_ERROR:
  93                        seq_printf(m, "x");
  94                        break;
  95                case SLSB_CU_INPUT_EMPTY:
  96                case SLSB_P_OUTPUT_EMPTY:
  97                        seq_printf(m, "-");
  98                        break;
  99                case SLSB_P_INPUT_HALTED:
 100                case SLSB_P_OUTPUT_HALTED:
 101                        seq_printf(m, ".");
 102                        break;
 103                default:
 104                        seq_printf(m, "?");
 105                }
 106                if (i == 63)
 107                        seq_printf(m, "\n");
 108        }
 109        seq_printf(m, "\n");
 110        seq_printf(m, "|64     |72     |80     |88     |96     |104    |112    |   127|\n");
 111
 112        seq_printf(m, "\nSBAL statistics:");
 113        if (!q->irq_ptr->perf_stat_enabled) {
 114                seq_printf(m, " disabled\n");
 115                return 0;
 116        }
 117
 118        seq_printf(m, "\n1          2..        4..        8..        "
 119                   "16..       32..       64..       127\n");
 120        for (i = 0; i < ARRAY_SIZE(q->q_stats.nr_sbals); i++)
 121                seq_printf(m, "%-10u ", q->q_stats.nr_sbals[i]);
 122        seq_printf(m, "\nError      NOP        Total\n%-10u %-10u %-10u\n\n",
 123                   q->q_stats.nr_sbal_error, q->q_stats.nr_sbal_nop,
 124                   q->q_stats.nr_sbal_total);
 125        return 0;
 126}
 127
 128static int qstat_seq_open(struct inode *inode, struct file *filp)
 129{
 130        return single_open(filp, qstat_show,
 131                           file_inode(filp)->i_private);
 132}
 133
 134static const struct file_operations debugfs_fops = {
 135        .owner   = THIS_MODULE,
 136        .open    = qstat_seq_open,
 137        .read    = seq_read,
 138        .llseek  = seq_lseek,
 139        .release = single_release,
 140};
 141
 142static char *qperf_names[] = {
 143        "Assumed adapter interrupts",
 144        "QDIO interrupts",
 145        "Requested PCIs",
 146        "Inbound tasklet runs",
 147        "Inbound tasklet resched",
 148        "Inbound tasklet resched2",
 149        "Outbound tasklet runs",
 150        "SIGA read",
 151        "SIGA write",
 152        "SIGA sync",
 153        "Inbound calls",
 154        "Inbound handler",
 155        "Inbound stop_polling",
 156        "Inbound queue full",
 157        "Outbound calls",
 158        "Outbound handler",
 159        "Outbound queue full",
 160        "Outbound fast_requeue",
 161        "Outbound target_full",
 162        "QEBSM eqbs",
 163        "QEBSM eqbs partial",
 164        "QEBSM sqbs",
 165        "QEBSM sqbs partial",
 166        "Discarded interrupts"
 167};
 168
 169static int qperf_show(struct seq_file *m, void *v)
 170{
 171        struct qdio_irq *irq_ptr = m->private;
 172        unsigned int *stat;
 173        int i;
 174
 175        if (!irq_ptr)
 176                return 0;
 177        if (!irq_ptr->perf_stat_enabled) {
 178                seq_printf(m, "disabled\n");
 179                return 0;
 180        }
 181        stat = (unsigned int *)&irq_ptr->perf_stat;
 182
 183        for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
 184                seq_printf(m, "%26s:\t%u\n",
 185                           qperf_names[i], *(stat + i));
 186        return 0;
 187}
 188
 189static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
 190                               size_t count, loff_t *off)
 191{
 192        struct seq_file *seq = file->private_data;
 193        struct qdio_irq *irq_ptr = seq->private;
 194        struct qdio_q *q;
 195        unsigned long val;
 196        int ret, i;
 197
 198        if (!irq_ptr)
 199                return 0;
 200
 201        ret = kstrtoul_from_user(ubuf, count, 10, &val);
 202        if (ret)
 203                return ret;
 204
 205        switch (val) {
 206        case 0:
 207                irq_ptr->perf_stat_enabled = 0;
 208                memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
 209                for_each_input_queue(irq_ptr, q, i)
 210                        memset(&q->q_stats, 0, sizeof(q->q_stats));
 211                for_each_output_queue(irq_ptr, q, i)
 212                        memset(&q->q_stats, 0, sizeof(q->q_stats));
 213                break;
 214        case 1:
 215                irq_ptr->perf_stat_enabled = 1;
 216                break;
 217        }
 218        return count;
 219}
 220
 221static int qperf_seq_open(struct inode *inode, struct file *filp)
 222{
 223        return single_open(filp, qperf_show,
 224                           file_inode(filp)->i_private);
 225}
 226
 227static const struct file_operations debugfs_perf_fops = {
 228        .owner   = THIS_MODULE,
 229        .open    = qperf_seq_open,
 230        .read    = seq_read,
 231        .write   = qperf_seq_write,
 232        .llseek  = seq_lseek,
 233        .release = single_release,
 234};
 235
 236static void setup_debugfs_entry(struct qdio_q *q)
 237{
 238        char name[QDIO_DEBUGFS_NAME_LEN];
 239
 240        snprintf(name, QDIO_DEBUGFS_NAME_LEN, "%s_%d",
 241                 q->is_input_q ? "input" : "output",
 242                 q->nr);
 243        q->debugfs_q = debugfs_create_file(name, S_IFREG | S_IRUGO | S_IWUSR,
 244                                q->irq_ptr->debugfs_dev, q, &debugfs_fops);
 245        if (IS_ERR(q->debugfs_q))
 246                q->debugfs_q = NULL;
 247}
 248
 249void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
 250{
 251        struct qdio_q *q;
 252        int i;
 253
 254        irq_ptr->debugfs_dev = debugfs_create_dir(dev_name(&cdev->dev),
 255                                                  debugfs_root);
 256        if (IS_ERR(irq_ptr->debugfs_dev))
 257                irq_ptr->debugfs_dev = NULL;
 258
 259        irq_ptr->debugfs_perf = debugfs_create_file("statistics",
 260                                S_IFREG | S_IRUGO | S_IWUSR,
 261                                irq_ptr->debugfs_dev, irq_ptr,
 262                                &debugfs_perf_fops);
 263        if (IS_ERR(irq_ptr->debugfs_perf))
 264                irq_ptr->debugfs_perf = NULL;
 265
 266        for_each_input_queue(irq_ptr, q, i)
 267                setup_debugfs_entry(q);
 268        for_each_output_queue(irq_ptr, q, i)
 269                setup_debugfs_entry(q);
 270}
 271
 272void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr)
 273{
 274        struct qdio_q *q;
 275        int i;
 276
 277        for_each_input_queue(irq_ptr, q, i)
 278                debugfs_remove(q->debugfs_q);
 279        for_each_output_queue(irq_ptr, q, i)
 280                debugfs_remove(q->debugfs_q);
 281        debugfs_remove(irq_ptr->debugfs_perf);
 282        debugfs_remove(irq_ptr->debugfs_dev);
 283}
 284
 285int __init qdio_debug_init(void)
 286{
 287        debugfs_root = debugfs_create_dir("qdio", NULL);
 288
 289        qdio_dbf_setup = debug_register("qdio_setup", 16, 1, 16);
 290        debug_register_view(qdio_dbf_setup, &debug_hex_ascii_view);
 291        debug_set_level(qdio_dbf_setup, DBF_INFO);
 292        DBF_EVENT("dbf created\n");
 293
 294        qdio_dbf_error = debug_register("qdio_error", 4, 1, 16);
 295        debug_register_view(qdio_dbf_error, &debug_hex_ascii_view);
 296        debug_set_level(qdio_dbf_error, DBF_INFO);
 297        DBF_ERROR("dbf created\n");
 298        return 0;
 299}
 300
 301void qdio_debug_exit(void)
 302{
 303        debugfs_remove(debugfs_root);
 304        if (qdio_dbf_setup)
 305                debug_unregister(qdio_dbf_setup);
 306        if (qdio_dbf_error)
 307                debug_unregister(qdio_dbf_error);
 308}
 309