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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
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 	if (IS_ERR(port_dir))
456 		return PTR_ERR(port_dir);
457 
458 	port_entry = &port->priv->dbgfs_entries->port_flow_entries[port->id];
459 
460 	port_entry->port = port;
461 	port_entry->dbg_fe = entry;
462 
463 	debugfs_create_file("hash_opts", 0444, port_dir, port_entry,
464 			    &mvpp2_dbgfs_port_flow_hash_opt_fops);
465 
466 	debugfs_create_file("engine", 0444, port_dir, port_entry,
467 			    &mvpp2_dbgfs_port_flow_engine_fops);
468 
469 	return 0;
470 }
471 
472 static int mvpp2_dbgfs_flow_entry_init(struct dentry *parent,
473 				       struct mvpp2 *priv, int flow)
474 {
475 	struct mvpp2_dbgfs_flow_entry *entry;
476 	struct dentry *flow_entry_dir;
477 	char flow_entry_name[10];
478 	int i, ret;
479 
480 	sprintf(flow_entry_name, "%02d", flow);
481 
482 	flow_entry_dir = debugfs_create_dir(flow_entry_name, parent);
483 	if (!flow_entry_dir)
484 		return -ENOMEM;
485 
486 	entry = &priv->dbgfs_entries->flow_entries[flow];
487 
488 	entry->flow = flow;
489 	entry->priv = priv;
490 
491 	debugfs_create_file("dec_hits", 0444, flow_entry_dir, entry,
492 			    &mvpp2_dbgfs_flow_dec_hits_fops);
493 
494 	debugfs_create_file("type", 0444, flow_entry_dir, entry,
495 			    &mvpp2_dbgfs_flow_type_fops);
496 
497 	debugfs_create_file("id", 0444, flow_entry_dir, entry,
498 			    &mvpp2_dbgfs_flow_id_fops);
499 
500 	/* Create entry for each port */
501 	for (i = 0; i < priv->port_count; i++) {
502 		ret = mvpp2_dbgfs_flow_port_init(flow_entry_dir,
503 						 priv->port_list[i], entry);
504 		if (ret)
505 			return ret;
506 	}
507 
508 	return 0;
509 }
510 
511 static int mvpp2_dbgfs_flow_init(struct dentry *parent, struct mvpp2 *priv)
512 {
513 	struct dentry *flow_dir;
514 	int i, ret;
515 
516 	flow_dir = debugfs_create_dir("flows", parent);
517 	if (!flow_dir)
518 		return -ENOMEM;
519 
520 	for (i = 0; i < MVPP2_N_PRS_FLOWS; i++) {
521 		ret = mvpp2_dbgfs_flow_entry_init(flow_dir, priv, i);
522 		if (ret)
523 			return ret;
524 	}
525 
526 	return 0;
527 }
528 
529 static int mvpp2_dbgfs_prs_entry_init(struct dentry *parent,
530 				      struct mvpp2 *priv, int tid)
531 {
532 	struct mvpp2_dbgfs_prs_entry *entry;
533 	struct dentry *prs_entry_dir;
534 	char prs_entry_name[10];
535 
536 	if (tid >= MVPP2_PRS_TCAM_SRAM_SIZE)
537 		return -EINVAL;
538 
539 	sprintf(prs_entry_name, "%03d", tid);
540 
541 	prs_entry_dir = debugfs_create_dir(prs_entry_name, parent);
542 	if (!prs_entry_dir)
543 		return -ENOMEM;
544 
545 	entry = &priv->dbgfs_entries->prs_entries[tid];
546 
547 	entry->tid = tid;
548 	entry->priv = priv;
549 
550 	/* Create each attr */
551 	debugfs_create_file("sram", 0444, prs_entry_dir, entry,
552 			    &mvpp2_dbgfs_prs_sram_fops);
553 
554 	debugfs_create_file("valid", 0644, prs_entry_dir, entry,
555 			    &mvpp2_dbgfs_prs_valid_fops);
556 
557 	debugfs_create_file("lookup_id", 0644, prs_entry_dir, entry,
558 			    &mvpp2_dbgfs_prs_lu_fops);
559 
560 	debugfs_create_file("ai", 0644, prs_entry_dir, entry,
561 			    &mvpp2_dbgfs_prs_ai_fops);
562 
563 	debugfs_create_file("header_data", 0644, prs_entry_dir, entry,
564 			    &mvpp2_dbgfs_prs_hdata_fops);
565 
566 	debugfs_create_file("hits", 0444, prs_entry_dir, entry,
567 			    &mvpp2_dbgfs_prs_hits_fops);
568 
569 	debugfs_create_file("pmap", 0444, prs_entry_dir, entry,
570 			     &mvpp2_dbgfs_prs_pmap_fops);
571 
572 	return 0;
573 }
574 
575 static int mvpp2_dbgfs_prs_init(struct dentry *parent, struct mvpp2 *priv)
576 {
577 	struct dentry *prs_dir;
578 	int i, ret;
579 
580 	prs_dir = debugfs_create_dir("parser", parent);
581 	if (!prs_dir)
582 		return -ENOMEM;
583 
584 	for (i = 0; i < MVPP2_PRS_TCAM_SRAM_SIZE; i++) {
585 		ret = mvpp2_dbgfs_prs_entry_init(prs_dir, priv, i);
586 		if (ret)
587 			return ret;
588 	}
589 
590 	return 0;
591 }
592 
593 static int mvpp2_dbgfs_c2_entry_init(struct dentry *parent,
594 				     struct mvpp2 *priv, int id)
595 {
596 	struct mvpp2_dbgfs_c2_entry *entry;
597 	struct dentry *c2_entry_dir;
598 	char c2_entry_name[10];
599 
600 	if (id >= MVPP22_CLS_C2_N_ENTRIES)
601 		return -EINVAL;
602 
603 	sprintf(c2_entry_name, "%03d", id);
604 
605 	c2_entry_dir = debugfs_create_dir(c2_entry_name, parent);
606 	if (!c2_entry_dir)
607 		return -ENOMEM;
608 
609 	entry = &priv->dbgfs_entries->c2_entries[id];
610 
611 	entry->id = id;
612 	entry->priv = priv;
613 
614 	debugfs_create_file("hits", 0444, c2_entry_dir, entry,
615 			    &mvpp2_dbgfs_flow_c2_hits_fops);
616 
617 	debugfs_create_file("default_rxq", 0444, c2_entry_dir, entry,
618 			    &mvpp2_dbgfs_flow_c2_rxq_fops);
619 
620 	debugfs_create_file("rss_enable", 0444, c2_entry_dir, entry,
621 			    &mvpp2_dbgfs_flow_c2_enable_fops);
622 
623 	return 0;
624 }
625 
626 static int mvpp2_dbgfs_flow_tbl_entry_init(struct dentry *parent,
627 					   struct mvpp2 *priv, int id)
628 {
629 	struct mvpp2_dbgfs_flow_tbl_entry *entry;
630 	struct dentry *flow_tbl_entry_dir;
631 	char flow_tbl_entry_name[10];
632 
633 	if (id >= MVPP2_CLS_FLOWS_TBL_SIZE)
634 		return -EINVAL;
635 
636 	sprintf(flow_tbl_entry_name, "%03d", id);
637 
638 	flow_tbl_entry_dir = debugfs_create_dir(flow_tbl_entry_name, parent);
639 	if (!flow_tbl_entry_dir)
640 		return -ENOMEM;
641 
642 	entry = &priv->dbgfs_entries->flt_entries[id];
643 
644 	entry->id = id;
645 	entry->priv = priv;
646 
647 	debugfs_create_file("hits", 0444, flow_tbl_entry_dir, entry,
648 			    &mvpp2_dbgfs_flow_flt_hits_fops);
649 
650 	return 0;
651 }
652 
653 static int mvpp2_dbgfs_cls_init(struct dentry *parent, struct mvpp2 *priv)
654 {
655 	struct dentry *cls_dir, *c2_dir, *flow_tbl_dir;
656 	int i, ret;
657 
658 	cls_dir = debugfs_create_dir("classifier", parent);
659 	if (!cls_dir)
660 		return -ENOMEM;
661 
662 	c2_dir = debugfs_create_dir("c2", cls_dir);
663 	if (!c2_dir)
664 		return -ENOMEM;
665 
666 	for (i = 0; i < MVPP22_CLS_C2_N_ENTRIES; i++) {
667 		ret = mvpp2_dbgfs_c2_entry_init(c2_dir, priv, i);
668 		if (ret)
669 			return ret;
670 	}
671 
672 	flow_tbl_dir = debugfs_create_dir("flow_table", cls_dir);
673 	if (!flow_tbl_dir)
674 		return -ENOMEM;
675 
676 	for (i = 0; i < MVPP2_CLS_FLOWS_TBL_SIZE; i++) {
677 		ret = mvpp2_dbgfs_flow_tbl_entry_init(flow_tbl_dir, priv, i);
678 		if (ret)
679 			return ret;
680 	}
681 
682 	return 0;
683 }
684 
685 static int mvpp2_dbgfs_port_init(struct dentry *parent,
686 				 struct mvpp2_port *port)
687 {
688 	struct dentry *port_dir;
689 
690 	port_dir = debugfs_create_dir(port->dev->name, parent);
691 	if (IS_ERR(port_dir))
692 		return PTR_ERR(port_dir);
693 
694 	debugfs_create_file("parser_entries", 0444, port_dir, port,
695 			    &mvpp2_dbgfs_port_parser_fops);
696 
697 	debugfs_create_file("mac_filter", 0444, port_dir, port,
698 			    &mvpp2_dbgfs_filter_fops);
699 
700 	debugfs_create_file("vid_filter", 0444, port_dir, port,
701 			    &mvpp2_dbgfs_port_vid_fops);
702 
703 	return 0;
704 }
705 
706 void mvpp2_dbgfs_cleanup(struct mvpp2 *priv)
707 {
708 	debugfs_remove_recursive(priv->dbgfs_dir);
709 
710 	kfree(priv->dbgfs_entries);
711 }
712 
713 void mvpp2_dbgfs_init(struct mvpp2 *priv, const char *name)
714 {
715 	struct dentry *mvpp2_dir, *mvpp2_root;
716 	int ret, i;
717 
718 	mvpp2_root = debugfs_lookup(MVPP2_DRIVER_NAME, NULL);
719 	if (!mvpp2_root) {
720 		mvpp2_root = debugfs_create_dir(MVPP2_DRIVER_NAME, NULL);
721 		if (IS_ERR(mvpp2_root))
722 			return;
723 	}
724 
725 	mvpp2_dir = debugfs_create_dir(name, mvpp2_root);
726 	if (IS_ERR(mvpp2_dir))
727 		return;
728 
729 	priv->dbgfs_dir = mvpp2_dir;
730 	priv->dbgfs_entries = kzalloc(sizeof(*priv->dbgfs_entries), GFP_KERNEL);
731 	if (!priv->dbgfs_entries)
732 		goto err;
733 
734 	ret = mvpp2_dbgfs_prs_init(mvpp2_dir, priv);
735 	if (ret)
736 		goto err;
737 
738 	ret = mvpp2_dbgfs_cls_init(mvpp2_dir, priv);
739 	if (ret)
740 		goto err;
741 
742 	for (i = 0; i < priv->port_count; i++) {
743 		ret = mvpp2_dbgfs_port_init(mvpp2_dir, priv->port_list[i]);
744 		if (ret)
745 			goto err;
746 	}
747 
748 	ret = mvpp2_dbgfs_flow_init(mvpp2_dir, priv);
749 	if (ret)
750 		goto err;
751 
752 	return;
753 err:
754 	mvpp2_dbgfs_cleanup(priv);
755 }
756