blob: 6e925fd61c4f54946c42a84e76364d7831787c6f [file] [log] [blame]
developer1966afb2023-08-08 16:02:18 +08001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2023 Mediatek Inc. All Rights Reserved.
4 *
5 * Author: Ren-Ting Wang <ren-ting.wang@mediatek.com>
6 */
7
8#include <linux/debugfs.h>
9#include <linux/inet.h>
10#include <linux/uaccess.h>
11
12#include "pce/cls.h"
13#include "pce/debugfs.h"
14#include "pce/dipfilter.h"
15#include "pce/internal.h"
16#include "pce/netsys.h"
17#include "pce/pce.h"
18#include "pce/tport_map.h"
19
20#define CLS_ENTRY_DBG_CFG(_name, _type, func) \
21 { \
22 .name = #_name, \
23 .type = _type, \
24 .func = cls_entry_debug_fill_ ## _name, \
25 }
26
27#define CLS_ENTRY_DBG_CFG_MASK_DATA(_name) \
28 CLS_ENTRY_DBG_CFG(_name, CLS_ENTRY_MASK_DATA, fill_mask_data)
29
30#define CLS_ENTRY_DBG_CFG_DATA(_name) \
31 CLS_ENTRY_DBG_CFG(_name, CLS_ENTRY_DATA, fill_data)
32
33enum cls_entry_config_type {
34 CLS_ENTRY_MASK_DATA,
35 CLS_ENTRY_DATA,
36};
37
38struct cls_entry_debug_config {
39 const char *name;
40 enum cls_entry_config_type type;
41
42 union {
43 int (*fill_mask_data)(struct cls_desc *cdesc, u32 mask, u32 data);
44 int (*fill_data)(struct cls_desc *cdesc, u32 data);
45 };
46};
47
48struct dentry *debug_root;
49
50static void cls_entry_debug_show_l4(struct seq_file *s, void *priv,
51 struct cls_desc *cdesc)
52{
53 bool l4_valid = false;
54 u32 l4_data_m = 0;
55 u32 l4_data = 0;
56
57 seq_printf(s, "\t\tL4 valid mask: 0x%X, data: 0x%X\n",
58 cdesc->l4_valid_m, cdesc->l4_valid);
59
60 if ((cdesc->l4_valid_m & CLS_DESC_VALID_DPORT_BIT)
61 && (cdesc->l4_valid & CLS_DESC_VALID_DPORT_BIT))
62 seq_printf(s, "\t\t\tL4 Dport mask: 0x%04X, data: %05u\n",
63 cdesc->l4_dport_m, cdesc->l4_dport);
64
65 if ((cdesc->l4_valid_m & CLS_DESC_VALID_LOWER_HALF_WORD_BIT)
66 && (cdesc->l4_valid & CLS_DESC_VALID_LOWER_HALF_WORD_BIT)) {
67 l4_valid = true;
68 l4_data_m |= cdesc->l4_hdr_usr_data_m & 0xFFFF;
69 l4_data |= cdesc->l4_hdr_usr_data & 0xFFFF;
70 }
71
72 if ((cdesc->l4_valid_m & CLS_DESC_VALID_UPPER_HALF_WORD_BIT)
73 && (cdesc->l4_valid & CLS_DESC_VALID_UPPER_HALF_WORD_BIT)) {
74 l4_valid = true;
75 l4_data_m |= ((cdesc->l4_hdr_usr_data_m & 0xFFFF0000) >> 16);
76 l4_data |= ((cdesc->l4_hdr_usr_data & 0xFFFF0000) >> 16);
77 }
78
79 if (!l4_valid)
80 return;
81
82 if ((cdesc->tag_m & CLS_DESC_TAG_MATCH_L4_HDR)
83 && (cdesc->tag & CLS_DESC_TAG_MATCH_L4_HDR)) {
84 seq_printf(s, "\t\t\tL4 header not empty mask: 0x%X, data: 0x%X\n",
85 cdesc->l4_udp_hdr_nez_m, cdesc->l4_udp_hdr_nez);
86 seq_printf(s, "\t\t\tL4 header mask: 0x%08X, data: 0x%08X\n",
87 cdesc->l4_hdr_usr_data_m, cdesc->l4_hdr_usr_data);
88 } else {
89 seq_printf(s, "\t\t\tUDP lite valid mask: 0x%X, data: 0x%X\n",
90 cdesc->l4_udp_hdr_nez_m, cdesc->l4_udp_hdr_nez);
91 seq_printf(s, "\t\t\tL4 user data mask: 0x%08X, data: 0x%08X\n",
92 cdesc->l4_hdr_usr_data_m, cdesc->l4_hdr_usr_data);
93 }
94}
95
96static int cls_entry_debug_read(struct seq_file *s, void *private)
97{
98 struct cls_desc cdesc;
99 bool cls_enabled;
100 int ret;
101 u32 i;
102
103 for (i = CLS_ENTRY_NONE + 1; i < FE_MEM_CLS_MAX_INDEX; i++) {
104 ret = mtk_pce_cls_desc_read(&cdesc, i);
105
106 if (ret) {
107 PCE_ERR("read cls desc: %u failed: %d\n", i, ret);
108 return 0;
109 }
110
111 cls_enabled = (cdesc.tag && cdesc.tag_m
112 && cdesc.tag == (cdesc.tag_m & cdesc.tag));
113
114 seq_printf(s, "CLS Entry%02u, Tag mask: 0x%X, data: 0x%X, enabled: %u\n",
115 i, cdesc.tag_m, cdesc.tag, cls_enabled);
116
117 /* cls entry is not enabled */
118 if (!cls_enabled)
119 continue;
120
121 /* CLS descriptor's tag data should only set 1 bit of [1:0] */
122 if (cdesc.tag ==
123 (CLS_DESC_TAG_MATCH_L4_HDR | CLS_DESC_TAG_MATCH_L4_USR)) {
124 seq_puts(s, "Invalid CLS descriptor tag\n");
125 continue;
126 }
127
128 seq_puts(s, "\tAction:\n");
129 seq_printf(s, "\t\tFport: %02u, Tport: %02u, TOPS_ENTRY: %02u, CDRT: %02u, QID: %u, DR_IDX: %u\n",
130 cdesc.fport, cdesc.tport_idx,
131 cdesc.tops_entry, cdesc.cdrt_idx,
132 cdesc.qid, cdesc.dr_idx);
133 seq_puts(s, "\tContent:\n");
134 seq_printf(s, "\t\tDIP match mask: 0x%X, data: 0x%X\n",
135 cdesc.dip_match_m, cdesc.dip_match);
136 seq_printf(s, "\t\tL4 protocol mask: 0x%02X, data: 0x%02X\n",
137 cdesc.l4_type_m, cdesc.l4_type);
138
139 cls_entry_debug_show_l4(s, private, &cdesc);
140
141 seq_printf(s, "\t\tSport map mask: 0x%04X, data: 0x%04X\n",
142 cdesc.sport_m, cdesc.sport);
143 }
144
145 return 0;
146}
147
148static int cls_entry_debug_fill_tag(struct cls_desc *cdesc, u32 mask, u32 data)
149{
150 if (mask > CLS_DESC_TAG_MASK || data > CLS_DESC_TAG_MASK)
151 return -EINVAL;
152
153 cdesc->tag_m = mask;
154 cdesc->tag = data;
155
156 return 0;
157}
158
159static int cls_entry_debug_fill_udplite_l4_hdr_nez(struct cls_desc *cdesc,
160 u32 mask, u32 data)
161{
162 if (mask > CLS_DESC_UDPLITE_L4_HDR_NEZ_MASK
163 || data > CLS_DESC_UDPLITE_L4_HDR_NEZ_MASK)
164 return -EINVAL;
165
166 cdesc->l4_udp_hdr_nez_m = mask;
167 cdesc->l4_udp_hdr_nez = data;
168
169 return 0;
170}
171
172static int cls_entry_debug_fill_dip_match(struct cls_desc *cdesc, u32 mask, u32 data)
173{
174 if (mask > CLS_DESC_DIP_MATCH || data > CLS_DESC_DIP_MATCH)
175 return -EINVAL;
176
177 cdesc->dip_match_m = mask;
178 cdesc->dip_match = data;
179
180 return 0;
181}
182
183static int cls_entry_debug_fill_l4_protocol(struct cls_desc *cdesc,
184 u32 mask, u32 data)
185{
186 if (mask > CLS_DESC_L4_TYPE_MASK || data > CLS_DESC_L4_TYPE_MASK)
187 return -EINVAL;
188
189 cdesc->l4_type_m = mask;
190 cdesc->l4_type = data;
191
192 return 0;
193}
194
195static int cls_entry_debug_fill_l4_valid(struct cls_desc *cdesc, u32 mask, u32 data)
196{
197 if (mask > CLS_DESC_L4_VALID_MASK || data > CLS_DESC_L4_VALID_MASK)
198 return -EINVAL;
199
200 cdesc->l4_valid_m = mask;
201 cdesc->l4_valid = data;
202
203 return 0;
204}
205
206static int cls_entry_debug_fill_l4_dport(struct cls_desc *cdesc, u32 mask, u32 data)
207{
208 if (mask > CLS_DESC_L4_DPORT_MASK || data > CLS_DESC_L4_DPORT_MASK)
209 return -EINVAL;
210
211 cdesc->l4_dport_m = mask;
212 cdesc->l4_dport = data;
213
214 return 0;
215}
216
217static int cls_entry_debug_fill_l4_data(struct cls_desc *cdesc, u32 mask, u32 data)
218{
219 cdesc->l4_hdr_usr_data_m = mask;
220 cdesc->l4_hdr_usr_data = data;
221
222 return 0;
223}
224
225static int cls_entry_debug_fill_fport(struct cls_desc *cdesc, u32 data)
226{
227 if (data > CLS_DESC_FPORT_MASK)
228 return -EINVAL;
229
230 cdesc->fport = data;
231
232 return 0;
233}
234
235static int cls_entry_debug_fill_dr_idx(struct cls_desc *cdesc, u32 data)
236{
237 if (data > CLS_DESC_DR_IDX_MASK)
238 return -EINVAL;
239
240 cdesc->dr_idx = data;
241
242 return 0;
243}
244
245static int cls_entry_debug_fill_qid(struct cls_desc *cdesc, u32 data)
246{
247 if (data > CLS_DESC_QID_MASK)
248 return -EINVAL;
249
250 cdesc->qid = data;
251
252 return 0;
253}
254
255static int cls_entry_debug_fill_cdrt(struct cls_desc *cdesc, u32 data)
256{
257 if (data > CLS_DESC_CDRT_MASK)
258 return -EINVAL;
259
260 cdesc->cdrt_idx = data;
261
262 return 0;
263}
264
265static int cls_entry_debug_fill_tport(struct cls_desc *cdesc, u32 data)
266{
267 if (data > CLS_DESC_TPORT_MASK)
268 return -EINVAL;
269
270 cdesc->tport_idx = data;
271
272 return 0;
273}
274
275static int cls_entry_debug_fill_tops_entry(struct cls_desc *cdesc, u32 data)
276{
277 if (data > CLS_DESC_TOPS_ENTRY_MASK)
278 return -EINVAL;
279
280 cdesc->tops_entry = data;
281
282 return 0;
283}
284
285static int cls_entry_debug_fill_mask_data(
286 const char *buf, u32 *ofs,
287 struct cls_desc *cdesc,
288 int (*fill_func)(struct cls_desc *cdesc, u32 mask, u32 data))
289{
290 u32 nchar = 0;
291 u32 mask = 0;
292 u32 data = 0;
293 int ret;
294
295 if (!fill_func)
296 return -ENODEV;
297
298 ret = sscanf(buf + *ofs, "%x %x %n", &mask, &data, &nchar);
299 if (ret != 2)
300 return -EINVAL;
301
302 *ofs += nchar;
303
304 ret = fill_func(cdesc, mask, data);
305 if (ret)
306 PCE_ERR("invalid mask: 0x%x, data: 0x%x\n", mask, data);
307
308 return ret;
309}
310
311static int cls_entry_debug_fill_data(const char *buf, u32 *ofs,
312 struct cls_desc *cdesc,
313 int (*fill_func)(struct cls_desc *cdesc, u32 data))
314{
315 u32 nchar = 0;
316 u32 data = 0;
317 int ret;
318
319 if (!fill_func)
320 return -ENODEV;
321
322 ret = sscanf(buf + *ofs, "%x %n", &data, &nchar);
323 if (ret != 1)
324 return -EINVAL;
325
326 *ofs += nchar;
327
328 ret = fill_func(cdesc, data);
329 if (ret)
330 PCE_ERR("invalid data: 0x%x\n", data);
331
332 return ret;
333}
334
335struct cls_entry_debug_config cls_entry_dbg_cfgs[] = {
336 CLS_ENTRY_DBG_CFG_MASK_DATA(tag),
337 CLS_ENTRY_DBG_CFG_MASK_DATA(udplite_l4_hdr_nez),
338 CLS_ENTRY_DBG_CFG_MASK_DATA(dip_match),
339 CLS_ENTRY_DBG_CFG_MASK_DATA(l4_protocol),
340 CLS_ENTRY_DBG_CFG_MASK_DATA(l4_valid),
341 CLS_ENTRY_DBG_CFG_MASK_DATA(l4_dport),
342 CLS_ENTRY_DBG_CFG_MASK_DATA(l4_data),
343 CLS_ENTRY_DBG_CFG_DATA(fport),
344 CLS_ENTRY_DBG_CFG_DATA(dr_idx),
345 CLS_ENTRY_DBG_CFG_DATA(qid),
346 CLS_ENTRY_DBG_CFG_DATA(cdrt),
347 CLS_ENTRY_DBG_CFG_DATA(tport),
348 CLS_ENTRY_DBG_CFG_DATA(tops_entry),
349};
350
351static int cls_entry_debug_fill(const char *buf, u32 *ofs, struct cls_desc *cdesc)
352{
353 struct cls_entry_debug_config *cls_entry_dbg_cfg;
354 char arg[32];
355 u32 nchar = 0;
356 u32 i;
357 int ret;
358
359 ret = sscanf(buf + *ofs, "%31s %n", arg, &nchar);
360 if (ret != 1)
361 return -EINVAL;
362
363 *ofs += nchar;
364
365 for (i = 0; i < ARRAY_SIZE(cls_entry_dbg_cfgs); i++) {
366 cls_entry_dbg_cfg = &cls_entry_dbg_cfgs[i];
367 if (strcmp(cls_entry_dbg_cfg->name, arg))
368 continue;
369
370 switch (cls_entry_dbg_cfg->type) {
371 case CLS_ENTRY_MASK_DATA:
372 ret = cls_entry_debug_fill_mask_data(buf, ofs, cdesc,
373 cls_entry_dbg_cfg->fill_mask_data);
374 break;
375
376 case CLS_ENTRY_DATA:
377 ret = cls_entry_debug_fill_data(buf, ofs, cdesc,
378 cls_entry_dbg_cfg->fill_data);
379 break;
380
381 default:
382 return -EINVAL;
383 }
384
385 if (ret)
386 goto err_out;
387
388 return ret;
389 }
390
391err_out:
392 PCE_ERR("invalid argument: %s\n", arg);
393
394 return ret;
395}
396
397static ssize_t cls_entry_debug_write(struct file *file, const char __user *buffer,
398 size_t count, loff_t *data)
399{
400 struct cls_desc cdesc;
401 char buf[512];
402 u32 cls_entry = 0;
403 u32 nchar = 0;
404 u32 ofs = 0;
405 int ret;
406
407 if (count > sizeof(buf))
408 return -ENOMEM;
409
410 if (copy_from_user(buf, buffer, count))
411 return -EFAULT;
412
413 buf[count] = '\0';
414
415 memset(&cdesc, 0, sizeof(struct cls_desc));
416
417 ret = sscanf(buf + ofs, "%u %n\n", &cls_entry, &nchar);
418 if (ret != 1)
419 return -EINVAL;
420
421 ofs += nchar;
422
423 if (cls_entry == CLS_ENTRY_NONE || cls_entry > __CLS_ENTRY_MAX) {
424 PCE_ERR("invalid cls entry: %u\n", cls_entry);
425 return -EINVAL;
426 }
427
428 while (1) {
429 if (ofs >= count)
430 break;
431
432 ret = cls_entry_debug_fill(buf, &ofs, &cdesc);
433 if (ret)
434 return ret;
435 }
436
437 ret = mtk_pce_cls_desc_write(&cdesc, cls_entry);
438 if (ret)
439 return ret;
440
441 return count;
442}
443
444static int cls_entry_debug_open(struct inode *inode, struct file *file)
445{
446 return single_open(file, cls_entry_debug_read, file->private_data);
447}
448
449static int dipfilter_debug_read(struct seq_file *s, void *private)
450{
451 struct dip_desc ddesc;
452 int ret;
453 u32 i;
454
455 for (i = 0; i < FE_MEM_DIPFILTER_MAX_IDX; i++) {
456 ret = mtk_pce_dipfilter_desc_read(&ddesc, i);
457 if (ret) {
458 PCE_ERR("read dipfilter desc: %u failed: %d\n", i, ret);
459 return 0;
460 }
461
462 seq_printf(s, "DIPFILTER Entry%02u, enabled: %u\n",
463 i, ddesc.tag != DIPFILTER_DISABLED);
464
465 if (ddesc.tag == DIPFILTER_DISABLED) {
466 continue;
467 } else if (ddesc.tag == DIPFILTER_IPV4) {
468 u32 addr = cpu_to_be32(ddesc.ipv4);
469
470 seq_printf(s, "IPv4 address: %pI4\n", &addr);
471 } else if (ddesc.tag == DIPFILTER_IPV6) {
472 seq_printf(s, "IPv6 address: %pI6\n", ddesc.ipv6);
473 }
474 }
475
476 return 0;
477}
478
479static int dipfilter_debug_open(struct inode *inode, struct file *file)
480{
481 return single_open(file, dipfilter_debug_read, file->private_data);
482}
483
484static ssize_t dipfilter_debug_write(struct file *file, const char __user *buffer,
485 size_t count, loff_t *data)
486{
487 struct dip_desc ddesc;
488 const char *end;
489 char buf[512];
490 char arg[5];
491 char s_dip[40];
492 int ret;
493
494 if (count > sizeof(buf))
495 return -ENOMEM;
496
497 if (copy_from_user(buf, buffer, count))
498 return -EFAULT;
499
500 buf[count] = '\0';
501
502 memset(&ddesc, 0, sizeof(struct dip_desc));
503
504 ret = sscanf(buf, "%s %s", arg, s_dip);
505 if (ret != 2)
506 return -EINVAL;
507
508 if (!strcmp(arg, "ipv4")) {
509 ddesc.tag = DIPFILTER_IPV4;
510 if (!in4_pton(s_dip, -1, (u8 *)(&ddesc.ipv4), -1, &end) || (*end)) {
511 PCE_ERR("invalid IPv4 address: %s\n", s_dip);
512 return -EINVAL;
513 }
514 } else if (!strcmp(arg, "ipv6")) {
515 ddesc.tag = DIPFILTER_IPV6;
516 if (!in6_pton(s_dip, -1, (u8 *)ddesc.ipv6, -1, &end) || (*end)) {
517 PCE_ERR("invalid Ipv6 address: %s\n", s_dip);
518 return -EINVAL;
519 }
520 } else {
521 return -EINVAL;
522 }
523
524 ret = mtk_pce_dipfilter_entry_add(&ddesc);
525 if (ret) {
526 PCE_ERR("add dipfilter entry failed: %d\n", ret);
527 return ret;
528 }
529
530 return count;
531}
532
533static int tport_map_debug_read(struct seq_file *s, void *private)
534{
535 struct tsc_desc tdesc;
536 int ret;
537 u64 map;
538 u32 i;
539
540 for (i = 0; i < __PSE_PORT_MAX; i++) {
541 if (TS_CONFIG_MASK & BIT(i)) {
542 ret = mtk_pce_tport_map_ts_config_read(i, &tdesc);
543 if (ret)
544 return ret;
545
546 map = tdesc.tport_map_lower;
547 map |= ((u64)tdesc.tport_map_upper) << 32;
548 seq_printf(s, "PSE_PORT%02u ", i);
549 seq_printf(s, "PORT_MAP: 0x%llX, ", map);
550 seq_printf(s, "default TPORT_IDX: %02u, ", tdesc.tport);
551 seq_printf(s, "default CDRT_IDX: %02u, ", tdesc.cdrt_idx);
552 seq_printf(s, "default TOPS_ENTRY: %02u\n", tdesc.tops_entry);
553 } else if (PSE_PORT_PPE_MASK & BIT(i)) {
554 ret = mtk_pce_tport_map_ppe_read(i, &map);
555 if (ret)
556 return ret;
557
558 seq_printf(s, "PSE PORT%02u ", i);
559 seq_printf(s, "PORT_MAP: 0x%llX\n", map);
560 }
561 }
562
563 return 0;
564}
565
566static int tport_map_debug_open(struct inode *inode, struct file *file)
567{
568 return single_open(file, tport_map_debug_read, file->private_data);
569}
570
571static int tport_map_debug_update_all(const char *buf, int *ofs, u32 tport_idx)
572{
573 enum pse_port port = PSE_PORT_ADMA;
574 enum pse_port target;
575 u64 port_map = 0;
576 int nchar = 0;
577 int ret = 0;
578
579 *ofs += nchar;
580
581 ret = sscanf(buf + *ofs, "%llx %n", &port_map, &nchar);
582 if (ret != 1)
583 return -EPERM;
584
585 while (port_map && port < __PSE_PORT_MAX) {
586 target = port_map & PSE_PER_PORT_MASK;
587 port_map >>= PSE_PER_PORT_BITS;
588
589 if (TS_CONFIG_MASK & BIT(port) || PSE_PORT_PPE_MASK & BIT(port)) {
590 ret = mtk_pce_tport_map_pse_port_update(port,
591 tport_idx,
592 target);
593 if (ret) {
594 PCE_ERR("invalid port: %u\n", port);
595 return ret;
596 }
597 }
598
599 port++;
600 }
601
602 return 0;
603}
604
605static int tport_map_debug_update_single(const char *buf, int *ofs,
606 enum pse_port port, u32 tport_idx)
607{
608 u32 target = 0;
609 int nchar = 0;
610 int ret = 0;
611
612 ret = sscanf(buf + *ofs, "%x %n", &target, &nchar);
613 if (ret != 1)
614 return -EPERM;
615
616 return mtk_pce_tport_map_pse_port_update(port, tport_idx, target);
617}
618
619static ssize_t tport_map_debug_write(struct file *file, const char __user *buffer,
620 size_t count, loff_t *data)
621{
622 enum pse_port port = PSE_PORT_ADMA;
623 char arg1[21] = {0};
624 char cmd[21] = {0};
625 char buf[512];
626 u32 tport_idx = 0;
627 int nchar = 0;
628 int ret;
629
630 if (count > sizeof(buf))
631 return -ENOMEM;
632
633 if (copy_from_user(buf, buffer, count))
634 return -EFAULT;
635
636 buf[count] = '\0';
637
638 ret = sscanf(buf, "%20s %20s %u %n", cmd, arg1, &tport_idx, &nchar);
639 if (ret != 3)
640 return -EINVAL;
641
642 if (tport_idx > TPORT_IDX_MAX) {
643 PCE_ERR("invalid tport idx: %u\n", tport_idx);
644 return -EINVAL;
645 }
646
647 if (!strcmp(cmd, "UPDATE")) {
648 if (!strcmp(arg1, "ALL")) {
649 ret = tport_map_debug_update_all(buf, &nchar, tport_idx);
650 if (ret)
651 return ret;
652 } else {
653 ret = kstrtou32(arg1, 10, &port);
654 if (ret) {
655 PCE_ERR("invalid pse port: %u\n", port);
656 return ret;
657 }
658
659 ret = tport_map_debug_update_single(buf, &nchar,
660 port, tport_idx);
661 if (ret) {
662 PCE_ERR("update tport map single failed: %d\n",
663 ret);
664 return ret;
665 }
666 }
667 }
668
669 return count;
670}
671
672static const struct file_operations cls_entry_debug_ops = {
673 .open = cls_entry_debug_open,
674 .read = seq_read,
675 .llseek = seq_lseek,
676 .write = cls_entry_debug_write,
677 .release = single_release,
678};
679
680static const struct file_operations dipfilter_debug_ops = {
681 .open = dipfilter_debug_open,
682 .read = seq_read,
683 .llseek = seq_lseek,
684 .write = dipfilter_debug_write,
685 .release = single_release,
686};
687
688static const struct file_operations tport_map_debug_ops = {
689 .open = tport_map_debug_open,
690 .read = seq_read,
691 .llseek = seq_lseek,
692 .write = tport_map_debug_write,
693 .release = single_release,
694};
695
696int mtk_pce_debugfs_init(struct platform_device *pdev)
697{
698 debug_root = debugfs_create_dir("pce", NULL);
699 if (!debug_root) {
700 PCE_ERR("create debugfs root directory failed\n");
701 return -ENOMEM;
702 }
703
704 debugfs_create_file("cls_entry", 0444, debug_root, NULL,
705 &cls_entry_debug_ops);
706 debugfs_create_file("dipfilter_entry", 0444, debug_root, NULL,
707 &dipfilter_debug_ops);
708 debugfs_create_file("tport_map", 0444, debug_root, NULL,
709 &tport_map_debug_ops);
710
711 return 0;
712}
713
714void mtk_pce_debugfs_deinit(struct platform_device *pdev)
715{
716 debugfs_remove_recursive(debug_root);
717
718 debug_root = NULL;
719}