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 void sparx5_vcap_port_keys(struct sparx5 *sparx5,
17 				  struct vcap_admin *admin,
18 				  struct sparx5_port *port,
19 				  struct vcap_output_print *out)
20 {
21 	int lookup;
22 	u32 value;
23 
24 	out->prf(out->dst, "  port[%02d] (%s): ", port->portno,
25 	   netdev_name(port->ndev));
26 	for (lookup = 0; lookup < admin->lookups; ++lookup) {
27 		out->prf(out->dst, "\n    Lookup %d: ", lookup);
28 
29 		/* Get lookup state */
30 		value = spx5_rd(sparx5, ANA_ACL_VCAP_S2_CFG(port->portno));
31 		out->prf(out->dst, "\n      state: ");
32 		if (ANA_ACL_VCAP_S2_CFG_SEC_ENA_GET(value))
33 			out->prf(out->dst, "on");
34 		else
35 			out->prf(out->dst, "off");
36 
37 		/* Get key selection state */
38 		value = spx5_rd(sparx5,
39 				ANA_ACL_VCAP_S2_KEY_SEL(port->portno, lookup));
40 
41 		out->prf(out->dst, "\n      noneth: ");
42 		switch (ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_GET(value)) {
43 		case VCAP_IS2_PS_NONETH_MAC_ETYPE:
44 			out->prf(out->dst, "mac_etype");
45 			break;
46 		case VCAP_IS2_PS_NONETH_CUSTOM_1:
47 			out->prf(out->dst, "custom1");
48 			break;
49 		case VCAP_IS2_PS_NONETH_CUSTOM_2:
50 			out->prf(out->dst, "custom2");
51 			break;
52 		case VCAP_IS2_PS_NONETH_NO_LOOKUP:
53 			out->prf(out->dst, "none");
54 			break;
55 		}
56 		out->prf(out->dst, "\n      ipv4_mc: ");
57 		switch (ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_GET(value)) {
58 		case VCAP_IS2_PS_IPV4_MC_MAC_ETYPE:
59 			out->prf(out->dst, "mac_etype");
60 			break;
61 		case VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER:
62 			out->prf(out->dst, "ip4_tcp_udp ip4_other");
63 			break;
64 		case VCAP_IS2_PS_IPV4_MC_IP_7TUPLE:
65 			out->prf(out->dst, "ip_7tuple");
66 			break;
67 		case VCAP_IS2_PS_IPV4_MC_IP4_VID:
68 			out->prf(out->dst, "ip4_vid");
69 			break;
70 		}
71 		out->prf(out->dst, "\n      ipv4_uc: ");
72 		switch (ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_GET(value)) {
73 		case VCAP_IS2_PS_IPV4_UC_MAC_ETYPE:
74 			out->prf(out->dst, "mac_etype");
75 			break;
76 		case VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER:
77 			out->prf(out->dst, "ip4_tcp_udp ip4_other");
78 			break;
79 		case VCAP_IS2_PS_IPV4_UC_IP_7TUPLE:
80 			out->prf(out->dst, "ip_7tuple");
81 			break;
82 		}
83 		out->prf(out->dst, "\n      ipv6_mc: ");
84 		switch (ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_GET(value)) {
85 		case VCAP_IS2_PS_IPV6_MC_MAC_ETYPE:
86 			out->prf(out->dst, "mac_etype");
87 			break;
88 		case VCAP_IS2_PS_IPV6_MC_IP_7TUPLE:
89 			out->prf(out->dst, "ip_7tuple");
90 			break;
91 		case VCAP_IS2_PS_IPV6_MC_IP6_VID:
92 			out->prf(out->dst, "ip6_vid");
93 			break;
94 		case VCAP_IS2_PS_IPV6_MC_IP6_STD:
95 			out->prf(out->dst, "ip6_std");
96 			break;
97 		case VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER:
98 			out->prf(out->dst, "ip4_tcp_udp ipv4_other");
99 			break;
100 		}
101 		out->prf(out->dst, "\n      ipv6_uc: ");
102 		switch (ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_GET(value)) {
103 		case VCAP_IS2_PS_IPV6_UC_MAC_ETYPE:
104 			out->prf(out->dst, "mac_etype");
105 			break;
106 		case VCAP_IS2_PS_IPV6_UC_IP_7TUPLE:
107 			out->prf(out->dst, "ip_7tuple");
108 			break;
109 		case VCAP_IS2_PS_IPV6_UC_IP6_STD:
110 			out->prf(out->dst, "ip6_std");
111 			break;
112 		case VCAP_IS2_PS_IPV6_UC_IP4_TCP_UDP_OTHER:
113 			out->prf(out->dst, "ip4_tcp_udp ip4_other");
114 			break;
115 		}
116 		out->prf(out->dst, "\n      arp: ");
117 		switch (ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_GET(value)) {
118 		case VCAP_IS2_PS_ARP_MAC_ETYPE:
119 			out->prf(out->dst, "mac_etype");
120 			break;
121 		case VCAP_IS2_PS_ARP_ARP:
122 			out->prf(out->dst, "arp");
123 			break;
124 		}
125 	}
126 	out->prf(out->dst, "\n");
127 }
128 
129 static void sparx5_vcap_port_stickies(struct sparx5 *sparx5,
130 				      struct vcap_admin *admin,
131 				      struct vcap_output_print *out)
132 {
133 	int lookup;
134 	u32 value;
135 
136 	out->prf(out->dst, "  Sticky bits: ");
137 	for (lookup = 0; lookup < admin->lookups; ++lookup) {
138 		out->prf(out->dst, "\n    Lookup %d: ", lookup);
139 		/* Get lookup sticky bits */
140 		value = spx5_rd(sparx5, ANA_ACL_SEC_LOOKUP_STICKY(lookup));
141 
142 		if (ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_CLM_STICKY_GET(value))
143 			out->prf(out->dst, " sel_clm");
144 		if (ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_IRLEG_STICKY_GET(value))
145 			out->prf(out->dst, " sel_irleg");
146 		if (ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_ERLEG_STICKY_GET(value))
147 			out->prf(out->dst, " sel_erleg");
148 		if (ANA_ACL_SEC_LOOKUP_STICKY_KEY_SEL_PORT_STICKY_GET(value))
149 			out->prf(out->dst, " sel_port");
150 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_CUSTOM2_STICKY_GET(value))
151 			out->prf(out->dst, " custom2");
152 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_CUSTOM1_STICKY_GET(value))
153 			out->prf(out->dst, " custom1");
154 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_OAM_STICKY_GET(value))
155 			out->prf(out->dst, " oam");
156 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_VID_STICKY_GET(value))
157 			out->prf(out->dst, " ip6_vid");
158 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_STD_STICKY_GET(value))
159 			out->prf(out->dst, " ip6_std");
160 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP6_TCPUDP_STICKY_GET(value))
161 			out->prf(out->dst, " ip6_tcpudp");
162 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP_7TUPLE_STICKY_GET(value))
163 			out->prf(out->dst, " ip_7tuple");
164 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_VID_STICKY_GET(value))
165 			out->prf(out->dst, " ip4_vid");
166 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_TCPUDP_STICKY_GET(value))
167 			out->prf(out->dst, " ip4_tcpudp");
168 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_IP4_OTHER_STICKY_GET(value))
169 			out->prf(out->dst, " ip4_other");
170 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_ARP_STICKY_GET(value))
171 			out->prf(out->dst, " arp");
172 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_SNAP_STICKY_GET(value))
173 			out->prf(out->dst, " mac_snap");
174 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_LLC_STICKY_GET(value))
175 			out->prf(out->dst, " mac_llc");
176 		if (ANA_ACL_SEC_LOOKUP_STICKY_SEC_TYPE_MAC_ETYPE_STICKY_GET(value))
177 			out->prf(out->dst, " mac_etype");
178 		/* Clear stickies */
179 		spx5_wr(value, sparx5, ANA_ACL_SEC_LOOKUP_STICKY(lookup));
180 	}
181 	out->prf(out->dst, "\n");
182 }
183 
184 /* Provide port information via a callback interface */
185 int sparx5_port_info(struct net_device *ndev,
186 		     struct vcap_admin *admin,
187 		     struct vcap_output_print *out)
188 {
189 	struct sparx5_port *port = netdev_priv(ndev);
190 	struct sparx5 *sparx5 = port->sparx5;
191 	const struct vcap_info *vcap;
192 	struct vcap_control *vctrl;
193 
194 	vctrl = sparx5->vcap_ctrl;
195 	vcap = &vctrl->vcaps[admin->vtype];
196 	out->prf(out->dst, "%s:\n", vcap->name);
197 	sparx5_vcap_port_keys(sparx5, admin, port, out);
198 	sparx5_vcap_port_stickies(sparx5, admin, out);
199 	return 0;
200 }
201