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 	__be32 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 = mtk_foe_get_entry(ppe, 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, i, NULL);
100 
101 		type = mtk_get_ib1_pkt_type(ppe->eth, entry->ib1);
102 		seq_printf(m, "%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, " orig=");
129 		mtk_print_addr_info(m, &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, " new=");
141 			mtk_print_addr_info(m, &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, " 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 
169 static int
170 mtk_ppe_debugfs_foe_all_show(struct seq_file *m, void *private)
171 {
172 	return mtk_ppe_debugfs_foe_show(m, private, false);
173 }
174 DEFINE_SHOW_ATTRIBUTE(mtk_ppe_debugfs_foe_all);
175 
176 static int
177 mtk_ppe_debugfs_foe_bind_show(struct seq_file *m, void *private)
178 {
179 	return mtk_ppe_debugfs_foe_show(m, private, true);
180 }
181 DEFINE_SHOW_ATTRIBUTE(mtk_ppe_debugfs_foe_bind);
182 
183 int mtk_ppe_debugfs_init(struct mtk_ppe *ppe, int index)
184 {
185 	struct dentry *root;
186 
187 	snprintf(ppe->dirname, sizeof(ppe->dirname), "ppe%d", index);
188 
189 	root = debugfs_create_dir(ppe->dirname, NULL);
190 	debugfs_create_file("entries", S_IRUGO, root, ppe, &mtk_ppe_debugfs_foe_all_fops);
191 	debugfs_create_file("bind", S_IRUGO, root, ppe, &mtk_ppe_debugfs_foe_bind_fops);
192 
193 	return 0;
194 }
195