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_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