1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
2 /* Copyright 2015 Freescale Semiconductor Inc.
3  * Copyright 2018-2019 NXP
4  */
5 #include <linux/module.h>
6 #include <linux/debugfs.h>
7 #include "dpaa2-eth.h"
8 #include "dpaa2-eth-debugfs.h"
9 
10 #define DPAA2_ETH_DBG_ROOT "dpaa2-eth"
11 
12 static struct dentry *dpaa2_dbg_root;
13 
14 static int dpaa2_dbg_cpu_show(struct seq_file *file, void *offset)
15 {
16 	struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)file->private;
17 	struct rtnl_link_stats64 *stats;
18 	struct dpaa2_eth_drv_stats *extras;
19 	int i;
20 
21 	seq_printf(file, "Per-CPU stats for %s\n", priv->net_dev->name);
22 	seq_printf(file, "%s%16s%16s%16s%16s%16s%16s%16s%16s%16s\n",
23 		   "CPU", "Rx", "Rx Err", "Rx SG", "Tx", "Tx Err", "Tx conf",
24 		   "Tx SG", "Tx realloc", "Enq busy");
25 
26 	for_each_online_cpu(i) {
27 		stats = per_cpu_ptr(priv->percpu_stats, i);
28 		extras = per_cpu_ptr(priv->percpu_extras, i);
29 		seq_printf(file, "%3d%16llu%16llu%16llu%16llu%16llu%16llu%16llu%16llu%16llu\n",
30 			   i,
31 			   stats->rx_packets,
32 			   stats->rx_errors,
33 			   extras->rx_sg_frames,
34 			   stats->tx_packets,
35 			   stats->tx_errors,
36 			   extras->tx_conf_frames,
37 			   extras->tx_sg_frames,
38 			   extras->tx_reallocs,
39 			   extras->tx_portal_busy);
40 	}
41 
42 	return 0;
43 }
44 
45 static int dpaa2_dbg_cpu_open(struct inode *inode, struct file *file)
46 {
47 	int err;
48 	struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)inode->i_private;
49 
50 	err = single_open(file, dpaa2_dbg_cpu_show, priv);
51 	if (err < 0)
52 		netdev_err(priv->net_dev, "single_open() failed\n");
53 
54 	return err;
55 }
56 
57 static const struct file_operations dpaa2_dbg_cpu_ops = {
58 	.open = dpaa2_dbg_cpu_open,
59 	.read = seq_read,
60 	.llseek = seq_lseek,
61 	.release = single_release,
62 };
63 
64 static char *fq_type_to_str(struct dpaa2_eth_fq *fq)
65 {
66 	switch (fq->type) {
67 	case DPAA2_RX_FQ:
68 		return "Rx";
69 	case DPAA2_TX_CONF_FQ:
70 		return "Tx conf";
71 	default:
72 		return "N/A";
73 	}
74 }
75 
76 static int dpaa2_dbg_fqs_show(struct seq_file *file, void *offset)
77 {
78 	struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)file->private;
79 	struct dpaa2_eth_fq *fq;
80 	u32 fcnt, bcnt;
81 	int i, err;
82 
83 	seq_printf(file, "FQ stats for %s:\n", priv->net_dev->name);
84 	seq_printf(file, "%s%16s%16s%16s%16s\n",
85 		   "VFQID", "CPU", "Type", "Frames", "Pending frames");
86 
87 	for (i = 0; i <  priv->num_fqs; i++) {
88 		fq = &priv->fq[i];
89 		err = dpaa2_io_query_fq_count(NULL, fq->fqid, &fcnt, &bcnt);
90 		if (err)
91 			fcnt = 0;
92 
93 		seq_printf(file, "%5d%16d%16s%16llu%16u\n",
94 			   fq->fqid,
95 			   fq->target_cpu,
96 			   fq_type_to_str(fq),
97 			   fq->stats.frames,
98 			   fcnt);
99 	}
100 
101 	return 0;
102 }
103 
104 static int dpaa2_dbg_fqs_open(struct inode *inode, struct file *file)
105 {
106 	int err;
107 	struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)inode->i_private;
108 
109 	err = single_open(file, dpaa2_dbg_fqs_show, priv);
110 	if (err < 0)
111 		netdev_err(priv->net_dev, "single_open() failed\n");
112 
113 	return err;
114 }
115 
116 static const struct file_operations dpaa2_dbg_fq_ops = {
117 	.open = dpaa2_dbg_fqs_open,
118 	.read = seq_read,
119 	.llseek = seq_lseek,
120 	.release = single_release,
121 };
122 
123 static int dpaa2_dbg_ch_show(struct seq_file *file, void *offset)
124 {
125 	struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)file->private;
126 	struct dpaa2_eth_channel *ch;
127 	int i;
128 
129 	seq_printf(file, "Channel stats for %s:\n", priv->net_dev->name);
130 	seq_printf(file, "%s%16s%16s%16s%16s\n",
131 		   "CHID", "CPU", "Deq busy", "CDANs", "Buf count");
132 
133 	for (i = 0; i < priv->num_channels; i++) {
134 		ch = priv->channel[i];
135 		seq_printf(file, "%4d%16d%16llu%16llu%16d\n",
136 			   ch->ch_id,
137 			   ch->nctx.desired_cpu,
138 			   ch->stats.dequeue_portal_busy,
139 			   ch->stats.cdan,
140 			   ch->buf_count);
141 	}
142 
143 	return 0;
144 }
145 
146 static int dpaa2_dbg_ch_open(struct inode *inode, struct file *file)
147 {
148 	int err;
149 	struct dpaa2_eth_priv *priv = (struct dpaa2_eth_priv *)inode->i_private;
150 
151 	err = single_open(file, dpaa2_dbg_ch_show, priv);
152 	if (err < 0)
153 		netdev_err(priv->net_dev, "single_open() failed\n");
154 
155 	return err;
156 }
157 
158 static const struct file_operations dpaa2_dbg_ch_ops = {
159 	.open = dpaa2_dbg_ch_open,
160 	.read = seq_read,
161 	.llseek = seq_lseek,
162 	.release = single_release,
163 };
164 
165 void dpaa2_dbg_add(struct dpaa2_eth_priv *priv)
166 {
167 	if (!dpaa2_dbg_root)
168 		return;
169 
170 	/* Create a directory for the interface */
171 	priv->dbg.dir = debugfs_create_dir(priv->net_dev->name,
172 					   dpaa2_dbg_root);
173 	if (!priv->dbg.dir) {
174 		netdev_err(priv->net_dev, "debugfs_create_dir() failed\n");
175 		return;
176 	}
177 
178 	/* per-cpu stats file */
179 	priv->dbg.cpu_stats = debugfs_create_file("cpu_stats", 0444,
180 						  priv->dbg.dir, priv,
181 						  &dpaa2_dbg_cpu_ops);
182 	if (!priv->dbg.cpu_stats) {
183 		netdev_err(priv->net_dev, "debugfs_create_file() failed\n");
184 		goto err_cpu_stats;
185 	}
186 
187 	/* per-fq stats file */
188 	priv->dbg.fq_stats = debugfs_create_file("fq_stats", 0444,
189 						 priv->dbg.dir, priv,
190 						 &dpaa2_dbg_fq_ops);
191 	if (!priv->dbg.fq_stats) {
192 		netdev_err(priv->net_dev, "debugfs_create_file() failed\n");
193 		goto err_fq_stats;
194 	}
195 
196 	/* per-fq stats file */
197 	priv->dbg.ch_stats = debugfs_create_file("ch_stats", 0444,
198 						 priv->dbg.dir, priv,
199 						 &dpaa2_dbg_ch_ops);
200 	if (!priv->dbg.fq_stats) {
201 		netdev_err(priv->net_dev, "debugfs_create_file() failed\n");
202 		goto err_ch_stats;
203 	}
204 
205 	return;
206 
207 err_ch_stats:
208 	debugfs_remove(priv->dbg.fq_stats);
209 err_fq_stats:
210 	debugfs_remove(priv->dbg.cpu_stats);
211 err_cpu_stats:
212 	debugfs_remove(priv->dbg.dir);
213 }
214 
215 void dpaa2_dbg_remove(struct dpaa2_eth_priv *priv)
216 {
217 	debugfs_remove(priv->dbg.fq_stats);
218 	debugfs_remove(priv->dbg.ch_stats);
219 	debugfs_remove(priv->dbg.cpu_stats);
220 	debugfs_remove(priv->dbg.dir);
221 }
222 
223 void dpaa2_eth_dbg_init(void)
224 {
225 	dpaa2_dbg_root = debugfs_create_dir(DPAA2_ETH_DBG_ROOT, NULL);
226 	if (!dpaa2_dbg_root) {
227 		pr_err("DPAA2-ETH: debugfs create failed\n");
228 		return;
229 	}
230 
231 	pr_debug("DPAA2-ETH: debugfs created\n");
232 }
233 
234 void dpaa2_eth_dbg_exit(void)
235 {
236 	debugfs_remove(dpaa2_dbg_root);
237 }
238