1// SPDX-License-Identifier: GPL-2.0+
2/* Microchip VCAP API
3 *
4 * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
5 */
6
7#include <net/tc_act/tc_gate.h>
8#include <net/tcp.h>
9
10#include "sparx5_tc.h"
11#include "vcap_api.h"
12#include "vcap_api_client.h"
13#include "vcap_tc.h"
14#include "sparx5_main.h"
15#include "sparx5_vcap_impl.h"
16
17#define SPX5_MAX_RULE_SIZE 13 /* allows X1, X2, X4, X6 and X12 rules */
18
19/* Collect keysets and type ids for multiple rules per size */
20struct sparx5_wildcard_rule {
21	bool selected;
22	u8 value;
23	u8 mask;
24	enum vcap_keyfield_set keyset;
25};
26
27struct sparx5_multiple_rules {
28	struct sparx5_wildcard_rule rule[SPX5_MAX_RULE_SIZE];
29};
30
31struct sparx5_tc_flower_template {
32	struct list_head list; /* for insertion in the list of templates */
33	int cid; /* chain id */
34	enum vcap_keyfield_set orig; /* keyset used before the template */
35	enum vcap_keyfield_set keyset; /* new keyset used by template */
36	u16 l3_proto; /* protocol specified in the template */
37};
38
39/* SparX-5 VCAP fragment types:
40 * 0 = no fragment, 1 = initial fragment,
41 * 2 = suspicious fragment, 3 = valid follow-up fragment
42 */
43enum {                   /* key / mask */
44	FRAG_NOT   = 0x03, /* 0 / 3 */
45	FRAG_SOME  = 0x11, /* 1 / 1 */
46	FRAG_FIRST = 0x13, /* 1 / 3 */
47	FRAG_LATER = 0x33, /* 3 / 3 */
48	FRAG_INVAL = 0xff, /* invalid */
49};
50
51/* Flower fragment flag to VCAP fragment type mapping */
52static const u8 sparx5_vcap_frag_map[4][4] = {		  /* is_frag */
53	{ FRAG_INVAL, FRAG_INVAL, FRAG_INVAL, FRAG_FIRST }, /* 0/0 */
54	{ FRAG_NOT,   FRAG_NOT,   FRAG_INVAL, FRAG_INVAL }, /* 0/1 */
55	{ FRAG_INVAL, FRAG_INVAL, FRAG_INVAL, FRAG_INVAL }, /* 1/0 */
56	{ FRAG_SOME,  FRAG_LATER, FRAG_INVAL, FRAG_FIRST }  /* 1/1 */
57	/* 0/0	      0/1	  1/0	      1/1 <-- first_frag */
58};
59
60static int
61sparx5_tc_flower_es0_tpid(struct vcap_tc_flower_parse_usage *st)
62{
63	int err = 0;
64
65	switch (st->tpid) {
66	case ETH_P_8021Q:
67		err = vcap_rule_add_key_u32(st->vrule,
68					    VCAP_KF_8021Q_TPID,
69					    SPX5_TPID_SEL_8100, ~0);
70		break;
71	case ETH_P_8021AD:
72		err = vcap_rule_add_key_u32(st->vrule,
73					    VCAP_KF_8021Q_TPID,
74					    SPX5_TPID_SEL_88A8, ~0);
75		break;
76	default:
77		NL_SET_ERR_MSG_MOD(st->fco->common.extack,
78				   "Invalid vlan proto");
79		err = -EINVAL;
80		break;
81	}
82	return err;
83}
84
85static int
86sparx5_tc_flower_handler_basic_usage(struct vcap_tc_flower_parse_usage *st)
87{
88	struct flow_match_basic mt;
89	int err = 0;
90
91	flow_rule_match_basic(st->frule, &mt);
92
93	if (mt.mask->n_proto) {
94		st->l3_proto = be16_to_cpu(mt.key->n_proto);
95		if (!sparx5_vcap_is_known_etype(st->admin, st->l3_proto)) {
96			err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE,
97						    st->l3_proto, ~0);
98			if (err)
99				goto out;
100		} else if (st->l3_proto == ETH_P_IP) {
101			err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
102						    VCAP_BIT_1);
103			if (err)
104				goto out;
105		} else if (st->l3_proto == ETH_P_IPV6) {
106			err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
107						    VCAP_BIT_0);
108			if (err)
109				goto out;
110			if (st->admin->vtype == VCAP_TYPE_IS0) {
111				err = vcap_rule_add_key_bit(st->vrule,
112							    VCAP_KF_IP_SNAP_IS,
113							    VCAP_BIT_1);
114				if (err)
115					goto out;
116			}
117		}
118	}
119
120	if (mt.mask->ip_proto) {
121		st->l4_proto = mt.key->ip_proto;
122		if (st->l4_proto == IPPROTO_TCP) {
123			err = vcap_rule_add_key_bit(st->vrule,
124						    VCAP_KF_TCP_IS,
125						    VCAP_BIT_1);
126			if (err)
127				goto out;
128		} else if (st->l4_proto == IPPROTO_UDP) {
129			err = vcap_rule_add_key_bit(st->vrule,
130						    VCAP_KF_TCP_IS,
131						    VCAP_BIT_0);
132			if (err)
133				goto out;
134			if (st->admin->vtype == VCAP_TYPE_IS0) {
135				err = vcap_rule_add_key_bit(st->vrule,
136							    VCAP_KF_TCP_UDP_IS,
137							    VCAP_BIT_1);
138				if (err)
139					goto out;
140			}
141		} else {
142			err = vcap_rule_add_key_u32(st->vrule,
143						    VCAP_KF_L3_IP_PROTO,
144						    st->l4_proto, ~0);
145			if (err)
146				goto out;
147		}
148	}
149
150	st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_BASIC);
151
152	return err;
153
154out:
155	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error");
156	return err;
157}
158
159static int
160sparx5_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st)
161{
162	struct flow_match_control mt;
163	u32 value, mask;
164	int err = 0;
165
166	flow_rule_match_control(st->frule, &mt);
167
168	if (mt.mask->flags) {
169		u8 is_frag_key = !!(mt.key->flags & FLOW_DIS_IS_FRAGMENT);
170		u8 is_frag_mask = !!(mt.mask->flags & FLOW_DIS_IS_FRAGMENT);
171		u8 is_frag_idx = (is_frag_key << 1) | is_frag_mask;
172
173		u8 first_frag_key = !!(mt.key->flags & FLOW_DIS_FIRST_FRAG);
174		u8 first_frag_mask = !!(mt.mask->flags & FLOW_DIS_FIRST_FRAG);
175		u8 first_frag_idx = (first_frag_key << 1) | first_frag_mask;
176
177		/* Lookup verdict based on the 2 + 2 input bits */
178		u8 vdt = sparx5_vcap_frag_map[is_frag_idx][first_frag_idx];
179
180		if (vdt == FRAG_INVAL) {
181			NL_SET_ERR_MSG_MOD(st->fco->common.extack,
182					   "Match on invalid fragment flag combination");
183			return -EINVAL;
184		}
185
186		/* Extract VCAP fragment key and mask from verdict */
187		value = (vdt >> 4) & 0x3;
188		mask = vdt & 0x3;
189
190		err = vcap_rule_add_key_u32(st->vrule,
191					    VCAP_KF_L3_FRAGMENT_TYPE,
192					    value, mask);
193		if (err)
194			goto out;
195	}
196
197	st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL);
198
199	return err;
200
201out:
202	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error");
203	return err;
204}
205
206static int
207sparx5_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st)
208{
209	if (st->admin->vtype != VCAP_TYPE_IS0) {
210		NL_SET_ERR_MSG_MOD(st->fco->common.extack,
211				   "cvlan not supported in this VCAP");
212		return -EINVAL;
213	}
214
215	return vcap_tc_flower_handler_cvlan_usage(st);
216}
217
218static int
219sparx5_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st)
220{
221	enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS;
222	enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS;
223	int err;
224
225	if (st->admin->vtype == VCAP_TYPE_IS0) {
226		vid_key = VCAP_KF_8021Q_VID0;
227		pcp_key = VCAP_KF_8021Q_PCP0;
228	}
229
230	err = vcap_tc_flower_handler_vlan_usage(st, vid_key, pcp_key);
231	if (err)
232		return err;
233
234	if (st->admin->vtype == VCAP_TYPE_ES0 && st->tpid)
235		err = sparx5_tc_flower_es0_tpid(st);
236
237	return err;
238}
239
240static int (*sparx5_tc_flower_usage_handlers[])(struct vcap_tc_flower_parse_usage *st) = {
241	[FLOW_DISSECTOR_KEY_ETH_ADDRS] = vcap_tc_flower_handler_ethaddr_usage,
242	[FLOW_DISSECTOR_KEY_IPV4_ADDRS] = vcap_tc_flower_handler_ipv4_usage,
243	[FLOW_DISSECTOR_KEY_IPV6_ADDRS] = vcap_tc_flower_handler_ipv6_usage,
244	[FLOW_DISSECTOR_KEY_CONTROL] = sparx5_tc_flower_handler_control_usage,
245	[FLOW_DISSECTOR_KEY_PORTS] = vcap_tc_flower_handler_portnum_usage,
246	[FLOW_DISSECTOR_KEY_BASIC] = sparx5_tc_flower_handler_basic_usage,
247	[FLOW_DISSECTOR_KEY_CVLAN] = sparx5_tc_flower_handler_cvlan_usage,
248	[FLOW_DISSECTOR_KEY_VLAN] = sparx5_tc_flower_handler_vlan_usage,
249	[FLOW_DISSECTOR_KEY_TCP] = vcap_tc_flower_handler_tcp_usage,
250	[FLOW_DISSECTOR_KEY_ARP] = vcap_tc_flower_handler_arp_usage,
251	[FLOW_DISSECTOR_KEY_IP] = vcap_tc_flower_handler_ip_usage,
252};
253
254static int sparx5_tc_use_dissectors(struct vcap_tc_flower_parse_usage *st,
255				    struct vcap_admin *admin,
256				    struct vcap_rule *vrule)
257{
258	int idx, err = 0;
259
260	for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_flower_usage_handlers); ++idx) {
261		if (!flow_rule_match_key(st->frule, idx))
262			continue;
263		if (!sparx5_tc_flower_usage_handlers[idx])
264			continue;
265		err = sparx5_tc_flower_usage_handlers[idx](st);
266		if (err)
267			return err;
268	}
269
270	if (st->frule->match.dissector->used_keys ^ st->used_keys) {
271		NL_SET_ERR_MSG_MOD(st->fco->common.extack,
272				   "Unsupported match item");
273		return -ENOENT;
274	}
275
276	return err;
277}
278
279static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
280					 struct net_device *ndev,
281					 struct flow_cls_offload *fco,
282					 bool ingress)
283{
284	struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
285	struct flow_action_entry *actent, *last_actent = NULL;
286	struct flow_action *act = &rule->action;
287	u64 action_mask = 0;
288	int idx;
289
290	if (!flow_action_has_entries(act)) {
291		NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions");
292		return -EINVAL;
293	}
294
295	if (!flow_action_basic_hw_stats_check(act, fco->common.extack))
296		return -EOPNOTSUPP;
297
298	flow_action_for_each(idx, actent, act) {
299		if (action_mask & BIT(actent->id)) {
300			NL_SET_ERR_MSG_MOD(fco->common.extack,
301					   "More actions of the same type");
302			return -EINVAL;
303		}
304		action_mask |= BIT(actent->id);
305		last_actent = actent; /* Save last action for later check */
306	}
307
308	/* Check if last action is a goto
309	 * The last chain/lookup does not need to have a goto action
310	 */
311	if (last_actent->id == FLOW_ACTION_GOTO) {
312		/* Check if the destination chain is in one of the VCAPs */
313		if (!vcap_is_next_lookup(vctrl, fco->common.chain_index,
314					 last_actent->chain_index)) {
315			NL_SET_ERR_MSG_MOD(fco->common.extack,
316					   "Invalid goto chain");
317			return -EINVAL;
318		}
319	} else if (!vcap_is_last_chain(vctrl, fco->common.chain_index,
320				       ingress)) {
321		NL_SET_ERR_MSG_MOD(fco->common.extack,
322				   "Last action must be 'goto'");
323		return -EINVAL;
324	}
325
326	/* Catch unsupported combinations of actions */
327	if (action_mask & BIT(FLOW_ACTION_TRAP) &&
328	    action_mask & BIT(FLOW_ACTION_ACCEPT)) {
329		NL_SET_ERR_MSG_MOD(fco->common.extack,
330				   "Cannot combine pass and trap action");
331		return -EOPNOTSUPP;
332	}
333
334	if (action_mask & BIT(FLOW_ACTION_VLAN_PUSH) &&
335	    action_mask & BIT(FLOW_ACTION_VLAN_POP)) {
336		NL_SET_ERR_MSG_MOD(fco->common.extack,
337				   "Cannot combine vlan push and pop action");
338		return -EOPNOTSUPP;
339	}
340
341	if (action_mask & BIT(FLOW_ACTION_VLAN_PUSH) &&
342	    action_mask & BIT(FLOW_ACTION_VLAN_MANGLE)) {
343		NL_SET_ERR_MSG_MOD(fco->common.extack,
344				   "Cannot combine vlan push and modify action");
345		return -EOPNOTSUPP;
346	}
347
348	if (action_mask & BIT(FLOW_ACTION_VLAN_POP) &&
349	    action_mask & BIT(FLOW_ACTION_VLAN_MANGLE)) {
350		NL_SET_ERR_MSG_MOD(fco->common.extack,
351				   "Cannot combine vlan pop and modify action");
352		return -EOPNOTSUPP;
353	}
354
355	return 0;
356}
357
358/* Add a rule counter action */
359static int sparx5_tc_add_rule_counter(struct vcap_admin *admin,
360				      struct vcap_rule *vrule)
361{
362	int err;
363
364	switch (admin->vtype) {
365	case VCAP_TYPE_IS0:
366		break;
367	case VCAP_TYPE_ES0:
368		err = vcap_rule_mod_action_u32(vrule, VCAP_AF_ESDX,
369					       vrule->id);
370		if (err)
371			return err;
372		vcap_rule_set_counter_id(vrule, vrule->id);
373		break;
374	case VCAP_TYPE_IS2:
375	case VCAP_TYPE_ES2:
376		err = vcap_rule_mod_action_u32(vrule, VCAP_AF_CNT_ID,
377					       vrule->id);
378		if (err)
379			return err;
380		vcap_rule_set_counter_id(vrule, vrule->id);
381		break;
382	default:
383		pr_err("%s:%d: vcap type: %d not supported\n",
384		       __func__, __LINE__, admin->vtype);
385		break;
386	}
387	return 0;
388}
389
390/* Collect all port keysets and apply the first of them, possibly wildcarded */
391static int sparx5_tc_select_protocol_keyset(struct net_device *ndev,
392					    struct vcap_rule *vrule,
393					    struct vcap_admin *admin,
394					    u16 l3_proto,
395					    struct sparx5_multiple_rules *multi)
396{
397	struct sparx5_port *port = netdev_priv(ndev);
398	struct vcap_keyset_list portkeysetlist = {};
399	enum vcap_keyfield_set portkeysets[10] = {};
400	struct vcap_keyset_list matches = {};
401	enum vcap_keyfield_set keysets[10];
402	int idx, jdx, err = 0, count = 0;
403	struct sparx5_wildcard_rule *mru;
404	const struct vcap_set *kinfo;
405	struct vcap_control *vctrl;
406
407	vctrl = port->sparx5->vcap_ctrl;
408
409	/* Find the keysets that the rule can use */
410	matches.keysets = keysets;
411	matches.max = ARRAY_SIZE(keysets);
412	if (!vcap_rule_find_keysets(vrule, &matches))
413		return -EINVAL;
414
415	/* Find the keysets that the port configuration supports */
416	portkeysetlist.max = ARRAY_SIZE(portkeysets);
417	portkeysetlist.keysets = portkeysets;
418	err = sparx5_vcap_get_port_keyset(ndev,
419					  admin, vrule->vcap_chain_id,
420					  l3_proto,
421					  &portkeysetlist);
422	if (err)
423		return err;
424
425	/* Find the intersection of the two sets of keyset */
426	for (idx = 0; idx < portkeysetlist.cnt; ++idx) {
427		kinfo = vcap_keyfieldset(vctrl, admin->vtype,
428					 portkeysetlist.keysets[idx]);
429		if (!kinfo)
430			continue;
431
432		/* Find a port keyset that matches the required keys
433		 * If there are multiple keysets then compose a type id mask
434		 */
435		for (jdx = 0; jdx < matches.cnt; ++jdx) {
436			if (portkeysetlist.keysets[idx] != matches.keysets[jdx])
437				continue;
438
439			mru = &multi->rule[kinfo->sw_per_item];
440			if (!mru->selected) {
441				mru->selected = true;
442				mru->keyset = portkeysetlist.keysets[idx];
443				mru->value = kinfo->type_id;
444			}
445			mru->value &= kinfo->type_id;
446			mru->mask |= kinfo->type_id;
447			++count;
448		}
449	}
450	if (count == 0)
451		return -EPROTO;
452
453	if (l3_proto == ETH_P_ALL && count < portkeysetlist.cnt)
454		return -ENOENT;
455
456	for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
457		mru = &multi->rule[idx];
458		if (!mru->selected)
459			continue;
460
461		/* Align the mask to the combined value */
462		mru->mask ^= mru->value;
463	}
464
465	/* Set the chosen keyset on the rule and set a wildcarded type if there
466	 * are more than one keyset
467	 */
468	for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
469		mru = &multi->rule[idx];
470		if (!mru->selected)
471			continue;
472
473		vcap_set_rule_set_keyset(vrule, mru->keyset);
474		if (count > 1)
475			/* Some keysets do not have a type field */
476			vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE,
477					      mru->value,
478					      ~mru->mask);
479		mru->selected = false; /* mark as done */
480		break; /* Stop here and add more rules later */
481	}
482	return err;
483}
484
485static int sparx5_tc_add_rule_copy(struct vcap_control *vctrl,
486				   struct flow_cls_offload *fco,
487				   struct vcap_rule *erule,
488				   struct vcap_admin *admin,
489				   struct sparx5_wildcard_rule *rule)
490{
491	enum vcap_key_field keylist[] = {
492		VCAP_KF_IF_IGR_PORT_MASK,
493		VCAP_KF_IF_IGR_PORT_MASK_SEL,
494		VCAP_KF_IF_IGR_PORT_MASK_RNG,
495		VCAP_KF_LOOKUP_FIRST_IS,
496		VCAP_KF_TYPE,
497	};
498	struct vcap_rule *vrule;
499	int err;
500
501	/* Add an extra rule with a special user and the new keyset */
502	erule->user = VCAP_USER_TC_EXTRA;
503	vrule = vcap_copy_rule(erule);
504	if (IS_ERR(vrule))
505		return PTR_ERR(vrule);
506
507	/* Link the new rule to the existing rule with the cookie */
508	vrule->cookie = erule->cookie;
509	vcap_filter_rule_keys(vrule, keylist, ARRAY_SIZE(keylist), true);
510	err = vcap_set_rule_set_keyset(vrule, rule->keyset);
511	if (err) {
512		pr_err("%s:%d: could not set keyset %s in rule: %u\n",
513		       __func__, __LINE__,
514		       vcap_keyset_name(vctrl, rule->keyset),
515		       vrule->id);
516		goto out;
517	}
518
519	/* Some keysets do not have a type field, so ignore return value */
520	vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE, rule->value, ~rule->mask);
521
522	err = vcap_set_rule_set_actionset(vrule, erule->actionset);
523	if (err)
524		goto out;
525
526	err = sparx5_tc_add_rule_counter(admin, vrule);
527	if (err)
528		goto out;
529
530	err = vcap_val_rule(vrule, ETH_P_ALL);
531	if (err) {
532		pr_err("%s:%d: could not validate rule: %u\n",
533		       __func__, __LINE__, vrule->id);
534		vcap_set_tc_exterr(fco, vrule);
535		goto out;
536	}
537	err = vcap_add_rule(vrule);
538	if (err) {
539		pr_err("%s:%d: could not add rule: %u\n",
540		       __func__, __LINE__, vrule->id);
541		goto out;
542	}
543out:
544	vcap_free_rule(vrule);
545	return err;
546}
547
548static int sparx5_tc_add_remaining_rules(struct vcap_control *vctrl,
549					 struct flow_cls_offload *fco,
550					 struct vcap_rule *erule,
551					 struct vcap_admin *admin,
552					 struct sparx5_multiple_rules *multi)
553{
554	int idx, err = 0;
555
556	for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
557		if (!multi->rule[idx].selected)
558			continue;
559
560		err = sparx5_tc_add_rule_copy(vctrl, fco, erule, admin,
561					      &multi->rule[idx]);
562		if (err)
563			break;
564	}
565	return err;
566}
567
568/* Add the actionset that is the default for the VCAP type */
569static int sparx5_tc_set_actionset(struct vcap_admin *admin,
570				   struct vcap_rule *vrule)
571{
572	enum vcap_actionfield_set aset;
573	int err = 0;
574
575	switch (admin->vtype) {
576	case VCAP_TYPE_IS0:
577		aset = VCAP_AFS_CLASSIFICATION;
578		break;
579	case VCAP_TYPE_IS2:
580		aset = VCAP_AFS_BASE_TYPE;
581		break;
582	case VCAP_TYPE_ES0:
583		aset = VCAP_AFS_ES0;
584		break;
585	case VCAP_TYPE_ES2:
586		aset = VCAP_AFS_BASE_TYPE;
587		break;
588	default:
589		pr_err("%s:%d: %s\n", __func__, __LINE__, "Invalid VCAP type");
590		return -EINVAL;
591	}
592	/* Do not overwrite any current actionset */
593	if (vrule->actionset == VCAP_AFS_NO_VALUE)
594		err = vcap_set_rule_set_actionset(vrule, aset);
595	return err;
596}
597
598/* Add the VCAP key to match on for a rule target value */
599static int sparx5_tc_add_rule_link_target(struct vcap_admin *admin,
600					  struct vcap_rule *vrule,
601					  int target_cid)
602{
603	int link_val = target_cid % VCAP_CID_LOOKUP_SIZE;
604	int err;
605
606	if (!link_val)
607		return 0;
608
609	switch (admin->vtype) {
610	case VCAP_TYPE_IS0:
611		/* Add NXT_IDX key for chaining rules between IS0 instances */
612		err = vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX_SEL,
613					    1, /* enable */
614					    ~0);
615		if (err)
616			return err;
617		return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX,
618					     link_val, /* target */
619					     ~0);
620	case VCAP_TYPE_IS2:
621		/* Add PAG key for chaining rules from IS0 */
622		return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG,
623					     link_val, /* target */
624					     ~0);
625	case VCAP_TYPE_ES0:
626	case VCAP_TYPE_ES2:
627		/* Add ISDX key for chaining rules from IS0 */
628		return vcap_rule_add_key_u32(vrule, VCAP_KF_ISDX_CLS, link_val,
629					     ~0);
630	default:
631		break;
632	}
633	return 0;
634}
635
636/* Add the VCAP action that adds a target value to a rule */
637static int sparx5_tc_add_rule_link(struct vcap_control *vctrl,
638				   struct vcap_admin *admin,
639				   struct vcap_rule *vrule,
640				   int from_cid, int to_cid)
641{
642	struct vcap_admin *to_admin = vcap_find_admin(vctrl, to_cid);
643	int diff, err = 0;
644
645	if (!to_admin) {
646		pr_err("%s:%d: unsupported chain direction: %d\n",
647		       __func__, __LINE__, to_cid);
648		return -EINVAL;
649	}
650
651	diff = vcap_chain_offset(vctrl, from_cid, to_cid);
652	if (!diff)
653		return 0;
654
655	if (admin->vtype == VCAP_TYPE_IS0 &&
656	    to_admin->vtype == VCAP_TYPE_IS0) {
657		/* Between IS0 instances the G_IDX value is used */
658		err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX, diff);
659		if (err)
660			goto out;
661		err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX_CTRL,
662					       1); /* Replace */
663		if (err)
664			goto out;
665	} else if (admin->vtype == VCAP_TYPE_IS0 &&
666		   to_admin->vtype == VCAP_TYPE_IS2) {
667		/* Between IS0 and IS2 the PAG value is used */
668		err = vcap_rule_add_action_u32(vrule, VCAP_AF_PAG_VAL, diff);
669		if (err)
670			goto out;
671		err = vcap_rule_add_action_u32(vrule,
672					       VCAP_AF_PAG_OVERRIDE_MASK,
673					       0xff);
674		if (err)
675			goto out;
676	} else if (admin->vtype == VCAP_TYPE_IS0 &&
677		   (to_admin->vtype == VCAP_TYPE_ES0 ||
678		    to_admin->vtype == VCAP_TYPE_ES2)) {
679		/* Between IS0 and ES0/ES2 the ISDX value is used */
680		err = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL,
681					       diff);
682		if (err)
683			goto out;
684		err = vcap_rule_add_action_bit(vrule,
685					       VCAP_AF_ISDX_ADD_REPLACE_SEL,
686					       VCAP_BIT_1);
687		if (err)
688			goto out;
689	} else {
690		pr_err("%s:%d: unsupported chain destination: %d\n",
691		       __func__, __LINE__, to_cid);
692		err = -EOPNOTSUPP;
693	}
694out:
695	return err;
696}
697
698static int sparx5_tc_flower_parse_act_gate(struct sparx5_psfp_sg *sg,
699					   struct flow_action_entry *act,
700					   struct netlink_ext_ack *extack)
701{
702	int i;
703
704	if (act->gate.prio < -1 || act->gate.prio > SPX5_PSFP_SG_MAX_IPV) {
705		NL_SET_ERR_MSG_MOD(extack, "Invalid gate priority");
706		return -EINVAL;
707	}
708
709	if (act->gate.cycletime < SPX5_PSFP_SG_MIN_CYCLE_TIME_NS ||
710	    act->gate.cycletime > SPX5_PSFP_SG_MAX_CYCLE_TIME_NS) {
711		NL_SET_ERR_MSG_MOD(extack, "Invalid gate cycletime");
712		return -EINVAL;
713	}
714
715	if (act->gate.cycletimeext > SPX5_PSFP_SG_MAX_CYCLE_TIME_NS) {
716		NL_SET_ERR_MSG_MOD(extack, "Invalid gate cycletimeext");
717		return -EINVAL;
718	}
719
720	if (act->gate.num_entries >= SPX5_PSFP_GCE_CNT) {
721		NL_SET_ERR_MSG_MOD(extack, "Invalid number of gate entries");
722		return -EINVAL;
723	}
724
725	sg->gate_state = true;
726	sg->ipv = act->gate.prio;
727	sg->num_entries = act->gate.num_entries;
728	sg->cycletime = act->gate.cycletime;
729	sg->cycletimeext = act->gate.cycletimeext;
730
731	for (i = 0; i < sg->num_entries; i++) {
732		sg->gce[i].gate_state = !!act->gate.entries[i].gate_state;
733		sg->gce[i].interval = act->gate.entries[i].interval;
734		sg->gce[i].ipv = act->gate.entries[i].ipv;
735		sg->gce[i].maxoctets = act->gate.entries[i].maxoctets;
736	}
737
738	return 0;
739}
740
741static int sparx5_tc_flower_parse_act_police(struct sparx5_policer *pol,
742					     struct flow_action_entry *act,
743					     struct netlink_ext_ack *extack)
744{
745	pol->type = SPX5_POL_SERVICE;
746	pol->rate = div_u64(act->police.rate_bytes_ps, 1000) * 8;
747	pol->burst = act->police.burst;
748	pol->idx = act->hw_index;
749
750	/* rate is now in kbit */
751	if (pol->rate > DIV_ROUND_UP(SPX5_SDLB_GROUP_RATE_MAX, 1000)) {
752		NL_SET_ERR_MSG_MOD(extack, "Maximum rate exceeded");
753		return -EINVAL;
754	}
755
756	if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
757		NL_SET_ERR_MSG_MOD(extack, "Offload not supported when exceed action is not drop");
758		return -EOPNOTSUPP;
759	}
760
761	if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
762	    act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
763		NL_SET_ERR_MSG_MOD(extack, "Offload not supported when conform action is not pipe or ok");
764		return -EOPNOTSUPP;
765	}
766
767	return 0;
768}
769
770static int sparx5_tc_flower_psfp_setup(struct sparx5 *sparx5,
771				       struct vcap_rule *vrule, int sg_idx,
772				       int pol_idx, struct sparx5_psfp_sg *sg,
773				       struct sparx5_psfp_fm *fm,
774				       struct sparx5_psfp_sf *sf)
775{
776	u32 psfp_sfid = 0, psfp_fmid = 0, psfp_sgid = 0;
777	int ret;
778
779	/* Must always have a stream gate - max sdu (filter option) is evaluated
780	 * after frames have passed the gate, so in case of only a policer, we
781	 * allocate a stream gate that is always open.
782	 */
783	if (sg_idx < 0) {
784		sg_idx = sparx5_pool_idx_to_id(SPX5_PSFP_SG_OPEN);
785		sg->ipv = 0; /* Disabled */
786		sg->cycletime = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT;
787		sg->num_entries = 1;
788		sg->gate_state = 1; /* Open */
789		sg->gate_enabled = 1;
790		sg->gce[0].gate_state = 1;
791		sg->gce[0].interval = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT;
792		sg->gce[0].ipv = 0;
793		sg->gce[0].maxoctets = 0; /* Disabled */
794	}
795
796	ret = sparx5_psfp_sg_add(sparx5, sg_idx, sg, &psfp_sgid);
797	if (ret < 0)
798		return ret;
799
800	if (pol_idx >= 0) {
801		/* Add new flow-meter */
802		ret = sparx5_psfp_fm_add(sparx5, pol_idx, fm, &psfp_fmid);
803		if (ret < 0)
804			return ret;
805	}
806
807	/* Map stream filter to stream gate */
808	sf->sgid = psfp_sgid;
809
810	/* Add new stream-filter and map it to a steam gate */
811	ret = sparx5_psfp_sf_add(sparx5, sf, &psfp_sfid);
812	if (ret < 0)
813		return ret;
814
815	/* Streams are classified by ISDX - map ISDX 1:1 to sfid for now. */
816	sparx5_isdx_conf_set(sparx5, psfp_sfid, psfp_sfid, psfp_fmid);
817
818	ret = vcap_rule_add_action_bit(vrule, VCAP_AF_ISDX_ADD_REPLACE_SEL,
819				       VCAP_BIT_1);
820	if (ret)
821		return ret;
822
823	ret = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL, psfp_sfid);
824	if (ret)
825		return ret;
826
827	return 0;
828}
829
830/* Handle the action trap for a VCAP rule */
831static int sparx5_tc_action_trap(struct vcap_admin *admin,
832				 struct vcap_rule *vrule,
833				 struct flow_cls_offload *fco)
834{
835	int err = 0;
836
837	switch (admin->vtype) {
838	case VCAP_TYPE_IS2:
839		err = vcap_rule_add_action_bit(vrule,
840					       VCAP_AF_CPU_COPY_ENA,
841					       VCAP_BIT_1);
842		if (err)
843			break;
844		err = vcap_rule_add_action_u32(vrule,
845					       VCAP_AF_CPU_QUEUE_NUM, 0);
846		if (err)
847			break;
848		err = vcap_rule_add_action_u32(vrule,
849					       VCAP_AF_MASK_MODE,
850					       SPX5_PMM_REPLACE_ALL);
851		break;
852	case VCAP_TYPE_ES0:
853		err = vcap_rule_add_action_u32(vrule,
854					       VCAP_AF_FWD_SEL,
855					       SPX5_FWSEL_REDIRECT_TO_LOOPBACK);
856		break;
857	case VCAP_TYPE_ES2:
858		err = vcap_rule_add_action_bit(vrule,
859					       VCAP_AF_CPU_COPY_ENA,
860					       VCAP_BIT_1);
861		if (err)
862			break;
863		err = vcap_rule_add_action_u32(vrule,
864					       VCAP_AF_CPU_QUEUE_NUM, 0);
865		break;
866	default:
867		NL_SET_ERR_MSG_MOD(fco->common.extack,
868				   "Trap action not supported in this VCAP");
869		err = -EOPNOTSUPP;
870		break;
871	}
872	return err;
873}
874
875static int sparx5_tc_action_vlan_pop(struct vcap_admin *admin,
876				     struct vcap_rule *vrule,
877				     struct flow_cls_offload *fco,
878				     u16 tpid)
879{
880	int err = 0;
881
882	switch (admin->vtype) {
883	case VCAP_TYPE_ES0:
884		break;
885	default:
886		NL_SET_ERR_MSG_MOD(fco->common.extack,
887				   "VLAN pop action not supported in this VCAP");
888		return -EOPNOTSUPP;
889	}
890
891	switch (tpid) {
892	case ETH_P_8021Q:
893	case ETH_P_8021AD:
894		err = vcap_rule_add_action_u32(vrule,
895					       VCAP_AF_PUSH_OUTER_TAG,
896					       SPX5_OTAG_UNTAG);
897		break;
898	default:
899		NL_SET_ERR_MSG_MOD(fco->common.extack,
900				   "Invalid vlan proto");
901		err = -EINVAL;
902	}
903	return err;
904}
905
906static int sparx5_tc_action_vlan_modify(struct vcap_admin *admin,
907					struct vcap_rule *vrule,
908					struct flow_cls_offload *fco,
909					struct flow_action_entry *act,
910					u16 tpid)
911{
912	int err = 0;
913
914	switch (admin->vtype) {
915	case VCAP_TYPE_ES0:
916		err = vcap_rule_add_action_u32(vrule,
917					       VCAP_AF_PUSH_OUTER_TAG,
918					       SPX5_OTAG_TAG_A);
919		if (err)
920			return err;
921		break;
922	default:
923		NL_SET_ERR_MSG_MOD(fco->common.extack,
924				   "VLAN modify action not supported in this VCAP");
925		return -EOPNOTSUPP;
926	}
927
928	switch (tpid) {
929	case ETH_P_8021Q:
930		err = vcap_rule_add_action_u32(vrule,
931					       VCAP_AF_TAG_A_TPID_SEL,
932					       SPX5_TPID_A_8100);
933		break;
934	case ETH_P_8021AD:
935		err = vcap_rule_add_action_u32(vrule,
936					       VCAP_AF_TAG_A_TPID_SEL,
937					       SPX5_TPID_A_88A8);
938		break;
939	default:
940		NL_SET_ERR_MSG_MOD(fco->common.extack,
941				   "Invalid vlan proto");
942		err = -EINVAL;
943	}
944	if (err)
945		return err;
946
947	err = vcap_rule_add_action_u32(vrule,
948				       VCAP_AF_TAG_A_VID_SEL,
949				       SPX5_VID_A_VAL);
950	if (err)
951		return err;
952
953	err = vcap_rule_add_action_u32(vrule,
954				       VCAP_AF_VID_A_VAL,
955				       act->vlan.vid);
956	if (err)
957		return err;
958
959	err = vcap_rule_add_action_u32(vrule,
960				       VCAP_AF_TAG_A_PCP_SEL,
961				       SPX5_PCP_A_VAL);
962	if (err)
963		return err;
964
965	err = vcap_rule_add_action_u32(vrule,
966				       VCAP_AF_PCP_A_VAL,
967				       act->vlan.prio);
968	if (err)
969		return err;
970
971	return vcap_rule_add_action_u32(vrule,
972					VCAP_AF_TAG_A_DEI_SEL,
973					SPX5_DEI_A_CLASSIFIED);
974}
975
976static int sparx5_tc_action_vlan_push(struct vcap_admin *admin,
977				      struct vcap_rule *vrule,
978				      struct flow_cls_offload *fco,
979				      struct flow_action_entry *act,
980				      u16 tpid)
981{
982	u16 act_tpid = be16_to_cpu(act->vlan.proto);
983	int err = 0;
984
985	switch (admin->vtype) {
986	case VCAP_TYPE_ES0:
987		break;
988	default:
989		NL_SET_ERR_MSG_MOD(fco->common.extack,
990				   "VLAN push action not supported in this VCAP");
991		return -EOPNOTSUPP;
992	}
993
994	if (tpid == ETH_P_8021AD) {
995		NL_SET_ERR_MSG_MOD(fco->common.extack,
996				   "Cannot push on double tagged frames");
997		return -EOPNOTSUPP;
998	}
999
1000	err = sparx5_tc_action_vlan_modify(admin, vrule, fco, act, act_tpid);
1001	if (err)
1002		return err;
1003
1004	switch (act_tpid) {
1005	case ETH_P_8021Q:
1006		break;
1007	case ETH_P_8021AD:
1008		/* Push classified tag as inner tag */
1009		err = vcap_rule_add_action_u32(vrule,
1010					       VCAP_AF_PUSH_INNER_TAG,
1011					       SPX5_ITAG_PUSH_B_TAG);
1012		if (err)
1013			break;
1014		err = vcap_rule_add_action_u32(vrule,
1015					       VCAP_AF_TAG_B_TPID_SEL,
1016					       SPX5_TPID_B_CLASSIFIED);
1017		break;
1018	default:
1019		NL_SET_ERR_MSG_MOD(fco->common.extack,
1020				   "Invalid vlan proto");
1021		err = -EINVAL;
1022	}
1023	return err;
1024}
1025
1026/* Remove rule keys that may prevent templates from matching a keyset */
1027static void sparx5_tc_flower_simplify_rule(struct vcap_admin *admin,
1028					   struct vcap_rule *vrule,
1029					   u16 l3_proto)
1030{
1031	switch (admin->vtype) {
1032	case VCAP_TYPE_IS0:
1033		vcap_rule_rem_key(vrule, VCAP_KF_ETYPE);
1034		switch (l3_proto) {
1035		case ETH_P_IP:
1036			break;
1037		case ETH_P_IPV6:
1038			vcap_rule_rem_key(vrule, VCAP_KF_IP_SNAP_IS);
1039			break;
1040		default:
1041			break;
1042		}
1043		break;
1044	case VCAP_TYPE_ES2:
1045		switch (l3_proto) {
1046		case ETH_P_IP:
1047			if (vrule->keyset == VCAP_KFS_IP4_OTHER)
1048				vcap_rule_rem_key(vrule, VCAP_KF_TCP_IS);
1049			break;
1050		case ETH_P_IPV6:
1051			if (vrule->keyset == VCAP_KFS_IP6_STD)
1052				vcap_rule_rem_key(vrule, VCAP_KF_TCP_IS);
1053			vcap_rule_rem_key(vrule, VCAP_KF_IP4_IS);
1054			break;
1055		default:
1056			break;
1057		}
1058		break;
1059	case VCAP_TYPE_IS2:
1060		switch (l3_proto) {
1061		case ETH_P_IP:
1062		case ETH_P_IPV6:
1063			vcap_rule_rem_key(vrule, VCAP_KF_IP4_IS);
1064			break;
1065		default:
1066			break;
1067		}
1068		break;
1069	default:
1070		break;
1071	}
1072}
1073
1074static bool sparx5_tc_flower_use_template(struct net_device *ndev,
1075					  struct flow_cls_offload *fco,
1076					  struct vcap_admin *admin,
1077					  struct vcap_rule *vrule)
1078{
1079	struct sparx5_port *port = netdev_priv(ndev);
1080	struct sparx5_tc_flower_template *ftp;
1081
1082	list_for_each_entry(ftp, &port->tc_templates, list) {
1083		if (ftp->cid != fco->common.chain_index)
1084			continue;
1085
1086		vcap_set_rule_set_keyset(vrule, ftp->keyset);
1087		sparx5_tc_flower_simplify_rule(admin, vrule, ftp->l3_proto);
1088		return true;
1089	}
1090	return false;
1091}
1092
1093static int sparx5_tc_flower_replace(struct net_device *ndev,
1094				    struct flow_cls_offload *fco,
1095				    struct vcap_admin *admin,
1096				    bool ingress)
1097{
1098	struct sparx5_psfp_sf sf = { .max_sdu = SPX5_PSFP_SF_MAX_SDU };
1099	struct netlink_ext_ack *extack = fco->common.extack;
1100	int err, idx, tc_sg_idx = -1, tc_pol_idx = -1;
1101	struct vcap_tc_flower_parse_usage state = {
1102		.fco = fco,
1103		.l3_proto = ETH_P_ALL,
1104		.admin = admin,
1105	};
1106	struct sparx5_port *port = netdev_priv(ndev);
1107	struct sparx5_multiple_rules multi = {};
1108	struct sparx5 *sparx5 = port->sparx5;
1109	struct sparx5_psfp_sg sg = { 0 };
1110	struct sparx5_psfp_fm fm = { 0 };
1111	struct flow_action_entry *act;
1112	struct vcap_control *vctrl;
1113	struct flow_rule *frule;
1114	struct vcap_rule *vrule;
1115
1116	vctrl = port->sparx5->vcap_ctrl;
1117
1118	err = sparx5_tc_flower_action_check(vctrl, ndev, fco, ingress);
1119	if (err)
1120		return err;
1121
1122	vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, VCAP_USER_TC,
1123				fco->common.prio, 0);
1124	if (IS_ERR(vrule))
1125		return PTR_ERR(vrule);
1126
1127	vrule->cookie = fco->cookie;
1128
1129	state.vrule = vrule;
1130	state.frule = flow_cls_offload_flow_rule(fco);
1131	err = sparx5_tc_use_dissectors(&state, admin, vrule);
1132	if (err)
1133		goto out;
1134
1135	err = sparx5_tc_add_rule_counter(admin, vrule);
1136	if (err)
1137		goto out;
1138
1139	err = sparx5_tc_add_rule_link_target(admin, vrule,
1140					     fco->common.chain_index);
1141	if (err)
1142		goto out;
1143
1144	frule = flow_cls_offload_flow_rule(fco);
1145	flow_action_for_each(idx, act, &frule->action) {
1146		switch (act->id) {
1147		case FLOW_ACTION_GATE: {
1148			err = sparx5_tc_flower_parse_act_gate(&sg, act, extack);
1149			if (err < 0)
1150				goto out;
1151
1152			tc_sg_idx = act->hw_index;
1153
1154			break;
1155		}
1156		case FLOW_ACTION_POLICE: {
1157			err = sparx5_tc_flower_parse_act_police(&fm.pol, act,
1158								extack);
1159			if (err < 0)
1160				goto out;
1161
1162			tc_pol_idx = fm.pol.idx;
1163			sf.max_sdu = act->police.mtu;
1164
1165			break;
1166		}
1167		case FLOW_ACTION_TRAP:
1168			err = sparx5_tc_action_trap(admin, vrule, fco);
1169			if (err)
1170				goto out;
1171			break;
1172		case FLOW_ACTION_ACCEPT:
1173			err = sparx5_tc_set_actionset(admin, vrule);
1174			if (err)
1175				goto out;
1176			break;
1177		case FLOW_ACTION_GOTO:
1178			err = sparx5_tc_set_actionset(admin, vrule);
1179			if (err)
1180				goto out;
1181			sparx5_tc_add_rule_link(vctrl, admin, vrule,
1182						fco->common.chain_index,
1183						act->chain_index);
1184			break;
1185		case FLOW_ACTION_VLAN_POP:
1186			err = sparx5_tc_action_vlan_pop(admin, vrule, fco,
1187							state.tpid);
1188			if (err)
1189				goto out;
1190			break;
1191		case FLOW_ACTION_VLAN_PUSH:
1192			err = sparx5_tc_action_vlan_push(admin, vrule, fco,
1193							 act, state.tpid);
1194			if (err)
1195				goto out;
1196			break;
1197		case FLOW_ACTION_VLAN_MANGLE:
1198			err = sparx5_tc_action_vlan_modify(admin, vrule, fco,
1199							   act, state.tpid);
1200			if (err)
1201				goto out;
1202			break;
1203		default:
1204			NL_SET_ERR_MSG_MOD(fco->common.extack,
1205					   "Unsupported TC action");
1206			err = -EOPNOTSUPP;
1207			goto out;
1208		}
1209	}
1210
1211	/* Setup PSFP */
1212	if (tc_sg_idx >= 0 || tc_pol_idx >= 0) {
1213		err = sparx5_tc_flower_psfp_setup(sparx5, vrule, tc_sg_idx,
1214						  tc_pol_idx, &sg, &fm, &sf);
1215		if (err)
1216			goto out;
1217	}
1218
1219	if (!sparx5_tc_flower_use_template(ndev, fco, admin, vrule)) {
1220		err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin,
1221						       state.l3_proto, &multi);
1222		if (err) {
1223			NL_SET_ERR_MSG_MOD(fco->common.extack,
1224					   "No matching port keyset for filter protocol and keys");
1225			goto out;
1226		}
1227	}
1228
1229	/* provide the l3 protocol to guide the keyset selection */
1230	err = vcap_val_rule(vrule, state.l3_proto);
1231	if (err) {
1232		vcap_set_tc_exterr(fco, vrule);
1233		goto out;
1234	}
1235	err = vcap_add_rule(vrule);
1236	if (err)
1237		NL_SET_ERR_MSG_MOD(fco->common.extack,
1238				   "Could not add the filter");
1239
1240	if (state.l3_proto == ETH_P_ALL)
1241		err = sparx5_tc_add_remaining_rules(vctrl, fco, vrule, admin,
1242						    &multi);
1243
1244out:
1245	vcap_free_rule(vrule);
1246	return err;
1247}
1248
1249static void sparx5_tc_free_psfp_resources(struct sparx5 *sparx5,
1250					  struct vcap_rule *vrule)
1251{
1252	struct vcap_client_actionfield *afield;
1253	u32 isdx, sfid, sgid, fmid;
1254
1255	/* Check if VCAP_AF_ISDX_VAL action is set for this rule - and if
1256	 * it is used for stream and/or flow-meter classification.
1257	 */
1258	afield = vcap_find_actionfield(vrule, VCAP_AF_ISDX_VAL);
1259	if (!afield)
1260		return;
1261
1262	isdx = afield->data.u32.value;
1263	sfid = sparx5_psfp_isdx_get_sf(sparx5, isdx);
1264
1265	if (!sfid)
1266		return;
1267
1268	fmid = sparx5_psfp_isdx_get_fm(sparx5, isdx);
1269	sgid = sparx5_psfp_sf_get_sg(sparx5, sfid);
1270
1271	if (fmid && sparx5_psfp_fm_del(sparx5, fmid) < 0)
1272		pr_err("%s:%d Could not delete invalid fmid: %d", __func__,
1273		       __LINE__, fmid);
1274
1275	if (sgid && sparx5_psfp_sg_del(sparx5, sgid) < 0)
1276		pr_err("%s:%d Could not delete invalid sgid: %d", __func__,
1277		       __LINE__, sgid);
1278
1279	if (sparx5_psfp_sf_del(sparx5, sfid) < 0)
1280		pr_err("%s:%d Could not delete invalid sfid: %d", __func__,
1281		       __LINE__, sfid);
1282
1283	sparx5_isdx_conf_set(sparx5, isdx, 0, 0);
1284}
1285
1286static int sparx5_tc_free_rule_resources(struct net_device *ndev,
1287					 struct vcap_control *vctrl,
1288					 int rule_id)
1289{
1290	struct sparx5_port *port = netdev_priv(ndev);
1291	struct sparx5 *sparx5 = port->sparx5;
1292	struct vcap_rule *vrule;
1293	int ret = 0;
1294
1295	vrule = vcap_get_rule(vctrl, rule_id);
1296	if (IS_ERR(vrule))
1297		return -EINVAL;
1298
1299	sparx5_tc_free_psfp_resources(sparx5, vrule);
1300
1301	vcap_free_rule(vrule);
1302	return ret;
1303}
1304
1305static int sparx5_tc_flower_destroy(struct net_device *ndev,
1306				    struct flow_cls_offload *fco,
1307				    struct vcap_admin *admin)
1308{
1309	struct sparx5_port *port = netdev_priv(ndev);
1310	int err = -ENOENT, count = 0, rule_id;
1311	struct vcap_control *vctrl;
1312
1313	vctrl = port->sparx5->vcap_ctrl;
1314	while (true) {
1315		rule_id = vcap_lookup_rule_by_cookie(vctrl, fco->cookie);
1316		if (rule_id <= 0)
1317			break;
1318		if (count == 0) {
1319			/* Resources are attached to the first rule of
1320			 * a set of rules. Only works if the rules are
1321			 * in the correct order.
1322			 */
1323			err = sparx5_tc_free_rule_resources(ndev, vctrl,
1324							    rule_id);
1325			if (err)
1326				pr_err("%s:%d: could not free resources %d\n",
1327				       __func__, __LINE__, rule_id);
1328		}
1329		err = vcap_del_rule(vctrl, ndev, rule_id);
1330		if (err) {
1331			pr_err("%s:%d: could not delete rule %d\n",
1332			       __func__, __LINE__, rule_id);
1333			break;
1334		}
1335	}
1336	return err;
1337}
1338
1339static int sparx5_tc_flower_stats(struct net_device *ndev,
1340				  struct flow_cls_offload *fco,
1341				  struct vcap_admin *admin)
1342{
1343	struct sparx5_port *port = netdev_priv(ndev);
1344	struct vcap_counter ctr = {};
1345	struct vcap_control *vctrl;
1346	ulong lastused = 0;
1347	int err;
1348
1349	vctrl = port->sparx5->vcap_ctrl;
1350	err = vcap_get_rule_count_by_cookie(vctrl, &ctr, fco->cookie);
1351	if (err)
1352		return err;
1353	flow_stats_update(&fco->stats, 0x0, ctr.value, 0, lastused,
1354			  FLOW_ACTION_HW_STATS_IMMEDIATE);
1355	return err;
1356}
1357
1358static int sparx5_tc_flower_template_create(struct net_device *ndev,
1359					    struct flow_cls_offload *fco,
1360					    struct vcap_admin *admin)
1361{
1362	struct sparx5_port *port = netdev_priv(ndev);
1363	struct vcap_tc_flower_parse_usage state = {
1364		.fco = fco,
1365		.l3_proto = ETH_P_ALL,
1366		.admin = admin,
1367	};
1368	struct sparx5_tc_flower_template *ftp;
1369	struct vcap_keyset_list kslist = {};
1370	enum vcap_keyfield_set keysets[10];
1371	struct vcap_control *vctrl;
1372	struct vcap_rule *vrule;
1373	int count, err;
1374
1375	if (admin->vtype == VCAP_TYPE_ES0) {
1376		pr_err("%s:%d: %s\n", __func__, __LINE__,
1377		       "VCAP does not support templates");
1378		return -EINVAL;
1379	}
1380
1381	count = vcap_admin_rule_count(admin, fco->common.chain_index);
1382	if (count > 0) {
1383		pr_err("%s:%d: %s\n", __func__, __LINE__,
1384		       "Filters are already present");
1385		return -EBUSY;
1386	}
1387
1388	ftp = kzalloc(sizeof(*ftp), GFP_KERNEL);
1389	if (!ftp)
1390		return -ENOMEM;
1391
1392	ftp->cid = fco->common.chain_index;
1393	ftp->orig = VCAP_KFS_NO_VALUE;
1394	ftp->keyset = VCAP_KFS_NO_VALUE;
1395
1396	vctrl = port->sparx5->vcap_ctrl;
1397	vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index,
1398				VCAP_USER_TC, fco->common.prio, 0);
1399	if (IS_ERR(vrule)) {
1400		err = PTR_ERR(vrule);
1401		goto err_rule;
1402	}
1403
1404	state.vrule = vrule;
1405	state.frule = flow_cls_offload_flow_rule(fco);
1406	err = sparx5_tc_use_dissectors(&state, admin, vrule);
1407	if (err) {
1408		pr_err("%s:%d: key error: %d\n", __func__, __LINE__, err);
1409		goto out;
1410	}
1411
1412	ftp->l3_proto = state.l3_proto;
1413
1414	sparx5_tc_flower_simplify_rule(admin, vrule, state.l3_proto);
1415
1416	/* Find the keysets that the rule can use */
1417	kslist.keysets = keysets;
1418	kslist.max = ARRAY_SIZE(keysets);
1419	if (!vcap_rule_find_keysets(vrule, &kslist)) {
1420		pr_err("%s:%d: %s\n", __func__, __LINE__,
1421		       "Could not find a suitable keyset");
1422		err = -ENOENT;
1423		goto out;
1424	}
1425
1426	ftp->keyset = vcap_select_min_rule_keyset(vctrl, admin->vtype, &kslist);
1427	kslist.cnt = 0;
1428	sparx5_vcap_set_port_keyset(ndev, admin, fco->common.chain_index,
1429				    state.l3_proto,
1430				    ftp->keyset,
1431				    &kslist);
1432
1433	if (kslist.cnt > 0)
1434		ftp->orig = kslist.keysets[0];
1435
1436	/* Store new template */
1437	list_add_tail(&ftp->list, &port->tc_templates);
1438	vcap_free_rule(vrule);
1439	return 0;
1440
1441out:
1442	vcap_free_rule(vrule);
1443err_rule:
1444	kfree(ftp);
1445	return err;
1446}
1447
1448static int sparx5_tc_flower_template_destroy(struct net_device *ndev,
1449					     struct flow_cls_offload *fco,
1450					     struct vcap_admin *admin)
1451{
1452	struct sparx5_port *port = netdev_priv(ndev);
1453	struct sparx5_tc_flower_template *ftp, *tmp;
1454	int err = -ENOENT;
1455
1456	/* Rules using the template are removed by the tc framework */
1457	list_for_each_entry_safe(ftp, tmp, &port->tc_templates, list) {
1458		if (ftp->cid != fco->common.chain_index)
1459			continue;
1460
1461		sparx5_vcap_set_port_keyset(ndev, admin,
1462					    fco->common.chain_index,
1463					    ftp->l3_proto, ftp->orig,
1464					    NULL);
1465		list_del(&ftp->list);
1466		kfree(ftp);
1467		break;
1468	}
1469	return err;
1470}
1471
1472int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
1473		     bool ingress)
1474{
1475	struct sparx5_port *port = netdev_priv(ndev);
1476	struct vcap_control *vctrl;
1477	struct vcap_admin *admin;
1478	int err = -EINVAL;
1479
1480	/* Get vcap instance from the chain id */
1481	vctrl = port->sparx5->vcap_ctrl;
1482	admin = vcap_find_admin(vctrl, fco->common.chain_index);
1483	if (!admin) {
1484		NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid chain");
1485		return err;
1486	}
1487
1488	switch (fco->command) {
1489	case FLOW_CLS_REPLACE:
1490		return sparx5_tc_flower_replace(ndev, fco, admin, ingress);
1491	case FLOW_CLS_DESTROY:
1492		return sparx5_tc_flower_destroy(ndev, fco, admin);
1493	case FLOW_CLS_STATS:
1494		return sparx5_tc_flower_stats(ndev, fco, admin);
1495	case FLOW_CLS_TMPLT_CREATE:
1496		return sparx5_tc_flower_template_create(ndev, fco, admin);
1497	case FLOW_CLS_TMPLT_DESTROY:
1498		return sparx5_tc_flower_template_destroy(ndev, fco, admin);
1499	default:
1500		return -EOPNOTSUPP;
1501	}
1502}
1503