cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

mvpp2_debugfs.c (16960B)


      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
     16struct mvpp2_dbgfs_prs_entry {
     17	int tid;
     18	struct mvpp2 *priv;
     19};
     20
     21struct mvpp2_dbgfs_c2_entry {
     22	int id;
     23	struct mvpp2 *priv;
     24};
     25
     26struct mvpp2_dbgfs_flow_entry {
     27	int flow;
     28	struct mvpp2 *priv;
     29};
     30
     31struct mvpp2_dbgfs_flow_tbl_entry {
     32	int id;
     33	struct mvpp2 *priv;
     34};
     35
     36struct mvpp2_dbgfs_port_flow_entry {
     37	struct mvpp2_port *port;
     38	struct mvpp2_dbgfs_flow_entry *dbg_fe;
     39};
     40
     41struct 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
     58static 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
     69DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_flt_hits);
     70
     71static 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
     82DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_dec_hits);
     83
     84static 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
    122DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_type);
    123
    124static 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
    138DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_id);
    139
    140static 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
    164DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_flow_hash_opt);
    165
    166static 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
    189DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_flow_engine);
    190
    191static 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
    203DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_c2_hits);
    204
    205static 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
    224DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_c2_rxq);
    225
    226static 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
    241DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_c2_enable);
    242
    243static 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
    276DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_vid);
    277
    278static 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
    297DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_parser);
    298
    299static 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
    335DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_filter);
    336
    337static 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
    347DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_lu);
    348
    349static 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
    365DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_pmap);
    366
    367static 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
    383DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_ai);
    384
    385static 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
    402DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_hdata);
    403
    404static 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
    416DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_sram);
    417
    418static 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
    432DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_hits);
    433
    434static 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
    445DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_valid);
    446
    447static 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
    470static 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
    507static 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
    523static 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
    567static 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
    583static 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	if (!c2_entry_dir)
    597		return -ENOMEM;
    598
    599	entry = &priv->dbgfs_entries->c2_entries[id];
    600
    601	entry->id = id;
    602	entry->priv = priv;
    603
    604	debugfs_create_file("hits", 0444, c2_entry_dir, entry,
    605			    &mvpp2_dbgfs_flow_c2_hits_fops);
    606
    607	debugfs_create_file("default_rxq", 0444, c2_entry_dir, entry,
    608			    &mvpp2_dbgfs_flow_c2_rxq_fops);
    609
    610	debugfs_create_file("rss_enable", 0444, c2_entry_dir, entry,
    611			    &mvpp2_dbgfs_flow_c2_enable_fops);
    612
    613	return 0;
    614}
    615
    616static int mvpp2_dbgfs_flow_tbl_entry_init(struct dentry *parent,
    617					   struct mvpp2 *priv, int id)
    618{
    619	struct mvpp2_dbgfs_flow_tbl_entry *entry;
    620	struct dentry *flow_tbl_entry_dir;
    621	char flow_tbl_entry_name[10];
    622
    623	if (id >= MVPP2_CLS_FLOWS_TBL_SIZE)
    624		return -EINVAL;
    625
    626	sprintf(flow_tbl_entry_name, "%03d", id);
    627
    628	flow_tbl_entry_dir = debugfs_create_dir(flow_tbl_entry_name, parent);
    629	if (!flow_tbl_entry_dir)
    630		return -ENOMEM;
    631
    632	entry = &priv->dbgfs_entries->flt_entries[id];
    633
    634	entry->id = id;
    635	entry->priv = priv;
    636
    637	debugfs_create_file("hits", 0444, flow_tbl_entry_dir, entry,
    638			    &mvpp2_dbgfs_flow_flt_hits_fops);
    639
    640	return 0;
    641}
    642
    643static int mvpp2_dbgfs_cls_init(struct dentry *parent, struct mvpp2 *priv)
    644{
    645	struct dentry *cls_dir, *c2_dir, *flow_tbl_dir;
    646	int i, ret;
    647
    648	cls_dir = debugfs_create_dir("classifier", parent);
    649	if (!cls_dir)
    650		return -ENOMEM;
    651
    652	c2_dir = debugfs_create_dir("c2", cls_dir);
    653	if (!c2_dir)
    654		return -ENOMEM;
    655
    656	for (i = 0; i < MVPP22_CLS_C2_N_ENTRIES; i++) {
    657		ret = mvpp2_dbgfs_c2_entry_init(c2_dir, priv, i);
    658		if (ret)
    659			return ret;
    660	}
    661
    662	flow_tbl_dir = debugfs_create_dir("flow_table", cls_dir);
    663	if (!flow_tbl_dir)
    664		return -ENOMEM;
    665
    666	for (i = 0; i < MVPP2_CLS_FLOWS_TBL_SIZE; i++) {
    667		ret = mvpp2_dbgfs_flow_tbl_entry_init(flow_tbl_dir, priv, i);
    668		if (ret)
    669			return ret;
    670	}
    671
    672	return 0;
    673}
    674
    675static int mvpp2_dbgfs_port_init(struct dentry *parent,
    676				 struct mvpp2_port *port)
    677{
    678	struct dentry *port_dir;
    679
    680	port_dir = debugfs_create_dir(port->dev->name, parent);
    681
    682	debugfs_create_file("parser_entries", 0444, port_dir, port,
    683			    &mvpp2_dbgfs_port_parser_fops);
    684
    685	debugfs_create_file("mac_filter", 0444, port_dir, port,
    686			    &mvpp2_dbgfs_filter_fops);
    687
    688	debugfs_create_file("vid_filter", 0444, port_dir, port,
    689			    &mvpp2_dbgfs_port_vid_fops);
    690
    691	return 0;
    692}
    693
    694void mvpp2_dbgfs_cleanup(struct mvpp2 *priv)
    695{
    696	debugfs_remove_recursive(priv->dbgfs_dir);
    697
    698	kfree(priv->dbgfs_entries);
    699}
    700
    701void mvpp2_dbgfs_init(struct mvpp2 *priv, const char *name)
    702{
    703	struct dentry *mvpp2_dir, *mvpp2_root;
    704	int ret, i;
    705
    706	mvpp2_root = debugfs_lookup(MVPP2_DRIVER_NAME, NULL);
    707	if (!mvpp2_root)
    708		mvpp2_root = debugfs_create_dir(MVPP2_DRIVER_NAME, NULL);
    709
    710	mvpp2_dir = debugfs_create_dir(name, mvpp2_root);
    711
    712	priv->dbgfs_dir = mvpp2_dir;
    713	priv->dbgfs_entries = kzalloc(sizeof(*priv->dbgfs_entries), GFP_KERNEL);
    714	if (!priv->dbgfs_entries)
    715		goto err;
    716
    717	ret = mvpp2_dbgfs_prs_init(mvpp2_dir, priv);
    718	if (ret)
    719		goto err;
    720
    721	ret = mvpp2_dbgfs_cls_init(mvpp2_dir, priv);
    722	if (ret)
    723		goto err;
    724
    725	for (i = 0; i < priv->port_count; i++) {
    726		ret = mvpp2_dbgfs_port_init(mvpp2_dir, priv->port_list[i]);
    727		if (ret)
    728			goto err;
    729	}
    730
    731	ret = mvpp2_dbgfs_flow_init(mvpp2_dir, priv);
    732	if (ret)
    733		goto err;
    734
    735	return;
    736err:
    737	mvpp2_dbgfs_cleanup(priv);
    738}