brintos

brintos / linux-shallow public Read only

0
0
Text · 60.6 KiB · 967c862 Raw
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