1
2
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_BRIDGE] = "L2",
36 [MTK_PPE_PKT_TYPE_IPV4_DSLITE] = "DS-LITE",
37 [MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T] = "IPv6 3T",
38 [MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T] = "IPv6 5T",
39 [MTK_PPE_PKT_TYPE_IPV6_6RD] = "6RD",
40 };
41
42 if (type >= ARRAY_SIZE(type_str) || !type_str[type])
43 return "UNKNOWN";
44
45 return type_str[type];
46}
47
48static void
49mtk_print_addr(struct seq_file *m, u32 *addr, bool ipv6)
50{
51 u32 n_addr[4];
52 int i;
53
54 if (!ipv6) {
55 seq_printf(m, "%pI4h", addr);
56 return;
57 }
58
59 for (i = 0; i < ARRAY_SIZE(n_addr); i++)
60 n_addr[i] = htonl(addr[i]);
61 seq_printf(m, "%pI6", n_addr);
62}
63
64static void
65mtk_print_addr_info(struct seq_file *m, struct mtk_flow_addr_info *ai)
66{
67 mtk_print_addr(m, ai->src, ai->ipv6);
68 if (ai->src_port)
69 seq_printf(m, ":%d", *ai->src_port);
70 seq_printf(m, "->");
71 mtk_print_addr(m, ai->dest, ai->ipv6);
72 if (ai->dest_port)
73 seq_printf(m, ":%d", *ai->dest_port);
74}
75
76static int
77mtk_ppe_debugfs_foe_show(struct seq_file *m, void *private, bool bind)
78{
79 struct mtk_ppe *ppe = m->private;
80 int i;
81
82 for (i = 0; i < MTK_PPE_ENTRIES; i++) {
83 struct mtk_foe_entry *entry = &ppe->foe_table[i];
84 struct mtk_foe_mac_info *l2;
85 struct mtk_flow_addr_info ai = {};
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 type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
100 seq_printf(m, "%05x %s %7s", i,
101 mtk_foe_entry_state_str(state),
102 mtk_foe_pkt_type_str(type));
103
104 switch (type) {
105 case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
106 case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
107 ai.src_port = &entry->ipv4.orig.src_port;
108 ai.dest_port = &entry->ipv4.orig.dest_port;
109 fallthrough;
110 case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
111 ai.src = &entry->ipv4.orig.src_ip;
112 ai.dest = &entry->ipv4.orig.dest_ip;
113 break;
114 case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T:
115 ai.src_port = &entry->ipv6.src_port;
116 ai.dest_port = &entry->ipv6.dest_port;
117 fallthrough;
118 case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T:
119 case MTK_PPE_PKT_TYPE_IPV6_6RD:
120 ai.src = &entry->ipv6.src_ip;
121 ai.dest = &entry->ipv6.dest_ip;
122 ai.ipv6 = true;
123 break;
124 }
125
126 seq_printf(m, " orig=");
127 mtk_print_addr_info(m, &ai);
128
129 switch (type) {
130 case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
131 case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
132 ai.src_port = &entry->ipv4.new.src_port;
133 ai.dest_port = &entry->ipv4.new.dest_port;
134 fallthrough;
135 case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
136 ai.src = &entry->ipv4.new.src_ip;
137 ai.dest = &entry->ipv4.new.dest_ip;
138 seq_printf(m, " new=");
139 mtk_print_addr_info(m, &ai);
140 break;
141 }
142
143 if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) {
144 l2 = &entry->ipv6.l2;
145 ib2 = entry->ipv6.ib2;
146 } else {
147 l2 = &entry->ipv4.l2;
148 ib2 = entry->ipv4.ib2;
149 }
150
151 *((__be32 *)h_source) = htonl(l2->src_mac_hi);
152 *((__be16 *)&h_source[4]) = htons(l2->src_mac_lo);
153 *((__be32 *)h_dest) = htonl(l2->dest_mac_hi);
154 *((__be16 *)&h_dest[4]) = htons(l2->dest_mac_lo);
155
156 seq_printf(m, " eth=%pM->%pM etype=%04x"
157 " vlan=%d,%d ib1=%08x ib2=%08x\n",
158 h_source, h_dest, ntohs(l2->etype),
159 l2->vlan1, l2->vlan2, entry->ib1, ib2);
160 }
161
162 return 0;
163}
164
165static int
166mtk_ppe_debugfs_foe_show_all(struct seq_file *m, void *private)
167{
168 return mtk_ppe_debugfs_foe_show(m, private, false);
169}
170
171static int
172mtk_ppe_debugfs_foe_show_bind(struct seq_file *m, void *private)
173{
174 return mtk_ppe_debugfs_foe_show(m, private, true);
175}
176
177static int
178mtk_ppe_debugfs_foe_open_all(struct inode *inode, struct file *file)
179{
180 return single_open(file, mtk_ppe_debugfs_foe_show_all,
181 inode->i_private);
182}
183
184static int
185mtk_ppe_debugfs_foe_open_bind(struct inode *inode, struct file *file)
186{
187 return single_open(file, mtk_ppe_debugfs_foe_show_bind,
188 inode->i_private);
189}
190
191int mtk_ppe_debugfs_init(struct mtk_ppe *ppe)
192{
193 static const struct file_operations fops_all = {
194 .open = mtk_ppe_debugfs_foe_open_all,
195 .read = seq_read,
196 .llseek = seq_lseek,
197 .release = single_release,
198 };
199
200 static const struct file_operations fops_bind = {
201 .open = mtk_ppe_debugfs_foe_open_bind,
202 .read = seq_read,
203 .llseek = seq_lseek,
204 .release = single_release,
205 };
206
207 struct dentry *root;
208
209 root = debugfs_create_dir("mtk_ppe", NULL);
210 if (!root)
211 return -ENOMEM;
212
213 debugfs_create_file("entries", S_IRUGO, root, ppe, &fops_all);
214 debugfs_create_file("bind", S_IRUGO, root, ppe, &fops_bind);
215
216 return 0;
217}
218