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 
8 struct mtk_flow_addr_info
9 {
10 	void *src, *dest;
11 	u16 *src_port, *dest_port;
12 	bool ipv6;
13 };
14 
15 static 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 
30 static 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 
48 static void
49 mtk_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 
64 static void
65 mtk_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 
76 static int
77 mtk_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 
165 static int
166 mtk_ppe_debugfs_foe_show_all(struct seq_file *m, void *private)
167 {
168 	return mtk_ppe_debugfs_foe_show(m, private, false);
169 }
170 
171 static int
172 mtk_ppe_debugfs_foe_show_bind(struct seq_file *m, void *private)
173 {
174 	return mtk_ppe_debugfs_foe_show(m, private, true);
175 }
176 
177 static int
178 mtk_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 
184 static int
185 mtk_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 
191 int 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