1 // SPDX-License-Identifier: GPL-2.0+ 2 /* Microchip Sparx5 Switch driver VCAP implementation 3 * 4 * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries. 5 * 6 * The Sparx5 Chip Register Model can be browsed at this location: 7 * https://github.com/microchip-ung/sparx-5_reginfo 8 */ 9 10 #include <linux/types.h> 11 #include <linux/list.h> 12 13 #include "vcap_api.h" 14 #include "vcap_api_client.h" 15 #include "sparx5_main_regs.h" 16 #include "sparx5_main.h" 17 #include "sparx5_vcap_impl.h" 18 #include "sparx5_vcap_ag_api.h" 19 20 #define SUPER_VCAP_BLK_SIZE 3072 /* addresses per Super VCAP block */ 21 #define STREAMSIZE (64 * 4) /* bytes in the VCAP cache area */ 22 23 #define SPARX5_IS2_LOOKUPS 4 24 #define VCAP_IS2_KEYSEL(_ena, _noneth, _v4_mc, _v4_uc, _v6_mc, _v6_uc, _arp) \ 25 (ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_SET(_ena) | \ 26 ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_SET(_noneth) | \ 27 ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_SET(_v4_mc) | \ 28 ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_SET(_v4_uc) | \ 29 ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_SET(_v6_mc) | \ 30 ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_SET(_v6_uc) | \ 31 ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_SET(_arp)) 32 33 /* IS2 port keyset selection control */ 34 35 /* IS2 non-ethernet traffic type keyset generation */ 36 enum vcap_is2_port_sel_noneth { 37 VCAP_IS2_PS_NONETH_MAC_ETYPE, 38 VCAP_IS2_PS_NONETH_CUSTOM_1, 39 VCAP_IS2_PS_NONETH_CUSTOM_2, 40 VCAP_IS2_PS_NONETH_NO_LOOKUP 41 }; 42 43 /* IS2 IPv4 unicast traffic type keyset generation */ 44 enum vcap_is2_port_sel_ipv4_uc { 45 VCAP_IS2_PS_IPV4_UC_MAC_ETYPE, 46 VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER, 47 VCAP_IS2_PS_IPV4_UC_IP_7TUPLE, 48 }; 49 50 /* IS2 IPv4 multicast traffic type keyset generation */ 51 enum vcap_is2_port_sel_ipv4_mc { 52 VCAP_IS2_PS_IPV4_MC_MAC_ETYPE, 53 VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER, 54 VCAP_IS2_PS_IPV4_MC_IP_7TUPLE, 55 VCAP_IS2_PS_IPV4_MC_IP4_VID, 56 }; 57 58 /* IS2 IPv6 unicast traffic type keyset generation */ 59 enum vcap_is2_port_sel_ipv6_uc { 60 VCAP_IS2_PS_IPV6_UC_MAC_ETYPE, 61 VCAP_IS2_PS_IPV6_UC_IP_7TUPLE, 62 VCAP_IS2_PS_IPV6_UC_IP6_STD, 63 VCAP_IS2_PS_IPV6_UC_IP4_TCP_UDP_OTHER, 64 }; 65 66 /* IS2 IPv6 multicast traffic type keyset generation */ 67 enum vcap_is2_port_sel_ipv6_mc { 68 VCAP_IS2_PS_IPV6_MC_MAC_ETYPE, 69 VCAP_IS2_PS_IPV6_MC_IP_7TUPLE, 70 VCAP_IS2_PS_IPV6_MC_IP6_VID, 71 VCAP_IS2_PS_IPV6_MC_IP6_STD, 72 VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER, 73 }; 74 75 /* IS2 ARP traffic type keyset generation */ 76 enum vcap_is2_port_sel_arp { 77 VCAP_IS2_PS_ARP_MAC_ETYPE, 78 VCAP_IS2_PS_ARP_ARP, 79 }; 80 81 static struct sparx5_vcap_inst { 82 enum vcap_type vtype; /* type of vcap */ 83 int vinst; /* instance number within the same type */ 84 int lookups; /* number of lookups in this vcap type */ 85 int lookups_per_instance; /* number of lookups in this instance */ 86 int first_cid; /* first chain id in this vcap */ 87 int last_cid; /* last chain id in this vcap */ 88 int count; /* number of available addresses, not in super vcap */ 89 int map_id; /* id in the super vcap block mapping (if applicable) */ 90 int blockno; /* starting block in super vcap (if applicable) */ 91 int blocks; /* number of blocks in super vcap (if applicable) */ 92 } sparx5_vcap_inst_cfg[] = { 93 { 94 .vtype = VCAP_TYPE_IS2, /* IS2-0 */ 95 .vinst = 0, 96 .map_id = 4, 97 .lookups = SPARX5_IS2_LOOKUPS, 98 .lookups_per_instance = SPARX5_IS2_LOOKUPS / 2, 99 .first_cid = SPARX5_VCAP_CID_IS2_L0, 100 .last_cid = SPARX5_VCAP_CID_IS2_L2 - 1, 101 .blockno = 0, /* Maps block 0-1 */ 102 .blocks = 2, 103 }, 104 { 105 .vtype = VCAP_TYPE_IS2, /* IS2-1 */ 106 .vinst = 1, 107 .map_id = 5, 108 .lookups = SPARX5_IS2_LOOKUPS, 109 .lookups_per_instance = SPARX5_IS2_LOOKUPS / 2, 110 .first_cid = SPARX5_VCAP_CID_IS2_L2, 111 .last_cid = SPARX5_VCAP_CID_IS2_MAX, 112 .blockno = 2, /* Maps block 2-3 */ 113 .blocks = 2, 114 }, 115 }; 116 117 /* Await the super VCAP completion of the current operation */ 118 static void sparx5_vcap_wait_super_update(struct sparx5 *sparx5) 119 { 120 u32 value; 121 122 read_poll_timeout(spx5_rd, value, 123 !VCAP_SUPER_CTRL_UPDATE_SHOT_GET(value), 500, 10000, 124 false, sparx5, VCAP_SUPER_CTRL); 125 } 126 127 /* Initializing a VCAP address range: only IS2 for now */ 128 static void _sparx5_vcap_range_init(struct sparx5 *sparx5, 129 struct vcap_admin *admin, 130 u32 addr, u32 count) 131 { 132 u32 size = count - 1; 133 134 spx5_wr(VCAP_SUPER_CFG_MV_NUM_POS_SET(0) | 135 VCAP_SUPER_CFG_MV_SIZE_SET(size), 136 sparx5, VCAP_SUPER_CFG); 137 spx5_wr(VCAP_SUPER_CTRL_UPDATE_CMD_SET(VCAP_CMD_INITIALIZE) | 138 VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET(0) | 139 VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET(0) | 140 VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET(0) | 141 VCAP_SUPER_CTRL_UPDATE_ADDR_SET(addr) | 142 VCAP_SUPER_CTRL_CLEAR_CACHE_SET(true) | 143 VCAP_SUPER_CTRL_UPDATE_SHOT_SET(true), 144 sparx5, VCAP_SUPER_CTRL); 145 sparx5_vcap_wait_super_update(sparx5); 146 } 147 148 /* Initializing VCAP rule data area */ 149 static void sparx5_vcap_block_init(struct sparx5 *sparx5, 150 struct vcap_admin *admin) 151 { 152 _sparx5_vcap_range_init(sparx5, admin, admin->first_valid_addr, 153 admin->last_valid_addr - 154 admin->first_valid_addr); 155 } 156 157 /* Get the keyset name from the sparx5 VCAP model */ 158 static const char *sparx5_vcap_keyset_name(struct net_device *ndev, 159 enum vcap_keyfield_set keyset) 160 { 161 struct sparx5_port *port = netdev_priv(ndev); 162 163 return vcap_keyset_name(port->sparx5->vcap_ctrl, keyset); 164 } 165 166 /* Check if this is the first lookup of IS2 */ 167 static bool sparx5_vcap_is2_is_first_chain(struct vcap_rule *rule) 168 { 169 return (rule->vcap_chain_id >= SPARX5_VCAP_CID_IS2_L0 && 170 rule->vcap_chain_id < SPARX5_VCAP_CID_IS2_L1) || 171 ((rule->vcap_chain_id >= SPARX5_VCAP_CID_IS2_L2 && 172 rule->vcap_chain_id < SPARX5_VCAP_CID_IS2_L3)); 173 } 174 175 /* Set the narrow range ingress port mask on a rule */ 176 static void sparx5_vcap_add_range_port_mask(struct vcap_rule *rule, 177 struct net_device *ndev) 178 { 179 struct sparx5_port *port = netdev_priv(ndev); 180 u32 port_mask; 181 u32 range; 182 183 range = port->portno / BITS_PER_TYPE(u32); 184 /* Port bit set to match-any */ 185 port_mask = ~BIT(port->portno % BITS_PER_TYPE(u32)); 186 vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK_SEL, 0, 0xf); 187 vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK_RNG, range, 0xf); 188 vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0, port_mask); 189 } 190 191 /* Set the wide range ingress port mask on a rule */ 192 static void sparx5_vcap_add_wide_port_mask(struct vcap_rule *rule, 193 struct net_device *ndev) 194 { 195 struct sparx5_port *port = netdev_priv(ndev); 196 struct vcap_u72_key port_mask; 197 u32 range; 198 199 /* Port bit set to match-any */ 200 memset(port_mask.value, 0, sizeof(port_mask.value)); 201 memset(port_mask.mask, 0xff, sizeof(port_mask.mask)); 202 range = port->portno / BITS_PER_BYTE; 203 port_mask.mask[range] = ~BIT(port->portno % BITS_PER_BYTE); 204 vcap_rule_add_key_u72(rule, VCAP_KF_IF_IGR_PORT_MASK, &port_mask); 205 } 206 207 /* Convert chain id to vcap lookup id */ 208 static int sparx5_vcap_cid_to_lookup(int cid) 209 { 210 int lookup = 0; 211 212 /* For now only handle IS2 */ 213 if (cid >= SPARX5_VCAP_CID_IS2_L1 && cid < SPARX5_VCAP_CID_IS2_L2) 214 lookup = 1; 215 else if (cid >= SPARX5_VCAP_CID_IS2_L2 && cid < SPARX5_VCAP_CID_IS2_L3) 216 lookup = 2; 217 else if (cid >= SPARX5_VCAP_CID_IS2_L3 && cid < SPARX5_VCAP_CID_IS2_MAX) 218 lookup = 3; 219 220 return lookup; 221 } 222 223 /* Return the list of keysets for the vcap port configuration */ 224 static int sparx5_vcap_is2_get_port_keysets(struct net_device *ndev, 225 int lookup, 226 struct vcap_keyset_list *keysetlist, 227 u16 l3_proto) 228 { 229 struct sparx5_port *port = netdev_priv(ndev); 230 struct sparx5 *sparx5 = port->sparx5; 231 int portno = port->portno; 232 u32 value; 233 234 /* Check if the port keyset selection is enabled */ 235 value = spx5_rd(sparx5, ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup)); 236 if (!ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_GET(value)) 237 return -ENOENT; 238 239 /* Collect all keysets for the port in a list */ 240 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_ARP) { 241 switch (ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_GET(value)) { 242 case VCAP_IS2_PS_ARP_MAC_ETYPE: 243 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE); 244 break; 245 case VCAP_IS2_PS_ARP_ARP: 246 vcap_keyset_list_add(keysetlist, VCAP_KFS_ARP); 247 break; 248 } 249 } 250 251 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) { 252 switch (ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_GET(value)) { 253 case VCAP_IS2_PS_IPV4_UC_MAC_ETYPE: 254 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE); 255 break; 256 case VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER: 257 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP); 258 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER); 259 break; 260 case VCAP_IS2_PS_IPV4_UC_IP_7TUPLE: 261 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE); 262 break; 263 } 264 265 switch (ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_GET(value)) { 266 case VCAP_IS2_PS_IPV4_MC_MAC_ETYPE: 267 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE); 268 break; 269 case VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER: 270 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP); 271 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER); 272 break; 273 case VCAP_IS2_PS_IPV4_MC_IP_7TUPLE: 274 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE); 275 break; 276 } 277 } 278 279 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) { 280 switch (ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_GET(value)) { 281 case VCAP_IS2_PS_IPV6_UC_MAC_ETYPE: 282 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE); 283 break; 284 case VCAP_IS2_PS_IPV6_UC_IP_7TUPLE: 285 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE); 286 break; 287 case VCAP_IS2_PS_IPV6_UC_IP6_STD: 288 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD); 289 break; 290 case VCAP_IS2_PS_IPV6_UC_IP4_TCP_UDP_OTHER: 291 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP); 292 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER); 293 break; 294 } 295 296 switch (ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_GET(value)) { 297 case VCAP_IS2_PS_IPV6_MC_MAC_ETYPE: 298 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE); 299 break; 300 case VCAP_IS2_PS_IPV6_MC_IP_7TUPLE: 301 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE); 302 break; 303 case VCAP_IS2_PS_IPV6_MC_IP6_STD: 304 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD); 305 break; 306 case VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER: 307 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP); 308 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER); 309 break; 310 case VCAP_IS2_PS_IPV6_MC_IP6_VID: 311 /* Not used */ 312 break; 313 } 314 } 315 316 if (l3_proto != ETH_P_ARP && l3_proto != ETH_P_IP && 317 l3_proto != ETH_P_IPV6) { 318 switch (ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_GET(value)) { 319 case VCAP_IS2_PS_NONETH_MAC_ETYPE: 320 /* IS2 non-classified frames generate MAC_ETYPE */ 321 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE); 322 break; 323 } 324 } 325 return 0; 326 } 327 328 /* API callback used for validating a field keyset (check the port keysets) */ 329 static enum vcap_keyfield_set 330 sparx5_vcap_validate_keyset(struct net_device *ndev, 331 struct vcap_admin *admin, 332 struct vcap_rule *rule, 333 struct vcap_keyset_list *kslist, 334 u16 l3_proto) 335 { 336 struct vcap_keyset_list keysetlist = {}; 337 enum vcap_keyfield_set keysets[10] = {}; 338 int idx, jdx, lookup; 339 340 if (!kslist || kslist->cnt == 0) 341 return VCAP_KFS_NO_VALUE; 342 343 /* Get a list of currently configured keysets in the lookups */ 344 lookup = sparx5_vcap_cid_to_lookup(rule->vcap_chain_id); 345 keysetlist.max = ARRAY_SIZE(keysets); 346 keysetlist.keysets = keysets; 347 sparx5_vcap_is2_get_port_keysets(ndev, lookup, &keysetlist, l3_proto); 348 349 /* Check if there is a match and return the match */ 350 for (idx = 0; idx < kslist->cnt; ++idx) 351 for (jdx = 0; jdx < keysetlist.cnt; ++jdx) 352 if (kslist->keysets[idx] == keysets[jdx]) 353 return kslist->keysets[idx]; 354 355 pr_err("%s:%d: %s not supported in port key selection\n", 356 __func__, __LINE__, 357 sparx5_vcap_keyset_name(ndev, kslist->keysets[0])); 358 359 return -ENOENT; 360 } 361 362 /* API callback used for adding default fields to a rule */ 363 static void sparx5_vcap_add_default_fields(struct net_device *ndev, 364 struct vcap_admin *admin, 365 struct vcap_rule *rule) 366 { 367 const struct vcap_field *field; 368 369 field = vcap_lookup_keyfield(rule, VCAP_KF_IF_IGR_PORT_MASK); 370 if (field && field->width == SPX5_PORTS) 371 sparx5_vcap_add_wide_port_mask(rule, ndev); 372 else if (field && field->width == BITS_PER_TYPE(u32)) 373 sparx5_vcap_add_range_port_mask(rule, ndev); 374 else 375 pr_err("%s:%d: %s: could not add an ingress port mask for: %s\n", 376 __func__, __LINE__, netdev_name(ndev), 377 sparx5_vcap_keyset_name(ndev, rule->keyset)); 378 /* add the lookup bit */ 379 if (sparx5_vcap_is2_is_first_chain(rule)) 380 vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, VCAP_BIT_1); 381 else 382 vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, VCAP_BIT_0); 383 } 384 385 /* API callback used for erasing the vcap cache area (not the register area) */ 386 static void sparx5_vcap_cache_erase(struct vcap_admin *admin) 387 { 388 memset(admin->cache.keystream, 0, STREAMSIZE); 389 memset(admin->cache.maskstream, 0, STREAMSIZE); 390 memset(admin->cache.actionstream, 0, STREAMSIZE); 391 memset(&admin->cache.counter, 0, sizeof(admin->cache.counter)); 392 } 393 394 /* API callback used for writing to the VCAP cache */ 395 static void sparx5_vcap_cache_write(struct net_device *ndev, 396 struct vcap_admin *admin, 397 enum vcap_selection sel, 398 u32 start, 399 u32 count) 400 { 401 struct sparx5_port *port = netdev_priv(ndev); 402 struct sparx5 *sparx5 = port->sparx5; 403 u32 *keystr, *mskstr, *actstr; 404 int idx; 405 406 keystr = &admin->cache.keystream[start]; 407 mskstr = &admin->cache.maskstream[start]; 408 actstr = &admin->cache.actionstream[start]; 409 switch (sel) { 410 case VCAP_SEL_ENTRY: 411 for (idx = 0; idx < count; ++idx) { 412 /* Avoid 'match-off' by setting value & mask */ 413 spx5_wr(keystr[idx] & mskstr[idx], sparx5, 414 VCAP_SUPER_VCAP_ENTRY_DAT(idx)); 415 spx5_wr(~mskstr[idx], sparx5, 416 VCAP_SUPER_VCAP_MASK_DAT(idx)); 417 } 418 break; 419 case VCAP_SEL_ACTION: 420 for (idx = 0; idx < count; ++idx) 421 spx5_wr(actstr[idx], sparx5, 422 VCAP_SUPER_VCAP_ACTION_DAT(idx)); 423 break; 424 case VCAP_SEL_ALL: 425 pr_err("%s:%d: cannot write all streams at once\n", 426 __func__, __LINE__); 427 break; 428 default: 429 break; 430 } 431 if (sel & VCAP_SEL_COUNTER) { 432 start = start & 0xfff; /* counter limit */ 433 if (admin->vinst == 0) 434 spx5_wr(admin->cache.counter, sparx5, 435 ANA_ACL_CNT_A(start)); 436 else 437 spx5_wr(admin->cache.counter, sparx5, 438 ANA_ACL_CNT_B(start)); 439 spx5_wr(admin->cache.sticky, sparx5, 440 VCAP_SUPER_VCAP_CNT_DAT(0)); 441 } 442 } 443 444 /* API callback used for reading from the VCAP into the VCAP cache */ 445 static void sparx5_vcap_cache_read(struct net_device *ndev, 446 struct vcap_admin *admin, 447 enum vcap_selection sel, 448 u32 start, 449 u32 count) 450 { 451 struct sparx5_port *port = netdev_priv(ndev); 452 struct sparx5 *sparx5 = port->sparx5; 453 u32 *keystr, *mskstr, *actstr; 454 int idx; 455 456 keystr = &admin->cache.keystream[start]; 457 mskstr = &admin->cache.maskstream[start]; 458 actstr = &admin->cache.actionstream[start]; 459 if (sel & VCAP_SEL_ENTRY) { 460 for (idx = 0; idx < count; ++idx) { 461 keystr[idx] = spx5_rd(sparx5, 462 VCAP_SUPER_VCAP_ENTRY_DAT(idx)); 463 mskstr[idx] = ~spx5_rd(sparx5, 464 VCAP_SUPER_VCAP_MASK_DAT(idx)); 465 } 466 } 467 if (sel & VCAP_SEL_ACTION) { 468 for (idx = 0; idx < count; ++idx) 469 actstr[idx] = spx5_rd(sparx5, 470 VCAP_SUPER_VCAP_ACTION_DAT(idx)); 471 } 472 if (sel & VCAP_SEL_COUNTER) { 473 start = start & 0xfff; /* counter limit */ 474 if (admin->vinst == 0) 475 admin->cache.counter = 476 spx5_rd(sparx5, ANA_ACL_CNT_A(start)); 477 else 478 admin->cache.counter = 479 spx5_rd(sparx5, ANA_ACL_CNT_B(start)); 480 admin->cache.sticky = 481 spx5_rd(sparx5, VCAP_SUPER_VCAP_CNT_DAT(0)); 482 } 483 } 484 485 /* API callback used for initializing a VCAP address range */ 486 static void sparx5_vcap_range_init(struct net_device *ndev, 487 struct vcap_admin *admin, u32 addr, 488 u32 count) 489 { 490 struct sparx5_port *port = netdev_priv(ndev); 491 struct sparx5 *sparx5 = port->sparx5; 492 493 _sparx5_vcap_range_init(sparx5, admin, addr, count); 494 } 495 496 /* API callback used for updating the VCAP cache */ 497 static void sparx5_vcap_update(struct net_device *ndev, 498 struct vcap_admin *admin, enum vcap_command cmd, 499 enum vcap_selection sel, u32 addr) 500 { 501 struct sparx5_port *port = netdev_priv(ndev); 502 struct sparx5 *sparx5 = port->sparx5; 503 bool clear; 504 505 clear = (cmd == VCAP_CMD_INITIALIZE); 506 spx5_wr(VCAP_SUPER_CFG_MV_NUM_POS_SET(0) | 507 VCAP_SUPER_CFG_MV_SIZE_SET(0), sparx5, VCAP_SUPER_CFG); 508 spx5_wr(VCAP_SUPER_CTRL_UPDATE_CMD_SET(cmd) | 509 VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET((VCAP_SEL_ENTRY & sel) == 0) | 510 VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET((VCAP_SEL_ACTION & sel) == 0) | 511 VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET((VCAP_SEL_COUNTER & sel) == 0) | 512 VCAP_SUPER_CTRL_UPDATE_ADDR_SET(addr) | 513 VCAP_SUPER_CTRL_CLEAR_CACHE_SET(clear) | 514 VCAP_SUPER_CTRL_UPDATE_SHOT_SET(true), 515 sparx5, VCAP_SUPER_CTRL); 516 sparx5_vcap_wait_super_update(sparx5); 517 } 518 519 /* API callback used for moving a block of rules in the VCAP */ 520 static void sparx5_vcap_move(struct net_device *ndev, struct vcap_admin *admin, 521 u32 addr, int offset, int count) 522 { 523 struct sparx5_port *port = netdev_priv(ndev); 524 struct sparx5 *sparx5 = port->sparx5; 525 enum vcap_command cmd; 526 u16 mv_num_pos; 527 u16 mv_size; 528 529 mv_size = count - 1; 530 if (offset > 0) { 531 mv_num_pos = offset - 1; 532 cmd = VCAP_CMD_MOVE_DOWN; 533 } else { 534 mv_num_pos = -offset - 1; 535 cmd = VCAP_CMD_MOVE_UP; 536 } 537 spx5_wr(VCAP_SUPER_CFG_MV_NUM_POS_SET(mv_num_pos) | 538 VCAP_SUPER_CFG_MV_SIZE_SET(mv_size), 539 sparx5, VCAP_SUPER_CFG); 540 spx5_wr(VCAP_SUPER_CTRL_UPDATE_CMD_SET(cmd) | 541 VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET(0) | 542 VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET(0) | 543 VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET(0) | 544 VCAP_SUPER_CTRL_UPDATE_ADDR_SET(addr) | 545 VCAP_SUPER_CTRL_CLEAR_CACHE_SET(false) | 546 VCAP_SUPER_CTRL_UPDATE_SHOT_SET(true), 547 sparx5, VCAP_SUPER_CTRL); 548 sparx5_vcap_wait_super_update(sparx5); 549 } 550 551 /* Provide port information via a callback interface */ 552 static int sparx5_port_info(struct net_device *ndev, enum vcap_type vtype, 553 int (*pf)(void *out, int arg, const char *fmt, ...), 554 void *out, int arg) 555 { 556 /* this will be added later */ 557 return 0; 558 } 559 560 /* Enable all lookups in the VCAP instance */ 561 static int sparx5_vcap_enable(struct net_device *ndev, 562 struct vcap_admin *admin, 563 bool enable) 564 { 565 struct sparx5_port *port = netdev_priv(ndev); 566 struct sparx5 *sparx5; 567 int portno; 568 569 sparx5 = port->sparx5; 570 portno = port->portno; 571 572 /* For now we only consider IS2 */ 573 if (enable) 574 spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf), sparx5, 575 ANA_ACL_VCAP_S2_CFG(portno)); 576 else 577 spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0), sparx5, 578 ANA_ACL_VCAP_S2_CFG(portno)); 579 return 0; 580 } 581 582 /* API callback operations: only IS2 is supported for now */ 583 static struct vcap_operations sparx5_vcap_ops = { 584 .validate_keyset = sparx5_vcap_validate_keyset, 585 .add_default_fields = sparx5_vcap_add_default_fields, 586 .cache_erase = sparx5_vcap_cache_erase, 587 .cache_write = sparx5_vcap_cache_write, 588 .cache_read = sparx5_vcap_cache_read, 589 .init = sparx5_vcap_range_init, 590 .update = sparx5_vcap_update, 591 .move = sparx5_vcap_move, 592 .port_info = sparx5_port_info, 593 .enable = sparx5_vcap_enable, 594 }; 595 596 /* Enable lookups per port and set the keyset generation: only IS2 for now */ 597 static void sparx5_vcap_port_key_selection(struct sparx5 *sparx5, 598 struct vcap_admin *admin) 599 { 600 int portno, lookup; 601 u32 keysel; 602 603 /* all traffic types generate the MAC_ETYPE keyset for now in all 604 * lookups on all ports 605 */ 606 keysel = VCAP_IS2_KEYSEL(true, VCAP_IS2_PS_NONETH_MAC_ETYPE, 607 VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER, 608 VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER, 609 VCAP_IS2_PS_IPV6_MC_IP_7TUPLE, 610 VCAP_IS2_PS_IPV6_UC_IP_7TUPLE, 611 VCAP_IS2_PS_ARP_ARP); 612 for (lookup = 0; lookup < admin->lookups; ++lookup) { 613 for (portno = 0; portno < SPX5_PORTS; ++portno) { 614 spx5_wr(keysel, sparx5, 615 ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup)); 616 } 617 } 618 } 619 620 /* Disable lookups per port and set the keyset generation: only IS2 for now */ 621 static void sparx5_vcap_port_key_deselection(struct sparx5 *sparx5, 622 struct vcap_admin *admin) 623 { 624 int portno; 625 626 for (portno = 0; portno < SPX5_PORTS; ++portno) 627 spx5_rmw(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0), 628 ANA_ACL_VCAP_S2_CFG_SEC_ENA, 629 sparx5, 630 ANA_ACL_VCAP_S2_CFG(portno)); 631 } 632 633 static void sparx5_vcap_admin_free(struct vcap_admin *admin) 634 { 635 if (!admin) 636 return; 637 kfree(admin->cache.keystream); 638 kfree(admin->cache.maskstream); 639 kfree(admin->cache.actionstream); 640 kfree(admin); 641 } 642 643 /* Allocate a vcap instance with a rule list and a cache area */ 644 static struct vcap_admin * 645 sparx5_vcap_admin_alloc(struct sparx5 *sparx5, struct vcap_control *ctrl, 646 const struct sparx5_vcap_inst *cfg) 647 { 648 struct vcap_admin *admin; 649 650 admin = kzalloc(sizeof(*admin), GFP_KERNEL); 651 if (!admin) 652 return ERR_PTR(-ENOMEM); 653 INIT_LIST_HEAD(&admin->list); 654 INIT_LIST_HEAD(&admin->rules); 655 INIT_LIST_HEAD(&admin->enabled); 656 admin->vtype = cfg->vtype; 657 admin->vinst = cfg->vinst; 658 admin->lookups = cfg->lookups; 659 admin->lookups_per_instance = cfg->lookups_per_instance; 660 admin->first_cid = cfg->first_cid; 661 admin->last_cid = cfg->last_cid; 662 admin->cache.keystream = 663 kzalloc(STREAMSIZE, GFP_KERNEL); 664 admin->cache.maskstream = 665 kzalloc(STREAMSIZE, GFP_KERNEL); 666 admin->cache.actionstream = 667 kzalloc(STREAMSIZE, GFP_KERNEL); 668 if (!admin->cache.keystream || !admin->cache.maskstream || 669 !admin->cache.actionstream) { 670 sparx5_vcap_admin_free(admin); 671 return ERR_PTR(-ENOMEM); 672 } 673 return admin; 674 } 675 676 /* Do block allocations and provide addresses for VCAP instances */ 677 static void sparx5_vcap_block_alloc(struct sparx5 *sparx5, 678 struct vcap_admin *admin, 679 const struct sparx5_vcap_inst *cfg) 680 { 681 int idx; 682 683 /* Super VCAP block mapping and address configuration. Block 0 684 * is assigned addresses 0 through 3071, block 1 is assigned 685 * addresses 3072 though 6143, and so on. 686 */ 687 for (idx = cfg->blockno; idx < cfg->blockno + cfg->blocks; ++idx) { 688 spx5_wr(VCAP_SUPER_IDX_CORE_IDX_SET(idx), sparx5, 689 VCAP_SUPER_IDX); 690 spx5_wr(VCAP_SUPER_MAP_CORE_MAP_SET(cfg->map_id), sparx5, 691 VCAP_SUPER_MAP); 692 } 693 admin->first_valid_addr = cfg->blockno * SUPER_VCAP_BLK_SIZE; 694 admin->last_used_addr = admin->first_valid_addr + 695 cfg->blocks * SUPER_VCAP_BLK_SIZE; 696 admin->last_valid_addr = admin->last_used_addr - 1; 697 } 698 699 /* Allocate a vcap control and vcap instances and configure the system */ 700 int sparx5_vcap_init(struct sparx5 *sparx5) 701 { 702 const struct sparx5_vcap_inst *cfg; 703 struct vcap_control *ctrl; 704 struct vcap_admin *admin; 705 int err = 0, idx; 706 707 /* Create a VCAP control instance that owns the platform specific VCAP 708 * model with VCAP instances and information about keysets, keys, 709 * actionsets and actions 710 * - Create administrative state for each available VCAP 711 * - Lists of rules 712 * - Address information 713 * - Initialize VCAP blocks 714 * - Configure port keysets 715 */ 716 ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); 717 if (!ctrl) 718 return -ENOMEM; 719 720 sparx5->vcap_ctrl = ctrl; 721 /* select the sparx5 VCAP model */ 722 ctrl->vcaps = sparx5_vcaps; 723 ctrl->stats = &sparx5_vcap_stats; 724 /* Setup callbacks to allow the API to use the VCAP HW */ 725 ctrl->ops = &sparx5_vcap_ops; 726 727 INIT_LIST_HEAD(&ctrl->list); 728 for (idx = 0; idx < ARRAY_SIZE(sparx5_vcap_inst_cfg); ++idx) { 729 cfg = &sparx5_vcap_inst_cfg[idx]; 730 admin = sparx5_vcap_admin_alloc(sparx5, ctrl, cfg); 731 if (IS_ERR(admin)) { 732 err = PTR_ERR(admin); 733 pr_err("%s:%d: vcap allocation failed: %d\n", 734 __func__, __LINE__, err); 735 return err; 736 } 737 sparx5_vcap_block_alloc(sparx5, admin, cfg); 738 sparx5_vcap_block_init(sparx5, admin); 739 if (cfg->vinst == 0) 740 sparx5_vcap_port_key_selection(sparx5, admin); 741 list_add_tail(&admin->list, &ctrl->list); 742 } 743 744 return err; 745 } 746 747 void sparx5_vcap_destroy(struct sparx5 *sparx5) 748 { 749 struct vcap_control *ctrl = sparx5->vcap_ctrl; 750 struct vcap_admin *admin, *admin_next; 751 752 if (!ctrl) 753 return; 754 755 list_for_each_entry_safe(admin, admin_next, &ctrl->list, list) { 756 sparx5_vcap_port_key_deselection(sparx5, admin); 757 vcap_del_rules(ctrl, admin); 758 list_del(&admin->list); 759 sparx5_vcap_admin_free(admin); 760 } 761 kfree(ctrl); 762 } 763