linux/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c
<<
>>
Prefs
   1// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
   2/* Copyright (C) 2015-2018 Netronome Systems, Inc. */
   3#include <linux/debugfs.h>
   4#include <linux/module.h>
   5#include <linux/rtnetlink.h>
   6
   7#include "nfp_net.h"
   8
   9static struct dentry *nfp_dir;
  10
  11static int nfp_rx_q_show(struct seq_file *file, void *data)
  12{
  13        struct nfp_net_r_vector *r_vec = file->private;
  14        struct nfp_net_rx_ring *rx_ring;
  15        int fl_rd_p, fl_wr_p, rxd_cnt;
  16        struct nfp_net_rx_desc *rxd;
  17        struct nfp_net *nn;
  18        void *frag;
  19        int i;
  20
  21        rtnl_lock();
  22
  23        if (!r_vec->nfp_net || !r_vec->rx_ring)
  24                goto out;
  25        nn = r_vec->nfp_net;
  26        rx_ring = r_vec->rx_ring;
  27        if (!nfp_net_running(nn))
  28                goto out;
  29
  30        rxd_cnt = rx_ring->cnt;
  31
  32        fl_rd_p = nfp_qcp_rd_ptr_read(rx_ring->qcp_fl);
  33        fl_wr_p = nfp_qcp_wr_ptr_read(rx_ring->qcp_fl);
  34
  35        seq_printf(file, "RX[%02d,%02d]: cnt=%u dma=%pad host=%p   H_RD=%u H_WR=%u FL_RD=%u FL_WR=%u\n",
  36                   rx_ring->idx, rx_ring->fl_qcidx,
  37                   rx_ring->cnt, &rx_ring->dma, rx_ring->rxds,
  38                   rx_ring->rd_p, rx_ring->wr_p, fl_rd_p, fl_wr_p);
  39
  40        for (i = 0; i < rxd_cnt; i++) {
  41                rxd = &rx_ring->rxds[i];
  42                seq_printf(file, "%04d: 0x%08x 0x%08x", i,
  43                           rxd->vals[0], rxd->vals[1]);
  44
  45                frag = READ_ONCE(rx_ring->rxbufs[i].frag);
  46                if (frag)
  47                        seq_printf(file, " frag=%p", frag);
  48
  49                if (rx_ring->rxbufs[i].dma_addr)
  50                        seq_printf(file, " dma_addr=%pad",
  51                                   &rx_ring->rxbufs[i].dma_addr);
  52
  53                if (i == rx_ring->rd_p % rxd_cnt)
  54                        seq_puts(file, " H_RD ");
  55                if (i == rx_ring->wr_p % rxd_cnt)
  56                        seq_puts(file, " H_WR ");
  57                if (i == fl_rd_p % rxd_cnt)
  58                        seq_puts(file, " FL_RD");
  59                if (i == fl_wr_p % rxd_cnt)
  60                        seq_puts(file, " FL_WR");
  61
  62                seq_putc(file, '\n');
  63        }
  64out:
  65        rtnl_unlock();
  66        return 0;
  67}
  68DEFINE_SHOW_ATTRIBUTE(nfp_rx_q);
  69
  70static int nfp_tx_q_show(struct seq_file *file, void *data);
  71DEFINE_SHOW_ATTRIBUTE(nfp_tx_q);
  72
  73static int nfp_tx_q_show(struct seq_file *file, void *data)
  74{
  75        struct nfp_net_r_vector *r_vec = file->private;
  76        struct nfp_net_tx_ring *tx_ring;
  77        struct nfp_net_tx_desc *txd;
  78        int d_rd_p, d_wr_p, txd_cnt;
  79        struct nfp_net *nn;
  80        int i;
  81
  82        rtnl_lock();
  83
  84        if (debugfs_real_fops(file->file) == &nfp_tx_q_fops)
  85                tx_ring = r_vec->tx_ring;
  86        else
  87                tx_ring = r_vec->xdp_ring;
  88        if (!r_vec->nfp_net || !tx_ring)
  89                goto out;
  90        nn = r_vec->nfp_net;
  91        if (!nfp_net_running(nn))
  92                goto out;
  93
  94        txd_cnt = tx_ring->cnt;
  95
  96        d_rd_p = nfp_qcp_rd_ptr_read(tx_ring->qcp_q);
  97        d_wr_p = nfp_qcp_wr_ptr_read(tx_ring->qcp_q);
  98
  99        seq_printf(file, "TX[%02d,%02d%s]: cnt=%u dma=%pad host=%p   H_RD=%u H_WR=%u D_RD=%u D_WR=%u\n",
 100                   tx_ring->idx, tx_ring->qcidx,
 101                   tx_ring == r_vec->tx_ring ? "" : "xdp",
 102                   tx_ring->cnt, &tx_ring->dma, tx_ring->txds,
 103                   tx_ring->rd_p, tx_ring->wr_p, d_rd_p, d_wr_p);
 104
 105        for (i = 0; i < txd_cnt; i++) {
 106                txd = &tx_ring->txds[i];
 107                seq_printf(file, "%04d: 0x%08x 0x%08x 0x%08x 0x%08x", i,
 108                           txd->vals[0], txd->vals[1],
 109                           txd->vals[2], txd->vals[3]);
 110
 111                if (tx_ring == r_vec->tx_ring) {
 112                        struct sk_buff *skb = READ_ONCE(tx_ring->txbufs[i].skb);
 113
 114                        if (skb)
 115                                seq_printf(file, " skb->head=%p skb->data=%p",
 116                                           skb->head, skb->data);
 117                } else {
 118                        seq_printf(file, " frag=%p",
 119                                   READ_ONCE(tx_ring->txbufs[i].frag));
 120                }
 121
 122                if (tx_ring->txbufs[i].dma_addr)
 123                        seq_printf(file, " dma_addr=%pad",
 124                                   &tx_ring->txbufs[i].dma_addr);
 125
 126                if (i == tx_ring->rd_p % txd_cnt)
 127                        seq_puts(file, " H_RD");
 128                if (i == tx_ring->wr_p % txd_cnt)
 129                        seq_puts(file, " H_WR");
 130                if (i == d_rd_p % txd_cnt)
 131                        seq_puts(file, " D_RD");
 132                if (i == d_wr_p % txd_cnt)
 133                        seq_puts(file, " D_WR");
 134
 135                seq_putc(file, '\n');
 136        }
 137out:
 138        rtnl_unlock();
 139        return 0;
 140}
 141
 142static int nfp_xdp_q_show(struct seq_file *file, void *data)
 143{
 144        return nfp_tx_q_show(file, data);
 145}
 146DEFINE_SHOW_ATTRIBUTE(nfp_xdp_q);
 147
 148void nfp_net_debugfs_vnic_add(struct nfp_net *nn, struct dentry *ddir)
 149{
 150        struct dentry *queues, *tx, *rx, *xdp;
 151        char name[20];
 152        int i;
 153
 154        if (IS_ERR_OR_NULL(nfp_dir))
 155                return;
 156
 157        if (nfp_net_is_data_vnic(nn))
 158                sprintf(name, "vnic%d", nn->id);
 159        else
 160                strcpy(name, "ctrl-vnic");
 161        nn->debugfs_dir = debugfs_create_dir(name, ddir);
 162
 163        /* Create queue debugging sub-tree */
 164        queues = debugfs_create_dir("queue", nn->debugfs_dir);
 165
 166        rx = debugfs_create_dir("rx", queues);
 167        tx = debugfs_create_dir("tx", queues);
 168        xdp = debugfs_create_dir("xdp", queues);
 169
 170        for (i = 0; i < min(nn->max_rx_rings, nn->max_r_vecs); i++) {
 171                sprintf(name, "%d", i);
 172                debugfs_create_file(name, 0400, rx,
 173                                    &nn->r_vecs[i], &nfp_rx_q_fops);
 174                debugfs_create_file(name, 0400, xdp,
 175                                    &nn->r_vecs[i], &nfp_xdp_q_fops);
 176        }
 177
 178        for (i = 0; i < min(nn->max_tx_rings, nn->max_r_vecs); i++) {
 179                sprintf(name, "%d", i);
 180                debugfs_create_file(name, 0400, tx,
 181                                    &nn->r_vecs[i], &nfp_tx_q_fops);
 182        }
 183}
 184
 185struct dentry *nfp_net_debugfs_device_add(struct pci_dev *pdev)
 186{
 187        return debugfs_create_dir(pci_name(pdev), nfp_dir);
 188}
 189
 190void nfp_net_debugfs_dir_clean(struct dentry **dir)
 191{
 192        debugfs_remove_recursive(*dir);
 193        *dir = NULL;
 194}
 195
 196void nfp_net_debugfs_create(void)
 197{
 198        nfp_dir = debugfs_create_dir("nfp_net", NULL);
 199}
 200
 201void nfp_net_debugfs_destroy(void)
 202{
 203        debugfs_remove_recursive(nfp_dir);
 204        nfp_dir = NULL;
 205}
 206