linux/arch/s390/pci/pci_debug.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 *  Copyright IBM Corp. 2012,2015
   4 *
   5 *  Author(s):
   6 *    Jan Glauber <jang@linux.vnet.ibm.com>
   7 */
   8
   9#define KMSG_COMPONENT "zpci"
  10#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
  11
  12#include <linux/kernel.h>
  13#include <linux/seq_file.h>
  14#include <linux/debugfs.h>
  15#include <linux/export.h>
  16#include <linux/pci.h>
  17#include <asm/debug.h>
  18
  19#include <asm/pci_dma.h>
  20
  21static struct dentry *debugfs_root;
  22debug_info_t *pci_debug_msg_id;
  23EXPORT_SYMBOL_GPL(pci_debug_msg_id);
  24debug_info_t *pci_debug_err_id;
  25EXPORT_SYMBOL_GPL(pci_debug_err_id);
  26
  27static char *pci_common_names[] = {
  28        "Load operations",
  29        "Store operations",
  30        "Store block operations",
  31        "Refresh operations",
  32};
  33
  34static char *pci_fmt0_names[] = {
  35        "DMA read bytes",
  36        "DMA write bytes",
  37};
  38
  39static char *pci_fmt1_names[] = {
  40        "Received bytes",
  41        "Received packets",
  42        "Transmitted bytes",
  43        "Transmitted packets",
  44};
  45
  46static char *pci_fmt2_names[] = {
  47        "Consumed work units",
  48        "Maximum work units",
  49};
  50
  51static char *pci_sw_names[] = {
  52        "Allocated pages",
  53        "Mapped pages",
  54        "Unmapped pages",
  55};
  56
  57static void pci_fmb_show(struct seq_file *m, char *name[], int length,
  58                         u64 *data)
  59{
  60        int i;
  61
  62        for (i = 0; i < length; i++, data++)
  63                seq_printf(m, "%26s:\t%llu\n", name[i], *data);
  64}
  65
  66static void pci_sw_counter_show(struct seq_file *m)
  67{
  68        struct zpci_dev *zdev = m->private;
  69        atomic64_t *counter = &zdev->allocated_pages;
  70        int i;
  71
  72        for (i = 0; i < ARRAY_SIZE(pci_sw_names); i++, counter++)
  73                seq_printf(m, "%26s:\t%lu\n", pci_sw_names[i],
  74                           atomic64_read(counter));
  75}
  76
  77static int pci_perf_show(struct seq_file *m, void *v)
  78{
  79        struct zpci_dev *zdev = m->private;
  80
  81        if (!zdev)
  82                return 0;
  83
  84        mutex_lock(&zdev->lock);
  85        if (!zdev->fmb) {
  86                mutex_unlock(&zdev->lock);
  87                seq_puts(m, "FMB statistics disabled\n");
  88                return 0;
  89        }
  90
  91        /* header */
  92        seq_printf(m, "FMB @ %p\n", zdev->fmb);
  93        seq_printf(m, "Update interval: %u ms\n", zdev->fmb_update);
  94        seq_printf(m, "Samples: %u\n", zdev->fmb->samples);
  95        seq_printf(m, "Last update TOD: %Lx\n", zdev->fmb->last_update);
  96
  97        pci_fmb_show(m, pci_common_names, ARRAY_SIZE(pci_common_names),
  98                     &zdev->fmb->ld_ops);
  99
 100        switch (zdev->fmb->format) {
 101        case 0:
 102                if (!(zdev->fmb->fmt_ind & ZPCI_FMB_DMA_COUNTER_VALID))
 103                        break;
 104                pci_fmb_show(m, pci_fmt0_names, ARRAY_SIZE(pci_fmt0_names),
 105                             &zdev->fmb->fmt0.dma_rbytes);
 106                break;
 107        case 1:
 108                pci_fmb_show(m, pci_fmt1_names, ARRAY_SIZE(pci_fmt1_names),
 109                             &zdev->fmb->fmt1.rx_bytes);
 110                break;
 111        case 2:
 112                pci_fmb_show(m, pci_fmt2_names, ARRAY_SIZE(pci_fmt2_names),
 113                             &zdev->fmb->fmt2.consumed_work_units);
 114                break;
 115        default:
 116                seq_puts(m, "Unknown format\n");
 117        }
 118
 119        pci_sw_counter_show(m);
 120        mutex_unlock(&zdev->lock);
 121        return 0;
 122}
 123
 124static ssize_t pci_perf_seq_write(struct file *file, const char __user *ubuf,
 125                                  size_t count, loff_t *off)
 126{
 127        struct zpci_dev *zdev = ((struct seq_file *) file->private_data)->private;
 128        unsigned long val;
 129        int rc;
 130
 131        if (!zdev)
 132                return 0;
 133
 134        rc = kstrtoul_from_user(ubuf, count, 10, &val);
 135        if (rc)
 136                return rc;
 137
 138        mutex_lock(&zdev->lock);
 139        switch (val) {
 140        case 0:
 141                rc = zpci_fmb_disable_device(zdev);
 142                break;
 143        case 1:
 144                rc = zpci_fmb_enable_device(zdev);
 145                break;
 146        }
 147        mutex_unlock(&zdev->lock);
 148        return rc ? rc : count;
 149}
 150
 151static int pci_perf_seq_open(struct inode *inode, struct file *filp)
 152{
 153        return single_open(filp, pci_perf_show,
 154                           file_inode(filp)->i_private);
 155}
 156
 157static const struct file_operations debugfs_pci_perf_fops = {
 158        .open    = pci_perf_seq_open,
 159        .read    = seq_read,
 160        .write   = pci_perf_seq_write,
 161        .llseek  = seq_lseek,
 162        .release = single_release,
 163};
 164
 165void zpci_debug_init_device(struct zpci_dev *zdev, const char *name)
 166{
 167        zdev->debugfs_dev = debugfs_create_dir(name, debugfs_root);
 168        if (IS_ERR(zdev->debugfs_dev))
 169                zdev->debugfs_dev = NULL;
 170
 171        zdev->debugfs_perf = debugfs_create_file("statistics",
 172                                S_IFREG | S_IRUGO | S_IWUSR,
 173                                zdev->debugfs_dev, zdev,
 174                                &debugfs_pci_perf_fops);
 175        if (IS_ERR(zdev->debugfs_perf))
 176                zdev->debugfs_perf = NULL;
 177}
 178
 179void zpci_debug_exit_device(struct zpci_dev *zdev)
 180{
 181        debugfs_remove(zdev->debugfs_perf);
 182        debugfs_remove(zdev->debugfs_dev);
 183}
 184
 185int __init zpci_debug_init(void)
 186{
 187        /* event trace buffer */
 188        pci_debug_msg_id = debug_register("pci_msg", 8, 1, 8 * sizeof(long));
 189        if (!pci_debug_msg_id)
 190                return -EINVAL;
 191        debug_register_view(pci_debug_msg_id, &debug_sprintf_view);
 192        debug_set_level(pci_debug_msg_id, 3);
 193
 194        /* error log */
 195        pci_debug_err_id = debug_register("pci_error", 2, 1, 16);
 196        if (!pci_debug_err_id)
 197                return -EINVAL;
 198        debug_register_view(pci_debug_err_id, &debug_hex_ascii_view);
 199        debug_set_level(pci_debug_err_id, 6);
 200
 201        debugfs_root = debugfs_create_dir("pci", NULL);
 202        return 0;
 203}
 204
 205void zpci_debug_exit(void)
 206{
 207        debug_unregister(pci_debug_msg_id);
 208        debug_unregister(pci_debug_err_id);
 209        debugfs_remove(debugfs_root);
 210}
 211