linux/drivers/infiniband/hw/qib/qib_debugfs.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2013 - 2017 Intel Corporation.  All rights reserved.
   3 *
   4 * This software is available to you under a choice of one of two
   5 * licenses.  You may choose to be licensed under the terms of the GNU
   6 * General Public License (GPL) Version 2, available from the file
   7 * COPYING in the main directory of this source tree, or the
   8 * OpenIB.org BSD license below:
   9 *
  10 *     Redistribution and use in source and binary forms, with or
  11 *     without modification, are permitted provided that the following
  12 *     conditions are met:
  13 *
  14 *      - Redistributions of source code must retain the above
  15 *        copyright notice, this list of conditions and the following
  16 *        disclaimer.
  17 *
  18 *      - Redistributions in binary form must reproduce the above
  19 *        copyright notice, this list of conditions and the following
  20 *        disclaimer in the documentation and/or other materials
  21 *        provided with the distribution.
  22 *
  23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
  27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
  28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  30 * SOFTWARE.
  31 */
  32#include <linux/debugfs.h>
  33#include <linux/seq_file.h>
  34#include <linux/kernel.h>
  35#include <linux/export.h>
  36
  37#include "qib.h"
  38#include "qib_verbs.h"
  39#include "qib_debugfs.h"
  40
  41static struct dentry *qib_dbg_root;
  42
  43#define DEBUGFS_FILE(name) \
  44static const struct seq_operations _##name##_seq_ops = { \
  45        .start = _##name##_seq_start, \
  46        .next  = _##name##_seq_next, \
  47        .stop  = _##name##_seq_stop, \
  48        .show  = _##name##_seq_show \
  49}; \
  50static int _##name##_open(struct inode *inode, struct file *s) \
  51{ \
  52        struct seq_file *seq; \
  53        int ret; \
  54        ret =  seq_open(s, &_##name##_seq_ops); \
  55        if (ret) \
  56                return ret; \
  57        seq = s->private_data; \
  58        seq->private = inode->i_private; \
  59        return 0; \
  60} \
  61static const struct file_operations _##name##_file_ops = { \
  62        .owner   = THIS_MODULE, \
  63        .open    = _##name##_open, \
  64        .read    = seq_read, \
  65        .llseek  = seq_lseek, \
  66        .release = seq_release \
  67};
  68
  69static void *_opcode_stats_seq_start(struct seq_file *s, loff_t *pos)
  70{
  71        struct qib_opcode_stats_perctx *opstats;
  72
  73        if (*pos >= ARRAY_SIZE(opstats->stats))
  74                return NULL;
  75        return pos;
  76}
  77
  78static void *_opcode_stats_seq_next(struct seq_file *s, void *v, loff_t *pos)
  79{
  80        struct qib_opcode_stats_perctx *opstats;
  81
  82        ++*pos;
  83        if (*pos >= ARRAY_SIZE(opstats->stats))
  84                return NULL;
  85        return pos;
  86}
  87
  88
  89static void _opcode_stats_seq_stop(struct seq_file *s, void *v)
  90{
  91        /* nothing allocated */
  92}
  93
  94static int _opcode_stats_seq_show(struct seq_file *s, void *v)
  95{
  96        loff_t *spos = v;
  97        loff_t i = *spos, j;
  98        u64 n_packets = 0, n_bytes = 0;
  99        struct qib_ibdev *ibd = (struct qib_ibdev *)s->private;
 100        struct qib_devdata *dd = dd_from_dev(ibd);
 101
 102        for (j = 0; j < dd->first_user_ctxt; j++) {
 103                if (!dd->rcd[j])
 104                        continue;
 105                n_packets += dd->rcd[j]->opstats->stats[i].n_packets;
 106                n_bytes += dd->rcd[j]->opstats->stats[i].n_bytes;
 107        }
 108        if (!n_packets && !n_bytes)
 109                return SEQ_SKIP;
 110        seq_printf(s, "%02llx %llu/%llu\n", i,
 111                (unsigned long long) n_packets,
 112                (unsigned long long) n_bytes);
 113
 114        return 0;
 115}
 116
 117DEBUGFS_FILE(opcode_stats)
 118
 119static void *_ctx_stats_seq_start(struct seq_file *s, loff_t *pos)
 120{
 121        struct qib_ibdev *ibd = (struct qib_ibdev *)s->private;
 122        struct qib_devdata *dd = dd_from_dev(ibd);
 123
 124        if (!*pos)
 125                return SEQ_START_TOKEN;
 126        if (*pos >= dd->first_user_ctxt)
 127                return NULL;
 128        return pos;
 129}
 130
 131static void *_ctx_stats_seq_next(struct seq_file *s, void *v, loff_t *pos)
 132{
 133        struct qib_ibdev *ibd = (struct qib_ibdev *)s->private;
 134        struct qib_devdata *dd = dd_from_dev(ibd);
 135
 136        if (v == SEQ_START_TOKEN)
 137                return pos;
 138
 139        ++*pos;
 140        if (*pos >= dd->first_user_ctxt)
 141                return NULL;
 142        return pos;
 143}
 144
 145static void _ctx_stats_seq_stop(struct seq_file *s, void *v)
 146{
 147        /* nothing allocated */
 148}
 149
 150static int _ctx_stats_seq_show(struct seq_file *s, void *v)
 151{
 152        loff_t *spos;
 153        loff_t i, j;
 154        u64 n_packets = 0;
 155        struct qib_ibdev *ibd = (struct qib_ibdev *)s->private;
 156        struct qib_devdata *dd = dd_from_dev(ibd);
 157
 158        if (v == SEQ_START_TOKEN) {
 159                seq_puts(s, "Ctx:npkts\n");
 160                return 0;
 161        }
 162
 163        spos = v;
 164        i = *spos;
 165
 166        if (!dd->rcd[i])
 167                return SEQ_SKIP;
 168
 169        for (j = 0; j < ARRAY_SIZE(dd->rcd[i]->opstats->stats); j++)
 170                n_packets += dd->rcd[i]->opstats->stats[j].n_packets;
 171
 172        if (!n_packets)
 173                return SEQ_SKIP;
 174
 175        seq_printf(s, "  %llu:%llu\n", i, n_packets);
 176        return 0;
 177}
 178
 179DEBUGFS_FILE(ctx_stats)
 180
 181static void *_qp_stats_seq_start(struct seq_file *s, loff_t *pos)
 182        __acquires(RCU)
 183{
 184        struct rvt_qp_iter *iter;
 185        loff_t n = *pos;
 186
 187        iter = rvt_qp_iter_init(s->private, 0, NULL);
 188
 189        /* stop calls rcu_read_unlock */
 190        rcu_read_lock();
 191
 192        if (!iter)
 193                return NULL;
 194
 195        do {
 196                if (rvt_qp_iter_next(iter)) {
 197                        kfree(iter);
 198                        return NULL;
 199                }
 200        } while (n--);
 201
 202        return iter;
 203}
 204
 205static void *_qp_stats_seq_next(struct seq_file *s, void *iter_ptr,
 206                                   loff_t *pos)
 207        __must_hold(RCU)
 208{
 209        struct rvt_qp_iter *iter = iter_ptr;
 210
 211        (*pos)++;
 212
 213        if (rvt_qp_iter_next(iter)) {
 214                kfree(iter);
 215                return NULL;
 216        }
 217
 218        return iter;
 219}
 220
 221static void _qp_stats_seq_stop(struct seq_file *s, void *iter_ptr)
 222        __releases(RCU)
 223{
 224        rcu_read_unlock();
 225}
 226
 227static int _qp_stats_seq_show(struct seq_file *s, void *iter_ptr)
 228{
 229        struct rvt_qp_iter *iter = iter_ptr;
 230
 231        if (!iter)
 232                return 0;
 233
 234        qib_qp_iter_print(s, iter);
 235
 236        return 0;
 237}
 238
 239DEBUGFS_FILE(qp_stats)
 240
 241void qib_dbg_ibdev_init(struct qib_ibdev *ibd)
 242{
 243        struct dentry *root;
 244        char name[10];
 245
 246        snprintf(name, sizeof(name), "qib%d", dd_from_dev(ibd)->unit);
 247        root = debugfs_create_dir(name, qib_dbg_root);
 248        ibd->qib_ibdev_dbg = root;
 249
 250        debugfs_create_file("opcode_stats", 0400, root, ibd,
 251                            &_opcode_stats_file_ops);
 252        debugfs_create_file("ctx_stats", 0400, root, ibd, &_ctx_stats_file_ops);
 253        debugfs_create_file("qp_stats", 0400, root, ibd, &_qp_stats_file_ops);
 254}
 255
 256void qib_dbg_ibdev_exit(struct qib_ibdev *ibd)
 257{
 258        if (!qib_dbg_root)
 259                goto out;
 260        debugfs_remove_recursive(ibd->qib_ibdev_dbg);
 261out:
 262        ibd->qib_ibdev_dbg = NULL;
 263}
 264
 265void qib_dbg_init(void)
 266{
 267        qib_dbg_root = debugfs_create_dir(QIB_DRV_NAME, NULL);
 268}
 269
 270void qib_dbg_exit(void)
 271{
 272        debugfs_remove_recursive(qib_dbg_root);
 273        qib_dbg_root = NULL;
 274}
 275