xref: /linux/drivers/net/ethernet/microchip/sparx5/sparx5_vcap_impl.c (revision 9b8107553424fd87955fed257a807672c2097297)
1 // SPDX-License-Identifier: GPL-2.0+
2 /* Microchip Sparx5 Switch driver VCAP implementation
3  *
4  * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
5  *
6  * The Sparx5 Chip Register Model can be browsed at this location:
7  * https://github.com/microchip-ung/sparx-5_reginfo
8  */
9 
10 #include <linux/types.h>
11 #include <linux/list.h>
12 
13 #include "vcap_api.h"
14 #include "vcap_api_client.h"
15 #include "sparx5_main_regs.h"
16 #include "sparx5_main.h"
17 #include "sparx5_vcap_impl.h"
18 #include "sparx5_vcap_ag_api.h"
19 
20 #define SUPER_VCAP_BLK_SIZE 3072 /* addresses per Super VCAP block */
21 #define STREAMSIZE (64 * 4)  /* bytes in the VCAP cache area */
22 
23 #define SPARX5_IS2_LOOKUPS 4
24 #define VCAP_IS2_KEYSEL(_ena, _noneth, _v4_mc, _v4_uc, _v6_mc, _v6_uc, _arp) \
25 	(ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_SET(_ena) | \
26 	 ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_SET(_noneth) | \
27 	 ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_SET(_v4_mc) | \
28 	 ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_SET(_v4_uc) | \
29 	 ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_SET(_v6_mc) | \
30 	 ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_SET(_v6_uc) | \
31 	 ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_SET(_arp))
32 
33 /* IS2 port keyset selection control */
34 
35 /* IS2 non-ethernet traffic type keyset generation */
36 enum vcap_is2_port_sel_noneth {
37 	VCAP_IS2_PS_NONETH_MAC_ETYPE,
38 	VCAP_IS2_PS_NONETH_CUSTOM_1,
39 	VCAP_IS2_PS_NONETH_CUSTOM_2,
40 	VCAP_IS2_PS_NONETH_NO_LOOKUP
41 };
42 
43 /* IS2 IPv4 unicast traffic type keyset generation */
44 enum vcap_is2_port_sel_ipv4_uc {
45 	VCAP_IS2_PS_IPV4_UC_MAC_ETYPE,
46 	VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER,
47 	VCAP_IS2_PS_IPV4_UC_IP_7TUPLE,
48 };
49 
50 /* IS2 IPv4 multicast traffic type keyset generation */
51 enum vcap_is2_port_sel_ipv4_mc {
52 	VCAP_IS2_PS_IPV4_MC_MAC_ETYPE,
53 	VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER,
54 	VCAP_IS2_PS_IPV4_MC_IP_7TUPLE,
55 	VCAP_IS2_PS_IPV4_MC_IP4_VID,
56 };
57 
58 /* IS2 IPv6 unicast traffic type keyset generation */
59 enum vcap_is2_port_sel_ipv6_uc {
60 	VCAP_IS2_PS_IPV6_UC_MAC_ETYPE,
61 	VCAP_IS2_PS_IPV6_UC_IP_7TUPLE,
62 	VCAP_IS2_PS_IPV6_UC_IP6_STD,
63 	VCAP_IS2_PS_IPV6_UC_IP4_TCP_UDP_OTHER,
64 };
65 
66 /* IS2 IPv6 multicast traffic type keyset generation */
67 enum vcap_is2_port_sel_ipv6_mc {
68 	VCAP_IS2_PS_IPV6_MC_MAC_ETYPE,
69 	VCAP_IS2_PS_IPV6_MC_IP_7TUPLE,
70 	VCAP_IS2_PS_IPV6_MC_IP6_VID,
71 	VCAP_IS2_PS_IPV6_MC_IP6_STD,
72 	VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER,
73 };
74 
75 /* IS2 ARP traffic type keyset generation */
76 enum vcap_is2_port_sel_arp {
77 	VCAP_IS2_PS_ARP_MAC_ETYPE,
78 	VCAP_IS2_PS_ARP_ARP,
79 };
80 
81 static struct sparx5_vcap_inst {
82 	enum vcap_type vtype; /* type of vcap */
83 	int vinst; /* instance number within the same type */
84 	int lookups; /* number of lookups in this vcap type */
85 	int lookups_per_instance; /* number of lookups in this instance */
86 	int first_cid; /* first chain id in this vcap */
87 	int last_cid; /* last chain id in this vcap */
88 	int count; /* number of available addresses, not in super vcap */
89 	int map_id; /* id in the super vcap block mapping (if applicable) */
90 	int blockno; /* starting block in super vcap (if applicable) */
91 	int blocks; /* number of blocks in super vcap (if applicable) */
92 } sparx5_vcap_inst_cfg[] = {
93 	{
94 		.vtype = VCAP_TYPE_IS2, /* IS2-0 */
95 		.vinst = 0,
96 		.map_id = 4,
97 		.lookups = SPARX5_IS2_LOOKUPS,
98 		.lookups_per_instance = SPARX5_IS2_LOOKUPS / 2,
99 		.first_cid = SPARX5_VCAP_CID_IS2_L0,
100 		.last_cid = SPARX5_VCAP_CID_IS2_L2 - 1,
101 		.blockno = 0, /* Maps block 0-1 */
102 		.blocks = 2,
103 	},
104 	{
105 		.vtype = VCAP_TYPE_IS2, /* IS2-1 */
106 		.vinst = 1,
107 		.map_id = 5,
108 		.lookups = SPARX5_IS2_LOOKUPS,
109 		.lookups_per_instance = SPARX5_IS2_LOOKUPS / 2,
110 		.first_cid = SPARX5_VCAP_CID_IS2_L2,
111 		.last_cid = SPARX5_VCAP_CID_IS2_MAX,
112 		.blockno = 2, /* Maps block 2-3 */
113 		.blocks = 2,
114 	},
115 };
116 
117 /* Await the super VCAP completion of the current operation */
118 static void sparx5_vcap_wait_super_update(struct sparx5 *sparx5)
119 {
120 	u32 value;
121 
122 	read_poll_timeout(spx5_rd, value,
123 			  !VCAP_SUPER_CTRL_UPDATE_SHOT_GET(value), 500, 10000,
124 			  false, sparx5, VCAP_SUPER_CTRL);
125 }
126 
127 /* Initializing a VCAP address range: only IS2 for now */
128 static void _sparx5_vcap_range_init(struct sparx5 *sparx5,
129 				    struct vcap_admin *admin,
130 				    u32 addr, u32 count)
131 {
132 	u32 size = count - 1;
133 
134 	spx5_wr(VCAP_SUPER_CFG_MV_NUM_POS_SET(0) |
135 		VCAP_SUPER_CFG_MV_SIZE_SET(size),
136 		sparx5, VCAP_SUPER_CFG);
137 	spx5_wr(VCAP_SUPER_CTRL_UPDATE_CMD_SET(VCAP_CMD_INITIALIZE) |
138 		VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET(0) |
139 		VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET(0) |
140 		VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET(0) |
141 		VCAP_SUPER_CTRL_UPDATE_ADDR_SET(addr) |
142 		VCAP_SUPER_CTRL_CLEAR_CACHE_SET(true) |
143 		VCAP_SUPER_CTRL_UPDATE_SHOT_SET(true),
144 		sparx5, VCAP_SUPER_CTRL);
145 	sparx5_vcap_wait_super_update(sparx5);
146 }
147 
148 /* Initializing VCAP rule data area */
149 static void sparx5_vcap_block_init(struct sparx5 *sparx5,
150 				   struct vcap_admin *admin)
151 {
152 	_sparx5_vcap_range_init(sparx5, admin, admin->first_valid_addr,
153 				admin->last_valid_addr -
154 					admin->first_valid_addr);
155 }
156 
157 /* Get the keyset name from the sparx5 VCAP model */
158 static const char *sparx5_vcap_keyset_name(struct net_device *ndev,
159 					   enum vcap_keyfield_set keyset)
160 {
161 	struct sparx5_port *port = netdev_priv(ndev);
162 
163 	return vcap_keyset_name(port->sparx5->vcap_ctrl, keyset);
164 }
165 
166 /* Check if this is the first lookup of IS2 */
167 static bool sparx5_vcap_is2_is_first_chain(struct vcap_rule *rule)
168 {
169 	return (rule->vcap_chain_id >= SPARX5_VCAP_CID_IS2_L0 &&
170 		rule->vcap_chain_id < SPARX5_VCAP_CID_IS2_L1) ||
171 		((rule->vcap_chain_id >= SPARX5_VCAP_CID_IS2_L2 &&
172 		  rule->vcap_chain_id < SPARX5_VCAP_CID_IS2_L3));
173 }
174 
175 /* Set the narrow range ingress port mask on a rule */
176 static void sparx5_vcap_add_range_port_mask(struct vcap_rule *rule,
177 					    struct net_device *ndev)
178 {
179 	struct sparx5_port *port = netdev_priv(ndev);
180 	u32 port_mask;
181 	u32 range;
182 
183 	range = port->portno / BITS_PER_TYPE(u32);
184 	/* Port bit set to match-any */
185 	port_mask = ~BIT(port->portno % BITS_PER_TYPE(u32));
186 	vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK_SEL, 0, 0xf);
187 	vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK_RNG, range, 0xf);
188 	vcap_rule_add_key_u32(rule, VCAP_KF_IF_IGR_PORT_MASK, 0, port_mask);
189 }
190 
191 /* Set the wide range ingress port mask on a rule */
192 static void sparx5_vcap_add_wide_port_mask(struct vcap_rule *rule,
193 					   struct net_device *ndev)
194 {
195 	struct sparx5_port *port = netdev_priv(ndev);
196 	struct vcap_u72_key port_mask;
197 	u32 range;
198 
199 	/* Port bit set to match-any */
200 	memset(port_mask.value, 0, sizeof(port_mask.value));
201 	memset(port_mask.mask, 0xff, sizeof(port_mask.mask));
202 	range = port->portno / BITS_PER_BYTE;
203 	port_mask.mask[range] = ~BIT(port->portno % BITS_PER_BYTE);
204 	vcap_rule_add_key_u72(rule, VCAP_KF_IF_IGR_PORT_MASK, &port_mask);
205 }
206 
207 /* Convert chain id to vcap lookup id */
208 static int sparx5_vcap_cid_to_lookup(int cid)
209 {
210 	int lookup = 0;
211 
212 	/* For now only handle IS2 */
213 	if (cid >= SPARX5_VCAP_CID_IS2_L1 && cid < SPARX5_VCAP_CID_IS2_L2)
214 		lookup = 1;
215 	else if (cid >= SPARX5_VCAP_CID_IS2_L2 && cid < SPARX5_VCAP_CID_IS2_L3)
216 		lookup = 2;
217 	else if (cid >= SPARX5_VCAP_CID_IS2_L3 && cid < SPARX5_VCAP_CID_IS2_MAX)
218 		lookup = 3;
219 
220 	return lookup;
221 }
222 
223 /* Return the list of keysets for the vcap port configuration */
224 static int sparx5_vcap_is2_get_port_keysets(struct net_device *ndev,
225 					    int lookup,
226 					    struct vcap_keyset_list *keysetlist,
227 					    u16 l3_proto)
228 {
229 	struct sparx5_port *port = netdev_priv(ndev);
230 	struct sparx5 *sparx5 = port->sparx5;
231 	int portno = port->portno;
232 	u32 value;
233 
234 	/* Check if the port keyset selection is enabled */
235 	value = spx5_rd(sparx5, ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup));
236 	if (!ANA_ACL_VCAP_S2_KEY_SEL_KEY_SEL_ENA_GET(value))
237 		return -ENOENT;
238 
239 	/* Collect all keysets for the port in a list */
240 	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_ARP) {
241 		switch (ANA_ACL_VCAP_S2_KEY_SEL_ARP_KEY_SEL_GET(value)) {
242 		case VCAP_IS2_PS_ARP_MAC_ETYPE:
243 			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
244 			break;
245 		case VCAP_IS2_PS_ARP_ARP:
246 			vcap_keyset_list_add(keysetlist, VCAP_KFS_ARP);
247 			break;
248 		}
249 	}
250 
251 	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IP) {
252 		switch (ANA_ACL_VCAP_S2_KEY_SEL_IP4_UC_KEY_SEL_GET(value)) {
253 		case VCAP_IS2_PS_IPV4_UC_MAC_ETYPE:
254 			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
255 			break;
256 		case VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER:
257 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
258 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
259 			break;
260 		case VCAP_IS2_PS_IPV4_UC_IP_7TUPLE:
261 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE);
262 			break;
263 		}
264 
265 		switch (ANA_ACL_VCAP_S2_KEY_SEL_IP4_MC_KEY_SEL_GET(value)) {
266 		case VCAP_IS2_PS_IPV4_MC_MAC_ETYPE:
267 			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
268 			break;
269 		case VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER:
270 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
271 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
272 			break;
273 		case VCAP_IS2_PS_IPV4_MC_IP_7TUPLE:
274 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE);
275 			break;
276 		}
277 	}
278 
279 	if (l3_proto == ETH_P_ALL || l3_proto == ETH_P_IPV6) {
280 		switch (ANA_ACL_VCAP_S2_KEY_SEL_IP6_UC_KEY_SEL_GET(value)) {
281 		case VCAP_IS2_PS_IPV6_UC_MAC_ETYPE:
282 			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
283 			break;
284 		case VCAP_IS2_PS_IPV6_UC_IP_7TUPLE:
285 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE);
286 			break;
287 		case VCAP_IS2_PS_IPV6_UC_IP6_STD:
288 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD);
289 			break;
290 		case VCAP_IS2_PS_IPV6_UC_IP4_TCP_UDP_OTHER:
291 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
292 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
293 			break;
294 		}
295 
296 		switch (ANA_ACL_VCAP_S2_KEY_SEL_IP6_MC_KEY_SEL_GET(value)) {
297 		case VCAP_IS2_PS_IPV6_MC_MAC_ETYPE:
298 			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
299 			break;
300 		case VCAP_IS2_PS_IPV6_MC_IP_7TUPLE:
301 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP_7TUPLE);
302 			break;
303 		case VCAP_IS2_PS_IPV6_MC_IP6_STD:
304 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP6_STD);
305 			break;
306 		case VCAP_IS2_PS_IPV6_MC_IP4_TCP_UDP_OTHER:
307 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_TCP_UDP);
308 			vcap_keyset_list_add(keysetlist, VCAP_KFS_IP4_OTHER);
309 			break;
310 		case VCAP_IS2_PS_IPV6_MC_IP6_VID:
311 			/* Not used */
312 			break;
313 		}
314 	}
315 
316 	if (l3_proto != ETH_P_ARP && l3_proto != ETH_P_IP &&
317 	    l3_proto != ETH_P_IPV6) {
318 		switch (ANA_ACL_VCAP_S2_KEY_SEL_NON_ETH_KEY_SEL_GET(value)) {
319 		case VCAP_IS2_PS_NONETH_MAC_ETYPE:
320 			/* IS2 non-classified frames generate MAC_ETYPE */
321 			vcap_keyset_list_add(keysetlist, VCAP_KFS_MAC_ETYPE);
322 			break;
323 		}
324 	}
325 	return 0;
326 }
327 
328 /* API callback used for validating a field keyset (check the port keysets) */
329 static enum vcap_keyfield_set
330 sparx5_vcap_validate_keyset(struct net_device *ndev,
331 			    struct vcap_admin *admin,
332 			    struct vcap_rule *rule,
333 			    struct vcap_keyset_list *kslist,
334 			    u16 l3_proto)
335 {
336 	struct vcap_keyset_list keysetlist = {};
337 	enum vcap_keyfield_set keysets[10] = {};
338 	int idx, jdx, lookup;
339 
340 	if (!kslist || kslist->cnt == 0)
341 		return VCAP_KFS_NO_VALUE;
342 
343 	/* Get a list of currently configured keysets in the lookups */
344 	lookup = sparx5_vcap_cid_to_lookup(rule->vcap_chain_id);
345 	keysetlist.max = ARRAY_SIZE(keysets);
346 	keysetlist.keysets = keysets;
347 	sparx5_vcap_is2_get_port_keysets(ndev, lookup, &keysetlist, l3_proto);
348 
349 	/* Check if there is a match and return the match */
350 	for (idx = 0; idx < kslist->cnt; ++idx)
351 		for (jdx = 0; jdx < keysetlist.cnt; ++jdx)
352 			if (kslist->keysets[idx] == keysets[jdx])
353 				return kslist->keysets[idx];
354 
355 	pr_err("%s:%d: %s not supported in port key selection\n",
356 	       __func__, __LINE__,
357 	       sparx5_vcap_keyset_name(ndev, kslist->keysets[0]));
358 
359 	return -ENOENT;
360 }
361 
362 /* API callback used for adding default fields to a rule */
363 static void sparx5_vcap_add_default_fields(struct net_device *ndev,
364 					   struct vcap_admin *admin,
365 					   struct vcap_rule *rule)
366 {
367 	const struct vcap_field *field;
368 
369 	field = vcap_lookup_keyfield(rule, VCAP_KF_IF_IGR_PORT_MASK);
370 	if (field && field->width == SPX5_PORTS)
371 		sparx5_vcap_add_wide_port_mask(rule, ndev);
372 	else if (field && field->width == BITS_PER_TYPE(u32))
373 		sparx5_vcap_add_range_port_mask(rule, ndev);
374 	else
375 		pr_err("%s:%d: %s: could not add an ingress port mask for: %s\n",
376 		       __func__, __LINE__, netdev_name(ndev),
377 		       sparx5_vcap_keyset_name(ndev, rule->keyset));
378 	/* add the lookup bit */
379 	if (sparx5_vcap_is2_is_first_chain(rule))
380 		vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, VCAP_BIT_1);
381 	else
382 		vcap_rule_add_key_bit(rule, VCAP_KF_LOOKUP_FIRST_IS, VCAP_BIT_0);
383 }
384 
385 /* API callback used for erasing the vcap cache area (not the register area) */
386 static void sparx5_vcap_cache_erase(struct vcap_admin *admin)
387 {
388 	memset(admin->cache.keystream, 0, STREAMSIZE);
389 	memset(admin->cache.maskstream, 0, STREAMSIZE);
390 	memset(admin->cache.actionstream, 0, STREAMSIZE);
391 	memset(&admin->cache.counter, 0, sizeof(admin->cache.counter));
392 }
393 
394 /* API callback used for writing to the VCAP cache */
395 static void sparx5_vcap_cache_write(struct net_device *ndev,
396 				    struct vcap_admin *admin,
397 				    enum vcap_selection sel,
398 				    u32 start,
399 				    u32 count)
400 {
401 	struct sparx5_port *port = netdev_priv(ndev);
402 	struct sparx5 *sparx5 = port->sparx5;
403 	u32 *keystr, *mskstr, *actstr;
404 	int idx;
405 
406 	keystr = &admin->cache.keystream[start];
407 	mskstr = &admin->cache.maskstream[start];
408 	actstr = &admin->cache.actionstream[start];
409 	switch (sel) {
410 	case VCAP_SEL_ENTRY:
411 		for (idx = 0; idx < count; ++idx) {
412 			/* Avoid 'match-off' by setting value & mask */
413 			spx5_wr(keystr[idx] & mskstr[idx], sparx5,
414 				VCAP_SUPER_VCAP_ENTRY_DAT(idx));
415 			spx5_wr(~mskstr[idx], sparx5,
416 				VCAP_SUPER_VCAP_MASK_DAT(idx));
417 		}
418 		break;
419 	case VCAP_SEL_ACTION:
420 		for (idx = 0; idx < count; ++idx)
421 			spx5_wr(actstr[idx], sparx5,
422 				VCAP_SUPER_VCAP_ACTION_DAT(idx));
423 		break;
424 	case VCAP_SEL_ALL:
425 		pr_err("%s:%d: cannot write all streams at once\n",
426 		       __func__, __LINE__);
427 		break;
428 	default:
429 		break;
430 	}
431 	if (sel & VCAP_SEL_COUNTER) {
432 		start = start & 0xfff; /* counter limit */
433 		if (admin->vinst == 0)
434 			spx5_wr(admin->cache.counter, sparx5,
435 				ANA_ACL_CNT_A(start));
436 		else
437 			spx5_wr(admin->cache.counter, sparx5,
438 				ANA_ACL_CNT_B(start));
439 		spx5_wr(admin->cache.sticky, sparx5,
440 			VCAP_SUPER_VCAP_CNT_DAT(0));
441 	}
442 }
443 
444 /* API callback used for reading from the VCAP into the VCAP cache */
445 static void sparx5_vcap_cache_read(struct net_device *ndev,
446 				   struct vcap_admin *admin,
447 				   enum vcap_selection sel,
448 				   u32 start,
449 				   u32 count)
450 {
451 	struct sparx5_port *port = netdev_priv(ndev);
452 	struct sparx5 *sparx5 = port->sparx5;
453 	u32 *keystr, *mskstr, *actstr;
454 	int idx;
455 
456 	keystr = &admin->cache.keystream[start];
457 	mskstr = &admin->cache.maskstream[start];
458 	actstr = &admin->cache.actionstream[start];
459 	if (sel & VCAP_SEL_ENTRY) {
460 		for (idx = 0; idx < count; ++idx) {
461 			keystr[idx] = spx5_rd(sparx5,
462 					      VCAP_SUPER_VCAP_ENTRY_DAT(idx));
463 			mskstr[idx] = ~spx5_rd(sparx5,
464 					       VCAP_SUPER_VCAP_MASK_DAT(idx));
465 		}
466 	}
467 	if (sel & VCAP_SEL_ACTION) {
468 		for (idx = 0; idx < count; ++idx)
469 			actstr[idx] = spx5_rd(sparx5,
470 					      VCAP_SUPER_VCAP_ACTION_DAT(idx));
471 	}
472 	if (sel & VCAP_SEL_COUNTER) {
473 		start = start & 0xfff; /* counter limit */
474 		if (admin->vinst == 0)
475 			admin->cache.counter =
476 				spx5_rd(sparx5, ANA_ACL_CNT_A(start));
477 		else
478 			admin->cache.counter =
479 				spx5_rd(sparx5, ANA_ACL_CNT_B(start));
480 		admin->cache.sticky =
481 			spx5_rd(sparx5, VCAP_SUPER_VCAP_CNT_DAT(0));
482 	}
483 }
484 
485 /* API callback used for initializing a VCAP address range */
486 static void sparx5_vcap_range_init(struct net_device *ndev,
487 				   struct vcap_admin *admin, u32 addr,
488 				   u32 count)
489 {
490 	struct sparx5_port *port = netdev_priv(ndev);
491 	struct sparx5 *sparx5 = port->sparx5;
492 
493 	_sparx5_vcap_range_init(sparx5, admin, addr, count);
494 }
495 
496 /* API callback used for updating the VCAP cache */
497 static void sparx5_vcap_update(struct net_device *ndev,
498 			       struct vcap_admin *admin, enum vcap_command cmd,
499 			       enum vcap_selection sel, u32 addr)
500 {
501 	struct sparx5_port *port = netdev_priv(ndev);
502 	struct sparx5 *sparx5 = port->sparx5;
503 	bool clear;
504 
505 	clear = (cmd == VCAP_CMD_INITIALIZE);
506 	spx5_wr(VCAP_SUPER_CFG_MV_NUM_POS_SET(0) |
507 		VCAP_SUPER_CFG_MV_SIZE_SET(0), sparx5, VCAP_SUPER_CFG);
508 	spx5_wr(VCAP_SUPER_CTRL_UPDATE_CMD_SET(cmd) |
509 		VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET((VCAP_SEL_ENTRY & sel) == 0) |
510 		VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET((VCAP_SEL_ACTION & sel) == 0) |
511 		VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET((VCAP_SEL_COUNTER & sel) == 0) |
512 		VCAP_SUPER_CTRL_UPDATE_ADDR_SET(addr) |
513 		VCAP_SUPER_CTRL_CLEAR_CACHE_SET(clear) |
514 		VCAP_SUPER_CTRL_UPDATE_SHOT_SET(true),
515 		sparx5, VCAP_SUPER_CTRL);
516 	sparx5_vcap_wait_super_update(sparx5);
517 }
518 
519 /* API callback used for moving a block of rules in the VCAP */
520 static void sparx5_vcap_move(struct net_device *ndev, struct vcap_admin *admin,
521 			     u32 addr, int offset, int count)
522 {
523 	struct sparx5_port *port = netdev_priv(ndev);
524 	struct sparx5 *sparx5 = port->sparx5;
525 	enum vcap_command cmd;
526 	u16 mv_num_pos;
527 	u16 mv_size;
528 
529 	mv_size = count - 1;
530 	if (offset > 0) {
531 		mv_num_pos = offset - 1;
532 		cmd = VCAP_CMD_MOVE_DOWN;
533 	} else {
534 		mv_num_pos = -offset - 1;
535 		cmd = VCAP_CMD_MOVE_UP;
536 	}
537 	spx5_wr(VCAP_SUPER_CFG_MV_NUM_POS_SET(mv_num_pos) |
538 		VCAP_SUPER_CFG_MV_SIZE_SET(mv_size),
539 		sparx5, VCAP_SUPER_CFG);
540 	spx5_wr(VCAP_SUPER_CTRL_UPDATE_CMD_SET(cmd) |
541 		VCAP_SUPER_CTRL_UPDATE_ENTRY_DIS_SET(0) |
542 		VCAP_SUPER_CTRL_UPDATE_ACTION_DIS_SET(0) |
543 		VCAP_SUPER_CTRL_UPDATE_CNT_DIS_SET(0) |
544 		VCAP_SUPER_CTRL_UPDATE_ADDR_SET(addr) |
545 		VCAP_SUPER_CTRL_CLEAR_CACHE_SET(false) |
546 		VCAP_SUPER_CTRL_UPDATE_SHOT_SET(true),
547 		sparx5, VCAP_SUPER_CTRL);
548 	sparx5_vcap_wait_super_update(sparx5);
549 }
550 
551 /* Provide port information via a callback interface */
552 static int sparx5_port_info(struct net_device *ndev, enum vcap_type vtype,
553 			    int (*pf)(void *out, int arg, const char *fmt, ...),
554 			    void *out, int arg)
555 {
556 	/* this will be added later */
557 	return 0;
558 }
559 
560 /* Enable all lookups in the VCAP instance */
561 static int sparx5_vcap_enable(struct net_device *ndev,
562 			      struct vcap_admin *admin,
563 			      bool enable)
564 {
565 	struct sparx5_port *port = netdev_priv(ndev);
566 	struct sparx5 *sparx5;
567 	int portno;
568 
569 	sparx5 = port->sparx5;
570 	portno = port->portno;
571 
572 	/* For now we only consider IS2 */
573 	if (enable)
574 		spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0xf), sparx5,
575 			ANA_ACL_VCAP_S2_CFG(portno));
576 	else
577 		spx5_wr(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0), sparx5,
578 			ANA_ACL_VCAP_S2_CFG(portno));
579 	return 0;
580 }
581 
582 /* API callback operations: only IS2 is supported for now */
583 static struct vcap_operations sparx5_vcap_ops = {
584 	.validate_keyset = sparx5_vcap_validate_keyset,
585 	.add_default_fields = sparx5_vcap_add_default_fields,
586 	.cache_erase = sparx5_vcap_cache_erase,
587 	.cache_write = sparx5_vcap_cache_write,
588 	.cache_read = sparx5_vcap_cache_read,
589 	.init = sparx5_vcap_range_init,
590 	.update = sparx5_vcap_update,
591 	.move = sparx5_vcap_move,
592 	.port_info = sparx5_port_info,
593 	.enable = sparx5_vcap_enable,
594 };
595 
596 /* Enable lookups per port and set the keyset generation: only IS2 for now */
597 static void sparx5_vcap_port_key_selection(struct sparx5 *sparx5,
598 					   struct vcap_admin *admin)
599 {
600 	int portno, lookup;
601 	u32 keysel;
602 
603 	/* all traffic types generate the MAC_ETYPE keyset for now in all
604 	 * lookups on all ports
605 	 */
606 	keysel = VCAP_IS2_KEYSEL(true, VCAP_IS2_PS_NONETH_MAC_ETYPE,
607 				 VCAP_IS2_PS_IPV4_MC_IP4_TCP_UDP_OTHER,
608 				 VCAP_IS2_PS_IPV4_UC_IP4_TCP_UDP_OTHER,
609 				 VCAP_IS2_PS_IPV6_MC_IP_7TUPLE,
610 				 VCAP_IS2_PS_IPV6_UC_IP_7TUPLE,
611 				 VCAP_IS2_PS_ARP_ARP);
612 	for (lookup = 0; lookup < admin->lookups; ++lookup) {
613 		for (portno = 0; portno < SPX5_PORTS; ++portno) {
614 			spx5_wr(keysel, sparx5,
615 				ANA_ACL_VCAP_S2_KEY_SEL(portno, lookup));
616 		}
617 	}
618 }
619 
620 /* Disable lookups per port and set the keyset generation: only IS2 for now */
621 static void sparx5_vcap_port_key_deselection(struct sparx5 *sparx5,
622 					     struct vcap_admin *admin)
623 {
624 	int portno;
625 
626 	for (portno = 0; portno < SPX5_PORTS; ++portno)
627 		spx5_rmw(ANA_ACL_VCAP_S2_CFG_SEC_ENA_SET(0),
628 			 ANA_ACL_VCAP_S2_CFG_SEC_ENA,
629 			 sparx5,
630 			 ANA_ACL_VCAP_S2_CFG(portno));
631 }
632 
633 static void sparx5_vcap_admin_free(struct vcap_admin *admin)
634 {
635 	if (!admin)
636 		return;
637 	kfree(admin->cache.keystream);
638 	kfree(admin->cache.maskstream);
639 	kfree(admin->cache.actionstream);
640 	kfree(admin);
641 }
642 
643 /* Allocate a vcap instance with a rule list and a cache area */
644 static struct vcap_admin *
645 sparx5_vcap_admin_alloc(struct sparx5 *sparx5, struct vcap_control *ctrl,
646 			const struct sparx5_vcap_inst *cfg)
647 {
648 	struct vcap_admin *admin;
649 
650 	admin = kzalloc(sizeof(*admin), GFP_KERNEL);
651 	if (!admin)
652 		return ERR_PTR(-ENOMEM);
653 	INIT_LIST_HEAD(&admin->list);
654 	INIT_LIST_HEAD(&admin->rules);
655 	INIT_LIST_HEAD(&admin->enabled);
656 	admin->vtype = cfg->vtype;
657 	admin->vinst = cfg->vinst;
658 	admin->lookups = cfg->lookups;
659 	admin->lookups_per_instance = cfg->lookups_per_instance;
660 	admin->first_cid = cfg->first_cid;
661 	admin->last_cid = cfg->last_cid;
662 	admin->cache.keystream =
663 		kzalloc(STREAMSIZE, GFP_KERNEL);
664 	admin->cache.maskstream =
665 		kzalloc(STREAMSIZE, GFP_KERNEL);
666 	admin->cache.actionstream =
667 		kzalloc(STREAMSIZE, GFP_KERNEL);
668 	if (!admin->cache.keystream || !admin->cache.maskstream ||
669 	    !admin->cache.actionstream) {
670 		sparx5_vcap_admin_free(admin);
671 		return ERR_PTR(-ENOMEM);
672 	}
673 	return admin;
674 }
675 
676 /* Do block allocations and provide addresses for VCAP instances */
677 static void sparx5_vcap_block_alloc(struct sparx5 *sparx5,
678 				    struct vcap_admin *admin,
679 				    const struct sparx5_vcap_inst *cfg)
680 {
681 	int idx;
682 
683 	/* Super VCAP block mapping and address configuration. Block 0
684 	 * is assigned addresses 0 through 3071, block 1 is assigned
685 	 * addresses 3072 though 6143, and so on.
686 	 */
687 	for (idx = cfg->blockno; idx < cfg->blockno + cfg->blocks; ++idx) {
688 		spx5_wr(VCAP_SUPER_IDX_CORE_IDX_SET(idx), sparx5,
689 			VCAP_SUPER_IDX);
690 		spx5_wr(VCAP_SUPER_MAP_CORE_MAP_SET(cfg->map_id), sparx5,
691 			VCAP_SUPER_MAP);
692 	}
693 	admin->first_valid_addr = cfg->blockno * SUPER_VCAP_BLK_SIZE;
694 	admin->last_used_addr = admin->first_valid_addr +
695 		cfg->blocks * SUPER_VCAP_BLK_SIZE;
696 	admin->last_valid_addr = admin->last_used_addr - 1;
697 }
698 
699 /* Allocate a vcap control and vcap instances and configure the system */
700 int sparx5_vcap_init(struct sparx5 *sparx5)
701 {
702 	const struct sparx5_vcap_inst *cfg;
703 	struct vcap_control *ctrl;
704 	struct vcap_admin *admin;
705 	int err = 0, idx;
706 
707 	/* Create a VCAP control instance that owns the platform specific VCAP
708 	 * model with VCAP instances and information about keysets, keys,
709 	 * actionsets and actions
710 	 * - Create administrative state for each available VCAP
711 	 *   - Lists of rules
712 	 *   - Address information
713 	 *   - Initialize VCAP blocks
714 	 *   - Configure port keysets
715 	 */
716 	ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
717 	if (!ctrl)
718 		return -ENOMEM;
719 
720 	sparx5->vcap_ctrl = ctrl;
721 	/* select the sparx5 VCAP model */
722 	ctrl->vcaps = sparx5_vcaps;
723 	ctrl->stats = &sparx5_vcap_stats;
724 	/* Setup callbacks to allow the API to use the VCAP HW */
725 	ctrl->ops = &sparx5_vcap_ops;
726 
727 	INIT_LIST_HEAD(&ctrl->list);
728 	for (idx = 0; idx < ARRAY_SIZE(sparx5_vcap_inst_cfg); ++idx) {
729 		cfg = &sparx5_vcap_inst_cfg[idx];
730 		admin = sparx5_vcap_admin_alloc(sparx5, ctrl, cfg);
731 		if (IS_ERR(admin)) {
732 			err = PTR_ERR(admin);
733 			pr_err("%s:%d: vcap allocation failed: %d\n",
734 			       __func__, __LINE__, err);
735 			return err;
736 		}
737 		sparx5_vcap_block_alloc(sparx5, admin, cfg);
738 		sparx5_vcap_block_init(sparx5, admin);
739 		if (cfg->vinst == 0)
740 			sparx5_vcap_port_key_selection(sparx5, admin);
741 		list_add_tail(&admin->list, &ctrl->list);
742 	}
743 
744 	return err;
745 }
746 
747 void sparx5_vcap_destroy(struct sparx5 *sparx5)
748 {
749 	struct vcap_control *ctrl = sparx5->vcap_ctrl;
750 	struct vcap_admin *admin, *admin_next;
751 
752 	if (!ctrl)
753 		return;
754 
755 	list_for_each_entry_safe(admin, admin_next, &ctrl->list, list) {
756 		sparx5_vcap_port_key_deselection(sparx5, admin);
757 		vcap_del_rules(ctrl, admin);
758 		list_del(&admin->list);
759 		sparx5_vcap_admin_free(admin);
760 	}
761 	kfree(ctrl);
762 }
763