xref: /openbmc/linux/drivers/net/ethernet/microchip/lan966x/lan966x_vcap_impl.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
1b0531225SHoratiu Vultur // SPDX-License-Identifier: GPL-2.0+
2b0531225SHoratiu Vultur 
3b0531225SHoratiu Vultur #include "lan966x_main.h"
439bedc16SHoratiu Vultur #include "lan966x_vcap_ag_api.h"
5b0531225SHoratiu Vultur #include "vcap_api.h"
63643abd6SHoratiu Vultur #include "vcap_api_client.h"
794281484SHoratiu Vultur #include "vcap_api_debugfs.h"
83643abd6SHoratiu Vultur 
93643abd6SHoratiu Vultur #define STREAMSIZE (64 * 4)
103643abd6SHoratiu Vultur 
11*a4d9b3ecSHoratiu Vultur #define LAN966X_IS1_LOOKUPS 3
123643abd6SHoratiu Vultur #define LAN966X_IS2_LOOKUPS 2
133643abd6SHoratiu Vultur #define LAN966X_ES0_LOOKUPS 1
143643abd6SHoratiu Vultur 
153643abd6SHoratiu Vultur #define LAN966X_STAT_ESDX_GRN_BYTES 0x300
163643abd6SHoratiu Vultur #define LAN966X_STAT_ESDX_GRN_PKTS 0x301
173643abd6SHoratiu Vultur #define LAN966X_STAT_ESDX_YEL_BYTES 0x302
183643abd6SHoratiu Vultur #define LAN966X_STAT_ESDX_YEL_PKTS 0x303
193643abd6SHoratiu Vultur 
203643abd6SHoratiu Vultur static struct lan966x_vcap_inst {
21e7e3f514SSteen Hegelund 	enum vcap_type vtype; /* type of vcap */
223643abd6SHoratiu Vultur 	int tgt_inst; /* hardware instance number */
233643abd6SHoratiu Vultur 	int lookups; /* number of lookups in this vcap type */
24*a4d9b3ecSHoratiu Vultur 	int first_cid; /* first chain id in this vcap */
25*a4d9b3ecSHoratiu Vultur 	int last_cid; /* last chain id in this vcap */
26*a4d9b3ecSHoratiu Vultur 	int count; /* number of available addresses */
27*a4d9b3ecSHoratiu Vultur 	bool ingress; /* is vcap in the ingress path */
28*a4d9b3ecSHoratiu Vultur } lan966x_vcap_inst_cfg[] = {
29*a4d9b3ecSHoratiu Vultur 	{
30*a4d9b3ecSHoratiu Vultur 		.vtype = VCAP_TYPE_ES0,
31*a4d9b3ecSHoratiu Vultur 		.tgt_inst = 0,
32*a4d9b3ecSHoratiu Vultur 		.lookups = LAN966X_ES0_LOOKUPS,
333643abd6SHoratiu Vultur 		.first_cid = LAN966X_VCAP_CID_ES0_L0,
343643abd6SHoratiu Vultur 		.last_cid = LAN966X_VCAP_CID_ES0_MAX,
353643abd6SHoratiu Vultur 		.count = 64,
363643abd6SHoratiu Vultur 	},
373643abd6SHoratiu Vultur 	{
383643abd6SHoratiu Vultur 		.vtype = VCAP_TYPE_IS1, /* IS1-0 */
39e7e3f514SSteen Hegelund 		.tgt_inst = 1,
403643abd6SHoratiu Vultur 		.lookups = LAN966X_IS1_LOOKUPS,
413643abd6SHoratiu Vultur 		.first_cid = LAN966X_VCAP_CID_IS1_L0,
423643abd6SHoratiu Vultur 		.last_cid = LAN966X_VCAP_CID_IS1_MAX,
433643abd6SHoratiu Vultur 		.count = 768,
443643abd6SHoratiu Vultur 		.ingress = true,
453643abd6SHoratiu Vultur 	},
463643abd6SHoratiu Vultur 	{
473643abd6SHoratiu Vultur 		.vtype = VCAP_TYPE_IS2, /* IS2-0 */
483643abd6SHoratiu Vultur 		.tgt_inst = 2,
493643abd6SHoratiu Vultur 		.lookups = LAN966X_IS2_LOOKUPS,
503643abd6SHoratiu Vultur 		.first_cid = LAN966X_VCAP_CID_IS2_L0,
513643abd6SHoratiu Vultur 		.last_cid = LAN966X_VCAP_CID_IS2_MAX,
523643abd6SHoratiu Vultur 		.count = 256,
533643abd6SHoratiu Vultur 		.ingress = true,
543643abd6SHoratiu Vultur 	},
553643abd6SHoratiu Vultur };
563643abd6SHoratiu Vultur 
573643abd6SHoratiu Vultur struct lan966x_vcap_cmd_cb {
583643abd6SHoratiu Vultur 	struct lan966x *lan966x;
593643abd6SHoratiu Vultur 	u32 instance;
603643abd6SHoratiu Vultur };
613643abd6SHoratiu Vultur 
lan966x_vcap_read_update_ctrl(const struct lan966x_vcap_cmd_cb * cb)623643abd6SHoratiu Vultur static u32 lan966x_vcap_read_update_ctrl(const struct lan966x_vcap_cmd_cb *cb)
633643abd6SHoratiu Vultur {
643643abd6SHoratiu Vultur 	return lan_rd(cb->lan966x, VCAP_UPDATE_CTRL(cb->instance));
653643abd6SHoratiu Vultur }
663643abd6SHoratiu Vultur 
lan966x_vcap_wait_update(struct lan966x * lan966x,int instance)673643abd6SHoratiu Vultur static void lan966x_vcap_wait_update(struct lan966x *lan966x, int instance)
683643abd6SHoratiu Vultur {
693643abd6SHoratiu Vultur 	const struct lan966x_vcap_cmd_cb cb = { .lan966x = lan966x,
703643abd6SHoratiu Vultur 						.instance = instance };
713643abd6SHoratiu Vultur 	u32 val;
723643abd6SHoratiu Vultur 
733643abd6SHoratiu Vultur 	readx_poll_timeout(lan966x_vcap_read_update_ctrl, &cb, val,
743643abd6SHoratiu Vultur 			   (val & VCAP_UPDATE_CTRL_UPDATE_SHOT) == 0, 10,
753643abd6SHoratiu Vultur 			   100000);
763643abd6SHoratiu Vultur }
773643abd6SHoratiu Vultur 
__lan966x_vcap_range_init(struct lan966x * lan966x,struct vcap_admin * admin,u32 addr,u32 count)783643abd6SHoratiu Vultur static void __lan966x_vcap_range_init(struct lan966x *lan966x,
793643abd6SHoratiu Vultur 				      struct vcap_admin *admin,
803643abd6SHoratiu Vultur 				      u32 addr,
813643abd6SHoratiu Vultur 				      u32 count)
823643abd6SHoratiu Vultur {
833643abd6SHoratiu Vultur 	lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(0) |
843643abd6SHoratiu Vultur 	       VCAP_MV_CFG_MV_SIZE_SET(count - 1),
85*a4d9b3ecSHoratiu Vultur 	       lan966x, VCAP_MV_CFG(admin->tgt_inst));
86*a4d9b3ecSHoratiu Vultur 
87*a4d9b3ecSHoratiu Vultur 	lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(VCAP_CMD_INITIALIZE) |
88*a4d9b3ecSHoratiu Vultur 	       VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET(0) |
89*a4d9b3ecSHoratiu Vultur 	       VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET(0) |
90*a4d9b3ecSHoratiu Vultur 	       VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET(0) |
91*a4d9b3ecSHoratiu Vultur 	       VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |
92*a4d9b3ecSHoratiu Vultur 	       VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(true) |
93*a4d9b3ecSHoratiu Vultur 	       VCAP_UPDATE_CTRL_UPDATE_SHOT_SET(1),
94*a4d9b3ecSHoratiu Vultur 	       lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));
95*a4d9b3ecSHoratiu Vultur 
96*a4d9b3ecSHoratiu Vultur 	lan966x_vcap_wait_update(lan966x, admin->tgt_inst);
97*a4d9b3ecSHoratiu Vultur }
98*a4d9b3ecSHoratiu Vultur 
lan966x_vcap_is1_cid_to_lookup(int cid)99*a4d9b3ecSHoratiu Vultur static int lan966x_vcap_is1_cid_to_lookup(int cid)
1004426b78cSHoratiu Vultur {
1014426b78cSHoratiu Vultur 	int lookup = 0;
1024426b78cSHoratiu Vultur 
1034426b78cSHoratiu Vultur 	if (cid >= LAN966X_VCAP_CID_IS1_L1 &&
1044426b78cSHoratiu Vultur 	    cid < LAN966X_VCAP_CID_IS1_L2)
1054426b78cSHoratiu Vultur 		lookup = 1;
1064426b78cSHoratiu Vultur 	else if (cid >= LAN966X_VCAP_CID_IS1_L2 &&
1074426b78cSHoratiu Vultur 		 cid < LAN966X_VCAP_CID_IS1_MAX)
108*a4d9b3ecSHoratiu Vultur 		lookup = 2;
109*a4d9b3ecSHoratiu Vultur 
110*a4d9b3ecSHoratiu Vultur 	return lookup;
111*a4d9b3ecSHoratiu Vultur }
112*a4d9b3ecSHoratiu Vultur 
lan966x_vcap_is2_cid_to_lookup(int cid)113*a4d9b3ecSHoratiu Vultur static int lan966x_vcap_is2_cid_to_lookup(int cid)
114*a4d9b3ecSHoratiu Vultur {
115*a4d9b3ecSHoratiu Vultur 	if (cid >= LAN966X_VCAP_CID_IS2_L1 &&
116*a4d9b3ecSHoratiu Vultur 	    cid < LAN966X_VCAP_CID_IS2_MAX)
117*a4d9b3ecSHoratiu Vultur 		return 1;
118*a4d9b3ecSHoratiu Vultur 
119*a4d9b3ecSHoratiu Vultur 	return 0;
120*a4d9b3ecSHoratiu Vultur }
121*a4d9b3ecSHoratiu Vultur 
122*a4d9b3ecSHoratiu Vultur /* Return the list of keysets for the vcap port configuration */
123*a4d9b3ecSHoratiu Vultur static int
lan966x_vcap_is1_get_port_keysets(struct net_device * ndev,int lookup,struct vcap_keyset_list * keysetlist,u16 l3_proto)124*a4d9b3ecSHoratiu Vultur lan966x_vcap_is1_get_port_keysets(struct net_device *ndev, int lookup,
125*a4d9b3ecSHoratiu Vultur 				  struct vcap_keyset_list *keysetlist,
126*a4d9b3ecSHoratiu Vultur 				  u16 l3_proto)
127*a4d9b3ecSHoratiu Vultur {
128*a4d9b3ecSHoratiu Vultur 	struct lan966x_port *port = netdev_priv(ndev);
129*a4d9b3ecSHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
130*a4d9b3ecSHoratiu Vultur 	u32 val;
131*a4d9b3ecSHoratiu Vultur 
132*a4d9b3ecSHoratiu Vultur 	val = lan_rd(lan966x, ANA_VCAP_S1_CFG(port->chip_port, lookup));
133*a4d9b3ecSHoratiu Vultur 
134*a4d9b3ecSHoratiu Vultur 	/* Collect all keysets for the port in a list */
135*a4d9b3ecSHoratiu Vultur 	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) {
136*a4d9b3ecSHoratiu Vultur 		switch (ANA_VCAP_S1_CFG_KEY_IP4_CFG_GET(val)) {
137*a4d9b3ecSHoratiu Vultur 		case VCAP_IS1_PS_IPV4_7TUPLE:
138*a4d9b3ecSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_7TUPLE);
139*a4d9b3ecSHoratiu Vultur 			break;
140*a4d9b3ecSHoratiu Vultur 		case VCAP_IS1_PS_IPV4_5TUPLE_IP4:
141*a4d9b3ecSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP4);
142*a4d9b3ecSHoratiu Vultur 			break;
143*a4d9b3ecSHoratiu Vultur 		case VCAP_IS1_PS_IPV4_NORMAL:
144*a4d9b3ecSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL);
145*a4d9b3ecSHoratiu Vultur 			break;
146*a4d9b3ecSHoratiu Vultur 		}
147*a4d9b3ecSHoratiu Vultur 	}
148*a4d9b3ecSHoratiu Vultur 
149*a4d9b3ecSHoratiu Vultur 	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) {
150*a4d9b3ecSHoratiu Vultur 		switch (ANA_VCAP_S1_CFG_KEY_IP6_CFG_GET(val)) {
151*a4d9b3ecSHoratiu Vultur 		case VCAP_IS1_PS_IPV6_NORMAL:
152*a4d9b3ecSHoratiu Vultur 		case VCAP_IS1_PS_IPV6_NORMAL_IP6:
153*a4d9b3ecSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL);
154*a4d9b3ecSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL_IP6);
155*a4d9b3ecSHoratiu Vultur 			break;
156*a4d9b3ecSHoratiu Vultur 		case VCAP_IS1_PS_IPV6_5TUPLE_IP6:
157*a4d9b3ecSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP6);
158*a4d9b3ecSHoratiu Vultur 			break;
159*a4d9b3ecSHoratiu Vultur 		case VCAP_IS1_PS_IPV6_7TUPLE:
160*a4d9b3ecSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_7TUPLE);
161*a4d9b3ecSHoratiu Vultur 			break;
162*a4d9b3ecSHoratiu Vultur 		case VCAP_IS1_PS_IPV6_5TUPLE_IP4:
163*a4d9b3ecSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_5TUPLE_IP4);
164*a4d9b3ecSHoratiu Vultur 			break;
165*a4d9b3ecSHoratiu Vultur 		case VCAP_IS1_PS_IPV6_DMAC_VID:
166*a4d9b3ecSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_DMAC_VID);
167*a4d9b3ecSHoratiu Vultur 			break;
168*a4d9b3ecSHoratiu Vultur 		}
1694426b78cSHoratiu Vultur 	}
1704426b78cSHoratiu Vultur 
1714426b78cSHoratiu Vultur 	switch (ANA_VCAP_S1_CFG_KEY_OTHER_CFG_GET(val)) {
1724426b78cSHoratiu Vultur 	case VCAP_IS1_PS_OTHER_7TUPLE:
1734426b78cSHoratiu Vultur 		vcap_keyset_list_add(keysetlist, VCAP_KFS_7TUPLE);
1744426b78cSHoratiu Vultur 		break;
1754426b78cSHoratiu Vultur 	case VCAP_IS1_PS_OTHER_NORMAL:
1764426b78cSHoratiu Vultur 		vcap_keyset_list_add(keysetlist, VCAP_KFS_NORMAL);
1774426b78cSHoratiu Vultur 		break;
1784426b78cSHoratiu Vultur 	}
1794426b78cSHoratiu Vultur 
1804426b78cSHoratiu Vultur 	return 0;
1814426b78cSHoratiu Vultur }
1824426b78cSHoratiu Vultur 
1834426b78cSHoratiu Vultur static int
lan966x_vcap_is2_get_port_keysets(struct net_device * dev,int lookup,struct vcap_keyset_list * keysetlist,u16 l3_proto)1844426b78cSHoratiu Vultur lan966x_vcap_is2_get_port_keysets(struct net_device *dev, int lookup,
1854426b78cSHoratiu Vultur 				  struct vcap_keyset_list *keysetlist,
1864426b78cSHoratiu Vultur 				  u16 l3_proto)
1874426b78cSHoratiu Vultur {
1884426b78cSHoratiu Vultur 	struct lan966x_port *port = netdev_priv(dev);
1894426b78cSHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
1904426b78cSHoratiu Vultur 	bool found = false;
1914426b78cSHoratiu Vultur 	u32 val;
1924426b78cSHoratiu Vultur 
1934426b78cSHoratiu Vultur 	val = lan_rd(lan966x, ANA_VCAP_S2_CFG(port->chip_port));
1944426b78cSHoratiu Vultur 
1954426b78cSHoratiu Vultur 	/* Collect all keysets for the port in a list */
1964426b78cSHoratiu Vultur 	if (l3_proto == ETH_P_ALL)
1974426b78cSHoratiu Vultur 		vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
1984426b78cSHoratiu Vultur 
1994426b78cSHoratiu Vultur 	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_SNAP) {
2004426b78cSHoratiu Vultur 		if (ANA_VCAP_S2_CFG_SNAP_DIS_GET(val) & (BIT(0) << lookup))
2014426b78cSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_LLC);
2024426b78cSHoratiu Vultur 		else
2034426b78cSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_SNAP);
2044426b78cSHoratiu Vultur 
2054426b78cSHoratiu Vultur 		found = true;
2064426b78cSHoratiu Vultur 	}
2074426b78cSHoratiu Vultur 
2084426b78cSHoratiu Vultur 	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_CFM) {
2094426b78cSHoratiu Vultur 		if (ANA_VCAP_S2_CFG_OAM_DIS_GET(val) & (BIT(0) << lookup))
2104426b78cSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
2114426b78cSHoratiu Vultur 		else
2124426b78cSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_OAM);
2134426b78cSHoratiu Vultur 
2144426b78cSHoratiu Vultur 		found = true;
2154426b78cSHoratiu Vultur 	}
2164426b78cSHoratiu Vultur 
2174426b78cSHoratiu Vultur 	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_ARP) {
2184426b78cSHoratiu Vultur 		if (ANA_VCAP_S2_CFG_ARP_DIS_GET(val) & (BIT(0) << lookup))
2194426b78cSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
2204426b78cSHoratiu Vultur 		else
2214426b78cSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_ARP);
2224426b78cSHoratiu Vultur 
2234426b78cSHoratiu Vultur 		found = true;
2244426b78cSHoratiu Vultur 	}
2254426b78cSHoratiu Vultur 
2264426b78cSHoratiu Vultur 	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) {
2274426b78cSHoratiu Vultur 		if (ANA_VCAP_S2_CFG_IP_OTHER_DIS_GET(val) & (BIT(0) << lookup))
2284426b78cSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
2294426b78cSHoratiu Vultur 		else
2304426b78cSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
2314426b78cSHoratiu Vultur 
2324426b78cSHoratiu Vultur 		if (ANA_VCAP_S2_CFG_IP_TCPUDP_DIS_GET(val) & (BIT(0) << lookup))
2334426b78cSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
2344426b78cSHoratiu Vultur 		else
2354426b78cSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
2364426b78cSHoratiu Vultur 
2374426b78cSHoratiu Vultur 		found = true;
2384426b78cSHoratiu Vultur 	}
2394426b78cSHoratiu Vultur 
2404426b78cSHoratiu Vultur 	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) {
2414426b78cSHoratiu Vultur 		switch (ANA_VCAP_S2_CFG_IP6_CFG_GET(val) & (0x3 << lookup)) {
2424426b78cSHoratiu Vultur 		case VCAP_IS2_PS_IPV6_TCPUDP_OTHER:
2434426b78cSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_OTHER);
2444426b78cSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_TCP_UDP);
2454426b78cSHoratiu Vultur 			break;
2464426b78cSHoratiu Vultur 		case VCAP_IS2_PS_IPV6_STD:
2474426b78cSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD);
2484426b78cSHoratiu Vultur 			break;
2494426b78cSHoratiu Vultur 		case VCAP_IS2_PS_IPV6_IP4_TCPUDP_IP4_OTHER:
2504426b78cSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
2514426b78cSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
2524426b78cSHoratiu Vultur 			break;
2534426b78cSHoratiu Vultur 		case VCAP_IS2_PS_IPV6_MAC_ETYPE:
2544426b78cSHoratiu Vultur 			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
2554426b78cSHoratiu Vultur 			break;
2564426b78cSHoratiu Vultur 		}
2574426b78cSHoratiu Vultur 
2584426b78cSHoratiu Vultur 		found = true;
2594426b78cSHoratiu Vultur 	}
2604426b78cSHoratiu Vultur 
2614426b78cSHoratiu Vultur 	if (!found)
2624426b78cSHoratiu Vultur 		vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
2634426b78cSHoratiu Vultur 
2644426b78cSHoratiu Vultur 	return 0;
2654426b78cSHoratiu Vultur }
2664426b78cSHoratiu Vultur 
2674426b78cSHoratiu Vultur static enum vcap_keyfield_set
lan966x_vcap_validate_keyset(struct net_device * dev,struct vcap_admin * admin,struct vcap_rule * rule,struct vcap_keyset_list * kslist,u16 l3_proto)2684426b78cSHoratiu Vultur lan966x_vcap_validate_keyset(struct net_device *dev,
2694426b78cSHoratiu Vultur 			     struct vcap_admin *admin,
270*a4d9b3ecSHoratiu Vultur 			     struct vcap_rule *rule,
271*a4d9b3ecSHoratiu Vultur 			     struct vcap_keyset_list *kslist,
272*a4d9b3ecSHoratiu Vultur 			     u16 l3_proto)
273*a4d9b3ecSHoratiu Vultur {
274*a4d9b3ecSHoratiu Vultur 	struct vcap_keyset_list keysetlist = {};
275*a4d9b3ecSHoratiu Vultur 	enum vcap_keyfield_set keysets[10] = {};
276*a4d9b3ecSHoratiu Vultur 	int lookup;
277*a4d9b3ecSHoratiu Vultur 	int err;
278*a4d9b3ecSHoratiu Vultur 
2794426b78cSHoratiu Vultur 	if (!kslist || kslist->cnt == 0)
2804426b78cSHoratiu Vultur 		return VCAP_KFS_NO_VALUE;
281*a4d9b3ecSHoratiu Vultur 
282*a4d9b3ecSHoratiu Vultur 	keysetlist.max = ARRAY_SIZE(keysets);
283*a4d9b3ecSHoratiu Vultur 	keysetlist.keysets = keysets;
284*a4d9b3ecSHoratiu Vultur 
285*a4d9b3ecSHoratiu Vultur 	switch (admin->vtype) {
286*a4d9b3ecSHoratiu Vultur 	case VCAP_TYPE_IS1:
287*a4d9b3ecSHoratiu Vultur 		lookup = lan966x_vcap_is1_cid_to_lookup(rule->vcap_chain_id);
2884426b78cSHoratiu Vultur 		err = lan966x_vcap_is1_get_port_keysets(dev, lookup, &keysetlist,
2894426b78cSHoratiu Vultur 							l3_proto);
2904426b78cSHoratiu Vultur 		break;
2914426b78cSHoratiu Vultur 	case VCAP_TYPE_IS2:
2924426b78cSHoratiu Vultur 		lookup = lan966x_vcap_is2_cid_to_lookup(rule->vcap_chain_id);
2934426b78cSHoratiu Vultur 		err = lan966x_vcap_is2_get_port_keysets(dev, lookup, &keysetlist,
2944426b78cSHoratiu Vultur 							l3_proto);
2954426b78cSHoratiu Vultur 		break;
2964426b78cSHoratiu Vultur 	case VCAP_TYPE_ES0:
2974426b78cSHoratiu Vultur 		return kslist->keysets[0];
2984426b78cSHoratiu Vultur 	default:
2994426b78cSHoratiu Vultur 		pr_err("vcap type: %s not supported\n",
300*a4d9b3ecSHoratiu Vultur 		       lan966x_vcaps[admin->vtype].name);
3014426b78cSHoratiu Vultur 		return VCAP_KFS_NO_VALUE;
3024426b78cSHoratiu Vultur 	}
3034426b78cSHoratiu Vultur 
3044426b78cSHoratiu Vultur 	if (err)
3054426b78cSHoratiu Vultur 		return VCAP_KFS_NO_VALUE;
306*a4d9b3ecSHoratiu Vultur 
3074426b78cSHoratiu Vultur 	/* Check if there is a match and return the match */
3084426b78cSHoratiu Vultur 	for (int i = 0; i < kslist->cnt; ++i)
3094426b78cSHoratiu Vultur 		for (int j = 0; j < keysetlist.cnt; ++j)
310*a4d9b3ecSHoratiu Vultur 			if (kslist->keysets[i] == keysets[j])
311*a4d9b3ecSHoratiu Vultur 				return kslist->keysets[i];
312*a4d9b3ecSHoratiu Vultur 
313*a4d9b3ecSHoratiu Vultur 	return VCAP_KFS_NO_VALUE;
314*a4d9b3ecSHoratiu Vultur }
315*a4d9b3ecSHoratiu Vultur 
lan966x_vcap_is2_is_first_chain(struct vcap_rule * rule)316*a4d9b3ecSHoratiu Vultur static bool lan966x_vcap_is2_is_first_chain(struct vcap_rule *rule)
317*a4d9b3ecSHoratiu Vultur {
318*a4d9b3ecSHoratiu Vultur 	return (rule->vcap_chain_id >= LAN966X_VCAP_CID_IS2_L0 &&
319*a4d9b3ecSHoratiu Vultur 		rule->vcap_chain_id < LAN966X_VCAP_CID_IS2_L1);
320*a4d9b3ecSHoratiu Vultur }
321*a4d9b3ecSHoratiu Vultur 
lan966x_vcap_is1_add_default_fields(struct lan966x_port * port,struct vcap_admin * admin,struct vcap_rule * rule)322*a4d9b3ecSHoratiu Vultur static void lan966x_vcap_is1_add_default_fields(struct lan966x_port *port,
323*a4d9b3ecSHoratiu Vultur 						struct vcap_admin *admin,
324*a4d9b3ecSHoratiu Vultur 						struct vcap_rule *rule)
325*a4d9b3ecSHoratiu Vultur {
32672df3489SHoratiu Vultur 	u32 value, mask;
3274426b78cSHoratiu Vultur 	u32 lookup;
32872df3489SHoratiu Vultur 
32972df3489SHoratiu Vultur 	if (vcap_rule_get_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK,
3304426b78cSHoratiu Vultur 				  &value, &mask))
3314426b78cSHoratiu Vultur 		vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0,
3324426b78cSHoratiu Vultur 				      ~BIT(port->chip_port));
333*a4d9b3ecSHoratiu Vultur 
3344426b78cSHoratiu Vultur 	lookup = lan966x_vcap_is1_cid_to_lookup(rule->vcap_chain_id);
3354426b78cSHoratiu Vultur 	vcap_rule_add_key_u32(rule, VCAP_KF_LOOKUP_INDEX, lookup, 0x3);
3364426b78cSHoratiu Vultur }
3374426b78cSHoratiu Vultur 
lan966x_vcap_is2_add_default_fields(struct lan966x_port * port,struct vcap_admin * admin,struct vcap_rule * rule)3384426b78cSHoratiu Vultur static void lan966x_vcap_is2_add_default_fields(struct lan966x_port *port,
3394426b78cSHoratiu Vultur 						struct vcap_admin *admin,
3404426b78cSHoratiu Vultur 						struct vcap_rule *rule)
341*a4d9b3ecSHoratiu Vultur {
342*a4d9b3ecSHoratiu Vultur 	u32 value, mask;
343*a4d9b3ecSHoratiu Vultur 
344*a4d9b3ecSHoratiu Vultur 	if (vcap_rule_get_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK,
345*a4d9b3ecSHoratiu Vultur 				  &value, &mask))
346*a4d9b3ecSHoratiu Vultur 		vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0,
347*a4d9b3ecSHoratiu Vultur 				      ~BIT(port->chip_port));
348*a4d9b3ecSHoratiu Vultur 
349*a4d9b3ecSHoratiu Vultur 	if (lan966x_vcap_is2_is_first_chain(rule))
350*a4d9b3ecSHoratiu Vultur 		vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,
351*a4d9b3ecSHoratiu Vultur 				      VCAP_BIT_1);
352*a4d9b3ecSHoratiu Vultur 	else
353*a4d9b3ecSHoratiu Vultur 		vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS,
354*a4d9b3ecSHoratiu Vultur 				      VCAP_BIT_0);
355*a4d9b3ecSHoratiu Vultur }
356*a4d9b3ecSHoratiu Vultur 
lan966x_vcap_es0_add_default_fields(struct lan966x_port * port,struct vcap_admin * admin,struct vcap_rule * rule)357*a4d9b3ecSHoratiu Vultur static void lan966x_vcap_es0_add_default_fields(struct lan966x_port *port,
358*a4d9b3ecSHoratiu Vultur 						struct vcap_admin *admin,
359*a4d9b3ecSHoratiu Vultur 						struct vcap_rule *rule)
360*a4d9b3ecSHoratiu Vultur {
3614426b78cSHoratiu Vultur 	vcap_rule_add_key_u32(rule, VCAP_KF_IF_EGR_PORT_NO,
3624426b78cSHoratiu Vultur 			      port->chip_port, GENMASK(4, 0));
3634426b78cSHoratiu Vultur }
3644426b78cSHoratiu Vultur 
lan966x_vcap_add_default_fields(struct net_device * dev,struct vcap_admin * admin,struct vcap_rule * rule)3654426b78cSHoratiu Vultur static void lan966x_vcap_add_default_fields(struct net_device *dev,
3664426b78cSHoratiu Vultur 					    struct vcap_admin *admin,
3674426b78cSHoratiu Vultur 					    struct vcap_rule *rule)
3684426b78cSHoratiu Vultur {
3694426b78cSHoratiu Vultur 	struct lan966x_port *port = netdev_priv(dev);
3704426b78cSHoratiu Vultur 
3714426b78cSHoratiu Vultur 	switch (admin->vtype) {
3724426b78cSHoratiu Vultur 	case VCAP_TYPE_IS1:
3734426b78cSHoratiu Vultur 		lan966x_vcap_is1_add_default_fields(port, admin, rule);
3744426b78cSHoratiu Vultur 		break;
3754426b78cSHoratiu Vultur 	case VCAP_TYPE_IS2:
3764426b78cSHoratiu Vultur 		lan966x_vcap_is2_add_default_fields(port, admin, rule);
3774426b78cSHoratiu Vultur 		break;
3784426b78cSHoratiu Vultur 	case VCAP_TYPE_ES0:
3794426b78cSHoratiu Vultur 		lan966x_vcap_es0_add_default_fields(port, admin, rule);
3804426b78cSHoratiu Vultur 		break;
3814426b78cSHoratiu Vultur 	default:
3824426b78cSHoratiu Vultur 		pr_err("vcap type: %s not supported\n",
3834426b78cSHoratiu Vultur 		       lan966x_vcaps[admin->vtype].name);
3844426b78cSHoratiu Vultur 		break;
3854426b78cSHoratiu Vultur 	}
3864426b78cSHoratiu Vultur }
3874426b78cSHoratiu Vultur 
lan966x_vcap_cache_erase(struct vcap_admin * admin)3884426b78cSHoratiu Vultur static void lan966x_vcap_cache_erase(struct vcap_admin *admin)
3894426b78cSHoratiu Vultur {
3904426b78cSHoratiu Vultur 	memset(admin->cache.keystream, 0, STREAMSIZE);
3914426b78cSHoratiu Vultur 	memset(admin->cache.maskstream, 0, STREAMSIZE);
3924426b78cSHoratiu Vultur 	memset(admin->cache.actionstream, 0, STREAMSIZE);
3934426b78cSHoratiu Vultur 	memset(&admin->cache.counter, 0, sizeof(admin->cache.counter));
3944426b78cSHoratiu Vultur }
3954426b78cSHoratiu Vultur 
3964426b78cSHoratiu Vultur /* The ESDX counter is only used/incremented if the frame has been classified
3974426b78cSHoratiu Vultur  * with an ISDX > 0 (e.g by a rule in IS0).  This is not mentioned in the
3984426b78cSHoratiu Vultur  * datasheet.
3994426b78cSHoratiu Vultur  */
lan966x_es0_read_esdx_counter(struct lan966x * lan966x,struct vcap_admin * admin,u32 id)4004426b78cSHoratiu Vultur static void lan966x_es0_read_esdx_counter(struct lan966x *lan966x,
4014426b78cSHoratiu Vultur 					  struct vcap_admin *admin, u32 id)
4024426b78cSHoratiu Vultur {
4034426b78cSHoratiu Vultur 	u32 counter;
4044426b78cSHoratiu Vultur 
4054426b78cSHoratiu Vultur 	id = id & 0xff; /* counter limit */
4064426b78cSHoratiu Vultur 	mutex_lock(&lan966x->stats_lock);
4074426b78cSHoratiu Vultur 	lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(id), lan966x, SYS_STAT_CFG);
4084426b78cSHoratiu Vultur 	counter = lan_rd(lan966x, SYS_CNT(LAN966X_STAT_ESDX_GRN_PKTS)) +
4094426b78cSHoratiu Vultur 		  lan_rd(lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_PKTS));
4104426b78cSHoratiu Vultur 	mutex_unlock(&lan966x->stats_lock);
4114426b78cSHoratiu Vultur 	if (counter)
4124426b78cSHoratiu Vultur 		admin->cache.counter = counter;
4134426b78cSHoratiu Vultur }
4144426b78cSHoratiu Vultur 
lan966x_es0_write_esdx_counter(struct lan966x * lan966x,struct vcap_admin * admin,u32 id)4154426b78cSHoratiu Vultur static void lan966x_es0_write_esdx_counter(struct lan966x *lan966x,
4164426b78cSHoratiu Vultur 					   struct vcap_admin *admin, u32 id)
4174426b78cSHoratiu Vultur {
4184426b78cSHoratiu Vultur 	id = id & 0xff; /* counter limit */
4194426b78cSHoratiu Vultur 
4204426b78cSHoratiu Vultur 	mutex_lock(&lan966x->stats_lock);
4214426b78cSHoratiu Vultur 	lan_wr(SYS_STAT_CFG_STAT_VIEW_SET(id), lan966x, SYS_STAT_CFG);
4224426b78cSHoratiu Vultur 	lan_wr(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_GRN_BYTES));
4234426b78cSHoratiu Vultur 	lan_wr(admin->cache.counter, lan966x,
4244426b78cSHoratiu Vultur 	       SYS_CNT(LAN966X_STAT_ESDX_GRN_PKTS));
4254426b78cSHoratiu Vultur 	lan_wr(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_BYTES));
4264426b78cSHoratiu Vultur 	lan_wr(0, lan966x, SYS_CNT(LAN966X_STAT_ESDX_YEL_PKTS));
4274426b78cSHoratiu Vultur 	mutex_unlock(&lan966x->stats_lock);
4284426b78cSHoratiu Vultur }
4294426b78cSHoratiu Vultur 
lan966x_vcap_cache_write(struct net_device * dev,struct vcap_admin * admin,enum vcap_selection sel,u32 start,u32 count)4304426b78cSHoratiu Vultur static void lan966x_vcap_cache_write(struct net_device *dev,
4314426b78cSHoratiu Vultur 				     struct vcap_admin *admin,
4324426b78cSHoratiu Vultur 				     enum vcap_selection sel,
4334426b78cSHoratiu Vultur 				     u32 start,
4344426b78cSHoratiu Vultur 				     u32 count)
4354426b78cSHoratiu Vultur {
4364426b78cSHoratiu Vultur 	struct lan966x_port *port = netdev_priv(dev);
4374426b78cSHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
4384426b78cSHoratiu Vultur 	u32 *keystr, *mskstr, *actstr;
4394426b78cSHoratiu Vultur 
4404426b78cSHoratiu Vultur 	keystr = &admin->cache.keystream[start];
4414426b78cSHoratiu Vultur 	mskstr = &admin->cache.maskstream[start];
4424426b78cSHoratiu Vultur 	actstr = &admin->cache.actionstream[start];
4434426b78cSHoratiu Vultur 
4444426b78cSHoratiu Vultur 	switch (sel) {
4454426b78cSHoratiu Vultur 	case VCAP_SEL_ENTRY:
4464426b78cSHoratiu Vultur 		for (int i = 0; i < count; ++i) {
4474426b78cSHoratiu Vultur 			lan_wr(keystr[i] & mskstr[i], lan966x,
4484426b78cSHoratiu Vultur 			       VCAP_ENTRY_DAT(admin->tgt_inst, i));
4494426b78cSHoratiu Vultur 			lan_wr(~mskstr[i], lan966x,
4504426b78cSHoratiu Vultur 			       VCAP_MASK_DAT(admin->tgt_inst, i));
4514426b78cSHoratiu Vultur 		}
4524426b78cSHoratiu Vultur 		break;
4534426b78cSHoratiu Vultur 	case VCAP_SEL_ACTION:
4544426b78cSHoratiu Vultur 		for (int i = 0; i < count; ++i)
4554426b78cSHoratiu Vultur 			lan_wr(actstr[i], lan966x,
4564426b78cSHoratiu Vultur 			       VCAP_ACTION_DAT(admin->tgt_inst, i));
4574426b78cSHoratiu Vultur 		break;
4584426b78cSHoratiu Vultur 	case VCAP_SEL_COUNTER:
4594426b78cSHoratiu Vultur 		admin->cache.sticky = admin->cache.counter > 0;
4604426b78cSHoratiu Vultur 		lan_wr(admin->cache.counter, lan966x,
4614426b78cSHoratiu Vultur 		       VCAP_CNT_DAT(admin->tgt_inst, 0));
4624426b78cSHoratiu Vultur 
4634426b78cSHoratiu Vultur 		if (admin->vtype == VCAP_TYPE_ES0)
4644426b78cSHoratiu Vultur 			lan966x_es0_write_esdx_counter(lan966x, admin, start);
4654426b78cSHoratiu Vultur 		break;
4664426b78cSHoratiu Vultur 	default:
4674426b78cSHoratiu Vultur 		break;
4684426b78cSHoratiu Vultur 	}
4694426b78cSHoratiu Vultur }
4704426b78cSHoratiu Vultur 
lan966x_vcap_cache_read(struct net_device * dev,struct vcap_admin * admin,enum vcap_selection sel,u32 start,u32 count)4714426b78cSHoratiu Vultur static void lan966x_vcap_cache_read(struct net_device *dev,
4724426b78cSHoratiu Vultur 				    struct vcap_admin *admin,
4734426b78cSHoratiu Vultur 				    enum vcap_selection sel,
4744426b78cSHoratiu Vultur 				    u32 start,
4754426b78cSHoratiu Vultur 				    u32 count)
4764426b78cSHoratiu Vultur {
4774426b78cSHoratiu Vultur 	struct lan966x_port *port = netdev_priv(dev);
4784426b78cSHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
4794426b78cSHoratiu Vultur 	int instance = admin->tgt_inst;
4804426b78cSHoratiu Vultur 	u32 *keystr, *mskstr, *actstr;
4814426b78cSHoratiu Vultur 
4824426b78cSHoratiu Vultur 	keystr = &admin->cache.keystream[start];
4834426b78cSHoratiu Vultur 	mskstr = &admin->cache.maskstream[start];
4844426b78cSHoratiu Vultur 	actstr = &admin->cache.actionstream[start];
4854426b78cSHoratiu Vultur 
4864426b78cSHoratiu Vultur 	if (sel & VCAP_SEL_ENTRY) {
4874426b78cSHoratiu Vultur 		for (int i = 0; i < count; ++i) {
4884426b78cSHoratiu Vultur 			keystr[i] =
4894426b78cSHoratiu Vultur 				lan_rd(lan966x, VCAP_ENTRY_DAT(instance, i));
4904426b78cSHoratiu Vultur 			mskstr[i] =
4914426b78cSHoratiu Vultur 				~lan_rd(lan966x, VCAP_MASK_DAT(instance, i));
4924426b78cSHoratiu Vultur 		}
4934426b78cSHoratiu Vultur 	}
4944426b78cSHoratiu Vultur 
4954426b78cSHoratiu Vultur 	if (sel & VCAP_SEL_ACTION)
4964426b78cSHoratiu Vultur 		for (int i = 0; i < count; ++i)
4974426b78cSHoratiu Vultur 			actstr[i] =
4984426b78cSHoratiu Vultur 				lan_rd(lan966x, VCAP_ACTION_DAT(instance, i));
4994426b78cSHoratiu Vultur 
5004426b78cSHoratiu Vultur 	if (sel & VCAP_SEL_COUNTER) {
5014426b78cSHoratiu Vultur 		admin->cache.counter =
5024426b78cSHoratiu Vultur 			lan_rd(lan966x, VCAP_CNT_DAT(instance, 0));
5034426b78cSHoratiu Vultur 		admin->cache.sticky = admin->cache.counter > 0;
5044426b78cSHoratiu Vultur 
5054426b78cSHoratiu Vultur 		if (admin->vtype == VCAP_TYPE_ES0)
5064426b78cSHoratiu Vultur 			lan966x_es0_read_esdx_counter(lan966x, admin, start);
5074426b78cSHoratiu Vultur 	}
5084426b78cSHoratiu Vultur }
5094426b78cSHoratiu Vultur 
lan966x_vcap_range_init(struct net_device * dev,struct vcap_admin * admin,u32 addr,u32 count)5104426b78cSHoratiu Vultur static void lan966x_vcap_range_init(struct net_device *dev,
5114426b78cSHoratiu Vultur 				    struct vcap_admin *admin,
5124426b78cSHoratiu Vultur 				    u32 addr,
5134426b78cSHoratiu Vultur 				    u32 count)
5144426b78cSHoratiu Vultur {
5154426b78cSHoratiu Vultur 	struct lan966x_port *port = netdev_priv(dev);
5164426b78cSHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
5174426b78cSHoratiu Vultur 
5184426b78cSHoratiu Vultur 	__lan966x_vcap_range_init(lan966x, admin, addr, count);
5194426b78cSHoratiu Vultur }
5204426b78cSHoratiu Vultur 
lan966x_vcap_update(struct net_device * dev,struct vcap_admin * admin,enum vcap_command cmd,enum vcap_selection sel,u32 addr)5214426b78cSHoratiu Vultur static void lan966x_vcap_update(struct net_device *dev,
5224426b78cSHoratiu Vultur 				struct vcap_admin *admin,
5234426b78cSHoratiu Vultur 				enum vcap_command cmd,
5244426b78cSHoratiu Vultur 				enum vcap_selection sel,
5254426b78cSHoratiu Vultur 				u32 addr)
5264426b78cSHoratiu Vultur {
5274426b78cSHoratiu Vultur 	struct lan966x_port *port = netdev_priv(dev);
5284426b78cSHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
5293643abd6SHoratiu Vultur 	bool clear;
5303643abd6SHoratiu Vultur 
5313643abd6SHoratiu Vultur 	clear = (cmd == VCAP_CMD_INITIALIZE);
5323643abd6SHoratiu Vultur 
5333643abd6SHoratiu Vultur 	lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(0) |
5343643abd6SHoratiu Vultur 	       VCAP_MV_CFG_MV_SIZE_SET(0),
5353643abd6SHoratiu Vultur 	       lan966x, VCAP_MV_CFG(admin->tgt_inst));
5363643abd6SHoratiu Vultur 
5373643abd6SHoratiu Vultur 	lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(cmd) |
5383643abd6SHoratiu Vultur 	       VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET((VCAP_SEL_ENTRY & sel) == 0) |
5393643abd6SHoratiu Vultur 	       VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET((VCAP_SEL_ACTION & sel) == 0) |
5403643abd6SHoratiu Vultur 	       VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET((VCAP_SEL_COUNTER & sel) == 0) |
5413643abd6SHoratiu Vultur 	       VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |
5423643abd6SHoratiu Vultur 	       VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(clear) |
5433643abd6SHoratiu Vultur 	       VCAP_UPDATE_CTRL_UPDATE_SHOT,
5443643abd6SHoratiu Vultur 	       lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));
5453643abd6SHoratiu Vultur 
5463643abd6SHoratiu Vultur 	lan966x_vcap_wait_update(lan966x, admin->tgt_inst);
5473643abd6SHoratiu Vultur }
5483643abd6SHoratiu Vultur 
lan966x_vcap_move(struct net_device * dev,struct vcap_admin * admin,u32 addr,int offset,int count)5493643abd6SHoratiu Vultur static void lan966x_vcap_move(struct net_device *dev,
5503643abd6SHoratiu Vultur 			      struct vcap_admin *admin,
5513643abd6SHoratiu Vultur 			      u32 addr, int offset, int count)
5523643abd6SHoratiu Vultur {
5533643abd6SHoratiu Vultur 	struct lan966x_port *port = netdev_priv(dev);
5544426b78cSHoratiu Vultur 	struct lan966x *lan966x = port->lan966x;
5554426b78cSHoratiu Vultur 	enum vcap_command cmd;
5563643abd6SHoratiu Vultur 	u16 mv_num_pos;
5573643abd6SHoratiu Vultur 	u16 mv_size;
558e7e3f514SSteen Hegelund 
5594426b78cSHoratiu Vultur 	mv_size = count - 1;
5604426b78cSHoratiu Vultur 	if (offset > 0) {
5614426b78cSHoratiu Vultur 		mv_num_pos = offset - 1;
5623643abd6SHoratiu Vultur 		cmd = VCAP_CMD_MOVE_DOWN;
5633643abd6SHoratiu Vultur 	} else {
5644426b78cSHoratiu Vultur 		mv_num_pos = -offset - 1;
5653643abd6SHoratiu Vultur 		cmd = VCAP_CMD_MOVE_UP;
5663643abd6SHoratiu Vultur 	}
5674426b78cSHoratiu Vultur 
5683643abd6SHoratiu Vultur 	lan_wr(VCAP_MV_CFG_MV_NUM_POS_SET(mv_num_pos) |
5693643abd6SHoratiu Vultur 	       VCAP_MV_CFG_MV_SIZE_SET(mv_size),
5703643abd6SHoratiu Vultur 	       lan966x, VCAP_MV_CFG(admin->tgt_inst));
5713643abd6SHoratiu Vultur 
5723643abd6SHoratiu Vultur 	lan_wr(VCAP_UPDATE_CTRL_UPDATE_CMD_SET(cmd) |
5733643abd6SHoratiu Vultur 	       VCAP_UPDATE_CTRL_UPDATE_ENTRY_DIS_SET(0) |
5743643abd6SHoratiu Vultur 	       VCAP_UPDATE_CTRL_UPDATE_ACTION_DIS_SET(0) |
5753643abd6SHoratiu Vultur 	       VCAP_UPDATE_CTRL_UPDATE_CNT_DIS_SET(0) |
5763643abd6SHoratiu Vultur 	       VCAP_UPDATE_CTRL_UPDATE_ADDR_SET(addr) |
5773643abd6SHoratiu Vultur 	       VCAP_UPDATE_CTRL_CLEAR_CACHE_SET(false) |
5783643abd6SHoratiu Vultur 	       VCAP_UPDATE_CTRL_UPDATE_SHOT,
5793643abd6SHoratiu Vultur 	       lan966x, VCAP_UPDATE_CTRL(admin->tgt_inst));
5803643abd6SHoratiu Vultur 
5813643abd6SHoratiu Vultur 	lan966x_vcap_wait_update(lan966x, admin->tgt_inst);
5823643abd6SHoratiu Vultur }
5833643abd6SHoratiu Vultur 
5843643abd6SHoratiu Vultur static struct vcap_operations lan966x_vcap_ops = {
5853643abd6SHoratiu Vultur 	.validate_keyset = lan966x_vcap_validate_keyset,
5863643abd6SHoratiu Vultur 	.add_default_fields = lan966x_vcap_add_default_fields,
5873643abd6SHoratiu Vultur 	.cache_erase = lan966x_vcap_cache_erase,
5883643abd6SHoratiu Vultur 	.cache_write = lan966x_vcap_cache_write,
5893643abd6SHoratiu Vultur 	.cache_read = lan966x_vcap_cache_read,
5903643abd6SHoratiu Vultur 	.init = lan966x_vcap_range_init,
5913643abd6SHoratiu Vultur 	.update = lan966x_vcap_update,
5923643abd6SHoratiu Vultur 	.move = lan966x_vcap_move,
5933643abd6SHoratiu Vultur 	.port_info = lan966x_vcap_port_info,
5943643abd6SHoratiu Vultur };
5953643abd6SHoratiu Vultur 
lan966x_vcap_admin_free(struct vcap_admin * admin)5963643abd6SHoratiu Vultur static void lan966x_vcap_admin_free(struct vcap_admin *admin)
5973643abd6SHoratiu Vultur {
598b0531225SHoratiu Vultur 	if (!admin)
5994426b78cSHoratiu Vultur 		return;
6004426b78cSHoratiu Vultur 
6014426b78cSHoratiu Vultur 	kfree(admin->cache.keystream);
602*a4d9b3ecSHoratiu Vultur 	kfree(admin->cache.maskstream);
603*a4d9b3ecSHoratiu Vultur 	kfree(admin->cache.actionstream);
604*a4d9b3ecSHoratiu Vultur 	mutex_destroy(&admin->lock);
605*a4d9b3ecSHoratiu Vultur 	kfree(admin);
606*a4d9b3ecSHoratiu Vultur }
607*a4d9b3ecSHoratiu Vultur 
608*a4d9b3ecSHoratiu Vultur static struct vcap_admin *
lan966x_vcap_admin_alloc(struct lan966x * lan966x,struct vcap_control * ctrl,const struct lan966x_vcap_inst * cfg)609*a4d9b3ecSHoratiu Vultur lan966x_vcap_admin_alloc(struct lan966x *lan966x, struct vcap_control *ctrl,
610*a4d9b3ecSHoratiu Vultur 			 const struct lan966x_vcap_inst *cfg)
611*a4d9b3ecSHoratiu Vultur {
612*a4d9b3ecSHoratiu Vultur 	struct vcap_admin *admin;
613*a4d9b3ecSHoratiu Vultur 
614*a4d9b3ecSHoratiu Vultur 	admin = kzalloc(sizeof(*admin), GFP_KERNEL);
615*a4d9b3ecSHoratiu Vultur 	if (!admin)
616*a4d9b3ecSHoratiu Vultur 		return ERR_PTR(-ENOMEM);
617*a4d9b3ecSHoratiu Vultur 
618*a4d9b3ecSHoratiu Vultur 	mutex_init(&admin->lock);
619*a4d9b3ecSHoratiu Vultur 	INIT_LIST_HEAD(&admin->list);
620*a4d9b3ecSHoratiu Vultur 	INIT_LIST_HEAD(&admin->rules);
621*a4d9b3ecSHoratiu Vultur 	INIT_LIST_HEAD(&admin->enabled);
622*a4d9b3ecSHoratiu Vultur 
623*a4d9b3ecSHoratiu Vultur 	admin->vtype = cfg->vtype;
6244426b78cSHoratiu Vultur 	admin->vinst = 0;
6254426b78cSHoratiu Vultur 	admin->ingress = cfg->ingress;
626*a4d9b3ecSHoratiu Vultur 	admin->w32be = true;
627*a4d9b3ecSHoratiu Vultur 	admin->tgt_inst = cfg->tgt_inst;
628*a4d9b3ecSHoratiu Vultur 
629*a4d9b3ecSHoratiu Vultur 	admin->lookups = cfg->lookups;
630*a4d9b3ecSHoratiu Vultur 	admin->lookups_per_instance = cfg->lookups;
631*a4d9b3ecSHoratiu Vultur 
632*a4d9b3ecSHoratiu Vultur 	admin->first_cid = cfg->first_cid;
6334426b78cSHoratiu Vultur 	admin->last_cid = cfg->last_cid;
6344426b78cSHoratiu Vultur 
635b0531225SHoratiu Vultur 	admin->cache.keystream = kzalloc(STREAMSIZE, GFP_KERNEL);
636b0531225SHoratiu Vultur 	admin->cache.maskstream = kzalloc(STREAMSIZE, GFP_KERNEL);
6373643abd6SHoratiu Vultur 	admin->cache.actionstream = kzalloc(STREAMSIZE, GFP_KERNEL);
638b0531225SHoratiu Vultur 	if (!admin->cache.keystream ||
6393643abd6SHoratiu Vultur 	    !admin->cache.maskstream ||
64094281484SHoratiu Vultur 	    !admin->cache.actionstream) {
641b0531225SHoratiu Vultur 		lan966x_vcap_admin_free(admin);
642b0531225SHoratiu Vultur 		return ERR_PTR(-ENOMEM);
643b0531225SHoratiu Vultur 	}
644b0531225SHoratiu Vultur 
645b0531225SHoratiu Vultur 	return admin;
64639bedc16SHoratiu Vultur }
64739bedc16SHoratiu Vultur 
lan966x_vcap_block_init(struct lan966x * lan966x,struct vcap_admin * admin,struct lan966x_vcap_inst * cfg)6484426b78cSHoratiu Vultur static void lan966x_vcap_block_init(struct lan966x *lan966x,
64939bedc16SHoratiu Vultur 				    struct vcap_admin *admin,
6503643abd6SHoratiu Vultur 				    struct lan966x_vcap_inst *cfg)
6513643abd6SHoratiu Vultur {
6523643abd6SHoratiu Vultur 	admin->first_valid_addr = 0;
6533643abd6SHoratiu Vultur 	admin->last_used_addr = cfg->count;
6543643abd6SHoratiu Vultur 	admin->last_valid_addr = cfg->count - 1;
6553643abd6SHoratiu Vultur 
6563643abd6SHoratiu Vultur 	lan_wr(VCAP_CORE_IDX_CORE_IDX_SET(0),
6573643abd6SHoratiu Vultur 	       lan966x, VCAP_CORE_IDX(admin->tgt_inst));
6583643abd6SHoratiu Vultur 	lan_wr(VCAP_CORE_MAP_CORE_MAP_SET(1),
6594426b78cSHoratiu Vultur 	       lan966x, VCAP_CORE_MAP(admin->tgt_inst));
6604426b78cSHoratiu Vultur 
6613643abd6SHoratiu Vultur 	__lan966x_vcap_range_init(lan966x, admin, admin->first_valid_addr,
6623643abd6SHoratiu Vultur 				  admin->last_valid_addr -
6633643abd6SHoratiu Vultur 					admin->first_valid_addr);
66494281484SHoratiu Vultur }
66594281484SHoratiu Vultur 
lan966x_vcap_port_key_deselection(struct lan966x * lan966x,struct vcap_admin * admin)66694281484SHoratiu Vultur static void lan966x_vcap_port_key_deselection(struct lan966x *lan966x,
66794281484SHoratiu Vultur 					      struct vcap_admin *admin)
66894281484SHoratiu Vultur {
66994281484SHoratiu Vultur 	u32 val;
67001ef75a2SSteen Hegelund 
67101ef75a2SSteen Hegelund 	switch (admin->vtype) {
67201ef75a2SSteen Hegelund 	case VCAP_TYPE_IS1:
673*a4d9b3ecSHoratiu Vultur 		val = ANA_VCAP_S1_CFG_KEY_IP6_CFG_SET(VCAP_IS1_PS_IPV6_5TUPLE_IP6) |
674*a4d9b3ecSHoratiu Vultur 		      ANA_VCAP_S1_CFG_KEY_IP4_CFG_SET(VCAP_IS1_PS_IPV4_5TUPLE_IP4) |
675*a4d9b3ecSHoratiu Vultur 		      ANA_VCAP_S1_CFG_KEY_OTHER_CFG_SET(VCAP_IS1_PS_OTHER_NORMAL);
676*a4d9b3ecSHoratiu Vultur 
67794281484SHoratiu Vultur 		for (int p = 0; p < lan966x->num_phys_ports; ++p) {
67894281484SHoratiu Vultur 			if (!lan966x->ports[p])
67901ef75a2SSteen Hegelund 				continue;
680b0531225SHoratiu Vultur 
681b0531225SHoratiu Vultur 			for (int l = 0; l < LAN966X_IS1_LOOKUPS; ++l)
682b0531225SHoratiu Vultur 				lan_wr(val, lan966x, ANA_VCAP_S1_CFG(p, l));
683b0531225SHoratiu Vultur 
684b0531225SHoratiu Vultur 			lan_rmw(ANA_VCAP_CFG_S1_ENA_SET(true),
685b0531225SHoratiu Vultur 				ANA_VCAP_CFG_S1_ENA, lan966x,
686b0531225SHoratiu Vultur 				ANA_VCAP_CFG(p));
6873643abd6SHoratiu Vultur 		}
688b0531225SHoratiu Vultur 
689b0531225SHoratiu Vultur 		break;
690b0531225SHoratiu Vultur 	case VCAP_TYPE_IS2:
691b0531225SHoratiu Vultur 		for (int p = 0; p < lan966x->num_phys_ports; ++p)
692b0531225SHoratiu Vultur 			lan_wr(0, lan966x, ANA_VCAP_S2_CFG(p));
693b0531225SHoratiu Vultur 
6943643abd6SHoratiu Vultur 		break;
6954426b78cSHoratiu Vultur 	case VCAP_TYPE_ES0:
6963643abd6SHoratiu Vultur 		for (int p = 0; p < lan966x->num_phys_ports; ++p)
6973643abd6SHoratiu Vultur 			lan_rmw(REW_PORT_CFG_ES0_EN_SET(false),
6983643abd6SHoratiu Vultur 				REW_PORT_CFG_ES0_EN, lan966x,
6993643abd6SHoratiu Vultur 				REW_PORT_CFG(p));
7003643abd6SHoratiu Vultur 		break;
701b0531225SHoratiu Vultur 	default:
702b0531225SHoratiu Vultur 		pr_err("vcap type: %s not supported\n",
703 		       lan966x_vcaps[admin->vtype].name);
704 		break;
705 	}
706 }
707 
lan966x_vcap_init(struct lan966x * lan966x)708 int 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 
lan966x_vcap_deinit(struct lan966x * lan966x)767 void 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