Merge branches 'acpi-tables', 'acpi-osl', 'acpi-misc' and 'acpi-tools'
[sfrench/cifs-2.6.git] / drivers / net / ethernet / marvell / mvpp2 / mvpp2_debugfs.c
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 }