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