1c9da1ac1SSteen Hegelund // SPDX-License-Identifier: GPL-2.0+ 2c9da1ac1SSteen Hegelund /* Microchip VCAP API 3c9da1ac1SSteen Hegelund * 4c9da1ac1SSteen Hegelund * Copyright (c) 2022 Microchip Technology Inc. and its subsidiaries. 5c9da1ac1SSteen Hegelund */ 6c9da1ac1SSteen Hegelund 76ebf182bSDaniel Machon #include <net/tc_act/tc_gate.h> 8c9da1ac1SSteen Hegelund #include <net/tcp.h> 9c9da1ac1SSteen Hegelund 10c9da1ac1SSteen Hegelund #include "sparx5_tc.h" 11c9da1ac1SSteen Hegelund #include "vcap_api.h" 12c9da1ac1SSteen Hegelund #include "vcap_api_client.h" 1347400aaeSHoratiu Vultur #include "vcap_tc.h" 14c9da1ac1SSteen Hegelund #include "sparx5_main.h" 15c9da1ac1SSteen Hegelund #include "sparx5_vcap_impl.h" 16c9da1ac1SSteen Hegelund 170ca60948SSteen Hegelund #define SPX5_MAX_RULE_SIZE 13 /* allows X1, X2, X4, X6 and X12 rules */ 180ca60948SSteen Hegelund 190ca60948SSteen Hegelund /* Collect keysets and type ids for multiple rules per size */ 200ca60948SSteen Hegelund struct sparx5_wildcard_rule { 210ca60948SSteen Hegelund bool selected; 220ca60948SSteen Hegelund u8 value; 230ca60948SSteen Hegelund u8 mask; 240ca60948SSteen Hegelund enum vcap_keyfield_set keyset; 250ca60948SSteen Hegelund }; 260ca60948SSteen Hegelund 270ca60948SSteen Hegelund struct sparx5_multiple_rules { 280ca60948SSteen Hegelund struct sparx5_wildcard_rule rule[SPX5_MAX_RULE_SIZE]; 290ca60948SSteen Hegelund }; 300ca60948SSteen Hegelund 31e1d597ecSSteen Hegelund struct sparx5_tc_flower_template { 32e1d597ecSSteen Hegelund struct list_head list; /* for insertion in the list of templates */ 33e1d597ecSSteen Hegelund int cid; /* chain id */ 34e1d597ecSSteen Hegelund enum vcap_keyfield_set orig; /* keyset used before the template */ 35e1d597ecSSteen Hegelund enum vcap_keyfield_set keyset; /* new keyset used by template */ 36e1d597ecSSteen Hegelund u16 l3_proto; /* protocol specified in the template */ 37e1d597ecSSteen Hegelund }; 38e1d597ecSSteen Hegelund 39d6c2964dSSteen Hegelund static int 40ebf44dedSSteen Hegelund sparx5_tc_flower_es0_tpid(struct vcap_tc_flower_parse_usage *st) 41ebf44dedSSteen Hegelund { 42ebf44dedSSteen Hegelund int err = 0; 43ebf44dedSSteen Hegelund 44ebf44dedSSteen Hegelund switch (st->tpid) { 45ebf44dedSSteen Hegelund case ETH_P_8021Q: 46ebf44dedSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, 47ebf44dedSSteen Hegelund VCAP_KF_8021Q_TPID, 48ebf44dedSSteen Hegelund SPX5_TPID_SEL_8100, ~0); 49ebf44dedSSteen Hegelund break; 50ebf44dedSSteen Hegelund case ETH_P_8021AD: 51ebf44dedSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, 52ebf44dedSSteen Hegelund VCAP_KF_8021Q_TPID, 53ebf44dedSSteen Hegelund SPX5_TPID_SEL_88A8, ~0); 54ebf44dedSSteen Hegelund break; 55ebf44dedSSteen Hegelund default: 56ebf44dedSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, 57ebf44dedSSteen Hegelund "Invalid vlan proto"); 58ebf44dedSSteen Hegelund err = -EINVAL; 59ebf44dedSSteen Hegelund break; 60ebf44dedSSteen Hegelund } 61ebf44dedSSteen Hegelund return err; 62ebf44dedSSteen Hegelund } 63ebf44dedSSteen Hegelund 64ebf44dedSSteen Hegelund static int 6547400aaeSHoratiu Vultur sparx5_tc_flower_handler_basic_usage(struct vcap_tc_flower_parse_usage *st) 66d6c2964dSSteen Hegelund { 6747400aaeSHoratiu Vultur struct flow_match_basic mt; 68d6c2964dSSteen Hegelund int err = 0; 69d6c2964dSSteen Hegelund 7047400aaeSHoratiu Vultur flow_rule_match_basic(st->frule, &mt); 71d6c2964dSSteen Hegelund 7247400aaeSHoratiu Vultur if (mt.mask->n_proto) { 7347400aaeSHoratiu Vultur st->l3_proto = be16_to_cpu(mt.key->n_proto); 7447400aaeSHoratiu Vultur if (!sparx5_vcap_is_known_etype(st->admin, st->l3_proto)) { 7547400aaeSHoratiu Vultur err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE, 7647400aaeSHoratiu Vultur st->l3_proto, ~0); 7747400aaeSHoratiu Vultur if (err) 7847400aaeSHoratiu Vultur goto out; 7947400aaeSHoratiu Vultur } else if (st->l3_proto == ETH_P_IP) { 8047400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS, 8147400aaeSHoratiu Vultur VCAP_BIT_1); 8247400aaeSHoratiu Vultur if (err) 8347400aaeSHoratiu Vultur goto out; 8447400aaeSHoratiu Vultur } else if (st->l3_proto == ETH_P_IPV6) { 8547400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS, 8647400aaeSHoratiu Vultur VCAP_BIT_0); 8747400aaeSHoratiu Vultur if (err) 8847400aaeSHoratiu Vultur goto out; 8947400aaeSHoratiu Vultur if (st->admin->vtype == VCAP_TYPE_IS0) { 9047400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, 9147400aaeSHoratiu Vultur VCAP_KF_IP_SNAP_IS, 9247400aaeSHoratiu Vultur VCAP_BIT_1); 9347400aaeSHoratiu Vultur if (err) 9447400aaeSHoratiu Vultur goto out; 9547400aaeSHoratiu Vultur } 9647400aaeSHoratiu Vultur } 9747400aaeSHoratiu Vultur } 9847400aaeSHoratiu Vultur 9947400aaeSHoratiu Vultur if (mt.mask->ip_proto) { 10047400aaeSHoratiu Vultur st->l4_proto = mt.key->ip_proto; 10147400aaeSHoratiu Vultur if (st->l4_proto == IPPROTO_TCP) { 10247400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, 10347400aaeSHoratiu Vultur VCAP_KF_TCP_IS, 10447400aaeSHoratiu Vultur VCAP_BIT_1); 10547400aaeSHoratiu Vultur if (err) 10647400aaeSHoratiu Vultur goto out; 10747400aaeSHoratiu Vultur } else if (st->l4_proto == IPPROTO_UDP) { 10847400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, 10947400aaeSHoratiu Vultur VCAP_KF_TCP_IS, 11047400aaeSHoratiu Vultur VCAP_BIT_0); 11147400aaeSHoratiu Vultur if (err) 11247400aaeSHoratiu Vultur goto out; 11347400aaeSHoratiu Vultur if (st->admin->vtype == VCAP_TYPE_IS0) { 11447400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, 11547400aaeSHoratiu Vultur VCAP_KF_TCP_UDP_IS, 11647400aaeSHoratiu Vultur VCAP_BIT_1); 11747400aaeSHoratiu Vultur if (err) 11847400aaeSHoratiu Vultur goto out; 11947400aaeSHoratiu Vultur } 12047400aaeSHoratiu Vultur } else { 121d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, 12247400aaeSHoratiu Vultur VCAP_KF_L3_IP_PROTO, 12347400aaeSHoratiu Vultur st->l4_proto, ~0); 124d6c2964dSSteen Hegelund if (err) 125d6c2964dSSteen Hegelund goto out; 126d6c2964dSSteen Hegelund } 127d6c2964dSSteen Hegelund } 128d6c2964dSSteen Hegelund 1292b3082c6SRatheesh Kannoth st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_BASIC); 130d6c2964dSSteen Hegelund 131d6c2964dSSteen Hegelund return err; 132d6c2964dSSteen Hegelund 133d6c2964dSSteen Hegelund out: 13447400aaeSHoratiu Vultur NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error"); 135d6c2964dSSteen Hegelund return err; 136d6c2964dSSteen Hegelund } 137d6c2964dSSteen Hegelund 138d6c2964dSSteen Hegelund static int 13947400aaeSHoratiu Vultur sparx5_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st) 140d6c2964dSSteen Hegelund { 141d6c2964dSSteen Hegelund struct flow_match_control mt; 142d6c2964dSSteen Hegelund u32 value, mask; 143d6c2964dSSteen Hegelund int err = 0; 144d6c2964dSSteen Hegelund 145d6c2964dSSteen Hegelund flow_rule_match_control(st->frule, &mt); 146d6c2964dSSteen Hegelund 147d6c2964dSSteen Hegelund if (mt.mask->flags) { 148d6c2964dSSteen Hegelund if (mt.mask->flags & FLOW_DIS_FIRST_FRAG) { 149d6c2964dSSteen Hegelund if (mt.key->flags & FLOW_DIS_FIRST_FRAG) { 150d6c2964dSSteen Hegelund value = 1; /* initial fragment */ 151d6c2964dSSteen Hegelund mask = 0x3; 152d6c2964dSSteen Hegelund } else { 153d6c2964dSSteen Hegelund if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) { 154d6c2964dSSteen Hegelund value = 3; /* follow up fragment */ 155d6c2964dSSteen Hegelund mask = 0x3; 156d6c2964dSSteen Hegelund } else { 157d6c2964dSSteen Hegelund value = 0; /* no fragment */ 158d6c2964dSSteen Hegelund mask = 0x3; 159d6c2964dSSteen Hegelund } 160d6c2964dSSteen Hegelund } 161d6c2964dSSteen Hegelund } else { 162d6c2964dSSteen Hegelund if (mt.mask->flags & FLOW_DIS_IS_FRAGMENT) { 163d6c2964dSSteen Hegelund value = 3; /* follow up fragment */ 164d6c2964dSSteen Hegelund mask = 0x3; 165d6c2964dSSteen Hegelund } else { 166d6c2964dSSteen Hegelund value = 0; /* no fragment */ 167d6c2964dSSteen Hegelund mask = 0x3; 168d6c2964dSSteen Hegelund } 169d6c2964dSSteen Hegelund } 170d6c2964dSSteen Hegelund 171d6c2964dSSteen Hegelund err = vcap_rule_add_key_u32(st->vrule, 172d6c2964dSSteen Hegelund VCAP_KF_L3_FRAGMENT_TYPE, 173d6c2964dSSteen Hegelund value, mask); 174d6c2964dSSteen Hegelund if (err) 175d6c2964dSSteen Hegelund goto out; 176d6c2964dSSteen Hegelund } 177d6c2964dSSteen Hegelund 1782b3082c6SRatheesh Kannoth st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL); 179d6c2964dSSteen Hegelund 180d6c2964dSSteen Hegelund return err; 181d6c2964dSSteen Hegelund 182d6c2964dSSteen Hegelund out: 183d6c2964dSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error"); 184d6c2964dSSteen Hegelund return err; 185d6c2964dSSteen Hegelund } 186d6c2964dSSteen Hegelund 187d6c2964dSSteen Hegelund static int 18847400aaeSHoratiu Vultur sparx5_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st) 189d6c2964dSSteen Hegelund { 190a5300724SSteen Hegelund if (st->admin->vtype != VCAP_TYPE_IS0) { 191a5300724SSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, 192a5300724SSteen Hegelund "cvlan not supported in this VCAP"); 19352df82ccSSteen Hegelund return -EINVAL; 194a5300724SSteen Hegelund } 19552df82ccSSteen Hegelund 19647400aaeSHoratiu Vultur return vcap_tc_flower_handler_cvlan_usage(st); 19752df82ccSSteen Hegelund } 19852df82ccSSteen Hegelund 19952df82ccSSteen Hegelund static int 20047400aaeSHoratiu Vultur sparx5_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st) 201d6c2964dSSteen Hegelund { 202d6c2964dSSteen Hegelund enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS; 203d6c2964dSSteen Hegelund enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS; 204ebf44dedSSteen Hegelund int err; 205d6c2964dSSteen Hegelund 20652df82ccSSteen Hegelund if (st->admin->vtype == VCAP_TYPE_IS0) { 20752df82ccSSteen Hegelund vid_key = VCAP_KF_8021Q_VID0; 20852df82ccSSteen Hegelund pcp_key = VCAP_KF_8021Q_PCP0; 20952df82ccSSteen Hegelund } 21052df82ccSSteen Hegelund 211ebf44dedSSteen Hegelund err = vcap_tc_flower_handler_vlan_usage(st, vid_key, pcp_key); 212ebf44dedSSteen Hegelund if (err) 213ebf44dedSSteen Hegelund return err; 214ebf44dedSSteen Hegelund 215ebf44dedSSteen Hegelund if (st->admin->vtype == VCAP_TYPE_ES0 && st->tpid) 216ebf44dedSSteen Hegelund err = sparx5_tc_flower_es0_tpid(st); 217ebf44dedSSteen Hegelund 218ebf44dedSSteen Hegelund return err; 219d6c2964dSSteen Hegelund } 220d6c2964dSSteen Hegelund 22147400aaeSHoratiu Vultur static int (*sparx5_tc_flower_usage_handlers[])(struct vcap_tc_flower_parse_usage *st) = { 22247400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_ETH_ADDRS] = vcap_tc_flower_handler_ethaddr_usage, 22347400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_IPV4_ADDRS] = vcap_tc_flower_handler_ipv4_usage, 22447400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_IPV6_ADDRS] = vcap_tc_flower_handler_ipv6_usage, 225d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_CONTROL] = sparx5_tc_flower_handler_control_usage, 22647400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_PORTS] = vcap_tc_flower_handler_portnum_usage, 227d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_BASIC] = sparx5_tc_flower_handler_basic_usage, 22852df82ccSSteen Hegelund [FLOW_DISSECTOR_KEY_CVLAN] = sparx5_tc_flower_handler_cvlan_usage, 229d6c2964dSSteen Hegelund [FLOW_DISSECTOR_KEY_VLAN] = sparx5_tc_flower_handler_vlan_usage, 23047400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_TCP] = vcap_tc_flower_handler_tcp_usage, 23147400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_ARP] = vcap_tc_flower_handler_arp_usage, 23247400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_IP] = vcap_tc_flower_handler_ip_usage, 233c9da1ac1SSteen Hegelund }; 234c9da1ac1SSteen Hegelund 235ebf44dedSSteen Hegelund static int sparx5_tc_use_dissectors(struct vcap_tc_flower_parse_usage *st, 236c9da1ac1SSteen Hegelund struct vcap_admin *admin, 237ebf44dedSSteen Hegelund struct vcap_rule *vrule) 238c9da1ac1SSteen Hegelund { 239c9da1ac1SSteen Hegelund int idx, err = 0; 240c9da1ac1SSteen Hegelund 241c9da1ac1SSteen Hegelund for (idx = 0; idx < ARRAY_SIZE(sparx5_tc_flower_usage_handlers); ++idx) { 242ebf44dedSSteen Hegelund if (!flow_rule_match_key(st->frule, idx)) 243c9da1ac1SSteen Hegelund continue; 244c9da1ac1SSteen Hegelund if (!sparx5_tc_flower_usage_handlers[idx]) 245c9da1ac1SSteen Hegelund continue; 246ebf44dedSSteen Hegelund err = sparx5_tc_flower_usage_handlers[idx](st); 247c9da1ac1SSteen Hegelund if (err) 248c9da1ac1SSteen Hegelund return err; 249c9da1ac1SSteen Hegelund } 250abc4010dSSteen Hegelund 251ebf44dedSSteen Hegelund if (st->frule->match.dissector->used_keys ^ st->used_keys) { 252ebf44dedSSteen Hegelund NL_SET_ERR_MSG_MOD(st->fco->common.extack, 253abc4010dSSteen Hegelund "Unsupported match item"); 254abc4010dSSteen Hegelund return -ENOENT; 255abc4010dSSteen Hegelund } 256abc4010dSSteen Hegelund 257c9da1ac1SSteen Hegelund return err; 258c9da1ac1SSteen Hegelund } 259c9da1ac1SSteen Hegelund 260392d0ab0SSteen Hegelund static int sparx5_tc_flower_action_check(struct vcap_control *vctrl, 261784c3067SSteen Hegelund struct net_device *ndev, 262e7e3f514SSteen Hegelund struct flow_cls_offload *fco, 263e7e3f514SSteen Hegelund bool ingress) 264392d0ab0SSteen Hegelund { 265392d0ab0SSteen Hegelund struct flow_rule *rule = flow_cls_offload_flow_rule(fco); 266392d0ab0SSteen Hegelund struct flow_action_entry *actent, *last_actent = NULL; 267392d0ab0SSteen Hegelund struct flow_action *act = &rule->action; 268392d0ab0SSteen Hegelund u64 action_mask = 0; 269392d0ab0SSteen Hegelund int idx; 270392d0ab0SSteen Hegelund 271392d0ab0SSteen Hegelund if (!flow_action_has_entries(act)) { 272392d0ab0SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions"); 273392d0ab0SSteen Hegelund return -EINVAL; 274392d0ab0SSteen Hegelund } 275392d0ab0SSteen Hegelund 276392d0ab0SSteen Hegelund if (!flow_action_basic_hw_stats_check(act, fco->common.extack)) 277392d0ab0SSteen Hegelund return -EOPNOTSUPP; 278392d0ab0SSteen Hegelund 279392d0ab0SSteen Hegelund flow_action_for_each(idx, actent, act) { 280392d0ab0SSteen Hegelund if (action_mask & BIT(actent->id)) { 281392d0ab0SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 282392d0ab0SSteen Hegelund "More actions of the same type"); 283392d0ab0SSteen Hegelund return -EINVAL; 284392d0ab0SSteen Hegelund } 285392d0ab0SSteen Hegelund action_mask |= BIT(actent->id); 286392d0ab0SSteen Hegelund last_actent = actent; /* Save last action for later check */ 287392d0ab0SSteen Hegelund } 288392d0ab0SSteen Hegelund 289784c3067SSteen Hegelund /* Check if last action is a goto 290784c3067SSteen Hegelund * The last chain/lookup does not need to have a goto action 291784c3067SSteen Hegelund */ 292784c3067SSteen Hegelund if (last_actent->id == FLOW_ACTION_GOTO) { 293784c3067SSteen Hegelund /* Check if the destination chain is in one of the VCAPs */ 294392d0ab0SSteen Hegelund if (!vcap_is_next_lookup(vctrl, fco->common.chain_index, 295392d0ab0SSteen Hegelund last_actent->chain_index)) { 296392d0ab0SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 297392d0ab0SSteen Hegelund "Invalid goto chain"); 298392d0ab0SSteen Hegelund return -EINVAL; 299392d0ab0SSteen Hegelund } 300e7e3f514SSteen Hegelund } else if (!vcap_is_last_chain(vctrl, fco->common.chain_index, 301e7e3f514SSteen Hegelund ingress)) { 302784c3067SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 303784c3067SSteen Hegelund "Last action must be 'goto'"); 304784c3067SSteen Hegelund return -EINVAL; 305784c3067SSteen Hegelund } 306392d0ab0SSteen Hegelund 307392d0ab0SSteen Hegelund /* Catch unsupported combinations of actions */ 308392d0ab0SSteen Hegelund if (action_mask & BIT(FLOW_ACTION_TRAP) && 309392d0ab0SSteen Hegelund action_mask & BIT(FLOW_ACTION_ACCEPT)) { 310392d0ab0SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 311392d0ab0SSteen Hegelund "Cannot combine pass and trap action"); 312392d0ab0SSteen Hegelund return -EOPNOTSUPP; 313392d0ab0SSteen Hegelund } 314392d0ab0SSteen Hegelund 315ebf44dedSSteen Hegelund if (action_mask & BIT(FLOW_ACTION_VLAN_PUSH) && 316ebf44dedSSteen Hegelund action_mask & BIT(FLOW_ACTION_VLAN_POP)) { 317ebf44dedSSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 318ebf44dedSSteen Hegelund "Cannot combine vlan push and pop action"); 319ebf44dedSSteen Hegelund return -EOPNOTSUPP; 320ebf44dedSSteen Hegelund } 321ebf44dedSSteen Hegelund 322ebf44dedSSteen Hegelund if (action_mask & BIT(FLOW_ACTION_VLAN_PUSH) && 323ebf44dedSSteen Hegelund action_mask & BIT(FLOW_ACTION_VLAN_MANGLE)) { 324ebf44dedSSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 325ebf44dedSSteen Hegelund "Cannot combine vlan push and modify action"); 326ebf44dedSSteen Hegelund return -EOPNOTSUPP; 327ebf44dedSSteen Hegelund } 328ebf44dedSSteen Hegelund 329ebf44dedSSteen Hegelund if (action_mask & BIT(FLOW_ACTION_VLAN_POP) && 330ebf44dedSSteen Hegelund action_mask & BIT(FLOW_ACTION_VLAN_MANGLE)) { 331ebf44dedSSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 332ebf44dedSSteen Hegelund "Cannot combine vlan pop and modify action"); 333ebf44dedSSteen Hegelund return -EOPNOTSUPP; 334ebf44dedSSteen Hegelund } 335ebf44dedSSteen Hegelund 336392d0ab0SSteen Hegelund return 0; 337392d0ab0SSteen Hegelund } 338392d0ab0SSteen Hegelund 339542e6e2cSSteen Hegelund /* Add a rule counter action */ 34040e7fe18SSteen Hegelund static int sparx5_tc_add_rule_counter(struct vcap_admin *admin, 34140e7fe18SSteen Hegelund struct vcap_rule *vrule) 34240e7fe18SSteen Hegelund { 34340e7fe18SSteen Hegelund int err; 34440e7fe18SSteen Hegelund 3453cbe7537SSteen Hegelund switch (admin->vtype) { 3463cbe7537SSteen Hegelund case VCAP_TYPE_IS0: 3473cbe7537SSteen Hegelund break; 3483cbe7537SSteen Hegelund case VCAP_TYPE_ES0: 3493cbe7537SSteen Hegelund err = vcap_rule_mod_action_u32(vrule, VCAP_AF_ESDX, 3503cbe7537SSteen Hegelund vrule->id); 3513cbe7537SSteen Hegelund if (err) 3523cbe7537SSteen Hegelund return err; 3533cbe7537SSteen Hegelund vcap_rule_set_counter_id(vrule, vrule->id); 3543cbe7537SSteen Hegelund break; 3553cbe7537SSteen Hegelund case VCAP_TYPE_IS2: 3563cbe7537SSteen Hegelund case VCAP_TYPE_ES2: 357542e6e2cSSteen Hegelund err = vcap_rule_mod_action_u32(vrule, VCAP_AF_CNT_ID, 358542e6e2cSSteen Hegelund vrule->id); 35940e7fe18SSteen Hegelund if (err) 36040e7fe18SSteen Hegelund return err; 36140e7fe18SSteen Hegelund vcap_rule_set_counter_id(vrule, vrule->id); 3623cbe7537SSteen Hegelund break; 3633cbe7537SSteen Hegelund default: 3643cbe7537SSteen Hegelund pr_err("%s:%d: vcap type: %d not supported\n", 3653cbe7537SSteen Hegelund __func__, __LINE__, admin->vtype); 3663cbe7537SSteen Hegelund break; 367542e6e2cSSteen Hegelund } 368542e6e2cSSteen Hegelund return 0; 36940e7fe18SSteen Hegelund } 37040e7fe18SSteen Hegelund 3710ca60948SSteen Hegelund /* Collect all port keysets and apply the first of them, possibly wildcarded */ 3720ca60948SSteen Hegelund static int sparx5_tc_select_protocol_keyset(struct net_device *ndev, 3730ca60948SSteen Hegelund struct vcap_rule *vrule, 3740ca60948SSteen Hegelund struct vcap_admin *admin, 3750ca60948SSteen Hegelund u16 l3_proto, 3760ca60948SSteen Hegelund struct sparx5_multiple_rules *multi) 3770ca60948SSteen Hegelund { 3780ca60948SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 3790ca60948SSteen Hegelund struct vcap_keyset_list portkeysetlist = {}; 3800ca60948SSteen Hegelund enum vcap_keyfield_set portkeysets[10] = {}; 3810ca60948SSteen Hegelund struct vcap_keyset_list matches = {}; 3820ca60948SSteen Hegelund enum vcap_keyfield_set keysets[10]; 3830ca60948SSteen Hegelund int idx, jdx, err = 0, count = 0; 3840ca60948SSteen Hegelund struct sparx5_wildcard_rule *mru; 3850ca60948SSteen Hegelund const struct vcap_set *kinfo; 3860ca60948SSteen Hegelund struct vcap_control *vctrl; 3870ca60948SSteen Hegelund 3880ca60948SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 3890ca60948SSteen Hegelund 3900ca60948SSteen Hegelund /* Find the keysets that the rule can use */ 3910ca60948SSteen Hegelund matches.keysets = keysets; 3920ca60948SSteen Hegelund matches.max = ARRAY_SIZE(keysets); 393e1d597ecSSteen Hegelund if (!vcap_rule_find_keysets(vrule, &matches)) 3940ca60948SSteen Hegelund return -EINVAL; 3950ca60948SSteen Hegelund 3960ca60948SSteen Hegelund /* Find the keysets that the port configuration supports */ 3970ca60948SSteen Hegelund portkeysetlist.max = ARRAY_SIZE(portkeysets); 3980ca60948SSteen Hegelund portkeysetlist.keysets = portkeysets; 3990ca60948SSteen Hegelund err = sparx5_vcap_get_port_keyset(ndev, 4000ca60948SSteen Hegelund admin, vrule->vcap_chain_id, 4010ca60948SSteen Hegelund l3_proto, 4020ca60948SSteen Hegelund &portkeysetlist); 4030ca60948SSteen Hegelund if (err) 4040ca60948SSteen Hegelund return err; 4050ca60948SSteen Hegelund 4060ca60948SSteen Hegelund /* Find the intersection of the two sets of keyset */ 4070ca60948SSteen Hegelund for (idx = 0; idx < portkeysetlist.cnt; ++idx) { 4080ca60948SSteen Hegelund kinfo = vcap_keyfieldset(vctrl, admin->vtype, 4090ca60948SSteen Hegelund portkeysetlist.keysets[idx]); 4100ca60948SSteen Hegelund if (!kinfo) 4110ca60948SSteen Hegelund continue; 4120ca60948SSteen Hegelund 4130ca60948SSteen Hegelund /* Find a port keyset that matches the required keys 4140ca60948SSteen Hegelund * If there are multiple keysets then compose a type id mask 4150ca60948SSteen Hegelund */ 4160ca60948SSteen Hegelund for (jdx = 0; jdx < matches.cnt; ++jdx) { 4170ca60948SSteen Hegelund if (portkeysetlist.keysets[idx] != matches.keysets[jdx]) 4180ca60948SSteen Hegelund continue; 4190ca60948SSteen Hegelund 4200ca60948SSteen Hegelund mru = &multi->rule[kinfo->sw_per_item]; 4210ca60948SSteen Hegelund if (!mru->selected) { 4220ca60948SSteen Hegelund mru->selected = true; 4230ca60948SSteen Hegelund mru->keyset = portkeysetlist.keysets[idx]; 4240ca60948SSteen Hegelund mru->value = kinfo->type_id; 4250ca60948SSteen Hegelund } 4260ca60948SSteen Hegelund mru->value &= kinfo->type_id; 4270ca60948SSteen Hegelund mru->mask |= kinfo->type_id; 4280ca60948SSteen Hegelund ++count; 4290ca60948SSteen Hegelund } 4300ca60948SSteen Hegelund } 4310ca60948SSteen Hegelund if (count == 0) 4320ca60948SSteen Hegelund return -EPROTO; 4330ca60948SSteen Hegelund 4340ca60948SSteen Hegelund if (l3_proto == ETH_P_ALL && count < portkeysetlist.cnt) 4350ca60948SSteen Hegelund return -ENOENT; 4360ca60948SSteen Hegelund 4370ca60948SSteen Hegelund for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) { 4380ca60948SSteen Hegelund mru = &multi->rule[idx]; 4390ca60948SSteen Hegelund if (!mru->selected) 4400ca60948SSteen Hegelund continue; 4410ca60948SSteen Hegelund 4420ca60948SSteen Hegelund /* Align the mask to the combined value */ 4430ca60948SSteen Hegelund mru->mask ^= mru->value; 4440ca60948SSteen Hegelund } 4450ca60948SSteen Hegelund 4460ca60948SSteen Hegelund /* Set the chosen keyset on the rule and set a wildcarded type if there 4470ca60948SSteen Hegelund * are more than one keyset 4480ca60948SSteen Hegelund */ 4490ca60948SSteen Hegelund for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) { 4500ca60948SSteen Hegelund mru = &multi->rule[idx]; 4510ca60948SSteen Hegelund if (!mru->selected) 4520ca60948SSteen Hegelund continue; 4530ca60948SSteen Hegelund 4540ca60948SSteen Hegelund vcap_set_rule_set_keyset(vrule, mru->keyset); 4550ca60948SSteen Hegelund if (count > 1) 4560ca60948SSteen Hegelund /* Some keysets do not have a type field */ 4570ca60948SSteen Hegelund vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE, 4580ca60948SSteen Hegelund mru->value, 4590ca60948SSteen Hegelund ~mru->mask); 4600ca60948SSteen Hegelund mru->selected = false; /* mark as done */ 4610ca60948SSteen Hegelund break; /* Stop here and add more rules later */ 4620ca60948SSteen Hegelund } 4630ca60948SSteen Hegelund return err; 4640ca60948SSteen Hegelund } 4650ca60948SSteen Hegelund 4660ca60948SSteen Hegelund static int sparx5_tc_add_rule_copy(struct vcap_control *vctrl, 4670ca60948SSteen Hegelund struct flow_cls_offload *fco, 4680ca60948SSteen Hegelund struct vcap_rule *erule, 4690ca60948SSteen Hegelund struct vcap_admin *admin, 4700ca60948SSteen Hegelund struct sparx5_wildcard_rule *rule) 4710ca60948SSteen Hegelund { 4720ca60948SSteen Hegelund enum vcap_key_field keylist[] = { 4730ca60948SSteen Hegelund VCAP_KF_IF_IGR_PORT_MASK, 4740ca60948SSteen Hegelund VCAP_KF_IF_IGR_PORT_MASK_SEL, 4750ca60948SSteen Hegelund VCAP_KF_IF_IGR_PORT_MASK_RNG, 4760ca60948SSteen Hegelund VCAP_KF_LOOKUP_FIRST_IS, 4770ca60948SSteen Hegelund VCAP_KF_TYPE, 4780ca60948SSteen Hegelund }; 4790ca60948SSteen Hegelund struct vcap_rule *vrule; 4800ca60948SSteen Hegelund int err; 4810ca60948SSteen Hegelund 4820ca60948SSteen Hegelund /* Add an extra rule with a special user and the new keyset */ 4830ca60948SSteen Hegelund erule->user = VCAP_USER_TC_EXTRA; 4840ca60948SSteen Hegelund vrule = vcap_copy_rule(erule); 4850ca60948SSteen Hegelund if (IS_ERR(vrule)) 4860ca60948SSteen Hegelund return PTR_ERR(vrule); 4870ca60948SSteen Hegelund 4880ca60948SSteen Hegelund /* Link the new rule to the existing rule with the cookie */ 4890ca60948SSteen Hegelund vrule->cookie = erule->cookie; 4900ca60948SSteen Hegelund vcap_filter_rule_keys(vrule, keylist, ARRAY_SIZE(keylist), true); 4910ca60948SSteen Hegelund err = vcap_set_rule_set_keyset(vrule, rule->keyset); 4920ca60948SSteen Hegelund if (err) { 4930ca60948SSteen Hegelund pr_err("%s:%d: could not set keyset %s in rule: %u\n", 4940ca60948SSteen Hegelund __func__, __LINE__, 4950ca60948SSteen Hegelund vcap_keyset_name(vctrl, rule->keyset), 4960ca60948SSteen Hegelund vrule->id); 4970ca60948SSteen Hegelund goto out; 4980ca60948SSteen Hegelund } 4990ca60948SSteen Hegelund 5000ca60948SSteen Hegelund /* Some keysets do not have a type field, so ignore return value */ 5010ca60948SSteen Hegelund vcap_rule_mod_key_u32(vrule, VCAP_KF_TYPE, rule->value, ~rule->mask); 5020ca60948SSteen Hegelund 5030ca60948SSteen Hegelund err = vcap_set_rule_set_actionset(vrule, erule->actionset); 5040ca60948SSteen Hegelund if (err) 5050ca60948SSteen Hegelund goto out; 5060ca60948SSteen Hegelund 5070ca60948SSteen Hegelund err = sparx5_tc_add_rule_counter(admin, vrule); 5080ca60948SSteen Hegelund if (err) 5090ca60948SSteen Hegelund goto out; 5100ca60948SSteen Hegelund 5110ca60948SSteen Hegelund err = vcap_val_rule(vrule, ETH_P_ALL); 5120ca60948SSteen Hegelund if (err) { 5130ca60948SSteen Hegelund pr_err("%s:%d: could not validate rule: %u\n", 5140ca60948SSteen Hegelund __func__, __LINE__, vrule->id); 5150ca60948SSteen Hegelund vcap_set_tc_exterr(fco, vrule); 5160ca60948SSteen Hegelund goto out; 5170ca60948SSteen Hegelund } 5180ca60948SSteen Hegelund err = vcap_add_rule(vrule); 5190ca60948SSteen Hegelund if (err) { 5200ca60948SSteen Hegelund pr_err("%s:%d: could not add rule: %u\n", 5210ca60948SSteen Hegelund __func__, __LINE__, vrule->id); 5220ca60948SSteen Hegelund goto out; 5230ca60948SSteen Hegelund } 5240ca60948SSteen Hegelund out: 5250ca60948SSteen Hegelund vcap_free_rule(vrule); 5260ca60948SSteen Hegelund return err; 5270ca60948SSteen Hegelund } 5280ca60948SSteen Hegelund 5290ca60948SSteen Hegelund static int sparx5_tc_add_remaining_rules(struct vcap_control *vctrl, 5300ca60948SSteen Hegelund struct flow_cls_offload *fco, 5310ca60948SSteen Hegelund struct vcap_rule *erule, 5320ca60948SSteen Hegelund struct vcap_admin *admin, 5330ca60948SSteen Hegelund struct sparx5_multiple_rules *multi) 5340ca60948SSteen Hegelund { 5350ca60948SSteen Hegelund int idx, err = 0; 5360ca60948SSteen Hegelund 5370ca60948SSteen Hegelund for (idx = 0; idx < SPX5_MAX_RULE_SIZE; ++idx) { 5380ca60948SSteen Hegelund if (!multi->rule[idx].selected) 5390ca60948SSteen Hegelund continue; 5400ca60948SSteen Hegelund 5410ca60948SSteen Hegelund err = sparx5_tc_add_rule_copy(vctrl, fco, erule, admin, 5420ca60948SSteen Hegelund &multi->rule[idx]); 5430ca60948SSteen Hegelund if (err) 5440ca60948SSteen Hegelund break; 5450ca60948SSteen Hegelund } 5460ca60948SSteen Hegelund return err; 5470ca60948SSteen Hegelund } 5480ca60948SSteen Hegelund 549542e6e2cSSteen Hegelund /* Add the actionset that is the default for the VCAP type */ 550542e6e2cSSteen Hegelund static int sparx5_tc_set_actionset(struct vcap_admin *admin, 551542e6e2cSSteen Hegelund struct vcap_rule *vrule) 552542e6e2cSSteen Hegelund { 553542e6e2cSSteen Hegelund enum vcap_actionfield_set aset; 554542e6e2cSSteen Hegelund int err = 0; 555542e6e2cSSteen Hegelund 556542e6e2cSSteen Hegelund switch (admin->vtype) { 557542e6e2cSSteen Hegelund case VCAP_TYPE_IS0: 558542e6e2cSSteen Hegelund aset = VCAP_AFS_CLASSIFICATION; 559542e6e2cSSteen Hegelund break; 560542e6e2cSSteen Hegelund case VCAP_TYPE_IS2: 561542e6e2cSSteen Hegelund aset = VCAP_AFS_BASE_TYPE; 562542e6e2cSSteen Hegelund break; 56352b28a93SSteen Hegelund case VCAP_TYPE_ES0: 56452b28a93SSteen Hegelund aset = VCAP_AFS_ES0; 56552b28a93SSteen Hegelund break; 5667b911a53SSteen Hegelund case VCAP_TYPE_ES2: 5677b911a53SSteen Hegelund aset = VCAP_AFS_BASE_TYPE; 5687b911a53SSteen Hegelund break; 569542e6e2cSSteen Hegelund default: 57052b28a93SSteen Hegelund pr_err("%s:%d: %s\n", __func__, __LINE__, "Invalid VCAP type"); 571542e6e2cSSteen Hegelund return -EINVAL; 572542e6e2cSSteen Hegelund } 573542e6e2cSSteen Hegelund /* Do not overwrite any current actionset */ 574542e6e2cSSteen Hegelund if (vrule->actionset == VCAP_AFS_NO_VALUE) 575542e6e2cSSteen Hegelund err = vcap_set_rule_set_actionset(vrule, aset); 576542e6e2cSSteen Hegelund return err; 577542e6e2cSSteen Hegelund } 578542e6e2cSSteen Hegelund 57988bd9ea7SSteen Hegelund /* Add the VCAP key to match on for a rule target value */ 58088bd9ea7SSteen Hegelund static int sparx5_tc_add_rule_link_target(struct vcap_admin *admin, 58188bd9ea7SSteen Hegelund struct vcap_rule *vrule, 58288bd9ea7SSteen Hegelund int target_cid) 58388bd9ea7SSteen Hegelund { 58488bd9ea7SSteen Hegelund int link_val = target_cid % VCAP_CID_LOOKUP_SIZE; 58588bd9ea7SSteen Hegelund int err; 58688bd9ea7SSteen Hegelund 58788bd9ea7SSteen Hegelund if (!link_val) 58888bd9ea7SSteen Hegelund return 0; 58988bd9ea7SSteen Hegelund 59088bd9ea7SSteen Hegelund switch (admin->vtype) { 59188bd9ea7SSteen Hegelund case VCAP_TYPE_IS0: 59288bd9ea7SSteen Hegelund /* Add NXT_IDX key for chaining rules between IS0 instances */ 59388bd9ea7SSteen Hegelund err = vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX_SEL, 59488bd9ea7SSteen Hegelund 1, /* enable */ 59588bd9ea7SSteen Hegelund ~0); 59688bd9ea7SSteen Hegelund if (err) 59788bd9ea7SSteen Hegelund return err; 59888bd9ea7SSteen Hegelund return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX, 59988bd9ea7SSteen Hegelund link_val, /* target */ 60088bd9ea7SSteen Hegelund ~0); 60188bd9ea7SSteen Hegelund case VCAP_TYPE_IS2: 60288bd9ea7SSteen Hegelund /* Add PAG key for chaining rules from IS0 */ 60388bd9ea7SSteen Hegelund return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG, 60488bd9ea7SSteen Hegelund link_val, /* target */ 60588bd9ea7SSteen Hegelund ~0); 60652b28a93SSteen Hegelund case VCAP_TYPE_ES0: 6077b911a53SSteen Hegelund case VCAP_TYPE_ES2: 6087b911a53SSteen Hegelund /* Add ISDX key for chaining rules from IS0 */ 6097b911a53SSteen Hegelund return vcap_rule_add_key_u32(vrule, VCAP_KF_ISDX_CLS, link_val, 6107b911a53SSteen Hegelund ~0); 61188bd9ea7SSteen Hegelund default: 61288bd9ea7SSteen Hegelund break; 61388bd9ea7SSteen Hegelund } 61488bd9ea7SSteen Hegelund return 0; 61588bd9ea7SSteen Hegelund } 61688bd9ea7SSteen Hegelund 61788bd9ea7SSteen Hegelund /* Add the VCAP action that adds a target value to a rule */ 61888bd9ea7SSteen Hegelund static int sparx5_tc_add_rule_link(struct vcap_control *vctrl, 61988bd9ea7SSteen Hegelund struct vcap_admin *admin, 62088bd9ea7SSteen Hegelund struct vcap_rule *vrule, 62188bd9ea7SSteen Hegelund int from_cid, int to_cid) 62288bd9ea7SSteen Hegelund { 62388bd9ea7SSteen Hegelund struct vcap_admin *to_admin = vcap_find_admin(vctrl, to_cid); 62488bd9ea7SSteen Hegelund int diff, err = 0; 62588bd9ea7SSteen Hegelund 626b5b0c364SSteen Hegelund if (!to_admin) { 62788bd9ea7SSteen Hegelund pr_err("%s:%d: unsupported chain direction: %d\n", 62888bd9ea7SSteen Hegelund __func__, __LINE__, to_cid); 62988bd9ea7SSteen Hegelund return -EINVAL; 63088bd9ea7SSteen Hegelund } 631b5b0c364SSteen Hegelund 632b5b0c364SSteen Hegelund diff = vcap_chain_offset(vctrl, from_cid, to_cid); 633b5b0c364SSteen Hegelund if (!diff) 634b5b0c364SSteen Hegelund return 0; 635b5b0c364SSteen Hegelund 63688bd9ea7SSteen Hegelund if (admin->vtype == VCAP_TYPE_IS0 && 63788bd9ea7SSteen Hegelund to_admin->vtype == VCAP_TYPE_IS0) { 63888bd9ea7SSteen Hegelund /* Between IS0 instances the G_IDX value is used */ 63988bd9ea7SSteen Hegelund err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX, diff); 64088bd9ea7SSteen Hegelund if (err) 64188bd9ea7SSteen Hegelund goto out; 64288bd9ea7SSteen Hegelund err = vcap_rule_add_action_u32(vrule, VCAP_AF_NXT_IDX_CTRL, 64388bd9ea7SSteen Hegelund 1); /* Replace */ 64488bd9ea7SSteen Hegelund if (err) 64588bd9ea7SSteen Hegelund goto out; 64688bd9ea7SSteen Hegelund } else if (admin->vtype == VCAP_TYPE_IS0 && 64788bd9ea7SSteen Hegelund to_admin->vtype == VCAP_TYPE_IS2) { 64888bd9ea7SSteen Hegelund /* Between IS0 and IS2 the PAG value is used */ 64988bd9ea7SSteen Hegelund err = vcap_rule_add_action_u32(vrule, VCAP_AF_PAG_VAL, diff); 65088bd9ea7SSteen Hegelund if (err) 65188bd9ea7SSteen Hegelund goto out; 65288bd9ea7SSteen Hegelund err = vcap_rule_add_action_u32(vrule, 65388bd9ea7SSteen Hegelund VCAP_AF_PAG_OVERRIDE_MASK, 65488bd9ea7SSteen Hegelund 0xff); 65588bd9ea7SSteen Hegelund if (err) 65688bd9ea7SSteen Hegelund goto out; 6577b911a53SSteen Hegelund } else if (admin->vtype == VCAP_TYPE_IS0 && 65852b28a93SSteen Hegelund (to_admin->vtype == VCAP_TYPE_ES0 || 65952b28a93SSteen Hegelund to_admin->vtype == VCAP_TYPE_ES2)) { 66052b28a93SSteen Hegelund /* Between IS0 and ES0/ES2 the ISDX value is used */ 6617b911a53SSteen Hegelund err = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL, 6627b911a53SSteen Hegelund diff); 6637b911a53SSteen Hegelund if (err) 6647b911a53SSteen Hegelund goto out; 6657b911a53SSteen Hegelund err = vcap_rule_add_action_bit(vrule, 6667b911a53SSteen Hegelund VCAP_AF_ISDX_ADD_REPLACE_SEL, 6677b911a53SSteen Hegelund VCAP_BIT_1); 6687b911a53SSteen Hegelund if (err) 6697b911a53SSteen Hegelund goto out; 67088bd9ea7SSteen Hegelund } else { 67188bd9ea7SSteen Hegelund pr_err("%s:%d: unsupported chain destination: %d\n", 67288bd9ea7SSteen Hegelund __func__, __LINE__, to_cid); 67388bd9ea7SSteen Hegelund err = -EOPNOTSUPP; 67488bd9ea7SSteen Hegelund } 67588bd9ea7SSteen Hegelund out: 67688bd9ea7SSteen Hegelund return err; 67788bd9ea7SSteen Hegelund } 67888bd9ea7SSteen Hegelund 6796ebf182bSDaniel Machon static int sparx5_tc_flower_parse_act_gate(struct sparx5_psfp_sg *sg, 6806ebf182bSDaniel Machon struct flow_action_entry *act, 6816ebf182bSDaniel Machon struct netlink_ext_ack *extack) 6826ebf182bSDaniel Machon { 6836ebf182bSDaniel Machon int i; 6846ebf182bSDaniel Machon 6856ebf182bSDaniel Machon if (act->gate.prio < -1 || act->gate.prio > SPX5_PSFP_SG_MAX_IPV) { 6866ebf182bSDaniel Machon NL_SET_ERR_MSG_MOD(extack, "Invalid gate priority"); 6876ebf182bSDaniel Machon return -EINVAL; 6886ebf182bSDaniel Machon } 6896ebf182bSDaniel Machon 6906ebf182bSDaniel Machon if (act->gate.cycletime < SPX5_PSFP_SG_MIN_CYCLE_TIME_NS || 6916ebf182bSDaniel Machon act->gate.cycletime > SPX5_PSFP_SG_MAX_CYCLE_TIME_NS) { 6926ebf182bSDaniel Machon NL_SET_ERR_MSG_MOD(extack, "Invalid gate cycletime"); 6936ebf182bSDaniel Machon return -EINVAL; 6946ebf182bSDaniel Machon } 6956ebf182bSDaniel Machon 6966ebf182bSDaniel Machon if (act->gate.cycletimeext > SPX5_PSFP_SG_MAX_CYCLE_TIME_NS) { 6976ebf182bSDaniel Machon NL_SET_ERR_MSG_MOD(extack, "Invalid gate cycletimeext"); 6986ebf182bSDaniel Machon return -EINVAL; 6996ebf182bSDaniel Machon } 7006ebf182bSDaniel Machon 7016ebf182bSDaniel Machon if (act->gate.num_entries >= SPX5_PSFP_GCE_CNT) { 7026ebf182bSDaniel Machon NL_SET_ERR_MSG_MOD(extack, "Invalid number of gate entries"); 7036ebf182bSDaniel Machon return -EINVAL; 7046ebf182bSDaniel Machon } 7056ebf182bSDaniel Machon 7066ebf182bSDaniel Machon sg->gate_state = true; 7076ebf182bSDaniel Machon sg->ipv = act->gate.prio; 7086ebf182bSDaniel Machon sg->num_entries = act->gate.num_entries; 7096ebf182bSDaniel Machon sg->cycletime = act->gate.cycletime; 7106ebf182bSDaniel Machon sg->cycletimeext = act->gate.cycletimeext; 7116ebf182bSDaniel Machon 7126ebf182bSDaniel Machon for (i = 0; i < sg->num_entries; i++) { 7136ebf182bSDaniel Machon sg->gce[i].gate_state = !!act->gate.entries[i].gate_state; 7146ebf182bSDaniel Machon sg->gce[i].interval = act->gate.entries[i].interval; 7156ebf182bSDaniel Machon sg->gce[i].ipv = act->gate.entries[i].ipv; 7166ebf182bSDaniel Machon sg->gce[i].maxoctets = act->gate.entries[i].maxoctets; 7176ebf182bSDaniel Machon } 7186ebf182bSDaniel Machon 7196ebf182bSDaniel Machon return 0; 7206ebf182bSDaniel Machon } 7216ebf182bSDaniel Machon 7226ebf182bSDaniel Machon static int sparx5_tc_flower_parse_act_police(struct sparx5_policer *pol, 7236ebf182bSDaniel Machon struct flow_action_entry *act, 7246ebf182bSDaniel Machon struct netlink_ext_ack *extack) 7256ebf182bSDaniel Machon { 7266ebf182bSDaniel Machon pol->type = SPX5_POL_SERVICE; 7276ebf182bSDaniel Machon pol->rate = div_u64(act->police.rate_bytes_ps, 1000) * 8; 7286ebf182bSDaniel Machon pol->burst = act->police.burst; 7296ebf182bSDaniel Machon pol->idx = act->hw_index; 7306ebf182bSDaniel Machon 7316ebf182bSDaniel Machon /* rate is now in kbit */ 7326ebf182bSDaniel Machon if (pol->rate > DIV_ROUND_UP(SPX5_SDLB_GROUP_RATE_MAX, 1000)) { 7336ebf182bSDaniel Machon NL_SET_ERR_MSG_MOD(extack, "Maximum rate exceeded"); 7346ebf182bSDaniel Machon return -EINVAL; 7356ebf182bSDaniel Machon } 7366ebf182bSDaniel Machon 7376ebf182bSDaniel Machon if (act->police.exceed.act_id != FLOW_ACTION_DROP) { 7386ebf182bSDaniel Machon NL_SET_ERR_MSG_MOD(extack, "Offload not supported when exceed action is not drop"); 7396ebf182bSDaniel Machon return -EOPNOTSUPP; 7406ebf182bSDaniel Machon } 7416ebf182bSDaniel Machon 7426ebf182bSDaniel Machon if (act->police.notexceed.act_id != FLOW_ACTION_PIPE && 7436ebf182bSDaniel Machon act->police.notexceed.act_id != FLOW_ACTION_ACCEPT) { 7446ebf182bSDaniel Machon NL_SET_ERR_MSG_MOD(extack, "Offload not supported when conform action is not pipe or ok"); 7456ebf182bSDaniel Machon return -EOPNOTSUPP; 7466ebf182bSDaniel Machon } 7476ebf182bSDaniel Machon 7486ebf182bSDaniel Machon return 0; 7496ebf182bSDaniel Machon } 7506ebf182bSDaniel Machon 7516ebf182bSDaniel Machon static int sparx5_tc_flower_psfp_setup(struct sparx5 *sparx5, 7526ebf182bSDaniel Machon struct vcap_rule *vrule, int sg_idx, 7536ebf182bSDaniel Machon int pol_idx, struct sparx5_psfp_sg *sg, 7546ebf182bSDaniel Machon struct sparx5_psfp_fm *fm, 7556ebf182bSDaniel Machon struct sparx5_psfp_sf *sf) 7566ebf182bSDaniel Machon { 7576ebf182bSDaniel Machon u32 psfp_sfid = 0, psfp_fmid = 0, psfp_sgid = 0; 7586ebf182bSDaniel Machon int ret; 7596ebf182bSDaniel Machon 7606ebf182bSDaniel Machon /* Must always have a stream gate - max sdu (filter option) is evaluated 7616ebf182bSDaniel Machon * after frames have passed the gate, so in case of only a policer, we 7626ebf182bSDaniel Machon * allocate a stream gate that is always open. 7636ebf182bSDaniel Machon */ 7646ebf182bSDaniel Machon if (sg_idx < 0) { 7656ebf182bSDaniel Machon sg_idx = sparx5_pool_idx_to_id(SPX5_PSFP_SG_OPEN); 7666ebf182bSDaniel Machon sg->ipv = 0; /* Disabled */ 7676ebf182bSDaniel Machon sg->cycletime = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT; 7686ebf182bSDaniel Machon sg->num_entries = 1; 7696ebf182bSDaniel Machon sg->gate_state = 1; /* Open */ 7706ebf182bSDaniel Machon sg->gate_enabled = 1; 7716ebf182bSDaniel Machon sg->gce[0].gate_state = 1; 7726ebf182bSDaniel Machon sg->gce[0].interval = SPX5_PSFP_SG_CYCLE_TIME_DEFAULT; 7736ebf182bSDaniel Machon sg->gce[0].ipv = 0; 7746ebf182bSDaniel Machon sg->gce[0].maxoctets = 0; /* Disabled */ 7756ebf182bSDaniel Machon } 7766ebf182bSDaniel Machon 7776ebf182bSDaniel Machon ret = sparx5_psfp_sg_add(sparx5, sg_idx, sg, &psfp_sgid); 7786ebf182bSDaniel Machon if (ret < 0) 7796ebf182bSDaniel Machon return ret; 7806ebf182bSDaniel Machon 7816ebf182bSDaniel Machon if (pol_idx >= 0) { 7826ebf182bSDaniel Machon /* Add new flow-meter */ 7836ebf182bSDaniel Machon ret = sparx5_psfp_fm_add(sparx5, pol_idx, fm, &psfp_fmid); 7846ebf182bSDaniel Machon if (ret < 0) 7856ebf182bSDaniel Machon return ret; 7866ebf182bSDaniel Machon } 7876ebf182bSDaniel Machon 7886ebf182bSDaniel Machon /* Map stream filter to stream gate */ 7896ebf182bSDaniel Machon sf->sgid = psfp_sgid; 7906ebf182bSDaniel Machon 7916ebf182bSDaniel Machon /* Add new stream-filter and map it to a steam gate */ 7926ebf182bSDaniel Machon ret = sparx5_psfp_sf_add(sparx5, sf, &psfp_sfid); 7936ebf182bSDaniel Machon if (ret < 0) 7946ebf182bSDaniel Machon return ret; 7956ebf182bSDaniel Machon 7966ebf182bSDaniel Machon /* Streams are classified by ISDX - map ISDX 1:1 to sfid for now. */ 7976ebf182bSDaniel Machon sparx5_isdx_conf_set(sparx5, psfp_sfid, psfp_sfid, psfp_fmid); 7986ebf182bSDaniel Machon 7996ebf182bSDaniel Machon ret = vcap_rule_add_action_bit(vrule, VCAP_AF_ISDX_ADD_REPLACE_SEL, 8006ebf182bSDaniel Machon VCAP_BIT_1); 8016ebf182bSDaniel Machon if (ret) 8026ebf182bSDaniel Machon return ret; 8036ebf182bSDaniel Machon 8046ebf182bSDaniel Machon ret = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_VAL, psfp_sfid); 8056ebf182bSDaniel Machon if (ret) 8066ebf182bSDaniel Machon return ret; 8076ebf182bSDaniel Machon 8086ebf182bSDaniel Machon return 0; 8096ebf182bSDaniel Machon } 8106ebf182bSDaniel Machon 81152b28a93SSteen Hegelund /* Handle the action trap for a VCAP rule */ 81252b28a93SSteen Hegelund static int sparx5_tc_action_trap(struct vcap_admin *admin, 81352b28a93SSteen Hegelund struct vcap_rule *vrule, 81452b28a93SSteen Hegelund struct flow_cls_offload *fco) 81552b28a93SSteen Hegelund { 81652b28a93SSteen Hegelund int err = 0; 81752b28a93SSteen Hegelund 81852b28a93SSteen Hegelund switch (admin->vtype) { 81952b28a93SSteen Hegelund case VCAP_TYPE_IS2: 82052b28a93SSteen Hegelund err = vcap_rule_add_action_bit(vrule, 82152b28a93SSteen Hegelund VCAP_AF_CPU_COPY_ENA, 82252b28a93SSteen Hegelund VCAP_BIT_1); 82352b28a93SSteen Hegelund if (err) 82452b28a93SSteen Hegelund break; 82552b28a93SSteen Hegelund err = vcap_rule_add_action_u32(vrule, 82652b28a93SSteen Hegelund VCAP_AF_CPU_QUEUE_NUM, 0); 82752b28a93SSteen Hegelund if (err) 82852b28a93SSteen Hegelund break; 82952b28a93SSteen Hegelund err = vcap_rule_add_action_u32(vrule, 83052b28a93SSteen Hegelund VCAP_AF_MASK_MODE, 83152b28a93SSteen Hegelund SPX5_PMM_REPLACE_ALL); 83252b28a93SSteen Hegelund break; 83352b28a93SSteen Hegelund case VCAP_TYPE_ES0: 83452b28a93SSteen Hegelund err = vcap_rule_add_action_u32(vrule, 83552b28a93SSteen Hegelund VCAP_AF_FWD_SEL, 83652b28a93SSteen Hegelund SPX5_FWSEL_REDIRECT_TO_LOOPBACK); 83752b28a93SSteen Hegelund break; 83852b28a93SSteen Hegelund case VCAP_TYPE_ES2: 83952b28a93SSteen Hegelund err = vcap_rule_add_action_bit(vrule, 84052b28a93SSteen Hegelund VCAP_AF_CPU_COPY_ENA, 84152b28a93SSteen Hegelund VCAP_BIT_1); 84252b28a93SSteen Hegelund if (err) 84352b28a93SSteen Hegelund break; 84452b28a93SSteen Hegelund err = vcap_rule_add_action_u32(vrule, 84552b28a93SSteen Hegelund VCAP_AF_CPU_QUEUE_NUM, 0); 84652b28a93SSteen Hegelund break; 84752b28a93SSteen Hegelund default: 84852b28a93SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 84952b28a93SSteen Hegelund "Trap action not supported in this VCAP"); 85052b28a93SSteen Hegelund err = -EOPNOTSUPP; 85152b28a93SSteen Hegelund break; 85252b28a93SSteen Hegelund } 85352b28a93SSteen Hegelund return err; 85452b28a93SSteen Hegelund } 85552b28a93SSteen Hegelund 856ebf44dedSSteen Hegelund static int sparx5_tc_action_vlan_pop(struct vcap_admin *admin, 857ebf44dedSSteen Hegelund struct vcap_rule *vrule, 858ebf44dedSSteen Hegelund struct flow_cls_offload *fco, 859ebf44dedSSteen Hegelund u16 tpid) 860ebf44dedSSteen Hegelund { 861ebf44dedSSteen Hegelund int err = 0; 862ebf44dedSSteen Hegelund 863ebf44dedSSteen Hegelund switch (admin->vtype) { 864ebf44dedSSteen Hegelund case VCAP_TYPE_ES0: 865ebf44dedSSteen Hegelund break; 866ebf44dedSSteen Hegelund default: 867ebf44dedSSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 868ebf44dedSSteen Hegelund "VLAN pop action not supported in this VCAP"); 869ebf44dedSSteen Hegelund return -EOPNOTSUPP; 870ebf44dedSSteen Hegelund } 871ebf44dedSSteen Hegelund 872ebf44dedSSteen Hegelund switch (tpid) { 873ebf44dedSSteen Hegelund case ETH_P_8021Q: 874ebf44dedSSteen Hegelund case ETH_P_8021AD: 875ebf44dedSSteen Hegelund err = vcap_rule_add_action_u32(vrule, 876ebf44dedSSteen Hegelund VCAP_AF_PUSH_OUTER_TAG, 877ebf44dedSSteen Hegelund SPX5_OTAG_UNTAG); 878ebf44dedSSteen Hegelund break; 879ebf44dedSSteen Hegelund default: 880ebf44dedSSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 881ebf44dedSSteen Hegelund "Invalid vlan proto"); 882ebf44dedSSteen Hegelund err = -EINVAL; 883ebf44dedSSteen Hegelund } 884ebf44dedSSteen Hegelund return err; 885ebf44dedSSteen Hegelund } 886ebf44dedSSteen Hegelund 887ebf44dedSSteen Hegelund static int sparx5_tc_action_vlan_modify(struct vcap_admin *admin, 888ebf44dedSSteen Hegelund struct vcap_rule *vrule, 889ebf44dedSSteen Hegelund struct flow_cls_offload *fco, 890ebf44dedSSteen Hegelund struct flow_action_entry *act, 891ebf44dedSSteen Hegelund u16 tpid) 892ebf44dedSSteen Hegelund { 893ebf44dedSSteen Hegelund int err = 0; 894ebf44dedSSteen Hegelund 895ebf44dedSSteen Hegelund switch (admin->vtype) { 896ebf44dedSSteen Hegelund case VCAP_TYPE_ES0: 897ebf44dedSSteen Hegelund err = vcap_rule_add_action_u32(vrule, 898ebf44dedSSteen Hegelund VCAP_AF_PUSH_OUTER_TAG, 899ebf44dedSSteen Hegelund SPX5_OTAG_TAG_A); 900ebf44dedSSteen Hegelund if (err) 901ebf44dedSSteen Hegelund return err; 902ebf44dedSSteen Hegelund break; 903ebf44dedSSteen Hegelund default: 904ebf44dedSSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 905ebf44dedSSteen Hegelund "VLAN modify action not supported in this VCAP"); 906ebf44dedSSteen Hegelund return -EOPNOTSUPP; 907ebf44dedSSteen Hegelund } 908ebf44dedSSteen Hegelund 909ebf44dedSSteen Hegelund switch (tpid) { 910ebf44dedSSteen Hegelund case ETH_P_8021Q: 911ebf44dedSSteen Hegelund err = vcap_rule_add_action_u32(vrule, 912ebf44dedSSteen Hegelund VCAP_AF_TAG_A_TPID_SEL, 913ebf44dedSSteen Hegelund SPX5_TPID_A_8100); 914ebf44dedSSteen Hegelund break; 915ebf44dedSSteen Hegelund case ETH_P_8021AD: 916ebf44dedSSteen Hegelund err = vcap_rule_add_action_u32(vrule, 917ebf44dedSSteen Hegelund VCAP_AF_TAG_A_TPID_SEL, 918ebf44dedSSteen Hegelund SPX5_TPID_A_88A8); 919ebf44dedSSteen Hegelund break; 920ebf44dedSSteen Hegelund default: 921ebf44dedSSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 922ebf44dedSSteen Hegelund "Invalid vlan proto"); 923ebf44dedSSteen Hegelund err = -EINVAL; 924ebf44dedSSteen Hegelund } 925ebf44dedSSteen Hegelund if (err) 926ebf44dedSSteen Hegelund return err; 927ebf44dedSSteen Hegelund 928ebf44dedSSteen Hegelund err = vcap_rule_add_action_u32(vrule, 929ebf44dedSSteen Hegelund VCAP_AF_TAG_A_VID_SEL, 930ebf44dedSSteen Hegelund SPX5_VID_A_VAL); 931ebf44dedSSteen Hegelund if (err) 932ebf44dedSSteen Hegelund return err; 933ebf44dedSSteen Hegelund 934ebf44dedSSteen Hegelund err = vcap_rule_add_action_u32(vrule, 935ebf44dedSSteen Hegelund VCAP_AF_VID_A_VAL, 936ebf44dedSSteen Hegelund act->vlan.vid); 937ebf44dedSSteen Hegelund if (err) 938ebf44dedSSteen Hegelund return err; 939ebf44dedSSteen Hegelund 940ebf44dedSSteen Hegelund err = vcap_rule_add_action_u32(vrule, 941ebf44dedSSteen Hegelund VCAP_AF_TAG_A_PCP_SEL, 942ebf44dedSSteen Hegelund SPX5_PCP_A_VAL); 943ebf44dedSSteen Hegelund if (err) 944ebf44dedSSteen Hegelund return err; 945ebf44dedSSteen Hegelund 946ebf44dedSSteen Hegelund err = vcap_rule_add_action_u32(vrule, 947ebf44dedSSteen Hegelund VCAP_AF_PCP_A_VAL, 948ebf44dedSSteen Hegelund act->vlan.prio); 949ebf44dedSSteen Hegelund if (err) 950ebf44dedSSteen Hegelund return err; 951ebf44dedSSteen Hegelund 952ebf44dedSSteen Hegelund return vcap_rule_add_action_u32(vrule, 953ebf44dedSSteen Hegelund VCAP_AF_TAG_A_DEI_SEL, 954ebf44dedSSteen Hegelund SPX5_DEI_A_CLASSIFIED); 955ebf44dedSSteen Hegelund } 956ebf44dedSSteen Hegelund 957ebf44dedSSteen Hegelund static int sparx5_tc_action_vlan_push(struct vcap_admin *admin, 958ebf44dedSSteen Hegelund struct vcap_rule *vrule, 959ebf44dedSSteen Hegelund struct flow_cls_offload *fco, 960ebf44dedSSteen Hegelund struct flow_action_entry *act, 961ebf44dedSSteen Hegelund u16 tpid) 962ebf44dedSSteen Hegelund { 963ebf44dedSSteen Hegelund u16 act_tpid = be16_to_cpu(act->vlan.proto); 964ebf44dedSSteen Hegelund int err = 0; 965ebf44dedSSteen Hegelund 966ebf44dedSSteen Hegelund switch (admin->vtype) { 967ebf44dedSSteen Hegelund case VCAP_TYPE_ES0: 968ebf44dedSSteen Hegelund break; 969ebf44dedSSteen Hegelund default: 970ebf44dedSSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 971ebf44dedSSteen Hegelund "VLAN push action not supported in this VCAP"); 972ebf44dedSSteen Hegelund return -EOPNOTSUPP; 973ebf44dedSSteen Hegelund } 974ebf44dedSSteen Hegelund 975ebf44dedSSteen Hegelund if (tpid == ETH_P_8021AD) { 976ebf44dedSSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 977ebf44dedSSteen Hegelund "Cannot push on double tagged frames"); 978ebf44dedSSteen Hegelund return -EOPNOTSUPP; 979ebf44dedSSteen Hegelund } 980ebf44dedSSteen Hegelund 981ebf44dedSSteen Hegelund err = sparx5_tc_action_vlan_modify(admin, vrule, fco, act, act_tpid); 982ebf44dedSSteen Hegelund if (err) 983ebf44dedSSteen Hegelund return err; 984ebf44dedSSteen Hegelund 985ebf44dedSSteen Hegelund switch (act_tpid) { 986ebf44dedSSteen Hegelund case ETH_P_8021Q: 987ebf44dedSSteen Hegelund break; 988ebf44dedSSteen Hegelund case ETH_P_8021AD: 989ebf44dedSSteen Hegelund /* Push classified tag as inner tag */ 990ebf44dedSSteen Hegelund err = vcap_rule_add_action_u32(vrule, 991ebf44dedSSteen Hegelund VCAP_AF_PUSH_INNER_TAG, 992ebf44dedSSteen Hegelund SPX5_ITAG_PUSH_B_TAG); 993ebf44dedSSteen Hegelund if (err) 994ebf44dedSSteen Hegelund break; 995ebf44dedSSteen Hegelund err = vcap_rule_add_action_u32(vrule, 996ebf44dedSSteen Hegelund VCAP_AF_TAG_B_TPID_SEL, 997ebf44dedSSteen Hegelund SPX5_TPID_B_CLASSIFIED); 998ebf44dedSSteen Hegelund break; 999ebf44dedSSteen Hegelund default: 1000ebf44dedSSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1001ebf44dedSSteen Hegelund "Invalid vlan proto"); 1002ebf44dedSSteen Hegelund err = -EINVAL; 1003ebf44dedSSteen Hegelund } 1004ebf44dedSSteen Hegelund return err; 1005ebf44dedSSteen Hegelund } 1006ebf44dedSSteen Hegelund 1007e1d597ecSSteen Hegelund /* Remove rule keys that may prevent templates from matching a keyset */ 1008e1d597ecSSteen Hegelund static void sparx5_tc_flower_simplify_rule(struct vcap_admin *admin, 1009e1d597ecSSteen Hegelund struct vcap_rule *vrule, 1010e1d597ecSSteen Hegelund u16 l3_proto) 1011e1d597ecSSteen Hegelund { 1012e1d597ecSSteen Hegelund switch (admin->vtype) { 1013e1d597ecSSteen Hegelund case VCAP_TYPE_IS0: 1014e1d597ecSSteen Hegelund vcap_rule_rem_key(vrule, VCAP_KF_ETYPE); 1015e1d597ecSSteen Hegelund switch (l3_proto) { 1016e1d597ecSSteen Hegelund case ETH_P_IP: 1017e1d597ecSSteen Hegelund break; 1018e1d597ecSSteen Hegelund case ETH_P_IPV6: 1019e1d597ecSSteen Hegelund vcap_rule_rem_key(vrule, VCAP_KF_IP_SNAP_IS); 1020e1d597ecSSteen Hegelund break; 1021e1d597ecSSteen Hegelund default: 1022e1d597ecSSteen Hegelund break; 1023e1d597ecSSteen Hegelund } 1024e1d597ecSSteen Hegelund break; 1025e1d597ecSSteen Hegelund case VCAP_TYPE_ES2: 1026e1d597ecSSteen Hegelund switch (l3_proto) { 1027e1d597ecSSteen Hegelund case ETH_P_IP: 1028e1d597ecSSteen Hegelund if (vrule->keyset == VCAP_KFS_IP4_OTHER) 1029e1d597ecSSteen Hegelund vcap_rule_rem_key(vrule, VCAP_KF_TCP_IS); 1030e1d597ecSSteen Hegelund break; 1031e1d597ecSSteen Hegelund case ETH_P_IPV6: 1032e1d597ecSSteen Hegelund if (vrule->keyset == VCAP_KFS_IP6_STD) 1033e1d597ecSSteen Hegelund vcap_rule_rem_key(vrule, VCAP_KF_TCP_IS); 1034e1d597ecSSteen Hegelund vcap_rule_rem_key(vrule, VCAP_KF_IP4_IS); 1035e1d597ecSSteen Hegelund break; 1036e1d597ecSSteen Hegelund default: 1037e1d597ecSSteen Hegelund break; 1038e1d597ecSSteen Hegelund } 1039e1d597ecSSteen Hegelund break; 1040e1d597ecSSteen Hegelund case VCAP_TYPE_IS2: 1041e1d597ecSSteen Hegelund switch (l3_proto) { 1042e1d597ecSSteen Hegelund case ETH_P_IP: 1043e1d597ecSSteen Hegelund case ETH_P_IPV6: 1044e1d597ecSSteen Hegelund vcap_rule_rem_key(vrule, VCAP_KF_IP4_IS); 1045e1d597ecSSteen Hegelund break; 1046e1d597ecSSteen Hegelund default: 1047e1d597ecSSteen Hegelund break; 1048e1d597ecSSteen Hegelund } 1049e1d597ecSSteen Hegelund break; 1050e1d597ecSSteen Hegelund default: 1051e1d597ecSSteen Hegelund break; 1052e1d597ecSSteen Hegelund } 1053e1d597ecSSteen Hegelund } 1054e1d597ecSSteen Hegelund 1055e1d597ecSSteen Hegelund static bool sparx5_tc_flower_use_template(struct net_device *ndev, 1056e1d597ecSSteen Hegelund struct flow_cls_offload *fco, 1057e1d597ecSSteen Hegelund struct vcap_admin *admin, 1058e1d597ecSSteen Hegelund struct vcap_rule *vrule) 1059e1d597ecSSteen Hegelund { 1060e1d597ecSSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 1061e1d597ecSSteen Hegelund struct sparx5_tc_flower_template *ftp; 1062e1d597ecSSteen Hegelund 1063e1d597ecSSteen Hegelund list_for_each_entry(ftp, &port->tc_templates, list) { 1064e1d597ecSSteen Hegelund if (ftp->cid != fco->common.chain_index) 1065e1d597ecSSteen Hegelund continue; 1066e1d597ecSSteen Hegelund 1067e1d597ecSSteen Hegelund vcap_set_rule_set_keyset(vrule, ftp->keyset); 1068e1d597ecSSteen Hegelund sparx5_tc_flower_simplify_rule(admin, vrule, ftp->l3_proto); 1069e1d597ecSSteen Hegelund return true; 1070e1d597ecSSteen Hegelund } 1071e1d597ecSSteen Hegelund return false; 1072e1d597ecSSteen Hegelund } 1073e1d597ecSSteen Hegelund 1074c9da1ac1SSteen Hegelund static int sparx5_tc_flower_replace(struct net_device *ndev, 1075c9da1ac1SSteen Hegelund struct flow_cls_offload *fco, 1076e7e3f514SSteen Hegelund struct vcap_admin *admin, 1077e7e3f514SSteen Hegelund bool ingress) 1078c9da1ac1SSteen Hegelund { 10796ebf182bSDaniel Machon struct sparx5_psfp_sf sf = { .max_sdu = SPX5_PSFP_SF_MAX_SDU }; 10806ebf182bSDaniel Machon struct netlink_ext_ack *extack = fco->common.extack; 10816ebf182bSDaniel Machon int err, idx, tc_sg_idx = -1, tc_pol_idx = -1; 1082ebf44dedSSteen Hegelund struct vcap_tc_flower_parse_usage state = { 1083ebf44dedSSteen Hegelund .fco = fco, 1084ebf44dedSSteen Hegelund .l3_proto = ETH_P_ALL, 1085ebf44dedSSteen Hegelund .admin = admin, 1086ebf44dedSSteen Hegelund }; 1087c9da1ac1SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 10880ca60948SSteen Hegelund struct sparx5_multiple_rules multi = {}; 10896ebf182bSDaniel Machon struct sparx5 *sparx5 = port->sparx5; 10906ebf182bSDaniel Machon struct sparx5_psfp_sg sg = { 0 }; 10916ebf182bSDaniel Machon struct sparx5_psfp_fm fm = { 0 }; 1092c9da1ac1SSteen Hegelund struct flow_action_entry *act; 1093c9da1ac1SSteen Hegelund struct vcap_control *vctrl; 1094c9da1ac1SSteen Hegelund struct flow_rule *frule; 1095c9da1ac1SSteen Hegelund struct vcap_rule *vrule; 1096c9da1ac1SSteen Hegelund 1097c9da1ac1SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 1098392d0ab0SSteen Hegelund 1099e7e3f514SSteen Hegelund err = sparx5_tc_flower_action_check(vctrl, ndev, fco, ingress); 1100392d0ab0SSteen Hegelund if (err) 1101392d0ab0SSteen Hegelund return err; 1102392d0ab0SSteen Hegelund 1103c9da1ac1SSteen Hegelund vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, VCAP_USER_TC, 1104c9da1ac1SSteen Hegelund fco->common.prio, 0); 1105c9da1ac1SSteen Hegelund if (IS_ERR(vrule)) 1106c9da1ac1SSteen Hegelund return PTR_ERR(vrule); 1107c9da1ac1SSteen Hegelund 1108c9da1ac1SSteen Hegelund vrule->cookie = fco->cookie; 1109bcddc196SSteen Hegelund 1110ebf44dedSSteen Hegelund state.vrule = vrule; 1111ebf44dedSSteen Hegelund state.frule = flow_cls_offload_flow_rule(fco); 1112ebf44dedSSteen Hegelund err = sparx5_tc_use_dissectors(&state, admin, vrule); 1113bcddc196SSteen Hegelund if (err) 1114bcddc196SSteen Hegelund goto out; 111540e7fe18SSteen Hegelund 111640e7fe18SSteen Hegelund err = sparx5_tc_add_rule_counter(admin, vrule); 111740e7fe18SSteen Hegelund if (err) 111840e7fe18SSteen Hegelund goto out; 111940e7fe18SSteen Hegelund 112088bd9ea7SSteen Hegelund err = sparx5_tc_add_rule_link_target(admin, vrule, 112188bd9ea7SSteen Hegelund fco->common.chain_index); 112288bd9ea7SSteen Hegelund if (err) 112388bd9ea7SSteen Hegelund goto out; 112488bd9ea7SSteen Hegelund 1125392d0ab0SSteen Hegelund frule = flow_cls_offload_flow_rule(fco); 1126c9da1ac1SSteen Hegelund flow_action_for_each(idx, act, &frule->action) { 1127c9da1ac1SSteen Hegelund switch (act->id) { 11286ebf182bSDaniel Machon case FLOW_ACTION_GATE: { 11296ebf182bSDaniel Machon err = sparx5_tc_flower_parse_act_gate(&sg, act, extack); 11306ebf182bSDaniel Machon if (err < 0) 11316ebf182bSDaniel Machon goto out; 11326ebf182bSDaniel Machon 11336ebf182bSDaniel Machon tc_sg_idx = act->hw_index; 11346ebf182bSDaniel Machon 11356ebf182bSDaniel Machon break; 11366ebf182bSDaniel Machon } 11376ebf182bSDaniel Machon case FLOW_ACTION_POLICE: { 11386ebf182bSDaniel Machon err = sparx5_tc_flower_parse_act_police(&fm.pol, act, 11396ebf182bSDaniel Machon extack); 11406ebf182bSDaniel Machon if (err < 0) 11416ebf182bSDaniel Machon goto out; 11426ebf182bSDaniel Machon 11436ebf182bSDaniel Machon tc_pol_idx = fm.pol.idx; 11446ebf182bSDaniel Machon sf.max_sdu = act->police.mtu; 11456ebf182bSDaniel Machon 11466ebf182bSDaniel Machon break; 11476ebf182bSDaniel Machon } 1148c9da1ac1SSteen Hegelund case FLOW_ACTION_TRAP: 114952b28a93SSteen Hegelund err = sparx5_tc_action_trap(admin, vrule, fco); 1150c9da1ac1SSteen Hegelund if (err) 1151c9da1ac1SSteen Hegelund goto out; 1152c9da1ac1SSteen Hegelund break; 1153c9da1ac1SSteen Hegelund case FLOW_ACTION_ACCEPT: 1154542e6e2cSSteen Hegelund err = sparx5_tc_set_actionset(admin, vrule); 1155c9da1ac1SSteen Hegelund if (err) 1156c9da1ac1SSteen Hegelund goto out; 1157c9da1ac1SSteen Hegelund break; 1158392d0ab0SSteen Hegelund case FLOW_ACTION_GOTO: 1159542e6e2cSSteen Hegelund err = sparx5_tc_set_actionset(admin, vrule); 1160542e6e2cSSteen Hegelund if (err) 1161542e6e2cSSteen Hegelund goto out; 116288bd9ea7SSteen Hegelund sparx5_tc_add_rule_link(vctrl, admin, vrule, 116388bd9ea7SSteen Hegelund fco->common.chain_index, 116488bd9ea7SSteen Hegelund act->chain_index); 1165392d0ab0SSteen Hegelund break; 1166ebf44dedSSteen Hegelund case FLOW_ACTION_VLAN_POP: 1167ebf44dedSSteen Hegelund err = sparx5_tc_action_vlan_pop(admin, vrule, fco, 1168ebf44dedSSteen Hegelund state.tpid); 1169ebf44dedSSteen Hegelund if (err) 1170ebf44dedSSteen Hegelund goto out; 1171ebf44dedSSteen Hegelund break; 1172ebf44dedSSteen Hegelund case FLOW_ACTION_VLAN_PUSH: 1173ebf44dedSSteen Hegelund err = sparx5_tc_action_vlan_push(admin, vrule, fco, 1174ebf44dedSSteen Hegelund act, state.tpid); 1175ebf44dedSSteen Hegelund if (err) 1176ebf44dedSSteen Hegelund goto out; 1177ebf44dedSSteen Hegelund break; 1178ebf44dedSSteen Hegelund case FLOW_ACTION_VLAN_MANGLE: 1179ebf44dedSSteen Hegelund err = sparx5_tc_action_vlan_modify(admin, vrule, fco, 1180ebf44dedSSteen Hegelund act, state.tpid); 1181ebf44dedSSteen Hegelund if (err) 1182ebf44dedSSteen Hegelund goto out; 1183ebf44dedSSteen Hegelund break; 1184c9da1ac1SSteen Hegelund default: 1185c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1186c9da1ac1SSteen Hegelund "Unsupported TC action"); 1187c9da1ac1SSteen Hegelund err = -EOPNOTSUPP; 1188c9da1ac1SSteen Hegelund goto out; 1189c9da1ac1SSteen Hegelund } 1190c9da1ac1SSteen Hegelund } 11910ca60948SSteen Hegelund 11926ebf182bSDaniel Machon /* Setup PSFP */ 11936ebf182bSDaniel Machon if (tc_sg_idx >= 0 || tc_pol_idx >= 0) { 11946ebf182bSDaniel Machon err = sparx5_tc_flower_psfp_setup(sparx5, vrule, tc_sg_idx, 11956ebf182bSDaniel Machon tc_pol_idx, &sg, &fm, &sf); 11966ebf182bSDaniel Machon if (err) 11976ebf182bSDaniel Machon goto out; 11986ebf182bSDaniel Machon } 11996ebf182bSDaniel Machon 1200e1d597ecSSteen Hegelund if (!sparx5_tc_flower_use_template(ndev, fco, admin, vrule)) { 1201ebf44dedSSteen Hegelund err = sparx5_tc_select_protocol_keyset(ndev, vrule, admin, 1202ebf44dedSSteen Hegelund state.l3_proto, &multi); 12030ca60948SSteen Hegelund if (err) { 12040ca60948SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 12050ca60948SSteen Hegelund "No matching port keyset for filter protocol and keys"); 12060ca60948SSteen Hegelund goto out; 12070ca60948SSteen Hegelund } 1208e1d597ecSSteen Hegelund } 12090ca60948SSteen Hegelund 1210abc4010dSSteen Hegelund /* provide the l3 protocol to guide the keyset selection */ 1211ebf44dedSSteen Hegelund err = vcap_val_rule(vrule, state.l3_proto); 1212c9da1ac1SSteen Hegelund if (err) { 1213c9da1ac1SSteen Hegelund vcap_set_tc_exterr(fco, vrule); 1214c9da1ac1SSteen Hegelund goto out; 1215c9da1ac1SSteen Hegelund } 1216c9da1ac1SSteen Hegelund err = vcap_add_rule(vrule); 1217c9da1ac1SSteen Hegelund if (err) 1218c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 1219c9da1ac1SSteen Hegelund "Could not add the filter"); 12200ca60948SSteen Hegelund 1221ebf44dedSSteen Hegelund if (state.l3_proto == ETH_P_ALL) 12220ca60948SSteen Hegelund err = sparx5_tc_add_remaining_rules(vctrl, fco, vrule, admin, 12230ca60948SSteen Hegelund &multi); 12240ca60948SSteen Hegelund 1225c9da1ac1SSteen Hegelund out: 1226c9da1ac1SSteen Hegelund vcap_free_rule(vrule); 1227c9da1ac1SSteen Hegelund return err; 1228c9da1ac1SSteen Hegelund } 1229c9da1ac1SSteen Hegelund 12306ebf182bSDaniel Machon static void sparx5_tc_free_psfp_resources(struct sparx5 *sparx5, 12316ebf182bSDaniel Machon struct vcap_rule *vrule) 12326ebf182bSDaniel Machon { 12336ebf182bSDaniel Machon struct vcap_client_actionfield *afield; 12346ebf182bSDaniel Machon u32 isdx, sfid, sgid, fmid; 12356ebf182bSDaniel Machon 12366ebf182bSDaniel Machon /* Check if VCAP_AF_ISDX_VAL action is set for this rule - and if 12376ebf182bSDaniel Machon * it is used for stream and/or flow-meter classification. 12386ebf182bSDaniel Machon */ 12396ebf182bSDaniel Machon afield = vcap_find_actionfield(vrule, VCAP_AF_ISDX_VAL); 12406ebf182bSDaniel Machon if (!afield) 12416ebf182bSDaniel Machon return; 12426ebf182bSDaniel Machon 12436ebf182bSDaniel Machon isdx = afield->data.u32.value; 12446ebf182bSDaniel Machon sfid = sparx5_psfp_isdx_get_sf(sparx5, isdx); 12456ebf182bSDaniel Machon 12466ebf182bSDaniel Machon if (!sfid) 12476ebf182bSDaniel Machon return; 12486ebf182bSDaniel Machon 12496ebf182bSDaniel Machon fmid = sparx5_psfp_isdx_get_fm(sparx5, isdx); 12506ebf182bSDaniel Machon sgid = sparx5_psfp_sf_get_sg(sparx5, sfid); 12516ebf182bSDaniel Machon 12526ebf182bSDaniel Machon if (fmid && sparx5_psfp_fm_del(sparx5, fmid) < 0) 12536ebf182bSDaniel Machon pr_err("%s:%d Could not delete invalid fmid: %d", __func__, 12546ebf182bSDaniel Machon __LINE__, fmid); 12556ebf182bSDaniel Machon 12566ebf182bSDaniel Machon if (sgid && sparx5_psfp_sg_del(sparx5, sgid) < 0) 12576ebf182bSDaniel Machon pr_err("%s:%d Could not delete invalid sgid: %d", __func__, 12586ebf182bSDaniel Machon __LINE__, sgid); 12596ebf182bSDaniel Machon 12606ebf182bSDaniel Machon if (sparx5_psfp_sf_del(sparx5, sfid) < 0) 12616ebf182bSDaniel Machon pr_err("%s:%d Could not delete invalid sfid: %d", __func__, 12626ebf182bSDaniel Machon __LINE__, sfid); 12636ebf182bSDaniel Machon 12646ebf182bSDaniel Machon sparx5_isdx_conf_set(sparx5, isdx, 0, 0); 12656ebf182bSDaniel Machon } 12666ebf182bSDaniel Machon 12676ebf182bSDaniel Machon static int sparx5_tc_free_rule_resources(struct net_device *ndev, 12686ebf182bSDaniel Machon struct vcap_control *vctrl, 12696ebf182bSDaniel Machon int rule_id) 12706ebf182bSDaniel Machon { 12716ebf182bSDaniel Machon struct sparx5_port *port = netdev_priv(ndev); 12726ebf182bSDaniel Machon struct sparx5 *sparx5 = port->sparx5; 12736ebf182bSDaniel Machon struct vcap_rule *vrule; 12746ebf182bSDaniel Machon int ret = 0; 12756ebf182bSDaniel Machon 12766ebf182bSDaniel Machon vrule = vcap_get_rule(vctrl, rule_id); 1277*95b358e4SRuan Jinjie if (IS_ERR(vrule)) 12786ebf182bSDaniel Machon return -EINVAL; 12796ebf182bSDaniel Machon 12806ebf182bSDaniel Machon sparx5_tc_free_psfp_resources(sparx5, vrule); 12816ebf182bSDaniel Machon 12826ebf182bSDaniel Machon vcap_free_rule(vrule); 12836ebf182bSDaniel Machon return ret; 12846ebf182bSDaniel Machon } 12856ebf182bSDaniel Machon 1286c9da1ac1SSteen Hegelund static int sparx5_tc_flower_destroy(struct net_device *ndev, 1287c9da1ac1SSteen Hegelund struct flow_cls_offload *fco, 1288c9da1ac1SSteen Hegelund struct vcap_admin *admin) 1289c9da1ac1SSteen Hegelund { 1290c9da1ac1SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 12916ebf182bSDaniel Machon int err = -ENOENT, count = 0, rule_id; 1292c9da1ac1SSteen Hegelund struct vcap_control *vctrl; 1293c9da1ac1SSteen Hegelund 1294c9da1ac1SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 1295c9da1ac1SSteen Hegelund while (true) { 1296c9da1ac1SSteen Hegelund rule_id = vcap_lookup_rule_by_cookie(vctrl, fco->cookie); 1297c9da1ac1SSteen Hegelund if (rule_id <= 0) 1298c9da1ac1SSteen Hegelund break; 12996ebf182bSDaniel Machon if (count == 0) { 13006ebf182bSDaniel Machon /* Resources are attached to the first rule of 13016ebf182bSDaniel Machon * a set of rules. Only works if the rules are 13026ebf182bSDaniel Machon * in the correct order. 13036ebf182bSDaniel Machon */ 13046ebf182bSDaniel Machon err = sparx5_tc_free_rule_resources(ndev, vctrl, 13056ebf182bSDaniel Machon rule_id); 13066ebf182bSDaniel Machon if (err) 13076ebf182bSDaniel Machon pr_err("%s:%d: could not free resources %d\n", 13086ebf182bSDaniel Machon __func__, __LINE__, rule_id); 13096ebf182bSDaniel Machon } 1310c9da1ac1SSteen Hegelund err = vcap_del_rule(vctrl, ndev, rule_id); 1311c9da1ac1SSteen Hegelund if (err) { 1312c9da1ac1SSteen Hegelund pr_err("%s:%d: could not delete rule %d\n", 1313c9da1ac1SSteen Hegelund __func__, __LINE__, rule_id); 1314c9da1ac1SSteen Hegelund break; 1315c9da1ac1SSteen Hegelund } 1316c9da1ac1SSteen Hegelund } 1317c9da1ac1SSteen Hegelund return err; 1318c9da1ac1SSteen Hegelund } 1319c9da1ac1SSteen Hegelund 132040e7fe18SSteen Hegelund static int sparx5_tc_flower_stats(struct net_device *ndev, 132140e7fe18SSteen Hegelund struct flow_cls_offload *fco, 132240e7fe18SSteen Hegelund struct vcap_admin *admin) 132340e7fe18SSteen Hegelund { 132440e7fe18SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 132527d293ccSSteen Hegelund struct vcap_counter ctr = {}; 132640e7fe18SSteen Hegelund struct vcap_control *vctrl; 132740e7fe18SSteen Hegelund ulong lastused = 0; 132840e7fe18SSteen Hegelund int err; 132940e7fe18SSteen Hegelund 133040e7fe18SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 133127d293ccSSteen Hegelund err = vcap_get_rule_count_by_cookie(vctrl, &ctr, fco->cookie); 133240e7fe18SSteen Hegelund if (err) 133340e7fe18SSteen Hegelund return err; 133427d293ccSSteen Hegelund flow_stats_update(&fco->stats, 0x0, ctr.value, 0, lastused, 133540e7fe18SSteen Hegelund FLOW_ACTION_HW_STATS_IMMEDIATE); 133640e7fe18SSteen Hegelund return err; 133740e7fe18SSteen Hegelund } 133840e7fe18SSteen Hegelund 1339e1d597ecSSteen Hegelund static int sparx5_tc_flower_template_create(struct net_device *ndev, 1340e1d597ecSSteen Hegelund struct flow_cls_offload *fco, 1341e1d597ecSSteen Hegelund struct vcap_admin *admin) 1342e1d597ecSSteen Hegelund { 1343e1d597ecSSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 1344e1d597ecSSteen Hegelund struct vcap_tc_flower_parse_usage state = { 1345e1d597ecSSteen Hegelund .fco = fco, 1346e1d597ecSSteen Hegelund .l3_proto = ETH_P_ALL, 1347e1d597ecSSteen Hegelund .admin = admin, 1348e1d597ecSSteen Hegelund }; 1349e1d597ecSSteen Hegelund struct sparx5_tc_flower_template *ftp; 1350e1d597ecSSteen Hegelund struct vcap_keyset_list kslist = {}; 1351e1d597ecSSteen Hegelund enum vcap_keyfield_set keysets[10]; 1352e1d597ecSSteen Hegelund struct vcap_control *vctrl; 1353e1d597ecSSteen Hegelund struct vcap_rule *vrule; 1354e1d597ecSSteen Hegelund int count, err; 1355e1d597ecSSteen Hegelund 1356e1d597ecSSteen Hegelund if (admin->vtype == VCAP_TYPE_ES0) { 1357e1d597ecSSteen Hegelund pr_err("%s:%d: %s\n", __func__, __LINE__, 1358e1d597ecSSteen Hegelund "VCAP does not support templates"); 1359e1d597ecSSteen Hegelund return -EINVAL; 1360e1d597ecSSteen Hegelund } 1361e1d597ecSSteen Hegelund 1362e1d597ecSSteen Hegelund count = vcap_admin_rule_count(admin, fco->common.chain_index); 1363e1d597ecSSteen Hegelund if (count > 0) { 1364e1d597ecSSteen Hegelund pr_err("%s:%d: %s\n", __func__, __LINE__, 1365e1d597ecSSteen Hegelund "Filters are already present"); 1366e1d597ecSSteen Hegelund return -EBUSY; 1367e1d597ecSSteen Hegelund } 1368e1d597ecSSteen Hegelund 1369e1d597ecSSteen Hegelund ftp = kzalloc(sizeof(*ftp), GFP_KERNEL); 1370e1d597ecSSteen Hegelund if (!ftp) 1371e1d597ecSSteen Hegelund return -ENOMEM; 1372e1d597ecSSteen Hegelund 1373e1d597ecSSteen Hegelund ftp->cid = fco->common.chain_index; 1374e1d597ecSSteen Hegelund ftp->orig = VCAP_KFS_NO_VALUE; 1375e1d597ecSSteen Hegelund ftp->keyset = VCAP_KFS_NO_VALUE; 1376e1d597ecSSteen Hegelund 1377e1d597ecSSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 1378e1d597ecSSteen Hegelund vrule = vcap_alloc_rule(vctrl, ndev, fco->common.chain_index, 1379e1d597ecSSteen Hegelund VCAP_USER_TC, fco->common.prio, 0); 1380e1d597ecSSteen Hegelund if (IS_ERR(vrule)) { 1381e1d597ecSSteen Hegelund err = PTR_ERR(vrule); 1382e1d597ecSSteen Hegelund goto err_rule; 1383e1d597ecSSteen Hegelund } 1384e1d597ecSSteen Hegelund 1385e1d597ecSSteen Hegelund state.vrule = vrule; 1386e1d597ecSSteen Hegelund state.frule = flow_cls_offload_flow_rule(fco); 1387e1d597ecSSteen Hegelund err = sparx5_tc_use_dissectors(&state, admin, vrule); 1388e1d597ecSSteen Hegelund if (err) { 1389e1d597ecSSteen Hegelund pr_err("%s:%d: key error: %d\n", __func__, __LINE__, err); 1390e1d597ecSSteen Hegelund goto out; 1391e1d597ecSSteen Hegelund } 1392e1d597ecSSteen Hegelund 1393e1d597ecSSteen Hegelund ftp->l3_proto = state.l3_proto; 1394e1d597ecSSteen Hegelund 1395e1d597ecSSteen Hegelund sparx5_tc_flower_simplify_rule(admin, vrule, state.l3_proto); 1396e1d597ecSSteen Hegelund 1397e1d597ecSSteen Hegelund /* Find the keysets that the rule can use */ 1398e1d597ecSSteen Hegelund kslist.keysets = keysets; 1399e1d597ecSSteen Hegelund kslist.max = ARRAY_SIZE(keysets); 1400e1d597ecSSteen Hegelund if (!vcap_rule_find_keysets(vrule, &kslist)) { 1401e1d597ecSSteen Hegelund pr_err("%s:%d: %s\n", __func__, __LINE__, 1402e1d597ecSSteen Hegelund "Could not find a suitable keyset"); 1403e1d597ecSSteen Hegelund err = -ENOENT; 1404e1d597ecSSteen Hegelund goto out; 1405e1d597ecSSteen Hegelund } 1406e1d597ecSSteen Hegelund 1407e1d597ecSSteen Hegelund ftp->keyset = vcap_select_min_rule_keyset(vctrl, admin->vtype, &kslist); 1408e1d597ecSSteen Hegelund kslist.cnt = 0; 1409e1d597ecSSteen Hegelund sparx5_vcap_set_port_keyset(ndev, admin, fco->common.chain_index, 1410e1d597ecSSteen Hegelund state.l3_proto, 1411e1d597ecSSteen Hegelund ftp->keyset, 1412e1d597ecSSteen Hegelund &kslist); 1413e1d597ecSSteen Hegelund 1414e1d597ecSSteen Hegelund if (kslist.cnt > 0) 1415e1d597ecSSteen Hegelund ftp->orig = kslist.keysets[0]; 1416e1d597ecSSteen Hegelund 1417e1d597ecSSteen Hegelund /* Store new template */ 1418e1d597ecSSteen Hegelund list_add_tail(&ftp->list, &port->tc_templates); 1419e1d597ecSSteen Hegelund vcap_free_rule(vrule); 1420e1d597ecSSteen Hegelund return 0; 1421e1d597ecSSteen Hegelund 1422e1d597ecSSteen Hegelund out: 1423e1d597ecSSteen Hegelund vcap_free_rule(vrule); 1424e1d597ecSSteen Hegelund err_rule: 1425e1d597ecSSteen Hegelund kfree(ftp); 1426e1d597ecSSteen Hegelund return err; 1427e1d597ecSSteen Hegelund } 1428e1d597ecSSteen Hegelund 1429e1d597ecSSteen Hegelund static int sparx5_tc_flower_template_destroy(struct net_device *ndev, 1430e1d597ecSSteen Hegelund struct flow_cls_offload *fco, 1431e1d597ecSSteen Hegelund struct vcap_admin *admin) 1432e1d597ecSSteen Hegelund { 1433e1d597ecSSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 1434e1d597ecSSteen Hegelund struct sparx5_tc_flower_template *ftp, *tmp; 1435e1d597ecSSteen Hegelund int err = -ENOENT; 1436e1d597ecSSteen Hegelund 1437e1d597ecSSteen Hegelund /* Rules using the template are removed by the tc framework */ 1438e1d597ecSSteen Hegelund list_for_each_entry_safe(ftp, tmp, &port->tc_templates, list) { 1439e1d597ecSSteen Hegelund if (ftp->cid != fco->common.chain_index) 1440e1d597ecSSteen Hegelund continue; 1441e1d597ecSSteen Hegelund 1442e1d597ecSSteen Hegelund sparx5_vcap_set_port_keyset(ndev, admin, 1443e1d597ecSSteen Hegelund fco->common.chain_index, 1444e1d597ecSSteen Hegelund ftp->l3_proto, ftp->orig, 1445e1d597ecSSteen Hegelund NULL); 1446e1d597ecSSteen Hegelund list_del(&ftp->list); 1447e1d597ecSSteen Hegelund kfree(ftp); 1448e1d597ecSSteen Hegelund break; 1449e1d597ecSSteen Hegelund } 1450e1d597ecSSteen Hegelund return err; 1451e1d597ecSSteen Hegelund } 1452e1d597ecSSteen Hegelund 1453c9da1ac1SSteen Hegelund int sparx5_tc_flower(struct net_device *ndev, struct flow_cls_offload *fco, 1454c9da1ac1SSteen Hegelund bool ingress) 1455c9da1ac1SSteen Hegelund { 1456c9da1ac1SSteen Hegelund struct sparx5_port *port = netdev_priv(ndev); 1457c9da1ac1SSteen Hegelund struct vcap_control *vctrl; 1458c9da1ac1SSteen Hegelund struct vcap_admin *admin; 1459c9da1ac1SSteen Hegelund int err = -EINVAL; 1460c9da1ac1SSteen Hegelund 1461c9da1ac1SSteen Hegelund /* Get vcap instance from the chain id */ 1462c9da1ac1SSteen Hegelund vctrl = port->sparx5->vcap_ctrl; 1463c9da1ac1SSteen Hegelund admin = vcap_find_admin(vctrl, fco->common.chain_index); 1464c9da1ac1SSteen Hegelund if (!admin) { 1465c9da1ac1SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, "Invalid chain"); 1466c9da1ac1SSteen Hegelund return err; 1467c9da1ac1SSteen Hegelund } 1468c9da1ac1SSteen Hegelund 1469c9da1ac1SSteen Hegelund switch (fco->command) { 1470c9da1ac1SSteen Hegelund case FLOW_CLS_REPLACE: 1471e7e3f514SSteen Hegelund return sparx5_tc_flower_replace(ndev, fco, admin, ingress); 1472c9da1ac1SSteen Hegelund case FLOW_CLS_DESTROY: 1473c9da1ac1SSteen Hegelund return sparx5_tc_flower_destroy(ndev, fco, admin); 147440e7fe18SSteen Hegelund case FLOW_CLS_STATS: 147540e7fe18SSteen Hegelund return sparx5_tc_flower_stats(ndev, fco, admin); 1476e1d597ecSSteen Hegelund case FLOW_CLS_TMPLT_CREATE: 1477e1d597ecSSteen Hegelund return sparx5_tc_flower_template_create(ndev, fco, admin); 1478e1d597ecSSteen Hegelund case FLOW_CLS_TMPLT_DESTROY: 1479e1d597ecSSteen Hegelund return sparx5_tc_flower_template_destroy(ndev, fco, admin); 1480c9da1ac1SSteen Hegelund default: 1481c9da1ac1SSteen Hegelund return -EOPNOTSUPP; 1482c9da1ac1SSteen Hegelund } 1483c9da1ac1SSteen Hegelund } 1484