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 
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 
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 
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 
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 
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 
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 
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 
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 
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 
686 void mvpp2_dbgfs_exit(void)
687 {
688 	debugfs_remove(mvpp2_root);
689 }
690 
691 void mvpp2_dbgfs_cleanup(struct mvpp2 *priv)
692 {
693 	debugfs_remove_recursive(priv->dbgfs_dir);
694 
695 	kfree(priv->dbgfs_entries);
696 }
697 
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