1// SPDX-License-Identifier: GPL-2.0-only
2/* Copyright (C) 2020 Felix Fietkau <nbd@nbd.name> */
3
4#include <linux/kernel.h>
5#include <linux/debugfs.h>
6#include "mtk_eth_soc.h"
7
8struct mtk_flow_addr_info
9{
10 void *src, *dest;
11 u16 *src_port, *dest_port;
12 bool ipv6;
13};
14
15static const char *mtk_foe_entry_state_str(int state)
16{
17 static const char * const state_str[] = {
18 [MTK_FOE_STATE_INVALID] = "INV",
19 [MTK_FOE_STATE_UNBIND] = "UNB",
20 [MTK_FOE_STATE_BIND] = "BND",
21 [MTK_FOE_STATE_FIN] = "FIN",
22 };
23
24 if (state >= ARRAY_SIZE(state_str) || !state_str[state])
25 return "UNK";
26
27 return state_str[state];
28}
29
30static const char *mtk_foe_pkt_type_str(int type)
31{
32 static const char * const type_str[] = {
33 [MTK_PPE_PKT_TYPE_IPV4_HNAPT] = "IPv4 5T",
34 [MTK_PPE_PKT_TYPE_IPV4_ROUTE] = "IPv4 3T",
35 [MTK_PPE_PKT_TYPE_IPV4_DSLITE] = "DS-LITE",
36 [MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T] = "IPv6 3T",
37 [MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T] = "IPv6 5T",
38 [MTK_PPE_PKT_TYPE_IPV6_6RD] = "6RD",
39 };
40
41 if (type >= ARRAY_SIZE(type_str) || !type_str[type])
42 return "UNKNOWN";
43
44 return type_str[type];
45}
46
47static void
48mtk_print_addr(struct seq_file *m, u32 *addr, bool ipv6)
49{
50 __be32 n_addr[4];
51 int i;
52
53 if (!ipv6) {
54 seq_printf(m, fmt: "%pI4h", addr);
55 return;
56 }
57
58 for (i = 0; i < ARRAY_SIZE(n_addr); i++)
59 n_addr[i] = htonl(addr[i]);
60 seq_printf(m, fmt: "%pI6", n_addr);
61}
62
63static void
64mtk_print_addr_info(struct seq_file *m, struct mtk_flow_addr_info *ai)
65{
66 mtk_print_addr(m, addr: ai->src, ipv6: ai->ipv6);
67 if (ai->src_port)
68 seq_printf(m, fmt: ":%d", *ai->src_port);
69 seq_printf(m, fmt: "->");
70 mtk_print_addr(m, addr: ai->dest, ipv6: ai->ipv6);
71 if (ai->dest_port)
72 seq_printf(m, fmt: ":%d", *ai->dest_port);
73}
74
75static int
76mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind)
77{
78 struct mtk_ppe *ppe = m->private;
79 int i;
80
81 for (i = 0; i < MTK_PPE_ENTRIES; i++) {
82 struct mtk_foe_entry *entry = mtk_foe_get_entry(ppe, hash: i);
83 struct mtk_foe_mac_info *l2;
84 struct mtk_flow_addr_info ai = {};
85 struct mtk_foe_accounting *acct;
86 unsigned char h_source[ETH_ALEN];
87 unsigned char h_dest[ETH_ALEN];
88 int type, state;
89 u32 ib2;
90
91
92 state = FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1);
93 if (!state)
94 continue;
95
96 if (bind && state != MTK_FOE_STATE_BIND)
97 continue;
98
99 acct = mtk_foe_entry_get_mib(ppe, index: i, NULL);
100
101 type = mtk_get_ib1_pkt_type(eth: ppe->eth, val: entry->ib1);
102 seq_printf(m, fmt: "%05x %s %7s", i,
103 mtk_foe_entry_state_str(state),
104 mtk_foe_pkt_type_str(type));
105
106 switch (type) {
107 case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
108 case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
109 ai.src_port = &entry->ipv4.orig.src_port;
110 ai.dest_port = &entry->ipv4.orig.dest_port;
111 fallthrough;
112 case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
113 ai.src = &entry->ipv4.orig.src_ip;
114 ai.dest = &entry->ipv4.orig.dest_ip;
115 break;
116 case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T:
117 ai.src_port = &entry->ipv6.src_port;
118 ai.dest_port = &entry->ipv6.dest_port;
119 fallthrough;
120 case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T:
121 case MTK_PPE_PKT_TYPE_IPV6_6RD:
122 ai.src = &entry->ipv6.src_ip;
123 ai.dest = &entry->ipv6.dest_ip;
124 ai.ipv6 = true;
125 break;
126 }
127
128 seq_printf(m, fmt: " orig=");
129 mtk_print_addr_info(m, ai: &ai);
130
131 switch (type) {
132 case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
133 case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
134 ai.src_port = &entry->ipv4.new.src_port;
135 ai.dest_port = &entry->ipv4.new.dest_port;
136 fallthrough;
137 case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
138 ai.src = &entry->ipv4.new.src_ip;
139 ai.dest = &entry->ipv4.new.dest_ip;
140 seq_printf(m, fmt: " new=");
141 mtk_print_addr_info(m, ai: &ai);
142 break;
143 }
144
145 if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) {
146 l2 = &entry->ipv6.l2;
147 ib2 = entry->ipv6.ib2;
148 } else {
149 l2 = &entry->ipv4.l2;
150 ib2 = entry->ipv4.ib2;
151 }
152
153 *((__be32 *)h_source) = htonl(l2->src_mac_hi);
154 *((__be16 *)&h_source[4]) = htons(l2->src_mac_lo);
155 *((__be32 *)h_dest) = htonl(l2->dest_mac_hi);
156 *((__be16 *)&h_dest[4]) = htons(l2->dest_mac_lo);
157
158 seq_printf(m, fmt: " eth=%pM->%pM etype=%04x"
159 " vlan=%d,%d ib1=%08x ib2=%08x"
160 " packets=%llu bytes=%llu\n",
161 h_source, h_dest, ntohs(l2->etype),
162 l2->vlan1, l2->vlan2, entry->ib1, ib2,
163 acct ? acct->packets : 0, acct ? acct->bytes : 0);
164 }
165
166 return 0;
167}
168
169static int
170mtk_ppe_debugfs_foe_all_show(struct seq_file *m, void *private)
171{
172 return mtk_ppe_debugfs_foe_show(m, private, bind: false);
173}
174DEFINE_SHOW_ATTRIBUTE(mtk_ppe_debugfs_foe_all);
175
176static int
177mtk_ppe_debugfs_foe_bind_show(struct seq_file *m, void *private)
178{
179 return mtk_ppe_debugfs_foe_show(m, private, bind: true);
180}
181DEFINE_SHOW_ATTRIBUTE(mtk_ppe_debugfs_foe_bind);
182
183int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index)
184{
185 struct dentry *root;
186
187 snprintf(buf: ppe->dirname, size: sizeof(ppe->dirname), fmt: "ppe%d", index);
188
189 root = debugfs_create_dir(name: ppe->dirname, NULL);
190 debugfs_create_file(name: "entries", S_IRUGO, parent: root, data: ppe, fops: &mtk_ppe_debugfs_foe_all_fops);
191 debugfs_create_file(name: "bind", S_IRUGO, parent: root, data: ppe, fops: &mtk_ppe_debugfs_foe_bind_fops);
192
193 return 0;
194}
195

source code of linux/drivers/net/ethernet/mediatek/mtk_ppe_debugfs.c