2112 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/* Microchip Sparx5 Switch driver VCAP implementation3 *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_reginfo8 */9 10#include "vcap_api_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#include "sparx5_vcap_debugfs.h"16 17#define SUPER_VCAP_BLK_SIZE 3072 /* addresses per Super VCAP block */18#define STREAMSIZE (64 * 4) /* bytes in the VCAP cache area */19 20#define SPARX5_IS2_LOOKUPS 421#define VCAP_IS2_KEYSEL(_ena, _noneth, _v4_mc, _v4_uc, _v6_mc, _v6_uc, _arp) \22 (ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_SET(_ena) | \23 ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_SET(_noneth) | \24 ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_SET(_v4_mc) | \25 ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_SET(_v4_uc) | \26 ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_SET(_v6_mc) | \27 ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_SET(_v6_uc) | \28 ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_SET(_arp))29 30#define SPARX5_IS0_LOOKUPS 631#define VCAP_IS0_KEYSEL(_ena, _etype, _ipv4, _ipv6, _mpls_uc, _mpls_mc, _mlbs) \32 (ANA_CL_ADV_CL_CFG_LOOKUP_ENA_SET(_ena) | \33 ANA_CL_ADV_CL_CFG_ETYPE_CLM_KEY_SEL_SET(_etype) | \34 ANA_CL_ADV_CL_CFG_IP4_CLM_KEY_SEL_SET(_ipv4) | \35 ANA_CL_ADV_CL_CFG_IP6_CLM_KEY_SEL_SET(_ipv6) | \36 ANA_CL_ADV_CL_CFG_MPLS_UC_CLM_KEY_SEL_SET(_mpls_uc) | \37 ANA_CL_ADV_CL_CFG_MPLS_MC_CLM_KEY_SEL_SET(_mpls_mc) | \38 ANA_CL_ADV_CL_CFG_MLBS_CLM_KEY_SEL_SET(_mlbs))39 40#define SPARX5_ES0_LOOKUPS 141#define VCAP_ES0_KEYSEL(_key) (REW_RTAG_ETAG_CTRL_ES0_ISDX_KEY_ENA_SET(_key))42#define SPARX5_STAT_ESDX_GRN_PKTS 0x30043#define SPARX5_STAT_ESDX_YEL_PKTS 0x30144 45#define SPARX5_ES2_LOOKUPS 246#define VCAP_ES2_KEYSEL(_ena, _arp, _ipv4, _ipv6) \47 (EACL_VCAP_ES2_KEY_SEL_KEY_ENA_SET(_ena) | \48 EACL_VCAP_ES2_KEY_SEL_ARP_KEY_SEL_SET(_arp) | \49 EACL_VCAP_ES2_KEY_SEL_IP4_KEY_SEL_SET(_ipv4) | \50 EACL_VCAP_ES2_KEY_SEL_IP6_KEY_SEL_SET(_ipv6))51 52static struct sparx5_vcap_inst {53 enum vcap_type vtype; /* type of vcap */54 int vinst; /* instance number within the same type */55 int lookups; /* number of lookups in this vcap type */56 int lookups_per_instance; /* number of lookups in this instance */57 int first_cid; /* first chain id in this vcap */58 int last_cid; /* last chain id in this vcap */59 int count; /* number of available addresses, not in super vcap */60 int map_id; /* id in the super vcap block mapping (if applicable) */61 int blockno; /* starting block in super vcap (if applicable) */62 int blocks; /* number of blocks in super vcap (if applicable) */63 bool ingress; /* is vcap in the ingress path */64} sparx5_vcap_inst_cfg[] = {65 {66 .vtype = VCAP_TYPE_IS0, /* CLM-0 */67 .vinst = 0,68 .map_id = 1,69 .lookups = SPARX5_IS0_LOOKUPS,70 .lookups_per_instance = SPARX5_IS0_LOOKUPS / 3,71 .first_cid = SPARX5_VCAP_CID_IS0_L0,72 .last_cid = SPARX5_VCAP_CID_IS0_L2 - 1,73 .blockno = 8, /* Maps block 8-9 */74 .blocks = 2,75 .ingress = true,76 },77 {78 .vtype = VCAP_TYPE_IS0, /* CLM-1 */79 .vinst = 1,80 .map_id = 2,81 .lookups = SPARX5_IS0_LOOKUPS,82 .lookups_per_instance = SPARX5_IS0_LOOKUPS / 3,83 .first_cid = SPARX5_VCAP_CID_IS0_L2,84 .last_cid = SPARX5_VCAP_CID_IS0_L4 - 1,85 .blockno = 6, /* Maps block 6-7 */86 .blocks = 2,87 .ingress = true,88 },89 {90 .vtype = VCAP_TYPE_IS0, /* CLM-2 */91 .vinst = 2,92 .map_id = 3,93 .lookups = SPARX5_IS0_LOOKUPS,94 .lookups_per_instance = SPARX5_IS0_LOOKUPS / 3,95 .first_cid = SPARX5_VCAP_CID_IS0_L4,96 .last_cid = SPARX5_VCAP_CID_IS0_MAX,97 .blockno = 4, /* Maps block 4-5 */98 .blocks = 2,99 .ingress = true,100 },101 {102 .vtype = VCAP_TYPE_IS2, /* IS2-0 */103 .vinst = 0,104 .map_id = 4,105 .lookups = SPARX5_IS2_LOOKUPS,106 .lookups_per_instance = SPARX5_IS2_LOOKUPS / 2,107 .first_cid = SPARX5_VCAP_CID_IS2_L0,108 .last_cid = SPARX5_VCAP_CID_IS2_L2 - 1,109 .blockno = 0, /* Maps block 0-1 */110 .blocks = 2,111 .ingress = true,112 },113 {114 .vtype = VCAP_TYPE_IS2, /* IS2-1 */115 .vinst = 1,116 .map_id = 5,117 .lookups = SPARX5_IS2_LOOKUPS,118 .lookups_per_instance = SPARX5_IS2_LOOKUPS / 2,119 .first_cid = SPARX5_VCAP_CID_IS2_L2,120 .last_cid = SPARX5_VCAP_CID_IS2_MAX,121 .blockno = 2, /* Maps block 2-3 */122 .blocks = 2,123 .ingress = true,124 },125 {126 .vtype = VCAP_TYPE_ES0,127 .lookups = SPARX5_ES0_LOOKUPS,128 .lookups_per_instance = SPARX5_ES0_LOOKUPS,129 .first_cid = SPARX5_VCAP_CID_ES0_L0,130 .last_cid = SPARX5_VCAP_CID_ES0_MAX,131 .count = 4096, /* Addresses according to datasheet */132 .ingress = false,133 },134 {135 .vtype = VCAP_TYPE_ES2,136 .lookups = SPARX5_ES2_LOOKUPS,137 .lookups_per_instance = SPARX5_ES2_LOOKUPS,138 .first_cid = SPARX5_VCAP_CID_ES2_L0,139 .last_cid = SPARX5_VCAP_CID_ES2_MAX,140 .count = 12288, /* Addresses according to datasheet */141 .ingress = false,142 },143};144 145/* These protocols have dedicated keysets in IS0 and a TC dissector */146static u16 sparx5_vcap_is0_known_etypes[] = {147 ETH_P_ALL,148 ETH_P_IP,149 ETH_P_IPV6,150};151 152/* These protocols have dedicated keysets in IS2 and a TC dissector */153static u16 sparx5_vcap_is2_known_etypes[] = {154 ETH_P_ALL,155 ETH_P_ARP,156 ETH_P_IP,157 ETH_P_IPV6,158};159 160/* These protocols have dedicated keysets in ES2 and a TC dissector */161static u16 sparx5_vcap_es2_known_etypes[] = {162 ETH_P_ALL,163 ETH_P_ARP,164 ETH_P_IP,165 ETH_P_IPV6,166};167 168static void sparx5_vcap_type_err(struct sparx5 *sparx5,169 struct vcap_admin *admin,170 const char *fname)171{172 pr_err("%s: vcap type: %s not supported\n",173 fname, sparx5_vcaps[admin->vtype].name);174}175 176/* Await the super VCAP completion of the current operation */177static void sparx5_vcap_wait_super_update(struct sparx5 *sparx5)178{179 u32 value;180 181 read_poll_timeout(spx5_rd, value,182 !VCAP_SUPER_CTRL_UPDATE_SHOT_GET(value), 500, 10000,183 false, sparx5, VCAP_SUPER_CTRL);184}185 186/* Await the ES0 VCAP completion of the current operation */187static void sparx5_vcap_wait_es0_update(struct sparx5 *sparx5)188{189 u32 value;190 191 read_poll_timeout(spx5_rd, value,192 !VCAP_ES0_CTRL_UPDATE_SHOT_GET(value), 500, 10000,193 false, sparx5, VCAP_ES0_CTRL);194}195 196/* Await the ES2 VCAP completion of the current operation */197static void sparx5_vcap_wait_es2_update(struct sparx5 *sparx5)198{199 u32 value;200 201 read_poll_timeout(spx5_rd, value,202 !VCAP_ES2_CTRL_UPDATE_SHOT_GET(value), 500, 10000,203 false, sparx5, VCAP_ES2_CTRL);204}205 206/* Initializing a VCAP address range */207static void _sparx5_vcap_range_init(struct sparx5 *sparx5,208 struct vcap_admin *admin,209 u32 addr, u32 count)210{211 u32 size = count - 1;212 213 switch (admin->vtype) {214 case VCAP_TYPE_IS0:215 case VCAP_TYPE_IS2:216 spx5_wr(VCAP_SUPER_CFG_MV_NUM_POS_SET(0) |217 VCAP_SUPER_CFG_MV_SIZE_SET(size),218 sparx5, VCAP_SUPER_CFG);219 spx5_wr(VCAP_SUPER_CTRL_UPDATE_CMD_SET(VCAP_CMD_INITIALIZE) |220 VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET(0) |221 VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET(0) |222 VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET(0) |223 VCAP_SUPER_CTRL_UPDATE_ADDR_SET(addr) |224 VCAP_SUPER_CTRL_CLEAR_CACHE_SET(true) |225 VCAP_SUPER_CTRL_UPDATE_SHOT_SET(true),226 sparx5, VCAP_SUPER_CTRL);227 sparx5_vcap_wait_super_update(sparx5);228 break;229 case VCAP_TYPE_ES0:230 spx5_wr(VCAP_ES0_CFG_MV_NUM_POS_SET(0) |231 VCAP_ES0_CFG_MV_SIZE_SET(size),232 sparx5, VCAP_ES0_CFG);233 spx5_wr(VCAP_ES0_CTRL_UPDATE_CMD_SET(VCAP_CMD_INITIALIZE) |234 VCAP_ES0_CTRL_UPDATE_ENTRY_DIS_SET(0) |235 VCAP_ES0_CTRL_UPDATE_ACTION_DIS_SET(0) |236 VCAP_ES0_CTRL_UPDATE_CNT_DIS_SET(0) |237 VCAP_ES0_CTRL_UPDATE_ADDR_SET(addr) |238 VCAP_ES0_CTRL_CLEAR_CACHE_SET(true) |239 VCAP_ES0_CTRL_UPDATE_SHOT_SET(true),240 sparx5, VCAP_ES0_CTRL);241 sparx5_vcap_wait_es0_update(sparx5);242 break;243 case VCAP_TYPE_ES2:244 spx5_wr(VCAP_ES2_CFG_MV_NUM_POS_SET(0) |245 VCAP_ES2_CFG_MV_SIZE_SET(size),246 sparx5, VCAP_ES2_CFG);247 spx5_wr(VCAP_ES2_CTRL_UPDATE_CMD_SET(VCAP_CMD_INITIALIZE) |248 VCAP_ES2_CTRL_UPDATE_ENTRY_DIS_SET(0) |249 VCAP_ES2_CTRL_UPDATE_ACTION_DIS_SET(0) |250 VCAP_ES2_CTRL_UPDATE_CNT_DIS_SET(0) |251 VCAP_ES2_CTRL_UPDATE_ADDR_SET(addr) |252 VCAP_ES2_CTRL_CLEAR_CACHE_SET(true) |253 VCAP_ES2_CTRL_UPDATE_SHOT_SET(true),254 sparx5, VCAP_ES2_CTRL);255 sparx5_vcap_wait_es2_update(sparx5);256 break;257 default:258 sparx5_vcap_type_err(sparx5, admin, __func__);259 break;260 }261}262 263/* Initializing VCAP rule data area */264static void sparx5_vcap_block_init(struct sparx5 *sparx5,265 struct vcap_admin *admin)266{267 _sparx5_vcap_range_init(sparx5, admin, admin->first_valid_addr,268 admin->last_valid_addr -269 admin->first_valid_addr);270}271 272/* Get the keyset name from the sparx5 VCAP model */273static const char *sparx5_vcap_keyset_name(struct net_device *ndev,274 enum vcap_keyfield_set keyset)275{276 struct sparx5_port *port = netdev_priv(ndev);277 278 return vcap_keyset_name(port->sparx5->vcap_ctrl, keyset);279}280 281/* Check if this is the first lookup of IS0 */282static bool sparx5_vcap_is0_is_first_chain(struct vcap_rule *rule)283{284 return (rule->vcap_chain_id >= SPARX5_VCAP_CID_IS0_L0 &&285 rule->vcap_chain_id < SPARX5_VCAP_CID_IS0_L1) ||286 ((rule->vcap_chain_id >= SPARX5_VCAP_CID_IS0_L2 &&287 rule->vcap_chain_id < SPARX5_VCAP_CID_IS0_L3)) ||288 ((rule->vcap_chain_id >= SPARX5_VCAP_CID_IS0_L4 &&289 rule->vcap_chain_id < SPARX5_VCAP_CID_IS0_L5));290}291 292/* Check if this is the first lookup of IS2 */293static bool sparx5_vcap_is2_is_first_chain(struct vcap_rule *rule)294{295 return (rule->vcap_chain_id >= SPARX5_VCAP_CID_IS2_L0 &&296 rule->vcap_chain_id < SPARX5_VCAP_CID_IS2_L1) ||297 ((rule->vcap_chain_id >= SPARX5_VCAP_CID_IS2_L2 &&298 rule->vcap_chain_id < SPARX5_VCAP_CID_IS2_L3));299}300 301static bool sparx5_vcap_es2_is_first_chain(struct vcap_rule *rule)302{303 return (rule->vcap_chain_id >= SPARX5_VCAP_CID_ES2_L0 &&304 rule->vcap_chain_id < SPARX5_VCAP_CID_ES2_L1);305}306 307/* Set the narrow range ingress port mask on a rule */308static void sparx5_vcap_add_ingress_range_port_mask(struct vcap_rule *rule,309 struct net_device *ndev)310{311 struct sparx5_port *port = netdev_priv(ndev);312 u32 port_mask;313 u32 range;314 315 range = port->portno / BITS_PER_TYPE(u32);316 /* Port bit set to match-any */317 port_mask = ~BIT(port->portno % BITS_PER_TYPE(u32));318 vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK_SEL, 0, 0xf);319 vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK_RNG, range, 0xf);320 vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0, port_mask);321}322 323/* Set the wide range ingress port mask on a rule */324static void sparx5_vcap_add_wide_port_mask(struct vcap_rule *rule,325 struct net_device *ndev)326{327 struct sparx5_port *port = netdev_priv(ndev);328 struct vcap_u72_key port_mask;329 u32 range;330 331 /* Port bit set to match-any */332 memset(port_mask.value, 0, sizeof(port_mask.value));333 memset(port_mask.mask, 0xff, sizeof(port_mask.mask));334 range = port->portno / BITS_PER_BYTE;335 port_mask.mask[range] = ~BIT(port->portno % BITS_PER_BYTE);336 vcap_rule_add_key_u72(rule, VCAP_KF_IF_IGR_PORT_MASK, &port_mask);337}338 339static void sparx5_vcap_add_egress_range_port_mask(struct vcap_rule *rule,340 struct net_device *ndev)341{342 struct sparx5_port *port = netdev_priv(ndev);343 u32 port_mask;344 u32 range;345 346 /* Mask range selects:347 * 0-2: Physical/Logical egress port number 0-31, 32–63, 64.348 * 3-5: Virtual Interface Number 0-31, 32-63, 64.349 * 6: CPU queue Number 0-7.350 *351 * Use physical/logical port ranges (0-2)352 */353 range = port->portno / BITS_PER_TYPE(u32);354 /* Port bit set to match-any */355 port_mask = ~BIT(port->portno % BITS_PER_TYPE(u32));356 vcap_rule_add_key_u32(rule, VCAP_KF_IF_EGR_PORT_MASK_RNG, range, 0xf);357 vcap_rule_add_key_u32(rule, VCAP_KF_IF_EGR_PORT_MASK, 0, port_mask);358}359 360/* Convert IS0 chain id to vcap lookup id */361static int sparx5_vcap_is0_cid_to_lookup(int cid)362{363 int lookup = 0;364 365 if (cid >= SPARX5_VCAP_CID_IS0_L1 && cid < SPARX5_VCAP_CID_IS0_L2)366 lookup = 1;367 else if (cid >= SPARX5_VCAP_CID_IS0_L2 && cid < SPARX5_VCAP_CID_IS0_L3)368 lookup = 2;369 else if (cid >= SPARX5_VCAP_CID_IS0_L3 && cid < SPARX5_VCAP_CID_IS0_L4)370 lookup = 3;371 else if (cid >= SPARX5_VCAP_CID_IS0_L4 && cid < SPARX5_VCAP_CID_IS0_L5)372 lookup = 4;373 else if (cid >= SPARX5_VCAP_CID_IS0_L5 && cid < SPARX5_VCAP_CID_IS0_MAX)374 lookup = 5;375 376 return lookup;377}378 379/* Convert IS2 chain id to vcap lookup id */380static int sparx5_vcap_is2_cid_to_lookup(int cid)381{382 int lookup = 0;383 384 if (cid >= SPARX5_VCAP_CID_IS2_L1 && cid < SPARX5_VCAP_CID_IS2_L2)385 lookup = 1;386 else if (cid >= SPARX5_VCAP_CID_IS2_L2 && cid < SPARX5_VCAP_CID_IS2_L3)387 lookup = 2;388 else if (cid >= SPARX5_VCAP_CID_IS2_L3 && cid < SPARX5_VCAP_CID_IS2_MAX)389 lookup = 3;390 391 return lookup;392}393 394/* Convert ES2 chain id to vcap lookup id */395static int sparx5_vcap_es2_cid_to_lookup(int cid)396{397 int lookup = 0;398 399 if (cid >= SPARX5_VCAP_CID_ES2_L1)400 lookup = 1;401 402 return lookup;403}404 405/* Add ethernet type IS0 keyset to a list */406static void407sparx5_vcap_is0_get_port_etype_keysets(struct vcap_keyset_list *keysetlist,408 u32 value)409{410 switch (ANA_CL_ADV_CL_CFG_ETYPE_CLM_KEY_SEL_GET(value)) {411 case VCAP_IS0_PS_ETYPE_NORMAL_7TUPLE:412 vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL_7TUPLE);413 break;414 case VCAP_IS0_PS_ETYPE_NORMAL_5TUPLE_IP4:415 vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL_5TUPLE_IP4);416 break;417 }418}419 420/* Return the list of keysets for the vcap port configuration */421static int sparx5_vcap_is0_get_port_keysets(struct net_device *ndev,422 int lookup,423 struct vcap_keyset_list *keysetlist,424 u16 l3_proto)425{426 struct sparx5_port *port = netdev_priv(ndev);427 struct sparx5 *sparx5 = port->sparx5;428 int portno = port->portno;429 u32 value;430 431 value = spx5_rd(sparx5, ANA_CL_ADV_CL_CFG(portno, lookup));432 433 /* Collect all keysets for the port in a list */434 if (l3_proto == ETH_P_ALL)435 sparx5_vcap_is0_get_port_etype_keysets(keysetlist, value);436 437 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP)438 switch (ANA_CL_ADV_CL_CFG_IP4_CLM_KEY_SEL_GET(value)) {439 case VCAP_IS0_PS_ETYPE_DEFAULT:440 sparx5_vcap_is0_get_port_etype_keysets(keysetlist,441 value);442 break;443 case VCAP_IS0_PS_ETYPE_NORMAL_7TUPLE:444 vcap_keyset_list_add(keysetlist,445 VCAP_KFS_NORMAL_7TUPLE);446 break;447 case VCAP_IS0_PS_ETYPE_NORMAL_5TUPLE_IP4:448 vcap_keyset_list_add(keysetlist,449 VCAP_KFS_NORMAL_5TUPLE_IP4);450 break;451 }452 453 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6)454 switch (ANA_CL_ADV_CL_CFG_IP6_CLM_KEY_SEL_GET(value)) {455 case VCAP_IS0_PS_ETYPE_DEFAULT:456 sparx5_vcap_is0_get_port_etype_keysets(keysetlist,457 value);458 break;459 case VCAP_IS0_PS_ETYPE_NORMAL_7TUPLE:460 vcap_keyset_list_add(keysetlist,461 VCAP_KFS_NORMAL_7TUPLE);462 break;463 case VCAP_IS0_PS_ETYPE_NORMAL_5TUPLE_IP4:464 vcap_keyset_list_add(keysetlist,465 VCAP_KFS_NORMAL_5TUPLE_IP4);466 break;467 }468 469 if (l3_proto != ETH_P_IP && l3_proto != ETH_P_IPV6)470 sparx5_vcap_is0_get_port_etype_keysets(keysetlist, value);471 return 0;472}473 474/* Return the list of keysets for the vcap port configuration */475static int sparx5_vcap_is2_get_port_keysets(struct net_device *ndev,476 int lookup,477 struct vcap_keyset_list *keysetlist,478 u16 l3_proto)479{480 struct sparx5_port *port = netdev_priv(ndev);481 struct sparx5 *sparx5 = port->sparx5;482 int portno = port->portno;483 u32 value;484 485 value = spx5_rd(sparx5, ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup));486 487 /* Collect all keysets for the port in a list */488 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_ARP) {489 switch (ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_GET(value)) {490 case VCAP_IS2_PS_ARP_MAC_ETYPE:491 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);492 break;493 case VCAP_IS2_PS_ARP_ARP:494 vcap_keyset_list_add(keysetlist, VCAP_KFS_ARP);495 break;496 }497 }498 499 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) {500 switch (ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_GET(value)) {501 case VCAP_IS2_PS_IPV4_UC_MAC_ETYPE:502 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);503 break;504 case VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER:505 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);506 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);507 break;508 case VCAP_IS2_PS_IPV4_UC_IP_7TUPLE:509 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE);510 break;511 }512 513 switch (ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_GET(value)) {514 case VCAP_IS2_PS_IPV4_MC_MAC_ETYPE:515 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);516 break;517 case VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER:518 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);519 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);520 break;521 case VCAP_IS2_PS_IPV4_MC_IP_7TUPLE:522 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE);523 break;524 }525 }526 527 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) {528 switch (ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_GET(value)) {529 case VCAP_IS2_PS_IPV6_UC_MAC_ETYPE:530 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);531 break;532 case VCAP_IS2_PS_IPV6_UC_IP_7TUPLE:533 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE);534 break;535 case VCAP_IS2_PS_IPV6_UC_IP6_STD:536 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD);537 break;538 case VCAP_IS2_PS_IPV6_UC_IP4_TCP_UDP_OTHER:539 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);540 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);541 break;542 }543 544 switch (ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_GET(value)) {545 case VCAP_IS2_PS_IPV6_MC_MAC_ETYPE:546 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);547 break;548 case VCAP_IS2_PS_IPV6_MC_IP_7TUPLE:549 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE);550 break;551 case VCAP_IS2_PS_IPV6_MC_IP6_STD:552 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD);553 break;554 case VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER:555 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);556 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);557 break;558 case VCAP_IS2_PS_IPV6_MC_IP6_VID:559 /* Not used */560 break;561 }562 }563 564 if (l3_proto != ETH_P_ARP && l3_proto != ETH_P_IP &&565 l3_proto != ETH_P_IPV6) {566 switch (ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_GET(value)) {567 case VCAP_IS2_PS_NONETH_MAC_ETYPE:568 /* IS2 non-classified frames generate MAC_ETYPE */569 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);570 break;571 }572 }573 return 0;574}575 576/* Return the keysets for the vcap port IP4 traffic class configuration */577static void578sparx5_vcap_es2_get_port_ipv4_keysets(struct vcap_keyset_list *keysetlist,579 u32 value)580{581 switch (EACL_VCAP_ES2_KEY_SEL_IP4_KEY_SEL_GET(value)) {582 case VCAP_ES2_PS_IPV4_MAC_ETYPE:583 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);584 break;585 case VCAP_ES2_PS_IPV4_IP_7TUPLE:586 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE);587 break;588 case VCAP_ES2_PS_IPV4_IP4_TCP_UDP_VID:589 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);590 break;591 case VCAP_ES2_PS_IPV4_IP4_TCP_UDP_OTHER:592 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);593 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);594 break;595 case VCAP_ES2_PS_IPV4_IP4_VID:596 /* Not used */597 break;598 case VCAP_ES2_PS_IPV4_IP4_OTHER:599 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);600 break;601 }602}603 604/* Return the list of keysets for the vcap port configuration */605static int sparx5_vcap_es0_get_port_keysets(struct net_device *ndev,606 struct vcap_keyset_list *keysetlist,607 u16 l3_proto)608{609 struct sparx5_port *port = netdev_priv(ndev);610 struct sparx5 *sparx5 = port->sparx5;611 int portno = port->portno;612 u32 value;613 614 value = spx5_rd(sparx5, REW_RTAG_ETAG_CTRL(portno));615 616 /* Collect all keysets for the port in a list */617 switch (REW_RTAG_ETAG_CTRL_ES0_ISDX_KEY_ENA_GET(value)) {618 case VCAP_ES0_PS_NORMAL_SELECTION:619 case VCAP_ES0_PS_FORCE_ISDX_LOOKUPS:620 vcap_keyset_list_add(keysetlist, VCAP_KFS_ISDX);621 break;622 default:623 break;624 }625 return 0;626}627 628/* Return the list of keysets for the vcap port configuration */629static int sparx5_vcap_es2_get_port_keysets(struct net_device *ndev,630 int lookup,631 struct vcap_keyset_list *keysetlist,632 u16 l3_proto)633{634 struct sparx5_port *port = netdev_priv(ndev);635 struct sparx5 *sparx5 = port->sparx5;636 int portno = port->portno;637 u32 value;638 639 value = spx5_rd(sparx5, EACL_VCAP_ES2_KEY_SEL(portno, lookup));640 641 /* Collect all keysets for the port in a list */642 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_ARP) {643 switch (EACL_VCAP_ES2_KEY_SEL_ARP_KEY_SEL_GET(value)) {644 case VCAP_ES2_PS_ARP_MAC_ETYPE:645 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);646 break;647 case VCAP_ES2_PS_ARP_ARP:648 vcap_keyset_list_add(keysetlist, VCAP_KFS_ARP);649 break;650 }651 }652 653 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP)654 sparx5_vcap_es2_get_port_ipv4_keysets(keysetlist, value);655 656 if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) {657 switch (EACL_VCAP_ES2_KEY_SEL_IP6_KEY_SEL_GET(value)) {658 case VCAP_ES2_PS_IPV6_MAC_ETYPE:659 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);660 break;661 case VCAP_ES2_PS_IPV6_IP_7TUPLE:662 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE);663 break;664 case VCAP_ES2_PS_IPV6_IP_7TUPLE_VID:665 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE);666 break;667 case VCAP_ES2_PS_IPV6_IP_7TUPLE_STD:668 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE);669 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD);670 break;671 case VCAP_ES2_PS_IPV6_IP6_VID:672 /* Not used */673 break;674 case VCAP_ES2_PS_IPV6_IP6_STD:675 vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD);676 break;677 case VCAP_ES2_PS_IPV6_IP4_DOWNGRADE:678 sparx5_vcap_es2_get_port_ipv4_keysets(keysetlist,679 value);680 break;681 }682 }683 684 if (l3_proto != ETH_P_ARP && l3_proto != ETH_P_IP &&685 l3_proto != ETH_P_IPV6) {686 vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);687 }688 return 0;689}690 691/* Get the port keyset for the vcap lookup */692int sparx5_vcap_get_port_keyset(struct net_device *ndev,693 struct vcap_admin *admin,694 int cid,695 u16 l3_proto,696 struct vcap_keyset_list *kslist)697{698 int lookup, err = -EINVAL;699 struct sparx5_port *port;700 701 switch (admin->vtype) {702 case VCAP_TYPE_IS0:703 lookup = sparx5_vcap_is0_cid_to_lookup(cid);704 err = sparx5_vcap_is0_get_port_keysets(ndev, lookup, kslist,705 l3_proto);706 break;707 case VCAP_TYPE_IS2:708 lookup = sparx5_vcap_is2_cid_to_lookup(cid);709 err = sparx5_vcap_is2_get_port_keysets(ndev, lookup, kslist,710 l3_proto);711 break;712 case VCAP_TYPE_ES0:713 err = sparx5_vcap_es0_get_port_keysets(ndev, kslist, l3_proto);714 break;715 case VCAP_TYPE_ES2:716 lookup = sparx5_vcap_es2_cid_to_lookup(cid);717 err = sparx5_vcap_es2_get_port_keysets(ndev, lookup, kslist,718 l3_proto);719 break;720 default:721 port = netdev_priv(ndev);722 sparx5_vcap_type_err(port->sparx5, admin, __func__);723 break;724 }725 return err;726}727 728/* Check if the ethertype is supported by the vcap port classification */729bool sparx5_vcap_is_known_etype(struct vcap_admin *admin, u16 etype)730{731 const u16 *known_etypes;732 int size, idx;733 734 switch (admin->vtype) {735 case VCAP_TYPE_IS0:736 known_etypes = sparx5_vcap_is0_known_etypes;737 size = ARRAY_SIZE(sparx5_vcap_is0_known_etypes);738 break;739 case VCAP_TYPE_IS2:740 known_etypes = sparx5_vcap_is2_known_etypes;741 size = ARRAY_SIZE(sparx5_vcap_is2_known_etypes);742 break;743 case VCAP_TYPE_ES0:744 return true;745 case VCAP_TYPE_ES2:746 known_etypes = sparx5_vcap_es2_known_etypes;747 size = ARRAY_SIZE(sparx5_vcap_es2_known_etypes);748 break;749 default:750 return false;751 }752 for (idx = 0; idx < size; ++idx)753 if (known_etypes[idx] == etype)754 return true;755 return false;756}757 758/* API callback used for validating a field keyset (check the port keysets) */759static enum vcap_keyfield_set760sparx5_vcap_validate_keyset(struct net_device *ndev,761 struct vcap_admin *admin,762 struct vcap_rule *rule,763 struct vcap_keyset_list *kslist,764 u16 l3_proto)765{766 struct vcap_keyset_list keysetlist = {};767 enum vcap_keyfield_set keysets[10] = {};768 struct sparx5_port *port;769 int idx, jdx, lookup;770 771 if (!kslist || kslist->cnt == 0)772 return VCAP_KFS_NO_VALUE;773 774 keysetlist.max = ARRAY_SIZE(keysets);775 keysetlist.keysets = keysets;776 777 /* Get a list of currently configured keysets in the lookups */778 switch (admin->vtype) {779 case VCAP_TYPE_IS0:780 lookup = sparx5_vcap_is0_cid_to_lookup(rule->vcap_chain_id);781 sparx5_vcap_is0_get_port_keysets(ndev, lookup, &keysetlist,782 l3_proto);783 break;784 case VCAP_TYPE_IS2:785 lookup = sparx5_vcap_is2_cid_to_lookup(rule->vcap_chain_id);786 sparx5_vcap_is2_get_port_keysets(ndev, lookup, &keysetlist,787 l3_proto);788 break;789 case VCAP_TYPE_ES0:790 sparx5_vcap_es0_get_port_keysets(ndev, &keysetlist, l3_proto);791 break;792 case VCAP_TYPE_ES2:793 lookup = sparx5_vcap_es2_cid_to_lookup(rule->vcap_chain_id);794 sparx5_vcap_es2_get_port_keysets(ndev, lookup, &keysetlist,795 l3_proto);796 break;797 default:798 port = netdev_priv(ndev);799 sparx5_vcap_type_err(port->sparx5, admin, __func__);800 break;801 }802 803 /* Check if there is a match and return the match */804 for (idx = 0; idx < kslist->cnt; ++idx)805 for (jdx = 0; jdx < keysetlist.cnt; ++jdx)806 if (kslist->keysets[idx] == keysets[jdx])807 return kslist->keysets[idx];808 809 pr_err("%s:%d: %s not supported in port key selection\n",810 __func__, __LINE__,811 sparx5_vcap_keyset_name(ndev, kslist->keysets[0]));812 813 return -ENOENT;814}815 816static void sparx5_vcap_ingress_add_default_fields(struct net_device *ndev,817 struct vcap_admin *admin,818 struct vcap_rule *rule)819{820 const struct vcap_field *field;821 bool is_first;822 823 /* Add ingress port mask matching the net device */824 field = vcap_lookup_keyfield(rule, VCAP_KF_IF_IGR_PORT_MASK);825 if (field && field->width == SPX5_PORTS)826 sparx5_vcap_add_wide_port_mask(rule, ndev);827 else if (field && field->width == BITS_PER_TYPE(u32))828 sparx5_vcap_add_ingress_range_port_mask(rule, ndev);829 else830 pr_err("%s:%d: %s: could not add an ingress port mask for: %s\n",831 __func__, __LINE__, netdev_name(ndev),832 sparx5_vcap_keyset_name(ndev, rule->keyset));833 834 if (admin->vtype == VCAP_TYPE_IS0)835 is_first = sparx5_vcap_is0_is_first_chain(rule);836 else837 is_first = sparx5_vcap_is2_is_first_chain(rule);838 839 /* Add key that selects the first/second lookup */840 if (is_first)841 vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,842 VCAP_BIT_1);843 else844 vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,845 VCAP_BIT_0);846}847 848static void sparx5_vcap_es0_add_default_fields(struct net_device *ndev,849 struct vcap_admin *admin,850 struct vcap_rule *rule)851{852 struct sparx5_port *port = netdev_priv(ndev);853 854 vcap_rule_add_key_u32(rule, VCAP_KF_IF_EGR_PORT_NO, port->portno, ~0);855 /* Match untagged frames if there was no VLAN key */856 vcap_rule_add_key_u32(rule, VCAP_KF_8021Q_TPID, SPX5_TPID_SEL_UNTAGGED,857 ~0);858}859 860static void sparx5_vcap_es2_add_default_fields(struct net_device *ndev,861 struct vcap_admin *admin,862 struct vcap_rule *rule)863{864 const struct vcap_field *field;865 bool is_first;866 867 /* Add egress port mask matching the net device */868 field = vcap_lookup_keyfield(rule, VCAP_KF_IF_EGR_PORT_MASK);869 if (field)870 sparx5_vcap_add_egress_range_port_mask(rule, ndev);871 872 /* Add key that selects the first/second lookup */873 is_first = sparx5_vcap_es2_is_first_chain(rule);874 875 if (is_first)876 vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,877 VCAP_BIT_1);878 else879 vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,880 VCAP_BIT_0);881}882 883/* API callback used for adding default fields to a rule */884static void sparx5_vcap_add_default_fields(struct net_device *ndev,885 struct vcap_admin *admin,886 struct vcap_rule *rule)887{888 struct sparx5_port *port;889 890 /* add the lookup bit */891 switch (admin->vtype) {892 case VCAP_TYPE_IS0:893 case VCAP_TYPE_IS2:894 sparx5_vcap_ingress_add_default_fields(ndev, admin, rule);895 break;896 case VCAP_TYPE_ES0:897 sparx5_vcap_es0_add_default_fields(ndev, admin, rule);898 break;899 case VCAP_TYPE_ES2:900 sparx5_vcap_es2_add_default_fields(ndev, admin, rule);901 break;902 default:903 port = netdev_priv(ndev);904 sparx5_vcap_type_err(port->sparx5, admin, __func__);905 break;906 }907}908 909/* API callback used for erasing the vcap cache area (not the register area) */910static void sparx5_vcap_cache_erase(struct vcap_admin *admin)911{912 memset(admin->cache.keystream, 0, STREAMSIZE);913 memset(admin->cache.maskstream, 0, STREAMSIZE);914 memset(admin->cache.actionstream, 0, STREAMSIZE);915 memset(&admin->cache.counter, 0, sizeof(admin->cache.counter));916}917 918static void sparx5_vcap_is0_cache_write(struct sparx5 *sparx5,919 struct vcap_admin *admin,920 enum vcap_selection sel,921 u32 start,922 u32 count)923{924 u32 *keystr, *mskstr, *actstr;925 int idx;926 927 keystr = &admin->cache.keystream[start];928 mskstr = &admin->cache.maskstream[start];929 actstr = &admin->cache.actionstream[start];930 931 switch (sel) {932 case VCAP_SEL_ENTRY:933 for (idx = 0; idx < count; ++idx) {934 /* Avoid 'match-off' by setting value & mask */935 spx5_wr(keystr[idx] & mskstr[idx], sparx5,936 VCAP_SUPER_VCAP_ENTRY_DAT(idx));937 spx5_wr(~mskstr[idx], sparx5,938 VCAP_SUPER_VCAP_MASK_DAT(idx));939 }940 break;941 case VCAP_SEL_ACTION:942 for (idx = 0; idx < count; ++idx)943 spx5_wr(actstr[idx], sparx5,944 VCAP_SUPER_VCAP_ACTION_DAT(idx));945 break;946 case VCAP_SEL_ALL:947 pr_err("%s:%d: cannot write all streams at once\n",948 __func__, __LINE__);949 break;950 default:951 break;952 }953 954 if (sel & VCAP_SEL_COUNTER)955 spx5_wr(admin->cache.counter, sparx5,956 VCAP_SUPER_VCAP_CNT_DAT(0));957}958 959static void sparx5_vcap_is2_cache_write(struct sparx5 *sparx5,960 struct vcap_admin *admin,961 enum vcap_selection sel,962 u32 start,963 u32 count)964{965 u32 *keystr, *mskstr, *actstr;966 int idx;967 968 keystr = &admin->cache.keystream[start];969 mskstr = &admin->cache.maskstream[start];970 actstr = &admin->cache.actionstream[start];971 972 switch (sel) {973 case VCAP_SEL_ENTRY:974 for (idx = 0; idx < count; ++idx) {975 /* Avoid 'match-off' by setting value & mask */976 spx5_wr(keystr[idx] & mskstr[idx], sparx5,977 VCAP_SUPER_VCAP_ENTRY_DAT(idx));978 spx5_wr(~mskstr[idx], sparx5,979 VCAP_SUPER_VCAP_MASK_DAT(idx));980 }981 break;982 case VCAP_SEL_ACTION:983 for (idx = 0; idx < count; ++idx)984 spx5_wr(actstr[idx], sparx5,985 VCAP_SUPER_VCAP_ACTION_DAT(idx));986 break;987 case VCAP_SEL_ALL:988 pr_err("%s:%d: cannot write all streams at once\n",989 __func__, __LINE__);990 break;991 default:992 break;993 }994 if (sel & VCAP_SEL_COUNTER) {995 start = start & 0xfff; /* counter limit */996 if (admin->vinst == 0)997 spx5_wr(admin->cache.counter, sparx5,998 ANA_ACL_CNT_A(start));999 else1000 spx5_wr(admin->cache.counter, sparx5,1001 ANA_ACL_CNT_B(start));1002 spx5_wr(admin->cache.sticky, sparx5,1003 VCAP_SUPER_VCAP_CNT_DAT(0));1004 }1005}1006 1007/* Use ESDX counters located in the XQS */1008static void sparx5_es0_write_esdx_counter(struct sparx5 *sparx5,1009 struct vcap_admin *admin, u32 id)1010{1011 mutex_lock(&sparx5->queue_stats_lock);1012 spx5_wr(XQS_STAT_CFG_STAT_VIEW_SET(id), sparx5, XQS_STAT_CFG);1013 spx5_wr(admin->cache.counter, sparx5,1014 XQS_CNT(SPARX5_STAT_ESDX_GRN_PKTS));1015 spx5_wr(0, sparx5, XQS_CNT(SPARX5_STAT_ESDX_YEL_PKTS));1016 mutex_unlock(&sparx5->queue_stats_lock);1017}1018 1019static void sparx5_vcap_es0_cache_write(struct sparx5 *sparx5,1020 struct vcap_admin *admin,1021 enum vcap_selection sel,1022 u32 start,1023 u32 count)1024{1025 u32 *keystr, *mskstr, *actstr;1026 int idx;1027 1028 keystr = &admin->cache.keystream[start];1029 mskstr = &admin->cache.maskstream[start];1030 actstr = &admin->cache.actionstream[start];1031 1032 switch (sel) {1033 case VCAP_SEL_ENTRY:1034 for (idx = 0; idx < count; ++idx) {1035 /* Avoid 'match-off' by setting value & mask */1036 spx5_wr(keystr[idx] & mskstr[idx], sparx5,1037 VCAP_ES0_VCAP_ENTRY_DAT(idx));1038 spx5_wr(~mskstr[idx], sparx5,1039 VCAP_ES0_VCAP_MASK_DAT(idx));1040 }1041 break;1042 case VCAP_SEL_ACTION:1043 for (idx = 0; idx < count; ++idx)1044 spx5_wr(actstr[idx], sparx5,1045 VCAP_ES0_VCAP_ACTION_DAT(idx));1046 break;1047 case VCAP_SEL_ALL:1048 pr_err("%s:%d: cannot write all streams at once\n",1049 __func__, __LINE__);1050 break;1051 default:1052 break;1053 }1054 if (sel & VCAP_SEL_COUNTER) {1055 spx5_wr(admin->cache.counter, sparx5, VCAP_ES0_VCAP_CNT_DAT(0));1056 sparx5_es0_write_esdx_counter(sparx5, admin, start);1057 }1058}1059 1060static void sparx5_vcap_es2_cache_write(struct sparx5 *sparx5,1061 struct vcap_admin *admin,1062 enum vcap_selection sel,1063 u32 start,1064 u32 count)1065{1066 u32 *keystr, *mskstr, *actstr;1067 int idx;1068 1069 keystr = &admin->cache.keystream[start];1070 mskstr = &admin->cache.maskstream[start];1071 actstr = &admin->cache.actionstream[start];1072 1073 switch (sel) {1074 case VCAP_SEL_ENTRY:1075 for (idx = 0; idx < count; ++idx) {1076 /* Avoid 'match-off' by setting value & mask */1077 spx5_wr(keystr[idx] & mskstr[idx], sparx5,1078 VCAP_ES2_VCAP_ENTRY_DAT(idx));1079 spx5_wr(~mskstr[idx], sparx5,1080 VCAP_ES2_VCAP_MASK_DAT(idx));1081 }1082 break;1083 case VCAP_SEL_ACTION:1084 for (idx = 0; idx < count; ++idx)1085 spx5_wr(actstr[idx], sparx5,1086 VCAP_ES2_VCAP_ACTION_DAT(idx));1087 break;1088 case VCAP_SEL_ALL:1089 pr_err("%s:%d: cannot write all streams at once\n",1090 __func__, __LINE__);1091 break;1092 default:1093 break;1094 }1095 if (sel & VCAP_SEL_COUNTER) {1096 start = start & 0x7ff; /* counter limit */1097 spx5_wr(admin->cache.counter, sparx5, EACL_ES2_CNT(start));1098 spx5_wr(admin->cache.sticky, sparx5, VCAP_ES2_VCAP_CNT_DAT(0));1099 }1100}1101 1102/* API callback used for writing to the VCAP cache */1103static void sparx5_vcap_cache_write(struct net_device *ndev,1104 struct vcap_admin *admin,1105 enum vcap_selection sel,1106 u32 start,1107 u32 count)1108{1109 struct sparx5_port *port = netdev_priv(ndev);1110 struct sparx5 *sparx5 = port->sparx5;1111 1112 switch (admin->vtype) {1113 case VCAP_TYPE_IS0:1114 sparx5_vcap_is0_cache_write(sparx5, admin, sel, start, count);1115 break;1116 case VCAP_TYPE_IS2:1117 sparx5_vcap_is2_cache_write(sparx5, admin, sel, start, count);1118 break;1119 case VCAP_TYPE_ES0:1120 sparx5_vcap_es0_cache_write(sparx5, admin, sel, start, count);1121 break;1122 case VCAP_TYPE_ES2:1123 sparx5_vcap_es2_cache_write(sparx5, admin, sel, start, count);1124 break;1125 default:1126 sparx5_vcap_type_err(sparx5, admin, __func__);1127 break;1128 }1129}1130 1131static void sparx5_vcap_is0_cache_read(struct sparx5 *sparx5,1132 struct vcap_admin *admin,1133 enum vcap_selection sel,1134 u32 start,1135 u32 count)1136{1137 u32 *keystr, *mskstr, *actstr;1138 int idx;1139 1140 keystr = &admin->cache.keystream[start];1141 mskstr = &admin->cache.maskstream[start];1142 actstr = &admin->cache.actionstream[start];1143 1144 if (sel & VCAP_SEL_ENTRY) {1145 for (idx = 0; idx < count; ++idx) {1146 keystr[idx] = spx5_rd(sparx5,1147 VCAP_SUPER_VCAP_ENTRY_DAT(idx));1148 mskstr[idx] = ~spx5_rd(sparx5,1149 VCAP_SUPER_VCAP_MASK_DAT(idx));1150 }1151 }1152 1153 if (sel & VCAP_SEL_ACTION)1154 for (idx = 0; idx < count; ++idx)1155 actstr[idx] = spx5_rd(sparx5,1156 VCAP_SUPER_VCAP_ACTION_DAT(idx));1157 1158 if (sel & VCAP_SEL_COUNTER) {1159 admin->cache.counter =1160 spx5_rd(sparx5, VCAP_SUPER_VCAP_CNT_DAT(0));1161 admin->cache.sticky =1162 spx5_rd(sparx5, VCAP_SUPER_VCAP_CNT_DAT(0));1163 }1164}1165 1166static void sparx5_vcap_is2_cache_read(struct sparx5 *sparx5,1167 struct vcap_admin *admin,1168 enum vcap_selection sel,1169 u32 start,1170 u32 count)1171{1172 u32 *keystr, *mskstr, *actstr;1173 int idx;1174 1175 keystr = &admin->cache.keystream[start];1176 mskstr = &admin->cache.maskstream[start];1177 actstr = &admin->cache.actionstream[start];1178 1179 if (sel & VCAP_SEL_ENTRY) {1180 for (idx = 0; idx < count; ++idx) {1181 keystr[idx] = spx5_rd(sparx5,1182 VCAP_SUPER_VCAP_ENTRY_DAT(idx));1183 mskstr[idx] = ~spx5_rd(sparx5,1184 VCAP_SUPER_VCAP_MASK_DAT(idx));1185 }1186 }1187 1188 if (sel & VCAP_SEL_ACTION)1189 for (idx = 0; idx < count; ++idx)1190 actstr[idx] = spx5_rd(sparx5,1191 VCAP_SUPER_VCAP_ACTION_DAT(idx));1192 1193 if (sel & VCAP_SEL_COUNTER) {1194 start = start & 0xfff; /* counter limit */1195 if (admin->vinst == 0)1196 admin->cache.counter =1197 spx5_rd(sparx5, ANA_ACL_CNT_A(start));1198 else1199 admin->cache.counter =1200 spx5_rd(sparx5, ANA_ACL_CNT_B(start));1201 admin->cache.sticky =1202 spx5_rd(sparx5, VCAP_SUPER_VCAP_CNT_DAT(0));1203 }1204}1205 1206/* Use ESDX counters located in the XQS */1207static void sparx5_es0_read_esdx_counter(struct sparx5 *sparx5,1208 struct vcap_admin *admin, u32 id)1209{1210 u32 counter;1211 1212 mutex_lock(&sparx5->queue_stats_lock);1213 spx5_wr(XQS_STAT_CFG_STAT_VIEW_SET(id), sparx5, XQS_STAT_CFG);1214 counter = spx5_rd(sparx5, XQS_CNT(SPARX5_STAT_ESDX_GRN_PKTS)) +1215 spx5_rd(sparx5, XQS_CNT(SPARX5_STAT_ESDX_YEL_PKTS));1216 mutex_unlock(&sparx5->queue_stats_lock);1217 if (counter)1218 admin->cache.counter = counter;1219}1220 1221static void sparx5_vcap_es0_cache_read(struct sparx5 *sparx5,1222 struct vcap_admin *admin,1223 enum vcap_selection sel,1224 u32 start,1225 u32 count)1226{1227 u32 *keystr, *mskstr, *actstr;1228 int idx;1229 1230 keystr = &admin->cache.keystream[start];1231 mskstr = &admin->cache.maskstream[start];1232 actstr = &admin->cache.actionstream[start];1233 1234 if (sel & VCAP_SEL_ENTRY) {1235 for (idx = 0; idx < count; ++idx) {1236 keystr[idx] =1237 spx5_rd(sparx5, VCAP_ES0_VCAP_ENTRY_DAT(idx));1238 mskstr[idx] =1239 ~spx5_rd(sparx5, VCAP_ES0_VCAP_MASK_DAT(idx));1240 }1241 }1242 1243 if (sel & VCAP_SEL_ACTION)1244 for (idx = 0; idx < count; ++idx)1245 actstr[idx] =1246 spx5_rd(sparx5, VCAP_ES0_VCAP_ACTION_DAT(idx));1247 1248 if (sel & VCAP_SEL_COUNTER) {1249 admin->cache.counter =1250 spx5_rd(sparx5, VCAP_ES0_VCAP_CNT_DAT(0));1251 admin->cache.sticky = admin->cache.counter;1252 sparx5_es0_read_esdx_counter(sparx5, admin, start);1253 }1254}1255 1256static void sparx5_vcap_es2_cache_read(struct sparx5 *sparx5,1257 struct vcap_admin *admin,1258 enum vcap_selection sel,1259 u32 start,1260 u32 count)1261{1262 u32 *keystr, *mskstr, *actstr;1263 int idx;1264 1265 keystr = &admin->cache.keystream[start];1266 mskstr = &admin->cache.maskstream[start];1267 actstr = &admin->cache.actionstream[start];1268 1269 if (sel & VCAP_SEL_ENTRY) {1270 for (idx = 0; idx < count; ++idx) {1271 keystr[idx] =1272 spx5_rd(sparx5, VCAP_ES2_VCAP_ENTRY_DAT(idx));1273 mskstr[idx] =1274 ~spx5_rd(sparx5, VCAP_ES2_VCAP_MASK_DAT(idx));1275 }1276 }1277 1278 if (sel & VCAP_SEL_ACTION)1279 for (idx = 0; idx < count; ++idx)1280 actstr[idx] =1281 spx5_rd(sparx5, VCAP_ES2_VCAP_ACTION_DAT(idx));1282 1283 if (sel & VCAP_SEL_COUNTER) {1284 start = start & 0x7ff; /* counter limit */1285 admin->cache.counter =1286 spx5_rd(sparx5, EACL_ES2_CNT(start));1287 admin->cache.sticky =1288 spx5_rd(sparx5, VCAP_ES2_VCAP_CNT_DAT(0));1289 }1290}1291 1292/* API callback used for reading from the VCAP into the VCAP cache */1293static void sparx5_vcap_cache_read(struct net_device *ndev,1294 struct vcap_admin *admin,1295 enum vcap_selection sel,1296 u32 start,1297 u32 count)1298{1299 struct sparx5_port *port = netdev_priv(ndev);1300 struct sparx5 *sparx5 = port->sparx5;1301 1302 switch (admin->vtype) {1303 case VCAP_TYPE_IS0:1304 sparx5_vcap_is0_cache_read(sparx5, admin, sel, start, count);1305 break;1306 case VCAP_TYPE_IS2:1307 sparx5_vcap_is2_cache_read(sparx5, admin, sel, start, count);1308 break;1309 case VCAP_TYPE_ES0:1310 sparx5_vcap_es0_cache_read(sparx5, admin, sel, start, count);1311 break;1312 case VCAP_TYPE_ES2:1313 sparx5_vcap_es2_cache_read(sparx5, admin, sel, start, count);1314 break;1315 default:1316 sparx5_vcap_type_err(sparx5, admin, __func__);1317 break;1318 }1319}1320 1321/* API callback used for initializing a VCAP address range */1322static void sparx5_vcap_range_init(struct net_device *ndev,1323 struct vcap_admin *admin, u32 addr,1324 u32 count)1325{1326 struct sparx5_port *port = netdev_priv(ndev);1327 struct sparx5 *sparx5 = port->sparx5;1328 1329 _sparx5_vcap_range_init(sparx5, admin, addr, count);1330}1331 1332static void sparx5_vcap_super_update(struct sparx5 *sparx5,1333 enum vcap_command cmd,1334 enum vcap_selection sel, u32 addr)1335{1336 bool clear = (cmd == VCAP_CMD_INITIALIZE);1337 1338 spx5_wr(VCAP_SUPER_CFG_MV_NUM_POS_SET(0) |1339 VCAP_SUPER_CFG_MV_SIZE_SET(0), sparx5, VCAP_SUPER_CFG);1340 spx5_wr(VCAP_SUPER_CTRL_UPDATE_CMD_SET(cmd) |1341 VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET((VCAP_SEL_ENTRY & sel) == 0) |1342 VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET((VCAP_SEL_ACTION & sel) == 0) |1343 VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET((VCAP_SEL_COUNTER & sel) == 0) |1344 VCAP_SUPER_CTRL_UPDATE_ADDR_SET(addr) |1345 VCAP_SUPER_CTRL_CLEAR_CACHE_SET(clear) |1346 VCAP_SUPER_CTRL_UPDATE_SHOT_SET(true),1347 sparx5, VCAP_SUPER_CTRL);1348 sparx5_vcap_wait_super_update(sparx5);1349}1350 1351static void sparx5_vcap_es0_update(struct sparx5 *sparx5,1352 enum vcap_command cmd,1353 enum vcap_selection sel, u32 addr)1354{1355 bool clear = (cmd == VCAP_CMD_INITIALIZE);1356 1357 spx5_wr(VCAP_ES0_CFG_MV_NUM_POS_SET(0) |1358 VCAP_ES0_CFG_MV_SIZE_SET(0), sparx5, VCAP_ES0_CFG);1359 spx5_wr(VCAP_ES0_CTRL_UPDATE_CMD_SET(cmd) |1360 VCAP_ES0_CTRL_UPDATE_ENTRY_DIS_SET((VCAP_SEL_ENTRY & sel) == 0) |1361 VCAP_ES0_CTRL_UPDATE_ACTION_DIS_SET((VCAP_SEL_ACTION & sel) == 0) |1362 VCAP_ES0_CTRL_UPDATE_CNT_DIS_SET((VCAP_SEL_COUNTER & sel) == 0) |1363 VCAP_ES0_CTRL_UPDATE_ADDR_SET(addr) |1364 VCAP_ES0_CTRL_CLEAR_CACHE_SET(clear) |1365 VCAP_ES0_CTRL_UPDATE_SHOT_SET(true),1366 sparx5, VCAP_ES0_CTRL);1367 sparx5_vcap_wait_es0_update(sparx5);1368}1369 1370static void sparx5_vcap_es2_update(struct sparx5 *sparx5,1371 enum vcap_command cmd,1372 enum vcap_selection sel, u32 addr)1373{1374 bool clear = (cmd == VCAP_CMD_INITIALIZE);1375 1376 spx5_wr(VCAP_ES2_CFG_MV_NUM_POS_SET(0) |1377 VCAP_ES2_CFG_MV_SIZE_SET(0), sparx5, VCAP_ES2_CFG);1378 spx5_wr(VCAP_ES2_CTRL_UPDATE_CMD_SET(cmd) |1379 VCAP_ES2_CTRL_UPDATE_ENTRY_DIS_SET((VCAP_SEL_ENTRY & sel) == 0) |1380 VCAP_ES2_CTRL_UPDATE_ACTION_DIS_SET((VCAP_SEL_ACTION & sel) == 0) |1381 VCAP_ES2_CTRL_UPDATE_CNT_DIS_SET((VCAP_SEL_COUNTER & sel) == 0) |1382 VCAP_ES2_CTRL_UPDATE_ADDR_SET(addr) |1383 VCAP_ES2_CTRL_CLEAR_CACHE_SET(clear) |1384 VCAP_ES2_CTRL_UPDATE_SHOT_SET(true),1385 sparx5, VCAP_ES2_CTRL);1386 sparx5_vcap_wait_es2_update(sparx5);1387}1388 1389/* API callback used for updating the VCAP cache */1390static void sparx5_vcap_update(struct net_device *ndev,1391 struct vcap_admin *admin, enum vcap_command cmd,1392 enum vcap_selection sel, u32 addr)1393{1394 struct sparx5_port *port = netdev_priv(ndev);1395 struct sparx5 *sparx5 = port->sparx5;1396 1397 switch (admin->vtype) {1398 case VCAP_TYPE_IS0:1399 case VCAP_TYPE_IS2:1400 sparx5_vcap_super_update(sparx5, cmd, sel, addr);1401 break;1402 case VCAP_TYPE_ES0:1403 sparx5_vcap_es0_update(sparx5, cmd, sel, addr);1404 break;1405 case VCAP_TYPE_ES2:1406 sparx5_vcap_es2_update(sparx5, cmd, sel, addr);1407 break;1408 default:1409 sparx5_vcap_type_err(sparx5, admin, __func__);1410 break;1411 }1412}1413 1414static void sparx5_vcap_super_move(struct sparx5 *sparx5,1415 u32 addr,1416 enum vcap_command cmd,1417 u16 mv_num_pos,1418 u16 mv_size)1419{1420 spx5_wr(VCAP_SUPER_CFG_MV_NUM_POS_SET(mv_num_pos) |1421 VCAP_SUPER_CFG_MV_SIZE_SET(mv_size),1422 sparx5, VCAP_SUPER_CFG);1423 spx5_wr(VCAP_SUPER_CTRL_UPDATE_CMD_SET(cmd) |1424 VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET(0) |1425 VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET(0) |1426 VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET(0) |1427 VCAP_SUPER_CTRL_UPDATE_ADDR_SET(addr) |1428 VCAP_SUPER_CTRL_CLEAR_CACHE_SET(false) |1429 VCAP_SUPER_CTRL_UPDATE_SHOT_SET(true),1430 sparx5, VCAP_SUPER_CTRL);1431 sparx5_vcap_wait_super_update(sparx5);1432}1433 1434static void sparx5_vcap_es0_move(struct sparx5 *sparx5,1435 u32 addr,1436 enum vcap_command cmd,1437 u16 mv_num_pos,1438 u16 mv_size)1439{1440 spx5_wr(VCAP_ES0_CFG_MV_NUM_POS_SET(mv_num_pos) |1441 VCAP_ES0_CFG_MV_SIZE_SET(mv_size),1442 sparx5, VCAP_ES0_CFG);1443 spx5_wr(VCAP_ES0_CTRL_UPDATE_CMD_SET(cmd) |1444 VCAP_ES0_CTRL_UPDATE_ENTRY_DIS_SET(0) |1445 VCAP_ES0_CTRL_UPDATE_ACTION_DIS_SET(0) |1446 VCAP_ES0_CTRL_UPDATE_CNT_DIS_SET(0) |1447 VCAP_ES0_CTRL_UPDATE_ADDR_SET(addr) |1448 VCAP_ES0_CTRL_CLEAR_CACHE_SET(false) |1449 VCAP_ES0_CTRL_UPDATE_SHOT_SET(true),1450 sparx5, VCAP_ES0_CTRL);1451 sparx5_vcap_wait_es0_update(sparx5);1452}1453 1454static void sparx5_vcap_es2_move(struct sparx5 *sparx5,1455 u32 addr,1456 enum vcap_command cmd,1457 u16 mv_num_pos,1458 u16 mv_size)1459{1460 spx5_wr(VCAP_ES2_CFG_MV_NUM_POS_SET(mv_num_pos) |1461 VCAP_ES2_CFG_MV_SIZE_SET(mv_size),1462 sparx5, VCAP_ES2_CFG);1463 spx5_wr(VCAP_ES2_CTRL_UPDATE_CMD_SET(cmd) |1464 VCAP_ES2_CTRL_UPDATE_ENTRY_DIS_SET(0) |1465 VCAP_ES2_CTRL_UPDATE_ACTION_DIS_SET(0) |1466 VCAP_ES2_CTRL_UPDATE_CNT_DIS_SET(0) |1467 VCAP_ES2_CTRL_UPDATE_ADDR_SET(addr) |1468 VCAP_ES2_CTRL_CLEAR_CACHE_SET(false) |1469 VCAP_ES2_CTRL_UPDATE_SHOT_SET(true),1470 sparx5, VCAP_ES2_CTRL);1471 sparx5_vcap_wait_es2_update(sparx5);1472}1473 1474/* API callback used for moving a block of rules in the VCAP */1475static void sparx5_vcap_move(struct net_device *ndev, struct vcap_admin *admin,1476 u32 addr, int offset, int count)1477{1478 struct sparx5_port *port = netdev_priv(ndev);1479 struct sparx5 *sparx5 = port->sparx5;1480 enum vcap_command cmd;1481 u16 mv_num_pos;1482 u16 mv_size;1483 1484 mv_size = count - 1;1485 if (offset > 0) {1486 mv_num_pos = offset - 1;1487 cmd = VCAP_CMD_MOVE_DOWN;1488 } else {1489 mv_num_pos = -offset - 1;1490 cmd = VCAP_CMD_MOVE_UP;1491 }1492 1493 switch (admin->vtype) {1494 case VCAP_TYPE_IS0:1495 case VCAP_TYPE_IS2:1496 sparx5_vcap_super_move(sparx5, addr, cmd, mv_num_pos, mv_size);1497 break;1498 case VCAP_TYPE_ES0:1499 sparx5_vcap_es0_move(sparx5, addr, cmd, mv_num_pos, mv_size);1500 break;1501 case VCAP_TYPE_ES2:1502 sparx5_vcap_es2_move(sparx5, addr, cmd, mv_num_pos, mv_size);1503 break;1504 default:1505 sparx5_vcap_type_err(sparx5, admin, __func__);1506 break;1507 }1508}1509 1510static const struct vcap_operations sparx5_vcap_ops = {1511 .validate_keyset = sparx5_vcap_validate_keyset,1512 .add_default_fields = sparx5_vcap_add_default_fields,1513 .cache_erase = sparx5_vcap_cache_erase,1514 .cache_write = sparx5_vcap_cache_write,1515 .cache_read = sparx5_vcap_cache_read,1516 .init = sparx5_vcap_range_init,1517 .update = sparx5_vcap_update,1518 .move = sparx5_vcap_move,1519 .port_info = sparx5_port_info,1520};1521 1522static u32 sparx5_vcap_is0_keyset_to_etype_ps(enum vcap_keyfield_set keyset)1523{1524 switch (keyset) {1525 case VCAP_KFS_NORMAL_7TUPLE:1526 return VCAP_IS0_PS_ETYPE_NORMAL_7TUPLE;1527 case VCAP_KFS_NORMAL_5TUPLE_IP4:1528 return VCAP_IS0_PS_ETYPE_NORMAL_5TUPLE_IP4;1529 default:1530 return VCAP_IS0_PS_ETYPE_NORMAL_7TUPLE;1531 }1532}1533 1534static void sparx5_vcap_is0_set_port_keyset(struct net_device *ndev, int lookup,1535 enum vcap_keyfield_set keyset,1536 int l3_proto)1537{1538 struct sparx5_port *port = netdev_priv(ndev);1539 struct sparx5 *sparx5 = port->sparx5;1540 int portno = port->portno;1541 u32 value;1542 1543 switch (l3_proto) {1544 case ETH_P_IP:1545 value = sparx5_vcap_is0_keyset_to_etype_ps(keyset);1546 spx5_rmw(ANA_CL_ADV_CL_CFG_IP4_CLM_KEY_SEL_SET(value),1547 ANA_CL_ADV_CL_CFG_IP4_CLM_KEY_SEL,1548 sparx5,1549 ANA_CL_ADV_CL_CFG(portno, lookup));1550 break;1551 case ETH_P_IPV6:1552 value = sparx5_vcap_is0_keyset_to_etype_ps(keyset);1553 spx5_rmw(ANA_CL_ADV_CL_CFG_IP6_CLM_KEY_SEL_SET(value),1554 ANA_CL_ADV_CL_CFG_IP6_CLM_KEY_SEL,1555 sparx5,1556 ANA_CL_ADV_CL_CFG(portno, lookup));1557 break;1558 default:1559 value = sparx5_vcap_is0_keyset_to_etype_ps(keyset);1560 spx5_rmw(ANA_CL_ADV_CL_CFG_ETYPE_CLM_KEY_SEL_SET(value),1561 ANA_CL_ADV_CL_CFG_ETYPE_CLM_KEY_SEL,1562 sparx5,1563 ANA_CL_ADV_CL_CFG(portno, lookup));1564 break;1565 }1566}1567 1568static u32 sparx5_vcap_is2_keyset_to_arp_ps(enum vcap_keyfield_set keyset)1569{1570 switch (keyset) {1571 case VCAP_KFS_ARP:1572 return VCAP_IS2_PS_ARP_ARP;1573 default:1574 return VCAP_IS2_PS_ARP_MAC_ETYPE;1575 }1576}1577 1578static u32 sparx5_vcap_is2_keyset_to_ipv4_ps(enum vcap_keyfield_set keyset)1579{1580 switch (keyset) {1581 case VCAP_KFS_MAC_ETYPE:1582 return VCAP_IS2_PS_IPV4_UC_MAC_ETYPE;1583 case VCAP_KFS_IP4_OTHER:1584 case VCAP_KFS_IP4_TCP_UDP:1585 return VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER;1586 case VCAP_KFS_IP_7TUPLE:1587 return VCAP_IS2_PS_IPV4_UC_IP_7TUPLE;1588 default:1589 return VCAP_KFS_NO_VALUE;1590 }1591}1592 1593static u32 sparx5_vcap_is2_keyset_to_ipv6_uc_ps(enum vcap_keyfield_set keyset)1594{1595 switch (keyset) {1596 case VCAP_KFS_MAC_ETYPE:1597 return VCAP_IS2_PS_IPV6_UC_MAC_ETYPE;1598 case VCAP_KFS_IP4_OTHER:1599 case VCAP_KFS_IP4_TCP_UDP:1600 return VCAP_IS2_PS_IPV6_UC_IP4_TCP_UDP_OTHER;1601 case VCAP_KFS_IP_7TUPLE:1602 return VCAP_IS2_PS_IPV6_UC_IP_7TUPLE;1603 default:1604 return VCAP_KFS_NO_VALUE;1605 }1606}1607 1608static u32 sparx5_vcap_is2_keyset_to_ipv6_mc_ps(enum vcap_keyfield_set keyset)1609{1610 switch (keyset) {1611 case VCAP_KFS_MAC_ETYPE:1612 return VCAP_IS2_PS_IPV6_MC_MAC_ETYPE;1613 case VCAP_KFS_IP4_OTHER:1614 case VCAP_KFS_IP4_TCP_UDP:1615 return VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER;1616 case VCAP_KFS_IP_7TUPLE:1617 return VCAP_IS2_PS_IPV6_MC_IP_7TUPLE;1618 default:1619 return VCAP_KFS_NO_VALUE;1620 }1621}1622 1623static void sparx5_vcap_is2_set_port_keyset(struct net_device *ndev, int lookup,1624 enum vcap_keyfield_set keyset,1625 int l3_proto)1626{1627 struct sparx5_port *port = netdev_priv(ndev);1628 struct sparx5 *sparx5 = port->sparx5;1629 int portno = port->portno;1630 u32 value;1631 1632 switch (l3_proto) {1633 case ETH_P_ARP:1634 value = sparx5_vcap_is2_keyset_to_arp_ps(keyset);1635 spx5_rmw(ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_SET(value),1636 ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL,1637 sparx5,1638 ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup));1639 break;1640 case ETH_P_IP:1641 value = sparx5_vcap_is2_keyset_to_ipv4_ps(keyset);1642 spx5_rmw(ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_SET(value),1643 ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL,1644 sparx5,1645 ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup));1646 spx5_rmw(ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_SET(value),1647 ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL,1648 sparx5,1649 ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup));1650 break;1651 case ETH_P_IPV6:1652 value = sparx5_vcap_is2_keyset_to_ipv6_uc_ps(keyset);1653 spx5_rmw(ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_SET(value),1654 ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL,1655 sparx5,1656 ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup));1657 value = sparx5_vcap_is2_keyset_to_ipv6_mc_ps(keyset);1658 spx5_rmw(ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_SET(value),1659 ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL,1660 sparx5,1661 ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup));1662 break;1663 default:1664 value = VCAP_IS2_PS_NONETH_MAC_ETYPE;1665 spx5_rmw(ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_SET(value),1666 ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL,1667 sparx5,1668 ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup));1669 break;1670 }1671}1672 1673static u32 sparx5_vcap_es2_keyset_to_arp_ps(enum vcap_keyfield_set keyset)1674{1675 switch (keyset) {1676 case VCAP_KFS_ARP:1677 return VCAP_ES2_PS_ARP_ARP;1678 default:1679 return VCAP_ES2_PS_ARP_MAC_ETYPE;1680 }1681}1682 1683static u32 sparx5_vcap_es2_keyset_to_ipv4_ps(enum vcap_keyfield_set keyset)1684{1685 switch (keyset) {1686 case VCAP_KFS_MAC_ETYPE:1687 return VCAP_ES2_PS_IPV4_MAC_ETYPE;1688 case VCAP_KFS_IP_7TUPLE:1689 return VCAP_ES2_PS_IPV4_IP_7TUPLE;1690 case VCAP_KFS_IP4_TCP_UDP:1691 return VCAP_ES2_PS_IPV4_IP4_TCP_UDP_OTHER;1692 case VCAP_KFS_IP4_OTHER:1693 return VCAP_ES2_PS_IPV4_IP4_OTHER;1694 default:1695 return VCAP_ES2_PS_IPV4_MAC_ETYPE;1696 }1697}1698 1699static u32 sparx5_vcap_es2_keyset_to_ipv6_ps(enum vcap_keyfield_set keyset)1700{1701 switch (keyset) {1702 case VCAP_KFS_MAC_ETYPE:1703 return VCAP_ES2_PS_IPV6_MAC_ETYPE;1704 case VCAP_KFS_IP4_TCP_UDP:1705 case VCAP_KFS_IP4_OTHER:1706 return VCAP_ES2_PS_IPV6_IP4_DOWNGRADE;1707 case VCAP_KFS_IP_7TUPLE:1708 return VCAP_ES2_PS_IPV6_IP_7TUPLE;1709 case VCAP_KFS_IP6_STD:1710 return VCAP_ES2_PS_IPV6_IP6_STD;1711 default:1712 return VCAP_ES2_PS_IPV6_MAC_ETYPE;1713 }1714}1715 1716static void sparx5_vcap_es2_set_port_keyset(struct net_device *ndev, int lookup,1717 enum vcap_keyfield_set keyset,1718 int l3_proto)1719{1720 struct sparx5_port *port = netdev_priv(ndev);1721 struct sparx5 *sparx5 = port->sparx5;1722 int portno = port->portno;1723 u32 value;1724 1725 switch (l3_proto) {1726 case ETH_P_IP:1727 value = sparx5_vcap_es2_keyset_to_ipv4_ps(keyset);1728 spx5_rmw(EACL_VCAP_ES2_KEY_SEL_IP4_KEY_SEL_SET(value),1729 EACL_VCAP_ES2_KEY_SEL_IP4_KEY_SEL,1730 sparx5,1731 EACL_VCAP_ES2_KEY_SEL(portno, lookup));1732 break;1733 case ETH_P_IPV6:1734 value = sparx5_vcap_es2_keyset_to_ipv6_ps(keyset);1735 spx5_rmw(EACL_VCAP_ES2_KEY_SEL_IP6_KEY_SEL_SET(value),1736 EACL_VCAP_ES2_KEY_SEL_IP6_KEY_SEL,1737 sparx5,1738 EACL_VCAP_ES2_KEY_SEL(portno, lookup));1739 break;1740 case ETH_P_ARP:1741 value = sparx5_vcap_es2_keyset_to_arp_ps(keyset);1742 spx5_rmw(EACL_VCAP_ES2_KEY_SEL_ARP_KEY_SEL_SET(value),1743 EACL_VCAP_ES2_KEY_SEL_ARP_KEY_SEL,1744 sparx5,1745 EACL_VCAP_ES2_KEY_SEL(portno, lookup));1746 break;1747 }1748}1749 1750/* Change the port keyset for the lookup and protocol */1751void sparx5_vcap_set_port_keyset(struct net_device *ndev,1752 struct vcap_admin *admin,1753 int cid,1754 u16 l3_proto,1755 enum vcap_keyfield_set keyset,1756 struct vcap_keyset_list *orig)1757{1758 struct sparx5_port *port;1759 int lookup;1760 1761 switch (admin->vtype) {1762 case VCAP_TYPE_IS0:1763 lookup = sparx5_vcap_is0_cid_to_lookup(cid);1764 if (orig)1765 sparx5_vcap_is0_get_port_keysets(ndev, lookup, orig,1766 l3_proto);1767 sparx5_vcap_is0_set_port_keyset(ndev, lookup, keyset, l3_proto);1768 break;1769 case VCAP_TYPE_IS2:1770 lookup = sparx5_vcap_is2_cid_to_lookup(cid);1771 if (orig)1772 sparx5_vcap_is2_get_port_keysets(ndev, lookup, orig,1773 l3_proto);1774 sparx5_vcap_is2_set_port_keyset(ndev, lookup, keyset, l3_proto);1775 break;1776 case VCAP_TYPE_ES0:1777 break;1778 case VCAP_TYPE_ES2:1779 lookup = sparx5_vcap_es2_cid_to_lookup(cid);1780 if (orig)1781 sparx5_vcap_es2_get_port_keysets(ndev, lookup, orig,1782 l3_proto);1783 sparx5_vcap_es2_set_port_keyset(ndev, lookup, keyset, l3_proto);1784 break;1785 default:1786 port = netdev_priv(ndev);1787 sparx5_vcap_type_err(port->sparx5, admin, __func__);1788 break;1789 }1790}1791 1792/* Enable IS0 lookups per port and set the keyset generation */1793static void sparx5_vcap_is0_port_key_selection(struct sparx5 *sparx5,1794 struct vcap_admin *admin)1795{1796 int portno, lookup;1797 u32 keysel;1798 1799 keysel = VCAP_IS0_KEYSEL(false,1800 VCAP_IS0_PS_ETYPE_NORMAL_7TUPLE,1801 VCAP_IS0_PS_ETYPE_NORMAL_5TUPLE_IP4,1802 VCAP_IS0_PS_ETYPE_NORMAL_7TUPLE,1803 VCAP_IS0_PS_MPLS_FOLLOW_ETYPE,1804 VCAP_IS0_PS_MPLS_FOLLOW_ETYPE,1805 VCAP_IS0_PS_MLBS_FOLLOW_ETYPE);1806 for (lookup = 0; lookup < admin->lookups; ++lookup) {1807 for (portno = 0; portno < SPX5_PORTS; ++portno) {1808 spx5_wr(keysel, sparx5,1809 ANA_CL_ADV_CL_CFG(portno, lookup));1810 spx5_rmw(ANA_CL_ADV_CL_CFG_LOOKUP_ENA,1811 ANA_CL_ADV_CL_CFG_LOOKUP_ENA,1812 sparx5,1813 ANA_CL_ADV_CL_CFG(portno, lookup));1814 }1815 }1816}1817 1818/* Enable IS2 lookups per port and set the keyset generation */1819static void sparx5_vcap_is2_port_key_selection(struct sparx5 *sparx5,1820 struct vcap_admin *admin)1821{1822 int portno, lookup;1823 u32 keysel;1824 1825 keysel = VCAP_IS2_KEYSEL(true, VCAP_IS2_PS_NONETH_MAC_ETYPE,1826 VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER,1827 VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER,1828 VCAP_IS2_PS_IPV6_MC_IP_7TUPLE,1829 VCAP_IS2_PS_IPV6_UC_IP_7TUPLE,1830 VCAP_IS2_PS_ARP_ARP);1831 for (lookup = 0; lookup < admin->lookups; ++lookup) {1832 for (portno = 0; portno < SPX5_PORTS; ++portno) {1833 spx5_wr(keysel, sparx5,1834 ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup));1835 }1836 }1837 /* IS2 lookups are in bit 0:3 */1838 for (portno = 0; portno < SPX5_PORTS; ++portno)1839 spx5_rmw(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf),1840 ANA_ACL_VCAP_S2_CFG_SEC_ENA,1841 sparx5,1842 ANA_ACL_VCAP_S2_CFG(portno));1843}1844 1845/* Enable ES0 lookups per port and set the keyset generation */1846static void sparx5_vcap_es0_port_key_selection(struct sparx5 *sparx5,1847 struct vcap_admin *admin)1848{1849 int portno;1850 u32 keysel;1851 1852 keysel = VCAP_ES0_KEYSEL(VCAP_ES0_PS_FORCE_ISDX_LOOKUPS);1853 for (portno = 0; portno < SPX5_PORTS; ++portno)1854 spx5_rmw(keysel, REW_RTAG_ETAG_CTRL_ES0_ISDX_KEY_ENA,1855 sparx5, REW_RTAG_ETAG_CTRL(portno));1856 1857 spx5_rmw(REW_ES0_CTRL_ES0_LU_ENA_SET(1), REW_ES0_CTRL_ES0_LU_ENA,1858 sparx5, REW_ES0_CTRL);1859}1860 1861/* Enable ES2 lookups per port and set the keyset generation */1862static void sparx5_vcap_es2_port_key_selection(struct sparx5 *sparx5,1863 struct vcap_admin *admin)1864{1865 int portno, lookup;1866 u32 keysel;1867 1868 keysel = VCAP_ES2_KEYSEL(true, VCAP_ES2_PS_ARP_MAC_ETYPE,1869 VCAP_ES2_PS_IPV4_IP4_TCP_UDP_OTHER,1870 VCAP_ES2_PS_IPV6_IP_7TUPLE);1871 for (lookup = 0; lookup < admin->lookups; ++lookup)1872 for (portno = 0; portno < SPX5_PORTS; ++portno)1873 spx5_wr(keysel, sparx5,1874 EACL_VCAP_ES2_KEY_SEL(portno, lookup));1875}1876 1877/* Enable lookups per port and set the keyset generation */1878static void sparx5_vcap_port_key_selection(struct sparx5 *sparx5,1879 struct vcap_admin *admin)1880{1881 switch (admin->vtype) {1882 case VCAP_TYPE_IS0:1883 sparx5_vcap_is0_port_key_selection(sparx5, admin);1884 break;1885 case VCAP_TYPE_IS2:1886 sparx5_vcap_is2_port_key_selection(sparx5, admin);1887 break;1888 case VCAP_TYPE_ES0:1889 sparx5_vcap_es0_port_key_selection(sparx5, admin);1890 break;1891 case VCAP_TYPE_ES2:1892 sparx5_vcap_es2_port_key_selection(sparx5, admin);1893 break;1894 default:1895 sparx5_vcap_type_err(sparx5, admin, __func__);1896 break;1897 }1898}1899 1900/* Disable lookups per port */1901static void sparx5_vcap_port_key_deselection(struct sparx5 *sparx5,1902 struct vcap_admin *admin)1903{1904 int portno, lookup;1905 1906 switch (admin->vtype) {1907 case VCAP_TYPE_IS0:1908 for (lookup = 0; lookup < admin->lookups; ++lookup)1909 for (portno = 0; portno < SPX5_PORTS; ++portno)1910 spx5_rmw(ANA_CL_ADV_CL_CFG_LOOKUP_ENA_SET(0),1911 ANA_CL_ADV_CL_CFG_LOOKUP_ENA,1912 sparx5,1913 ANA_CL_ADV_CL_CFG(portno, lookup));1914 break;1915 case VCAP_TYPE_IS2:1916 for (portno = 0; portno < SPX5_PORTS; ++portno)1917 spx5_rmw(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0),1918 ANA_ACL_VCAP_S2_CFG_SEC_ENA,1919 sparx5,1920 ANA_ACL_VCAP_S2_CFG(portno));1921 break;1922 case VCAP_TYPE_ES0:1923 spx5_rmw(REW_ES0_CTRL_ES0_LU_ENA_SET(0),1924 REW_ES0_CTRL_ES0_LU_ENA, sparx5, REW_ES0_CTRL);1925 break;1926 case VCAP_TYPE_ES2:1927 for (lookup = 0; lookup < admin->lookups; ++lookup)1928 for (portno = 0; portno < SPX5_PORTS; ++portno)1929 spx5_rmw(EACL_VCAP_ES2_KEY_SEL_KEY_ENA_SET(0),1930 EACL_VCAP_ES2_KEY_SEL_KEY_ENA,1931 sparx5,1932 EACL_VCAP_ES2_KEY_SEL(portno, lookup));1933 break;1934 default:1935 sparx5_vcap_type_err(sparx5, admin, __func__);1936 break;1937 }1938}1939 1940static void sparx5_vcap_admin_free(struct vcap_admin *admin)1941{1942 if (!admin)1943 return;1944 mutex_destroy(&admin->lock);1945 kfree(admin->cache.keystream);1946 kfree(admin->cache.maskstream);1947 kfree(admin->cache.actionstream);1948 kfree(admin);1949}1950 1951/* Allocate a vcap instance with a rule list and a cache area */1952static struct vcap_admin *1953sparx5_vcap_admin_alloc(struct sparx5 *sparx5, struct vcap_control *ctrl,1954 const struct sparx5_vcap_inst *cfg)1955{1956 struct vcap_admin *admin;1957 1958 admin = kzalloc(sizeof(*admin), GFP_KERNEL);1959 if (!admin)1960 return ERR_PTR(-ENOMEM);1961 INIT_LIST_HEAD(&admin->list);1962 INIT_LIST_HEAD(&admin->rules);1963 INIT_LIST_HEAD(&admin->enabled);1964 mutex_init(&admin->lock);1965 admin->vtype = cfg->vtype;1966 admin->vinst = cfg->vinst;1967 admin->ingress = cfg->ingress;1968 admin->lookups = cfg->lookups;1969 admin->lookups_per_instance = cfg->lookups_per_instance;1970 admin->first_cid = cfg->first_cid;1971 admin->last_cid = cfg->last_cid;1972 admin->cache.keystream =1973 kzalloc(STREAMSIZE, GFP_KERNEL);1974 admin->cache.maskstream =1975 kzalloc(STREAMSIZE, GFP_KERNEL);1976 admin->cache.actionstream =1977 kzalloc(STREAMSIZE, GFP_KERNEL);1978 if (!admin->cache.keystream || !admin->cache.maskstream ||1979 !admin->cache.actionstream) {1980 sparx5_vcap_admin_free(admin);1981 return ERR_PTR(-ENOMEM);1982 }1983 return admin;1984}1985 1986/* Do block allocations and provide addresses for VCAP instances */1987static void sparx5_vcap_block_alloc(struct sparx5 *sparx5,1988 struct vcap_admin *admin,1989 const struct sparx5_vcap_inst *cfg)1990{1991 int idx, cores;1992 1993 switch (admin->vtype) {1994 case VCAP_TYPE_IS0:1995 case VCAP_TYPE_IS2:1996 /* Super VCAP block mapping and address configuration. Block 01997 * is assigned addresses 0 through 3071, block 1 is assigned1998 * addresses 3072 though 6143, and so on.1999 */2000 for (idx = cfg->blockno; idx < cfg->blockno + cfg->blocks;2001 ++idx) {2002 spx5_wr(VCAP_SUPER_IDX_CORE_IDX_SET(idx), sparx5,2003 VCAP_SUPER_IDX);2004 spx5_wr(VCAP_SUPER_MAP_CORE_MAP_SET(cfg->map_id),2005 sparx5, VCAP_SUPER_MAP);2006 }2007 admin->first_valid_addr = cfg->blockno * SUPER_VCAP_BLK_SIZE;2008 admin->last_used_addr = admin->first_valid_addr +2009 cfg->blocks * SUPER_VCAP_BLK_SIZE;2010 admin->last_valid_addr = admin->last_used_addr - 1;2011 break;2012 case VCAP_TYPE_ES0:2013 admin->first_valid_addr = 0;2014 admin->last_used_addr = cfg->count;2015 admin->last_valid_addr = cfg->count - 1;2016 cores = spx5_rd(sparx5, VCAP_ES0_CORE_CNT);2017 for (idx = 0; idx < cores; ++idx) {2018 spx5_wr(VCAP_ES0_IDX_CORE_IDX_SET(idx), sparx5,2019 VCAP_ES0_IDX);2020 spx5_wr(VCAP_ES0_MAP_CORE_MAP_SET(1), sparx5,2021 VCAP_ES0_MAP);2022 }2023 break;2024 case VCAP_TYPE_ES2:2025 admin->first_valid_addr = 0;2026 admin->last_used_addr = cfg->count;2027 admin->last_valid_addr = cfg->count - 1;2028 cores = spx5_rd(sparx5, VCAP_ES2_CORE_CNT);2029 for (idx = 0; idx < cores; ++idx) {2030 spx5_wr(VCAP_ES2_IDX_CORE_IDX_SET(idx), sparx5,2031 VCAP_ES2_IDX);2032 spx5_wr(VCAP_ES2_MAP_CORE_MAP_SET(1), sparx5,2033 VCAP_ES2_MAP);2034 }2035 break;2036 default:2037 sparx5_vcap_type_err(sparx5, admin, __func__);2038 break;2039 }2040}2041 2042/* Allocate a vcap control and vcap instances and configure the system */2043int sparx5_vcap_init(struct sparx5 *sparx5)2044{2045 const struct sparx5_vcap_inst *cfg;2046 struct vcap_control *ctrl;2047 struct vcap_admin *admin;2048 struct dentry *dir;2049 int err = 0, idx;2050 2051 /* Create a VCAP control instance that owns the platform specific VCAP2052 * model with VCAP instances and information about keysets, keys,2053 * actionsets and actions2054 * - Create administrative state for each available VCAP2055 * - Lists of rules2056 * - Address information2057 * - Initialize VCAP blocks2058 * - Configure port keysets2059 */2060 ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);2061 if (!ctrl)2062 return -ENOMEM;2063 2064 sparx5->vcap_ctrl = ctrl;2065 /* select the sparx5 VCAP model */2066 ctrl->vcaps = sparx5_vcaps;2067 ctrl->stats = &sparx5_vcap_stats;2068 /* Setup callbacks to allow the API to use the VCAP HW */2069 ctrl->ops = &sparx5_vcap_ops;2070 2071 INIT_LIST_HEAD(&ctrl->list);2072 for (idx = 0; idx < ARRAY_SIZE(sparx5_vcap_inst_cfg); ++idx) {2073 cfg = &sparx5_vcap_inst_cfg[idx];2074 admin = sparx5_vcap_admin_alloc(sparx5, ctrl, cfg);2075 if (IS_ERR(admin)) {2076 err = PTR_ERR(admin);2077 pr_err("%s:%d: vcap allocation failed: %d\n",2078 __func__, __LINE__, err);2079 return err;2080 }2081 sparx5_vcap_block_alloc(sparx5, admin, cfg);2082 sparx5_vcap_block_init(sparx5, admin);2083 if (cfg->vinst == 0)2084 sparx5_vcap_port_key_selection(sparx5, admin);2085 list_add_tail(&admin->list, &ctrl->list);2086 }2087 dir = vcap_debugfs(sparx5->dev, sparx5->debugfs_root, ctrl);2088 for (idx = 0; idx < SPX5_PORTS; ++idx)2089 if (sparx5->ports[idx])2090 vcap_port_debugfs(sparx5->dev, dir, ctrl,2091 sparx5->ports[idx]->ndev);2092 2093 return err;2094}2095 2096void sparx5_vcap_destroy(struct sparx5 *sparx5)2097{2098 struct vcap_control *ctrl = sparx5->vcap_ctrl;2099 struct vcap_admin *admin, *admin_next;2100 2101 if (!ctrl)2102 return;2103 2104 list_for_each_entry_safe(admin, admin_next, &ctrl->list, list) {2105 sparx5_vcap_port_key_deselection(sparx5, admin);2106 vcap_del_rules(ctrl, admin);2107 list_del(&admin->list);2108 sparx5_vcap_admin_free(admin);2109 }2110 kfree(ctrl);2111}2112