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 } 432 433 /* API callback used for reading from the VCAP into the VCAP cache */ 434 static void sparx5_vcap_cache_read(struct net_device *ndev, 435 struct vcap_admin *admin, 436 enum vcap_selection sel, u32 start, 437 u32 count) 438 { 439 /* this will be added later */ 440 } 441 442 /* API callback used for initializing a VCAP address range */ 443 static void sparx5_vcap_range_init(struct net_device *ndev, 444 struct vcap_admin *admin, u32 addr, 445 u32 count) 446 { 447 struct sparx5_port *port = netdev_priv(ndev); 448 struct sparx5 *sparx5 = port->sparx5; 449 450 _sparx5_vcap_range_init(sparx5, admin, addr, count); 451 } 452 453 /* API callback used for updating the VCAP cache */ 454 static void sparx5_vcap_update(struct net_device *ndev, 455 struct vcap_admin *admin, enum vcap_command cmd, 456 enum vcap_selection sel, u32 addr) 457 { 458 struct sparx5_port *port = netdev_priv(ndev); 459 struct sparx5 *sparx5 = port->sparx5; 460 bool clear; 461 462 clear = (cmd == VCAP_CMD_INITIALIZE); 463 spx5_wr(VCAP_SUPER_CFG_MV_NUM_POS_SET(0) | 464 VCAP_SUPER_CFG_MV_SIZE_SET(0), sparx5, VCAP_SUPER_CFG); 465 spx5_wr(VCAP_SUPER_CTRL_UPDATE_CMD_SET(cmd) | 466 VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET((VCAP_SEL_ENTRY & sel) == 0) | 467 VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET((VCAP_SEL_ACTION & sel) == 0) | 468 VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET((VCAP_SEL_COUNTER & sel) == 0) | 469 VCAP_SUPER_CTRL_UPDATE_ADDR_SET(addr) | 470 VCAP_SUPER_CTRL_CLEAR_CACHE_SET(clear) | 471 VCAP_SUPER_CTRL_UPDATE_SHOT_SET(true), 472 sparx5, VCAP_SUPER_CTRL); 473 sparx5_vcap_wait_super_update(sparx5); 474 } 475 476 /* API callback used for moving a block of rules in the VCAP */ 477 static void sparx5_vcap_move(struct net_device *ndev, struct vcap_admin *admin, 478 u32 addr, int offset, int count) 479 { 480 /* this will be added later */ 481 } 482 483 /* Provide port information via a callback interface */ 484 static int sparx5_port_info(struct net_device *ndev, enum vcap_type vtype, 485 int (*pf)(void *out, int arg, const char *fmt, ...), 486 void *out, int arg) 487 { 488 /* this will be added later */ 489 return 0; 490 } 491 492 /* Enable all lookups in the VCAP instance */ 493 static int sparx5_vcap_enable(struct net_device *ndev, 494 struct vcap_admin *admin, 495 bool enable) 496 { 497 struct sparx5_port *port = netdev_priv(ndev); 498 struct sparx5 *sparx5; 499 int portno; 500 501 sparx5 = port->sparx5; 502 portno = port->portno; 503 504 /* For now we only consider IS2 */ 505 if (enable) 506 spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf), sparx5, 507 ANA_ACL_VCAP_S2_CFG(portno)); 508 else 509 spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0), sparx5, 510 ANA_ACL_VCAP_S2_CFG(portno)); 511 return 0; 512 } 513 514 /* API callback operations: only IS2 is supported for now */ 515 static struct vcap_operations sparx5_vcap_ops = { 516 .validate_keyset = sparx5_vcap_validate_keyset, 517 .add_default_fields = sparx5_vcap_add_default_fields, 518 .cache_erase = sparx5_vcap_cache_erase, 519 .cache_write = sparx5_vcap_cache_write, 520 .cache_read = sparx5_vcap_cache_read, 521 .init = sparx5_vcap_range_init, 522 .update = sparx5_vcap_update, 523 .move = sparx5_vcap_move, 524 .port_info = sparx5_port_info, 525 .enable = sparx5_vcap_enable, 526 }; 527 528 /* Enable lookups per port and set the keyset generation: only IS2 for now */ 529 static void sparx5_vcap_port_key_selection(struct sparx5 *sparx5, 530 struct vcap_admin *admin) 531 { 532 int portno, lookup; 533 u32 keysel; 534 535 /* all traffic types generate the MAC_ETYPE keyset for now in all 536 * lookups on all ports 537 */ 538 keysel = VCAP_IS2_KEYSEL(true, VCAP_IS2_PS_NONETH_MAC_ETYPE, 539 VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER, 540 VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER, 541 VCAP_IS2_PS_IPV6_MC_IP_7TUPLE, 542 VCAP_IS2_PS_IPV6_UC_IP_7TUPLE, 543 VCAP_IS2_PS_ARP_MAC_ETYPE); 544 for (lookup = 0; lookup < admin->lookups; ++lookup) { 545 for (portno = 0; portno < SPX5_PORTS; ++portno) { 546 spx5_wr(keysel, sparx5, 547 ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup)); 548 } 549 } 550 } 551 552 /* Disable lookups per port and set the keyset generation: only IS2 for now */ 553 static void sparx5_vcap_port_key_deselection(struct sparx5 *sparx5, 554 struct vcap_admin *admin) 555 { 556 int portno; 557 558 for (portno = 0; portno < SPX5_PORTS; ++portno) 559 spx5_rmw(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0), 560 ANA_ACL_VCAP_S2_CFG_SEC_ENA, 561 sparx5, 562 ANA_ACL_VCAP_S2_CFG(portno)); 563 } 564 565 static void sparx5_vcap_admin_free(struct vcap_admin *admin) 566 { 567 if (!admin) 568 return; 569 kfree(admin->cache.keystream); 570 kfree(admin->cache.maskstream); 571 kfree(admin->cache.actionstream); 572 kfree(admin); 573 } 574 575 /* Allocate a vcap instance with a rule list and a cache area */ 576 static struct vcap_admin * 577 sparx5_vcap_admin_alloc(struct sparx5 *sparx5, struct vcap_control *ctrl, 578 const struct sparx5_vcap_inst *cfg) 579 { 580 struct vcap_admin *admin; 581 582 admin = kzalloc(sizeof(*admin), GFP_KERNEL); 583 if (!admin) 584 return ERR_PTR(-ENOMEM); 585 INIT_LIST_HEAD(&admin->list); 586 INIT_LIST_HEAD(&admin->rules); 587 INIT_LIST_HEAD(&admin->enabled); 588 admin->vtype = cfg->vtype; 589 admin->vinst = cfg->vinst; 590 admin->lookups = cfg->lookups; 591 admin->lookups_per_instance = cfg->lookups_per_instance; 592 admin->first_cid = cfg->first_cid; 593 admin->last_cid = cfg->last_cid; 594 admin->cache.keystream = 595 kzalloc(STREAMSIZE, GFP_KERNEL); 596 admin->cache.maskstream = 597 kzalloc(STREAMSIZE, GFP_KERNEL); 598 admin->cache.actionstream = 599 kzalloc(STREAMSIZE, GFP_KERNEL); 600 if (!admin->cache.keystream || !admin->cache.maskstream || 601 !admin->cache.actionstream) { 602 sparx5_vcap_admin_free(admin); 603 return ERR_PTR(-ENOMEM); 604 } 605 return admin; 606 } 607 608 /* Do block allocations and provide addresses for VCAP instances */ 609 static void sparx5_vcap_block_alloc(struct sparx5 *sparx5, 610 struct vcap_admin *admin, 611 const struct sparx5_vcap_inst *cfg) 612 { 613 int idx; 614 615 /* Super VCAP block mapping and address configuration. Block 0 616 * is assigned addresses 0 through 3071, block 1 is assigned 617 * addresses 3072 though 6143, and so on. 618 */ 619 for (idx = cfg->blockno; idx < cfg->blockno + cfg->blocks; ++idx) { 620 spx5_wr(VCAP_SUPER_IDX_CORE_IDX_SET(idx), sparx5, 621 VCAP_SUPER_IDX); 622 spx5_wr(VCAP_SUPER_MAP_CORE_MAP_SET(cfg->map_id), sparx5, 623 VCAP_SUPER_MAP); 624 } 625 admin->first_valid_addr = cfg->blockno * SUPER_VCAP_BLK_SIZE; 626 admin->last_used_addr = admin->first_valid_addr + 627 cfg->blocks * SUPER_VCAP_BLK_SIZE; 628 admin->last_valid_addr = admin->last_used_addr - 1; 629 } 630 631 /* Allocate a vcap control and vcap instances and configure the system */ 632 int sparx5_vcap_init(struct sparx5 *sparx5) 633 { 634 const struct sparx5_vcap_inst *cfg; 635 struct vcap_control *ctrl; 636 struct vcap_admin *admin; 637 int err = 0, idx; 638 639 /* Create a VCAP control instance that owns the platform specific VCAP 640 * model with VCAP instances and information about keysets, keys, 641 * actionsets and actions 642 * - Create administrative state for each available VCAP 643 * - Lists of rules 644 * - Address information 645 * - Initialize VCAP blocks 646 * - Configure port keysets 647 */ 648 ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL); 649 if (!ctrl) 650 return -ENOMEM; 651 652 sparx5->vcap_ctrl = ctrl; 653 /* select the sparx5 VCAP model */ 654 ctrl->vcaps = sparx5_vcaps; 655 ctrl->stats = &sparx5_vcap_stats; 656 /* Setup callbacks to allow the API to use the VCAP HW */ 657 ctrl->ops = &sparx5_vcap_ops; 658 659 INIT_LIST_HEAD(&ctrl->list); 660 for (idx = 0; idx < ARRAY_SIZE(sparx5_vcap_inst_cfg); ++idx) { 661 cfg = &sparx5_vcap_inst_cfg[idx]; 662 admin = sparx5_vcap_admin_alloc(sparx5, ctrl, cfg); 663 if (IS_ERR(admin)) { 664 err = PTR_ERR(admin); 665 pr_err("%s:%d: vcap allocation failed: %d\n", 666 __func__, __LINE__, err); 667 return err; 668 } 669 sparx5_vcap_block_alloc(sparx5, admin, cfg); 670 sparx5_vcap_block_init(sparx5, admin); 671 if (cfg->vinst == 0) 672 sparx5_vcap_port_key_selection(sparx5, admin); 673 list_add_tail(&admin->list, &ctrl->list); 674 } 675 676 return err; 677 } 678 679 void sparx5_vcap_destroy(struct sparx5 *sparx5) 680 { 681 struct vcap_control *ctrl = sparx5->vcap_ctrl; 682 struct vcap_admin *admin, *admin_next; 683 684 if (!ctrl) 685 return; 686 687 list_for_each_entry_safe(admin, admin_next, &ctrl->list, list) { 688 sparx5_vcap_port_key_deselection(sparx5, admin); 689 vcap_del_rules(ctrl, admin); 690 list_del(&admin->list); 691 sparx5_vcap_admin_free(admin); 692 } 693 kfree(ctrl); 694 } 695