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
16static 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
40static 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
64static 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
76static 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
119static 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
232static 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
287static 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
325static 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
405static 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 */
439int 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