Linux Audio

Check our new training course

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