[S390] qdio: convert global statistics to per-device stats
[linux-2.6.git] / drivers / s390 / cio / qdio_debug.c
index 7676997..f49761f 100644 (file)
@@ -55,13 +55,11 @@ static int qstat_show(struct seq_file *m, void *v)
        if (!q)
                return 0;
 
-       seq_printf(m, "device state indicator: %d\n", *(u32 *)q->irq_ptr->dsci);
-       seq_printf(m, "nr_used: %d\n", atomic_read(&q->nr_buf_used));
-       seq_printf(m, "ftc: %d\n", q->first_to_check);
-       seq_printf(m, "last_move: %d\n", q->last_move);
-       seq_printf(m, "polling: %d\n", q->u.in.polling);
-       seq_printf(m, "ack start: %d\n", q->u.in.ack_start);
-       seq_printf(m, "ack count: %d\n", q->u.in.ack_count);
+       seq_printf(m, "DSCI: %d   nr_used: %d\n",
+                  *(u32 *)q->irq_ptr->dsci, atomic_read(&q->nr_buf_used));
+       seq_printf(m, "ftc: %d  last_move: %d\n", q->first_to_check, q->last_move);
+       seq_printf(m, "polling: %d  ack start: %d  ack count: %d\n",
+                  q->u.in.polling, q->u.in.ack_start, q->u.in.ack_count);
        seq_printf(m, "slsb buffer states:\n");
        seq_printf(m, "|0      |8      |16     |24     |32     |40     |48     |56  63|\n");
 
@@ -110,7 +108,6 @@ static ssize_t qstat_seq_write(struct file *file, const char __user *buf,
 
        if (!q)
                return 0;
-
        if (q->is_input_q)
                xchg(q->irq_ptr->dsci, 1);
        local_bh_disable();
@@ -134,6 +131,98 @@ static const struct file_operations debugfs_fops = {
        .release = single_release,
 };
 
+static char *qperf_names[] = {
+       "Assumed adapter interrupts",
+       "QDIO interrupts",
+       "Requested PCIs",
+       "Inbound tasklet runs",
+       "Inbound tasklet resched",
+       "Inbound tasklet resched2",
+       "Outbound tasklet runs",
+       "SIGA read",
+       "SIGA write",
+       "SIGA sync",
+       "Inbound calls",
+       "Inbound handler",
+       "Inbound stop_polling",
+       "Inbound queue full",
+       "Outbound calls",
+       "Outbound handler",
+       "Outbound fast_requeue",
+       "Outbound target_full",
+       "QEBSM eqbs",
+       "QEBSM eqbs partial",
+       "QEBSM sqbs",
+       "QEBSM sqbs partial"
+};
+
+static int qperf_show(struct seq_file *m, void *v)
+{
+       struct qdio_irq *irq_ptr = m->private;
+       unsigned int *stat;
+       int i;
+
+       if (!irq_ptr)
+               return 0;
+       if (!irq_ptr->perf_stat_enabled) {
+               seq_printf(m, "disabled\n");
+               return 0;
+       }
+       stat = (unsigned int *)&irq_ptr->perf_stat;
+
+       for (i = 0; i < ARRAY_SIZE(qperf_names); i++)
+               seq_printf(m, "%26s:\t%u\n",
+                          qperf_names[i], *(stat + i));
+       return 0;
+}
+
+static ssize_t qperf_seq_write(struct file *file, const char __user *ubuf,
+                              size_t count, loff_t *off)
+{
+       struct seq_file *seq = file->private_data;
+       struct qdio_irq *irq_ptr = seq->private;
+       unsigned long val;
+       char buf[8];
+       int ret;
+
+       if (!irq_ptr)
+               return 0;
+       if (count >= sizeof(buf))
+               return -EINVAL;
+       if (copy_from_user(&buf, ubuf, count))
+               return -EFAULT;
+       buf[count] = 0;
+
+       ret = strict_strtoul(buf, 10, &val);
+       if (ret < 0)
+               return ret;
+
+       switch (val) {
+       case 0:
+               irq_ptr->perf_stat_enabled = 0;
+               memset(&irq_ptr->perf_stat, 0, sizeof(irq_ptr->perf_stat));
+               break;
+       case 1:
+               irq_ptr->perf_stat_enabled = 1;
+               break;
+       }
+       return count;
+}
+
+static int qperf_seq_open(struct inode *inode, struct file *filp)
+{
+       return single_open(filp, qperf_show,
+                          filp->f_path.dentry->d_inode->i_private);
+}
+
+static struct file_operations debugfs_perf_fops = {
+       .owner   = THIS_MODULE,
+       .open    = qperf_seq_open,
+       .read    = seq_read,
+       .write   = qperf_seq_write,
+       .llseek  = seq_lseek,
+       .release = single_release,
+};
 static void setup_debugfs_entry(struct qdio_q *q, struct ccw_device *cdev)
 {
        char name[QDIO_DEBUGFS_NAME_LEN];
@@ -156,6 +245,14 @@ void qdio_setup_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cdev)
                                                  debugfs_root);
        if (IS_ERR(irq_ptr->debugfs_dev))
                irq_ptr->debugfs_dev = NULL;
+
+       irq_ptr->debugfs_perf = debugfs_create_file("statistics",
+                               S_IFREG | S_IRUGO | S_IWUSR,
+                               irq_ptr->debugfs_dev, irq_ptr,
+                               &debugfs_perf_fops);
+       if (IS_ERR(irq_ptr->debugfs_perf))
+               irq_ptr->debugfs_perf = NULL;
+
        for_each_input_queue(irq_ptr, q, i)
                setup_debugfs_entry(q, cdev);
        for_each_output_queue(irq_ptr, q, i)
@@ -171,6 +268,7 @@ void qdio_shutdown_debug_entries(struct qdio_irq *irq_ptr, struct ccw_device *cd
                debugfs_remove(q->debugfs_q);
        for_each_output_queue(irq_ptr, q, i)
                debugfs_remove(q->debugfs_q);
+       debugfs_remove(irq_ptr->debugfs_perf);
        debugfs_remove(irq_ptr->debugfs_dev);
 }