Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Driver for Marvell PPv2 network controller for Armada 375 SoC.
0004  *
0005  * Copyright (C) 2018 Marvell
0006  */
0007 
0008 #include <linux/kernel.h>
0009 #include <linux/slab.h>
0010 #include <linux/debugfs.h>
0011 
0012 #include "mvpp2.h"
0013 #include "mvpp2_prs.h"
0014 #include "mvpp2_cls.h"
0015 
0016 struct mvpp2_dbgfs_prs_entry {
0017     int tid;
0018     struct mvpp2 *priv;
0019 };
0020 
0021 struct mvpp2_dbgfs_c2_entry {
0022     int id;
0023     struct mvpp2 *priv;
0024 };
0025 
0026 struct mvpp2_dbgfs_flow_entry {
0027     int flow;
0028     struct mvpp2 *priv;
0029 };
0030 
0031 struct mvpp2_dbgfs_flow_tbl_entry {
0032     int id;
0033     struct mvpp2 *priv;
0034 };
0035 
0036 struct mvpp2_dbgfs_port_flow_entry {
0037     struct mvpp2_port *port;
0038     struct mvpp2_dbgfs_flow_entry *dbg_fe;
0039 };
0040 
0041 struct mvpp2_dbgfs_entries {
0042     /* Entries for Header Parser debug info */
0043     struct mvpp2_dbgfs_prs_entry prs_entries[MVPP2_PRS_TCAM_SRAM_SIZE];
0044 
0045     /* Entries for Classifier C2 engine debug info */
0046     struct mvpp2_dbgfs_c2_entry c2_entries[MVPP22_CLS_C2_N_ENTRIES];
0047 
0048     /* Entries for Classifier Flow Table debug info */
0049     struct mvpp2_dbgfs_flow_tbl_entry flt_entries[MVPP2_CLS_FLOWS_TBL_SIZE];
0050 
0051     /* Entries for Classifier flows debug info */
0052     struct mvpp2_dbgfs_flow_entry flow_entries[MVPP2_N_PRS_FLOWS];
0053 
0054     /* Entries for per-port flows debug info */
0055     struct mvpp2_dbgfs_port_flow_entry port_flow_entries[MVPP2_MAX_PORTS];
0056 };
0057 
0058 static int mvpp2_dbgfs_flow_flt_hits_show(struct seq_file *s, void *unused)
0059 {
0060     struct mvpp2_dbgfs_flow_tbl_entry *entry = s->private;
0061 
0062     u32 hits = mvpp2_cls_flow_hits(entry->priv, entry->id);
0063 
0064     seq_printf(s, "%u\n", hits);
0065 
0066     return 0;
0067 }
0068 
0069 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_flt_hits);
0070 
0071 static int mvpp2_dbgfs_flow_dec_hits_show(struct seq_file *s, void *unused)
0072 {
0073     struct mvpp2_dbgfs_flow_entry *entry = s->private;
0074 
0075     u32 hits = mvpp2_cls_lookup_hits(entry->priv, entry->flow);
0076 
0077     seq_printf(s, "%u\n", hits);
0078 
0079     return 0;
0080 }
0081 
0082 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_dec_hits);
0083 
0084 static int mvpp2_dbgfs_flow_type_show(struct seq_file *s, void *unused)
0085 {
0086     struct mvpp2_dbgfs_flow_entry *entry = s->private;
0087     const struct mvpp2_cls_flow *f;
0088     const char *flow_name;
0089 
0090     f = mvpp2_cls_flow_get(entry->flow);
0091     if (!f)
0092         return -EINVAL;
0093 
0094     switch (f->flow_type) {
0095     case IPV4_FLOW:
0096         flow_name = "ipv4";
0097         break;
0098     case IPV6_FLOW:
0099         flow_name = "ipv6";
0100         break;
0101     case TCP_V4_FLOW:
0102         flow_name = "tcp4";
0103         break;
0104     case TCP_V6_FLOW:
0105         flow_name = "tcp6";
0106         break;
0107     case UDP_V4_FLOW:
0108         flow_name = "udp4";
0109         break;
0110     case UDP_V6_FLOW:
0111         flow_name = "udp6";
0112         break;
0113     default:
0114         flow_name = "other";
0115     }
0116 
0117     seq_printf(s, "%s\n", flow_name);
0118 
0119     return 0;
0120 }
0121 
0122 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_type);
0123 
0124 static int mvpp2_dbgfs_flow_id_show(struct seq_file *s, void *unused)
0125 {
0126     const struct mvpp2_dbgfs_flow_entry *entry = s->private;
0127     const struct mvpp2_cls_flow *f;
0128 
0129     f = mvpp2_cls_flow_get(entry->flow);
0130     if (!f)
0131         return -EINVAL;
0132 
0133     seq_printf(s, "%d\n", f->flow_id);
0134 
0135     return 0;
0136 }
0137 
0138 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_id);
0139 
0140 static int mvpp2_dbgfs_port_flow_hash_opt_show(struct seq_file *s, void *unused)
0141 {
0142     struct mvpp2_dbgfs_port_flow_entry *entry = s->private;
0143     struct mvpp2_port *port = entry->port;
0144     struct mvpp2_cls_flow_entry fe;
0145     const struct mvpp2_cls_flow *f;
0146     int flow_index;
0147     u16 hash_opts;
0148 
0149     f = mvpp2_cls_flow_get(entry->dbg_fe->flow);
0150     if (!f)
0151         return -EINVAL;
0152 
0153     flow_index = MVPP2_CLS_FLT_HASH_ENTRY(entry->port->id, f->flow_id);
0154 
0155     mvpp2_cls_flow_read(port->priv, flow_index, &fe);
0156 
0157     hash_opts = mvpp2_flow_get_hek_fields(&fe);
0158 
0159     seq_printf(s, "0x%04x\n", hash_opts);
0160 
0161     return 0;
0162 }
0163 
0164 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_flow_hash_opt);
0165 
0166 static int mvpp2_dbgfs_port_flow_engine_show(struct seq_file *s, void *unused)
0167 {
0168     struct mvpp2_dbgfs_port_flow_entry *entry = s->private;
0169     struct mvpp2_port *port = entry->port;
0170     struct mvpp2_cls_flow_entry fe;
0171     const struct mvpp2_cls_flow *f;
0172     int flow_index, engine;
0173 
0174     f = mvpp2_cls_flow_get(entry->dbg_fe->flow);
0175     if (!f)
0176         return -EINVAL;
0177 
0178     flow_index = MVPP2_CLS_FLT_HASH_ENTRY(entry->port->id, f->flow_id);
0179 
0180     mvpp2_cls_flow_read(port->priv, flow_index, &fe);
0181 
0182     engine = mvpp2_cls_flow_eng_get(&fe);
0183 
0184     seq_printf(s, "%d\n", engine);
0185 
0186     return 0;
0187 }
0188 
0189 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_flow_engine);
0190 
0191 static int mvpp2_dbgfs_flow_c2_hits_show(struct seq_file *s, void *unused)
0192 {
0193     struct mvpp2_dbgfs_c2_entry *entry = s->private;
0194     u32 hits;
0195 
0196     hits = mvpp2_cls_c2_hit_count(entry->priv, entry->id);
0197 
0198     seq_printf(s, "%u\n", hits);
0199 
0200     return 0;
0201 }
0202 
0203 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_c2_hits);
0204 
0205 static int mvpp2_dbgfs_flow_c2_rxq_show(struct seq_file *s, void *unused)
0206 {
0207     struct mvpp2_dbgfs_c2_entry *entry = s->private;
0208     struct mvpp2_cls_c2_entry c2;
0209     u8 qh, ql;
0210 
0211     mvpp2_cls_c2_read(entry->priv, entry->id, &c2);
0212 
0213     qh = (c2.attr[0] >> MVPP22_CLS_C2_ATTR0_QHIGH_OFFS) &
0214          MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
0215 
0216     ql = (c2.attr[0] >> MVPP22_CLS_C2_ATTR0_QLOW_OFFS) &
0217          MVPP22_CLS_C2_ATTR0_QLOW_MASK;
0218 
0219     seq_printf(s, "%d\n", (qh << 3 | ql));
0220 
0221     return 0;
0222 }
0223 
0224 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_c2_rxq);
0225 
0226 static int mvpp2_dbgfs_flow_c2_enable_show(struct seq_file *s, void *unused)
0227 {
0228     struct mvpp2_dbgfs_c2_entry *entry = s->private;
0229     struct mvpp2_cls_c2_entry c2;
0230     int enabled;
0231 
0232     mvpp2_cls_c2_read(entry->priv, entry->id, &c2);
0233 
0234     enabled = !!(c2.attr[2] & MVPP22_CLS_C2_ATTR2_RSS_EN);
0235 
0236     seq_printf(s, "%d\n", enabled);
0237 
0238     return 0;
0239 }
0240 
0241 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_c2_enable);
0242 
0243 static int mvpp2_dbgfs_port_vid_show(struct seq_file *s, void *unused)
0244 {
0245     struct mvpp2_port *port = s->private;
0246     unsigned char byte[2], enable[2];
0247     struct mvpp2 *priv = port->priv;
0248     struct mvpp2_prs_entry pe;
0249     unsigned long pmap;
0250     u16 rvid;
0251     int tid;
0252 
0253     for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id);
0254          tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) {
0255         mvpp2_prs_init_from_hw(priv, &pe, tid);
0256 
0257         pmap = mvpp2_prs_tcam_port_map_get(&pe);
0258 
0259         if (!priv->prs_shadow[tid].valid)
0260             continue;
0261 
0262         if (!test_bit(port->id, &pmap))
0263             continue;
0264 
0265         mvpp2_prs_tcam_data_byte_get(&pe, 2, &byte[0], &enable[0]);
0266         mvpp2_prs_tcam_data_byte_get(&pe, 3, &byte[1], &enable[1]);
0267 
0268         rvid = ((byte[0] & 0xf) << 8) + byte[1];
0269 
0270         seq_printf(s, "%u\n", rvid);
0271     }
0272 
0273     return 0;
0274 }
0275 
0276 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_vid);
0277 
0278 static int mvpp2_dbgfs_port_parser_show(struct seq_file *s, void *unused)
0279 {
0280     struct mvpp2_port *port = s->private;
0281     struct mvpp2 *priv = port->priv;
0282     struct mvpp2_prs_entry pe;
0283     unsigned long pmap;
0284     int i;
0285 
0286     for (i = 0; i < MVPP2_PRS_TCAM_SRAM_SIZE; i++) {
0287         mvpp2_prs_init_from_hw(port->priv, &pe, i);
0288 
0289         pmap = mvpp2_prs_tcam_port_map_get(&pe);
0290         if (priv->prs_shadow[i].valid && test_bit(port->id, &pmap))
0291             seq_printf(s, "%03d\n", i);
0292     }
0293 
0294     return 0;
0295 }
0296 
0297 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_parser);
0298 
0299 static int mvpp2_dbgfs_filter_show(struct seq_file *s, void *unused)
0300 {
0301     struct mvpp2_port *port = s->private;
0302     struct mvpp2 *priv = port->priv;
0303     struct mvpp2_prs_entry pe;
0304     unsigned long pmap;
0305     int index, tid;
0306 
0307     for (tid = MVPP2_PE_MAC_RANGE_START;
0308          tid <= MVPP2_PE_MAC_RANGE_END; tid++) {
0309         unsigned char da[ETH_ALEN], da_mask[ETH_ALEN];
0310 
0311         if (!priv->prs_shadow[tid].valid ||
0312             priv->prs_shadow[tid].lu != MVPP2_PRS_LU_MAC ||
0313             priv->prs_shadow[tid].udf != MVPP2_PRS_UDF_MAC_DEF)
0314             continue;
0315 
0316         mvpp2_prs_init_from_hw(priv, &pe, tid);
0317 
0318         pmap = mvpp2_prs_tcam_port_map_get(&pe);
0319 
0320         /* We only want entries active on this port */
0321         if (!test_bit(port->id, &pmap))
0322             continue;
0323 
0324         /* Read mac addr from entry */
0325         for (index = 0; index < ETH_ALEN; index++)
0326             mvpp2_prs_tcam_data_byte_get(&pe, index, &da[index],
0327                              &da_mask[index]);
0328 
0329         seq_printf(s, "%pM\n", da);
0330     }
0331 
0332     return 0;
0333 }
0334 
0335 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_filter);
0336 
0337 static int mvpp2_dbgfs_prs_lu_show(struct seq_file *s, void *unused)
0338 {
0339     struct mvpp2_dbgfs_prs_entry *entry = s->private;
0340     struct mvpp2 *priv = entry->priv;
0341 
0342     seq_printf(s, "%x\n", priv->prs_shadow[entry->tid].lu);
0343 
0344     return 0;
0345 }
0346 
0347 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_lu);
0348 
0349 static int mvpp2_dbgfs_prs_pmap_show(struct seq_file *s, void *unused)
0350 {
0351     struct mvpp2_dbgfs_prs_entry *entry = s->private;
0352     struct mvpp2_prs_entry pe;
0353     unsigned int pmap;
0354 
0355     mvpp2_prs_init_from_hw(entry->priv, &pe, entry->tid);
0356 
0357     pmap = mvpp2_prs_tcam_port_map_get(&pe);
0358     pmap &= MVPP2_PRS_PORT_MASK;
0359 
0360     seq_printf(s, "%02x\n", pmap);
0361 
0362     return 0;
0363 }
0364 
0365 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_pmap);
0366 
0367 static int mvpp2_dbgfs_prs_ai_show(struct seq_file *s, void *unused)
0368 {
0369     struct mvpp2_dbgfs_prs_entry *entry = s->private;
0370     struct mvpp2_prs_entry pe;
0371     unsigned char ai, ai_mask;
0372 
0373     mvpp2_prs_init_from_hw(entry->priv, &pe, entry->tid);
0374 
0375     ai = pe.tcam[MVPP2_PRS_TCAM_AI_WORD] & MVPP2_PRS_AI_MASK;
0376     ai_mask = (pe.tcam[MVPP2_PRS_TCAM_AI_WORD] >> 16) & MVPP2_PRS_AI_MASK;
0377 
0378     seq_printf(s, "%02x %02x\n", ai, ai_mask);
0379 
0380     return 0;
0381 }
0382 
0383 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_ai);
0384 
0385 static int mvpp2_dbgfs_prs_hdata_show(struct seq_file *s, void *unused)
0386 {
0387     struct mvpp2_dbgfs_prs_entry *entry = s->private;
0388     struct mvpp2_prs_entry pe;
0389     unsigned char data[8], mask[8];
0390     int i;
0391 
0392     mvpp2_prs_init_from_hw(entry->priv, &pe, entry->tid);
0393 
0394     for (i = 0; i < 8; i++)
0395         mvpp2_prs_tcam_data_byte_get(&pe, i, &data[i], &mask[i]);
0396 
0397     seq_printf(s, "%*phN %*phN\n", 8, data, 8, mask);
0398 
0399     return 0;
0400 }
0401 
0402 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_hdata);
0403 
0404 static int mvpp2_dbgfs_prs_sram_show(struct seq_file *s, void *unused)
0405 {
0406     struct mvpp2_dbgfs_prs_entry *entry = s->private;
0407     struct mvpp2_prs_entry pe;
0408 
0409     mvpp2_prs_init_from_hw(entry->priv, &pe, entry->tid);
0410 
0411     seq_printf(s, "%*phN\n", 14, pe.sram);
0412 
0413     return 0;
0414 }
0415 
0416 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_sram);
0417 
0418 static int mvpp2_dbgfs_prs_hits_show(struct seq_file *s, void *unused)
0419 {
0420     struct mvpp2_dbgfs_prs_entry *entry = s->private;
0421     int val;
0422 
0423     val = mvpp2_prs_hits(entry->priv, entry->tid);
0424     if (val < 0)
0425         return val;
0426 
0427     seq_printf(s, "%d\n", val);
0428 
0429     return 0;
0430 }
0431 
0432 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_hits);
0433 
0434 static int mvpp2_dbgfs_prs_valid_show(struct seq_file *s, void *unused)
0435 {
0436     struct mvpp2_dbgfs_prs_entry *entry = s->private;
0437     struct mvpp2 *priv = entry->priv;
0438     int tid = entry->tid;
0439 
0440     seq_printf(s, "%d\n", priv->prs_shadow[tid].valid ? 1 : 0);
0441 
0442     return 0;
0443 }
0444 
0445 DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_valid);
0446 
0447 static int mvpp2_dbgfs_flow_port_init(struct dentry *parent,
0448                       struct mvpp2_port *port,
0449                       struct mvpp2_dbgfs_flow_entry *entry)
0450 {
0451     struct mvpp2_dbgfs_port_flow_entry *port_entry;
0452     struct dentry *port_dir;
0453 
0454     port_dir = debugfs_create_dir(port->dev->name, parent);
0455 
0456     port_entry = &port->priv->dbgfs_entries->port_flow_entries[port->id];
0457 
0458     port_entry->port = port;
0459     port_entry->dbg_fe = entry;
0460 
0461     debugfs_create_file("hash_opts", 0444, port_dir, port_entry,
0462                 &mvpp2_dbgfs_port_flow_hash_opt_fops);
0463 
0464     debugfs_create_file("engine", 0444, port_dir, port_entry,
0465                 &mvpp2_dbgfs_port_flow_engine_fops);
0466 
0467     return 0;
0468 }
0469 
0470 static int mvpp2_dbgfs_flow_entry_init(struct dentry *parent,
0471                        struct mvpp2 *priv, int flow)
0472 {
0473     struct mvpp2_dbgfs_flow_entry *entry;
0474     struct dentry *flow_entry_dir;
0475     char flow_entry_name[10];
0476     int i, ret;
0477 
0478     sprintf(flow_entry_name, "%02d", flow);
0479 
0480     flow_entry_dir = debugfs_create_dir(flow_entry_name, parent);
0481 
0482     entry = &priv->dbgfs_entries->flow_entries[flow];
0483 
0484     entry->flow = flow;
0485     entry->priv = priv;
0486 
0487     debugfs_create_file("dec_hits", 0444, flow_entry_dir, entry,
0488                 &mvpp2_dbgfs_flow_dec_hits_fops);
0489 
0490     debugfs_create_file("type", 0444, flow_entry_dir, entry,
0491                 &mvpp2_dbgfs_flow_type_fops);
0492 
0493     debugfs_create_file("id", 0444, flow_entry_dir, entry,
0494                 &mvpp2_dbgfs_flow_id_fops);
0495 
0496     /* Create entry for each port */
0497     for (i = 0; i < priv->port_count; i++) {
0498         ret = mvpp2_dbgfs_flow_port_init(flow_entry_dir,
0499                          priv->port_list[i], entry);
0500         if (ret)
0501             return ret;
0502     }
0503 
0504     return 0;
0505 }
0506 
0507 static int mvpp2_dbgfs_flow_init(struct dentry *parent, struct mvpp2 *priv)
0508 {
0509     struct dentry *flow_dir;
0510     int i, ret;
0511 
0512     flow_dir = debugfs_create_dir("flows", parent);
0513 
0514     for (i = 0; i < MVPP2_N_PRS_FLOWS; i++) {
0515         ret = mvpp2_dbgfs_flow_entry_init(flow_dir, priv, i);
0516         if (ret)
0517             return ret;
0518     }
0519 
0520     return 0;
0521 }
0522 
0523 static int mvpp2_dbgfs_prs_entry_init(struct dentry *parent,
0524                       struct mvpp2 *priv, int tid)
0525 {
0526     struct mvpp2_dbgfs_prs_entry *entry;
0527     struct dentry *prs_entry_dir;
0528     char prs_entry_name[10];
0529 
0530     if (tid >= MVPP2_PRS_TCAM_SRAM_SIZE)
0531         return -EINVAL;
0532 
0533     sprintf(prs_entry_name, "%03d", tid);
0534 
0535     prs_entry_dir = debugfs_create_dir(prs_entry_name, parent);
0536 
0537     entry = &priv->dbgfs_entries->prs_entries[tid];
0538 
0539     entry->tid = tid;
0540     entry->priv = priv;
0541 
0542     /* Create each attr */
0543     debugfs_create_file("sram", 0444, prs_entry_dir, entry,
0544                 &mvpp2_dbgfs_prs_sram_fops);
0545 
0546     debugfs_create_file("valid", 0644, prs_entry_dir, entry,
0547                 &mvpp2_dbgfs_prs_valid_fops);
0548 
0549     debugfs_create_file("lookup_id", 0644, prs_entry_dir, entry,
0550                 &mvpp2_dbgfs_prs_lu_fops);
0551 
0552     debugfs_create_file("ai", 0644, prs_entry_dir, entry,
0553                 &mvpp2_dbgfs_prs_ai_fops);
0554 
0555     debugfs_create_file("header_data", 0644, prs_entry_dir, entry,
0556                 &mvpp2_dbgfs_prs_hdata_fops);
0557 
0558     debugfs_create_file("hits", 0444, prs_entry_dir, entry,
0559                 &mvpp2_dbgfs_prs_hits_fops);
0560 
0561     debugfs_create_file("pmap", 0444, prs_entry_dir, entry,
0562                  &mvpp2_dbgfs_prs_pmap_fops);
0563 
0564     return 0;
0565 }
0566 
0567 static int mvpp2_dbgfs_prs_init(struct dentry *parent, struct mvpp2 *priv)
0568 {
0569     struct dentry *prs_dir;
0570     int i, ret;
0571 
0572     prs_dir = debugfs_create_dir("parser", parent);
0573 
0574     for (i = 0; i < MVPP2_PRS_TCAM_SRAM_SIZE; i++) {
0575         ret = mvpp2_dbgfs_prs_entry_init(prs_dir, priv, i);
0576         if (ret)
0577             return ret;
0578     }
0579 
0580     return 0;
0581 }
0582 
0583 static int mvpp2_dbgfs_c2_entry_init(struct dentry *parent,
0584                      struct mvpp2 *priv, int id)
0585 {
0586     struct mvpp2_dbgfs_c2_entry *entry;
0587     struct dentry *c2_entry_dir;
0588     char c2_entry_name[10];
0589 
0590     if (id >= MVPP22_CLS_C2_N_ENTRIES)
0591         return -EINVAL;
0592 
0593     sprintf(c2_entry_name, "%03d", id);
0594 
0595     c2_entry_dir = debugfs_create_dir(c2_entry_name, parent);
0596     if (!c2_entry_dir)
0597         return -ENOMEM;
0598 
0599     entry = &priv->dbgfs_entries->c2_entries[id];
0600 
0601     entry->id = id;
0602     entry->priv = priv;
0603 
0604     debugfs_create_file("hits", 0444, c2_entry_dir, entry,
0605                 &mvpp2_dbgfs_flow_c2_hits_fops);
0606 
0607     debugfs_create_file("default_rxq", 0444, c2_entry_dir, entry,
0608                 &mvpp2_dbgfs_flow_c2_rxq_fops);
0609 
0610     debugfs_create_file("rss_enable", 0444, c2_entry_dir, entry,
0611                 &mvpp2_dbgfs_flow_c2_enable_fops);
0612 
0613     return 0;
0614 }
0615 
0616 static int mvpp2_dbgfs_flow_tbl_entry_init(struct dentry *parent,
0617                        struct mvpp2 *priv, int id)
0618 {
0619     struct mvpp2_dbgfs_flow_tbl_entry *entry;
0620     struct dentry *flow_tbl_entry_dir;
0621     char flow_tbl_entry_name[10];
0622 
0623     if (id >= MVPP2_CLS_FLOWS_TBL_SIZE)
0624         return -EINVAL;
0625 
0626     sprintf(flow_tbl_entry_name, "%03d", id);
0627 
0628     flow_tbl_entry_dir = debugfs_create_dir(flow_tbl_entry_name, parent);
0629     if (!flow_tbl_entry_dir)
0630         return -ENOMEM;
0631 
0632     entry = &priv->dbgfs_entries->flt_entries[id];
0633 
0634     entry->id = id;
0635     entry->priv = priv;
0636 
0637     debugfs_create_file("hits", 0444, flow_tbl_entry_dir, entry,
0638                 &mvpp2_dbgfs_flow_flt_hits_fops);
0639 
0640     return 0;
0641 }
0642 
0643 static int mvpp2_dbgfs_cls_init(struct dentry *parent, struct mvpp2 *priv)
0644 {
0645     struct dentry *cls_dir, *c2_dir, *flow_tbl_dir;
0646     int i, ret;
0647 
0648     cls_dir = debugfs_create_dir("classifier", parent);
0649     if (!cls_dir)
0650         return -ENOMEM;
0651 
0652     c2_dir = debugfs_create_dir("c2", cls_dir);
0653     if (!c2_dir)
0654         return -ENOMEM;
0655 
0656     for (i = 0; i < MVPP22_CLS_C2_N_ENTRIES; i++) {
0657         ret = mvpp2_dbgfs_c2_entry_init(c2_dir, priv, i);
0658         if (ret)
0659             return ret;
0660     }
0661 
0662     flow_tbl_dir = debugfs_create_dir("flow_table", cls_dir);
0663     if (!flow_tbl_dir)
0664         return -ENOMEM;
0665 
0666     for (i = 0; i < MVPP2_CLS_FLOWS_TBL_SIZE; i++) {
0667         ret = mvpp2_dbgfs_flow_tbl_entry_init(flow_tbl_dir, priv, i);
0668         if (ret)
0669             return ret;
0670     }
0671 
0672     return 0;
0673 }
0674 
0675 static int mvpp2_dbgfs_port_init(struct dentry *parent,
0676                  struct mvpp2_port *port)
0677 {
0678     struct dentry *port_dir;
0679 
0680     port_dir = debugfs_create_dir(port->dev->name, parent);
0681 
0682     debugfs_create_file("parser_entries", 0444, port_dir, port,
0683                 &mvpp2_dbgfs_port_parser_fops);
0684 
0685     debugfs_create_file("mac_filter", 0444, port_dir, port,
0686                 &mvpp2_dbgfs_filter_fops);
0687 
0688     debugfs_create_file("vid_filter", 0444, port_dir, port,
0689                 &mvpp2_dbgfs_port_vid_fops);
0690 
0691     return 0;
0692 }
0693 
0694 void mvpp2_dbgfs_cleanup(struct mvpp2 *priv)
0695 {
0696     debugfs_remove_recursive(priv->dbgfs_dir);
0697 
0698     kfree(priv->dbgfs_entries);
0699 }
0700 
0701 void mvpp2_dbgfs_init(struct mvpp2 *priv, const char *name)
0702 {
0703     struct dentry *mvpp2_dir, *mvpp2_root;
0704     int ret, i;
0705 
0706     mvpp2_root = debugfs_lookup(MVPP2_DRIVER_NAME, NULL);
0707     if (!mvpp2_root)
0708         mvpp2_root = debugfs_create_dir(MVPP2_DRIVER_NAME, NULL);
0709 
0710     mvpp2_dir = debugfs_create_dir(name, mvpp2_root);
0711 
0712     priv->dbgfs_dir = mvpp2_dir;
0713     priv->dbgfs_entries = kzalloc(sizeof(*priv->dbgfs_entries), GFP_KERNEL);
0714     if (!priv->dbgfs_entries)
0715         goto err;
0716 
0717     ret = mvpp2_dbgfs_prs_init(mvpp2_dir, priv);
0718     if (ret)
0719         goto err;
0720 
0721     ret = mvpp2_dbgfs_cls_init(mvpp2_dir, priv);
0722     if (ret)
0723         goto err;
0724 
0725     for (i = 0; i < priv->port_count; i++) {
0726         ret = mvpp2_dbgfs_port_init(mvpp2_dir, priv->port_list[i]);
0727         if (ret)
0728             goto err;
0729     }
0730 
0731     ret = mvpp2_dbgfs_flow_init(mvpp2_dir, priv);
0732     if (ret)
0733         goto err;
0734 
0735     return;
0736 err:
0737     mvpp2_dbgfs_cleanup(priv);
0738 }