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 */
20 struct sparx5_wildcard_rule {
21 	bool selected;
22 	u8 value;
23 	u8 mask;
24 	enum vcap_keyfield_set keyset;
25 };
26 
27 struct sparx5_multiple_rules {
28 	struct sparx5_wildcard_rule rule[SPX5_MAX_RULE_SIZE];
29 };
30 
31 static int
32 sparx5_tc_flower_handler_basic_usage(struct vcap_tc_flower_parse_usage *st)
33 {
34 	struct flow_match_basic mt;
35 	int err = 0;
36 
37 	flow_rule_match_basic(st->frule, &mt);
38 
39 	if (mt.mask->n_proto) {
40 		st->l3_proto = be16_to_cpu(mt.key->n_proto);
41 		if (!sparx5_vcap_is_known_etype(st->admin, st->l3_proto)) {
42 			err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE,
43 						    st->l3_proto, ~0);
44 			if (err)
45 				goto out;
46 		} else if (st->l3_proto == ETH_P_IP) {
47 			err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
48 						    VCAP_BIT_1);
49 			if (err)
50 				goto out;
51 		} else if (st->l3_proto == ETH_P_IPV6) {
52 			err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
53 						    VCAP_BIT_0);
54 			if (err)
55 				goto out;
56 			if (st->admin->vtype == VCAP_TYPE_IS0) {
57 				err = vcap_rule_add_key_bit(st->vrule,
58 							    VCAP_KF_IP_SNAP_IS,
59 							    VCAP_BIT_1);
60 				if (err)
61 					goto out;
62 			}
63 		}
64 	}
65 
66 	if (mt.mask->ip_proto) {
67 		st->l4_proto = mt.key->ip_proto;
68 		if (st->l4_proto == IPPROTO_TCP) {
69 			err = vcap_rule_add_key_bit(st->vrule,
70 						    VCAP_KF_TCP_IS,
71 						    VCAP_BIT_1);
72 			if (err)
73 				goto out;
74 		} else if (st->l4_proto == IPPROTO_UDP) {
75 			err = vcap_rule_add_key_bit(st->vrule,
76 						    VCAP_KF_TCP_IS,
77 						    VCAP_BIT_0);
78 			if (err)
79 				goto out;
80 			if (st->admin->vtype == VCAP_TYPE_IS0) {
81 				err = vcap_rule_add_key_bit(st->vrule,
82 							    VCAP_KF_TCP_UDP_IS,
83 							    VCAP_BIT_1);
84 				if (err)
85 					goto out;
86 			}
87 		} else {
88 			err = vcap_rule_add_key_u32(st->vrule,
89 						    VCAP_KF_L3_IP_PROTO,
90 						    st->l4_proto, ~0);
91 			if (err)
92 				goto out;
93 		}
94 	}
95 
96 	st->used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC);
97 
98 	return err;
99 
100 out:
101 	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error");
102 	return err;
103 }
104 
105 static int
106 sparx5_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st)
107 {
108 	struct flow_match_control mt;
109 	u32 value, mask;
110 	int err = 0;
111 
112 	flow_rule_match_control(st->frule, &mt);
113 
114 	if (mt.mask->flags) {
115 		if (mt.mask->flags & FLOW_DIS_FIRST_FRAG) {
116 			if (mt.key->flags & FLOW_DIS_FIRST_FRAG) {
117 				value = 1; /* initial fragment */
118 				mask = 0x3;
119 			} else {
120 				if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) {
121 					value = 3; /* follow up fragment */
122 					mask = 0x3;
123 				} else {
124 					value = 0; /* no fragment */
125 					mask = 0x3;
126 				}
127 			}
128 		} else {
129 			if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) {
130 				value = 3; /* follow up fragment */
131 				mask = 0x3;
132 			} else {
133 				value = 0; /* no fragment */
134 				mask = 0x3;
135 			}
136 		}
137 
138 		err = vcap_rule_add_key_u32(st->vrule,
139 					    VCAP_KF_L3_FRAGMENT_TYPE,
140 					    value, mask);
141 		if (err)
142 			goto out;
143 	}
144 
145 	st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL);
146 
147 	return err;
148 
149 out:
150 	NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error");
151 	return err;
152 }
153 
154 static int
155 sparx5_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st)
156 {
157 	if (st->admin->vtype != VCAP_TYPE_IS0) {
158 		NL_SET_ERR_MSG_MOD(st->fco->common.extack,
159 				   "cvlan not supported in this VCAP");
160 		return -EINVAL;
161 	}
162 
163 	return vcap_tc_flower_handler_cvlan_usage(st);
164 }
165 
166 static int
167 sparx5_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st)
168 {
169 	enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS;
170 	enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS;
171 
172 	if (st->admin->vtype == VCAP_TYPE_IS0) {
173 		vid_key = VCAP_KF_8021Q_VID0;
174 		pcp_key = VCAP_KF_8021Q_PCP0;
175 	}
176 
177 	return vcap_tc_flower_handler_vlan_usage(st, vid_key, pcp_key);
178 }
179 
180 static int (*sparx5_tc_flower_usage_handlers[])(struct vcap_tc_flower_parse_usage *st) = {
181 	[FLOW_DISSECTOR_KEY_ETH_ADDRS] = vcap_tc_flower_handler_ethaddr_usage,
182 	[FLOW_DISSECTOR_KEY_IPV4_ADDRS] = vcap_tc_flower_handler_ipv4_usage,
183 	[FLOW_DISSECTOR_KEY_IPV6_ADDRS] = vcap_tc_flower_handler_ipv6_usage,
184 	[FLOW_DISSECTOR_KEY_CONTROL] = sparx5_tc_flower_handler_control_usage,
185 	[FLOW_DISSECTOR_KEY_PORTS] = vcap_tc_flower_handler_portnum_usage,
186 	[FLOW_DISSECTOR_KEY_BASIC] = sparx5_tc_flower_handler_basic_usage,
187 	[FLOW_DISSECTOR_KEY_CVLAN] = sparx5_tc_flower_handler_cvlan_usage,
188 	[FLOW_DISSECTOR_KEY_VLAN] = sparx5_tc_flower_handler_vlan_usage,
189 	[FLOW_DISSECTOR_KEY_TCP] = vcap_tc_flower_handler_tcp_usage,
190 	[FLOW_DISSECTOR_KEY_ARP] = vcap_tc_flower_handler_arp_usage,
191 	[FLOW_DISSECTOR_KEY_IP] = vcap_tc_flower_handler_ip_usage,
192 };
193 
194 static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco,
195 				    struct vcap_admin *admin,
196 				    struct vcap_rule *vrule,
197 				    u16 *l3_proto)
198 {
199 	struct vcap_tc_flower_parse_usage state = {
200 		.fco = fco,
201 		.vrule = vrule,
202 		.l3_proto = ETH_P_ALL,
203 		.admin = admin,
204 	};
205 	int idx, err = 0;
206 
207 	state.frule = flow_cls_offload_flow_rule(fco);
208 	for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_flower_usage_handlers); ++idx) {
209 		if (!flow_rule_match_key(state.frule, idx))
210 			continue;
211 		if (!sparx5_tc_flower_usage_handlers[idx])
212 			continue;
213 		err = sparx5_tc_flower_usage_handlers[idx](&state);
214 		if (err)
215 			return err;
216 	}
217 
218 	if (state.frule->match.dissector->used_keys ^ state.used_keys) {
219 		NL_SET_ERR_MSG_MOD(fco->common.extack,
220 				   "Unsupported match item");
221 		return -ENOENT;
222 	}
223 
224 	if (l3_proto)
225 		*l3_proto = state.l3_proto;
226 	return err;
227 }
228 
229 static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
230 					 struct net_device *ndev,
231 					 struct flow_cls_offload *fco,
232 					 bool ingress)
233 {
234 	struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
235 	struct flow_action_entry *actent, *last_actent = NULL;
236 	struct flow_action *act = &rule->action;
237 	u64 action_mask = 0;
238 	int idx;
239 
240 	if (!flow_action_has_entries(act)) {
241 		NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions");
242 		return -EINVAL;
243 	}
244 
245 	if (!flow_action_basic_hw_stats_check(act, fco->common.extack))
246 		return -EOPNOTSUPP;
247 
248 	flow_action_for_each(idx, actent, act) {
249 		if (action_mask & BIT(actent->id)) {
250 			NL_SET_ERR_MSG_MOD(fco->common.extack,
251 					   "More actions of the same type");
252 			return -EINVAL;
253 		}
254 		action_mask |= BIT(actent->id);
255 		last_actent = actent; /* Save last action for later check */
256 	}
257 
258 	/* Check if last action is a goto
259 	 * The last chain/lookup does not need to have a goto action
260 	 */
261 	if (last_actent->id == FLOW_ACTION_GOTO) {
262 		/* Check if the destination chain is in one of the VCAPs */
263 		if (!vcap_is_next_lookup(vctrl, fco->common.chain_index,
264 					 last_actent->chain_index)) {
265 			NL_SET_ERR_MSG_MOD(fco->common.extack,
266 					   "Invalid goto chain");
267 			return -EINVAL;
268 		}
269 	} else if (!vcap_is_last_chain(vctrl, fco->common.chain_index,
270 				       ingress)) {
271 		NL_SET_ERR_MSG_MOD(fco->common.extack,
272 				   "Last action must be 'goto'");
273 		return -EINVAL;
274 	}
275 
276 	/* Catch unsupported combinations of actions */
277 	if (action_mask & BIT(FLOW_ACTION_TRAP) &&
278 	    action_mask & BIT(FLOW_ACTION_ACCEPT)) {
279 		NL_SET_ERR_MSG_MOD(fco->common.extack,
280 				   "Cannot combine pass and trap action");
281 		return -EOPNOTSUPP;
282 	}
283 
284 	return 0;
285 }
286 
287 /* Add a rule counter action */
288 static int sparx5_tc_add_rule_counter(struct vcap_admin *admin,
289 				      struct vcap_rule *vrule)
290 {
291 	int err;
292 
293 	if (admin->vtype == VCAP_TYPE_IS2 || admin->vtype == VCAP_TYPE_ES2) {
294 		err = vcap_rule_mod_action_u32(vrule, VCAP_AF_CNT_ID,
295 					       vrule->id);
296 		if (err)
297 			return err;
298 		vcap_rule_set_counter_id(vrule, vrule->id);
299 	}
300 
301 	return 0;
302 }
303 
304 /* Collect all port keysets and apply the first of them, possibly wildcarded */
305 static int sparx5_tc_select_protocol_keyset(struct net_device *ndev,
306 					    struct vcap_rule *vrule,
307 					    struct vcap_admin *admin,
308 					    u16 l3_proto,
309 					    struct sparx5_multiple_rules *multi)
310 {
311 	struct sparx5_port *port = netdev_priv(ndev);
312 	struct vcap_keyset_list portkeysetlist = {};
313 	enum vcap_keyfield_set portkeysets[10] = {};
314 	struct vcap_keyset_list matches = {};
315 	enum vcap_keyfield_set keysets[10];
316 	int idx, jdx, err = 0, count = 0;
317 	struct sparx5_wildcard_rule *mru;
318 	const struct vcap_set *kinfo;
319 	struct vcap_control *vctrl;
320 
321 	vctrl = port->sparx5->vcap_ctrl;
322 
323 	/* Find the keysets that the rule can use */
324 	matches.keysets = keysets;
325 	matches.max = ARRAY_SIZE(keysets);
326 	if (vcap_rule_find_keysets(vrule, &matches) == 0)
327 		return -EINVAL;
328 
329 	/* Find the keysets that the port configuration supports */
330 	portkeysetlist.max = ARRAY_SIZE(portkeysets);
331 	portkeysetlist.keysets = portkeysets;
332 	err = sparx5_vcap_get_port_keyset(ndev,
333 					  admin, vrule->vcap_chain_id,
334 					  l3_proto,
335 					  &portkeysetlist);
336 	if (err)
337 		return err;
338 
339 	/* Find the intersection of the two sets of keyset */
340 	for (idx = 0; idx < portkeysetlist.cnt; ++idx) {
341 		kinfo = vcap_keyfieldset(vctrl, admin->vtype,
342 					 portkeysetlist.keysets[idx]);
343 		if (!kinfo)
344 			continue;
345 
346 		/* Find a port keyset that matches the required keys
347 		 * If there are multiple keysets then compose a type id mask
348 		 */
349 		for (jdx = 0; jdx < matches.cnt; ++jdx) {
350 			if (portkeysetlist.keysets[idx] != matches.keysets[jdx])
351 				continue;
352 
353 			mru = &multi->rule[kinfo->sw_per_item];
354 			if (!mru->selected) {
355 				mru->selected = true;
356 				mru->keyset = portkeysetlist.keysets[idx];
357 				mru->value = kinfo->type_id;
358 			}
359 			mru->value &= kinfo->type_id;
360 			mru->mask |= kinfo->type_id;
361 			++count;
362 		}
363 	}
364 	if (count == 0)
365 		return -EPROTO;
366 
367 	if (l3_proto == ETH_P_ALL && count < portkeysetlist.cnt)
368 		return -ENOENT;
369 
370 	for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
371 		mru = &multi->rule[idx];
372 		if (!mru->selected)
373 			continue;
374 
375 		/* Align the mask to the combined value */
376 		mru->mask ^= mru->value;
377 	}
378 
379 	/* Set the chosen keyset on the rule and set a wildcarded type if there
380 	 * are more than one keyset
381 	 */
382 	for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
383 		mru = &multi->rule[idx];
384 		if (!mru->selected)
385 			continue;
386 
387 		vcap_set_rule_set_keyset(vrule, mru->keyset);
388 		if (count > 1)
389 			/* Some keysets do not have a type field */
390 			vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE,
391 					      mru->value,
392 					      ~mru->mask);
393 		mru->selected = false; /* mark as done */
394 		break; /* Stop here and add more rules later */
395 	}
396 	return err;
397 }
398 
399 static int sparx5_tc_add_rule_copy(struct vcap_control *vctrl,
400 				   struct flow_cls_offload *fco,
401 				   struct vcap_rule *erule,
402 				   struct vcap_admin *admin,
403 				   struct sparx5_wildcard_rule *rule)
404 {
405 	enum vcap_key_field keylist[] = {
406 		VCAP_KF_IF_IGR_PORT_MASK,
407 		VCAP_KF_IF_IGR_PORT_MASK_SEL,
408 		VCAP_KF_IF_IGR_PORT_MASK_RNG,
409 		VCAP_KF_LOOKUP_FIRST_IS,
410 		VCAP_KF_TYPE,
411 	};
412 	struct vcap_rule *vrule;
413 	int err;
414 
415 	/* Add an extra rule with a special user and the new keyset */
416 	erule->user = VCAP_USER_TC_EXTRA;
417 	vrule = vcap_copy_rule(erule);
418 	if (IS_ERR(vrule))
419 		return PTR_ERR(vrule);
420 
421 	/* Link the new rule to the existing rule with the cookie */
422 	vrule->cookie = erule->cookie;
423 	vcap_filter_rule_keys(vrule, keylist, ARRAY_SIZE(keylist), true);
424 	err = vcap_set_rule_set_keyset(vrule, rule->keyset);
425 	if (err) {
426 		pr_err("%s:%d: could not set keyset %s in rule: %u\n",
427 		       __func__, __LINE__,
428 		       vcap_keyset_name(vctrl, rule->keyset),
429 		       vrule->id);
430 		goto out;
431 	}
432 
433 	/* Some keysets do not have a type field, so ignore return value */
434 	vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE, rule->value, ~rule->mask);
435 
436 	err = vcap_set_rule_set_actionset(vrule, erule->actionset);
437 	if (err)
438 		goto out;
439 
440 	err = sparx5_tc_add_rule_counter(admin, vrule);
441 	if (err)
442 		goto out;
443 
444 	err = vcap_val_rule(vrule, ETH_P_ALL);
445 	if (err) {
446 		pr_err("%s:%d: could not validate rule: %u\n",
447 		       __func__, __LINE__, vrule->id);
448 		vcap_set_tc_exterr(fco, vrule);
449 		goto out;
450 	}
451 	err = vcap_add_rule(vrule);
452 	if (err) {
453 		pr_err("%s:%d: could not add rule: %u\n",
454 		       __func__, __LINE__, vrule->id);
455 		goto out;
456 	}
457 out:
458 	vcap_free_rule(vrule);
459 	return err;
460 }
461 
462 static int sparx5_tc_add_remaining_rules(struct vcap_control *vctrl,
463 					 struct flow_cls_offload *fco,
464 					 struct vcap_rule *erule,
465 					 struct vcap_admin *admin,
466 					 struct sparx5_multiple_rules *multi)
467 {
468 	int idx, err = 0;
469 
470 	for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
471 		if (!multi->rule[idx].selected)
472 			continue;
473 
474 		err = sparx5_tc_add_rule_copy(vctrl, fco, erule, admin,
475 					      &multi->rule[idx]);
476 		if (err)
477 			break;
478 	}
479 	return err;
480 }
481 
482 /* Add the actionset that is the default for the VCAP type */
483 static int sparx5_tc_set_actionset(struct vcap_admin *admin,
484 				   struct vcap_rule *vrule)
485 {
486 	enum vcap_actionfield_set aset;
487 	int err = 0;
488 
489 	switch (admin->vtype) {
490 	case VCAP_TYPE_IS0:
491 		aset = VCAP_AFS_CLASSIFICATION;
492 		break;
493 	case VCAP_TYPE_IS2:
494 		aset = VCAP_AFS_BASE_TYPE;
495 		break;
496 	case VCAP_TYPE_ES2:
497 		aset = VCAP_AFS_BASE_TYPE;
498 		break;
499 	default:
500 		return -EINVAL;
501 	}
502 	/* Do not overwrite any current actionset */
503 	if (vrule->actionset == VCAP_AFS_NO_VALUE)
504 		err = vcap_set_rule_set_actionset(vrule, aset);
505 	return err;
506 }
507 
508 /* Add the VCAP key to match on for a rule target value */
509 static int sparx5_tc_add_rule_link_target(struct vcap_admin *admin,
510 					  struct vcap_rule *vrule,
511 					  int target_cid)
512 {
513 	int link_val = target_cid % VCAP_CID_LOOKUP_SIZE;
514 	int err;
515 
516 	if (!link_val)
517 		return 0;
518 
519 	switch (admin->vtype) {
520 	case VCAP_TYPE_IS0:
521 		/* Add NXT_IDX key for chaining rules between IS0 instances */
522 		err = vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX_SEL,
523 					    1, /* enable */
524 					    ~0);
525 		if (err)
526 			return err;
527 		return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX,
528 					     link_val, /* target */
529 					     ~0);
530 	case VCAP_TYPE_IS2:
531 		/* Add PAG key for chaining rules from IS0 */
532 		return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG,
533 					     link_val, /* target */
534 					     ~0);
535 	case VCAP_TYPE_ES2:
536 		/* Add ISDX key for chaining rules from IS0 */
537 		return vcap_rule_add_key_u32(vrule, VCAP_KF_ISDX_CLS, link_val,
538 					     ~0);
539 	default:
540 		break;
541 	}
542 	return 0;
543 }
544 
545 /* Add the VCAP action that adds a target value to a rule */
546 static int sparx5_tc_add_rule_link(struct vcap_control *vctrl,
547 				   struct vcap_admin *admin,
548 				   struct vcap_rule *vrule,
549 				   int from_cid, int to_cid)
550 {
551 	struct vcap_admin *to_admin = vcap_find_admin(vctrl, to_cid);
552 	int diff, err = 0;
553 
554 	diff = vcap_chain_offset(vctrl, from_cid, to_cid);
555 	if (!(to_admin && diff > 0)) {
556 		pr_err("%s:%d: unsupported chain direction: %d\n",
557 		       __func__, __LINE__, to_cid);
558 		return -EINVAL;
559 	}
560 	if (admin->vtype == VCAP_TYPE_IS0 &&
561 	    to_admin->vtype == VCAP_TYPE_IS0) {
562 		/* Between IS0 instances the G_IDX value is used */
563 		err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX, diff);
564 		if (err)
565 			goto out;
566 		err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX_CTRL,
567 					       1); /* Replace */
568 		if (err)
569 			goto out;
570 	} else if (admin->vtype == VCAP_TYPE_IS0 &&
571 		   to_admin->vtype == VCAP_TYPE_IS2) {
572 		/* Between IS0 and IS2 the PAG value is used */
573 		err = vcap_rule_add_action_u32(vrule, VCAP_AF_PAG_VAL, diff);
574 		if (err)
575 			goto out;
576 		err = vcap_rule_add_action_u32(vrule,
577 					       VCAP_AF_PAG_OVERRIDE_MASK,
578 					       0xff);
579 		if (err)
580 			goto out;
581 	} else if (admin->vtype == VCAP_TYPE_IS0 &&
582 		   to_admin->vtype == VCAP_TYPE_ES2) {
583 		/* Between IS0 and ES2 the ISDX value is used */
584 		err = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL,
585 					       diff);
586 		if (err)
587 			goto out;
588 		err = vcap_rule_add_action_bit(vrule,
589 					       VCAP_AF_ISDX_ADD_REPLACE_SEL,
590 					       VCAP_BIT_1);
591 		if (err)
592 			goto out;
593 	} else {
594 		pr_err("%s:%d: unsupported chain destination: %d\n",
595 		       __func__, __LINE__, to_cid);
596 		err = -EOPNOTSUPP;
597 	}
598 out:
599 	return err;
600 }
601 
602 static int sparx5_tc_flower_parse_act_gate(struct sparx5_psfp_sg *sg,
603 					   struct flow_action_entry *act,
604 					   struct netlink_ext_ack *extack)
605 {
606 	int i;
607 
608 	if (act->gate.prio < -1 || act->gate.prio > SPX5_PSFP_SG_MAX_IPV) {
609 		NL_SET_ERR_MSG_MOD(extack, "Invalid gate priority");
610 		return -EINVAL;
611 	}
612 
613 	if (act->gate.cycletime < SPX5_PSFP_SG_MIN_CYCLE_TIME_NS ||
614 	    act->gate.cycletime > SPX5_PSFP_SG_MAX_CYCLE_TIME_NS) {
615 		NL_SET_ERR_MSG_MOD(extack, "Invalid gate cycletime");
616 		return -EINVAL;
617 	}
618 
619 	if (act->gate.cycletimeext > SPX5_PSFP_SG_MAX_CYCLE_TIME_NS) {
620 		NL_SET_ERR_MSG_MOD(extack, "Invalid gate cycletimeext");
621 		return -EINVAL;
622 	}
623 
624 	if (act->gate.num_entries >= SPX5_PSFP_GCE_CNT) {
625 		NL_SET_ERR_MSG_MOD(extack, "Invalid number of gate entries");
626 		return -EINVAL;
627 	}
628 
629 	sg->gate_state = true;
630 	sg->ipv = act->gate.prio;
631 	sg->num_entries = act->gate.num_entries;
632 	sg->cycletime = act->gate.cycletime;
633 	sg->cycletimeext = act->gate.cycletimeext;
634 
635 	for (i = 0; i < sg->num_entries; i++) {
636 		sg->gce[i].gate_state = !!act->gate.entries[i].gate_state;
637 		sg->gce[i].interval = act->gate.entries[i].interval;
638 		sg->gce[i].ipv = act->gate.entries[i].ipv;
639 		sg->gce[i].maxoctets = act->gate.entries[i].maxoctets;
640 	}
641 
642 	return 0;
643 }
644 
645 static int sparx5_tc_flower_parse_act_police(struct sparx5_policer *pol,
646 					     struct flow_action_entry *act,
647 					     struct netlink_ext_ack *extack)
648 {
649 	pol->type = SPX5_POL_SERVICE;
650 	pol->rate = div_u64(act->police.rate_bytes_ps, 1000) * 8;
651 	pol->burst = act->police.burst;
652 	pol->idx = act->hw_index;
653 
654 	/* rate is now in kbit */
655 	if (pol->rate > DIV_ROUND_UP(SPX5_SDLB_GROUP_RATE_MAX, 1000)) {
656 		NL_SET_ERR_MSG_MOD(extack, "Maximum rate exceeded");
657 		return -EINVAL;
658 	}
659 
660 	if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
661 		NL_SET_ERR_MSG_MOD(extack, "Offload not supported when exceed action is not drop");
662 		return -EOPNOTSUPP;
663 	}
664 
665 	if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
666 	    act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
667 		NL_SET_ERR_MSG_MOD(extack, "Offload not supported when conform action is not pipe or ok");
668 		return -EOPNOTSUPP;
669 	}
670 
671 	return 0;
672 }
673 
674 static int sparx5_tc_flower_psfp_setup(struct sparx5 *sparx5,
675 				       struct vcap_rule *vrule, int sg_idx,
676 				       int pol_idx, struct sparx5_psfp_sg *sg,
677 				       struct sparx5_psfp_fm *fm,
678 				       struct sparx5_psfp_sf *sf)
679 {
680 	u32 psfp_sfid = 0, psfp_fmid = 0, psfp_sgid = 0;
681 	int ret;
682 
683 	/* Must always have a stream gate - max sdu (filter option) is evaluated
684 	 * after frames have passed the gate, so in case of only a policer, we
685 	 * allocate a stream gate that is always open.
686 	 */
687 	if (sg_idx < 0) {
688 		sg_idx = sparx5_pool_idx_to_id(SPX5_PSFP_SG_OPEN);
689 		sg->ipv = 0; /* Disabled */
690 		sg->cycletime = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT;
691 		sg->num_entries = 1;
692 		sg->gate_state = 1; /* Open */
693 		sg->gate_enabled = 1;
694 		sg->gce[0].gate_state = 1;
695 		sg->gce[0].interval = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT;
696 		sg->gce[0].ipv = 0;
697 		sg->gce[0].maxoctets = 0; /* Disabled */
698 	}
699 
700 	ret = sparx5_psfp_sg_add(sparx5, sg_idx, sg, &psfp_sgid);
701 	if (ret < 0)
702 		return ret;
703 
704 	if (pol_idx >= 0) {
705 		/* Add new flow-meter */
706 		ret = sparx5_psfp_fm_add(sparx5, pol_idx, fm, &psfp_fmid);
707 		if (ret < 0)
708 			return ret;
709 	}
710 
711 	/* Map stream filter to stream gate */
712 	sf->sgid = psfp_sgid;
713 
714 	/* Add new stream-filter and map it to a steam gate */
715 	ret = sparx5_psfp_sf_add(sparx5, sf, &psfp_sfid);
716 	if (ret < 0)
717 		return ret;
718 
719 	/* Streams are classified by ISDX - map ISDX 1:1 to sfid for now. */
720 	sparx5_isdx_conf_set(sparx5, psfp_sfid, psfp_sfid, psfp_fmid);
721 
722 	ret = vcap_rule_add_action_bit(vrule, VCAP_AF_ISDX_ADD_REPLACE_SEL,
723 				       VCAP_BIT_1);
724 	if (ret)
725 		return ret;
726 
727 	ret = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL, psfp_sfid);
728 	if (ret)
729 		return ret;
730 
731 	return 0;
732 }
733 
734 static int sparx5_tc_flower_replace(struct net_device *ndev,
735 				    struct flow_cls_offload *fco,
736 				    struct vcap_admin *admin,
737 				    bool ingress)
738 {
739 	struct sparx5_psfp_sf sf = { .max_sdu = SPX5_PSFP_SF_MAX_SDU };
740 	struct netlink_ext_ack *extack = fco->common.extack;
741 	int err, idx, tc_sg_idx = -1, tc_pol_idx = -1;
742 	struct sparx5_port *port = netdev_priv(ndev);
743 	struct sparx5_multiple_rules multi = {};
744 	struct sparx5 *sparx5 = port->sparx5;
745 	struct sparx5_psfp_sg sg = { 0 };
746 	struct sparx5_psfp_fm fm = { 0 };
747 	struct flow_action_entry *act;
748 	struct vcap_control *vctrl;
749 	struct flow_rule *frule;
750 	struct vcap_rule *vrule;
751 	u16 l3_proto;
752 
753 	vctrl = port->sparx5->vcap_ctrl;
754 
755 	err = sparx5_tc_flower_action_check(vctrl, ndev, fco, ingress);
756 	if (err)
757 		return err;
758 
759 	vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, VCAP_USER_TC,
760 				fco->common.prio, 0);
761 	if (IS_ERR(vrule))
762 		return PTR_ERR(vrule);
763 
764 	vrule->cookie = fco->cookie;
765 
766 	l3_proto = ETH_P_ALL;
767 	err = sparx5_tc_use_dissectors(fco, admin, vrule, &l3_proto);
768 	if (err)
769 		goto out;
770 
771 	err = sparx5_tc_add_rule_counter(admin, vrule);
772 	if (err)
773 		goto out;
774 
775 	err = sparx5_tc_add_rule_link_target(admin, vrule,
776 					     fco->common.chain_index);
777 	if (err)
778 		goto out;
779 
780 	frule = flow_cls_offload_flow_rule(fco);
781 	flow_action_for_each(idx, act, &frule->action) {
782 		switch (act->id) {
783 		case FLOW_ACTION_GATE: {
784 			err = sparx5_tc_flower_parse_act_gate(&sg, act, extack);
785 			if (err < 0)
786 				goto out;
787 
788 			tc_sg_idx = act->hw_index;
789 
790 			break;
791 		}
792 		case FLOW_ACTION_POLICE: {
793 			err = sparx5_tc_flower_parse_act_police(&fm.pol, act,
794 								extack);
795 			if (err < 0)
796 				goto out;
797 
798 			tc_pol_idx = fm.pol.idx;
799 			sf.max_sdu = act->police.mtu;
800 
801 			break;
802 		}
803 		case FLOW_ACTION_TRAP:
804 			if (admin->vtype != VCAP_TYPE_IS2 &&
805 			    admin->vtype != VCAP_TYPE_ES2) {
806 				NL_SET_ERR_MSG_MOD(fco->common.extack,
807 						   "Trap action not supported in this VCAP");
808 				err = -EOPNOTSUPP;
809 				goto out;
810 			}
811 			err = vcap_rule_add_action_bit(vrule,
812 						       VCAP_AF_CPU_COPY_ENA,
813 						       VCAP_BIT_1);
814 			if (err)
815 				goto out;
816 			err = vcap_rule_add_action_u32(vrule,
817 						       VCAP_AF_CPU_QUEUE_NUM, 0);
818 			if (err)
819 				goto out;
820 			if (admin->vtype != VCAP_TYPE_IS2)
821 				break;
822 			err = vcap_rule_add_action_u32(vrule,
823 						       VCAP_AF_MASK_MODE,
824 				SPX5_PMM_REPLACE_ALL);
825 			if (err)
826 				goto out;
827 			break;
828 		case FLOW_ACTION_ACCEPT:
829 			err = sparx5_tc_set_actionset(admin, vrule);
830 			if (err)
831 				goto out;
832 			break;
833 		case FLOW_ACTION_GOTO:
834 			err = sparx5_tc_set_actionset(admin, vrule);
835 			if (err)
836 				goto out;
837 			sparx5_tc_add_rule_link(vctrl, admin, vrule,
838 						fco->common.chain_index,
839 						act->chain_index);
840 			break;
841 		default:
842 			NL_SET_ERR_MSG_MOD(fco->common.extack,
843 					   "Unsupported TC action");
844 			err = -EOPNOTSUPP;
845 			goto out;
846 		}
847 	}
848 
849 	/* Setup PSFP */
850 	if (tc_sg_idx >= 0 || tc_pol_idx >= 0) {
851 		err = sparx5_tc_flower_psfp_setup(sparx5, vrule, tc_sg_idx,
852 						  tc_pol_idx, &sg, &fm, &sf);
853 		if (err)
854 			goto out;
855 	}
856 
857 	err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin, l3_proto,
858 					       &multi);
859 	if (err) {
860 		NL_SET_ERR_MSG_MOD(fco->common.extack,
861 				   "No matching port keyset for filter protocol and keys");
862 		goto out;
863 	}
864 
865 	/* provide the l3 protocol to guide the keyset selection */
866 	err = vcap_val_rule(vrule, l3_proto);
867 	if (err) {
868 		vcap_set_tc_exterr(fco, vrule);
869 		goto out;
870 	}
871 	err = vcap_add_rule(vrule);
872 	if (err)
873 		NL_SET_ERR_MSG_MOD(fco->common.extack,
874 				   "Could not add the filter");
875 
876 	if (l3_proto == ETH_P_ALL)
877 		err = sparx5_tc_add_remaining_rules(vctrl, fco, vrule, admin,
878 						    &multi);
879 
880 out:
881 	vcap_free_rule(vrule);
882 	return err;
883 }
884 
885 static void sparx5_tc_free_psfp_resources(struct sparx5 *sparx5,
886 					  struct vcap_rule *vrule)
887 {
888 	struct vcap_client_actionfield *afield;
889 	u32 isdx, sfid, sgid, fmid;
890 
891 	/* Check if VCAP_AF_ISDX_VAL action is set for this rule - and if
892 	 * it is used for stream and/or flow-meter classification.
893 	 */
894 	afield = vcap_find_actionfield(vrule, VCAP_AF_ISDX_VAL);
895 	if (!afield)
896 		return;
897 
898 	isdx = afield->data.u32.value;
899 	sfid = sparx5_psfp_isdx_get_sf(sparx5, isdx);
900 
901 	if (!sfid)
902 		return;
903 
904 	fmid = sparx5_psfp_isdx_get_fm(sparx5, isdx);
905 	sgid = sparx5_psfp_sf_get_sg(sparx5, sfid);
906 
907 	if (fmid && sparx5_psfp_fm_del(sparx5, fmid) < 0)
908 		pr_err("%s:%d Could not delete invalid fmid: %d", __func__,
909 		       __LINE__, fmid);
910 
911 	if (sgid && sparx5_psfp_sg_del(sparx5, sgid) < 0)
912 		pr_err("%s:%d Could not delete invalid sgid: %d", __func__,
913 		       __LINE__, sgid);
914 
915 	if (sparx5_psfp_sf_del(sparx5, sfid) < 0)
916 		pr_err("%s:%d Could not delete invalid sfid: %d", __func__,
917 		       __LINE__, sfid);
918 
919 	sparx5_isdx_conf_set(sparx5, isdx, 0, 0);
920 }
921 
922 static int sparx5_tc_free_rule_resources(struct net_device *ndev,
923 					 struct vcap_control *vctrl,
924 					 int rule_id)
925 {
926 	struct sparx5_port *port = netdev_priv(ndev);
927 	struct sparx5 *sparx5 = port->sparx5;
928 	struct vcap_rule *vrule;
929 	int ret = 0;
930 
931 	vrule = vcap_get_rule(vctrl, rule_id);
932 	if (!vrule || IS_ERR(vrule))
933 		return -EINVAL;
934 
935 	sparx5_tc_free_psfp_resources(sparx5, vrule);
936 
937 	vcap_free_rule(vrule);
938 	return ret;
939 }
940 
941 static int sparx5_tc_flower_destroy(struct net_device *ndev,
942 				    struct flow_cls_offload *fco,
943 				    struct vcap_admin *admin)
944 {
945 	struct sparx5_port *port = netdev_priv(ndev);
946 	int err = -ENOENT, count = 0, rule_id;
947 	struct vcap_control *vctrl;
948 
949 	vctrl = port->sparx5->vcap_ctrl;
950 	while (true) {
951 		rule_id = vcap_lookup_rule_by_cookie(vctrl, fco->cookie);
952 		if (rule_id <= 0)
953 			break;
954 		if (count == 0) {
955 			/* Resources are attached to the first rule of
956 			 * a set of rules. Only works if the rules are
957 			 * in the correct order.
958 			 */
959 			err = sparx5_tc_free_rule_resources(ndev, vctrl,
960 							    rule_id);
961 			if (err)
962 				pr_err("%s:%d: could not free resources %d\n",
963 				       __func__, __LINE__, rule_id);
964 		}
965 		err = vcap_del_rule(vctrl, ndev, rule_id);
966 		if (err) {
967 			pr_err("%s:%d: could not delete rule %d\n",
968 			       __func__, __LINE__, rule_id);
969 			break;
970 		}
971 	}
972 	return err;
973 }
974 
975 static int sparx5_tc_flower_stats(struct net_device *ndev,
976 				  struct flow_cls_offload *fco,
977 				  struct vcap_admin *admin)
978 {
979 	struct sparx5_port *port = netdev_priv(ndev);
980 	struct vcap_counter ctr = {};
981 	struct vcap_control *vctrl;
982 	ulong lastused = 0;
983 	int err;
984 
985 	vctrl = port->sparx5->vcap_ctrl;
986 	err = vcap_get_rule_count_by_cookie(vctrl, &ctr, fco->cookie);
987 	if (err)
988 		return err;
989 	flow_stats_update(&fco->stats, 0x0, ctr.value, 0, lastused,
990 			  FLOW_ACTION_HW_STATS_IMMEDIATE);
991 	return err;
992 }
993 
994 int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
995 		     bool ingress)
996 {
997 	struct sparx5_port *port = netdev_priv(ndev);
998 	struct vcap_control *vctrl;
999 	struct vcap_admin *admin;
1000 	int err = -EINVAL;
1001 
1002 	/* Get vcap instance from the chain id */
1003 	vctrl = port->sparx5->vcap_ctrl;
1004 	admin = vcap_find_admin(vctrl, fco->common.chain_index);
1005 	if (!admin) {
1006 		NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid chain");
1007 		return err;
1008 	}
1009 
1010 	switch (fco->command) {
1011 	case FLOW_CLS_REPLACE:
1012 		return sparx5_tc_flower_replace(ndev, fco, admin, ingress);
1013 	case FLOW_CLS_DESTROY:
1014 		return sparx5_tc_flower_destroy(ndev, fco, admin);
1015 	case FLOW_CLS_STATS:
1016 		return sparx5_tc_flower_stats(ndev, fco, admin);
1017 	default:
1018 		return -EOPNOTSUPP;
1019 	}
1020 }
1021