xref: /openbmc/linux/drivers/net/ethernet/netronome/nfp/nfp_net_debugfs.c (revision e5f586c763a079349398e2b0c7c271386193ac34)
1 /*
2  * Copyright (C) 2015-2017 Netronome Systems, Inc.
3  *
4  * This software is dual licensed under the GNU General License Version 2,
5  * June 1991 as shown in the file COPYING in the top-level directory of this
6  * source tree or the BSD 2-Clause License provided below.  You have the
7  * option to license this software under the complete terms of either license.
8  *
9  * The BSD 2-Clause License:
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  *      1. Redistributions of source code must retain the above
16  *         copyright notice, this list of conditions and the following
17  *         disclaimer.
18  *
19  *      2. 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/module.h>
35 #include <linux/rtnetlink.h>
36 
37 #include "nfp_net.h"
38 
39 static struct dentry *nfp_dir;
40 
41 static int nfp_net_debugfs_rx_q_read(struct seq_file *file, void *data)
42 {
43 	int fl_rd_p, fl_wr_p, rx_rd_p, rx_wr_p, rxd_cnt;
44 	struct nfp_net_r_vector *r_vec = file->private;
45 	struct nfp_net_rx_ring *rx_ring;
46 	struct nfp_net_rx_desc *rxd;
47 	struct nfp_net *nn;
48 	void *frag;
49 	int i;
50 
51 	rtnl_lock();
52 
53 	if (!r_vec->nfp_net || !r_vec->rx_ring)
54 		goto out;
55 	nn = r_vec->nfp_net;
56 	rx_ring = r_vec->rx_ring;
57 	if (!netif_running(nn->netdev))
58 		goto out;
59 
60 	rxd_cnt = rx_ring->cnt;
61 
62 	fl_rd_p = nfp_qcp_rd_ptr_read(rx_ring->qcp_fl);
63 	fl_wr_p = nfp_qcp_wr_ptr_read(rx_ring->qcp_fl);
64 	rx_rd_p = nfp_qcp_rd_ptr_read(rx_ring->qcp_rx);
65 	rx_wr_p = nfp_qcp_wr_ptr_read(rx_ring->qcp_rx);
66 
67 	seq_printf(file, "RX[%02d]: H_RD=%d H_WR=%d FL_RD=%d FL_WR=%d RX_RD=%d RX_WR=%d\n",
68 		   rx_ring->idx, rx_ring->rd_p, rx_ring->wr_p,
69 		   fl_rd_p, fl_wr_p, rx_rd_p, rx_wr_p);
70 
71 	for (i = 0; i < rxd_cnt; i++) {
72 		rxd = &rx_ring->rxds[i];
73 		seq_printf(file, "%04d: 0x%08x 0x%08x", i,
74 			   rxd->vals[0], rxd->vals[1]);
75 
76 		frag = READ_ONCE(rx_ring->rxbufs[i].frag);
77 		if (frag)
78 			seq_printf(file, " frag=%p", frag);
79 
80 		if (rx_ring->rxbufs[i].dma_addr)
81 			seq_printf(file, " dma_addr=%pad",
82 				   &rx_ring->rxbufs[i].dma_addr);
83 
84 		if (i == rx_ring->rd_p % rxd_cnt)
85 			seq_puts(file, " H_RD ");
86 		if (i == rx_ring->wr_p % rxd_cnt)
87 			seq_puts(file, " H_WR ");
88 		if (i == fl_rd_p % rxd_cnt)
89 			seq_puts(file, " FL_RD");
90 		if (i == fl_wr_p % rxd_cnt)
91 			seq_puts(file, " FL_WR");
92 		if (i == rx_rd_p % rxd_cnt)
93 			seq_puts(file, " RX_RD");
94 		if (i == rx_wr_p % rxd_cnt)
95 			seq_puts(file, " RX_WR");
96 
97 		seq_putc(file, '\n');
98 	}
99 out:
100 	rtnl_unlock();
101 	return 0;
102 }
103 
104 static int nfp_net_debugfs_rx_q_open(struct inode *inode, struct file *f)
105 {
106 	return single_open(f, nfp_net_debugfs_rx_q_read, inode->i_private);
107 }
108 
109 static const struct file_operations nfp_rx_q_fops = {
110 	.owner = THIS_MODULE,
111 	.open = nfp_net_debugfs_rx_q_open,
112 	.release = single_release,
113 	.read = seq_read,
114 	.llseek = seq_lseek
115 };
116 
117 static int nfp_net_debugfs_tx_q_open(struct inode *inode, struct file *f);
118 
119 static const struct file_operations nfp_tx_q_fops = {
120 	.owner = THIS_MODULE,
121 	.open = nfp_net_debugfs_tx_q_open,
122 	.release = single_release,
123 	.read = seq_read,
124 	.llseek = seq_lseek
125 };
126 
127 static int nfp_net_debugfs_tx_q_read(struct seq_file *file, void *data)
128 {
129 	struct nfp_net_r_vector *r_vec = file->private;
130 	struct nfp_net_tx_ring *tx_ring;
131 	struct nfp_net_tx_desc *txd;
132 	int d_rd_p, d_wr_p, txd_cnt;
133 	struct sk_buff *skb;
134 	struct nfp_net *nn;
135 	int i;
136 
137 	rtnl_lock();
138 
139 	if (debugfs_real_fops(file->file) == &nfp_tx_q_fops)
140 		tx_ring = r_vec->tx_ring;
141 	else
142 		tx_ring = r_vec->xdp_ring;
143 	if (!r_vec->nfp_net || !tx_ring)
144 		goto out;
145 	nn = r_vec->nfp_net;
146 	if (!netif_running(nn->netdev))
147 		goto out;
148 
149 	txd_cnt = tx_ring->cnt;
150 
151 	d_rd_p = nfp_qcp_rd_ptr_read(tx_ring->qcp_q);
152 	d_wr_p = nfp_qcp_wr_ptr_read(tx_ring->qcp_q);
153 
154 	seq_printf(file, "TX[%02d]: H_RD=%d H_WR=%d D_RD=%d D_WR=%d\n",
155 		   tx_ring->idx, tx_ring->rd_p, tx_ring->wr_p, d_rd_p, d_wr_p);
156 
157 	for (i = 0; i < txd_cnt; i++) {
158 		txd = &tx_ring->txds[i];
159 		seq_printf(file, "%04d: 0x%08x 0x%08x 0x%08x 0x%08x", i,
160 			   txd->vals[0], txd->vals[1],
161 			   txd->vals[2], txd->vals[3]);
162 
163 		skb = READ_ONCE(tx_ring->txbufs[i].skb);
164 		if (skb) {
165 			if (tx_ring == r_vec->tx_ring)
166 				seq_printf(file, " skb->head=%p skb->data=%p",
167 					   skb->head, skb->data);
168 			else
169 				seq_printf(file, " frag=%p", skb);
170 		}
171 
172 		if (tx_ring->txbufs[i].dma_addr)
173 			seq_printf(file, " dma_addr=%pad",
174 				   &tx_ring->txbufs[i].dma_addr);
175 
176 		if (i == tx_ring->rd_p % txd_cnt)
177 			seq_puts(file, " H_RD");
178 		if (i == tx_ring->wr_p % txd_cnt)
179 			seq_puts(file, " H_WR");
180 		if (i == d_rd_p % txd_cnt)
181 			seq_puts(file, " D_RD");
182 		if (i == d_wr_p % txd_cnt)
183 			seq_puts(file, " D_WR");
184 
185 		seq_putc(file, '\n');
186 	}
187 out:
188 	rtnl_unlock();
189 	return 0;
190 }
191 
192 static int nfp_net_debugfs_tx_q_open(struct inode *inode, struct file *f)
193 {
194 	return single_open(f, nfp_net_debugfs_tx_q_read, inode->i_private);
195 }
196 
197 static const struct file_operations nfp_xdp_q_fops = {
198 	.owner = THIS_MODULE,
199 	.open = nfp_net_debugfs_tx_q_open,
200 	.release = single_release,
201 	.read = seq_read,
202 	.llseek = seq_lseek
203 };
204 
205 void nfp_net_debugfs_port_add(struct nfp_net *nn, struct dentry *ddir, int id)
206 {
207 	struct dentry *queues, *tx, *rx, *xdp;
208 	char name[20];
209 	int i;
210 
211 	if (IS_ERR_OR_NULL(nfp_dir))
212 		return;
213 
214 	sprintf(name, "port%d", id);
215 	nn->debugfs_dir = debugfs_create_dir(name, ddir);
216 	if (IS_ERR_OR_NULL(nn->debugfs_dir))
217 		return;
218 
219 	/* Create queue debugging sub-tree */
220 	queues = debugfs_create_dir("queue", nn->debugfs_dir);
221 	if (IS_ERR_OR_NULL(queues))
222 		return;
223 
224 	rx = debugfs_create_dir("rx", queues);
225 	tx = debugfs_create_dir("tx", queues);
226 	xdp = debugfs_create_dir("xdp", queues);
227 	if (IS_ERR_OR_NULL(rx) || IS_ERR_OR_NULL(tx) || IS_ERR_OR_NULL(xdp))
228 		return;
229 
230 	for (i = 0; i < min(nn->max_rx_rings, nn->max_r_vecs); i++) {
231 		sprintf(name, "%d", i);
232 		debugfs_create_file(name, S_IRUSR, rx,
233 				    &nn->r_vecs[i], &nfp_rx_q_fops);
234 		debugfs_create_file(name, S_IRUSR, xdp,
235 				    &nn->r_vecs[i], &nfp_xdp_q_fops);
236 	}
237 
238 	for (i = 0; i < min(nn->max_tx_rings, nn->max_r_vecs); i++) {
239 		sprintf(name, "%d", i);
240 		debugfs_create_file(name, S_IRUSR, tx,
241 				    &nn->r_vecs[i], &nfp_tx_q_fops);
242 	}
243 }
244 
245 struct dentry *nfp_net_debugfs_device_add(struct pci_dev *pdev)
246 {
247 	struct dentry *dev_dir;
248 
249 	if (IS_ERR_OR_NULL(nfp_dir))
250 		return NULL;
251 
252 	dev_dir = debugfs_create_dir(pci_name(pdev), nfp_dir);
253 	if (IS_ERR_OR_NULL(dev_dir))
254 		return NULL;
255 
256 	return dev_dir;
257 }
258 
259 void nfp_net_debugfs_dir_clean(struct dentry **dir)
260 {
261 	debugfs_remove_recursive(*dir);
262 	*dir = NULL;
263 }
264 
265 void nfp_net_debugfs_create(void)
266 {
267 	nfp_dir = debugfs_create_dir("nfp_net", NULL);
268 }
269 
270 void nfp_net_debugfs_destroy(void)
271 {
272 	debugfs_remove_recursive(nfp_dir);
273 	nfp_dir = NULL;
274 }
275