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];
31 struct 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 */
40 sparx5_tc_flower_es0_tpid(struct vcap_tc_flower_parse_usage *st)
46 err = vcap_rule_add_key_u32(st->vrule,
48 SPX5_TPID_SEL_8100, ~0);
51 err = vcap_rule_add_key_u32(st->vrule,
53 SPX5_TPID_SEL_88A8, ~0);
56 NL_SET_ERR_MSG_MOD(st->fco->common.extack,
57 "Invalid vlan proto");
65 sparx5_tc_flower_handler_basic_usage(struct vcap_tc_flower_parse_usage *st)
67 struct flow_match_basic mt;
70 flow_rule_match_basic(st->frule, &mt);
72 if (mt.mask->n_proto) {
73 st->l3_proto = be16_to_cpu(mt.key->n_proto);
74 if (!sparx5_vcap_is_known_etype(st->admin, st->l3_proto)) {
75 err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE,
79 } else if (st->l3_proto == ETH_P_IP) {
80 err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
84 } else if (st->l3_proto == ETH_P_IPV6) {
85 err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
89 if (st->admin->vtype == VCAP_TYPE_IS0) {
90 err = vcap_rule_add_key_bit(st->vrule,
99 if (mt.mask->ip_proto) {
100 st->l4_proto = mt.key->ip_proto;
101 if (st->l4_proto == IPPROTO_TCP) {
102 err = vcap_rule_add_key_bit(st->vrule,
107 } else if (st->l4_proto == IPPROTO_UDP) {
108 err = vcap_rule_add_key_bit(st->vrule,
113 if (st->admin->vtype == VCAP_TYPE_IS0) {
114 err = vcap_rule_add_key_bit(st->vrule,
121 err = vcap_rule_add_key_u32(st->vrule,
129 st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_BASIC);
134 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error");
139 sparx5_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st)
141 struct flow_match_control mt;
145 flow_rule_match_control(st->frule, &mt);
147 if (mt.mask->flags) {
148 if (mt.mask->flags & FLOW_DIS_FIRST_FRAG) {
149 if (mt.key->flags & FLOW_DIS_FIRST_FRAG) {
150 value = 1; /* initial fragment */
153 if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) {
154 value = 3; /* follow up fragment */
157 value = 0; /* no fragment */
162 if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) {
163 value = 3; /* follow up fragment */
166 value = 0; /* no fragment */
171 err = vcap_rule_add_key_u32(st->vrule,
172 VCAP_KF_L3_FRAGMENT_TYPE,
178 st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL);
183 NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error");
188 sparx5_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st)
190 if (st->admin->vtype != VCAP_TYPE_IS0) {
191 NL_SET_ERR_MSG_MOD(st->fco->common.extack,
192 "cvlan not supported in this VCAP");
196 return vcap_tc_flower_handler_cvlan_usage(st);
200 sparx5_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st)
202 enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS;
203 enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS;
206 if (st->admin->vtype == VCAP_TYPE_IS0) {
207 vid_key = VCAP_KF_8021Q_VID0;
208 pcp_key = VCAP_KF_8021Q_PCP0;
211 err = vcap_tc_flower_handler_vlan_usage(st, vid_key, pcp_key);
215 if (st->admin->vtype == VCAP_TYPE_ES0 && st->tpid)
216 err = sparx5_tc_flower_es0_tpid(st);
221 static int (*sparx5_tc_flower_usage_handlers[])(struct vcap_tc_flower_parse_usage *st) = {
222 [FLOW_DISSECTOR_KEY_ETH_ADDRS] = vcap_tc_flower_handler_ethaddr_usage,
223 [FLOW_DISSECTOR_KEY_IPV4_ADDRS] = vcap_tc_flower_handler_ipv4_usage,
224 [FLOW_DISSECTOR_KEY_IPV6_ADDRS] = vcap_tc_flower_handler_ipv6_usage,
225 [FLOW_DISSECTOR_KEY_CONTROL] = sparx5_tc_flower_handler_control_usage,
226 [FLOW_DISSECTOR_KEY_PORTS] = vcap_tc_flower_handler_portnum_usage,
227 [FLOW_DISSECTOR_KEY_BASIC] = sparx5_tc_flower_handler_basic_usage,
228 [FLOW_DISSECTOR_KEY_CVLAN] = sparx5_tc_flower_handler_cvlan_usage,
229 [FLOW_DISSECTOR_KEY_VLAN] = sparx5_tc_flower_handler_vlan_usage,
230 [FLOW_DISSECTOR_KEY_TCP] = vcap_tc_flower_handler_tcp_usage,
231 [FLOW_DISSECTOR_KEY_ARP] = vcap_tc_flower_handler_arp_usage,
232 [FLOW_DISSECTOR_KEY_IP] = vcap_tc_flower_handler_ip_usage,
235 static int sparx5_tc_use_dissectors(struct vcap_tc_flower_parse_usage *st,
236 struct vcap_admin *admin,
237 struct vcap_rule *vrule)
241 for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_flower_usage_handlers); ++idx) {
242 if (!flow_rule_match_key(st->frule, idx))
244 if (!sparx5_tc_flower_usage_handlers[idx])
246 err = sparx5_tc_flower_usage_handlers[idx](st);
251 if (st->frule->match.dissector->used_keys ^ st->used_keys) {
252 NL_SET_ERR_MSG_MOD(st->fco->common.extack,
253 "Unsupported match item");
260 static int sparx5_tc_flower_action_check(struct vcap_control *vctrl,
261 struct net_device *ndev,
262 struct flow_cls_offload *fco,
265 struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
266 struct flow_action_entry *actent, *last_actent = NULL;
267 struct flow_action *act = &rule->action;
271 if (!flow_action_has_entries(act)) {
272 NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions");
276 if (!flow_action_basic_hw_stats_check(act, fco->common.extack))
279 flow_action_for_each(idx, actent, act) {
280 if (action_mask & BIT(actent->id)) {
281 NL_SET_ERR_MSG_MOD(fco->common.extack,
282 "More actions of the same type");
285 action_mask |= BIT(actent->id);
286 last_actent = actent; /* Save last action for later check */
289 /* Check if last action is a goto
290 * The last chain/lookup does not need to have a goto action
292 if (last_actent->id == FLOW_ACTION_GOTO) {
293 /* Check if the destination chain is in one of the VCAPs */
294 if (!vcap_is_next_lookup(vctrl, fco->common.chain_index,
295 last_actent->chain_index)) {
296 NL_SET_ERR_MSG_MOD(fco->common.extack,
297 "Invalid goto chain");
300 } else if (!vcap_is_last_chain(vctrl, fco->common.chain_index,
302 NL_SET_ERR_MSG_MOD(fco->common.extack,
303 "Last action must be 'goto'");
307 /* Catch unsupported combinations of actions */
308 if (action_mask & BIT(FLOW_ACTION_TRAP) &&
309 action_mask & BIT(FLOW_ACTION_ACCEPT)) {
310 NL_SET_ERR_MSG_MOD(fco->common.extack,
311 "Cannot combine pass and trap action");
315 if (action_mask & BIT(FLOW_ACTION_VLAN_PUSH) &&
316 action_mask & BIT(FLOW_ACTION_VLAN_POP)) {
317 NL_SET_ERR_MSG_MOD(fco->common.extack,
318 "Cannot combine vlan push and pop action");
322 if (action_mask & BIT(FLOW_ACTION_VLAN_PUSH) &&
323 action_mask & BIT(FLOW_ACTION_VLAN_MANGLE)) {
324 NL_SET_ERR_MSG_MOD(fco->common.extack,
325 "Cannot combine vlan push and modify action");
329 if (action_mask & BIT(FLOW_ACTION_VLAN_POP) &&
330 action_mask & BIT(FLOW_ACTION_VLAN_MANGLE)) {
331 NL_SET_ERR_MSG_MOD(fco->common.extack,
332 "Cannot combine vlan pop and modify action");
339 /* Add a rule counter action */
340 static int sparx5_tc_add_rule_counter(struct vcap_admin *admin,
341 struct vcap_rule *vrule)
345 switch (admin->vtype) {
349 err = vcap_rule_mod_action_u32(vrule, VCAP_AF_ESDX,
353 vcap_rule_set_counter_id(vrule, vrule->id);
357 err = vcap_rule_mod_action_u32(vrule, VCAP_AF_CNT_ID,
361 vcap_rule_set_counter_id(vrule, vrule->id);
364 pr_err("%s:%d: vcap type: %d not supported\n",
365 __func__, __LINE__, admin->vtype);
371 /* Collect all port keysets and apply the first of them, possibly wildcarded */
372 static int sparx5_tc_select_protocol_keyset(struct net_device *ndev,
373 struct vcap_rule *vrule,
374 struct vcap_admin *admin,
376 struct sparx5_multiple_rules *multi)
378 struct sparx5_port *port = netdev_priv(ndev);
379 struct vcap_keyset_list portkeysetlist = {};
380 enum vcap_keyfield_set portkeysets[10] = {};
381 struct vcap_keyset_list matches = {};
382 enum vcap_keyfield_set keysets[10];
383 int idx, jdx, err = 0, count = 0;
384 struct sparx5_wildcard_rule *mru;
385 const struct vcap_set *kinfo;
386 struct vcap_control *vctrl;
388 vctrl = port->sparx5->vcap_ctrl;
390 /* Find the keysets that the rule can use */
391 matches.keysets = keysets;
392 matches.max = ARRAY_SIZE(keysets);
393 if (!vcap_rule_find_keysets(vrule, &matches))
396 /* Find the keysets that the port configuration supports */
397 portkeysetlist.max = ARRAY_SIZE(portkeysets);
398 portkeysetlist.keysets = portkeysets;
399 err = sparx5_vcap_get_port_keyset(ndev,
400 admin, vrule->vcap_chain_id,
406 /* Find the intersection of the two sets of keyset */
407 for (idx = 0; idx < portkeysetlist.cnt; ++idx) {
408 kinfo = vcap_keyfieldset(vctrl, admin->vtype,
409 portkeysetlist.keysets[idx]);
413 /* Find a port keyset that matches the required keys
414 * If there are multiple keysets then compose a type id mask
416 for (jdx = 0; jdx < matches.cnt; ++jdx) {
417 if (portkeysetlist.keysets[idx] != matches.keysets[jdx])
420 mru = &multi->rule[kinfo->sw_per_item];
421 if (!mru->selected) {
422 mru->selected = true;
423 mru->keyset = portkeysetlist.keysets[idx];
424 mru->value = kinfo->type_id;
426 mru->value &= kinfo->type_id;
427 mru->mask |= kinfo->type_id;
434 if (l3_proto == ETH_P_ALL && count < portkeysetlist.cnt)
437 for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
438 mru = &multi->rule[idx];
442 /* Align the mask to the combined value */
443 mru->mask ^= mru->value;
446 /* Set the chosen keyset on the rule and set a wildcarded type if there
447 * are more than one keyset
449 for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
450 mru = &multi->rule[idx];
454 vcap_set_rule_set_keyset(vrule, mru->keyset);
456 /* Some keysets do not have a type field */
457 vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE,
460 mru->selected = false; /* mark as done */
461 break; /* Stop here and add more rules later */
466 static int sparx5_tc_add_rule_copy(struct vcap_control *vctrl,
467 struct flow_cls_offload *fco,
468 struct vcap_rule *erule,
469 struct vcap_admin *admin,
470 struct sparx5_wildcard_rule *rule)
472 enum vcap_key_field keylist[] = {
473 VCAP_KF_IF_IGR_PORT_MASK,
474 VCAP_KF_IF_IGR_PORT_MASK_SEL,
475 VCAP_KF_IF_IGR_PORT_MASK_RNG,
476 VCAP_KF_LOOKUP_FIRST_IS,
479 struct vcap_rule *vrule;
482 /* Add an extra rule with a special user and the new keyset */
483 erule->user = VCAP_USER_TC_EXTRA;
484 vrule = vcap_copy_rule(erule);
486 return PTR_ERR(vrule);
488 /* Link the new rule to the existing rule with the cookie */
489 vrule->cookie = erule->cookie;
490 vcap_filter_rule_keys(vrule, keylist, ARRAY_SIZE(keylist), true);
491 err = vcap_set_rule_set_keyset(vrule, rule->keyset);
493 pr_err("%s:%d: could not set keyset %s in rule: %u\n",
495 vcap_keyset_name(vctrl, rule->keyset),
500 /* Some keysets do not have a type field, so ignore return value */
501 vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE, rule->value, ~rule->mask);
503 err = vcap_set_rule_set_actionset(vrule, erule->actionset);
507 err = sparx5_tc_add_rule_counter(admin, vrule);
511 err = vcap_val_rule(vrule, ETH_P_ALL);
513 pr_err("%s:%d: could not validate rule: %u\n",
514 __func__, __LINE__, vrule->id);
515 vcap_set_tc_exterr(fco, vrule);
518 err = vcap_add_rule(vrule);
520 pr_err("%s:%d: could not add rule: %u\n",
521 __func__, __LINE__, vrule->id);
525 vcap_free_rule(vrule);
529 static int sparx5_tc_add_remaining_rules(struct vcap_control *vctrl,
530 struct flow_cls_offload *fco,
531 struct vcap_rule *erule,
532 struct vcap_admin *admin,
533 struct sparx5_multiple_rules *multi)
537 for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) {
538 if (!multi->rule[idx].selected)
541 err = sparx5_tc_add_rule_copy(vctrl, fco, erule, admin,
549 /* Add the actionset that is the default for the VCAP type */
550 static int sparx5_tc_set_actionset(struct vcap_admin *admin,
551 struct vcap_rule *vrule)
553 enum vcap_actionfield_set aset;
556 switch (admin->vtype) {
558 aset = VCAP_AFS_CLASSIFICATION;
561 aset = VCAP_AFS_BASE_TYPE;
567 aset = VCAP_AFS_BASE_TYPE;
570 pr_err("%s:%d: %s\n", __func__, __LINE__, "Invalid VCAP type");
573 /* Do not overwrite any current actionset */
574 if (vrule->actionset == VCAP_AFS_NO_VALUE)
575 err = vcap_set_rule_set_actionset(vrule, aset);
579 /* Add the VCAP key to match on for a rule target value */
580 static int sparx5_tc_add_rule_link_target(struct vcap_admin *admin,
581 struct vcap_rule *vrule,
584 int link_val = target_cid % VCAP_CID_LOOKUP_SIZE;
590 switch (admin->vtype) {
592 /* Add NXT_IDX key for chaining rules between IS0 instances */
593 err = vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX_SEL,
598 return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX,
599 link_val, /* target */
602 /* Add PAG key for chaining rules from IS0 */
603 return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG,
604 link_val, /* target */
608 /* Add ISDX key for chaining rules from IS0 */
609 return vcap_rule_add_key_u32(vrule, VCAP_KF_ISDX_CLS, link_val,
617 /* Add the VCAP action that adds a target value to a rule */
618 static int sparx5_tc_add_rule_link(struct vcap_control *vctrl,
619 struct vcap_admin *admin,
620 struct vcap_rule *vrule,
621 int from_cid, int to_cid)
623 struct vcap_admin *to_admin = vcap_find_admin(vctrl, to_cid);
627 pr_err("%s:%d: unsupported chain direction: %d\n",
628 __func__, __LINE__, to_cid);
632 diff = vcap_chain_offset(vctrl, from_cid, to_cid);
636 if (admin->vtype == VCAP_TYPE_IS0 &&
637 to_admin->vtype == VCAP_TYPE_IS0) {
638 /* Between IS0 instances the G_IDX value is used */
639 err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX, diff);
642 err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX_CTRL,
646 } else if (admin->vtype == VCAP_TYPE_IS0 &&
647 to_admin->vtype == VCAP_TYPE_IS2) {
648 /* Between IS0 and IS2 the PAG value is used */
649 err = vcap_rule_add_action_u32(vrule, VCAP_AF_PAG_VAL, diff);
652 err = vcap_rule_add_action_u32(vrule,
653 VCAP_AF_PAG_OVERRIDE_MASK,
657 } else if (admin->vtype == VCAP_TYPE_IS0 &&
658 (to_admin->vtype == VCAP_TYPE_ES0 ||
659 to_admin->vtype == VCAP_TYPE_ES2)) {
660 /* Between IS0 and ES0/ES2 the ISDX value is used */
661 err = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL,
665 err = vcap_rule_add_action_bit(vrule,
666 VCAP_AF_ISDX_ADD_REPLACE_SEL,
671 pr_err("%s:%d: unsupported chain destination: %d\n",
672 __func__, __LINE__, to_cid);
679 static int sparx5_tc_flower_parse_act_gate(struct sparx5_psfp_sg *sg,
680 struct flow_action_entry *act,
681 struct netlink_ext_ack *extack)
685 if (act->gate.prio < -1 || act->gate.prio > SPX5_PSFP_SG_MAX_IPV) {
686 NL_SET_ERR_MSG_MOD(extack, "Invalid gate priority");
690 if (act->gate.cycletime < SPX5_PSFP_SG_MIN_CYCLE_TIME_NS ||
691 act->gate.cycletime > SPX5_PSFP_SG_MAX_CYCLE_TIME_NS) {
692 NL_SET_ERR_MSG_MOD(extack, "Invalid gate cycletime");
696 if (act->gate.cycletimeext > SPX5_PSFP_SG_MAX_CYCLE_TIME_NS) {
697 NL_SET_ERR_MSG_MOD(extack, "Invalid gate cycletimeext");
701 if (act->gate.num_entries >= SPX5_PSFP_GCE_CNT) {
702 NL_SET_ERR_MSG_MOD(extack, "Invalid number of gate entries");
706 sg->gate_state = true;
707 sg->ipv = act->gate.prio;
708 sg->num_entries = act->gate.num_entries;
709 sg->cycletime = act->gate.cycletime;
710 sg->cycletimeext = act->gate.cycletimeext;
712 for (i = 0; i < sg->num_entries; i++) {
713 sg->gce[i].gate_state = !!act->gate.entries[i].gate_state;
714 sg->gce[i].interval = act->gate.entries[i].interval;
715 sg->gce[i].ipv = act->gate.entries[i].ipv;
716 sg->gce[i].maxoctets = act->gate.entries[i].maxoctets;
722 static int sparx5_tc_flower_parse_act_police(struct sparx5_policer *pol,
723 struct flow_action_entry *act,
724 struct netlink_ext_ack *extack)
726 pol->type = SPX5_POL_SERVICE;
727 pol->rate = div_u64(act->police.rate_bytes_ps, 1000) * 8;
728 pol->burst = act->police.burst;
729 pol->idx = act->hw_index;
731 /* rate is now in kbit */
732 if (pol->rate > DIV_ROUND_UP(SPX5_SDLB_GROUP_RATE_MAX, 1000)) {
733 NL_SET_ERR_MSG_MOD(extack, "Maximum rate exceeded");
737 if (act->police.exceed.act_id != FLOW_ACTION_DROP) {
738 NL_SET_ERR_MSG_MOD(extack, "Offload not supported when exceed action is not drop");
742 if (act->police.notexceed.act_id != FLOW_ACTION_PIPE &&
743 act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) {
744 NL_SET_ERR_MSG_MOD(extack, "Offload not supported when conform action is not pipe or ok");
751 static int sparx5_tc_flower_psfp_setup(struct sparx5 *sparx5,
752 struct vcap_rule *vrule, int sg_idx,
753 int pol_idx, struct sparx5_psfp_sg *sg,
754 struct sparx5_psfp_fm *fm,
755 struct sparx5_psfp_sf *sf)
757 u32 psfp_sfid = 0, psfp_fmid = 0, psfp_sgid = 0;
760 /* Must always have a stream gate - max sdu (filter option) is evaluated
761 * after frames have passed the gate, so in case of only a policer, we
762 * allocate a stream gate that is always open.
765 sg_idx = sparx5_pool_idx_to_id(SPX5_PSFP_SG_OPEN);
766 sg->ipv = 0; /* Disabled */
767 sg->cycletime = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT;
769 sg->gate_state = 1; /* Open */
770 sg->gate_enabled = 1;
771 sg->gce[0].gate_state = 1;
772 sg->gce[0].interval = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT;
774 sg->gce[0].maxoctets = 0; /* Disabled */
777 ret = sparx5_psfp_sg_add(sparx5, sg_idx, sg, &psfp_sgid);
782 /* Add new flow-meter */
783 ret = sparx5_psfp_fm_add(sparx5, pol_idx, fm, &psfp_fmid);
788 /* Map stream filter to stream gate */
789 sf->sgid = psfp_sgid;
791 /* Add new stream-filter and map it to a steam gate */
792 ret = sparx5_psfp_sf_add(sparx5, sf, &psfp_sfid);
796 /* Streams are classified by ISDX - map ISDX 1:1 to sfid for now. */
797 sparx5_isdx_conf_set(sparx5, psfp_sfid, psfp_sfid, psfp_fmid);
799 ret = vcap_rule_add_action_bit(vrule, VCAP_AF_ISDX_ADD_REPLACE_SEL,
804 ret = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL, psfp_sfid);
811 /* Handle the action trap for a VCAP rule */
812 static int sparx5_tc_action_trap(struct vcap_admin *admin,
813 struct vcap_rule *vrule,
814 struct flow_cls_offload *fco)
818 switch (admin->vtype) {
820 err = vcap_rule_add_action_bit(vrule,
821 VCAP_AF_CPU_COPY_ENA,
825 err = vcap_rule_add_action_u32(vrule,
826 VCAP_AF_CPU_QUEUE_NUM, 0);
829 err = vcap_rule_add_action_u32(vrule,
831 SPX5_PMM_REPLACE_ALL);
834 err = vcap_rule_add_action_u32(vrule,
836 SPX5_FWSEL_REDIRECT_TO_LOOPBACK);
839 err = vcap_rule_add_action_bit(vrule,
840 VCAP_AF_CPU_COPY_ENA,
844 err = vcap_rule_add_action_u32(vrule,
845 VCAP_AF_CPU_QUEUE_NUM, 0);
848 NL_SET_ERR_MSG_MOD(fco->common.extack,
849 "Trap action not supported in this VCAP");
856 static int sparx5_tc_action_vlan_pop(struct vcap_admin *admin,
857 struct vcap_rule *vrule,
858 struct flow_cls_offload *fco,
863 switch (admin->vtype) {
867 NL_SET_ERR_MSG_MOD(fco->common.extack,
868 "VLAN pop action not supported in this VCAP");
875 err = vcap_rule_add_action_u32(vrule,
876 VCAP_AF_PUSH_OUTER_TAG,
880 NL_SET_ERR_MSG_MOD(fco->common.extack,
881 "Invalid vlan proto");
887 static int sparx5_tc_action_vlan_modify(struct vcap_admin *admin,
888 struct vcap_rule *vrule,
889 struct flow_cls_offload *fco,
890 struct flow_action_entry *act,
895 switch (admin->vtype) {
897 err = vcap_rule_add_action_u32(vrule,
898 VCAP_AF_PUSH_OUTER_TAG,
904 NL_SET_ERR_MSG_MOD(fco->common.extack,
905 "VLAN modify action not supported in this VCAP");
911 err = vcap_rule_add_action_u32(vrule,
912 VCAP_AF_TAG_A_TPID_SEL,
916 err = vcap_rule_add_action_u32(vrule,
917 VCAP_AF_TAG_A_TPID_SEL,
921 NL_SET_ERR_MSG_MOD(fco->common.extack,
922 "Invalid vlan proto");
928 err = vcap_rule_add_action_u32(vrule,
929 VCAP_AF_TAG_A_VID_SEL,
934 err = vcap_rule_add_action_u32(vrule,
940 err = vcap_rule_add_action_u32(vrule,
941 VCAP_AF_TAG_A_PCP_SEL,
946 err = vcap_rule_add_action_u32(vrule,
952 return vcap_rule_add_action_u32(vrule,
953 VCAP_AF_TAG_A_DEI_SEL,
954 SPX5_DEI_A_CLASSIFIED);
957 static int sparx5_tc_action_vlan_push(struct vcap_admin *admin,
958 struct vcap_rule *vrule,
959 struct flow_cls_offload *fco,
960 struct flow_action_entry *act,
963 u16 act_tpid = be16_to_cpu(act->vlan.proto);
966 switch (admin->vtype) {
970 NL_SET_ERR_MSG_MOD(fco->common.extack,
971 "VLAN push action not supported in this VCAP");
975 if (tpid == ETH_P_8021AD) {
976 NL_SET_ERR_MSG_MOD(fco->common.extack,
977 "Cannot push on double tagged frames");
981 err = sparx5_tc_action_vlan_modify(admin, vrule, fco, act, act_tpid);
989 /* Push classified tag as inner tag */
990 err = vcap_rule_add_action_u32(vrule,
991 VCAP_AF_PUSH_INNER_TAG,
992 SPX5_ITAG_PUSH_B_TAG);
995 err = vcap_rule_add_action_u32(vrule,
996 VCAP_AF_TAG_B_TPID_SEL,
997 SPX5_TPID_B_CLASSIFIED);
1000 NL_SET_ERR_MSG_MOD(fco->common.extack,
1001 "Invalid vlan proto");
1007 /* Remove rule keys that may prevent templates from matching a keyset */
1008 static void sparx5_tc_flower_simplify_rule(struct vcap_admin *admin,
1009 struct vcap_rule *vrule,
1012 switch (admin->vtype) {
1014 vcap_rule_rem_key(vrule, VCAP_KF_ETYPE);
1019 vcap_rule_rem_key(vrule, VCAP_KF_IP_SNAP_IS);
1028 if (vrule->keyset == VCAP_KFS_IP4_OTHER)
1029 vcap_rule_rem_key(vrule, VCAP_KF_TCP_IS);
1032 if (vrule->keyset == VCAP_KFS_IP6_STD)
1033 vcap_rule_rem_key(vrule, VCAP_KF_TCP_IS);
1034 vcap_rule_rem_key(vrule, VCAP_KF_IP4_IS);
1044 vcap_rule_rem_key(vrule, VCAP_KF_IP4_IS);
1055 static bool sparx5_tc_flower_use_template(struct net_device *ndev,
1056 struct flow_cls_offload *fco,
1057 struct vcap_admin *admin,
1058 struct vcap_rule *vrule)
1060 struct sparx5_port *port = netdev_priv(ndev);
1061 struct sparx5_tc_flower_template *ftp;
1063 list_for_each_entry(ftp, &port->tc_templates, list) {
1064 if (ftp->cid != fco->common.chain_index)
1067 vcap_set_rule_set_keyset(vrule, ftp->keyset);
1068 sparx5_tc_flower_simplify_rule(admin, vrule, ftp->l3_proto);
1074 static int sparx5_tc_flower_replace(struct net_device *ndev,
1075 struct flow_cls_offload *fco,
1076 struct vcap_admin *admin,
1079 struct sparx5_psfp_sf sf = { .max_sdu = SPX5_PSFP_SF_MAX_SDU };
1080 struct netlink_ext_ack *extack = fco->common.extack;
1081 int err, idx, tc_sg_idx = -1, tc_pol_idx = -1;
1082 struct vcap_tc_flower_parse_usage state = {
1084 .l3_proto = ETH_P_ALL,
1087 struct sparx5_port *port = netdev_priv(ndev);
1088 struct sparx5_multiple_rules multi = {};
1089 struct sparx5 *sparx5 = port->sparx5;
1090 struct sparx5_psfp_sg sg = { 0 };
1091 struct sparx5_psfp_fm fm = { 0 };
1092 struct flow_action_entry *act;
1093 struct vcap_control *vctrl;
1094 struct flow_rule *frule;
1095 struct vcap_rule *vrule;
1097 vctrl = port->sparx5->vcap_ctrl;
1099 err = sparx5_tc_flower_action_check(vctrl, ndev, fco, ingress);
1103 vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, VCAP_USER_TC,
1104 fco->common.prio, 0);
1106 return PTR_ERR(vrule);
1108 vrule->cookie = fco->cookie;
1110 state.vrule = vrule;
1111 state.frule = flow_cls_offload_flow_rule(fco);
1112 err = sparx5_tc_use_dissectors(&state, admin, vrule);
1116 err = sparx5_tc_add_rule_counter(admin, vrule);
1120 err = sparx5_tc_add_rule_link_target(admin, vrule,
1121 fco->common.chain_index);
1125 frule = flow_cls_offload_flow_rule(fco);
1126 flow_action_for_each(idx, act, &frule->action) {
1128 case FLOW_ACTION_GATE: {
1129 err = sparx5_tc_flower_parse_act_gate(&sg, act, extack);
1133 tc_sg_idx = act->hw_index;
1137 case FLOW_ACTION_POLICE: {
1138 err = sparx5_tc_flower_parse_act_police(&fm.pol, act,
1143 tc_pol_idx = fm.pol.idx;
1144 sf.max_sdu = act->police.mtu;
1148 case FLOW_ACTION_TRAP:
1149 err = sparx5_tc_action_trap(admin, vrule, fco);
1153 case FLOW_ACTION_ACCEPT:
1154 err = sparx5_tc_set_actionset(admin, vrule);
1158 case FLOW_ACTION_GOTO:
1159 err = sparx5_tc_set_actionset(admin, vrule);
1162 sparx5_tc_add_rule_link(vctrl, admin, vrule,
1163 fco->common.chain_index,
1166 case FLOW_ACTION_VLAN_POP:
1167 err = sparx5_tc_action_vlan_pop(admin, vrule, fco,
1172 case FLOW_ACTION_VLAN_PUSH:
1173 err = sparx5_tc_action_vlan_push(admin, vrule, fco,
1178 case FLOW_ACTION_VLAN_MANGLE:
1179 err = sparx5_tc_action_vlan_modify(admin, vrule, fco,
1185 NL_SET_ERR_MSG_MOD(fco->common.extack,
1186 "Unsupported TC action");
1193 if (tc_sg_idx >= 0 || tc_pol_idx >= 0) {
1194 err = sparx5_tc_flower_psfp_setup(sparx5, vrule, tc_sg_idx,
1195 tc_pol_idx, &sg, &fm, &sf);
1200 if (!sparx5_tc_flower_use_template(ndev, fco, admin, vrule)) {
1201 err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin,
1202 state.l3_proto, &multi);
1204 NL_SET_ERR_MSG_MOD(fco->common.extack,
1205 "No matching port keyset for filter protocol and keys");
1210 /* provide the l3 protocol to guide the keyset selection */
1211 err = vcap_val_rule(vrule, state.l3_proto);
1213 vcap_set_tc_exterr(fco, vrule);
1216 err = vcap_add_rule(vrule);
1218 NL_SET_ERR_MSG_MOD(fco->common.extack,
1219 "Could not add the filter");
1221 if (state.l3_proto == ETH_P_ALL)
1222 err = sparx5_tc_add_remaining_rules(vctrl, fco, vrule, admin,
1226 vcap_free_rule(vrule);
1230 static void sparx5_tc_free_psfp_resources(struct sparx5 *sparx5,
1231 struct vcap_rule *vrule)
1233 struct vcap_client_actionfield *afield;
1234 u32 isdx, sfid, sgid, fmid;
1236 /* Check if VCAP_AF_ISDX_VAL action is set for this rule - and if
1237 * it is used for stream and/or flow-meter classification.
1239 afield = vcap_find_actionfield(vrule, VCAP_AF_ISDX_VAL);
1243 isdx = afield->data.u32.value;
1244 sfid = sparx5_psfp_isdx_get_sf(sparx5, isdx);
1249 fmid = sparx5_psfp_isdx_get_fm(sparx5, isdx);
1250 sgid = sparx5_psfp_sf_get_sg(sparx5, sfid);
1252 if (fmid && sparx5_psfp_fm_del(sparx5, fmid) < 0)
1253 pr_err("%s:%d Could not delete invalid fmid: %d", __func__,
1256 if (sgid && sparx5_psfp_sg_del(sparx5, sgid) < 0)
1257 pr_err("%s:%d Could not delete invalid sgid: %d", __func__,
1260 if (sparx5_psfp_sf_del(sparx5, sfid) < 0)
1261 pr_err("%s:%d Could not delete invalid sfid: %d", __func__,
1264 sparx5_isdx_conf_set(sparx5, isdx, 0, 0);
1267 static int sparx5_tc_free_rule_resources(struct net_device *ndev,
1268 struct vcap_control *vctrl,
1271 struct sparx5_port *port = netdev_priv(ndev);
1272 struct sparx5 *sparx5 = port->sparx5;
1273 struct vcap_rule *vrule;
1276 vrule = vcap_get_rule(vctrl, rule_id);
1280 sparx5_tc_free_psfp_resources(sparx5, vrule);
1282 vcap_free_rule(vrule);
1286 static int sparx5_tc_flower_destroy(struct net_device *ndev,
1287 struct flow_cls_offload *fco,
1288 struct vcap_admin *admin)
1290 struct sparx5_port *port = netdev_priv(ndev);
1291 int err = -ENOENT, count = 0, rule_id;
1292 struct vcap_control *vctrl;
1294 vctrl = port->sparx5->vcap_ctrl;
1296 rule_id = vcap_lookup_rule_by_cookie(vctrl, fco->cookie);
1300 /* Resources are attached to the first rule of
1301 * a set of rules. Only works if the rules are
1302 * in the correct order.
1304 err = sparx5_tc_free_rule_resources(ndev, vctrl,
1307 pr_err("%s:%d: could not free resources %d\n",
1308 __func__, __LINE__, rule_id);
1310 err = vcap_del_rule(vctrl, ndev, rule_id);
1312 pr_err("%s:%d: could not delete rule %d\n",
1313 __func__, __LINE__, rule_id);
1320 static int sparx5_tc_flower_stats(struct net_device *ndev,
1321 struct flow_cls_offload *fco,
1322 struct vcap_admin *admin)
1324 struct sparx5_port *port = netdev_priv(ndev);
1325 struct vcap_counter ctr = {};
1326 struct vcap_control *vctrl;
1330 vctrl = port->sparx5->vcap_ctrl;
1331 err = vcap_get_rule_count_by_cookie(vctrl, &ctr, fco->cookie);
1334 flow_stats_update(&fco->stats, 0x0, ctr.value, 0, lastused,
1335 FLOW_ACTION_HW_STATS_IMMEDIATE);
1339 static int sparx5_tc_flower_template_create(struct net_device *ndev,
1340 struct flow_cls_offload *fco,
1341 struct vcap_admin *admin)
1343 struct sparx5_port *port = netdev_priv(ndev);
1344 struct vcap_tc_flower_parse_usage state = {
1346 .l3_proto = ETH_P_ALL,
1349 struct sparx5_tc_flower_template *ftp;
1350 struct vcap_keyset_list kslist = {};
1351 enum vcap_keyfield_set keysets[10];
1352 struct vcap_control *vctrl;
1353 struct vcap_rule *vrule;
1356 if (admin->vtype == VCAP_TYPE_ES0) {
1357 pr_err("%s:%d: %s\n", __func__, __LINE__,
1358 "VCAP does not support templates");
1362 count = vcap_admin_rule_count(admin, fco->common.chain_index);
1364 pr_err("%s:%d: %s\n", __func__, __LINE__,
1365 "Filters are already present");
1369 ftp = kzalloc(sizeof(*ftp), GFP_KERNEL);
1373 ftp->cid = fco->common.chain_index;
1374 ftp->orig = VCAP_KFS_NO_VALUE;
1375 ftp->keyset = VCAP_KFS_NO_VALUE;
1377 vctrl = port->sparx5->vcap_ctrl;
1378 vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index,
1379 VCAP_USER_TC, fco->common.prio, 0);
1380 if (IS_ERR(vrule)) {
1381 err = PTR_ERR(vrule);
1385 state.vrule = vrule;
1386 state.frule = flow_cls_offload_flow_rule(fco);
1387 err = sparx5_tc_use_dissectors(&state, admin, vrule);
1389 pr_err("%s:%d: key error: %d\n", __func__, __LINE__, err);
1393 ftp->l3_proto = state.l3_proto;
1395 sparx5_tc_flower_simplify_rule(admin, vrule, state.l3_proto);
1397 /* Find the keysets that the rule can use */
1398 kslist.keysets = keysets;
1399 kslist.max = ARRAY_SIZE(keysets);
1400 if (!vcap_rule_find_keysets(vrule, &kslist)) {
1401 pr_err("%s:%d: %s\n", __func__, __LINE__,
1402 "Could not find a suitable keyset");
1407 ftp->keyset = vcap_select_min_rule_keyset(vctrl, admin->vtype, &kslist);
1409 sparx5_vcap_set_port_keyset(ndev, admin, fco->common.chain_index,
1415 ftp->orig = kslist.keysets[0];
1417 /* Store new template */
1418 list_add_tail(&ftp->list, &port->tc_templates);
1419 vcap_free_rule(vrule);
1423 vcap_free_rule(vrule);
1429 static int sparx5_tc_flower_template_destroy(struct net_device *ndev,
1430 struct flow_cls_offload *fco,
1431 struct vcap_admin *admin)
1433 struct sparx5_port *port = netdev_priv(ndev);
1434 struct sparx5_tc_flower_template *ftp, *tmp;
1437 /* Rules using the template are removed by the tc framework */
1438 list_for_each_entry_safe(ftp, tmp, &port->tc_templates, list) {
1439 if (ftp->cid != fco->common.chain_index)
1442 sparx5_vcap_set_port_keyset(ndev, admin,
1443 fco->common.chain_index,
1444 ftp->l3_proto, ftp->orig,
1446 list_del(&ftp->list);
1453 int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco,
1456 struct sparx5_port *port = netdev_priv(ndev);
1457 struct vcap_control *vctrl;
1458 struct vcap_admin *admin;
1461 /* Get vcap instance from the chain id */
1462 vctrl = port->sparx5->vcap_ctrl;
1463 admin = vcap_find_admin(vctrl, fco->common.chain_index);
1465 NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid chain");
1469 switch (fco->command) {
1470 case FLOW_CLS_REPLACE:
1471 return sparx5_tc_flower_replace(ndev, fco, admin, ingress);
1472 case FLOW_CLS_DESTROY:
1473 return sparx5_tc_flower_destroy(ndev, fco, admin);
1474 case FLOW_CLS_STATS:
1475 return sparx5_tc_flower_stats(ndev, fco, admin);
1476 case FLOW_CLS_TMPLT_CREATE:
1477 return sparx5_tc_flower_template_create(ndev, fco, admin);
1478 case FLOW_CLS_TMPLT_DESTROY:
1479 return sparx5_tc_flower_template_destroy(ndev, fco, admin);