1 // SPDX-License-Identifier: GPL-2.0+
4 * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries.
7 #include <net/tc_act/tc_gate.h>
10 #include "sparx5_tc.h"
12 #include "vcap_api_client.h"
14 #include "sparx5_main.h"
15 #include "sparx5_vcap_impl.h"
17 #define SPX5_MAX_RULE_SIZE 13 /* allows X1, X2, X4, X6 and X12 rules */
19 /* Collect keysets and type ids for multiple rules per size */
20 struct sparx5_wildcard_rule {
24 enum vcap_keyfield_set keyset;
27 struct sparx5_multiple_rules {
28 struct sparx5_wildcard_rule rule[SPX5_MAX_RULE_SIZE];
32 sparx5_tc_flower_handler_basic_usage(struct vcap_tc_flower_parse_usage *st)
34 struct flow_match_basic mt;
37 flow_rule_match_basic(st->frule, &mt);
39 if (mt.mask->n_proto) {
40 st->l3_proto = be16_to_cpu(mt.key->n_proto);
41 if (!sparx5_vcap_is_known_etype(st->admin, st->l3_proto)) {
42 err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE,
46 } else if (st->l3_proto == ETH_P_IP) {
47 err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
51 } else if (st->l3_proto == ETH_P_IPV6) {
52 err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
56 if (st->admin->vtype == VCAP_TYPE_IS0) {
57 err = vcap_rule_add_key_bit(st->vrule,
66 if (mt.mask->ip_proto) {
67 st->l4_proto = mt.key->ip_proto;
68 if (st->l4_proto == IPPROTO_TCP) {
69 err = vcap_rule_add_key_bit(st->vrule,
74 } else if (st->l4_proto == IPPROTO_UDP) {
75 err = vcap_rule_add_key_bit(st->vrule,
80 if (st->admin->vtype == VCAP_TYPE_IS0) {
81 err = vcap_rule_add_key_bit(st->vrule,
88 err = vcap_rule_add_key_u32(st->vrule,
96 st->used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC);
101 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error");
106 sparx5_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st)
108 struct flow_match_control mt;
112 flow_rule_match_control(st->frule, &mt);
114 if (mt.mask->flags) {
115 if (mt.mask->flags & FLOW_DIS_FIRST_FRAG) {
116 if (mt.key->flags & FLOW_DIS_FIRST_FRAG) {
117 value = 1; /* initial fragment */
120 if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) {
121 value = 3; /* follow up fragment */
124 value = 0; /* no fragment */
129 if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) {
130 value = 3; /* follow up fragment */
133 value = 0; /* no fragment */
138 err = vcap_rule_add_key_u32(st->vrule,
139 VCAP_KF_L3_FRAGMENT_TYPE,
145 st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL);
150 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error");
155 sparx5_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st)
157 if (st->admin->vtype != VCAP_TYPE_IS0) {
158 NL_SET_ERR_MSG_MOD(st->fco->common.extack,
159 "cvlan not supported in this VCAP");
163 return vcap_tc_flower_handler_cvlan_usage(st);
167 sparx5_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st)
169 enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS;
170 enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS;
172 if (st->admin->vtype == VCAP_TYPE_IS0) {
173 vid_key = VCAP_KF_8021Q_VID0;
174 pcp_key = VCAP_KF_8021Q_PCP0;
177 return vcap_tc_flower_handler_vlan_usage(st, vid_key, pcp_key);
180 static int (*sparx5_tc_flower_usage_handlers[])(struct vcap_tc_flower_parse_usage *st) = {
181 [FLOW_DISSECTOR_KEY_ETH_ADDRS] = vcap_tc_flower_handler_ethaddr_usage,
182 [FLOW_DISSECTOR_KEY_IPV4_ADDRS] = vcap_tc_flower_handler_ipv4_usage,
183 [FLOW_DISSECTOR_KEY_IPV6_ADDRS] = vcap_tc_flower_handler_ipv6_usage,
184 [FLOW_DISSECTOR_KEY_CONTROL] = sparx5_tc_flower_handler_control_usage,
185 [FLOW_DISSECTOR_KEY_PORTS] = vcap_tc_flower_handler_portnum_usage,
186 [FLOW_DISSECTOR_KEY_BASIC] = sparx5_tc_flower_handler_basic_usage,
187 [FLOW_DISSECTOR_KEY_CVLAN] = sparx5_tc_flower_handler_cvlan_usage,
188 [FLOW_DISSECTOR_KEY_VLAN] = sparx5_tc_flower_handler_vlan_usage,
189 [FLOW_DISSECTOR_KEY_TCP] = vcap_tc_flower_handler_tcp_usage,
190 [FLOW_DISSECTOR_KEY_ARP] = vcap_tc_flower_handler_arp_usage,
191 [FLOW_DISSECTOR_KEY_IP] = vcap_tc_flower_handler_ip_usage,
194 static int sparx5_tc_use_dissectors(struct flow_cls_offload *fco,
195 struct vcap_admin *admin,
196 struct vcap_rule *vrule,
199 struct vcap_tc_flower_parse_usage state = {
202 .l3_proto = ETH_P_ALL,
207 state.frule = flow_cls_offload_flow_rule(fco);
208 for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_flower_usage_handlers); ++idx) {
209 if (!flow_rule_match_key(state.frule, idx))
211 if (!sparx5_tc_flower_usage_handlers[idx])
213 err = sparx5_tc_flower_usage_handlers[idx](&state);
218 if (state.frule->match.dissector->used_keys ^ state.used_keys) {
219 NL_SET_ERR_MSG_MOD(fco->common.extack,
220 "Unsupported match item");
225 *l3_proto = state.l3_proto;
229 static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
230 struct net_device *ndev,
231 struct flow_cls_offload *fco,
234 struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
235 struct flow_action_entry *actent, *last_actent = NULL;
236 struct flow_action *act = &rule->action;
240 if (!flow_action_has_entries(act)) {
241 NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions");
245 if (!flow_action_basic_hw_stats_check(act, fco->common.extack))
248 flow_action_for_each(idx, actent, act) {
249 if (action_mask & BIT(actent->id)) {
250 NL_SET_ERR_MSG_MOD(fco->common.extack,
251 "More actions of the same type");
254 action_mask |= BIT(actent->id);
255 last_actent = actent; /* Save last action for later check */
258 /* Check if last action is a goto
259 * The last chain/lookup does not need to have a goto action
261 if (last_actent->id == FLOW_ACTION_GOTO) {
262 /* Check if the destination chain is in one of the VCAPs */
263 if (!vcap_is_next_lookup(vctrl, fco->common.chain_index,
264 last_actent->chain_index)) {
265 NL_SET_ERR_MSG_MOD(fco->common.extack,
266 "Invalid goto chain");
269 } else if (!vcap_is_last_chain(vctrl, fco->common.chain_index,
271 NL_SET_ERR_MSG_MOD(fco->common.extack,
272 "Last action must be 'goto'");
276 /* Catch unsupported combinations of actions */
277 if (action_mask & BIT(FLOW_ACTION_TRAP) &&
278 action_mask & BIT(FLOW_ACTION_ACCEPT)) {
279 NL_SET_ERR_MSG_MOD(fco->common.extack,
280 "Cannot combine pass and trap action");
287 /* Add a rule counter action */
288 static int sparx5_tc_add_rule_counter(struct vcap_admin *admin,
289 struct vcap_rule *vrule)
293 switch (admin->vtype) {
297 err = vcap_rule_mod_action_u32(vrule, VCAP_AF_ESDX,
301 vcap_rule_set_counter_id(vrule, vrule->id);
305 err = vcap_rule_mod_action_u32(vrule, VCAP_AF_CNT_ID,
309 vcap_rule_set_counter_id(vrule, vrule->id);
312 pr_err("%s:%d: vcap type: %d not supported\n",
313 __func__, __LINE__, admin->vtype);
319 /* Collect all port keysets and apply the first of them, possibly wildcarded */
320 static int sparx5_tc_select_protocol_keyset(struct net_device *ndev,
321 struct vcap_rule *vrule,
322 struct vcap_admin *admin,
324 struct sparx5_multiple_rules *multi)
326 struct sparx5_port *port = netdev_priv(ndev);
327 struct vcap_keyset_list portkeysetlist = {};
328 enum vcap_keyfield_set portkeysets[10] = {};
329 struct vcap_keyset_list matches = {};
330 enum vcap_keyfield_set keysets[10];
331 int idx, jdx, err = 0, count = 0;
332 struct sparx5_wildcard_rule *mru;
333 const struct vcap_set *kinfo;
334 struct vcap_control *vctrl;
336 vctrl = port->sparx5->vcap_ctrl;
338 /* Find the keysets that the rule can use */
339 matches.keysets = keysets;
340 matches.max = ARRAY_SIZE(keysets);
341 if (vcap_rule_find_keysets(vrule, &matches) == 0)
344 /* Find the keysets that the port configuration supports */
345 portkeysetlist.max = ARRAY_SIZE(portkeysets);
346 portkeysetlist.keysets = portkeysets;
347 err = sparx5_vcap_get_port_keyset(ndev,
348 admin, vrule->vcap_chain_id,
354 /* Find the intersection of the two sets of keyset */
355 for (idx = 0; idx < portkeysetlist.cnt; ++idx) {
356 kinfo = vcap_keyfieldset(vctrl, admin->vtype,
357 portkeysetlist.keysets[idx]);
361 /* Find a port keyset that matches the required keys
362 * If there are multiple keysets then compose a type id mask
364 for (jdx = 0; jdx < matches.cnt; ++jdx) {
365 if (portkeysetlist.keysets[idx] != matches.keysets[jdx])
368 mru = &multi->rule[kinfo->sw_per_item];
369 if (!mru->selected) {
370 mru->selected = true;
371 mru->keyset = portkeysetlist.keysets[idx];
372 mru->value = kinfo->type_id;
374 mru->value &= kinfo->type_id;
375 mru->mask |= kinfo->type_id;
382 if (l3_proto == ETH_P_ALL && count < portkeysetlist.cnt)
385 for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
386 mru = &multi->rule[idx];
390 /* Align the mask to the combined value */
391 mru->mask ^= mru->value;
394 /* Set the chosen keyset on the rule and set a wildcarded type if there
395 * are more than one keyset
397 for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
398 mru = &multi->rule[idx];
402 vcap_set_rule_set_keyset(vrule, mru->keyset);
404 /* Some keysets do not have a type field */
405 vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE,
408 mru->selected = false; /* mark as done */
409 break; /* Stop here and add more rules later */
414 static int sparx5_tc_add_rule_copy(struct vcap_control *vctrl,
415 struct flow_cls_offload *fco,
416 struct vcap_rule *erule,
417 struct vcap_admin *admin,
418 struct sparx5_wildcard_rule *rule)
420 enum vcap_key_field keylist[] = {
421 VCAP_KF_IF_IGR_PORT_MASK,
422 VCAP_KF_IF_IGR_PORT_MASK_SEL,
423 VCAP_KF_IF_IGR_PORT_MASK_RNG,
424 VCAP_KF_LOOKUP_FIRST_IS,
427 struct vcap_rule *vrule;
430 /* Add an extra rule with a special user and the new keyset */
431 erule->user = VCAP_USER_TC_EXTRA;
432 vrule = vcap_copy_rule(erule);
434 return PTR_ERR(vrule);
436 /* Link the new rule to the existing rule with the cookie */
437 vrule->cookie = erule->cookie;
438 vcap_filter_rule_keys(vrule, keylist, ARRAY_SIZE(keylist), true);
439 err = vcap_set_rule_set_keyset(vrule, rule->keyset);
441 pr_err("%s:%d: could not set keyset %s in rule: %u\n",
443 vcap_keyset_name(vctrl, rule->keyset),
448 /* Some keysets do not have a type field, so ignore return value */
449 vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE, rule->value, ~rule->mask);
451 err = vcap_set_rule_set_actionset(vrule, erule->actionset);
455 err = sparx5_tc_add_rule_counter(admin, vrule);
459 err = vcap_val_rule(vrule, ETH_P_ALL);
461 pr_err("%s:%d: could not validate rule: %u\n",
462 __func__, __LINE__, vrule->id);
463 vcap_set_tc_exterr(fco, vrule);
466 err = vcap_add_rule(vrule);
468 pr_err("%s:%d: could not add rule: %u\n",
469 __func__, __LINE__, vrule->id);
473 vcap_free_rule(vrule);
477 static int sparx5_tc_add_remaining_rules(struct vcap_control *vctrl,
478 struct flow_cls_offload *fco,
479 struct vcap_rule *erule,
480 struct vcap_admin *admin,
481 struct sparx5_multiple_rules *multi)
485 for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
486 if (!multi->rule[idx].selected)
489 err = sparx5_tc_add_rule_copy(vctrl, fco, erule, admin,
497 /* Add the actionset that is the default for the VCAP type */
498 static int sparx5_tc_set_actionset(struct vcap_admin *admin,
499 struct vcap_rule *vrule)
501 enum vcap_actionfield_set aset;
504 switch (admin->vtype) {
506 aset = VCAP_AFS_CLASSIFICATION;
509 aset = VCAP_AFS_BASE_TYPE;
512 aset = VCAP_AFS_BASE_TYPE;
517 /* Do not overwrite any current actionset */
518 if (vrule->actionset == VCAP_AFS_NO_VALUE)
519 err = vcap_set_rule_set_actionset(vrule, aset);
523 /* Add the VCAP key to match on for a rule target value */
524 static int sparx5_tc_add_rule_link_target(struct vcap_admin *admin,
525 struct vcap_rule *vrule,
528 int link_val = target_cid % VCAP_CID_LOOKUP_SIZE;
534 switch (admin->vtype) {
536 /* Add NXT_IDX key for chaining rules between IS0 instances */
537 err = vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX_SEL,
542 return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX,
543 link_val, /* target */
546 /* Add PAG key for chaining rules from IS0 */
547 return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG,
548 link_val, /* target */
551 /* Add ISDX key for chaining rules from IS0 */
552 return vcap_rule_add_key_u32(vrule, VCAP_KF_ISDX_CLS, link_val,
560 /* Add the VCAP action that adds a target value to a rule */
561 static int sparx5_tc_add_rule_link(struct vcap_control *vctrl,
562 struct vcap_admin *admin,
563 struct vcap_rule *vrule,
564 int from_cid, int to_cid)
566 struct vcap_admin *to_admin = vcap_find_admin(vctrl, to_cid);
570 pr_err("%s:%d: unsupported chain direction: %d\n",
571 __func__, __LINE__, to_cid);
575 diff = vcap_chain_offset(vctrl, from_cid, to_cid);
579 if (admin->vtype == VCAP_TYPE_IS0 &&
580 to_admin->vtype == VCAP_TYPE_IS0) {
581 /* Between IS0 instances the G_IDX value is used */
582 err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX, diff);
585 err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX_CTRL,
589 } else if (admin->vtype == VCAP_TYPE_IS0 &&
590 to_admin->vtype == VCAP_TYPE_IS2) {
591 /* Between IS0 and IS2 the PAG value is used */
592 err = vcap_rule_add_action_u32(vrule, VCAP_AF_PAG_VAL, diff);
595 err = vcap_rule_add_action_u32(vrule,
596 VCAP_AF_PAG_OVERRIDE_MASK,
600 } else if (admin->vtype == VCAP_TYPE_IS0 &&
601 to_admin->vtype == VCAP_TYPE_ES2) {
602 /* Between IS0 and ES2 the ISDX value is used */
603 err = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL,
607 err = vcap_rule_add_action_bit(vrule,
608 VCAP_AF_ISDX_ADD_REPLACE_SEL,
613 pr_err("%s:%d: unsupported chain destination: %d\n",
614 __func__, __LINE__, to_cid);
621 static int sparx5_tc_flower_parse_act_gate(struct sparx5_psfp_sg *sg,
622 struct flow_action_entry *act,
623 struct netlink_ext_ack *extack)
627 if (act->gate.prio < -1 || act->gate.prio > SPX5_PSFP_SG_MAX_IPV) {
628 NL_SET_ERR_MSG_MOD(extack, "Invalid gate priority");
632 if (act->gate.cycletime < SPX5_PSFP_SG_MIN_CYCLE_TIME_NS ||
633 act->gate.cycletime > SPX5_PSFP_SG_MAX_CYCLE_TIME_NS) {
634 NL_SET_ERR_MSG_MOD(extack, "Invalid gate cycletime");
638 if (act->gate.cycletimeext > SPX5_PSFP_SG_MAX_CYCLE_TIME_NS) {
639 NL_SET_ERR_MSG_MOD(extack, "Invalid gate cycletimeext");
643 if (act->gate.num_entries >= SPX5_PSFP_GCE_CNT) {
644 NL_SET_ERR_MSG_MOD(extack, "Invalid number of gate entries");
648 sg->gate_state = true;
649 sg->ipv = act->gate.prio;
650 sg->num_entries = act->gate.num_entries;
651 sg->cycletime = act->gate.cycletime;
652 sg->cycletimeext = act->gate.cycletimeext;
654 for (i = 0; i < sg->num_entries; i++) {
655 sg->gce[i].gate_state = !!act->gate.entries[i].gate_state;
656 sg->gce[i].interval = act->gate.entries[i].interval;
657 sg->gce[i].ipv = act->gate.entries[i].ipv;
658 sg->gce[i].maxoctets = act->gate.entries[i].maxoctets;
664 static int sparx5_tc_flower_parse_act_police(struct sparx5_policer *pol,
665 struct flow_action_entry *act,
666 struct netlink_ext_ack *extack)
668 pol->type = SPX5_POL_SERVICE;
669 pol->rate = div_u64(act->police.rate_bytes_ps, 1000) * 8;
670 pol->burst = act->police.burst;
671 pol->idx = act->hw_index;
673 /* rate is now in kbit */
674 if (pol->rate > DIV_ROUND_UP(SPX5_SDLB_GROUP_RATE_MAX, 1000)) {
675 NL_SET_ERR_MSG_MOD(extack, "Maximum rate exceeded");
679 if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
680 NL_SET_ERR_MSG_MOD(extack, "Offload not supported when exceed action is not drop");
684 if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
685 act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
686 NL_SET_ERR_MSG_MOD(extack, "Offload not supported when conform action is not pipe or ok");
693 static int sparx5_tc_flower_psfp_setup(struct sparx5 *sparx5,
694 struct vcap_rule *vrule, int sg_idx,
695 int pol_idx, struct sparx5_psfp_sg *sg,
696 struct sparx5_psfp_fm *fm,
697 struct sparx5_psfp_sf *sf)
699 u32 psfp_sfid = 0, psfp_fmid = 0, psfp_sgid = 0;
702 /* Must always have a stream gate - max sdu (filter option) is evaluated
703 * after frames have passed the gate, so in case of only a policer, we
704 * allocate a stream gate that is always open.
707 sg_idx = sparx5_pool_idx_to_id(SPX5_PSFP_SG_OPEN);
708 sg->ipv = 0; /* Disabled */
709 sg->cycletime = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT;
711 sg->gate_state = 1; /* Open */
712 sg->gate_enabled = 1;
713 sg->gce[0].gate_state = 1;
714 sg->gce[0].interval = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT;
716 sg->gce[0].maxoctets = 0; /* Disabled */
719 ret = sparx5_psfp_sg_add(sparx5, sg_idx, sg, &psfp_sgid);
724 /* Add new flow-meter */
725 ret = sparx5_psfp_fm_add(sparx5, pol_idx, fm, &psfp_fmid);
730 /* Map stream filter to stream gate */
731 sf->sgid = psfp_sgid;
733 /* Add new stream-filter and map it to a steam gate */
734 ret = sparx5_psfp_sf_add(sparx5, sf, &psfp_sfid);
738 /* Streams are classified by ISDX - map ISDX 1:1 to sfid for now. */
739 sparx5_isdx_conf_set(sparx5, psfp_sfid, psfp_sfid, psfp_fmid);
741 ret = vcap_rule_add_action_bit(vrule, VCAP_AF_ISDX_ADD_REPLACE_SEL,
746 ret = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL, psfp_sfid);
753 static int sparx5_tc_flower_replace(struct net_device *ndev,
754 struct flow_cls_offload *fco,
755 struct vcap_admin *admin,
758 struct sparx5_psfp_sf sf = { .max_sdu = SPX5_PSFP_SF_MAX_SDU };
759 struct netlink_ext_ack *extack = fco->common.extack;
760 int err, idx, tc_sg_idx = -1, tc_pol_idx = -1;
761 struct sparx5_port *port = netdev_priv(ndev);
762 struct sparx5_multiple_rules multi = {};
763 struct sparx5 *sparx5 = port->sparx5;
764 struct sparx5_psfp_sg sg = { 0 };
765 struct sparx5_psfp_fm fm = { 0 };
766 struct flow_action_entry *act;
767 struct vcap_control *vctrl;
768 struct flow_rule *frule;
769 struct vcap_rule *vrule;
772 vctrl = port->sparx5->vcap_ctrl;
774 err = sparx5_tc_flower_action_check(vctrl, ndev, fco, ingress);
778 vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, VCAP_USER_TC,
779 fco->common.prio, 0);
781 return PTR_ERR(vrule);
783 vrule->cookie = fco->cookie;
785 l3_proto = ETH_P_ALL;
786 err = sparx5_tc_use_dissectors(fco, admin, vrule, &l3_proto);
790 err = sparx5_tc_add_rule_counter(admin, vrule);
794 err = sparx5_tc_add_rule_link_target(admin, vrule,
795 fco->common.chain_index);
799 frule = flow_cls_offload_flow_rule(fco);
800 flow_action_for_each(idx, act, &frule->action) {
802 case FLOW_ACTION_GATE: {
803 err = sparx5_tc_flower_parse_act_gate(&sg, act, extack);
807 tc_sg_idx = act->hw_index;
811 case FLOW_ACTION_POLICE: {
812 err = sparx5_tc_flower_parse_act_police(&fm.pol, act,
817 tc_pol_idx = fm.pol.idx;
818 sf.max_sdu = act->police.mtu;
822 case FLOW_ACTION_TRAP:
823 if (admin->vtype != VCAP_TYPE_IS2 &&
824 admin->vtype != VCAP_TYPE_ES2) {
825 NL_SET_ERR_MSG_MOD(fco->common.extack,
826 "Trap action not supported in this VCAP");
830 err = vcap_rule_add_action_bit(vrule,
831 VCAP_AF_CPU_COPY_ENA,
835 err = vcap_rule_add_action_u32(vrule,
836 VCAP_AF_CPU_QUEUE_NUM, 0);
839 if (admin->vtype != VCAP_TYPE_IS2)
841 err = vcap_rule_add_action_u32(vrule,
843 SPX5_PMM_REPLACE_ALL);
847 case FLOW_ACTION_ACCEPT:
848 err = sparx5_tc_set_actionset(admin, vrule);
852 case FLOW_ACTION_GOTO:
853 err = sparx5_tc_set_actionset(admin, vrule);
856 sparx5_tc_add_rule_link(vctrl, admin, vrule,
857 fco->common.chain_index,
861 NL_SET_ERR_MSG_MOD(fco->common.extack,
862 "Unsupported TC action");
869 if (tc_sg_idx >= 0 || tc_pol_idx >= 0) {
870 err = sparx5_tc_flower_psfp_setup(sparx5, vrule, tc_sg_idx,
871 tc_pol_idx, &sg, &fm, &sf);
876 err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin, l3_proto,
879 NL_SET_ERR_MSG_MOD(fco->common.extack,
880 "No matching port keyset for filter protocol and keys");
884 /* provide the l3 protocol to guide the keyset selection */
885 err = vcap_val_rule(vrule, l3_proto);
887 vcap_set_tc_exterr(fco, vrule);
890 err = vcap_add_rule(vrule);
892 NL_SET_ERR_MSG_MOD(fco->common.extack,
893 "Could not add the filter");
895 if (l3_proto == ETH_P_ALL)
896 err = sparx5_tc_add_remaining_rules(vctrl, fco, vrule, admin,
900 vcap_free_rule(vrule);
904 static void sparx5_tc_free_psfp_resources(struct sparx5 *sparx5,
905 struct vcap_rule *vrule)
907 struct vcap_client_actionfield *afield;
908 u32 isdx, sfid, sgid, fmid;
910 /* Check if VCAP_AF_ISDX_VAL action is set for this rule - and if
911 * it is used for stream and/or flow-meter classification.
913 afield = vcap_find_actionfield(vrule, VCAP_AF_ISDX_VAL);
917 isdx = afield->data.u32.value;
918 sfid = sparx5_psfp_isdx_get_sf(sparx5, isdx);
923 fmid = sparx5_psfp_isdx_get_fm(sparx5, isdx);
924 sgid = sparx5_psfp_sf_get_sg(sparx5, sfid);
926 if (fmid && sparx5_psfp_fm_del(sparx5, fmid) < 0)
927 pr_err("%s:%d Could not delete invalid fmid: %d", __func__,
930 if (sgid && sparx5_psfp_sg_del(sparx5, sgid) < 0)
931 pr_err("%s:%d Could not delete invalid sgid: %d", __func__,
934 if (sparx5_psfp_sf_del(sparx5, sfid) < 0)
935 pr_err("%s:%d Could not delete invalid sfid: %d", __func__,
938 sparx5_isdx_conf_set(sparx5, isdx, 0, 0);
941 static int sparx5_tc_free_rule_resources(struct net_device *ndev,
942 struct vcap_control *vctrl,
945 struct sparx5_port *port = netdev_priv(ndev);
946 struct sparx5 *sparx5 = port->sparx5;
947 struct vcap_rule *vrule;
950 vrule = vcap_get_rule(vctrl, rule_id);
951 if (!vrule || IS_ERR(vrule))
954 sparx5_tc_free_psfp_resources(sparx5, vrule);
956 vcap_free_rule(vrule);
960 static int sparx5_tc_flower_destroy(struct net_device *ndev,
961 struct flow_cls_offload *fco,
962 struct vcap_admin *admin)
964 struct sparx5_port *port = netdev_priv(ndev);
965 int err = -ENOENT, count = 0, rule_id;
966 struct vcap_control *vctrl;
968 vctrl = port->sparx5->vcap_ctrl;
970 rule_id = vcap_lookup_rule_by_cookie(vctrl, fco->cookie);
974 /* Resources are attached to the first rule of
975 * a set of rules. Only works if the rules are
976 * in the correct order.
978 err = sparx5_tc_free_rule_resources(ndev, vctrl,
981 pr_err("%s:%d: could not free resources %d\n",
982 __func__, __LINE__, rule_id);
984 err = vcap_del_rule(vctrl, ndev, rule_id);
986 pr_err("%s:%d: could not delete rule %d\n",
987 __func__, __LINE__, rule_id);
994 static int sparx5_tc_flower_stats(struct net_device *ndev,
995 struct flow_cls_offload *fco,
996 struct vcap_admin *admin)
998 struct sparx5_port *port = netdev_priv(ndev);
999 struct vcap_counter ctr = {};
1000 struct vcap_control *vctrl;
1004 vctrl = port->sparx5->vcap_ctrl;
1005 err = vcap_get_rule_count_by_cookie(vctrl, &ctr, fco->cookie);
1008 flow_stats_update(&fco->stats, 0x0, ctr.value, 0, lastused,
1009 FLOW_ACTION_HW_STATS_IMMEDIATE);
1013 int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
1016 struct sparx5_port *port = netdev_priv(ndev);
1017 struct vcap_control *vctrl;
1018 struct vcap_admin *admin;
1021 /* Get vcap instance from the chain id */
1022 vctrl = port->sparx5->vcap_ctrl;
1023 admin = vcap_find_admin(vctrl, fco->common.chain_index);
1025 NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid chain");
1029 switch (fco->command) {
1030 case FLOW_CLS_REPLACE:
1031 return sparx5_tc_flower_replace(ndev, fco, admin, ingress);
1032 case FLOW_CLS_DESTROY:
1033 return sparx5_tc_flower_destroy(ndev, fco, admin);
1034 case FLOW_CLS_STATS:
1035 return sparx5_tc_flower_stats(ndev, fco, admin);