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_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 
47 static void
48 mtk_print_addr(struct seq_file *m, u32 *addr, bool ipv6)
49 {
50 	u32 n_addr[4];
51 	int i;
52 
53 	if (!ipv6) {
54 		seq_printf(m, "%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, "%pI6", n_addr);
61 }
62 
63 static void
64 mtk_print_addr_info(struct seq_file *m, struct mtk_flow_addr_info *ai)
65 {
66 	mtk_print_addr(m, ai->src, ai->ipv6);
67 	if (ai->src_port)
68 		seq_printf(m, ":%d", *ai->src_port);
69 	seq_printf(m, "->");
70 	mtk_print_addr(m, ai->dest, ai->ipv6);
71 	if (ai->dest_port)
72 		seq_printf(m, ":%d", *ai->dest_port);
73 }
74 
75 static int
76 mtk_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 = &ppe->foe_table[i];
83 		struct mtk_foe_mac_info *l2;
84 		struct mtk_flow_addr_info ai = {};
85 		unsigned char h_source[ETH_ALEN];
86 		unsigned char h_dest[ETH_ALEN];
87 		int type, state;
88 		u32 ib2;
89 
90 
91 		state = FIELD_GET(MTK_FOE_IB1_STATE, entry->ib1);
92 		if (!state)
93 			continue;
94 
95 		if (bind && state != MTK_FOE_STATE_BIND)
96 			continue;
97 
98 		type = FIELD_GET(MTK_FOE_IB1_PACKET_TYPE, entry->ib1);
99 		seq_printf(m, "%05x %s %7s", i,
100 			   mtk_foe_entry_state_str(state),
101 			   mtk_foe_pkt_type_str(type));
102 
103 		switch (type) {
104 		case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
105 		case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
106 			ai.src_port = &entry->ipv4.orig.src_port;
107 			ai.dest_port = &entry->ipv4.orig.dest_port;
108 			fallthrough;
109 		case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
110 			ai.src = &entry->ipv4.orig.src_ip;
111 			ai.dest = &entry->ipv4.orig.dest_ip;
112 			break;
113 		case MTK_PPE_PKT_TYPE_IPV6_ROUTE_5T:
114 			ai.src_port = &entry->ipv6.src_port;
115 			ai.dest_port = &entry->ipv6.dest_port;
116 			fallthrough;
117 		case MTK_PPE_PKT_TYPE_IPV6_ROUTE_3T:
118 		case MTK_PPE_PKT_TYPE_IPV6_6RD:
119 			ai.src = &entry->ipv6.src_ip;
120 			ai.dest = &entry->ipv6.dest_ip;
121 			ai.ipv6 = true;
122 			break;
123 		}
124 
125 		seq_printf(m, " orig=");
126 		mtk_print_addr_info(m, &ai);
127 
128 		switch (type) {
129 		case MTK_PPE_PKT_TYPE_IPV4_HNAPT:
130 		case MTK_PPE_PKT_TYPE_IPV4_DSLITE:
131 			ai.src_port = &entry->ipv4.new.src_port;
132 			ai.dest_port = &entry->ipv4.new.dest_port;
133 			fallthrough;
134 		case MTK_PPE_PKT_TYPE_IPV4_ROUTE:
135 			ai.src = &entry->ipv4.new.src_ip;
136 			ai.dest = &entry->ipv4.new.dest_ip;
137 			seq_printf(m, " new=");
138 			mtk_print_addr_info(m, &ai);
139 			break;
140 		}
141 
142 		if (type >= MTK_PPE_PKT_TYPE_IPV4_DSLITE) {
143 			l2 = &entry->ipv6.l2;
144 			ib2 = entry->ipv6.ib2;
145 		} else {
146 			l2 = &entry->ipv4.l2;
147 			ib2 = entry->ipv4.ib2;
148 		}
149 
150 		*((__be32 *)h_source) = htonl(l2->src_mac_hi);
151 		*((__be16 *)&h_source[4]) = htons(l2->src_mac_lo);
152 		*((__be32 *)h_dest) = htonl(l2->dest_mac_hi);
153 		*((__be16 *)&h_dest[4]) = htons(l2->dest_mac_lo);
154 
155 		seq_printf(m, " eth=%pM->%pM etype=%04x"
156 			      " vlan=%d,%d ib1=%08x ib2=%08x\n",
157 			   h_source, h_dest, ntohs(l2->etype),
158 			   l2->vlan1, l2->vlan2, entry->ib1, ib2);
159 	}
160 
161 	return 0;
162 }
163 
164 static int
165 mtk_ppe_debugfs_foe_show_all(struct seq_file *m, void *private)
166 {
167 	return mtk_ppe_debugfs_foe_show(m, private, false);
168 }
169 
170 static int
171 mtk_ppe_debugfs_foe_show_bind(struct seq_file *m, void *private)
172 {
173 	return mtk_ppe_debugfs_foe_show(m, private, true);
174 }
175 
176 static int
177 mtk_ppe_debugfs_foe_open_all(struct inode *inode, struct file *file)
178 {
179 	return single_open(file, mtk_ppe_debugfs_foe_show_all,
180 			   inode->i_private);
181 }
182 
183 static int
184 mtk_ppe_debugfs_foe_open_bind(struct inode *inode, struct file *file)
185 {
186 	return single_open(file, mtk_ppe_debugfs_foe_show_bind,
187 			   inode->i_private);
188 }
189 
190 int mtk_ppe_debugfs_init(struct mtk_ppe *ppe)
191 {
192 	static const struct file_operations fops_all = {
193 		.open = mtk_ppe_debugfs_foe_open_all,
194 		.read = seq_read,
195 		.llseek = seq_lseek,
196 		.release = single_release,
197 	};
198 
199 	static const struct file_operations fops_bind = {
200 		.open = mtk_ppe_debugfs_foe_open_bind,
201 		.read = seq_read,
202 		.llseek = seq_lseek,
203 		.release = single_release,
204 	};
205 
206 	struct dentry *root;
207 
208 	root = debugfs_create_dir("mtk_ppe", NULL);
209 	debugfs_create_file("entries", S_IRUGO, root, ppe, &fops_all);
210 	debugfs_create_file("bind", S_IRUGO, root, ppe, &fops_bind);
211 
212 	return 0;
213 }
214