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(dev: 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(value: 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(value: 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(value: 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(value: 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(value: 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(value: 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(dev: 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(val: 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(dev: 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(dev: 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(val: 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(dev: 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

source code of linux/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_debugfs.c