1 // SPDX-License-Identifier: GPL-2.0
3 * Driver for Marvell PPv2 network controller for Armada 375 SoC.
5 * Copyright (C) 2018 Marvell
8 #include <linux/kernel.h>
9 #include <linux/slab.h>
10 #include <linux/debugfs.h>
13 #include "mvpp2_prs.h"
14 #include "mvpp2_cls.h"
16 struct mvpp2_dbgfs_prs_entry
{
21 struct mvpp2_dbgfs_c2_entry
{
26 struct mvpp2_dbgfs_flow_entry
{
31 struct mvpp2_dbgfs_flow_tbl_entry
{
36 struct mvpp2_dbgfs_port_flow_entry
{
37 struct mvpp2_port
*port
;
38 struct mvpp2_dbgfs_flow_entry
*dbg_fe
;
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
];
45 /* Entries for Classifier C2 engine debug info */
46 struct mvpp2_dbgfs_c2_entry c2_entries
[MVPP22_CLS_C2_N_ENTRIES
];
48 /* Entries for Classifier Flow Table debug info */
49 struct mvpp2_dbgfs_flow_tbl_entry flt_entries
[MVPP2_CLS_FLOWS_TBL_SIZE
];
51 /* Entries for Classifier flows debug info */
52 struct mvpp2_dbgfs_flow_entry flow_entries
[MVPP2_N_PRS_FLOWS
];
54 /* Entries for per-port flows debug info */
55 struct mvpp2_dbgfs_port_flow_entry port_flow_entries
[MVPP2_MAX_PORTS
];
58 static int mvpp2_dbgfs_flow_flt_hits_show(struct seq_file
*s
, void *unused
)
60 struct mvpp2_dbgfs_flow_tbl_entry
*entry
= s
->private;
62 u32 hits
= mvpp2_cls_flow_hits(entry
->priv
, entry
->id
);
64 seq_printf(s
, "%u\n", hits
);
69 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_flt_hits
);
71 static int mvpp2_dbgfs_flow_dec_hits_show(struct seq_file
*s
, void *unused
)
73 struct mvpp2_dbgfs_flow_entry
*entry
= s
->private;
75 u32 hits
= mvpp2_cls_lookup_hits(entry
->priv
, entry
->flow
);
77 seq_printf(s
, "%u\n", hits
);
82 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_dec_hits
);
84 static int mvpp2_dbgfs_flow_type_show(struct seq_file
*s
, void *unused
)
86 struct mvpp2_dbgfs_flow_entry
*entry
= s
->private;
87 const struct mvpp2_cls_flow
*f
;
88 const char *flow_name
;
90 f
= mvpp2_cls_flow_get(entry
->flow
);
94 switch (f
->flow_type
) {
117 seq_printf(s
, "%s\n", flow_name
);
122 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_type
);
124 static int mvpp2_dbgfs_flow_id_show(struct seq_file
*s
, void *unused
)
126 const struct mvpp2_dbgfs_flow_entry
*entry
= s
->private;
127 const struct mvpp2_cls_flow
*f
;
129 f
= mvpp2_cls_flow_get(entry
->flow
);
133 seq_printf(s
, "%d\n", f
->flow_id
);
138 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_id
);
140 static int mvpp2_dbgfs_port_flow_hash_opt_show(struct seq_file
*s
, void *unused
)
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
;
149 f
= mvpp2_cls_flow_get(entry
->dbg_fe
->flow
);
153 flow_index
= MVPP2_CLS_FLT_HASH_ENTRY(entry
->port
->id
, f
->flow_id
);
155 mvpp2_cls_flow_read(port
->priv
, flow_index
, &fe
);
157 hash_opts
= mvpp2_flow_get_hek_fields(&fe
);
159 seq_printf(s
, "0x%04x\n", hash_opts
);
164 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_flow_hash_opt
);
166 static int mvpp2_dbgfs_port_flow_engine_show(struct seq_file
*s
, void *unused
)
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
;
174 f
= mvpp2_cls_flow_get(entry
->dbg_fe
->flow
);
178 flow_index
= MVPP2_CLS_FLT_HASH_ENTRY(entry
->port
->id
, f
->flow_id
);
180 mvpp2_cls_flow_read(port
->priv
, flow_index
, &fe
);
182 engine
= mvpp2_cls_flow_eng_get(&fe
);
184 seq_printf(s
, "%d\n", engine
);
189 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_flow_engine
);
191 static int mvpp2_dbgfs_flow_c2_hits_show(struct seq_file
*s
, void *unused
)
193 struct mvpp2_dbgfs_c2_entry
*entry
= s
->private;
196 hits
= mvpp2_cls_c2_hit_count(entry
->priv
, entry
->id
);
198 seq_printf(s
, "%u\n", hits
);
203 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_c2_hits
);
205 static int mvpp2_dbgfs_flow_c2_rxq_show(struct seq_file
*s
, void *unused
)
207 struct mvpp2_dbgfs_c2_entry
*entry
= s
->private;
208 struct mvpp2_cls_c2_entry c2
;
211 mvpp2_cls_c2_read(entry
->priv
, entry
->id
, &c2
);
213 qh
= (c2
.attr
[0] >> MVPP22_CLS_C2_ATTR0_QHIGH_OFFS
) &
214 MVPP22_CLS_C2_ATTR0_QHIGH_MASK
;
216 ql
= (c2
.attr
[0] >> MVPP22_CLS_C2_ATTR0_QLOW_OFFS
) &
217 MVPP22_CLS_C2_ATTR0_QLOW_MASK
;
219 seq_printf(s
, "%d\n", (qh
<< 3 | ql
));
224 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_c2_rxq
);
226 static int mvpp2_dbgfs_flow_c2_enable_show(struct seq_file
*s
, void *unused
)
228 struct mvpp2_dbgfs_c2_entry
*entry
= s
->private;
229 struct mvpp2_cls_c2_entry c2
;
232 mvpp2_cls_c2_read(entry
->priv
, entry
->id
, &c2
);
234 enabled
= !!(c2
.attr
[2] & MVPP22_CLS_C2_ATTR2_RSS_EN
);
236 seq_printf(s
, "%d\n", enabled
);
241 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_c2_enable
);
243 static int mvpp2_dbgfs_port_vid_show(struct seq_file
*s
, void *unused
)
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
;
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
);
257 pmap
= mvpp2_prs_tcam_port_map_get(&pe
);
259 if (!priv
->prs_shadow
[tid
].valid
)
262 if (!test_bit(port
->id
, &pmap
))
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]);
268 rvid
= ((byte
[0] & 0xf) << 8) + byte
[1];
270 seq_printf(s
, "%u\n", rvid
);
276 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_vid
);
278 static int mvpp2_dbgfs_port_parser_show(struct seq_file
*s
, void *unused
)
280 struct mvpp2_port
*port
= s
->private;
281 struct mvpp2
*priv
= port
->priv
;
282 struct mvpp2_prs_entry pe
;
286 for (i
= 0; i
< MVPP2_PRS_TCAM_SRAM_SIZE
; i
++) {
287 mvpp2_prs_init_from_hw(port
->priv
, &pe
, i
);
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
);
297 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_parser
);
299 static int mvpp2_dbgfs_filter_show(struct seq_file
*s
, void *unused
)
301 struct mvpp2_port
*port
= s
->private;
302 struct mvpp2
*priv
= port
->priv
;
303 struct mvpp2_prs_entry pe
;
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
];
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
)
316 mvpp2_prs_init_from_hw(priv
, &pe
, tid
);
318 pmap
= mvpp2_prs_tcam_port_map_get(&pe
);
320 /* We only want entries active on this port */
321 if (!test_bit(port
->id
, &pmap
))
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
],
329 seq_printf(s
, "%pM\n", da
);
335 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_filter
);
337 static int mvpp2_dbgfs_prs_lu_show(struct seq_file
*s
, void *unused
)
339 struct mvpp2_dbgfs_prs_entry
*entry
= s
->private;
340 struct mvpp2
*priv
= entry
->priv
;
342 seq_printf(s
, "%x\n", priv
->prs_shadow
[entry
->tid
].lu
);
347 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_lu
);
349 static int mvpp2_dbgfs_prs_pmap_show(struct seq_file
*s
, void *unused
)
351 struct mvpp2_dbgfs_prs_entry
*entry
= s
->private;
352 struct mvpp2_prs_entry pe
;
355 mvpp2_prs_init_from_hw(entry
->priv
, &pe
, entry
->tid
);
357 pmap
= mvpp2_prs_tcam_port_map_get(&pe
);
358 pmap
&= MVPP2_PRS_PORT_MASK
;
360 seq_printf(s
, "%02x\n", pmap
);
365 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_pmap
);
367 static int mvpp2_dbgfs_prs_ai_show(struct seq_file
*s
, void *unused
)
369 struct mvpp2_dbgfs_prs_entry
*entry
= s
->private;
370 struct mvpp2_prs_entry pe
;
371 unsigned char ai
, ai_mask
;
373 mvpp2_prs_init_from_hw(entry
->priv
, &pe
, entry
->tid
);
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
;
378 seq_printf(s
, "%02x %02x\n", ai
, ai_mask
);
383 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_ai
);
385 static int mvpp2_dbgfs_prs_hdata_show(struct seq_file
*s
, void *unused
)
387 struct mvpp2_dbgfs_prs_entry
*entry
= s
->private;
388 struct mvpp2_prs_entry pe
;
389 unsigned char data
[8], mask
[8];
392 mvpp2_prs_init_from_hw(entry
->priv
, &pe
, entry
->tid
);
394 for (i
= 0; i
< 8; i
++)
395 mvpp2_prs_tcam_data_byte_get(&pe
, i
, &data
[i
], &mask
[i
]);
397 seq_printf(s
, "%*phN %*phN\n", 8, data
, 8, mask
);
402 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_hdata
);
404 static int mvpp2_dbgfs_prs_sram_show(struct seq_file
*s
, void *unused
)
406 struct mvpp2_dbgfs_prs_entry
*entry
= s
->private;
407 struct mvpp2_prs_entry pe
;
409 mvpp2_prs_init_from_hw(entry
->priv
, &pe
, entry
->tid
);
411 seq_printf(s
, "%*phN\n", 14, pe
.sram
);
416 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_sram
);
418 static int mvpp2_dbgfs_prs_hits_show(struct seq_file
*s
, void *unused
)
420 struct mvpp2_dbgfs_prs_entry
*entry
= s
->private;
423 val
= mvpp2_prs_hits(entry
->priv
, entry
->tid
);
427 seq_printf(s
, "%d\n", val
);
432 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_hits
);
434 static int mvpp2_dbgfs_prs_valid_show(struct seq_file
*s
, void *unused
)
436 struct mvpp2_dbgfs_prs_entry
*entry
= s
->private;
437 struct mvpp2
*priv
= entry
->priv
;
438 int tid
= entry
->tid
;
440 seq_printf(s
, "%d\n", priv
->prs_shadow
[tid
].valid
? 1 : 0);
445 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_valid
);
447 static int mvpp2_dbgfs_flow_port_init(struct dentry
*parent
,
448 struct mvpp2_port
*port
,
449 struct mvpp2_dbgfs_flow_entry
*entry
)
451 struct mvpp2_dbgfs_port_flow_entry
*port_entry
;
452 struct dentry
*port_dir
;
454 port_dir
= debugfs_create_dir(port
->dev
->name
, parent
);
456 port_entry
= &port
->priv
->dbgfs_entries
->port_flow_entries
[port
->id
];
458 port_entry
->port
= port
;
459 port_entry
->dbg_fe
= entry
;
461 debugfs_create_file("hash_opts", 0444, port_dir
, port_entry
,
462 &mvpp2_dbgfs_port_flow_hash_opt_fops
);
464 debugfs_create_file("engine", 0444, port_dir
, port_entry
,
465 &mvpp2_dbgfs_port_flow_engine_fops
);
470 static int mvpp2_dbgfs_flow_entry_init(struct dentry
*parent
,
471 struct mvpp2
*priv
, int flow
)
473 struct mvpp2_dbgfs_flow_entry
*entry
;
474 struct dentry
*flow_entry_dir
;
475 char flow_entry_name
[10];
478 sprintf(flow_entry_name
, "%02d", flow
);
480 flow_entry_dir
= debugfs_create_dir(flow_entry_name
, parent
);
482 entry
= &priv
->dbgfs_entries
->flow_entries
[flow
];
487 debugfs_create_file("dec_hits", 0444, flow_entry_dir
, entry
,
488 &mvpp2_dbgfs_flow_dec_hits_fops
);
490 debugfs_create_file("type", 0444, flow_entry_dir
, entry
,
491 &mvpp2_dbgfs_flow_type_fops
);
493 debugfs_create_file("id", 0444, flow_entry_dir
, entry
,
494 &mvpp2_dbgfs_flow_id_fops
);
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
);
507 static int mvpp2_dbgfs_flow_init(struct dentry
*parent
, struct mvpp2
*priv
)
509 struct dentry
*flow_dir
;
512 flow_dir
= debugfs_create_dir("flows", parent
);
514 for (i
= 0; i
< MVPP2_N_PRS_FLOWS
; i
++) {
515 ret
= mvpp2_dbgfs_flow_entry_init(flow_dir
, priv
, i
);
523 static int mvpp2_dbgfs_prs_entry_init(struct dentry
*parent
,
524 struct mvpp2
*priv
, int tid
)
526 struct mvpp2_dbgfs_prs_entry
*entry
;
527 struct dentry
*prs_entry_dir
;
528 char prs_entry_name
[10];
530 if (tid
>= MVPP2_PRS_TCAM_SRAM_SIZE
)
533 sprintf(prs_entry_name
, "%03d", tid
);
535 prs_entry_dir
= debugfs_create_dir(prs_entry_name
, parent
);
537 entry
= &priv
->dbgfs_entries
->prs_entries
[tid
];
542 /* Create each attr */
543 debugfs_create_file("sram", 0444, prs_entry_dir
, entry
,
544 &mvpp2_dbgfs_prs_sram_fops
);
546 debugfs_create_file("valid", 0644, prs_entry_dir
, entry
,
547 &mvpp2_dbgfs_prs_valid_fops
);
549 debugfs_create_file("lookup_id", 0644, prs_entry_dir
, entry
,
550 &mvpp2_dbgfs_prs_lu_fops
);
552 debugfs_create_file("ai", 0644, prs_entry_dir
, entry
,
553 &mvpp2_dbgfs_prs_ai_fops
);
555 debugfs_create_file("header_data", 0644, prs_entry_dir
, entry
,
556 &mvpp2_dbgfs_prs_hdata_fops
);
558 debugfs_create_file("hits", 0444, prs_entry_dir
, entry
,
559 &mvpp2_dbgfs_prs_hits_fops
);
561 debugfs_create_file("pmap", 0444, prs_entry_dir
, entry
,
562 &mvpp2_dbgfs_prs_pmap_fops
);
567 static int mvpp2_dbgfs_prs_init(struct dentry
*parent
, struct mvpp2
*priv
)
569 struct dentry
*prs_dir
;
572 prs_dir
= debugfs_create_dir("parser", parent
);
574 for (i
= 0; i
< MVPP2_PRS_TCAM_SRAM_SIZE
; i
++) {
575 ret
= mvpp2_dbgfs_prs_entry_init(prs_dir
, priv
, i
);
583 static int mvpp2_dbgfs_c2_entry_init(struct dentry
*parent
,
584 struct mvpp2
*priv
, int id
)
586 struct mvpp2_dbgfs_c2_entry
*entry
;
587 struct dentry
*c2_entry_dir
;
588 char c2_entry_name
[10];
590 if (id
>= MVPP22_CLS_C2_N_ENTRIES
)
593 sprintf(c2_entry_name
, "%03d", id
);
595 c2_entry_dir
= debugfs_create_dir(c2_entry_name
, parent
);
599 entry
= &priv
->dbgfs_entries
->c2_entries
[id
];
604 debugfs_create_file("hits", 0444, c2_entry_dir
, entry
,
605 &mvpp2_dbgfs_flow_c2_hits_fops
);
607 debugfs_create_file("default_rxq", 0444, c2_entry_dir
, entry
,
608 &mvpp2_dbgfs_flow_c2_rxq_fops
);
610 debugfs_create_file("rss_enable", 0444, c2_entry_dir
, entry
,
611 &mvpp2_dbgfs_flow_c2_enable_fops
);
616 static int mvpp2_dbgfs_flow_tbl_entry_init(struct dentry
*parent
,
617 struct mvpp2
*priv
, int id
)
619 struct mvpp2_dbgfs_flow_tbl_entry
*entry
;
620 struct dentry
*flow_tbl_entry_dir
;
621 char flow_tbl_entry_name
[10];
623 if (id
>= MVPP2_CLS_FLOWS_TBL_SIZE
)
626 sprintf(flow_tbl_entry_name
, "%03d", id
);
628 flow_tbl_entry_dir
= debugfs_create_dir(flow_tbl_entry_name
, parent
);
629 if (!flow_tbl_entry_dir
)
632 entry
= &priv
->dbgfs_entries
->flt_entries
[id
];
637 debugfs_create_file("hits", 0444, flow_tbl_entry_dir
, entry
,
638 &mvpp2_dbgfs_flow_flt_hits_fops
);
643 static int mvpp2_dbgfs_cls_init(struct dentry
*parent
, struct mvpp2
*priv
)
645 struct dentry
*cls_dir
, *c2_dir
, *flow_tbl_dir
;
648 cls_dir
= debugfs_create_dir("classifier", parent
);
652 c2_dir
= debugfs_create_dir("c2", cls_dir
);
656 for (i
= 0; i
< MVPP22_CLS_C2_N_ENTRIES
; i
++) {
657 ret
= mvpp2_dbgfs_c2_entry_init(c2_dir
, priv
, i
);
662 flow_tbl_dir
= debugfs_create_dir("flow_table", cls_dir
);
666 for (i
= 0; i
< MVPP2_CLS_FLOWS_TBL_SIZE
; i
++) {
667 ret
= mvpp2_dbgfs_flow_tbl_entry_init(flow_tbl_dir
, priv
, i
);
675 static int mvpp2_dbgfs_port_init(struct dentry
*parent
,
676 struct mvpp2_port
*port
)
678 struct dentry
*port_dir
;
680 port_dir
= debugfs_create_dir(port
->dev
->name
, parent
);
682 debugfs_create_file("parser_entries", 0444, port_dir
, port
,
683 &mvpp2_dbgfs_port_parser_fops
);
685 debugfs_create_file("mac_filter", 0444, port_dir
, port
,
686 &mvpp2_dbgfs_filter_fops
);
688 debugfs_create_file("vid_filter", 0444, port_dir
, port
,
689 &mvpp2_dbgfs_port_vid_fops
);
694 void mvpp2_dbgfs_cleanup(struct mvpp2
*priv
)
696 debugfs_remove_recursive(priv
->dbgfs_dir
);
698 kfree(priv
->dbgfs_entries
);
701 void mvpp2_dbgfs_init(struct mvpp2
*priv
, const char *name
)
703 struct dentry
*mvpp2_dir
, *mvpp2_root
;
706 mvpp2_root
= debugfs_lookup(MVPP2_DRIVER_NAME
, NULL
);
708 mvpp2_root
= debugfs_create_dir(MVPP2_DRIVER_NAME
, NULL
);
710 mvpp2_dir
= debugfs_create_dir(name
, mvpp2_root
);
712 priv
->dbgfs_dir
= mvpp2_dir
;
713 priv
->dbgfs_entries
= kzalloc(sizeof(*priv
->dbgfs_entries
), GFP_KERNEL
);
714 if (!priv
->dbgfs_entries
)
717 ret
= mvpp2_dbgfs_prs_init(mvpp2_dir
, priv
);
721 ret
= mvpp2_dbgfs_cls_init(mvpp2_dir
, priv
);
725 for (i
= 0; i
< priv
->port_count
; i
++) {
726 ret
= mvpp2_dbgfs_port_init(mvpp2_dir
, priv
->port_list
[i
]);
731 ret
= mvpp2_dbgfs_flow_init(mvpp2_dir
, priv
);
737 mvpp2_dbgfs_cleanup(priv
);