brintos

brintos / linux-shallow public Read only

0
0
Text · 21.4 KiB · a1471e3 Raw
785 lines · c
1// SPDX-License-Identifier: GPL-2.0+2 3#include "lan966x_main.h"4#include "lan966x_vcap_ag_api.h"5#include "vcap_api.h"6#include "vcap_api_client.h"7#include "vcap_api_debugfs.h"8 9#define STREAMSIZE (64 * 4)10 11#define LAN966X_IS1_LOOKUPS 312#define LAN966X_IS2_LOOKUPS 213#define LAN966X_ES0_LOOKUPS 114 15#define LAN966X_STAT_ESDX_GRN_BYTES 0x30016#define LAN966X_STAT_ESDX_GRN_PKTS 0x30117#define LAN966X_STAT_ESDX_YEL_BYTES 0x30218#define LAN966X_STAT_ESDX_YEL_PKTS 0x30319 20static struct lan966x_vcap_inst {21	enum vcap_type vtype; /* type of vcap */22	int tgt_inst; /* hardware instance number */23	int lookups; /* number of lookups in this vcap type */24	int first_cid; /* first chain id in this vcap */25	int last_cid; /* last chain id in this vcap */26	int count; /* number of available addresses */27	bool ingress; /* is vcap in the ingress path */28} lan966x_vcap_inst_cfg[] = {29	{30		.vtype = VCAP_TYPE_ES0,31		.tgt_inst = 0,32		.lookups = LAN966X_ES0_LOOKUPS,33		.first_cid = LAN966X_VCAP_CID_ES0_L0,34		.last_cid = LAN966X_VCAP_CID_ES0_MAX,35		.count = 64,36	},37	{38		.vtype = VCAP_TYPE_IS1, /* IS1-0 */39		.tgt_inst = 1,40		.lookups = LAN966X_IS1_LOOKUPS,41		.first_cid = LAN966X_VCAP_CID_IS1_L0,42		.last_cid = LAN966X_VCAP_CID_IS1_MAX,43		.count = 768,44		.ingress = true,45	},46	{47		.vtype = VCAP_TYPE_IS2, /* IS2-0 */48		.tgt_inst = 2,49		.lookups = LAN966X_IS2_LOOKUPS,50		.first_cid = LAN966X_VCAP_CID_IS2_L0,51		.last_cid = LAN966X_VCAP_CID_IS2_MAX,52		.count = 256,53		.ingress = true,54	},55};56 57struct lan966x_vcap_cmd_cb {58	struct lan966x *lan966x;59	u32 instance;60};61 62static u32 lan966x_vcap_read_update_ctrl(const struct lan966x_vcap_cmd_cb *cb)63{64	return lan_rd(cb->lan966x, VCAP_UPDATE_CTRL(cb->instance));65}66 67static void lan966x_vcap_wait_update(struct lan966x *lan966x, int instance)68{69	const struct lan966x_vcap_cmd_cb cb = { .lan966x = lan966x,70						.instance = instance };71	u32 val;72 73	readx_poll_timeout(lan966x_vcap_read_update_ctrl, &cb, val,74			   (val & VCAP_UPDATE_CTRL_UPDATE_SHOT) == 0, 10,75			   100000);76}77 78static void __lan966x_vcap_range_init(struct lan966x *lan966x,79				      struct vcap_admin *admin,80				      u32 addr,81				      u32 count)82{83	lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(0) |84	       VCAP_MV_CFG_MV_SIZE_SET(count - 1),85	       lan966x, VCAP_MV_CFG(admin->tgt_inst));86 87	lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(VCAP_CMD_INITIALIZE) |88	       VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET(0) |89	       VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET(0) |90	       VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET(0) |91	       VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |92	       VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(true) |93	       VCAP_UPDATE_CTRL_UPDATE_SHOT_SET(1),94	       lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));95 96	lan966x_vcap_wait_update(lan966x, admin->tgt_inst);97}98 99static int lan966x_vcap_is1_cid_to_lookup(int cid)100{101	int lookup = 0;102 103	if (cid >= LAN966X_VCAP_CID_IS1_L1 &&104	    cid < LAN966X_VCAP_CID_IS1_L2)105		lookup = 1;106	else if (cid >= LAN966X_VCAP_CID_IS1_L2 &&107		 cid < LAN966X_VCAP_CID_IS1_MAX)108		lookup = 2;109 110	return lookup;111}112 113static int lan966x_vcap_is2_cid_to_lookup(int cid)114{115	if (cid >= LAN966X_VCAP_CID_IS2_L1 &&116	    cid < LAN966X_VCAP_CID_IS2_MAX)117		return 1;118 119	return 0;120}121 122/* Return the list of keysets for the vcap port configuration */123static int124lan966x_vcap_is1_get_port_keysets(struct net_device *ndev, int lookup,125				  struct vcap_keyset_list *keysetlist,126				  u16 l3_proto)127{128	struct lan966x_port *port = netdev_priv(ndev);129	struct lan966x *lan966x = port->lan966x;130	u32 val;131 132	val = lan_rd(lan966x, ANA_VCAP_S1_CFG(port->chip_port, lookup));133 134	/* Collect all keysets for the port in a list */135	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) {136		switch (ANA_VCAP_S1_CFG_KEY_IP4_CFG_GET(val)) {137		case VCAP_IS1_PS_IPV4_7TUPLE:138			vcap_keyset_list_add(keysetlist, VCAP_KFS_7TUPLE);139			break;140		case VCAP_IS1_PS_IPV4_5TUPLE_IP4:141			vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP4);142			break;143		case VCAP_IS1_PS_IPV4_NORMAL:144			vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL);145			break;146		}147	}148 149	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) {150		switch (ANA_VCAP_S1_CFG_KEY_IP6_CFG_GET(val)) {151		case VCAP_IS1_PS_IPV6_NORMAL:152		case VCAP_IS1_PS_IPV6_NORMAL_IP6:153			vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL);154			vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL_IP6);155			break;156		case VCAP_IS1_PS_IPV6_5TUPLE_IP6:157			vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP6);158			break;159		case VCAP_IS1_PS_IPV6_7TUPLE:160			vcap_keyset_list_add(keysetlist, VCAP_KFS_7TUPLE);161			break;162		case VCAP_IS1_PS_IPV6_5TUPLE_IP4:163			vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP4);164			break;165		case VCAP_IS1_PS_IPV6_DMAC_VID:166			vcap_keyset_list_add(keysetlist, VCAP_KFS_DMAC_VID);167			break;168		}169	}170 171	switch (ANA_VCAP_S1_CFG_KEY_OTHER_CFG_GET(val)) {172	case VCAP_IS1_PS_OTHER_7TUPLE:173		vcap_keyset_list_add(keysetlist, VCAP_KFS_7TUPLE);174		break;175	case VCAP_IS1_PS_OTHER_NORMAL:176		vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL);177		break;178	}179 180	return 0;181}182 183static int184lan966x_vcap_is2_get_port_keysets(struct net_device *dev, int lookup,185				  struct vcap_keyset_list *keysetlist,186				  u16 l3_proto)187{188	struct lan966x_port *port = netdev_priv(dev);189	struct lan966x *lan966x = port->lan966x;190	bool found = false;191	u32 val;192 193	val = lan_rd(lan966x, ANA_VCAP_S2_CFG(port->chip_port));194 195	/* Collect all keysets for the port in a list */196	if (l3_proto == ETH_P_ALL)197		vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);198 199	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_SNAP) {200		if (ANA_VCAP_S2_CFG_SNAP_DIS_GET(val) & (BIT(0) << lookup))201			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_LLC);202		else203			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_SNAP);204 205		found = true;206	}207 208	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_CFM) {209		if (ANA_VCAP_S2_CFG_OAM_DIS_GET(val) & (BIT(0) << lookup))210			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);211		else212			vcap_keyset_list_add(keysetlist, VCAP_KFS_OAM);213 214		found = true;215	}216 217	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_ARP) {218		if (ANA_VCAP_S2_CFG_ARP_DIS_GET(val) & (BIT(0) << lookup))219			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);220		else221			vcap_keyset_list_add(keysetlist, VCAP_KFS_ARP);222 223		found = true;224	}225 226	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) {227		if (ANA_VCAP_S2_CFG_IP_OTHER_DIS_GET(val) & (BIT(0) << lookup))228			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);229		else230			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);231 232		if (ANA_VCAP_S2_CFG_IP_TCPUDP_DIS_GET(val) & (BIT(0) << lookup))233			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);234		else235			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);236 237		found = true;238	}239 240	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) {241		switch (ANA_VCAP_S2_CFG_IP6_CFG_GET(val) & (0x3 << lookup)) {242		case VCAP_IS2_PS_IPV6_TCPUDP_OTHER:243			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_OTHER);244			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_TCP_UDP);245			break;246		case VCAP_IS2_PS_IPV6_STD:247			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD);248			break;249		case VCAP_IS2_PS_IPV6_IP4_TCPUDP_IP4_OTHER:250			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);251			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);252			break;253		case VCAP_IS2_PS_IPV6_MAC_ETYPE:254			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);255			break;256		}257 258		found = true;259	}260 261	if (!found)262		vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);263 264	return 0;265}266 267static enum vcap_keyfield_set268lan966x_vcap_validate_keyset(struct net_device *dev,269			     struct vcap_admin *admin,270			     struct vcap_rule *rule,271			     struct vcap_keyset_list *kslist,272			     u16 l3_proto)273{274	struct vcap_keyset_list keysetlist = {};275	enum vcap_keyfield_set keysets[10] = {};276	int lookup;277	int err;278 279	if (!kslist || kslist->cnt == 0)280		return VCAP_KFS_NO_VALUE;281 282	keysetlist.max = ARRAY_SIZE(keysets);283	keysetlist.keysets = keysets;284 285	switch (admin->vtype) {286	case VCAP_TYPE_IS1:287		lookup = lan966x_vcap_is1_cid_to_lookup(rule->vcap_chain_id);288		err = lan966x_vcap_is1_get_port_keysets(dev, lookup, &keysetlist,289							l3_proto);290		break;291	case VCAP_TYPE_IS2:292		lookup = lan966x_vcap_is2_cid_to_lookup(rule->vcap_chain_id);293		err = lan966x_vcap_is2_get_port_keysets(dev, lookup, &keysetlist,294							l3_proto);295		break;296	case VCAP_TYPE_ES0:297		return kslist->keysets[0];298	default:299		pr_err("vcap type: %s not supported\n",300		       lan966x_vcaps[admin->vtype].name);301		return VCAP_KFS_NO_VALUE;302	}303 304	if (err)305		return VCAP_KFS_NO_VALUE;306 307	/* Check if there is a match and return the match */308	for (int i = 0; i < kslist->cnt; ++i)309		for (int j = 0; j < keysetlist.cnt; ++j)310			if (kslist->keysets[i] == keysets[j])311				return kslist->keysets[i];312 313	return VCAP_KFS_NO_VALUE;314}315 316static bool lan966x_vcap_is2_is_first_chain(struct vcap_rule *rule)317{318	return (rule->vcap_chain_id >= LAN966X_VCAP_CID_IS2_L0 &&319		rule->vcap_chain_id < LAN966X_VCAP_CID_IS2_L1);320}321 322static void lan966x_vcap_is1_add_default_fields(struct lan966x_port *port,323						struct vcap_admin *admin,324						struct vcap_rule *rule)325{326	u32 value, mask;327	u32 lookup;328 329	if (vcap_rule_get_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK,330				  &value, &mask))331		vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0,332				      ~BIT(port->chip_port));333 334	lookup = lan966x_vcap_is1_cid_to_lookup(rule->vcap_chain_id);335	vcap_rule_add_key_u32(rule, VCAP_KF_LOOKUP_INDEX, lookup, 0x3);336}337 338static void lan966x_vcap_is2_add_default_fields(struct lan966x_port *port,339						struct vcap_admin *admin,340						struct vcap_rule *rule)341{342	u32 value, mask;343 344	if (vcap_rule_get_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK,345				  &value, &mask))346		vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0,347				      ~BIT(port->chip_port));348 349	if (lan966x_vcap_is2_is_first_chain(rule))350		vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,351				      VCAP_BIT_1);352	else353		vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,354				      VCAP_BIT_0);355}356 357static void lan966x_vcap_es0_add_default_fields(struct lan966x_port *port,358						struct vcap_admin *admin,359						struct vcap_rule *rule)360{361	vcap_rule_add_key_u32(rule, VCAP_KF_IF_EGR_PORT_NO,362			      port->chip_port, GENMASK(4, 0));363}364 365static void lan966x_vcap_add_default_fields(struct net_device *dev,366					    struct vcap_admin *admin,367					    struct vcap_rule *rule)368{369	struct lan966x_port *port = netdev_priv(dev);370 371	switch (admin->vtype) {372	case VCAP_TYPE_IS1:373		lan966x_vcap_is1_add_default_fields(port, admin, rule);374		break;375	case VCAP_TYPE_IS2:376		lan966x_vcap_is2_add_default_fields(port, admin, rule);377		break;378	case VCAP_TYPE_ES0:379		lan966x_vcap_es0_add_default_fields(port, admin, rule);380		break;381	default:382		pr_err("vcap type: %s not supported\n",383		       lan966x_vcaps[admin->vtype].name);384		break;385	}386}387 388static void lan966x_vcap_cache_erase(struct vcap_admin *admin)389{390	memset(admin->cache.keystream, 0, STREAMSIZE);391	memset(admin->cache.maskstream, 0, STREAMSIZE);392	memset(admin->cache.actionstream, 0, STREAMSIZE);393	memset(&admin->cache.counter, 0, sizeof(admin->cache.counter));394}395 396/* The ESDX counter is only used/incremented if the frame has been classified397 * with an ISDX > 0 (e.g by a rule in IS0).  This is not mentioned in the398 * datasheet.399 */400static void lan966x_es0_read_esdx_counter(struct lan966x *lan966x,401					  struct vcap_admin *admin, u32 id)402{403	u32 counter;404 405	id = id & 0xff; /* counter limit */406	mutex_lock(&lan966x->stats_lock);407	lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(id), lan966x, SYS_STAT_CFG);408	counter = lan_rd(lan966x, SYS_CNT(LAN966X_STAT_ESDX_GRN_PKTS)) +409		  lan_rd(lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_PKTS));410	mutex_unlock(&lan966x->stats_lock);411	if (counter)412		admin->cache.counter = counter;413}414 415static void lan966x_es0_write_esdx_counter(struct lan966x *lan966x,416					   struct vcap_admin *admin, u32 id)417{418	id = id & 0xff; /* counter limit */419 420	mutex_lock(&lan966x->stats_lock);421	lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(id), lan966x, SYS_STAT_CFG);422	lan_wr(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_GRN_BYTES));423	lan_wr(admin->cache.counter, lan966x,424	       SYS_CNT(LAN966X_STAT_ESDX_GRN_PKTS));425	lan_wr(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_BYTES));426	lan_wr(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_PKTS));427	mutex_unlock(&lan966x->stats_lock);428}429 430static void lan966x_vcap_cache_write(struct net_device *dev,431				     struct vcap_admin *admin,432				     enum vcap_selection sel,433				     u32 start,434				     u32 count)435{436	struct lan966x_port *port = netdev_priv(dev);437	struct lan966x *lan966x = port->lan966x;438	u32 *keystr, *mskstr, *actstr;439 440	keystr = &admin->cache.keystream[start];441	mskstr = &admin->cache.maskstream[start];442	actstr = &admin->cache.actionstream[start];443 444	switch (sel) {445	case VCAP_SEL_ENTRY:446		for (int i = 0; i < count; ++i) {447			lan_wr(keystr[i] & mskstr[i], lan966x,448			       VCAP_ENTRY_DAT(admin->tgt_inst, i));449			lan_wr(~mskstr[i], lan966x,450			       VCAP_MASK_DAT(admin->tgt_inst, i));451		}452		break;453	case VCAP_SEL_ACTION:454		for (int i = 0; i < count; ++i)455			lan_wr(actstr[i], lan966x,456			       VCAP_ACTION_DAT(admin->tgt_inst, i));457		break;458	case VCAP_SEL_COUNTER:459		admin->cache.sticky = admin->cache.counter > 0;460		lan_wr(admin->cache.counter, lan966x,461		       VCAP_CNT_DAT(admin->tgt_inst, 0));462 463		if (admin->vtype == VCAP_TYPE_ES0)464			lan966x_es0_write_esdx_counter(lan966x, admin, start);465		break;466	default:467		break;468	}469}470 471static void lan966x_vcap_cache_read(struct net_device *dev,472				    struct vcap_admin *admin,473				    enum vcap_selection sel,474				    u32 start,475				    u32 count)476{477	struct lan966x_port *port = netdev_priv(dev);478	struct lan966x *lan966x = port->lan966x;479	int instance = admin->tgt_inst;480	u32 *keystr, *mskstr, *actstr;481 482	keystr = &admin->cache.keystream[start];483	mskstr = &admin->cache.maskstream[start];484	actstr = &admin->cache.actionstream[start];485 486	if (sel & VCAP_SEL_ENTRY) {487		for (int i = 0; i < count; ++i) {488			keystr[i] =489				lan_rd(lan966x, VCAP_ENTRY_DAT(instance, i));490			mskstr[i] =491				~lan_rd(lan966x, VCAP_MASK_DAT(instance, i));492		}493	}494 495	if (sel & VCAP_SEL_ACTION)496		for (int i = 0; i < count; ++i)497			actstr[i] =498				lan_rd(lan966x, VCAP_ACTION_DAT(instance, i));499 500	if (sel & VCAP_SEL_COUNTER) {501		admin->cache.counter =502			lan_rd(lan966x, VCAP_CNT_DAT(instance, 0));503		admin->cache.sticky = admin->cache.counter > 0;504 505		if (admin->vtype == VCAP_TYPE_ES0)506			lan966x_es0_read_esdx_counter(lan966x, admin, start);507	}508}509 510static void lan966x_vcap_range_init(struct net_device *dev,511				    struct vcap_admin *admin,512				    u32 addr,513				    u32 count)514{515	struct lan966x_port *port = netdev_priv(dev);516	struct lan966x *lan966x = port->lan966x;517 518	__lan966x_vcap_range_init(lan966x, admin, addr, count);519}520 521static void lan966x_vcap_update(struct net_device *dev,522				struct vcap_admin *admin,523				enum vcap_command cmd,524				enum vcap_selection sel,525				u32 addr)526{527	struct lan966x_port *port = netdev_priv(dev);528	struct lan966x *lan966x = port->lan966x;529	bool clear;530 531	clear = (cmd == VCAP_CMD_INITIALIZE);532 533	lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(0) |534	       VCAP_MV_CFG_MV_SIZE_SET(0),535	       lan966x, VCAP_MV_CFG(admin->tgt_inst));536 537	lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(cmd) |538	       VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET((VCAP_SEL_ENTRY & sel) == 0) |539	       VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET((VCAP_SEL_ACTION & sel) == 0) |540	       VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET((VCAP_SEL_COUNTER & sel) == 0) |541	       VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |542	       VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(clear) |543	       VCAP_UPDATE_CTRL_UPDATE_SHOT,544	       lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));545 546	lan966x_vcap_wait_update(lan966x, admin->tgt_inst);547}548 549static void lan966x_vcap_move(struct net_device *dev,550			      struct vcap_admin *admin,551			      u32 addr, int offset, int count)552{553	struct lan966x_port *port = netdev_priv(dev);554	struct lan966x *lan966x = port->lan966x;555	enum vcap_command cmd;556	u16 mv_num_pos;557	u16 mv_size;558 559	mv_size = count - 1;560	if (offset > 0) {561		mv_num_pos = offset - 1;562		cmd = VCAP_CMD_MOVE_DOWN;563	} else {564		mv_num_pos = -offset - 1;565		cmd = VCAP_CMD_MOVE_UP;566	}567 568	lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(mv_num_pos) |569	       VCAP_MV_CFG_MV_SIZE_SET(mv_size),570	       lan966x, VCAP_MV_CFG(admin->tgt_inst));571 572	lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(cmd) |573	       VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET(0) |574	       VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET(0) |575	       VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET(0) |576	       VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |577	       VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(false) |578	       VCAP_UPDATE_CTRL_UPDATE_SHOT,579	       lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));580 581	lan966x_vcap_wait_update(lan966x, admin->tgt_inst);582}583 584static const struct vcap_operations lan966x_vcap_ops = {585	.validate_keyset = lan966x_vcap_validate_keyset,586	.add_default_fields = lan966x_vcap_add_default_fields,587	.cache_erase = lan966x_vcap_cache_erase,588	.cache_write = lan966x_vcap_cache_write,589	.cache_read = lan966x_vcap_cache_read,590	.init = lan966x_vcap_range_init,591	.update = lan966x_vcap_update,592	.move = lan966x_vcap_move,593	.port_info = lan966x_vcap_port_info,594};595 596static void lan966x_vcap_admin_free(struct vcap_admin *admin)597{598	if (!admin)599		return;600 601	kfree(admin->cache.keystream);602	kfree(admin->cache.maskstream);603	kfree(admin->cache.actionstream);604	mutex_destroy(&admin->lock);605	kfree(admin);606}607 608static struct vcap_admin *609lan966x_vcap_admin_alloc(struct lan966x *lan966x, struct vcap_control *ctrl,610			 const struct lan966x_vcap_inst *cfg)611{612	struct vcap_admin *admin;613 614	admin = kzalloc(sizeof(*admin), GFP_KERNEL);615	if (!admin)616		return ERR_PTR(-ENOMEM);617 618	mutex_init(&admin->lock);619	INIT_LIST_HEAD(&admin->list);620	INIT_LIST_HEAD(&admin->rules);621	INIT_LIST_HEAD(&admin->enabled);622 623	admin->vtype = cfg->vtype;624	admin->vinst = 0;625	admin->ingress = cfg->ingress;626	admin->w32be = true;627	admin->tgt_inst = cfg->tgt_inst;628 629	admin->lookups = cfg->lookups;630	admin->lookups_per_instance = cfg->lookups;631 632	admin->first_cid = cfg->first_cid;633	admin->last_cid = cfg->last_cid;634 635	admin->cache.keystream = kzalloc(STREAMSIZE, GFP_KERNEL);636	admin->cache.maskstream = kzalloc(STREAMSIZE, GFP_KERNEL);637	admin->cache.actionstream = kzalloc(STREAMSIZE, GFP_KERNEL);638	if (!admin->cache.keystream ||639	    !admin->cache.maskstream ||640	    !admin->cache.actionstream) {641		lan966x_vcap_admin_free(admin);642		return ERR_PTR(-ENOMEM);643	}644 645	return admin;646}647 648static void lan966x_vcap_block_init(struct lan966x *lan966x,649				    struct vcap_admin *admin,650				    struct lan966x_vcap_inst *cfg)651{652	admin->first_valid_addr = 0;653	admin->last_used_addr = cfg->count;654	admin->last_valid_addr = cfg->count - 1;655 656	lan_wr(VCAP_CORE_IDX_CORE_IDX_SET(0),657	       lan966x, VCAP_CORE_IDX(admin->tgt_inst));658	lan_wr(VCAP_CORE_MAP_CORE_MAP_SET(1),659	       lan966x, VCAP_CORE_MAP(admin->tgt_inst));660 661	__lan966x_vcap_range_init(lan966x, admin, admin->first_valid_addr,662				  admin->last_valid_addr -663					admin->first_valid_addr);664}665 666static void lan966x_vcap_port_key_deselection(struct lan966x *lan966x,667					      struct vcap_admin *admin)668{669	u32 val;670 671	switch (admin->vtype) {672	case VCAP_TYPE_IS1:673		val = ANA_VCAP_S1_CFG_KEY_IP6_CFG_SET(VCAP_IS1_PS_IPV6_5TUPLE_IP6) |674		      ANA_VCAP_S1_CFG_KEY_IP4_CFG_SET(VCAP_IS1_PS_IPV4_5TUPLE_IP4) |675		      ANA_VCAP_S1_CFG_KEY_OTHER_CFG_SET(VCAP_IS1_PS_OTHER_NORMAL);676 677		for (int p = 0; p < lan966x->num_phys_ports; ++p) {678			if (!lan966x->ports[p])679				continue;680 681			for (int l = 0; l < LAN966X_IS1_LOOKUPS; ++l)682				lan_wr(val, lan966x, ANA_VCAP_S1_CFG(p, l));683 684			lan_rmw(ANA_VCAP_CFG_S1_ENA_SET(true),685				ANA_VCAP_CFG_S1_ENA, lan966x,686				ANA_VCAP_CFG(p));687		}688 689		break;690	case VCAP_TYPE_IS2:691		for (int p = 0; p < lan966x->num_phys_ports; ++p)692			lan_wr(0, lan966x, ANA_VCAP_S2_CFG(p));693 694		break;695	case VCAP_TYPE_ES0:696		for (int p = 0; p < lan966x->num_phys_ports; ++p)697			lan_rmw(REW_PORT_CFG_ES0_EN_SET(false),698				REW_PORT_CFG_ES0_EN, lan966x,699				REW_PORT_CFG(p));700		break;701	default:702		pr_err("vcap type: %s not supported\n",703		       lan966x_vcaps[admin->vtype].name);704		break;705	}706}707 708int lan966x_vcap_init(struct lan966x *lan966x)709{710	struct lan966x_vcap_inst *cfg;711	struct vcap_control *ctrl;712	struct vcap_admin *admin;713	struct dentry *dir;714 715	ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);716	if (!ctrl)717		return -ENOMEM;718 719	ctrl->vcaps = lan966x_vcaps;720	ctrl->stats = &lan966x_vcap_stats;721	ctrl->ops = &lan966x_vcap_ops;722 723	INIT_LIST_HEAD(&ctrl->list);724	for (int i = 0; i < ARRAY_SIZE(lan966x_vcap_inst_cfg); ++i) {725		cfg = &lan966x_vcap_inst_cfg[i];726 727		admin = lan966x_vcap_admin_alloc(lan966x, ctrl, cfg);728		if (IS_ERR(admin))729			return PTR_ERR(admin);730 731		lan966x_vcap_block_init(lan966x, admin, cfg);732		lan966x_vcap_port_key_deselection(lan966x, admin);733 734		list_add_tail(&admin->list, &ctrl->list);735	}736 737	dir = vcap_debugfs(lan966x->dev, lan966x->debugfs_root, ctrl);738	for (int p = 0; p < lan966x->num_phys_ports; ++p) {739		if (lan966x->ports[p]) {740			vcap_port_debugfs(lan966x->dev, dir, ctrl,741					  lan966x->ports[p]->dev);742 743			lan_rmw(ANA_VCAP_S2_CFG_ENA_SET(true),744				ANA_VCAP_S2_CFG_ENA, lan966x,745				ANA_VCAP_S2_CFG(lan966x->ports[p]->chip_port));746 747			lan_rmw(ANA_VCAP_CFG_S1_ENA_SET(true),748				ANA_VCAP_CFG_S1_ENA, lan966x,749				ANA_VCAP_CFG(lan966x->ports[p]->chip_port));750 751			lan_rmw(REW_PORT_CFG_ES0_EN_SET(true),752				REW_PORT_CFG_ES0_EN, lan966x,753				REW_PORT_CFG(lan966x->ports[p]->chip_port));754		}755	}756 757	/* Statistics: Use ESDX from ES0 if hit, otherwise no counting */758	lan_rmw(REW_STAT_CFG_STAT_MODE_SET(1),759		REW_STAT_CFG_STAT_MODE, lan966x,760		REW_STAT_CFG);761 762	lan966x->vcap_ctrl = ctrl;763 764	return 0;765}766 767void lan966x_vcap_deinit(struct lan966x *lan966x)768{769	struct vcap_admin *admin, *admin_next;770	struct vcap_control *ctrl;771 772	ctrl = lan966x->vcap_ctrl;773	if (!ctrl)774		return;775 776	list_for_each_entry_safe(admin, admin_next, &ctrl->list, list) {777		lan966x_vcap_port_key_deselection(lan966x, admin);778		vcap_del_rules(ctrl, admin);779		list_del(&admin->list);780		lan966x_vcap_admin_free(admin);781	}782 783	kfree(ctrl);784}785