xref: /openbmc/linux/drivers/net/ethernet/marvell/mvpp2/mvpp2_debugfs.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1  // SPDX-License-Identifier: GPL-2.0
2  /*
3   * Driver for Marvell PPv2 network controller for Armada 375 SoC.
4   *
5   * Copyright (C) 2018 Marvell
6   */
7  
8  #include <linux/kernel.h>
9  #include <linux/slab.h>
10  #include <linux/debugfs.h>
11  
12  #include "mvpp2.h"
13  #include "mvpp2_prs.h"
14  #include "mvpp2_cls.h"
15  
16  struct mvpp2_dbgfs_prs_entry {
17  	int tid;
18  	struct mvpp2 *priv;
19  };
20  
21  struct mvpp2_dbgfs_c2_entry {
22  	int id;
23  	struct mvpp2 *priv;
24  };
25  
26  struct mvpp2_dbgfs_flow_entry {
27  	int flow;
28  	struct mvpp2 *priv;
29  };
30  
31  struct mvpp2_dbgfs_flow_tbl_entry {
32  	int id;
33  	struct mvpp2 *priv;
34  };
35  
36  struct mvpp2_dbgfs_port_flow_entry {
37  	struct mvpp2_port *port;
38  	struct mvpp2_dbgfs_flow_entry *dbg_fe;
39  };
40  
41  struct mvpp2_dbgfs_entries {
42  	/* Entries for Header Parser debug info */
43  	struct mvpp2_dbgfs_prs_entry prs_entries[MVPP2_PRS_TCAM_SRAM_SIZE];
44  
45  	/* Entries for Classifier C2 engine debug info */
46  	struct mvpp2_dbgfs_c2_entry c2_entries[MVPP22_CLS_C2_N_ENTRIES];
47  
48  	/* Entries for Classifier Flow Table debug info */
49  	struct mvpp2_dbgfs_flow_tbl_entry flt_entries[MVPP2_CLS_FLOWS_TBL_SIZE];
50  
51  	/* Entries for Classifier flows debug info */
52  	struct mvpp2_dbgfs_flow_entry flow_entries[MVPP2_N_PRS_FLOWS];
53  
54  	/* Entries for per-port flows debug info */
55  	struct mvpp2_dbgfs_port_flow_entry port_flow_entries[MVPP2_MAX_PORTS];
56  };
57  
mvpp2_dbgfs_flow_flt_hits_show(struct seq_file * s,void * unused)58  static int mvpp2_dbgfs_flow_flt_hits_show(struct seq_file *s, void *unused)
59  {
60  	struct mvpp2_dbgfs_flow_tbl_entry *entry = s->private;
61  
62  	u32 hits = mvpp2_cls_flow_hits(entry->priv, entry->id);
63  
64  	seq_printf(s, "%u\n", hits);
65  
66  	return 0;
67  }
68  
69  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_flt_hits);
70  
mvpp2_dbgfs_flow_dec_hits_show(struct seq_file * s,void * unused)71  static int mvpp2_dbgfs_flow_dec_hits_show(struct seq_file *s, void *unused)
72  {
73  	struct mvpp2_dbgfs_flow_entry *entry = s->private;
74  
75  	u32 hits = mvpp2_cls_lookup_hits(entry->priv, entry->flow);
76  
77  	seq_printf(s, "%u\n", hits);
78  
79  	return 0;
80  }
81  
82  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_dec_hits);
83  
mvpp2_dbgfs_flow_type_show(struct seq_file * s,void * unused)84  static int mvpp2_dbgfs_flow_type_show(struct seq_file *s, void *unused)
85  {
86  	struct mvpp2_dbgfs_flow_entry *entry = s->private;
87  	const struct mvpp2_cls_flow *f;
88  	const char *flow_name;
89  
90  	f = mvpp2_cls_flow_get(entry->flow);
91  	if (!f)
92  		return -EINVAL;
93  
94  	switch (f->flow_type) {
95  	case IPV4_FLOW:
96  		flow_name = "ipv4";
97  		break;
98  	case IPV6_FLOW:
99  		flow_name = "ipv6";
100  		break;
101  	case TCP_V4_FLOW:
102  		flow_name = "tcp4";
103  		break;
104  	case TCP_V6_FLOW:
105  		flow_name = "tcp6";
106  		break;
107  	case UDP_V4_FLOW:
108  		flow_name = "udp4";
109  		break;
110  	case UDP_V6_FLOW:
111  		flow_name = "udp6";
112  		break;
113  	default:
114  		flow_name = "other";
115  	}
116  
117  	seq_printf(s, "%s\n", flow_name);
118  
119  	return 0;
120  }
121  
122  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_type);
123  
mvpp2_dbgfs_flow_id_show(struct seq_file * s,void * unused)124  static int mvpp2_dbgfs_flow_id_show(struct seq_file *s, void *unused)
125  {
126  	const struct mvpp2_dbgfs_flow_entry *entry = s->private;
127  	const struct mvpp2_cls_flow *f;
128  
129  	f = mvpp2_cls_flow_get(entry->flow);
130  	if (!f)
131  		return -EINVAL;
132  
133  	seq_printf(s, "%d\n", f->flow_id);
134  
135  	return 0;
136  }
137  
138  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_id);
139  
mvpp2_dbgfs_port_flow_hash_opt_show(struct seq_file * s,void * unused)140  static int mvpp2_dbgfs_port_flow_hash_opt_show(struct seq_file *s, void *unused)
141  {
142  	struct mvpp2_dbgfs_port_flow_entry *entry = s->private;
143  	struct mvpp2_port *port = entry->port;
144  	struct mvpp2_cls_flow_entry fe;
145  	const struct mvpp2_cls_flow *f;
146  	int flow_index;
147  	u16 hash_opts;
148  
149  	f = mvpp2_cls_flow_get(entry->dbg_fe->flow);
150  	if (!f)
151  		return -EINVAL;
152  
153  	flow_index = MVPP2_CLS_FLT_HASH_ENTRY(entry->port->id, f->flow_id);
154  
155  	mvpp2_cls_flow_read(port->priv, flow_index, &fe);
156  
157  	hash_opts = mvpp2_flow_get_hek_fields(&fe);
158  
159  	seq_printf(s, "0x%04x\n", hash_opts);
160  
161  	return 0;
162  }
163  
164  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_flow_hash_opt);
165  
mvpp2_dbgfs_port_flow_engine_show(struct seq_file * s,void * unused)166  static int mvpp2_dbgfs_port_flow_engine_show(struct seq_file *s, void *unused)
167  {
168  	struct mvpp2_dbgfs_port_flow_entry *entry = s->private;
169  	struct mvpp2_port *port = entry->port;
170  	struct mvpp2_cls_flow_entry fe;
171  	const struct mvpp2_cls_flow *f;
172  	int flow_index, engine;
173  
174  	f = mvpp2_cls_flow_get(entry->dbg_fe->flow);
175  	if (!f)
176  		return -EINVAL;
177  
178  	flow_index = MVPP2_CLS_FLT_HASH_ENTRY(entry->port->id, f->flow_id);
179  
180  	mvpp2_cls_flow_read(port->priv, flow_index, &fe);
181  
182  	engine = mvpp2_cls_flow_eng_get(&fe);
183  
184  	seq_printf(s, "%d\n", engine);
185  
186  	return 0;
187  }
188  
189  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_flow_engine);
190  
mvpp2_dbgfs_flow_c2_hits_show(struct seq_file * s,void * unused)191  static int mvpp2_dbgfs_flow_c2_hits_show(struct seq_file *s, void *unused)
192  {
193  	struct mvpp2_dbgfs_c2_entry *entry = s->private;
194  	u32 hits;
195  
196  	hits = mvpp2_cls_c2_hit_count(entry->priv, entry->id);
197  
198  	seq_printf(s, "%u\n", hits);
199  
200  	return 0;
201  }
202  
203  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_c2_hits);
204  
mvpp2_dbgfs_flow_c2_rxq_show(struct seq_file * s,void * unused)205  static int mvpp2_dbgfs_flow_c2_rxq_show(struct seq_file *s, void *unused)
206  {
207  	struct mvpp2_dbgfs_c2_entry *entry = s->private;
208  	struct mvpp2_cls_c2_entry c2;
209  	u8 qh, ql;
210  
211  	mvpp2_cls_c2_read(entry->priv, entry->id, &c2);
212  
213  	qh = (c2.attr[0] >> MVPP22_CLS_C2_ATTR0_QHIGH_OFFS) &
214  	     MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
215  
216  	ql = (c2.attr[0] >> MVPP22_CLS_C2_ATTR0_QLOW_OFFS) &
217  	     MVPP22_CLS_C2_ATTR0_QLOW_MASK;
218  
219  	seq_printf(s, "%d\n", (qh << 3 | ql));
220  
221  	return 0;
222  }
223  
224  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_c2_rxq);
225  
mvpp2_dbgfs_flow_c2_enable_show(struct seq_file * s,void * unused)226  static int mvpp2_dbgfs_flow_c2_enable_show(struct seq_file *s, void *unused)
227  {
228  	struct mvpp2_dbgfs_c2_entry *entry = s->private;
229  	struct mvpp2_cls_c2_entry c2;
230  	int enabled;
231  
232  	mvpp2_cls_c2_read(entry->priv, entry->id, &c2);
233  
234  	enabled = !!(c2.attr[2] & MVPP22_CLS_C2_ATTR2_RSS_EN);
235  
236  	seq_printf(s, "%d\n", enabled);
237  
238  	return 0;
239  }
240  
241  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_c2_enable);
242  
mvpp2_dbgfs_port_vid_show(struct seq_file * s,void * unused)243  static int mvpp2_dbgfs_port_vid_show(struct seq_file *s, void *unused)
244  {
245  	struct mvpp2_port *port = s->private;
246  	unsigned char byte[2], enable[2];
247  	struct mvpp2 *priv = port->priv;
248  	struct mvpp2_prs_entry pe;
249  	unsigned long pmap;
250  	u16 rvid;
251  	int tid;
252  
253  	for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id);
254  	     tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) {
255  		mvpp2_prs_init_from_hw(priv, &pe, tid);
256  
257  		pmap = mvpp2_prs_tcam_port_map_get(&pe);
258  
259  		if (!priv->prs_shadow[tid].valid)
260  			continue;
261  
262  		if (!test_bit(port->id, &pmap))
263  			continue;
264  
265  		mvpp2_prs_tcam_data_byte_get(&pe, 2, &byte[0], &enable[0]);
266  		mvpp2_prs_tcam_data_byte_get(&pe, 3, &byte[1], &enable[1]);
267  
268  		rvid = ((byte[0] & 0xf) << 8) + byte[1];
269  
270  		seq_printf(s, "%u\n", rvid);
271  	}
272  
273  	return 0;
274  }
275  
276  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_vid);
277  
mvpp2_dbgfs_port_parser_show(struct seq_file * s,void * unused)278  static int mvpp2_dbgfs_port_parser_show(struct seq_file *s, void *unused)
279  {
280  	struct mvpp2_port *port = s->private;
281  	struct mvpp2 *priv = port->priv;
282  	struct mvpp2_prs_entry pe;
283  	unsigned long pmap;
284  	int i;
285  
286  	for (i = 0; i < MVPP2_PRS_TCAM_SRAM_SIZE; i++) {
287  		mvpp2_prs_init_from_hw(port->priv, &pe, i);
288  
289  		pmap = mvpp2_prs_tcam_port_map_get(&pe);
290  		if (priv->prs_shadow[i].valid && test_bit(port->id, &pmap))
291  			seq_printf(s, "%03d\n", i);
292  	}
293  
294  	return 0;
295  }
296  
297  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_parser);
298  
mvpp2_dbgfs_filter_show(struct seq_file * s,void * unused)299  static int mvpp2_dbgfs_filter_show(struct seq_file *s, void *unused)
300  {
301  	struct mvpp2_port *port = s->private;
302  	struct mvpp2 *priv = port->priv;
303  	struct mvpp2_prs_entry pe;
304  	unsigned long pmap;
305  	int index, tid;
306  
307  	for (tid = MVPP2_PE_MAC_RANGE_START;
308  	     tid <= MVPP2_PE_MAC_RANGE_END; tid++) {
309  		unsigned char da[ETH_ALEN], da_mask[ETH_ALEN];
310  
311  		if (!priv->prs_shadow[tid].valid ||
312  		    priv->prs_shadow[tid].lu != MVPP2_PRS_LU_MAC ||
313  		    priv->prs_shadow[tid].udf != MVPP2_PRS_UDF_MAC_DEF)
314  			continue;
315  
316  		mvpp2_prs_init_from_hw(priv, &pe, tid);
317  
318  		pmap = mvpp2_prs_tcam_port_map_get(&pe);
319  
320  		/* We only want entries active on this port */
321  		if (!test_bit(port->id, &pmap))
322  			continue;
323  
324  		/* Read mac addr from entry */
325  		for (index = 0; index < ETH_ALEN; index++)
326  			mvpp2_prs_tcam_data_byte_get(&pe, index, &da[index],
327  						     &da_mask[index]);
328  
329  		seq_printf(s, "%pM\n", da);
330  	}
331  
332  	return 0;
333  }
334  
335  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_filter);
336  
mvpp2_dbgfs_prs_lu_show(struct seq_file * s,void * unused)337  static int mvpp2_dbgfs_prs_lu_show(struct seq_file *s, void *unused)
338  {
339  	struct mvpp2_dbgfs_prs_entry *entry = s->private;
340  	struct mvpp2 *priv = entry->priv;
341  
342  	seq_printf(s, "%x\n", priv->prs_shadow[entry->tid].lu);
343  
344  	return 0;
345  }
346  
347  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_lu);
348  
mvpp2_dbgfs_prs_pmap_show(struct seq_file * s,void * unused)349  static int mvpp2_dbgfs_prs_pmap_show(struct seq_file *s, void *unused)
350  {
351  	struct mvpp2_dbgfs_prs_entry *entry = s->private;
352  	struct mvpp2_prs_entry pe;
353  	unsigned int pmap;
354  
355  	mvpp2_prs_init_from_hw(entry->priv, &pe, entry->tid);
356  
357  	pmap = mvpp2_prs_tcam_port_map_get(&pe);
358  	pmap &= MVPP2_PRS_PORT_MASK;
359  
360  	seq_printf(s, "%02x\n", pmap);
361  
362  	return 0;
363  }
364  
365  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_pmap);
366  
mvpp2_dbgfs_prs_ai_show(struct seq_file * s,void * unused)367  static int mvpp2_dbgfs_prs_ai_show(struct seq_file *s, void *unused)
368  {
369  	struct mvpp2_dbgfs_prs_entry *entry = s->private;
370  	struct mvpp2_prs_entry pe;
371  	unsigned char ai, ai_mask;
372  
373  	mvpp2_prs_init_from_hw(entry->priv, &pe, entry->tid);
374  
375  	ai = pe.tcam[MVPP2_PRS_TCAM_AI_WORD] & MVPP2_PRS_AI_MASK;
376  	ai_mask = (pe.tcam[MVPP2_PRS_TCAM_AI_WORD] >> 16) & MVPP2_PRS_AI_MASK;
377  
378  	seq_printf(s, "%02x %02x\n", ai, ai_mask);
379  
380  	return 0;
381  }
382  
383  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_ai);
384  
mvpp2_dbgfs_prs_hdata_show(struct seq_file * s,void * unused)385  static int mvpp2_dbgfs_prs_hdata_show(struct seq_file *s, void *unused)
386  {
387  	struct mvpp2_dbgfs_prs_entry *entry = s->private;
388  	struct mvpp2_prs_entry pe;
389  	unsigned char data[8], mask[8];
390  	int i;
391  
392  	mvpp2_prs_init_from_hw(entry->priv, &pe, entry->tid);
393  
394  	for (i = 0; i < 8; i++)
395  		mvpp2_prs_tcam_data_byte_get(&pe, i, &data[i], &mask[i]);
396  
397  	seq_printf(s, "%*phN %*phN\n", 8, data, 8, mask);
398  
399  	return 0;
400  }
401  
402  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_hdata);
403  
mvpp2_dbgfs_prs_sram_show(struct seq_file * s,void * unused)404  static int mvpp2_dbgfs_prs_sram_show(struct seq_file *s, void *unused)
405  {
406  	struct mvpp2_dbgfs_prs_entry *entry = s->private;
407  	struct mvpp2_prs_entry pe;
408  
409  	mvpp2_prs_init_from_hw(entry->priv, &pe, entry->tid);
410  
411  	seq_printf(s, "%*phN\n", 14, pe.sram);
412  
413  	return 0;
414  }
415  
416  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_sram);
417  
mvpp2_dbgfs_prs_hits_show(struct seq_file * s,void * unused)418  static int mvpp2_dbgfs_prs_hits_show(struct seq_file *s, void *unused)
419  {
420  	struct mvpp2_dbgfs_prs_entry *entry = s->private;
421  	int val;
422  
423  	val = mvpp2_prs_hits(entry->priv, entry->tid);
424  	if (val < 0)
425  		return val;
426  
427  	seq_printf(s, "%d\n", val);
428  
429  	return 0;
430  }
431  
432  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_hits);
433  
mvpp2_dbgfs_prs_valid_show(struct seq_file * s,void * unused)434  static int mvpp2_dbgfs_prs_valid_show(struct seq_file *s, void *unused)
435  {
436  	struct mvpp2_dbgfs_prs_entry *entry = s->private;
437  	struct mvpp2 *priv = entry->priv;
438  	int tid = entry->tid;
439  
440  	seq_printf(s, "%d\n", priv->prs_shadow[tid].valid ? 1 : 0);
441  
442  	return 0;
443  }
444  
445  DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_valid);
446  
mvpp2_dbgfs_flow_port_init(struct dentry * parent,struct mvpp2_port * port,struct mvpp2_dbgfs_flow_entry * entry)447  static int mvpp2_dbgfs_flow_port_init(struct dentry *parent,
448  				      struct mvpp2_port *port,
449  				      struct mvpp2_dbgfs_flow_entry *entry)
450  {
451  	struct mvpp2_dbgfs_port_flow_entry *port_entry;
452  	struct dentry *port_dir;
453  
454  	port_dir = debugfs_create_dir(port->dev->name, parent);
455  
456  	port_entry = &port->priv->dbgfs_entries->port_flow_entries[port->id];
457  
458  	port_entry->port = port;
459  	port_entry->dbg_fe = entry;
460  
461  	debugfs_create_file("hash_opts", 0444, port_dir, port_entry,
462  			    &mvpp2_dbgfs_port_flow_hash_opt_fops);
463  
464  	debugfs_create_file("engine", 0444, port_dir, port_entry,
465  			    &mvpp2_dbgfs_port_flow_engine_fops);
466  
467  	return 0;
468  }
469  
mvpp2_dbgfs_flow_entry_init(struct dentry * parent,struct mvpp2 * priv,int flow)470  static int mvpp2_dbgfs_flow_entry_init(struct dentry *parent,
471  				       struct mvpp2 *priv, int flow)
472  {
473  	struct mvpp2_dbgfs_flow_entry *entry;
474  	struct dentry *flow_entry_dir;
475  	char flow_entry_name[10];
476  	int i, ret;
477  
478  	sprintf(flow_entry_name, "%02d", flow);
479  
480  	flow_entry_dir = debugfs_create_dir(flow_entry_name, parent);
481  
482  	entry = &priv->dbgfs_entries->flow_entries[flow];
483  
484  	entry->flow = flow;
485  	entry->priv = priv;
486  
487  	debugfs_create_file("dec_hits", 0444, flow_entry_dir, entry,
488  			    &mvpp2_dbgfs_flow_dec_hits_fops);
489  
490  	debugfs_create_file("type", 0444, flow_entry_dir, entry,
491  			    &mvpp2_dbgfs_flow_type_fops);
492  
493  	debugfs_create_file("id", 0444, flow_entry_dir, entry,
494  			    &mvpp2_dbgfs_flow_id_fops);
495  
496  	/* Create entry for each port */
497  	for (i = 0; i < priv->port_count; i++) {
498  		ret = mvpp2_dbgfs_flow_port_init(flow_entry_dir,
499  						 priv->port_list[i], entry);
500  		if (ret)
501  			return ret;
502  	}
503  
504  	return 0;
505  }
506  
mvpp2_dbgfs_flow_init(struct dentry * parent,struct mvpp2 * priv)507  static int mvpp2_dbgfs_flow_init(struct dentry *parent, struct mvpp2 *priv)
508  {
509  	struct dentry *flow_dir;
510  	int i, ret;
511  
512  	flow_dir = debugfs_create_dir("flows", parent);
513  
514  	for (i = 0; i < MVPP2_N_PRS_FLOWS; i++) {
515  		ret = mvpp2_dbgfs_flow_entry_init(flow_dir, priv, i);
516  		if (ret)
517  			return ret;
518  	}
519  
520  	return 0;
521  }
522  
mvpp2_dbgfs_prs_entry_init(struct dentry * parent,struct mvpp2 * priv,int tid)523  static int mvpp2_dbgfs_prs_entry_init(struct dentry *parent,
524  				      struct mvpp2 *priv, int tid)
525  {
526  	struct mvpp2_dbgfs_prs_entry *entry;
527  	struct dentry *prs_entry_dir;
528  	char prs_entry_name[10];
529  
530  	if (tid >= MVPP2_PRS_TCAM_SRAM_SIZE)
531  		return -EINVAL;
532  
533  	sprintf(prs_entry_name, "%03d", tid);
534  
535  	prs_entry_dir = debugfs_create_dir(prs_entry_name, parent);
536  
537  	entry = &priv->dbgfs_entries->prs_entries[tid];
538  
539  	entry->tid = tid;
540  	entry->priv = priv;
541  
542  	/* Create each attr */
543  	debugfs_create_file("sram", 0444, prs_entry_dir, entry,
544  			    &mvpp2_dbgfs_prs_sram_fops);
545  
546  	debugfs_create_file("valid", 0644, prs_entry_dir, entry,
547  			    &mvpp2_dbgfs_prs_valid_fops);
548  
549  	debugfs_create_file("lookup_id", 0644, prs_entry_dir, entry,
550  			    &mvpp2_dbgfs_prs_lu_fops);
551  
552  	debugfs_create_file("ai", 0644, prs_entry_dir, entry,
553  			    &mvpp2_dbgfs_prs_ai_fops);
554  
555  	debugfs_create_file("header_data", 0644, prs_entry_dir, entry,
556  			    &mvpp2_dbgfs_prs_hdata_fops);
557  
558  	debugfs_create_file("hits", 0444, prs_entry_dir, entry,
559  			    &mvpp2_dbgfs_prs_hits_fops);
560  
561  	debugfs_create_file("pmap", 0444, prs_entry_dir, entry,
562  			     &mvpp2_dbgfs_prs_pmap_fops);
563  
564  	return 0;
565  }
566  
mvpp2_dbgfs_prs_init(struct dentry * parent,struct mvpp2 * priv)567  static int mvpp2_dbgfs_prs_init(struct dentry *parent, struct mvpp2 *priv)
568  {
569  	struct dentry *prs_dir;
570  	int i, ret;
571  
572  	prs_dir = debugfs_create_dir("parser", parent);
573  
574  	for (i = 0; i < MVPP2_PRS_TCAM_SRAM_SIZE; i++) {
575  		ret = mvpp2_dbgfs_prs_entry_init(prs_dir, priv, i);
576  		if (ret)
577  			return ret;
578  	}
579  
580  	return 0;
581  }
582  
mvpp2_dbgfs_c2_entry_init(struct dentry * parent,struct mvpp2 * priv,int id)583  static int mvpp2_dbgfs_c2_entry_init(struct dentry *parent,
584  				     struct mvpp2 *priv, int id)
585  {
586  	struct mvpp2_dbgfs_c2_entry *entry;
587  	struct dentry *c2_entry_dir;
588  	char c2_entry_name[10];
589  
590  	if (id >= MVPP22_CLS_C2_N_ENTRIES)
591  		return -EINVAL;
592  
593  	sprintf(c2_entry_name, "%03d", id);
594  
595  	c2_entry_dir = debugfs_create_dir(c2_entry_name, parent);
596  
597  	entry = &priv->dbgfs_entries->c2_entries[id];
598  
599  	entry->id = id;
600  	entry->priv = priv;
601  
602  	debugfs_create_file("hits", 0444, c2_entry_dir, entry,
603  			    &mvpp2_dbgfs_flow_c2_hits_fops);
604  
605  	debugfs_create_file("default_rxq", 0444, c2_entry_dir, entry,
606  			    &mvpp2_dbgfs_flow_c2_rxq_fops);
607  
608  	debugfs_create_file("rss_enable", 0444, c2_entry_dir, entry,
609  			    &mvpp2_dbgfs_flow_c2_enable_fops);
610  
611  	return 0;
612  }
613  
mvpp2_dbgfs_flow_tbl_entry_init(struct dentry * parent,struct mvpp2 * priv,int id)614  static int mvpp2_dbgfs_flow_tbl_entry_init(struct dentry *parent,
615  					   struct mvpp2 *priv, int id)
616  {
617  	struct mvpp2_dbgfs_flow_tbl_entry *entry;
618  	struct dentry *flow_tbl_entry_dir;
619  	char flow_tbl_entry_name[10];
620  
621  	if (id >= MVPP2_CLS_FLOWS_TBL_SIZE)
622  		return -EINVAL;
623  
624  	sprintf(flow_tbl_entry_name, "%03d", id);
625  
626  	flow_tbl_entry_dir = debugfs_create_dir(flow_tbl_entry_name, parent);
627  
628  	entry = &priv->dbgfs_entries->flt_entries[id];
629  
630  	entry->id = id;
631  	entry->priv = priv;
632  
633  	debugfs_create_file("hits", 0444, flow_tbl_entry_dir, entry,
634  			    &mvpp2_dbgfs_flow_flt_hits_fops);
635  
636  	return 0;
637  }
638  
mvpp2_dbgfs_cls_init(struct dentry * parent,struct mvpp2 * priv)639  static int mvpp2_dbgfs_cls_init(struct dentry *parent, struct mvpp2 *priv)
640  {
641  	struct dentry *cls_dir, *c2_dir, *flow_tbl_dir;
642  	int i, ret;
643  
644  	cls_dir = debugfs_create_dir("classifier", parent);
645  
646  	c2_dir = debugfs_create_dir("c2", cls_dir);
647  
648  	for (i = 0; i < MVPP22_CLS_C2_N_ENTRIES; i++) {
649  		ret = mvpp2_dbgfs_c2_entry_init(c2_dir, priv, i);
650  		if (ret)
651  			return ret;
652  	}
653  
654  	flow_tbl_dir = debugfs_create_dir("flow_table", cls_dir);
655  
656  	for (i = 0; i < MVPP2_CLS_FLOWS_TBL_SIZE; i++) {
657  		ret = mvpp2_dbgfs_flow_tbl_entry_init(flow_tbl_dir, priv, i);
658  		if (ret)
659  			return ret;
660  	}
661  
662  	return 0;
663  }
664  
mvpp2_dbgfs_port_init(struct dentry * parent,struct mvpp2_port * port)665  static int mvpp2_dbgfs_port_init(struct dentry *parent,
666  				 struct mvpp2_port *port)
667  {
668  	struct dentry *port_dir;
669  
670  	port_dir = debugfs_create_dir(port->dev->name, parent);
671  
672  	debugfs_create_file("parser_entries", 0444, port_dir, port,
673  			    &mvpp2_dbgfs_port_parser_fops);
674  
675  	debugfs_create_file("mac_filter", 0444, port_dir, port,
676  			    &mvpp2_dbgfs_filter_fops);
677  
678  	debugfs_create_file("vid_filter", 0444, port_dir, port,
679  			    &mvpp2_dbgfs_port_vid_fops);
680  
681  	return 0;
682  }
683  
684  static struct dentry *mvpp2_root;
685  
mvpp2_dbgfs_exit(void)686  void mvpp2_dbgfs_exit(void)
687  {
688  	debugfs_remove(mvpp2_root);
689  }
690  
mvpp2_dbgfs_cleanup(struct mvpp2 * priv)691  void mvpp2_dbgfs_cleanup(struct mvpp2 *priv)
692  {
693  	debugfs_remove_recursive(priv->dbgfs_dir);
694  
695  	kfree(priv->dbgfs_entries);
696  }
697  
mvpp2_dbgfs_init(struct mvpp2 * priv,const char * name)698  void mvpp2_dbgfs_init(struct mvpp2 *priv, const char *name)
699  {
700  	struct dentry *mvpp2_dir;
701  	int ret, i;
702  
703  	if (!mvpp2_root)
704  		mvpp2_root = debugfs_create_dir(MVPP2_DRIVER_NAME, NULL);
705  
706  	mvpp2_dir = debugfs_create_dir(name, mvpp2_root);
707  
708  	priv->dbgfs_dir = mvpp2_dir;
709  	priv->dbgfs_entries = kzalloc(sizeof(*priv->dbgfs_entries), GFP_KERNEL);
710  	if (!priv->dbgfs_entries)
711  		goto err;
712  
713  	ret = mvpp2_dbgfs_prs_init(mvpp2_dir, priv);
714  	if (ret)
715  		goto err;
716  
717  	ret = mvpp2_dbgfs_cls_init(mvpp2_dir, priv);
718  	if (ret)
719  		goto err;
720  
721  	for (i = 0; i < priv->port_count; i++) {
722  		ret = mvpp2_dbgfs_port_init(mvpp2_dir, priv->port_list[i]);
723  		if (ret)
724  			goto err;
725  	}
726  
727  	ret = mvpp2_dbgfs_flow_init(mvpp2_dir, priv);
728  	if (ret)
729  		goto err;
730  
731  	return;
732  err:
733  	mvpp2_dbgfs_cleanup(priv);
734  }
735