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(q: rx_ring->qcp_fl); |
34 | fl_wr_p = nfp_qcp_wr_ptr_read(q: rx_ring->qcp_fl); |
35 | |
36 | seq_printf(m: file, fmt: "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(m: file, fmt: "%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(m: file, fmt: " frag=%p" , frag); |
50 | |
51 | if (rx_ring->rxbufs[i].dma_addr) |
52 | seq_printf(m: file, fmt: " dma_addr=%pad" , |
53 | &rx_ring->rxbufs[i].dma_addr); |
54 | } else { |
55 | if (rx_ring->xsk_rxbufs[i].dma_addr) |
56 | seq_printf(m: file, fmt: " 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(m: file, s: " H_RD " ); |
62 | if (i == rx_ring->wr_p % rxd_cnt) |
63 | seq_puts(m: file, s: " H_WR " ); |
64 | if (i == fl_rd_p % rxd_cnt) |
65 | seq_puts(m: file, s: " FL_RD" ); |
66 | if (i == fl_wr_p % rxd_cnt) |
67 | seq_puts(m: file, s: " FL_WR" ); |
68 | |
69 | seq_putc(m: file, c: '\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(filp: 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(q: tx_ring->qcp_q); |
100 | d_wr_p = nfp_qcp_wr_ptr_read(q: tx_ring->qcp_q); |
101 | |
102 | seq_printf(m: file, fmt: "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(m: file, fmt: " TXRWB=%llu" , *tx_ring->txrwb); |
109 | seq_putc(m: file, c: '\n'); |
110 | |
111 | nfp_net_debugfs_print_tx_descs(file, dp: &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(ptr: nfp_dir)) |
131 | return; |
132 | |
133 | if (nfp_net_is_data_vnic(nn)) |
134 | sprintf(buf: name, fmt: "vnic%d" , nn->id); |
135 | else |
136 | strcpy(p: name, q: "ctrl-vnic" ); |
137 | nn->debugfs_dir = debugfs_create_dir(name, parent: ddir); |
138 | |
139 | /* Create queue debugging sub-tree */ |
140 | queues = debugfs_create_dir(name: "queue" , parent: nn->debugfs_dir); |
141 | |
142 | rx = debugfs_create_dir(name: "rx" , parent: queues); |
143 | tx = debugfs_create_dir(name: "tx" , parent: queues); |
144 | xdp = debugfs_create_dir(name: "xdp" , parent: queues); |
145 | |
146 | for (i = 0; i < min(nn->max_rx_rings, nn->max_r_vecs); i++) { |
147 | sprintf(buf: name, fmt: "%d" , i); |
148 | debugfs_create_file(name, mode: 0400, parent: rx, |
149 | data: &nn->r_vecs[i], fops: &nfp_rx_q_fops); |
150 | debugfs_create_file(name, mode: 0400, parent: xdp, |
151 | data: &nn->r_vecs[i], fops: &nfp_xdp_q_fops); |
152 | } |
153 | |
154 | for (i = 0; i < min(nn->max_tx_rings, nn->max_r_vecs); i++) { |
155 | sprintf(buf: name, fmt: "%d" , i); |
156 | debugfs_create_file(name, mode: 0400, parent: tx, |
157 | data: &nn->r_vecs[i], fops: &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(name: pci_name(pdev), parent: nfp_dir); |
164 | } |
165 | |
166 | void nfp_net_debugfs_dir_clean(struct dentry **dir) |
167 | { |
168 | debugfs_remove_recursive(dentry: *dir); |
169 | *dir = NULL; |
170 | } |
171 | |
172 | void nfp_net_debugfs_create(void) |
173 | { |
174 | nfp_dir = debugfs_create_dir(name: "nfp_net" , NULL); |
175 | } |
176 | |
177 | void nfp_net_debugfs_destroy(void) |
178 | { |
179 | debugfs_remove_recursive(dentry: nfp_dir); |
180 | nfp_dir = NULL; |
181 | } |
182 | |