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