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, "%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
63static void
64mtk_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
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, 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
169static int
170mtk_ppe_debugfs_foe_all_show(struct seq_file *m, void *private)
171{
172	return mtk_ppe_debugfs_foe_show(m, private, 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, 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(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