1 // SPDX-License-Identifier: GPL-2.0+
2 /* Microchip Sparx5 Switch driver VCAP debugFS implementation
3  *
4  * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
5  */
6 
7 #include <linux/types.h>
8 #include <linux/list.h>
9 
10 #include "sparx5_vcap_debugfs.h"
11 #include "sparx5_main_regs.h"
12 #include "sparx5_main.h"
13 #include "sparx5_vcap_impl.h"
14 #include "sparx5_vcap_ag_api.h"
15 
16 static const char *sparx5_vcap_is0_etype_str(u32 value)
17 {
18 	switch (value) {
19 	case VCAP_IS0_PS_ETYPE_DEFAULT:
20 		return "default";
21 	case VCAP_IS0_PS_ETYPE_NORMAL_7TUPLE:
22 		return "normal_7tuple";
23 	case VCAP_IS0_PS_ETYPE_NORMAL_5TUPLE_IP4:
24 		return "normal_5tuple_ip4";
25 	case VCAP_IS0_PS_ETYPE_MLL:
26 		return "mll";
27 	case VCAP_IS0_PS_ETYPE_LL_FULL:
28 		return "ll_full";
29 	case VCAP_IS0_PS_ETYPE_PURE_5TUPLE_IP4:
30 		return "pure_5tuple_ip4";
31 	case VCAP_IS0_PS_ETYPE_ETAG:
32 		return "etag";
33 	case VCAP_IS0_PS_ETYPE_NO_LOOKUP:
34 		return "no lookup";
35 	default:
36 		return "unknown";
37 	}
38 }
39 
40 static const char *sparx5_vcap_is0_mpls_str(u32 value)
41 {
42 	switch (value) {
43 	case VCAP_IS0_PS_MPLS_FOLLOW_ETYPE:
44 		return "follow_etype";
45 	case VCAP_IS0_PS_MPLS_NORMAL_7TUPLE:
46 		return "normal_7tuple";
47 	case VCAP_IS0_PS_MPLS_NORMAL_5TUPLE_IP4:
48 		return "normal_5tuple_ip4";
49 	case VCAP_IS0_PS_MPLS_MLL:
50 		return "mll";
51 	case VCAP_IS0_PS_MPLS_LL_FULL:
52 		return "ll_full";
53 	case VCAP_IS0_PS_MPLS_PURE_5TUPLE_IP4:
54 		return "pure_5tuple_ip4";
55 	case VCAP_IS0_PS_MPLS_ETAG:
56 		return "etag";
57 	case VCAP_IS0_PS_MPLS_NO_LOOKUP:
58 		return "no lookup";
59 	default:
60 		return "unknown";
61 	}
62 }
63 
64 static const char *sparx5_vcap_is0_mlbs_str(u32 value)
65 {
66 	switch (value) {
67 	case VCAP_IS0_PS_MLBS_FOLLOW_ETYPE:
68 		return "follow_etype";
69 	case VCAP_IS0_PS_MLBS_NO_LOOKUP:
70 		return "no lookup";
71 	default:
72 		return "unknown";
73 	}
74 }
75 
76 static void sparx5_vcap_is0_port_keys(struct sparx5 *sparx5,
77 				      struct vcap_admin *admin,
78 				      struct sparx5_port *port,
79 				      struct vcap_output_print *out)
80 {
81 	int lookup;
82 	u32 value, val;
83 
84 	out->prf(out->dst, "  port[%02d] (%s): ", port->portno,
85 		 netdev_name(port->ndev));
86 	for (lookup = 0; lookup < admin->lookups; ++lookup) {
87 		out->prf(out->dst, "\n    Lookup %d: ", lookup);
88 
89 		/* Get lookup state */
90 		value = spx5_rd(sparx5,
91 				ANA_CL_ADV_CL_CFG(port->portno, lookup));
92 		out->prf(out->dst, "\n      state: ");
93 		if (ANA_CL_ADV_CL_CFG_LOOKUP_ENA_GET(value))
94 			out->prf(out->dst, "on");
95 		else
96 			out->prf(out->dst, "off");
97 		val = ANA_CL_ADV_CL_CFG_ETYPE_CLM_KEY_SEL_GET(value);
98 		out->prf(out->dst, "\n      etype: %s",
99 			 sparx5_vcap_is0_etype_str(val));
100 		val = ANA_CL_ADV_CL_CFG_IP4_CLM_KEY_SEL_GET(value);
101 		out->prf(out->dst, "\n      ipv4: %s",
102 			 sparx5_vcap_is0_etype_str(val));
103 		val = ANA_CL_ADV_CL_CFG_IP6_CLM_KEY_SEL_GET(value);
104 		out->prf(out->dst, "\n      ipv6: %s",
105 			 sparx5_vcap_is0_etype_str(val));
106 		val = ANA_CL_ADV_CL_CFG_MPLS_UC_CLM_KEY_SEL_GET(value);
107 		out->prf(out->dst, "\n      mpls_uc: %s",
108 			 sparx5_vcap_is0_mpls_str(val));
109 		val = ANA_CL_ADV_CL_CFG_MPLS_MC_CLM_KEY_SEL_GET(value);
110 		out->prf(out->dst, "\n      mpls_mc: %s",
111 			 sparx5_vcap_is0_mpls_str(val));
112 		val = ANA_CL_ADV_CL_CFG_MLBS_CLM_KEY_SEL_GET(value);
113 		out->prf(out->dst, "\n      mlbs: %s",
114 			 sparx5_vcap_is0_mlbs_str(val));
115 	}
116 	out->prf(out->dst, "\n");
117 }
118 
119 static void sparx5_vcap_is2_port_keys(struct sparx5 *sparx5,
120 				      struct vcap_admin *admin,
121 				      struct sparx5_port *port,
122 				      struct vcap_output_print *out)
123 {
124 	int lookup;
125 	u32 value;
126 
127 	out->prf(out->dst, "  port[%02d] (%s): ", port->portno,
128 	   netdev_name(port->ndev));
129 	for (lookup = 0; lookup < admin->lookups; ++lookup) {
130 		out->prf(out->dst, "\n    Lookup %d: ", lookup);
131 
132 		/* Get lookup state */
133 		value = spx5_rd(sparx5, ANA_ACL_VCAP_S2_CFG(port->portno));
134 		out->prf(out->dst, "\n      state: ");
135 		if (ANA_ACL_VCAP_S2_CFG_SEC_ENA_GET(value) & BIT(lookup))
136 			out->prf(out->dst, "on");
137 		else
138 			out->prf(out->dst, "off");
139 
140 		/* Get key selection state */
141 		value = spx5_rd(sparx5,
142 				ANA_ACL_VCAP_S2_KEY_SEL(port->portno, lookup));
143 
144 		out->prf(out->dst, "\n      noneth: ");
145 		switch (ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_GET(value)) {
146 		case VCAP_IS2_PS_NONETH_MAC_ETYPE:
147 			out->prf(out->dst, "mac_etype");
148 			break;
149 		case VCAP_IS2_PS_NONETH_CUSTOM_1:
150 			out->prf(out->dst, "custom1");
151 			break;
152 		case VCAP_IS2_PS_NONETH_CUSTOM_2:
153 			out->prf(out->dst, "custom2");
154 			break;
155 		case VCAP_IS2_PS_NONETH_NO_LOOKUP:
156 			out->prf(out->dst, "none");
157 			break;
158 		}
159 		out->prf(out->dst, "\n      ipv4_mc: ");
160 		switch (ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_GET(value)) {
161 		case VCAP_IS2_PS_IPV4_MC_MAC_ETYPE:
162 			out->prf(out->dst, "mac_etype");
163 			break;
164 		case VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER:
165 			out->prf(out->dst, "ip4_tcp_udp ip4_other");
166 			break;
167 		case VCAP_IS2_PS_IPV4_MC_IP_7TUPLE:
168 			out->prf(out->dst, "ip_7tuple");
169 			break;
170 		case VCAP_IS2_PS_IPV4_MC_IP4_VID:
171 			out->prf(out->dst, "ip4_vid");
172 			break;
173 		}
174 		out->prf(out->dst, "\n      ipv4_uc: ");
175 		switch (ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_GET(value)) {
176 		case VCAP_IS2_PS_IPV4_UC_MAC_ETYPE:
177 			out->prf(out->dst, "mac_etype");
178 			break;
179 		case VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER:
180 			out->prf(out->dst, "ip4_tcp_udp ip4_other");
181 			break;
182 		case VCAP_IS2_PS_IPV4_UC_IP_7TUPLE:
183 			out->prf(out->dst, "ip_7tuple");
184 			break;
185 		}
186 		out->prf(out->dst, "\n      ipv6_mc: ");
187 		switch (ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_GET(value)) {
188 		case VCAP_IS2_PS_IPV6_MC_MAC_ETYPE:
189 			out->prf(out->dst, "mac_etype");
190 			break;
191 		case VCAP_IS2_PS_IPV6_MC_IP_7TUPLE:
192 			out->prf(out->dst, "ip_7tuple");
193 			break;
194 		case VCAP_IS2_PS_IPV6_MC_IP6_VID:
195 			out->prf(out->dst, "ip6_vid");
196 			break;
197 		case VCAP_IS2_PS_IPV6_MC_IP6_STD:
198 			out->prf(out->dst, "ip6_std");
199 			break;
200 		case VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER:
201 			out->prf(out->dst, "ip4_tcp_udp ipv4_other");
202 			break;
203 		}
204 		out->prf(out->dst, "\n      ipv6_uc: ");
205 		switch (ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_GET(value)) {
206 		case VCAP_IS2_PS_IPV6_UC_MAC_ETYPE:
207 			out->prf(out->dst, "mac_etype");
208 			break;
209 		case VCAP_IS2_PS_IPV6_UC_IP_7TUPLE:
210 			out->prf(out->dst, "ip_7tuple");
211 			break;
212 		case VCAP_IS2_PS_IPV6_UC_IP6_STD:
213 			out->prf(out->dst, "ip6_std");
214 			break;
215 		case VCAP_IS2_PS_IPV6_UC_IP4_TCP_UDP_OTHER:
216 			out->prf(out->dst, "ip4_tcp_udp ip4_other");
217 			break;
218 		}
219 		out->prf(out->dst, "\n      arp: ");
220 		switch (ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_GET(value)) {
221 		case VCAP_IS2_PS_ARP_MAC_ETYPE:
222 			out->prf(out->dst, "mac_etype");
223 			break;
224 		case VCAP_IS2_PS_ARP_ARP:
225 			out->prf(out->dst, "arp");
226 			break;
227 		}
228 	}
229 	out->prf(out->dst, "\n");
230 }
231 
232 static void sparx5_vcap_is2_port_stickies(struct sparx5 *sparx5,
233 					  struct vcap_admin *admin,
234 					  struct vcap_output_print *out)
235 {
236 	int lookup;
237 	u32 value;
238 
239 	out->prf(out->dst, "  Sticky bits: ");
240 	for (lookup = 0; lookup < admin->lookups; ++lookup) {
241 		out->prf(out->dst, "\n    Lookup %d: ", lookup);
242 		/* Get lookup sticky bits */
243 		value = spx5_rd(sparx5, ANA_ACL_SEC_LOOKUP_STICKY(lookup));
244 
245 		if (ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_CLM_STICKY_GET(value))
246 			out->prf(out->dst, " sel_clm");
247 		if (ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_IRLEG_STICKY_GET(value))
248 			out->prf(out->dst, " sel_irleg");
249 		if (ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_ERLEG_STICKY_GET(value))
250 			out->prf(out->dst, " sel_erleg");
251 		if (ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_PORT_STICKY_GET(value))
252 			out->prf(out->dst, " sel_port");
253 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_CUSTOM2_STICKY_GET(value))
254 			out->prf(out->dst, " custom2");
255 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_CUSTOM1_STICKY_GET(value))
256 			out->prf(out->dst, " custom1");
257 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_OAM_STICKY_GET(value))
258 			out->prf(out->dst, " oam");
259 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_VID_STICKY_GET(value))
260 			out->prf(out->dst, " ip6_vid");
261 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_STD_STICKY_GET(value))
262 			out->prf(out->dst, " ip6_std");
263 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_TCPUDP_STICKY_GET(value))
264 			out->prf(out->dst, " ip6_tcpudp");
265 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP_7TUPLE_STICKY_GET(value))
266 			out->prf(out->dst, " ip_7tuple");
267 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_VID_STICKY_GET(value))
268 			out->prf(out->dst, " ip4_vid");
269 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_TCPUDP_STICKY_GET(value))
270 			out->prf(out->dst, " ip4_tcpudp");
271 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_OTHER_STICKY_GET(value))
272 			out->prf(out->dst, " ip4_other");
273 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_ARP_STICKY_GET(value))
274 			out->prf(out->dst, " arp");
275 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_SNAP_STICKY_GET(value))
276 			out->prf(out->dst, " mac_snap");
277 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_LLC_STICKY_GET(value))
278 			out->prf(out->dst, " mac_llc");
279 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_ETYPE_STICKY_GET(value))
280 			out->prf(out->dst, " mac_etype");
281 		/* Clear stickies */
282 		spx5_wr(value, sparx5, ANA_ACL_SEC_LOOKUP_STICKY(lookup));
283 	}
284 	out->prf(out->dst, "\n");
285 }
286 
287 static void sparx5_vcap_es2_port_keys(struct sparx5 *sparx5,
288 				      struct vcap_admin *admin,
289 				      struct sparx5_port *port,
290 				      struct vcap_output_print *out)
291 {
292 	int lookup;
293 	u32 value;
294 
295 	out->prf(out->dst, "  port[%02d] (%s): ", port->portno,
296 	   netdev_name(port->ndev));
297 	for (lookup = 0; lookup < admin->lookups; ++lookup) {
298 		out->prf(out->dst, "\n    Lookup %d: ", lookup);
299 
300 		/* Get lookup state */
301 		value = spx5_rd(sparx5, EACL_VCAP_ES2_KEY_SEL(port->portno,
302 							      lookup));
303 		out->prf(out->dst, "\n      state: ");
304 		if (EACL_VCAP_ES2_KEY_SEL_KEY_ENA_GET(value))
305 			out->prf(out->dst, "on");
306 		else
307 			out->prf(out->dst, "off");
308 
309 		out->prf(out->dst, "\n      arp: ");
310 		switch (EACL_VCAP_ES2_KEY_SEL_ARP_KEY_SEL_GET(value)) {
311 		case VCAP_ES2_PS_ARP_MAC_ETYPE:
312 			out->prf(out->dst, "mac_etype");
313 			break;
314 		case VCAP_ES2_PS_ARP_ARP:
315 			out->prf(out->dst, "arp");
316 			break;
317 		}
318 		out->prf(out->dst, "\n      ipv4: ");
319 		switch (EACL_VCAP_ES2_KEY_SEL_IP4_KEY_SEL_GET(value)) {
320 		case VCAP_ES2_PS_IPV4_MAC_ETYPE:
321 			out->prf(out->dst, "mac_etype");
322 			break;
323 		case VCAP_ES2_PS_IPV4_IP_7TUPLE:
324 			out->prf(out->dst, "ip_7tuple");
325 			break;
326 		case VCAP_ES2_PS_IPV4_IP4_TCP_UDP_VID:
327 			out->prf(out->dst, "ip4_tcp_udp ip4_vid");
328 			break;
329 		case VCAP_ES2_PS_IPV4_IP4_TCP_UDP_OTHER:
330 			out->prf(out->dst, "ip4_tcp_udp ip4_other");
331 			break;
332 		case VCAP_ES2_PS_IPV4_IP4_VID:
333 			out->prf(out->dst, "ip4_vid");
334 			break;
335 		case VCAP_ES2_PS_IPV4_IP4_OTHER:
336 			out->prf(out->dst, "ip4_other");
337 			break;
338 		}
339 		out->prf(out->dst, "\n      ipv6: ");
340 		switch (EACL_VCAP_ES2_KEY_SEL_IP6_KEY_SEL_GET(value)) {
341 		case VCAP_ES2_PS_IPV6_MAC_ETYPE:
342 			out->prf(out->dst, "mac_etype");
343 			break;
344 		case VCAP_ES2_PS_IPV6_IP_7TUPLE:
345 			out->prf(out->dst, "ip_7tuple");
346 			break;
347 		case VCAP_ES2_PS_IPV6_IP_7TUPLE_VID:
348 			out->prf(out->dst, "ip_7tuple ip6_vid");
349 			break;
350 		case VCAP_ES2_PS_IPV6_IP_7TUPLE_STD:
351 			out->prf(out->dst, "ip_7tuple ip6_std");
352 			break;
353 		case VCAP_ES2_PS_IPV6_IP6_VID:
354 			out->prf(out->dst, "ip6_vid");
355 			break;
356 		case VCAP_ES2_PS_IPV6_IP6_STD:
357 			out->prf(out->dst, "ip6_std");
358 			break;
359 		case VCAP_ES2_PS_IPV6_IP4_DOWNGRADE:
360 			out->prf(out->dst, "ip4_downgrade");
361 			break;
362 		}
363 	}
364 	out->prf(out->dst, "\n");
365 }
366 
367 static void sparx5_vcap_es2_port_stickies(struct sparx5 *sparx5,
368 					  struct vcap_admin *admin,
369 					  struct vcap_output_print *out)
370 {
371 	int lookup;
372 	u32 value;
373 
374 	out->prf(out->dst, "  Sticky bits: ");
375 	for (lookup = 0; lookup < admin->lookups; ++lookup) {
376 		value = spx5_rd(sparx5, EACL_SEC_LOOKUP_STICKY(lookup));
377 		out->prf(out->dst, "\n    Lookup %d: ", lookup);
378 		if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP_7TUPLE_STICKY_GET(value))
379 			out->prf(out->dst, " ip_7tuple");
380 		if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_VID_STICKY_GET(value))
381 			out->prf(out->dst, " ip6_vid");
382 		if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_STD_STICKY_GET(value))
383 			out->prf(out->dst, " ip6_std");
384 		if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_TCPUDP_STICKY_GET(value))
385 			out->prf(out->dst, " ip4_tcp_udp");
386 		if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_VID_STICKY_GET(value))
387 			out->prf(out->dst, " ip4_vid");
388 		if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_OTHER_STICKY_GET(value))
389 			out->prf(out->dst, " ip4_other");
390 		if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_ARP_STICKY_GET(value))
391 			out->prf(out->dst, " arp");
392 		if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_ETYPE_STICKY_GET(value))
393 			out->prf(out->dst, " mac_etype");
394 		/* Clear stickies */
395 		spx5_wr(value, sparx5, EACL_SEC_LOOKUP_STICKY(lookup));
396 	}
397 	out->prf(out->dst, "\n");
398 }
399 
400 /* Provide port information via a callback interface */
401 int sparx5_port_info(struct net_device *ndev,
402 		     struct vcap_admin *admin,
403 		     struct vcap_output_print *out)
404 {
405 	struct sparx5_port *port = netdev_priv(ndev);
406 	struct sparx5 *sparx5 = port->sparx5;
407 	const struct vcap_info *vcap;
408 	struct vcap_control *vctrl;
409 
410 	vctrl = sparx5->vcap_ctrl;
411 	vcap = &vctrl->vcaps[admin->vtype];
412 	out->prf(out->dst, "%s:\n", vcap->name);
413 	switch (admin->vtype) {
414 	case VCAP_TYPE_IS0:
415 		sparx5_vcap_is0_port_keys(sparx5, admin, port, out);
416 		break;
417 	case VCAP_TYPE_IS2:
418 		sparx5_vcap_is2_port_keys(sparx5, admin, port, out);
419 		sparx5_vcap_is2_port_stickies(sparx5, admin, out);
420 		break;
421 	case VCAP_TYPE_ES2:
422 		sparx5_vcap_es2_port_keys(sparx5, admin, port, out);
423 		sparx5_vcap_es2_port_stickies(sparx5, admin, out);
424 		break;
425 	default:
426 		out->prf(out->dst, "  no info\n");
427 		break;
428 	}
429 	return 0;
430 }
431