mvpp2_debugfs.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703
  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. #include <linux/kernel.h>
  8. #include <linux/slab.h>
  9. #include <linux/debugfs.h>
  10. #include "mvpp2.h"
  11. #include "mvpp2_prs.h"
  12. #include "mvpp2_cls.h"
  13. struct mvpp2_dbgfs_prs_entry {
  14. int tid;
  15. struct mvpp2 *priv;
  16. };
  17. struct mvpp2_dbgfs_flow_entry {
  18. int flow;
  19. struct mvpp2 *priv;
  20. };
  21. struct mvpp2_dbgfs_port_flow_entry {
  22. struct mvpp2_port *port;
  23. struct mvpp2_dbgfs_flow_entry *dbg_fe;
  24. };
  25. static int mvpp2_dbgfs_flow_flt_hits_show(struct seq_file *s, void *unused)
  26. {
  27. struct mvpp2_dbgfs_flow_entry *entry = s->private;
  28. int id = MVPP2_FLOW_C2_ENTRY(entry->flow);
  29. u32 hits = mvpp2_cls_flow_hits(entry->priv, id);
  30. seq_printf(s, "%u\n", hits);
  31. return 0;
  32. }
  33. DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_flt_hits);
  34. static int mvpp2_dbgfs_flow_dec_hits_show(struct seq_file *s, void *unused)
  35. {
  36. struct mvpp2_dbgfs_flow_entry *entry = s->private;
  37. u32 hits = mvpp2_cls_lookup_hits(entry->priv, entry->flow);
  38. seq_printf(s, "%u\n", hits);
  39. return 0;
  40. }
  41. DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_dec_hits);
  42. static int mvpp2_dbgfs_flow_type_show(struct seq_file *s, void *unused)
  43. {
  44. struct mvpp2_dbgfs_flow_entry *entry = s->private;
  45. struct mvpp2_cls_flow *f;
  46. const char *flow_name;
  47. f = mvpp2_cls_flow_get(entry->flow);
  48. if (!f)
  49. return -EINVAL;
  50. switch (f->flow_type) {
  51. case IPV4_FLOW:
  52. flow_name = "ipv4";
  53. break;
  54. case IPV6_FLOW:
  55. flow_name = "ipv6";
  56. break;
  57. case TCP_V4_FLOW:
  58. flow_name = "tcp4";
  59. break;
  60. case TCP_V6_FLOW:
  61. flow_name = "tcp6";
  62. break;
  63. case UDP_V4_FLOW:
  64. flow_name = "udp4";
  65. break;
  66. case UDP_V6_FLOW:
  67. flow_name = "udp6";
  68. break;
  69. default:
  70. flow_name = "other";
  71. }
  72. seq_printf(s, "%s\n", flow_name);
  73. return 0;
  74. }
  75. static int mvpp2_dbgfs_flow_type_open(struct inode *inode, struct file *file)
  76. {
  77. return single_open(file, mvpp2_dbgfs_flow_type_show, inode->i_private);
  78. }
  79. static int mvpp2_dbgfs_flow_type_release(struct inode *inode, struct file *file)
  80. {
  81. struct seq_file *seq = file->private_data;
  82. struct mvpp2_dbgfs_flow_entry *flow_entry = seq->private;
  83. kfree(flow_entry);
  84. return single_release(inode, file);
  85. }
  86. static const struct file_operations mvpp2_dbgfs_flow_type_fops = {
  87. .open = mvpp2_dbgfs_flow_type_open,
  88. .read = seq_read,
  89. .release = mvpp2_dbgfs_flow_type_release,
  90. };
  91. static int mvpp2_dbgfs_flow_id_show(struct seq_file *s, void *unused)
  92. {
  93. struct mvpp2_dbgfs_flow_entry *entry = s->private;
  94. struct mvpp2_cls_flow *f;
  95. f = mvpp2_cls_flow_get(entry->flow);
  96. if (!f)
  97. return -EINVAL;
  98. seq_printf(s, "%d\n", f->flow_id);
  99. return 0;
  100. }
  101. DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_id);
  102. static int mvpp2_dbgfs_port_flow_hash_opt_show(struct seq_file *s, void *unused)
  103. {
  104. struct mvpp2_dbgfs_port_flow_entry *entry = s->private;
  105. struct mvpp2_port *port = entry->port;
  106. struct mvpp2_cls_flow_entry fe;
  107. struct mvpp2_cls_flow *f;
  108. int flow_index;
  109. u16 hash_opts;
  110. f = mvpp2_cls_flow_get(entry->dbg_fe->flow);
  111. if (!f)
  112. return -EINVAL;
  113. flow_index = MVPP2_PORT_FLOW_HASH_ENTRY(entry->port->id, f->flow_id);
  114. mvpp2_cls_flow_read(port->priv, flow_index, &fe);
  115. hash_opts = mvpp2_flow_get_hek_fields(&fe);
  116. seq_printf(s, "0x%04x\n", hash_opts);
  117. return 0;
  118. }
  119. static int mvpp2_dbgfs_port_flow_hash_opt_open(struct inode *inode,
  120. struct file *file)
  121. {
  122. return single_open(file, mvpp2_dbgfs_port_flow_hash_opt_show,
  123. inode->i_private);
  124. }
  125. static int mvpp2_dbgfs_port_flow_hash_opt_release(struct inode *inode,
  126. struct file *file)
  127. {
  128. struct seq_file *seq = file->private_data;
  129. struct mvpp2_dbgfs_port_flow_entry *flow_entry = seq->private;
  130. kfree(flow_entry);
  131. return single_release(inode, file);
  132. }
  133. static const struct file_operations mvpp2_dbgfs_port_flow_hash_opt_fops = {
  134. .open = mvpp2_dbgfs_port_flow_hash_opt_open,
  135. .read = seq_read,
  136. .release = mvpp2_dbgfs_port_flow_hash_opt_release,
  137. };
  138. static int mvpp2_dbgfs_port_flow_engine_show(struct seq_file *s, void *unused)
  139. {
  140. struct mvpp2_dbgfs_port_flow_entry *entry = s->private;
  141. struct mvpp2_port *port = entry->port;
  142. struct mvpp2_cls_flow_entry fe;
  143. struct mvpp2_cls_flow *f;
  144. int flow_index, engine;
  145. f = mvpp2_cls_flow_get(entry->dbg_fe->flow);
  146. if (!f)
  147. return -EINVAL;
  148. flow_index = MVPP2_PORT_FLOW_HASH_ENTRY(entry->port->id, f->flow_id);
  149. mvpp2_cls_flow_read(port->priv, flow_index, &fe);
  150. engine = mvpp2_cls_flow_eng_get(&fe);
  151. seq_printf(s, "%d\n", engine);
  152. return 0;
  153. }
  154. DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_flow_engine);
  155. static int mvpp2_dbgfs_flow_c2_hits_show(struct seq_file *s, void *unused)
  156. {
  157. struct mvpp2_port *port = s->private;
  158. u32 hits;
  159. hits = mvpp2_cls_c2_hit_count(port->priv,
  160. MVPP22_CLS_C2_RSS_ENTRY(port->id));
  161. seq_printf(s, "%u\n", hits);
  162. return 0;
  163. }
  164. DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_c2_hits);
  165. static int mvpp2_dbgfs_flow_c2_rxq_show(struct seq_file *s, void *unused)
  166. {
  167. struct mvpp2_port *port = s->private;
  168. struct mvpp2_cls_c2_entry c2;
  169. u8 qh, ql;
  170. mvpp2_cls_c2_read(port->priv, MVPP22_CLS_C2_RSS_ENTRY(port->id), &c2);
  171. qh = (c2.attr[0] >> MVPP22_CLS_C2_ATTR0_QHIGH_OFFS) &
  172. MVPP22_CLS_C2_ATTR0_QHIGH_MASK;
  173. ql = (c2.attr[0] >> MVPP22_CLS_C2_ATTR0_QLOW_OFFS) &
  174. MVPP22_CLS_C2_ATTR0_QLOW_MASK;
  175. seq_printf(s, "%d\n", (qh << 3 | ql));
  176. return 0;
  177. }
  178. DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_c2_rxq);
  179. static int mvpp2_dbgfs_flow_c2_enable_show(struct seq_file *s, void *unused)
  180. {
  181. struct mvpp2_port *port = s->private;
  182. struct mvpp2_cls_c2_entry c2;
  183. int enabled;
  184. mvpp2_cls_c2_read(port->priv, MVPP22_CLS_C2_RSS_ENTRY(port->id), &c2);
  185. enabled = !!(c2.attr[2] & MVPP22_CLS_C2_ATTR2_RSS_EN);
  186. seq_printf(s, "%d\n", enabled);
  187. return 0;
  188. }
  189. DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_flow_c2_enable);
  190. static int mvpp2_dbgfs_port_vid_show(struct seq_file *s, void *unused)
  191. {
  192. struct mvpp2_port *port = s->private;
  193. unsigned char byte[2], enable[2];
  194. struct mvpp2 *priv = port->priv;
  195. struct mvpp2_prs_entry pe;
  196. unsigned long pmap;
  197. u16 rvid;
  198. int tid;
  199. for (tid = MVPP2_PRS_VID_PORT_FIRST(port->id);
  200. tid <= MVPP2_PRS_VID_PORT_LAST(port->id); tid++) {
  201. mvpp2_prs_init_from_hw(priv, &pe, tid);
  202. pmap = mvpp2_prs_tcam_port_map_get(&pe);
  203. if (!priv->prs_shadow[tid].valid)
  204. continue;
  205. if (!test_bit(port->id, &pmap))
  206. continue;
  207. mvpp2_prs_tcam_data_byte_get(&pe, 2, &byte[0], &enable[0]);
  208. mvpp2_prs_tcam_data_byte_get(&pe, 3, &byte[1], &enable[1]);
  209. rvid = ((byte[0] & 0xf) << 8) + byte[1];
  210. seq_printf(s, "%u\n", rvid);
  211. }
  212. return 0;
  213. }
  214. DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_vid);
  215. static int mvpp2_dbgfs_port_parser_show(struct seq_file *s, void *unused)
  216. {
  217. struct mvpp2_port *port = s->private;
  218. struct mvpp2 *priv = port->priv;
  219. struct mvpp2_prs_entry pe;
  220. unsigned long pmap;
  221. int i;
  222. for (i = 0; i < MVPP2_PRS_TCAM_SRAM_SIZE; i++) {
  223. mvpp2_prs_init_from_hw(port->priv, &pe, i);
  224. pmap = mvpp2_prs_tcam_port_map_get(&pe);
  225. if (priv->prs_shadow[i].valid && test_bit(port->id, &pmap))
  226. seq_printf(s, "%03d\n", i);
  227. }
  228. return 0;
  229. }
  230. DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_port_parser);
  231. static int mvpp2_dbgfs_filter_show(struct seq_file *s, void *unused)
  232. {
  233. struct mvpp2_port *port = s->private;
  234. struct mvpp2 *priv = port->priv;
  235. struct mvpp2_prs_entry pe;
  236. unsigned long pmap;
  237. int index, tid;
  238. for (tid = MVPP2_PE_MAC_RANGE_START;
  239. tid <= MVPP2_PE_MAC_RANGE_END; tid++) {
  240. unsigned char da[ETH_ALEN], da_mask[ETH_ALEN];
  241. if (!priv->prs_shadow[tid].valid ||
  242. priv->prs_shadow[tid].lu != MVPP2_PRS_LU_MAC ||
  243. priv->prs_shadow[tid].udf != MVPP2_PRS_UDF_MAC_DEF)
  244. continue;
  245. mvpp2_prs_init_from_hw(priv, &pe, tid);
  246. pmap = mvpp2_prs_tcam_port_map_get(&pe);
  247. /* We only want entries active on this port */
  248. if (!test_bit(port->id, &pmap))
  249. continue;
  250. /* Read mac addr from entry */
  251. for (index = 0; index < ETH_ALEN; index++)
  252. mvpp2_prs_tcam_data_byte_get(&pe, index, &da[index],
  253. &da_mask[index]);
  254. seq_printf(s, "%pM\n", da);
  255. }
  256. return 0;
  257. }
  258. DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_filter);
  259. static int mvpp2_dbgfs_prs_lu_show(struct seq_file *s, void *unused)
  260. {
  261. struct mvpp2_dbgfs_prs_entry *entry = s->private;
  262. struct mvpp2 *priv = entry->priv;
  263. seq_printf(s, "%x\n", priv->prs_shadow[entry->tid].lu);
  264. return 0;
  265. }
  266. DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_lu);
  267. static int mvpp2_dbgfs_prs_pmap_show(struct seq_file *s, void *unused)
  268. {
  269. struct mvpp2_dbgfs_prs_entry *entry = s->private;
  270. struct mvpp2_prs_entry pe;
  271. unsigned int pmap;
  272. mvpp2_prs_init_from_hw(entry->priv, &pe, entry->tid);
  273. pmap = mvpp2_prs_tcam_port_map_get(&pe);
  274. pmap &= MVPP2_PRS_PORT_MASK;
  275. seq_printf(s, "%02x\n", pmap);
  276. return 0;
  277. }
  278. DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_pmap);
  279. static int mvpp2_dbgfs_prs_ai_show(struct seq_file *s, void *unused)
  280. {
  281. struct mvpp2_dbgfs_prs_entry *entry = s->private;
  282. struct mvpp2_prs_entry pe;
  283. unsigned char ai, ai_mask;
  284. mvpp2_prs_init_from_hw(entry->priv, &pe, entry->tid);
  285. ai = pe.tcam[MVPP2_PRS_TCAM_AI_WORD] & MVPP2_PRS_AI_MASK;
  286. ai_mask = (pe.tcam[MVPP2_PRS_TCAM_AI_WORD] >> 16) & MVPP2_PRS_AI_MASK;
  287. seq_printf(s, "%02x %02x\n", ai, ai_mask);
  288. return 0;
  289. }
  290. DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_ai);
  291. static int mvpp2_dbgfs_prs_hdata_show(struct seq_file *s, void *unused)
  292. {
  293. struct mvpp2_dbgfs_prs_entry *entry = s->private;
  294. struct mvpp2_prs_entry pe;
  295. unsigned char data[8], mask[8];
  296. int i;
  297. mvpp2_prs_init_from_hw(entry->priv, &pe, entry->tid);
  298. for (i = 0; i < 8; i++)
  299. mvpp2_prs_tcam_data_byte_get(&pe, i, &data[i], &mask[i]);
  300. seq_printf(s, "%*phN %*phN\n", 8, data, 8, mask);
  301. return 0;
  302. }
  303. DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_hdata);
  304. static int mvpp2_dbgfs_prs_sram_show(struct seq_file *s, void *unused)
  305. {
  306. struct mvpp2_dbgfs_prs_entry *entry = s->private;
  307. struct mvpp2_prs_entry pe;
  308. mvpp2_prs_init_from_hw(entry->priv, &pe, entry->tid);
  309. seq_printf(s, "%*phN\n", 14, pe.sram);
  310. return 0;
  311. }
  312. DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_sram);
  313. static int mvpp2_dbgfs_prs_hits_show(struct seq_file *s, void *unused)
  314. {
  315. struct mvpp2_dbgfs_prs_entry *entry = s->private;
  316. int val;
  317. val = mvpp2_prs_hits(entry->priv, entry->tid);
  318. if (val < 0)
  319. return val;
  320. seq_printf(s, "%d\n", val);
  321. return 0;
  322. }
  323. DEFINE_SHOW_ATTRIBUTE(mvpp2_dbgfs_prs_hits);
  324. static int mvpp2_dbgfs_prs_valid_show(struct seq_file *s, void *unused)
  325. {
  326. struct mvpp2_dbgfs_prs_entry *entry = s->private;
  327. struct mvpp2 *priv = entry->priv;
  328. int tid = entry->tid;
  329. seq_printf(s, "%d\n", priv->prs_shadow[tid].valid ? 1 : 0);
  330. return 0;
  331. }
  332. static int mvpp2_dbgfs_prs_valid_open(struct inode *inode, struct file *file)
  333. {
  334. return single_open(file, mvpp2_dbgfs_prs_valid_show, inode->i_private);
  335. }
  336. static int mvpp2_dbgfs_prs_valid_release(struct inode *inode, struct file *file)
  337. {
  338. struct seq_file *seq = file->private_data;
  339. struct mvpp2_dbgfs_prs_entry *entry = seq->private;
  340. kfree(entry);
  341. return single_release(inode, file);
  342. }
  343. static const struct file_operations mvpp2_dbgfs_prs_valid_fops = {
  344. .open = mvpp2_dbgfs_prs_valid_open,
  345. .read = seq_read,
  346. .release = mvpp2_dbgfs_prs_valid_release,
  347. };
  348. static int mvpp2_dbgfs_flow_port_init(struct dentry *parent,
  349. struct mvpp2_port *port,
  350. struct mvpp2_dbgfs_flow_entry *entry)
  351. {
  352. struct mvpp2_dbgfs_port_flow_entry *port_entry;
  353. struct dentry *port_dir;
  354. port_dir = debugfs_create_dir(port->dev->name, parent);
  355. if (IS_ERR(port_dir))
  356. return PTR_ERR(port_dir);
  357. /* This will be freed by 'hash_opts' release op */
  358. port_entry = kmalloc(sizeof(*port_entry), GFP_KERNEL);
  359. if (!port_entry)
  360. return -ENOMEM;
  361. port_entry->port = port;
  362. port_entry->dbg_fe = entry;
  363. debugfs_create_file("hash_opts", 0444, port_dir, port_entry,
  364. &mvpp2_dbgfs_port_flow_hash_opt_fops);
  365. debugfs_create_file("engine", 0444, port_dir, port_entry,
  366. &mvpp2_dbgfs_port_flow_engine_fops);
  367. return 0;
  368. }
  369. static int mvpp2_dbgfs_flow_entry_init(struct dentry *parent,
  370. struct mvpp2 *priv, int flow)
  371. {
  372. struct mvpp2_dbgfs_flow_entry *entry;
  373. struct dentry *flow_entry_dir;
  374. char flow_entry_name[10];
  375. int i, ret;
  376. sprintf(flow_entry_name, "%02d", flow);
  377. flow_entry_dir = debugfs_create_dir(flow_entry_name, parent);
  378. if (!flow_entry_dir)
  379. return -ENOMEM;
  380. /* This will be freed by 'type' release op */
  381. entry = kmalloc(sizeof(*entry), GFP_KERNEL);
  382. if (!entry)
  383. return -ENOMEM;
  384. entry->flow = flow;
  385. entry->priv = priv;
  386. debugfs_create_file("flow_hits", 0444, flow_entry_dir, entry,
  387. &mvpp2_dbgfs_flow_flt_hits_fops);
  388. debugfs_create_file("dec_hits", 0444, flow_entry_dir, entry,
  389. &mvpp2_dbgfs_flow_dec_hits_fops);
  390. debugfs_create_file("type", 0444, flow_entry_dir, entry,
  391. &mvpp2_dbgfs_flow_type_fops);
  392. debugfs_create_file("id", 0444, flow_entry_dir, entry,
  393. &mvpp2_dbgfs_flow_id_fops);
  394. /* Create entry for each port */
  395. for (i = 0; i < priv->port_count; i++) {
  396. ret = mvpp2_dbgfs_flow_port_init(flow_entry_dir,
  397. priv->port_list[i], entry);
  398. if (ret)
  399. return ret;
  400. }
  401. return 0;
  402. }
  403. static int mvpp2_dbgfs_flow_init(struct dentry *parent, struct mvpp2 *priv)
  404. {
  405. struct dentry *flow_dir;
  406. int i, ret;
  407. flow_dir = debugfs_create_dir("flows", parent);
  408. if (!flow_dir)
  409. return -ENOMEM;
  410. for (i = 0; i < MVPP2_N_FLOWS; i++) {
  411. ret = mvpp2_dbgfs_flow_entry_init(flow_dir, priv, i);
  412. if (ret)
  413. return ret;
  414. }
  415. return 0;
  416. }
  417. static int mvpp2_dbgfs_prs_entry_init(struct dentry *parent,
  418. struct mvpp2 *priv, int tid)
  419. {
  420. struct mvpp2_dbgfs_prs_entry *entry;
  421. struct dentry *prs_entry_dir;
  422. char prs_entry_name[10];
  423. if (tid >= MVPP2_PRS_TCAM_SRAM_SIZE)
  424. return -EINVAL;
  425. sprintf(prs_entry_name, "%03d", tid);
  426. prs_entry_dir = debugfs_create_dir(prs_entry_name, parent);
  427. if (!prs_entry_dir)
  428. return -ENOMEM;
  429. /* The 'valid' entry's ops will free that */
  430. entry = kmalloc(sizeof(*entry), GFP_KERNEL);
  431. if (!entry)
  432. return -ENOMEM;
  433. entry->tid = tid;
  434. entry->priv = priv;
  435. /* Create each attr */
  436. debugfs_create_file("sram", 0444, prs_entry_dir, entry,
  437. &mvpp2_dbgfs_prs_sram_fops);
  438. debugfs_create_file("valid", 0644, prs_entry_dir, entry,
  439. &mvpp2_dbgfs_prs_valid_fops);
  440. debugfs_create_file("lookup_id", 0644, prs_entry_dir, entry,
  441. &mvpp2_dbgfs_prs_lu_fops);
  442. debugfs_create_file("ai", 0644, prs_entry_dir, entry,
  443. &mvpp2_dbgfs_prs_ai_fops);
  444. debugfs_create_file("header_data", 0644, prs_entry_dir, entry,
  445. &mvpp2_dbgfs_prs_hdata_fops);
  446. debugfs_create_file("hits", 0444, prs_entry_dir, entry,
  447. &mvpp2_dbgfs_prs_hits_fops);
  448. return 0;
  449. }
  450. static int mvpp2_dbgfs_prs_init(struct dentry *parent, struct mvpp2 *priv)
  451. {
  452. struct dentry *prs_dir;
  453. int i, ret;
  454. prs_dir = debugfs_create_dir("parser", parent);
  455. if (!prs_dir)
  456. return -ENOMEM;
  457. for (i = 0; i < MVPP2_PRS_TCAM_SRAM_SIZE; i++) {
  458. ret = mvpp2_dbgfs_prs_entry_init(prs_dir, priv, i);
  459. if (ret)
  460. return ret;
  461. }
  462. return 0;
  463. }
  464. static int mvpp2_dbgfs_port_init(struct dentry *parent,
  465. struct mvpp2_port *port)
  466. {
  467. struct dentry *port_dir;
  468. port_dir = debugfs_create_dir(port->dev->name, parent);
  469. if (IS_ERR(port_dir))
  470. return PTR_ERR(port_dir);
  471. debugfs_create_file("parser_entries", 0444, port_dir, port,
  472. &mvpp2_dbgfs_port_parser_fops);
  473. debugfs_create_file("mac_filter", 0444, port_dir, port,
  474. &mvpp2_dbgfs_filter_fops);
  475. debugfs_create_file("vid_filter", 0444, port_dir, port,
  476. &mvpp2_dbgfs_port_vid_fops);
  477. debugfs_create_file("c2_hits", 0444, port_dir, port,
  478. &mvpp2_dbgfs_flow_c2_hits_fops);
  479. debugfs_create_file("default_rxq", 0444, port_dir, port,
  480. &mvpp2_dbgfs_flow_c2_rxq_fops);
  481. debugfs_create_file("rss_enable", 0444, port_dir, port,
  482. &mvpp2_dbgfs_flow_c2_enable_fops);
  483. return 0;
  484. }
  485. void mvpp2_dbgfs_cleanup(struct mvpp2 *priv)
  486. {
  487. debugfs_remove_recursive(priv->dbgfs_dir);
  488. }
  489. void mvpp2_dbgfs_init(struct mvpp2 *priv, const char *name)
  490. {
  491. struct dentry *mvpp2_dir, *mvpp2_root;
  492. int ret, i;
  493. mvpp2_root = debugfs_lookup(MVPP2_DRIVER_NAME, NULL);
  494. if (!mvpp2_root) {
  495. mvpp2_root = debugfs_create_dir(MVPP2_DRIVER_NAME, NULL);
  496. if (IS_ERR(mvpp2_root))
  497. return;
  498. }
  499. mvpp2_dir = debugfs_create_dir(name, mvpp2_root);
  500. if (IS_ERR(mvpp2_dir))
  501. return;
  502. priv->dbgfs_dir = mvpp2_dir;
  503. ret = mvpp2_dbgfs_prs_init(mvpp2_dir, priv);
  504. if (ret)
  505. goto err;
  506. for (i = 0; i < priv->port_count; i++) {
  507. ret = mvpp2_dbgfs_port_init(mvpp2_dir, priv->port_list[i]);
  508. if (ret)
  509. goto err;
  510. }
  511. ret = mvpp2_dbgfs_flow_init(mvpp2_dir, priv);
  512. if (ret)
  513. goto err;
  514. return;
  515. err:
  516. mvpp2_dbgfs_cleanup(priv);
  517. }