File Index
Files and directories
Sign in
FILE

ppe_debugfs.c

File preview with syntax highlighting.

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