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 ip4_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_es0_port_keys(struct sparx5 *sparx5,
288 				      struct vcap_admin *admin,
289 				      struct sparx5_port *port,
290 				      struct vcap_output_print *out)
291 {
292 	u32 value;
293 
294 	out->prf(out->dst, "  port[%02d] (%s): ", port->portno,
295 		 netdev_name(port->ndev));
296 	out->prf(out->dst, "\n    Lookup 0: ");
297 
298 	/* Get lookup state */
299 	value = spx5_rd(sparx5, REW_ES0_CTRL);
300 	out->prf(out->dst, "\n      state: ");
301 	if (REW_ES0_CTRL_ES0_LU_ENA_GET(value))
302 		out->prf(out->dst, "on");
303 	else
304 		out->prf(out->dst, "off");
305 
306 	out->prf(out->dst, "\n      keyset: ");
307 	value = spx5_rd(sparx5, REW_RTAG_ETAG_CTRL(port->portno));
308 	switch (REW_RTAG_ETAG_CTRL_ES0_ISDX_KEY_ENA_GET(value)) {
309 	case VCAP_ES0_PS_NORMAL_SELECTION:
310 		out->prf(out->dst, "normal");
311 		break;
312 	case VCAP_ES0_PS_FORCE_ISDX_LOOKUPS:
313 		out->prf(out->dst, "isdx");
314 		break;
315 	case VCAP_ES0_PS_FORCE_VID_LOOKUPS:
316 		out->prf(out->dst, "vid");
317 		break;
318 	case VCAP_ES0_PS_RESERVED:
319 		out->prf(out->dst, "reserved");
320 		break;
321 	}
322 	out->prf(out->dst, "\n");
323 }
324 
325 static void sparx5_vcap_es2_port_keys(struct sparx5 *sparx5,
326 				      struct vcap_admin *admin,
327 				      struct sparx5_port *port,
328 				      struct vcap_output_print *out)
329 {
330 	int lookup;
331 	u32 value;
332 
333 	out->prf(out->dst, "  port[%02d] (%s): ", port->portno,
334 	   netdev_name(port->ndev));
335 	for (lookup = 0; lookup < admin->lookups; ++lookup) {
336 		out->prf(out->dst, "\n    Lookup %d: ", lookup);
337 
338 		/* Get lookup state */
339 		value = spx5_rd(sparx5, EACL_VCAP_ES2_KEY_SEL(port->portno,
340 							      lookup));
341 		out->prf(out->dst, "\n      state: ");
342 		if (EACL_VCAP_ES2_KEY_SEL_KEY_ENA_GET(value))
343 			out->prf(out->dst, "on");
344 		else
345 			out->prf(out->dst, "off");
346 
347 		out->prf(out->dst, "\n      arp: ");
348 		switch (EACL_VCAP_ES2_KEY_SEL_ARP_KEY_SEL_GET(value)) {
349 		case VCAP_ES2_PS_ARP_MAC_ETYPE:
350 			out->prf(out->dst, "mac_etype");
351 			break;
352 		case VCAP_ES2_PS_ARP_ARP:
353 			out->prf(out->dst, "arp");
354 			break;
355 		}
356 		out->prf(out->dst, "\n      ipv4: ");
357 		switch (EACL_VCAP_ES2_KEY_SEL_IP4_KEY_SEL_GET(value)) {
358 		case VCAP_ES2_PS_IPV4_MAC_ETYPE:
359 			out->prf(out->dst, "mac_etype");
360 			break;
361 		case VCAP_ES2_PS_IPV4_IP_7TUPLE:
362 			out->prf(out->dst, "ip_7tuple");
363 			break;
364 		case VCAP_ES2_PS_IPV4_IP4_TCP_UDP_VID:
365 			out->prf(out->dst, "ip4_tcp_udp ip4_vid");
366 			break;
367 		case VCAP_ES2_PS_IPV4_IP4_TCP_UDP_OTHER:
368 			out->prf(out->dst, "ip4_tcp_udp ip4_other");
369 			break;
370 		case VCAP_ES2_PS_IPV4_IP4_VID:
371 			out->prf(out->dst, "ip4_vid");
372 			break;
373 		case VCAP_ES2_PS_IPV4_IP4_OTHER:
374 			out->prf(out->dst, "ip4_other");
375 			break;
376 		}
377 		out->prf(out->dst, "\n      ipv6: ");
378 		switch (EACL_VCAP_ES2_KEY_SEL_IP6_KEY_SEL_GET(value)) {
379 		case VCAP_ES2_PS_IPV6_MAC_ETYPE:
380 			out->prf(out->dst, "mac_etype");
381 			break;
382 		case VCAP_ES2_PS_IPV6_IP_7TUPLE:
383 			out->prf(out->dst, "ip_7tuple");
384 			break;
385 		case VCAP_ES2_PS_IPV6_IP_7TUPLE_VID:
386 			out->prf(out->dst, "ip_7tuple ip6_vid");
387 			break;
388 		case VCAP_ES2_PS_IPV6_IP_7TUPLE_STD:
389 			out->prf(out->dst, "ip_7tuple ip6_std");
390 			break;
391 		case VCAP_ES2_PS_IPV6_IP6_VID:
392 			out->prf(out->dst, "ip6_vid");
393 			break;
394 		case VCAP_ES2_PS_IPV6_IP6_STD:
395 			out->prf(out->dst, "ip6_std");
396 			break;
397 		case VCAP_ES2_PS_IPV6_IP4_DOWNGRADE:
398 			out->prf(out->dst, "ip4_downgrade");
399 			break;
400 		}
401 	}
402 	out->prf(out->dst, "\n");
403 }
404 
405 static void sparx5_vcap_es2_port_stickies(struct sparx5 *sparx5,
406 					  struct vcap_admin *admin,
407 					  struct vcap_output_print *out)
408 {
409 	int lookup;
410 	u32 value;
411 
412 	out->prf(out->dst, "  Sticky bits: ");
413 	for (lookup = 0; lookup < admin->lookups; ++lookup) {
414 		value = spx5_rd(sparx5, EACL_SEC_LOOKUP_STICKY(lookup));
415 		out->prf(out->dst, "\n    Lookup %d: ", lookup);
416 		if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP_7TUPLE_STICKY_GET(value))
417 			out->prf(out->dst, " ip_7tuple");
418 		if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_VID_STICKY_GET(value))
419 			out->prf(out->dst, " ip6_vid");
420 		if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_STD_STICKY_GET(value))
421 			out->prf(out->dst, " ip6_std");
422 		if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_TCPUDP_STICKY_GET(value))
423 			out->prf(out->dst, " ip4_tcp_udp");
424 		if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_VID_STICKY_GET(value))
425 			out->prf(out->dst, " ip4_vid");
426 		if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_OTHER_STICKY_GET(value))
427 			out->prf(out->dst, " ip4_other");
428 		if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_ARP_STICKY_GET(value))
429 			out->prf(out->dst, " arp");
430 		if (EACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_ETYPE_STICKY_GET(value))
431 			out->prf(out->dst, " mac_etype");
432 		/* Clear stickies */
433 		spx5_wr(value, sparx5, EACL_SEC_LOOKUP_STICKY(lookup));
434 	}
435 	out->prf(out->dst, "\n");
436 }
437 
438 /* Provide port information via a callback interface */
439 int sparx5_port_info(struct net_device *ndev,
440 		     struct vcap_admin *admin,
441 		     struct vcap_output_print *out)
442 {
443 	struct sparx5_port *port = netdev_priv(ndev);
444 	struct sparx5 *sparx5 = port->sparx5;
445 	const struct vcap_info *vcap;
446 	struct vcap_control *vctrl;
447 
448 	vctrl = sparx5->vcap_ctrl;
449 	vcap = &vctrl->vcaps[admin->vtype];
450 	out->prf(out->dst, "%s:\n", vcap->name);
451 	switch (admin->vtype) {
452 	case VCAP_TYPE_IS0:
453 		sparx5_vcap_is0_port_keys(sparx5, admin, port, out);
454 		break;
455 	case VCAP_TYPE_IS2:
456 		sparx5_vcap_is2_port_keys(sparx5, admin, port, out);
457 		sparx5_vcap_is2_port_stickies(sparx5, admin, out);
458 		break;
459 	case VCAP_TYPE_ES0:
460 		sparx5_vcap_es0_port_keys(sparx5, admin, port, out);
461 		break;
462 	case VCAP_TYPE_ES2:
463 		sparx5_vcap_es2_port_keys(sparx5, admin, port, out);
464 		sparx5_vcap_es2_port_stickies(sparx5, admin, out);
465 		break;
466 	default:
467 		out->prf(out->dst, "  no info\n");
468 		break;
469 	}
470 	return 0;
471 }
472