xref: /linux/drivers/net/ethernet/qualcomm/ppe/ppe_debugfs.c (revision 07fdad3a93756b872da7b53647715c48d0f4a2d0)
1*a2a7221dSLuo Jie // SPDX-License-Identifier: GPL-2.0-only
2*a2a7221dSLuo Jie /*
3*a2a7221dSLuo Jie  * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
4*a2a7221dSLuo Jie  */
5*a2a7221dSLuo Jie 
6*a2a7221dSLuo Jie /* PPE debugfs routines for display of PPE counters useful for debug. */
7*a2a7221dSLuo Jie 
8*a2a7221dSLuo Jie #include <linux/bitfield.h>
9*a2a7221dSLuo Jie #include <linux/debugfs.h>
10*a2a7221dSLuo Jie #include <linux/dev_printk.h>
11*a2a7221dSLuo Jie #include <linux/device.h>
12*a2a7221dSLuo Jie #include <linux/regmap.h>
13*a2a7221dSLuo Jie #include <linux/seq_file.h>
14*a2a7221dSLuo Jie 
15*a2a7221dSLuo Jie #include "ppe.h"
16*a2a7221dSLuo Jie #include "ppe_config.h"
17*a2a7221dSLuo Jie #include "ppe_debugfs.h"
18*a2a7221dSLuo Jie #include "ppe_regs.h"
19*a2a7221dSLuo Jie 
20*a2a7221dSLuo Jie #define PPE_PKT_CNT_TBL_SIZE				3
21*a2a7221dSLuo Jie #define PPE_DROP_PKT_CNT_TBL_SIZE			5
22*a2a7221dSLuo Jie 
23*a2a7221dSLuo Jie #define PPE_W0_PKT_CNT					GENMASK(31, 0)
24*a2a7221dSLuo Jie #define PPE_W2_DROP_PKT_CNT_LOW				GENMASK(31, 8)
25*a2a7221dSLuo Jie #define PPE_W3_DROP_PKT_CNT_HIGH			GENMASK(7, 0)
26*a2a7221dSLuo Jie 
27*a2a7221dSLuo Jie #define PPE_GET_PKT_CNT(tbl_cnt)			\
28*a2a7221dSLuo Jie 	FIELD_GET(PPE_W0_PKT_CNT, *(tbl_cnt))
29*a2a7221dSLuo Jie #define PPE_GET_DROP_PKT_CNT_LOW(tbl_cnt)		\
30*a2a7221dSLuo Jie 	FIELD_GET(PPE_W2_DROP_PKT_CNT_LOW, *((tbl_cnt) + 0x2))
31*a2a7221dSLuo Jie #define PPE_GET_DROP_PKT_CNT_HIGH(tbl_cnt)		\
32*a2a7221dSLuo Jie 	FIELD_GET(PPE_W3_DROP_PKT_CNT_HIGH, *((tbl_cnt) + 0x3))
33*a2a7221dSLuo Jie 
34*a2a7221dSLuo Jie /**
35*a2a7221dSLuo Jie  * enum ppe_cnt_size_type - PPE counter size type
36*a2a7221dSLuo Jie  * @PPE_PKT_CNT_SIZE_1WORD: Counter size with single register
37*a2a7221dSLuo Jie  * @PPE_PKT_CNT_SIZE_3WORD: Counter size with table of 3 words
38*a2a7221dSLuo Jie  * @PPE_PKT_CNT_SIZE_5WORD: Counter size with table of 5 words
39*a2a7221dSLuo Jie  *
40*a2a7221dSLuo Jie  * PPE takes the different register size to record the packet counters.
41*a2a7221dSLuo Jie  * It uses single register, or register table with 3 words or 5 words.
42*a2a7221dSLuo Jie  * The counter with table size 5 words also records the drop counter.
43*a2a7221dSLuo Jie  * There are also some other counter types occupying sizes less than 32
44*a2a7221dSLuo Jie  * bits, which is not covered by this enumeration type.
45*a2a7221dSLuo Jie  */
46*a2a7221dSLuo Jie enum ppe_cnt_size_type {
47*a2a7221dSLuo Jie 	PPE_PKT_CNT_SIZE_1WORD,
48*a2a7221dSLuo Jie 	PPE_PKT_CNT_SIZE_3WORD,
49*a2a7221dSLuo Jie 	PPE_PKT_CNT_SIZE_5WORD,
50*a2a7221dSLuo Jie };
51*a2a7221dSLuo Jie 
52*a2a7221dSLuo Jie /**
53*a2a7221dSLuo Jie  * enum ppe_cnt_type - PPE counter type.
54*a2a7221dSLuo Jie  * @PPE_CNT_BM: Packet counter processed by BM.
55*a2a7221dSLuo Jie  * @PPE_CNT_PARSE: Packet counter parsed on ingress.
56*a2a7221dSLuo Jie  * @PPE_CNT_PORT_RX: Packet counter on the ingress port.
57*a2a7221dSLuo Jie  * @PPE_CNT_VLAN_RX: VLAN packet counter received.
58*a2a7221dSLuo Jie  * @PPE_CNT_L2_FWD: Packet counter processed by L2 forwarding.
59*a2a7221dSLuo Jie  * @PPE_CNT_CPU_CODE: Packet counter marked with various CPU codes.
60*a2a7221dSLuo Jie  * @PPE_CNT_VLAN_TX: VLAN packet counter transmitted.
61*a2a7221dSLuo Jie  * @PPE_CNT_PORT_TX: Packet counter on the egress port.
62*a2a7221dSLuo Jie  * @PPE_CNT_QM: Packet counter processed by QM.
63*a2a7221dSLuo Jie  */
64*a2a7221dSLuo Jie enum ppe_cnt_type {
65*a2a7221dSLuo Jie 	PPE_CNT_BM,
66*a2a7221dSLuo Jie 	PPE_CNT_PARSE,
67*a2a7221dSLuo Jie 	PPE_CNT_PORT_RX,
68*a2a7221dSLuo Jie 	PPE_CNT_VLAN_RX,
69*a2a7221dSLuo Jie 	PPE_CNT_L2_FWD,
70*a2a7221dSLuo Jie 	PPE_CNT_CPU_CODE,
71*a2a7221dSLuo Jie 	PPE_CNT_VLAN_TX,
72*a2a7221dSLuo Jie 	PPE_CNT_PORT_TX,
73*a2a7221dSLuo Jie 	PPE_CNT_QM,
74*a2a7221dSLuo Jie };
75*a2a7221dSLuo Jie 
76*a2a7221dSLuo Jie /**
77*a2a7221dSLuo Jie  * struct ppe_debugfs_entry - PPE debugfs entry.
78*a2a7221dSLuo Jie  * @name: Debugfs file name.
79*a2a7221dSLuo Jie  * @counter_type: PPE packet counter type.
80*a2a7221dSLuo Jie  * @ppe: PPE device.
81*a2a7221dSLuo Jie  *
82*a2a7221dSLuo Jie  * The PPE debugfs entry is used to create the debugfs file and passed
83*a2a7221dSLuo Jie  * to debugfs_create_file() as private data.
84*a2a7221dSLuo Jie  */
85*a2a7221dSLuo Jie struct ppe_debugfs_entry {
86*a2a7221dSLuo Jie 	const char *name;
87*a2a7221dSLuo Jie 	enum ppe_cnt_type counter_type;
88*a2a7221dSLuo Jie 	struct ppe_device *ppe;
89*a2a7221dSLuo Jie };
90*a2a7221dSLuo Jie 
91*a2a7221dSLuo Jie static const struct ppe_debugfs_entry debugfs_files[] = {
92*a2a7221dSLuo Jie 	{
93*a2a7221dSLuo Jie 		.name			= "bm",
94*a2a7221dSLuo Jie 		.counter_type		= PPE_CNT_BM,
95*a2a7221dSLuo Jie 	},
96*a2a7221dSLuo Jie 	{
97*a2a7221dSLuo Jie 		.name			= "parse",
98*a2a7221dSLuo Jie 		.counter_type		= PPE_CNT_PARSE,
99*a2a7221dSLuo Jie 	},
100*a2a7221dSLuo Jie 	{
101*a2a7221dSLuo Jie 		.name			= "port_rx",
102*a2a7221dSLuo Jie 		.counter_type		= PPE_CNT_PORT_RX,
103*a2a7221dSLuo Jie 	},
104*a2a7221dSLuo Jie 	{
105*a2a7221dSLuo Jie 		.name			= "vlan_rx",
106*a2a7221dSLuo Jie 		.counter_type		= PPE_CNT_VLAN_RX,
107*a2a7221dSLuo Jie 	},
108*a2a7221dSLuo Jie 	{
109*a2a7221dSLuo Jie 		.name			= "l2_forward",
110*a2a7221dSLuo Jie 		.counter_type		= PPE_CNT_L2_FWD,
111*a2a7221dSLuo Jie 	},
112*a2a7221dSLuo Jie 	{
113*a2a7221dSLuo Jie 		.name			= "cpu_code",
114*a2a7221dSLuo Jie 		.counter_type		= PPE_CNT_CPU_CODE,
115*a2a7221dSLuo Jie 	},
116*a2a7221dSLuo Jie 	{
117*a2a7221dSLuo Jie 		.name			= "vlan_tx",
118*a2a7221dSLuo Jie 		.counter_type		= PPE_CNT_VLAN_TX,
119*a2a7221dSLuo Jie 	},
120*a2a7221dSLuo Jie 	{
121*a2a7221dSLuo Jie 		.name			= "port_tx",
122*a2a7221dSLuo Jie 		.counter_type		= PPE_CNT_PORT_TX,
123*a2a7221dSLuo Jie 	},
124*a2a7221dSLuo Jie 	{
125*a2a7221dSLuo Jie 		.name			= "qm",
126*a2a7221dSLuo Jie 		.counter_type		= PPE_CNT_QM,
127*a2a7221dSLuo Jie 	},
128*a2a7221dSLuo Jie };
129*a2a7221dSLuo Jie 
130*a2a7221dSLuo Jie static int ppe_pkt_cnt_get(struct ppe_device *ppe_dev, u32 reg,
131*a2a7221dSLuo Jie 			   enum ppe_cnt_size_type cnt_type,
132*a2a7221dSLuo Jie 			   u32 *cnt, u32 *drop_cnt)
133*a2a7221dSLuo Jie {
134*a2a7221dSLuo Jie 	u32 drop_pkt_cnt[PPE_DROP_PKT_CNT_TBL_SIZE];
135*a2a7221dSLuo Jie 	u32 pkt_cnt[PPE_PKT_CNT_TBL_SIZE];
136*a2a7221dSLuo Jie 	u32 value;
137*a2a7221dSLuo Jie 	int ret;
138*a2a7221dSLuo Jie 
139*a2a7221dSLuo Jie 	switch (cnt_type) {
140*a2a7221dSLuo Jie 	case PPE_PKT_CNT_SIZE_1WORD:
141*a2a7221dSLuo Jie 		ret = regmap_read(ppe_dev->regmap, reg, &value);
142*a2a7221dSLuo Jie 		if (ret)
143*a2a7221dSLuo Jie 			return ret;
144*a2a7221dSLuo Jie 
145*a2a7221dSLuo Jie 		*cnt = value;
146*a2a7221dSLuo Jie 		break;
147*a2a7221dSLuo Jie 	case PPE_PKT_CNT_SIZE_3WORD:
148*a2a7221dSLuo Jie 		ret = regmap_bulk_read(ppe_dev->regmap, reg,
149*a2a7221dSLuo Jie 				       pkt_cnt, ARRAY_SIZE(pkt_cnt));
150*a2a7221dSLuo Jie 		if (ret)
151*a2a7221dSLuo Jie 			return ret;
152*a2a7221dSLuo Jie 
153*a2a7221dSLuo Jie 		*cnt = PPE_GET_PKT_CNT(pkt_cnt);
154*a2a7221dSLuo Jie 		break;
155*a2a7221dSLuo Jie 	case PPE_PKT_CNT_SIZE_5WORD:
156*a2a7221dSLuo Jie 		ret = regmap_bulk_read(ppe_dev->regmap, reg,
157*a2a7221dSLuo Jie 				       drop_pkt_cnt, ARRAY_SIZE(drop_pkt_cnt));
158*a2a7221dSLuo Jie 		if (ret)
159*a2a7221dSLuo Jie 			return ret;
160*a2a7221dSLuo Jie 
161*a2a7221dSLuo Jie 		*cnt = PPE_GET_PKT_CNT(drop_pkt_cnt);
162*a2a7221dSLuo Jie 
163*a2a7221dSLuo Jie 		/* Drop counter with low 24 bits. */
164*a2a7221dSLuo Jie 		value  = PPE_GET_DROP_PKT_CNT_LOW(drop_pkt_cnt);
165*a2a7221dSLuo Jie 		*drop_cnt = FIELD_PREP(GENMASK(23, 0), value);
166*a2a7221dSLuo Jie 
167*a2a7221dSLuo Jie 		/* Drop counter with high 8 bits. */
168*a2a7221dSLuo Jie 		value  = PPE_GET_DROP_PKT_CNT_HIGH(drop_pkt_cnt);
169*a2a7221dSLuo Jie 		*drop_cnt |= FIELD_PREP(GENMASK(31, 24), value);
170*a2a7221dSLuo Jie 		break;
171*a2a7221dSLuo Jie 	}
172*a2a7221dSLuo Jie 
173*a2a7221dSLuo Jie 	return 0;
174*a2a7221dSLuo Jie }
175*a2a7221dSLuo Jie 
176*a2a7221dSLuo Jie static void ppe_tbl_pkt_cnt_clear(struct ppe_device *ppe_dev, u32 reg,
177*a2a7221dSLuo Jie 				  enum ppe_cnt_size_type cnt_type)
178*a2a7221dSLuo Jie {
179*a2a7221dSLuo Jie 	u32 drop_pkt_cnt[PPE_DROP_PKT_CNT_TBL_SIZE] = {};
180*a2a7221dSLuo Jie 	u32 pkt_cnt[PPE_PKT_CNT_TBL_SIZE] = {};
181*a2a7221dSLuo Jie 
182*a2a7221dSLuo Jie 	switch (cnt_type) {
183*a2a7221dSLuo Jie 	case PPE_PKT_CNT_SIZE_1WORD:
184*a2a7221dSLuo Jie 		regmap_write(ppe_dev->regmap, reg, 0);
185*a2a7221dSLuo Jie 		break;
186*a2a7221dSLuo Jie 	case PPE_PKT_CNT_SIZE_3WORD:
187*a2a7221dSLuo Jie 		regmap_bulk_write(ppe_dev->regmap, reg,
188*a2a7221dSLuo Jie 				  pkt_cnt, ARRAY_SIZE(pkt_cnt));
189*a2a7221dSLuo Jie 		break;
190*a2a7221dSLuo Jie 	case PPE_PKT_CNT_SIZE_5WORD:
191*a2a7221dSLuo Jie 		regmap_bulk_write(ppe_dev->regmap, reg,
192*a2a7221dSLuo Jie 				  drop_pkt_cnt, ARRAY_SIZE(drop_pkt_cnt));
193*a2a7221dSLuo Jie 		break;
194*a2a7221dSLuo Jie 	}
195*a2a7221dSLuo Jie }
196*a2a7221dSLuo Jie 
197*a2a7221dSLuo Jie static int ppe_bm_counter_get(struct ppe_device *ppe_dev, struct seq_file *seq)
198*a2a7221dSLuo Jie {
199*a2a7221dSLuo Jie 	u32 reg, val, pkt_cnt, pkt_cnt1;
200*a2a7221dSLuo Jie 	int ret, i, tag;
201*a2a7221dSLuo Jie 
202*a2a7221dSLuo Jie 	seq_printf(seq, "%-24s", "BM SILENT_DROP:");
203*a2a7221dSLuo Jie 	tag = 0;
204*a2a7221dSLuo Jie 	for (i = 0; i < PPE_DROP_CNT_TBL_ENTRIES; i++) {
205*a2a7221dSLuo Jie 		reg = PPE_DROP_CNT_TBL_ADDR + i * PPE_DROP_CNT_TBL_INC;
206*a2a7221dSLuo Jie 		ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD,
207*a2a7221dSLuo Jie 				      &pkt_cnt, NULL);
208*a2a7221dSLuo Jie 		if (ret) {
209*a2a7221dSLuo Jie 			dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
210*a2a7221dSLuo Jie 			return ret;
211*a2a7221dSLuo Jie 		}
212*a2a7221dSLuo Jie 
213*a2a7221dSLuo Jie 		if (pkt_cnt > 0) {
214*a2a7221dSLuo Jie 			if (!((++tag) % 4))
215*a2a7221dSLuo Jie 				seq_printf(seq, "\n%-24s", "");
216*a2a7221dSLuo Jie 
217*a2a7221dSLuo Jie 			seq_printf(seq, "%10u(%s=%04d)", pkt_cnt, "port", i);
218*a2a7221dSLuo Jie 		}
219*a2a7221dSLuo Jie 	}
220*a2a7221dSLuo Jie 
221*a2a7221dSLuo Jie 	seq_putc(seq, '\n');
222*a2a7221dSLuo Jie 
223*a2a7221dSLuo Jie 	/* The number of packets dropped because hardware buffers were
224*a2a7221dSLuo Jie 	 * available only partially for the packet.
225*a2a7221dSLuo Jie 	 */
226*a2a7221dSLuo Jie 	seq_printf(seq, "%-24s", "BM OVERFLOW_DROP:");
227*a2a7221dSLuo Jie 	tag = 0;
228*a2a7221dSLuo Jie 	for (i = 0; i < PPE_DROP_STAT_TBL_ENTRIES; i++) {
229*a2a7221dSLuo Jie 		reg = PPE_DROP_STAT_TBL_ADDR + PPE_DROP_STAT_TBL_INC * i;
230*a2a7221dSLuo Jie 
231*a2a7221dSLuo Jie 		ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
232*a2a7221dSLuo Jie 				      &pkt_cnt, NULL);
233*a2a7221dSLuo Jie 		if (ret) {
234*a2a7221dSLuo Jie 			dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
235*a2a7221dSLuo Jie 			return ret;
236*a2a7221dSLuo Jie 		}
237*a2a7221dSLuo Jie 
238*a2a7221dSLuo Jie 		if (pkt_cnt > 0) {
239*a2a7221dSLuo Jie 			if (!((++tag) % 4))
240*a2a7221dSLuo Jie 				seq_printf(seq, "\n%-24s", "");
241*a2a7221dSLuo Jie 
242*a2a7221dSLuo Jie 			seq_printf(seq, "%10u(%s=%04d)", pkt_cnt, "port", i);
243*a2a7221dSLuo Jie 		}
244*a2a7221dSLuo Jie 	}
245*a2a7221dSLuo Jie 
246*a2a7221dSLuo Jie 	seq_putc(seq, '\n');
247*a2a7221dSLuo Jie 
248*a2a7221dSLuo Jie 	/* The number of currently occupied buffers, that can't be flushed. */
249*a2a7221dSLuo Jie 	seq_printf(seq, "%-24s", "BM USED/REACT:");
250*a2a7221dSLuo Jie 	tag = 0;
251*a2a7221dSLuo Jie 	for (i = 0; i < PPE_BM_USED_CNT_TBL_ENTRIES; i++) {
252*a2a7221dSLuo Jie 		reg = PPE_BM_USED_CNT_TBL_ADDR + i * PPE_BM_USED_CNT_TBL_INC;
253*a2a7221dSLuo Jie 		ret = regmap_read(ppe_dev->regmap, reg, &val);
254*a2a7221dSLuo Jie 		if (ret) {
255*a2a7221dSLuo Jie 			dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
256*a2a7221dSLuo Jie 			return ret;
257*a2a7221dSLuo Jie 		}
258*a2a7221dSLuo Jie 
259*a2a7221dSLuo Jie 		/* The number of PPE buffers used for caching the received
260*a2a7221dSLuo Jie 		 * packets before the pause frame sent.
261*a2a7221dSLuo Jie 		 */
262*a2a7221dSLuo Jie 		pkt_cnt = FIELD_GET(PPE_BM_USED_CNT_VAL, val);
263*a2a7221dSLuo Jie 
264*a2a7221dSLuo Jie 		reg = PPE_BM_REACT_CNT_TBL_ADDR + i * PPE_BM_REACT_CNT_TBL_INC;
265*a2a7221dSLuo Jie 		ret = regmap_read(ppe_dev->regmap, reg, &val);
266*a2a7221dSLuo Jie 		if (ret) {
267*a2a7221dSLuo Jie 			dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
268*a2a7221dSLuo Jie 			return ret;
269*a2a7221dSLuo Jie 		}
270*a2a7221dSLuo Jie 
271*a2a7221dSLuo Jie 		/* The number of PPE buffers used for caching the received
272*a2a7221dSLuo Jie 		 * packets after pause frame sent out.
273*a2a7221dSLuo Jie 		 */
274*a2a7221dSLuo Jie 		pkt_cnt1 = FIELD_GET(PPE_BM_REACT_CNT_VAL, val);
275*a2a7221dSLuo Jie 
276*a2a7221dSLuo Jie 		if (pkt_cnt > 0 || pkt_cnt1 > 0) {
277*a2a7221dSLuo Jie 			if (!((++tag) % 4))
278*a2a7221dSLuo Jie 				seq_printf(seq, "\n%-24s", "");
279*a2a7221dSLuo Jie 
280*a2a7221dSLuo Jie 			seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, pkt_cnt1,
281*a2a7221dSLuo Jie 				   "port", i);
282*a2a7221dSLuo Jie 		}
283*a2a7221dSLuo Jie 	}
284*a2a7221dSLuo Jie 
285*a2a7221dSLuo Jie 	seq_putc(seq, '\n');
286*a2a7221dSLuo Jie 
287*a2a7221dSLuo Jie 	return 0;
288*a2a7221dSLuo Jie }
289*a2a7221dSLuo Jie 
290*a2a7221dSLuo Jie /* The number of packets processed by the ingress parser module of PPE. */
291*a2a7221dSLuo Jie static int ppe_parse_pkt_counter_get(struct ppe_device *ppe_dev,
292*a2a7221dSLuo Jie 				     struct seq_file *seq)
293*a2a7221dSLuo Jie {
294*a2a7221dSLuo Jie 	u32 reg, cnt = 0, tunnel_cnt = 0;
295*a2a7221dSLuo Jie 	int i, ret, tag = 0;
296*a2a7221dSLuo Jie 
297*a2a7221dSLuo Jie 	seq_printf(seq, "%-24s", "PARSE TPRX/IPRX:");
298*a2a7221dSLuo Jie 	for (i = 0; i < PPE_IPR_PKT_CNT_TBL_ENTRIES; i++) {
299*a2a7221dSLuo Jie 		reg = PPE_TPR_PKT_CNT_TBL_ADDR + i * PPE_TPR_PKT_CNT_TBL_INC;
300*a2a7221dSLuo Jie 		ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD,
301*a2a7221dSLuo Jie 				      &tunnel_cnt, NULL);
302*a2a7221dSLuo Jie 		if (ret) {
303*a2a7221dSLuo Jie 			dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
304*a2a7221dSLuo Jie 			return ret;
305*a2a7221dSLuo Jie 		}
306*a2a7221dSLuo Jie 
307*a2a7221dSLuo Jie 		reg = PPE_IPR_PKT_CNT_TBL_ADDR + i * PPE_IPR_PKT_CNT_TBL_INC;
308*a2a7221dSLuo Jie 		ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD,
309*a2a7221dSLuo Jie 				      &cnt, NULL);
310*a2a7221dSLuo Jie 		if (ret) {
311*a2a7221dSLuo Jie 			dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
312*a2a7221dSLuo Jie 			return ret;
313*a2a7221dSLuo Jie 		}
314*a2a7221dSLuo Jie 
315*a2a7221dSLuo Jie 		if (tunnel_cnt > 0 || cnt > 0) {
316*a2a7221dSLuo Jie 			if (!((++tag) % 4))
317*a2a7221dSLuo Jie 				seq_printf(seq, "\n%-24s", "");
318*a2a7221dSLuo Jie 
319*a2a7221dSLuo Jie 			seq_printf(seq, "%10u/%u(%s=%04d)", tunnel_cnt, cnt,
320*a2a7221dSLuo Jie 				   "port", i);
321*a2a7221dSLuo Jie 		}
322*a2a7221dSLuo Jie 	}
323*a2a7221dSLuo Jie 
324*a2a7221dSLuo Jie 	seq_putc(seq, '\n');
325*a2a7221dSLuo Jie 
326*a2a7221dSLuo Jie 	return 0;
327*a2a7221dSLuo Jie }
328*a2a7221dSLuo Jie 
329*a2a7221dSLuo Jie /* The number of packets received or dropped on the ingress port. */
330*a2a7221dSLuo Jie static int ppe_port_rx_counter_get(struct ppe_device *ppe_dev,
331*a2a7221dSLuo Jie 				   struct seq_file *seq)
332*a2a7221dSLuo Jie {
333*a2a7221dSLuo Jie 	u32 reg, pkt_cnt = 0, drop_cnt = 0;
334*a2a7221dSLuo Jie 	int ret, i, tag;
335*a2a7221dSLuo Jie 
336*a2a7221dSLuo Jie 	seq_printf(seq, "%-24s", "PORT RX/RX_DROP:");
337*a2a7221dSLuo Jie 	tag = 0;
338*a2a7221dSLuo Jie 	for (i = 0; i < PPE_PHY_PORT_RX_CNT_TBL_ENTRIES; i++) {
339*a2a7221dSLuo Jie 		reg = PPE_PHY_PORT_RX_CNT_TBL_ADDR + PPE_PHY_PORT_RX_CNT_TBL_INC * i;
340*a2a7221dSLuo Jie 		ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD,
341*a2a7221dSLuo Jie 				      &pkt_cnt, &drop_cnt);
342*a2a7221dSLuo Jie 		if (ret) {
343*a2a7221dSLuo Jie 			dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
344*a2a7221dSLuo Jie 			return ret;
345*a2a7221dSLuo Jie 		}
346*a2a7221dSLuo Jie 
347*a2a7221dSLuo Jie 		if (pkt_cnt > 0) {
348*a2a7221dSLuo Jie 			if (!((++tag) % 4))
349*a2a7221dSLuo Jie 				seq_printf(seq, "\n%-24s", "");
350*a2a7221dSLuo Jie 
351*a2a7221dSLuo Jie 			seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, drop_cnt,
352*a2a7221dSLuo Jie 				   "port", i);
353*a2a7221dSLuo Jie 		}
354*a2a7221dSLuo Jie 	}
355*a2a7221dSLuo Jie 
356*a2a7221dSLuo Jie 	seq_putc(seq, '\n');
357*a2a7221dSLuo Jie 
358*a2a7221dSLuo Jie 	seq_printf(seq, "%-24s", "VPORT RX/RX_DROP:");
359*a2a7221dSLuo Jie 	tag = 0;
360*a2a7221dSLuo Jie 	for (i = 0; i < PPE_PORT_RX_CNT_TBL_ENTRIES; i++) {
361*a2a7221dSLuo Jie 		reg = PPE_PORT_RX_CNT_TBL_ADDR + PPE_PORT_RX_CNT_TBL_INC * i;
362*a2a7221dSLuo Jie 		ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD,
363*a2a7221dSLuo Jie 				      &pkt_cnt, &drop_cnt);
364*a2a7221dSLuo Jie 		if (ret) {
365*a2a7221dSLuo Jie 			dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
366*a2a7221dSLuo Jie 			return ret;
367*a2a7221dSLuo Jie 		}
368*a2a7221dSLuo Jie 
369*a2a7221dSLuo Jie 		if (pkt_cnt > 0) {
370*a2a7221dSLuo Jie 			if (!((++tag) % 4))
371*a2a7221dSLuo Jie 				seq_printf(seq, "\n%-24s", "");
372*a2a7221dSLuo Jie 
373*a2a7221dSLuo Jie 			seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, drop_cnt,
374*a2a7221dSLuo Jie 				   "port", i);
375*a2a7221dSLuo Jie 		}
376*a2a7221dSLuo Jie 	}
377*a2a7221dSLuo Jie 
378*a2a7221dSLuo Jie 	seq_putc(seq, '\n');
379*a2a7221dSLuo Jie 
380*a2a7221dSLuo Jie 	return 0;
381*a2a7221dSLuo Jie }
382*a2a7221dSLuo Jie 
383*a2a7221dSLuo Jie /* The number of packets received or dropped by layer 2 processing. */
384*a2a7221dSLuo Jie static int ppe_l2_counter_get(struct ppe_device *ppe_dev,
385*a2a7221dSLuo Jie 			      struct seq_file *seq)
386*a2a7221dSLuo Jie {
387*a2a7221dSLuo Jie 	u32 reg, pkt_cnt = 0, drop_cnt = 0;
388*a2a7221dSLuo Jie 	int ret, i, tag = 0;
389*a2a7221dSLuo Jie 
390*a2a7221dSLuo Jie 	seq_printf(seq, "%-24s", "L2 RX/RX_DROP:");
391*a2a7221dSLuo Jie 	for (i = 0; i < PPE_PRE_L2_CNT_TBL_ENTRIES; i++) {
392*a2a7221dSLuo Jie 		reg = PPE_PRE_L2_CNT_TBL_ADDR + PPE_PRE_L2_CNT_TBL_INC * i;
393*a2a7221dSLuo Jie 		ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD,
394*a2a7221dSLuo Jie 				      &pkt_cnt, &drop_cnt);
395*a2a7221dSLuo Jie 		if (ret) {
396*a2a7221dSLuo Jie 			dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
397*a2a7221dSLuo Jie 			return ret;
398*a2a7221dSLuo Jie 		}
399*a2a7221dSLuo Jie 
400*a2a7221dSLuo Jie 		if (pkt_cnt > 0) {
401*a2a7221dSLuo Jie 			if (!((++tag) % 4))
402*a2a7221dSLuo Jie 				seq_printf(seq, "\n%-24s", "");
403*a2a7221dSLuo Jie 
404*a2a7221dSLuo Jie 			seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, drop_cnt,
405*a2a7221dSLuo Jie 				   "vsi", i);
406*a2a7221dSLuo Jie 		}
407*a2a7221dSLuo Jie 	}
408*a2a7221dSLuo Jie 
409*a2a7221dSLuo Jie 	seq_putc(seq, '\n');
410*a2a7221dSLuo Jie 
411*a2a7221dSLuo Jie 	return 0;
412*a2a7221dSLuo Jie }
413*a2a7221dSLuo Jie 
414*a2a7221dSLuo Jie /* The number of VLAN packets received by PPE. */
415*a2a7221dSLuo Jie static int ppe_vlan_rx_counter_get(struct ppe_device *ppe_dev,
416*a2a7221dSLuo Jie 				   struct seq_file *seq)
417*a2a7221dSLuo Jie {
418*a2a7221dSLuo Jie 	u32 reg, pkt_cnt = 0;
419*a2a7221dSLuo Jie 	int ret, i, tag = 0;
420*a2a7221dSLuo Jie 
421*a2a7221dSLuo Jie 	seq_printf(seq, "%-24s", "VLAN RX:");
422*a2a7221dSLuo Jie 	for (i = 0; i < PPE_VLAN_CNT_TBL_ENTRIES; i++) {
423*a2a7221dSLuo Jie 		reg = PPE_VLAN_CNT_TBL_ADDR + PPE_VLAN_CNT_TBL_INC * i;
424*a2a7221dSLuo Jie 
425*a2a7221dSLuo Jie 		ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
426*a2a7221dSLuo Jie 				      &pkt_cnt, NULL);
427*a2a7221dSLuo Jie 		if (ret) {
428*a2a7221dSLuo Jie 			dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
429*a2a7221dSLuo Jie 			return ret;
430*a2a7221dSLuo Jie 		}
431*a2a7221dSLuo Jie 
432*a2a7221dSLuo Jie 		if (pkt_cnt > 0) {
433*a2a7221dSLuo Jie 			if (!((++tag) % 4))
434*a2a7221dSLuo Jie 				seq_printf(seq, "\n%-24s", "");
435*a2a7221dSLuo Jie 
436*a2a7221dSLuo Jie 			seq_printf(seq, "%10u(%s=%04d)", pkt_cnt, "vsi", i);
437*a2a7221dSLuo Jie 		}
438*a2a7221dSLuo Jie 	}
439*a2a7221dSLuo Jie 
440*a2a7221dSLuo Jie 	seq_putc(seq, '\n');
441*a2a7221dSLuo Jie 
442*a2a7221dSLuo Jie 	return 0;
443*a2a7221dSLuo Jie }
444*a2a7221dSLuo Jie 
445*a2a7221dSLuo Jie /* The number of packets handed to CPU by PPE. */
446*a2a7221dSLuo Jie static int ppe_cpu_code_counter_get(struct ppe_device *ppe_dev,
447*a2a7221dSLuo Jie 				    struct seq_file *seq)
448*a2a7221dSLuo Jie {
449*a2a7221dSLuo Jie 	u32 reg, pkt_cnt = 0;
450*a2a7221dSLuo Jie 	int ret, i;
451*a2a7221dSLuo Jie 
452*a2a7221dSLuo Jie 	seq_printf(seq, "%-24s", "CPU CODE:");
453*a2a7221dSLuo Jie 	for (i = 0; i < PPE_DROP_CPU_CNT_TBL_ENTRIES; i++) {
454*a2a7221dSLuo Jie 		reg = PPE_DROP_CPU_CNT_TBL_ADDR + PPE_DROP_CPU_CNT_TBL_INC * i;
455*a2a7221dSLuo Jie 
456*a2a7221dSLuo Jie 		ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
457*a2a7221dSLuo Jie 				      &pkt_cnt, NULL);
458*a2a7221dSLuo Jie 		if (ret) {
459*a2a7221dSLuo Jie 			dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
460*a2a7221dSLuo Jie 			return ret;
461*a2a7221dSLuo Jie 		}
462*a2a7221dSLuo Jie 
463*a2a7221dSLuo Jie 		if (!pkt_cnt)
464*a2a7221dSLuo Jie 			continue;
465*a2a7221dSLuo Jie 
466*a2a7221dSLuo Jie 		/* There are 256 CPU codes saved in the first 256 entries
467*a2a7221dSLuo Jie 		 * of register table, and 128 drop codes for each PPE port
468*a2a7221dSLuo Jie 		 * (0-7), the total entries is 256 + 8 * 128.
469*a2a7221dSLuo Jie 		 */
470*a2a7221dSLuo Jie 		if (i < 256)
471*a2a7221dSLuo Jie 			seq_printf(seq, "%10u(cpucode:%d)", pkt_cnt, i);
472*a2a7221dSLuo Jie 		else
473*a2a7221dSLuo Jie 			seq_printf(seq, "%10u(port=%04d),dropcode:%d", pkt_cnt,
474*a2a7221dSLuo Jie 				   (i - 256) % 8, (i - 256) / 8);
475*a2a7221dSLuo Jie 		seq_putc(seq, '\n');
476*a2a7221dSLuo Jie 		seq_printf(seq, "%-24s", "");
477*a2a7221dSLuo Jie 	}
478*a2a7221dSLuo Jie 
479*a2a7221dSLuo Jie 	seq_putc(seq, '\n');
480*a2a7221dSLuo Jie 
481*a2a7221dSLuo Jie 	return 0;
482*a2a7221dSLuo Jie }
483*a2a7221dSLuo Jie 
484*a2a7221dSLuo Jie /* The number of packets forwarded by VLAN on the egress direction. */
485*a2a7221dSLuo Jie static int ppe_vlan_tx_counter_get(struct ppe_device *ppe_dev,
486*a2a7221dSLuo Jie 				   struct seq_file *seq)
487*a2a7221dSLuo Jie {
488*a2a7221dSLuo Jie 	u32 reg, pkt_cnt = 0;
489*a2a7221dSLuo Jie 	int ret, i, tag = 0;
490*a2a7221dSLuo Jie 
491*a2a7221dSLuo Jie 	seq_printf(seq, "%-24s", "VLAN TX:");
492*a2a7221dSLuo Jie 	for (i = 0; i < PPE_EG_VSI_COUNTER_TBL_ENTRIES; i++) {
493*a2a7221dSLuo Jie 		reg = PPE_EG_VSI_COUNTER_TBL_ADDR + PPE_EG_VSI_COUNTER_TBL_INC * i;
494*a2a7221dSLuo Jie 
495*a2a7221dSLuo Jie 		ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
496*a2a7221dSLuo Jie 				      &pkt_cnt, NULL);
497*a2a7221dSLuo Jie 		if (ret) {
498*a2a7221dSLuo Jie 			dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
499*a2a7221dSLuo Jie 			return ret;
500*a2a7221dSLuo Jie 		}
501*a2a7221dSLuo Jie 
502*a2a7221dSLuo Jie 		if (pkt_cnt > 0) {
503*a2a7221dSLuo Jie 			if (!((++tag) % 4))
504*a2a7221dSLuo Jie 				seq_printf(seq, "\n%-24s", "");
505*a2a7221dSLuo Jie 
506*a2a7221dSLuo Jie 			seq_printf(seq, "%10u(%s=%04d)", pkt_cnt, "vsi", i);
507*a2a7221dSLuo Jie 		}
508*a2a7221dSLuo Jie 	}
509*a2a7221dSLuo Jie 
510*a2a7221dSLuo Jie 	seq_putc(seq, '\n');
511*a2a7221dSLuo Jie 
512*a2a7221dSLuo Jie 	return 0;
513*a2a7221dSLuo Jie }
514*a2a7221dSLuo Jie 
515*a2a7221dSLuo Jie /* The number of packets transmitted or dropped on the egress port. */
516*a2a7221dSLuo Jie static int ppe_port_tx_counter_get(struct ppe_device *ppe_dev,
517*a2a7221dSLuo Jie 				   struct seq_file *seq)
518*a2a7221dSLuo Jie {
519*a2a7221dSLuo Jie 	u32 reg, pkt_cnt = 0, drop_cnt = 0;
520*a2a7221dSLuo Jie 	int ret, i, tag;
521*a2a7221dSLuo Jie 
522*a2a7221dSLuo Jie 	seq_printf(seq, "%-24s", "VPORT TX/TX_DROP:");
523*a2a7221dSLuo Jie 	tag = 0;
524*a2a7221dSLuo Jie 	for (i = 0; i < PPE_VPORT_TX_COUNTER_TBL_ENTRIES; i++) {
525*a2a7221dSLuo Jie 		reg = PPE_VPORT_TX_COUNTER_TBL_ADDR + PPE_VPORT_TX_COUNTER_TBL_INC * i;
526*a2a7221dSLuo Jie 		ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
527*a2a7221dSLuo Jie 				      &pkt_cnt, NULL);
528*a2a7221dSLuo Jie 		if (ret) {
529*a2a7221dSLuo Jie 			dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
530*a2a7221dSLuo Jie 			return ret;
531*a2a7221dSLuo Jie 		}
532*a2a7221dSLuo Jie 
533*a2a7221dSLuo Jie 		reg = PPE_VPORT_TX_DROP_CNT_TBL_ADDR + PPE_VPORT_TX_DROP_CNT_TBL_INC * i;
534*a2a7221dSLuo Jie 		ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
535*a2a7221dSLuo Jie 				      &drop_cnt, NULL);
536*a2a7221dSLuo Jie 		if (ret) {
537*a2a7221dSLuo Jie 			dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
538*a2a7221dSLuo Jie 			return ret;
539*a2a7221dSLuo Jie 		}
540*a2a7221dSLuo Jie 
541*a2a7221dSLuo Jie 		if (pkt_cnt > 0 || drop_cnt > 0) {
542*a2a7221dSLuo Jie 			if (!((++tag) % 4))
543*a2a7221dSLuo Jie 				seq_printf(seq, "\n%-24s", "");
544*a2a7221dSLuo Jie 
545*a2a7221dSLuo Jie 			seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, drop_cnt,
546*a2a7221dSLuo Jie 				   "port", i);
547*a2a7221dSLuo Jie 		}
548*a2a7221dSLuo Jie 	}
549*a2a7221dSLuo Jie 
550*a2a7221dSLuo Jie 	seq_putc(seq, '\n');
551*a2a7221dSLuo Jie 
552*a2a7221dSLuo Jie 	seq_printf(seq, "%-24s", "PORT TX/TX_DROP:");
553*a2a7221dSLuo Jie 	tag = 0;
554*a2a7221dSLuo Jie 	for (i = 0; i < PPE_PORT_TX_COUNTER_TBL_ENTRIES; i++) {
555*a2a7221dSLuo Jie 		reg = PPE_PORT_TX_COUNTER_TBL_ADDR + PPE_PORT_TX_COUNTER_TBL_INC * i;
556*a2a7221dSLuo Jie 		ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
557*a2a7221dSLuo Jie 				      &pkt_cnt, NULL);
558*a2a7221dSLuo Jie 		if (ret) {
559*a2a7221dSLuo Jie 			dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
560*a2a7221dSLuo Jie 			return ret;
561*a2a7221dSLuo Jie 		}
562*a2a7221dSLuo Jie 
563*a2a7221dSLuo Jie 		reg = PPE_PORT_TX_DROP_CNT_TBL_ADDR + PPE_PORT_TX_DROP_CNT_TBL_INC * i;
564*a2a7221dSLuo Jie 		ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
565*a2a7221dSLuo Jie 				      &drop_cnt, NULL);
566*a2a7221dSLuo Jie 		if (ret) {
567*a2a7221dSLuo Jie 			dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
568*a2a7221dSLuo Jie 			return ret;
569*a2a7221dSLuo Jie 		}
570*a2a7221dSLuo Jie 
571*a2a7221dSLuo Jie 		if (pkt_cnt > 0 || drop_cnt > 0) {
572*a2a7221dSLuo Jie 			if (!((++tag) % 4))
573*a2a7221dSLuo Jie 				seq_printf(seq, "\n%-24s", "");
574*a2a7221dSLuo Jie 
575*a2a7221dSLuo Jie 			seq_printf(seq, "%10u/%u(%s=%04d)", pkt_cnt, drop_cnt,
576*a2a7221dSLuo Jie 				   "port", i);
577*a2a7221dSLuo Jie 		}
578*a2a7221dSLuo Jie 	}
579*a2a7221dSLuo Jie 
580*a2a7221dSLuo Jie 	seq_putc(seq, '\n');
581*a2a7221dSLuo Jie 
582*a2a7221dSLuo Jie 	return 0;
583*a2a7221dSLuo Jie }
584*a2a7221dSLuo Jie 
585*a2a7221dSLuo Jie /* The number of packets transmitted or pending by the PPE queue. */
586*a2a7221dSLuo Jie static int ppe_queue_counter_get(struct ppe_device *ppe_dev,
587*a2a7221dSLuo Jie 				 struct seq_file *seq)
588*a2a7221dSLuo Jie {
589*a2a7221dSLuo Jie 	u32 reg, val, pkt_cnt = 0, pend_cnt = 0, drop_cnt = 0;
590*a2a7221dSLuo Jie 	int ret, i, tag = 0;
591*a2a7221dSLuo Jie 
592*a2a7221dSLuo Jie 	seq_printf(seq, "%-24s", "QUEUE TX/PEND/DROP:");
593*a2a7221dSLuo Jie 	for (i = 0; i < PPE_QUEUE_TX_COUNTER_TBL_ENTRIES; i++) {
594*a2a7221dSLuo Jie 		reg = PPE_QUEUE_TX_COUNTER_TBL_ADDR + PPE_QUEUE_TX_COUNTER_TBL_INC * i;
595*a2a7221dSLuo Jie 		ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
596*a2a7221dSLuo Jie 				      &pkt_cnt, NULL);
597*a2a7221dSLuo Jie 		if (ret) {
598*a2a7221dSLuo Jie 			dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
599*a2a7221dSLuo Jie 			return ret;
600*a2a7221dSLuo Jie 		}
601*a2a7221dSLuo Jie 
602*a2a7221dSLuo Jie 		if (i < PPE_AC_UNICAST_QUEUE_CFG_TBL_ENTRIES) {
603*a2a7221dSLuo Jie 			reg = PPE_AC_UNICAST_QUEUE_CNT_TBL_ADDR +
604*a2a7221dSLuo Jie 			      PPE_AC_UNICAST_QUEUE_CNT_TBL_INC * i;
605*a2a7221dSLuo Jie 			ret = regmap_read(ppe_dev->regmap, reg, &val);
606*a2a7221dSLuo Jie 			if (ret) {
607*a2a7221dSLuo Jie 				dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
608*a2a7221dSLuo Jie 				return ret;
609*a2a7221dSLuo Jie 			}
610*a2a7221dSLuo Jie 
611*a2a7221dSLuo Jie 			pend_cnt = FIELD_GET(PPE_AC_UNICAST_QUEUE_CNT_TBL_PEND_CNT, val);
612*a2a7221dSLuo Jie 
613*a2a7221dSLuo Jie 			reg = PPE_UNICAST_DROP_CNT_TBL_ADDR +
614*a2a7221dSLuo Jie 			      PPE_AC_UNICAST_QUEUE_CNT_TBL_INC *
615*a2a7221dSLuo Jie 			      (i * PPE_UNICAST_DROP_TYPES + PPE_UNICAST_DROP_FORCE_OFFSET);
616*a2a7221dSLuo Jie 
617*a2a7221dSLuo Jie 			ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
618*a2a7221dSLuo Jie 					      &drop_cnt, NULL);
619*a2a7221dSLuo Jie 			if (ret) {
620*a2a7221dSLuo Jie 				dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
621*a2a7221dSLuo Jie 				return ret;
622*a2a7221dSLuo Jie 			}
623*a2a7221dSLuo Jie 		} else {
624*a2a7221dSLuo Jie 			int mq_offset = i - PPE_AC_UNICAST_QUEUE_CFG_TBL_ENTRIES;
625*a2a7221dSLuo Jie 
626*a2a7221dSLuo Jie 			reg = PPE_AC_MULTICAST_QUEUE_CNT_TBL_ADDR +
627*a2a7221dSLuo Jie 			      PPE_AC_MULTICAST_QUEUE_CNT_TBL_INC * mq_offset;
628*a2a7221dSLuo Jie 			ret = regmap_read(ppe_dev->regmap, reg, &val);
629*a2a7221dSLuo Jie 			if (ret) {
630*a2a7221dSLuo Jie 				dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
631*a2a7221dSLuo Jie 				return ret;
632*a2a7221dSLuo Jie 			}
633*a2a7221dSLuo Jie 
634*a2a7221dSLuo Jie 			pend_cnt = FIELD_GET(PPE_AC_MULTICAST_QUEUE_CNT_TBL_PEND_CNT, val);
635*a2a7221dSLuo Jie 
636*a2a7221dSLuo Jie 			if (mq_offset < PPE_P0_MULTICAST_QUEUE_NUM) {
637*a2a7221dSLuo Jie 				reg = PPE_CPU_PORT_MULTICAST_FORCE_DROP_CNT_TBL_ADDR(mq_offset);
638*a2a7221dSLuo Jie 			} else {
639*a2a7221dSLuo Jie 				mq_offset -= PPE_P0_MULTICAST_QUEUE_NUM;
640*a2a7221dSLuo Jie 
641*a2a7221dSLuo Jie 				reg = PPE_P1_MULTICAST_DROP_CNT_TBL_ADDR;
642*a2a7221dSLuo Jie 				reg += (mq_offset / PPE_MULTICAST_QUEUE_NUM) *
643*a2a7221dSLuo Jie 					PPE_MULTICAST_QUEUE_PORT_ADDR_INC;
644*a2a7221dSLuo Jie 				reg += (mq_offset % PPE_MULTICAST_QUEUE_NUM) *
645*a2a7221dSLuo Jie 					PPE_MULTICAST_DROP_CNT_TBL_INC *
646*a2a7221dSLuo Jie 					PPE_MULTICAST_DROP_TYPES;
647*a2a7221dSLuo Jie 			}
648*a2a7221dSLuo Jie 
649*a2a7221dSLuo Jie 			ret = ppe_pkt_cnt_get(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD,
650*a2a7221dSLuo Jie 					      &drop_cnt, NULL);
651*a2a7221dSLuo Jie 			if (ret) {
652*a2a7221dSLuo Jie 				dev_err(ppe_dev->dev, "CNT ERROR %d\n", ret);
653*a2a7221dSLuo Jie 				return ret;
654*a2a7221dSLuo Jie 			}
655*a2a7221dSLuo Jie 		}
656*a2a7221dSLuo Jie 
657*a2a7221dSLuo Jie 		if (pkt_cnt > 0 || pend_cnt > 0 || drop_cnt > 0) {
658*a2a7221dSLuo Jie 			if (!((++tag) % 4))
659*a2a7221dSLuo Jie 				seq_printf(seq, "\n%-24s", "");
660*a2a7221dSLuo Jie 
661*a2a7221dSLuo Jie 			seq_printf(seq, "%10u/%u/%u(%s=%04d)",
662*a2a7221dSLuo Jie 				   pkt_cnt, pend_cnt, drop_cnt, "queue", i);
663*a2a7221dSLuo Jie 		}
664*a2a7221dSLuo Jie 	}
665*a2a7221dSLuo Jie 
666*a2a7221dSLuo Jie 	seq_putc(seq, '\n');
667*a2a7221dSLuo Jie 
668*a2a7221dSLuo Jie 	return 0;
669*a2a7221dSLuo Jie }
670*a2a7221dSLuo Jie 
671*a2a7221dSLuo Jie /* Display the various packet counters of PPE. */
672*a2a7221dSLuo Jie static int ppe_packet_counter_show(struct seq_file *seq, void *v)
673*a2a7221dSLuo Jie {
674*a2a7221dSLuo Jie 	struct ppe_debugfs_entry *entry = seq->private;
675*a2a7221dSLuo Jie 	struct ppe_device *ppe_dev = entry->ppe;
676*a2a7221dSLuo Jie 	int ret;
677*a2a7221dSLuo Jie 
678*a2a7221dSLuo Jie 	switch (entry->counter_type) {
679*a2a7221dSLuo Jie 	case PPE_CNT_BM:
680*a2a7221dSLuo Jie 		ret = ppe_bm_counter_get(ppe_dev, seq);
681*a2a7221dSLuo Jie 		break;
682*a2a7221dSLuo Jie 	case PPE_CNT_PARSE:
683*a2a7221dSLuo Jie 		ret = ppe_parse_pkt_counter_get(ppe_dev, seq);
684*a2a7221dSLuo Jie 		break;
685*a2a7221dSLuo Jie 	case PPE_CNT_PORT_RX:
686*a2a7221dSLuo Jie 		ret = ppe_port_rx_counter_get(ppe_dev, seq);
687*a2a7221dSLuo Jie 		break;
688*a2a7221dSLuo Jie 	case PPE_CNT_VLAN_RX:
689*a2a7221dSLuo Jie 		ret = ppe_vlan_rx_counter_get(ppe_dev, seq);
690*a2a7221dSLuo Jie 		break;
691*a2a7221dSLuo Jie 	case PPE_CNT_L2_FWD:
692*a2a7221dSLuo Jie 		ret = ppe_l2_counter_get(ppe_dev, seq);
693*a2a7221dSLuo Jie 		break;
694*a2a7221dSLuo Jie 	case PPE_CNT_CPU_CODE:
695*a2a7221dSLuo Jie 		ret = ppe_cpu_code_counter_get(ppe_dev, seq);
696*a2a7221dSLuo Jie 		break;
697*a2a7221dSLuo Jie 	case PPE_CNT_VLAN_TX:
698*a2a7221dSLuo Jie 		ret = ppe_vlan_tx_counter_get(ppe_dev, seq);
699*a2a7221dSLuo Jie 		break;
700*a2a7221dSLuo Jie 	case PPE_CNT_PORT_TX:
701*a2a7221dSLuo Jie 		ret = ppe_port_tx_counter_get(ppe_dev, seq);
702*a2a7221dSLuo Jie 		break;
703*a2a7221dSLuo Jie 	case PPE_CNT_QM:
704*a2a7221dSLuo Jie 		ret = ppe_queue_counter_get(ppe_dev, seq);
705*a2a7221dSLuo Jie 		break;
706*a2a7221dSLuo Jie 	default:
707*a2a7221dSLuo Jie 		ret = -EINVAL;
708*a2a7221dSLuo Jie 		break;
709*a2a7221dSLuo Jie 	}
710*a2a7221dSLuo Jie 
711*a2a7221dSLuo Jie 	return ret;
712*a2a7221dSLuo Jie }
713*a2a7221dSLuo Jie 
714*a2a7221dSLuo Jie /* Flush the various packet counters of PPE. */
715*a2a7221dSLuo Jie static ssize_t ppe_packet_counter_write(struct file *file,
716*a2a7221dSLuo Jie 					const char __user *buf,
717*a2a7221dSLuo Jie 					size_t count, loff_t *pos)
718*a2a7221dSLuo Jie {
719*a2a7221dSLuo Jie 	struct ppe_debugfs_entry *entry = file_inode(file)->i_private;
720*a2a7221dSLuo Jie 	struct ppe_device *ppe_dev = entry->ppe;
721*a2a7221dSLuo Jie 	u32 reg;
722*a2a7221dSLuo Jie 	int i;
723*a2a7221dSLuo Jie 
724*a2a7221dSLuo Jie 	switch (entry->counter_type) {
725*a2a7221dSLuo Jie 	case PPE_CNT_BM:
726*a2a7221dSLuo Jie 		for (i = 0; i < PPE_DROP_CNT_TBL_ENTRIES; i++) {
727*a2a7221dSLuo Jie 			reg = PPE_DROP_CNT_TBL_ADDR + i * PPE_DROP_CNT_TBL_INC;
728*a2a7221dSLuo Jie 			ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD);
729*a2a7221dSLuo Jie 		}
730*a2a7221dSLuo Jie 
731*a2a7221dSLuo Jie 		for (i = 0; i < PPE_DROP_STAT_TBL_ENTRIES; i++) {
732*a2a7221dSLuo Jie 			reg = PPE_DROP_STAT_TBL_ADDR + PPE_DROP_STAT_TBL_INC * i;
733*a2a7221dSLuo Jie 			ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
734*a2a7221dSLuo Jie 		}
735*a2a7221dSLuo Jie 
736*a2a7221dSLuo Jie 		break;
737*a2a7221dSLuo Jie 	case PPE_CNT_PARSE:
738*a2a7221dSLuo Jie 		for (i = 0; i < PPE_IPR_PKT_CNT_TBL_ENTRIES; i++) {
739*a2a7221dSLuo Jie 			reg = PPE_IPR_PKT_CNT_TBL_ADDR + i * PPE_IPR_PKT_CNT_TBL_INC;
740*a2a7221dSLuo Jie 			ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD);
741*a2a7221dSLuo Jie 
742*a2a7221dSLuo Jie 			reg = PPE_TPR_PKT_CNT_TBL_ADDR + i * PPE_TPR_PKT_CNT_TBL_INC;
743*a2a7221dSLuo Jie 			ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_1WORD);
744*a2a7221dSLuo Jie 		}
745*a2a7221dSLuo Jie 
746*a2a7221dSLuo Jie 		break;
747*a2a7221dSLuo Jie 	case PPE_CNT_PORT_RX:
748*a2a7221dSLuo Jie 		for (i = 0; i < PPE_PORT_RX_CNT_TBL_ENTRIES; i++) {
749*a2a7221dSLuo Jie 			reg = PPE_PORT_RX_CNT_TBL_ADDR + PPE_PORT_RX_CNT_TBL_INC * i;
750*a2a7221dSLuo Jie 			ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD);
751*a2a7221dSLuo Jie 		}
752*a2a7221dSLuo Jie 
753*a2a7221dSLuo Jie 		for (i = 0; i < PPE_PHY_PORT_RX_CNT_TBL_ENTRIES; i++) {
754*a2a7221dSLuo Jie 			reg = PPE_PHY_PORT_RX_CNT_TBL_ADDR + PPE_PHY_PORT_RX_CNT_TBL_INC * i;
755*a2a7221dSLuo Jie 			ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD);
756*a2a7221dSLuo Jie 		}
757*a2a7221dSLuo Jie 
758*a2a7221dSLuo Jie 		break;
759*a2a7221dSLuo Jie 	case PPE_CNT_VLAN_RX:
760*a2a7221dSLuo Jie 		for (i = 0; i < PPE_VLAN_CNT_TBL_ENTRIES; i++) {
761*a2a7221dSLuo Jie 			reg = PPE_VLAN_CNT_TBL_ADDR + PPE_VLAN_CNT_TBL_INC * i;
762*a2a7221dSLuo Jie 			ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
763*a2a7221dSLuo Jie 		}
764*a2a7221dSLuo Jie 
765*a2a7221dSLuo Jie 		break;
766*a2a7221dSLuo Jie 	case PPE_CNT_L2_FWD:
767*a2a7221dSLuo Jie 		for (i = 0; i < PPE_PRE_L2_CNT_TBL_ENTRIES; i++) {
768*a2a7221dSLuo Jie 			reg = PPE_PRE_L2_CNT_TBL_ADDR + PPE_PRE_L2_CNT_TBL_INC * i;
769*a2a7221dSLuo Jie 			ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_5WORD);
770*a2a7221dSLuo Jie 		}
771*a2a7221dSLuo Jie 
772*a2a7221dSLuo Jie 		break;
773*a2a7221dSLuo Jie 	case PPE_CNT_CPU_CODE:
774*a2a7221dSLuo Jie 		for (i = 0; i < PPE_DROP_CPU_CNT_TBL_ENTRIES; i++) {
775*a2a7221dSLuo Jie 			reg = PPE_DROP_CPU_CNT_TBL_ADDR + PPE_DROP_CPU_CNT_TBL_INC * i;
776*a2a7221dSLuo Jie 			ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
777*a2a7221dSLuo Jie 		}
778*a2a7221dSLuo Jie 
779*a2a7221dSLuo Jie 		break;
780*a2a7221dSLuo Jie 	case PPE_CNT_VLAN_TX:
781*a2a7221dSLuo Jie 		for (i = 0; i < PPE_EG_VSI_COUNTER_TBL_ENTRIES; i++) {
782*a2a7221dSLuo Jie 			reg = PPE_EG_VSI_COUNTER_TBL_ADDR + PPE_EG_VSI_COUNTER_TBL_INC * i;
783*a2a7221dSLuo Jie 			ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
784*a2a7221dSLuo Jie 		}
785*a2a7221dSLuo Jie 
786*a2a7221dSLuo Jie 		break;
787*a2a7221dSLuo Jie 	case PPE_CNT_PORT_TX:
788*a2a7221dSLuo Jie 		for (i = 0; i < PPE_PORT_TX_COUNTER_TBL_ENTRIES; i++) {
789*a2a7221dSLuo Jie 			reg = PPE_PORT_TX_DROP_CNT_TBL_ADDR + PPE_PORT_TX_DROP_CNT_TBL_INC * i;
790*a2a7221dSLuo Jie 			ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
791*a2a7221dSLuo Jie 
792*a2a7221dSLuo Jie 			reg = PPE_PORT_TX_COUNTER_TBL_ADDR + PPE_PORT_TX_COUNTER_TBL_INC * i;
793*a2a7221dSLuo Jie 			ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
794*a2a7221dSLuo Jie 		}
795*a2a7221dSLuo Jie 
796*a2a7221dSLuo Jie 		for (i = 0; i < PPE_VPORT_TX_COUNTER_TBL_ENTRIES; i++) {
797*a2a7221dSLuo Jie 			reg = PPE_VPORT_TX_COUNTER_TBL_ADDR + PPE_VPORT_TX_COUNTER_TBL_INC * i;
798*a2a7221dSLuo Jie 			ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
799*a2a7221dSLuo Jie 
800*a2a7221dSLuo Jie 			reg = PPE_VPORT_TX_DROP_CNT_TBL_ADDR + PPE_VPORT_TX_DROP_CNT_TBL_INC * i;
801*a2a7221dSLuo Jie 			ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
802*a2a7221dSLuo Jie 		}
803*a2a7221dSLuo Jie 
804*a2a7221dSLuo Jie 		break;
805*a2a7221dSLuo Jie 	case PPE_CNT_QM:
806*a2a7221dSLuo Jie 		for (i = 0; i < PPE_QUEUE_TX_COUNTER_TBL_ENTRIES; i++) {
807*a2a7221dSLuo Jie 			reg = PPE_QUEUE_TX_COUNTER_TBL_ADDR + PPE_QUEUE_TX_COUNTER_TBL_INC * i;
808*a2a7221dSLuo Jie 			ppe_tbl_pkt_cnt_clear(ppe_dev, reg, PPE_PKT_CNT_SIZE_3WORD);
809*a2a7221dSLuo Jie 		}
810*a2a7221dSLuo Jie 
811*a2a7221dSLuo Jie 		break;
812*a2a7221dSLuo Jie 	default:
813*a2a7221dSLuo Jie 		break;
814*a2a7221dSLuo Jie 	}
815*a2a7221dSLuo Jie 
816*a2a7221dSLuo Jie 	return count;
817*a2a7221dSLuo Jie }
818*a2a7221dSLuo Jie DEFINE_SHOW_STORE_ATTRIBUTE(ppe_packet_counter);
819*a2a7221dSLuo Jie 
820*a2a7221dSLuo Jie void ppe_debugfs_setup(struct ppe_device *ppe_dev)
821*a2a7221dSLuo Jie {
822*a2a7221dSLuo Jie 	struct ppe_debugfs_entry *entry;
823*a2a7221dSLuo Jie 	int i;
824*a2a7221dSLuo Jie 
825*a2a7221dSLuo Jie 	ppe_dev->debugfs_root = debugfs_create_dir("ppe", NULL);
826*a2a7221dSLuo Jie 	if (IS_ERR(ppe_dev->debugfs_root))
827*a2a7221dSLuo Jie 		return;
828*a2a7221dSLuo Jie 
829*a2a7221dSLuo Jie 	for (i = 0; i < ARRAY_SIZE(debugfs_files); i++) {
830*a2a7221dSLuo Jie 		entry = devm_kzalloc(ppe_dev->dev, sizeof(*entry), GFP_KERNEL);
831*a2a7221dSLuo Jie 		if (!entry)
832*a2a7221dSLuo Jie 			return;
833*a2a7221dSLuo Jie 
834*a2a7221dSLuo Jie 		entry->ppe = ppe_dev;
835*a2a7221dSLuo Jie 		entry->counter_type = debugfs_files[i].counter_type;
836*a2a7221dSLuo Jie 
837*a2a7221dSLuo Jie 		debugfs_create_file(debugfs_files[i].name, 0444,
838*a2a7221dSLuo Jie 				    ppe_dev->debugfs_root, entry,
839*a2a7221dSLuo Jie 				    &ppe_packet_counter_fops);
840*a2a7221dSLuo Jie 	}
841*a2a7221dSLuo Jie }
842*a2a7221dSLuo Jie 
843*a2a7221dSLuo Jie void ppe_debugfs_teardown(struct ppe_device *ppe_dev)
844*a2a7221dSLuo Jie {
845*a2a7221dSLuo Jie 	debugfs_remove_recursive(ppe_dev->debugfs_root);
846*a2a7221dSLuo Jie 	ppe_dev->debugfs_root = NULL;
847*a2a7221dSLuo Jie }
848