13643abd6SHoratiu Vultur // SPDX-License-Identifier: GPL-2.0+ 23643abd6SHoratiu Vultur 33643abd6SHoratiu Vultur #include "lan966x_main.h" 43643abd6SHoratiu Vultur #include "vcap_api.h" 53643abd6SHoratiu Vultur #include "vcap_api_client.h" 647400aaeSHoratiu Vultur #include "vcap_tc.h" 73643abd6SHoratiu Vultur 847400aaeSHoratiu Vultur static bool lan966x_tc_is_known_etype(u16 etype) 93643abd6SHoratiu Vultur { 1047400aaeSHoratiu Vultur switch (etype) { 1147400aaeSHoratiu Vultur case ETH_P_ALL: 1247400aaeSHoratiu Vultur case ETH_P_ARP: 1347400aaeSHoratiu Vultur case ETH_P_IP: 1447400aaeSHoratiu Vultur case ETH_P_IPV6: 1547400aaeSHoratiu Vultur return true; 1647400aaeSHoratiu Vultur } 1747400aaeSHoratiu Vultur 1847400aaeSHoratiu Vultur return false; 1947400aaeSHoratiu Vultur } 2047400aaeSHoratiu Vultur 2147400aaeSHoratiu Vultur static int 2247400aaeSHoratiu Vultur lan966x_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st) 2347400aaeSHoratiu Vultur { 2447400aaeSHoratiu Vultur struct flow_match_control match; 253643abd6SHoratiu Vultur int err = 0; 263643abd6SHoratiu Vultur 2747400aaeSHoratiu Vultur flow_rule_match_control(st->frule, &match); 2847400aaeSHoratiu Vultur if (match.mask->flags & FLOW_DIS_IS_FRAGMENT) { 2947400aaeSHoratiu Vultur if (match.key->flags & FLOW_DIS_IS_FRAGMENT) 3047400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, 3147400aaeSHoratiu Vultur VCAP_KF_L3_FRAGMENT, 3247400aaeSHoratiu Vultur VCAP_BIT_1); 3347400aaeSHoratiu Vultur else 3447400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, 3547400aaeSHoratiu Vultur VCAP_KF_L3_FRAGMENT, 3647400aaeSHoratiu Vultur VCAP_BIT_0); 373643abd6SHoratiu Vultur if (err) 383643abd6SHoratiu Vultur goto out; 393643abd6SHoratiu Vultur } 403643abd6SHoratiu Vultur 4147400aaeSHoratiu Vultur if (match.mask->flags & FLOW_DIS_FIRST_FRAG) { 4247400aaeSHoratiu Vultur if (match.key->flags & FLOW_DIS_FIRST_FRAG) 4347400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, 4447400aaeSHoratiu Vultur VCAP_KF_L3_FRAG_OFS_GT0, 4547400aaeSHoratiu Vultur VCAP_BIT_0); 4647400aaeSHoratiu Vultur else 4747400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, 4847400aaeSHoratiu Vultur VCAP_KF_L3_FRAG_OFS_GT0, 4947400aaeSHoratiu Vultur VCAP_BIT_1); 503643abd6SHoratiu Vultur if (err) 513643abd6SHoratiu Vultur goto out; 523643abd6SHoratiu Vultur } 533643abd6SHoratiu Vultur 5447400aaeSHoratiu Vultur st->used_keys |= BIT(FLOW_DISSECTOR_KEY_CONTROL); 553643abd6SHoratiu Vultur 563643abd6SHoratiu Vultur return err; 573643abd6SHoratiu Vultur 583643abd6SHoratiu Vultur out: 5947400aaeSHoratiu Vultur NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error"); 603643abd6SHoratiu Vultur return err; 613643abd6SHoratiu Vultur } 623643abd6SHoratiu Vultur 633643abd6SHoratiu Vultur static int 6447400aaeSHoratiu Vultur lan966x_tc_flower_handler_basic_usage(struct vcap_tc_flower_parse_usage *st) 6547400aaeSHoratiu Vultur { 6647400aaeSHoratiu Vultur struct flow_match_basic match; 6747400aaeSHoratiu Vultur int err = 0; 6847400aaeSHoratiu Vultur 6947400aaeSHoratiu Vultur flow_rule_match_basic(st->frule, &match); 7047400aaeSHoratiu Vultur if (match.mask->n_proto) { 7147400aaeSHoratiu Vultur st->l3_proto = be16_to_cpu(match.key->n_proto); 7247400aaeSHoratiu Vultur if (!lan966x_tc_is_known_etype(st->l3_proto)) { 7347400aaeSHoratiu Vultur err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE, 7447400aaeSHoratiu Vultur st->l3_proto, ~0); 7547400aaeSHoratiu Vultur if (err) 7647400aaeSHoratiu Vultur goto out; 7747400aaeSHoratiu Vultur } else if (st->l3_proto == ETH_P_IP) { 7847400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS, 7947400aaeSHoratiu Vultur VCAP_BIT_1); 8047400aaeSHoratiu Vultur if (err) 8147400aaeSHoratiu Vultur goto out; 82*135c2116SHoratiu Vultur } else if (st->l3_proto == ETH_P_IPV6 && 83*135c2116SHoratiu Vultur st->admin->vtype == VCAP_TYPE_IS1) { 84*135c2116SHoratiu Vultur /* Don't set any keys in this case */ 85*135c2116SHoratiu Vultur } else if (st->l3_proto == ETH_P_SNAP && 86*135c2116SHoratiu Vultur st->admin->vtype == VCAP_TYPE_IS1) { 87*135c2116SHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, 88*135c2116SHoratiu Vultur VCAP_KF_ETYPE_LEN_IS, 89*135c2116SHoratiu Vultur VCAP_BIT_0); 90*135c2116SHoratiu Vultur if (err) 91*135c2116SHoratiu Vultur goto out; 92*135c2116SHoratiu Vultur 93*135c2116SHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, 94*135c2116SHoratiu Vultur VCAP_KF_IP_SNAP_IS, 95*135c2116SHoratiu Vultur VCAP_BIT_1); 96*135c2116SHoratiu Vultur if (err) 97*135c2116SHoratiu Vultur goto out; 98*135c2116SHoratiu Vultur } else if (st->admin->vtype == VCAP_TYPE_IS1) { 99*135c2116SHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, 100*135c2116SHoratiu Vultur VCAP_KF_ETYPE_LEN_IS, 101*135c2116SHoratiu Vultur VCAP_BIT_1); 102*135c2116SHoratiu Vultur if (err) 103*135c2116SHoratiu Vultur goto out; 104*135c2116SHoratiu Vultur 105*135c2116SHoratiu Vultur err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE, 106*135c2116SHoratiu Vultur st->l3_proto, ~0); 107*135c2116SHoratiu Vultur if (err) 108*135c2116SHoratiu Vultur goto out; 10947400aaeSHoratiu Vultur } 11047400aaeSHoratiu Vultur } 11147400aaeSHoratiu Vultur if (match.mask->ip_proto) { 11247400aaeSHoratiu Vultur st->l4_proto = match.key->ip_proto; 11347400aaeSHoratiu Vultur 11447400aaeSHoratiu Vultur if (st->l4_proto == IPPROTO_TCP) { 115*135c2116SHoratiu Vultur if (st->admin->vtype == VCAP_TYPE_IS1) { 116*135c2116SHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, 117*135c2116SHoratiu Vultur VCAP_KF_TCP_UDP_IS, 118*135c2116SHoratiu Vultur VCAP_BIT_1); 119*135c2116SHoratiu Vultur if (err) 120*135c2116SHoratiu Vultur goto out; 121*135c2116SHoratiu Vultur } 122*135c2116SHoratiu Vultur 12347400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, 12447400aaeSHoratiu Vultur VCAP_KF_TCP_IS, 12547400aaeSHoratiu Vultur VCAP_BIT_1); 12647400aaeSHoratiu Vultur if (err) 12747400aaeSHoratiu Vultur goto out; 12847400aaeSHoratiu Vultur } else if (st->l4_proto == IPPROTO_UDP) { 129*135c2116SHoratiu Vultur if (st->admin->vtype == VCAP_TYPE_IS1) { 130*135c2116SHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, 131*135c2116SHoratiu Vultur VCAP_KF_TCP_UDP_IS, 132*135c2116SHoratiu Vultur VCAP_BIT_1); 133*135c2116SHoratiu Vultur if (err) 134*135c2116SHoratiu Vultur goto out; 135*135c2116SHoratiu Vultur } 136*135c2116SHoratiu Vultur 13747400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, 13847400aaeSHoratiu Vultur VCAP_KF_TCP_IS, 13947400aaeSHoratiu Vultur VCAP_BIT_0); 14047400aaeSHoratiu Vultur if (err) 14147400aaeSHoratiu Vultur goto out; 14247400aaeSHoratiu Vultur } else { 14347400aaeSHoratiu Vultur err = vcap_rule_add_key_u32(st->vrule, 14447400aaeSHoratiu Vultur VCAP_KF_L3_IP_PROTO, 14547400aaeSHoratiu Vultur st->l4_proto, ~0); 14647400aaeSHoratiu Vultur if (err) 14747400aaeSHoratiu Vultur goto out; 14847400aaeSHoratiu Vultur } 14947400aaeSHoratiu Vultur } 15047400aaeSHoratiu Vultur 15147400aaeSHoratiu Vultur st->used_keys |= BIT(FLOW_DISSECTOR_KEY_BASIC); 15247400aaeSHoratiu Vultur return err; 15347400aaeSHoratiu Vultur out: 15447400aaeSHoratiu Vultur NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error"); 15547400aaeSHoratiu Vultur return err; 15647400aaeSHoratiu Vultur } 15747400aaeSHoratiu Vultur 15847400aaeSHoratiu Vultur static int 159*135c2116SHoratiu Vultur lan966x_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st) 160*135c2116SHoratiu Vultur { 161*135c2116SHoratiu Vultur if (st->admin->vtype != VCAP_TYPE_IS1) { 162*135c2116SHoratiu Vultur NL_SET_ERR_MSG_MOD(st->fco->common.extack, 163*135c2116SHoratiu Vultur "cvlan not supported in this VCAP"); 164*135c2116SHoratiu Vultur return -EINVAL; 165*135c2116SHoratiu Vultur } 166*135c2116SHoratiu Vultur 167*135c2116SHoratiu Vultur return vcap_tc_flower_handler_cvlan_usage(st); 168*135c2116SHoratiu Vultur } 169*135c2116SHoratiu Vultur 170*135c2116SHoratiu Vultur static int 17147400aaeSHoratiu Vultur lan966x_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st) 17247400aaeSHoratiu Vultur { 173*135c2116SHoratiu Vultur enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS; 174*135c2116SHoratiu Vultur enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS; 175*135c2116SHoratiu Vultur 176*135c2116SHoratiu Vultur if (st->admin->vtype == VCAP_TYPE_IS1) { 177*135c2116SHoratiu Vultur vid_key = VCAP_KF_8021Q_VID0; 178*135c2116SHoratiu Vultur pcp_key = VCAP_KF_8021Q_PCP0; 179*135c2116SHoratiu Vultur } 180*135c2116SHoratiu Vultur 181*135c2116SHoratiu Vultur return vcap_tc_flower_handler_vlan_usage(st, vid_key, pcp_key); 18247400aaeSHoratiu Vultur } 18347400aaeSHoratiu Vultur 18447400aaeSHoratiu Vultur static int 18547400aaeSHoratiu Vultur (*lan966x_tc_flower_handlers_usage[])(struct vcap_tc_flower_parse_usage *st) = { 18647400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_ETH_ADDRS] = vcap_tc_flower_handler_ethaddr_usage, 18747400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_IPV4_ADDRS] = vcap_tc_flower_handler_ipv4_usage, 18847400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_IPV6_ADDRS] = vcap_tc_flower_handler_ipv6_usage, 18947400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_CONTROL] = lan966x_tc_flower_handler_control_usage, 19047400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_PORTS] = vcap_tc_flower_handler_portnum_usage, 19147400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_BASIC] = lan966x_tc_flower_handler_basic_usage, 192*135c2116SHoratiu Vultur [FLOW_DISSECTOR_KEY_CVLAN] = lan966x_tc_flower_handler_cvlan_usage, 19347400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_VLAN] = lan966x_tc_flower_handler_vlan_usage, 19447400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_TCP] = vcap_tc_flower_handler_tcp_usage, 19547400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_ARP] = vcap_tc_flower_handler_arp_usage, 19647400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_IP] = vcap_tc_flower_handler_ip_usage, 1973643abd6SHoratiu Vultur }; 1983643abd6SHoratiu Vultur 1993643abd6SHoratiu Vultur static int lan966x_tc_flower_use_dissectors(struct flow_cls_offload *f, 2003643abd6SHoratiu Vultur struct vcap_admin *admin, 2013643abd6SHoratiu Vultur struct vcap_rule *vrule, 2023643abd6SHoratiu Vultur u16 *l3_proto) 2033643abd6SHoratiu Vultur { 20447400aaeSHoratiu Vultur struct vcap_tc_flower_parse_usage state = { 20547400aaeSHoratiu Vultur .fco = f, 2063643abd6SHoratiu Vultur .vrule = vrule, 2073643abd6SHoratiu Vultur .l3_proto = ETH_P_ALL, 208*135c2116SHoratiu Vultur .admin = admin, 2093643abd6SHoratiu Vultur }; 2103643abd6SHoratiu Vultur int err = 0; 2113643abd6SHoratiu Vultur 2123643abd6SHoratiu Vultur state.frule = flow_cls_offload_flow_rule(f); 2133643abd6SHoratiu Vultur for (int i = 0; i < ARRAY_SIZE(lan966x_tc_flower_handlers_usage); ++i) { 2143643abd6SHoratiu Vultur if (!flow_rule_match_key(state.frule, i) || 2153643abd6SHoratiu Vultur !lan966x_tc_flower_handlers_usage[i]) 2163643abd6SHoratiu Vultur continue; 2173643abd6SHoratiu Vultur 2183643abd6SHoratiu Vultur err = lan966x_tc_flower_handlers_usage[i](&state); 2193643abd6SHoratiu Vultur if (err) 2203643abd6SHoratiu Vultur return err; 2213643abd6SHoratiu Vultur } 2223643abd6SHoratiu Vultur 2233643abd6SHoratiu Vultur if (l3_proto) 2243643abd6SHoratiu Vultur *l3_proto = state.l3_proto; 2253643abd6SHoratiu Vultur 2263643abd6SHoratiu Vultur return err; 2273643abd6SHoratiu Vultur } 2283643abd6SHoratiu Vultur 2293643abd6SHoratiu Vultur static int lan966x_tc_flower_action_check(struct vcap_control *vctrl, 230784c3067SSteen Hegelund struct net_device *dev, 231e7e3f514SSteen Hegelund struct flow_cls_offload *fco, 232e7e3f514SSteen Hegelund bool ingress) 2333643abd6SHoratiu Vultur { 2343643abd6SHoratiu Vultur struct flow_rule *rule = flow_cls_offload_flow_rule(fco); 2353643abd6SHoratiu Vultur struct flow_action_entry *actent, *last_actent = NULL; 2363643abd6SHoratiu Vultur struct flow_action *act = &rule->action; 2373643abd6SHoratiu Vultur u64 action_mask = 0; 2383643abd6SHoratiu Vultur int idx; 2393643abd6SHoratiu Vultur 2403643abd6SHoratiu Vultur if (!flow_action_has_entries(act)) { 2413643abd6SHoratiu Vultur NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions"); 2423643abd6SHoratiu Vultur return -EINVAL; 2433643abd6SHoratiu Vultur } 2443643abd6SHoratiu Vultur 2453643abd6SHoratiu Vultur if (!flow_action_basic_hw_stats_check(act, fco->common.extack)) 2463643abd6SHoratiu Vultur return -EOPNOTSUPP; 2473643abd6SHoratiu Vultur 2483643abd6SHoratiu Vultur flow_action_for_each(idx, actent, act) { 2493643abd6SHoratiu Vultur if (action_mask & BIT(actent->id)) { 2503643abd6SHoratiu Vultur NL_SET_ERR_MSG_MOD(fco->common.extack, 2513643abd6SHoratiu Vultur "More actions of the same type"); 2523643abd6SHoratiu Vultur return -EINVAL; 2533643abd6SHoratiu Vultur } 2543643abd6SHoratiu Vultur action_mask |= BIT(actent->id); 2553643abd6SHoratiu Vultur last_actent = actent; /* Save last action for later check */ 2563643abd6SHoratiu Vultur } 2573643abd6SHoratiu Vultur 258784c3067SSteen Hegelund /* Check that last action is a goto 259784c3067SSteen Hegelund * The last chain/lookup does not need to have goto action 260784c3067SSteen Hegelund */ 261784c3067SSteen Hegelund if (last_actent->id == FLOW_ACTION_GOTO) { 262784c3067SSteen Hegelund /* Check if the destination chain is in one of the VCAPs */ 2633643abd6SHoratiu Vultur if (!vcap_is_next_lookup(vctrl, fco->common.chain_index, 2643643abd6SHoratiu Vultur last_actent->chain_index)) { 2653643abd6SHoratiu Vultur NL_SET_ERR_MSG_MOD(fco->common.extack, 2663643abd6SHoratiu Vultur "Invalid goto chain"); 2673643abd6SHoratiu Vultur return -EINVAL; 2683643abd6SHoratiu Vultur } 269e7e3f514SSteen Hegelund } else if (!vcap_is_last_chain(vctrl, fco->common.chain_index, 270e7e3f514SSteen Hegelund ingress)) { 271784c3067SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack, 272784c3067SSteen Hegelund "Last action must be 'goto'"); 273784c3067SSteen Hegelund return -EINVAL; 274784c3067SSteen Hegelund } 2753643abd6SHoratiu Vultur 2763643abd6SHoratiu Vultur /* Catch unsupported combinations of actions */ 2773643abd6SHoratiu Vultur if (action_mask & BIT(FLOW_ACTION_TRAP) && 2783643abd6SHoratiu Vultur action_mask & BIT(FLOW_ACTION_ACCEPT)) { 2793643abd6SHoratiu Vultur NL_SET_ERR_MSG_MOD(fco->common.extack, 2803643abd6SHoratiu Vultur "Cannot combine pass and trap action"); 2813643abd6SHoratiu Vultur return -EOPNOTSUPP; 2823643abd6SHoratiu Vultur } 2833643abd6SHoratiu Vultur 2843643abd6SHoratiu Vultur return 0; 2853643abd6SHoratiu Vultur } 2863643abd6SHoratiu Vultur 287*135c2116SHoratiu Vultur /* Add the actionset that is the default for the VCAP type */ 288*135c2116SHoratiu Vultur static int lan966x_tc_set_actionset(struct vcap_admin *admin, 289*135c2116SHoratiu Vultur struct vcap_rule *vrule) 290*135c2116SHoratiu Vultur { 291*135c2116SHoratiu Vultur enum vcap_actionfield_set aset; 292*135c2116SHoratiu Vultur int err = 0; 293*135c2116SHoratiu Vultur 294*135c2116SHoratiu Vultur switch (admin->vtype) { 295*135c2116SHoratiu Vultur case VCAP_TYPE_IS1: 296*135c2116SHoratiu Vultur aset = VCAP_AFS_S1; 297*135c2116SHoratiu Vultur break; 298*135c2116SHoratiu Vultur case VCAP_TYPE_IS2: 299*135c2116SHoratiu Vultur aset = VCAP_AFS_BASE_TYPE; 300*135c2116SHoratiu Vultur break; 301*135c2116SHoratiu Vultur default: 302*135c2116SHoratiu Vultur return -EINVAL; 303*135c2116SHoratiu Vultur } 304*135c2116SHoratiu Vultur 305*135c2116SHoratiu Vultur /* Do not overwrite any current actionset */ 306*135c2116SHoratiu Vultur if (vrule->actionset == VCAP_AFS_NO_VALUE) 307*135c2116SHoratiu Vultur err = vcap_set_rule_set_actionset(vrule, aset); 308*135c2116SHoratiu Vultur 309*135c2116SHoratiu Vultur return err; 310*135c2116SHoratiu Vultur } 311*135c2116SHoratiu Vultur 3123643abd6SHoratiu Vultur static int lan966x_tc_flower_add(struct lan966x_port *port, 3133643abd6SHoratiu Vultur struct flow_cls_offload *f, 314e7e3f514SSteen Hegelund struct vcap_admin *admin, 315e7e3f514SSteen Hegelund bool ingress) 3163643abd6SHoratiu Vultur { 3173643abd6SHoratiu Vultur struct flow_action_entry *act; 3183643abd6SHoratiu Vultur u16 l3_proto = ETH_P_ALL; 3193643abd6SHoratiu Vultur struct flow_rule *frule; 3203643abd6SHoratiu Vultur struct vcap_rule *vrule; 3213643abd6SHoratiu Vultur int err, idx; 3223643abd6SHoratiu Vultur 323784c3067SSteen Hegelund err = lan966x_tc_flower_action_check(port->lan966x->vcap_ctrl, 324e7e3f514SSteen Hegelund port->dev, f, ingress); 3253643abd6SHoratiu Vultur if (err) 3263643abd6SHoratiu Vultur return err; 3273643abd6SHoratiu Vultur 3283643abd6SHoratiu Vultur vrule = vcap_alloc_rule(port->lan966x->vcap_ctrl, port->dev, 3293643abd6SHoratiu Vultur f->common.chain_index, VCAP_USER_TC, 3303643abd6SHoratiu Vultur f->common.prio, 0); 3313643abd6SHoratiu Vultur if (IS_ERR(vrule)) 3323643abd6SHoratiu Vultur return PTR_ERR(vrule); 3333643abd6SHoratiu Vultur 3343643abd6SHoratiu Vultur vrule->cookie = f->cookie; 3353643abd6SHoratiu Vultur err = lan966x_tc_flower_use_dissectors(f, admin, vrule, &l3_proto); 3363643abd6SHoratiu Vultur if (err) 3373643abd6SHoratiu Vultur goto out; 3383643abd6SHoratiu Vultur 3393643abd6SHoratiu Vultur frule = flow_cls_offload_flow_rule(f); 3403643abd6SHoratiu Vultur 3413643abd6SHoratiu Vultur flow_action_for_each(idx, act, &frule->action) { 3423643abd6SHoratiu Vultur switch (act->id) { 3433643abd6SHoratiu Vultur case FLOW_ACTION_TRAP: 344*135c2116SHoratiu Vultur if (admin->vtype != VCAP_TYPE_IS2) { 345*135c2116SHoratiu Vultur NL_SET_ERR_MSG_MOD(f->common.extack, 346*135c2116SHoratiu Vultur "Trap action not supported in this VCAP"); 347*135c2116SHoratiu Vultur err = -EOPNOTSUPP; 348*135c2116SHoratiu Vultur goto out; 349*135c2116SHoratiu Vultur } 350*135c2116SHoratiu Vultur 3513643abd6SHoratiu Vultur err = vcap_rule_add_action_bit(vrule, 3523643abd6SHoratiu Vultur VCAP_AF_CPU_COPY_ENA, 3533643abd6SHoratiu Vultur VCAP_BIT_1); 3543643abd6SHoratiu Vultur err |= vcap_rule_add_action_u32(vrule, 3553643abd6SHoratiu Vultur VCAP_AF_CPU_QUEUE_NUM, 3563643abd6SHoratiu Vultur 0); 3573643abd6SHoratiu Vultur err |= vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE, 3583643abd6SHoratiu Vultur LAN966X_PMM_REPLACE); 3593643abd6SHoratiu Vultur if (err) 3603643abd6SHoratiu Vultur goto out; 3613643abd6SHoratiu Vultur 3623643abd6SHoratiu Vultur break; 3633643abd6SHoratiu Vultur case FLOW_ACTION_GOTO: 364*135c2116SHoratiu Vultur err = lan966x_tc_set_actionset(admin, vrule); 365*135c2116SHoratiu Vultur if (err) 366*135c2116SHoratiu Vultur goto out; 367*135c2116SHoratiu Vultur 3683643abd6SHoratiu Vultur break; 3693643abd6SHoratiu Vultur default: 3703643abd6SHoratiu Vultur NL_SET_ERR_MSG_MOD(f->common.extack, 3713643abd6SHoratiu Vultur "Unsupported TC action"); 3723643abd6SHoratiu Vultur err = -EOPNOTSUPP; 3733643abd6SHoratiu Vultur goto out; 3743643abd6SHoratiu Vultur } 3753643abd6SHoratiu Vultur } 3763643abd6SHoratiu Vultur 3773643abd6SHoratiu Vultur err = vcap_val_rule(vrule, l3_proto); 3783643abd6SHoratiu Vultur if (err) { 3793643abd6SHoratiu Vultur vcap_set_tc_exterr(f, vrule); 3803643abd6SHoratiu Vultur goto out; 3813643abd6SHoratiu Vultur } 3823643abd6SHoratiu Vultur 3833643abd6SHoratiu Vultur err = vcap_add_rule(vrule); 3843643abd6SHoratiu Vultur if (err) 3853643abd6SHoratiu Vultur NL_SET_ERR_MSG_MOD(f->common.extack, 3863643abd6SHoratiu Vultur "Could not add the filter"); 3873643abd6SHoratiu Vultur out: 3883643abd6SHoratiu Vultur vcap_free_rule(vrule); 3893643abd6SHoratiu Vultur return err; 3903643abd6SHoratiu Vultur } 3913643abd6SHoratiu Vultur 3923643abd6SHoratiu Vultur static int lan966x_tc_flower_del(struct lan966x_port *port, 3933643abd6SHoratiu Vultur struct flow_cls_offload *f, 3943643abd6SHoratiu Vultur struct vcap_admin *admin) 3953643abd6SHoratiu Vultur { 3963643abd6SHoratiu Vultur struct vcap_control *vctrl; 3973643abd6SHoratiu Vultur int err = -ENOENT, rule_id; 3983643abd6SHoratiu Vultur 3993643abd6SHoratiu Vultur vctrl = port->lan966x->vcap_ctrl; 4003643abd6SHoratiu Vultur while (true) { 4013643abd6SHoratiu Vultur rule_id = vcap_lookup_rule_by_cookie(vctrl, f->cookie); 4023643abd6SHoratiu Vultur if (rule_id <= 0) 4033643abd6SHoratiu Vultur break; 4043643abd6SHoratiu Vultur 4053643abd6SHoratiu Vultur err = vcap_del_rule(vctrl, port->dev, rule_id); 4063643abd6SHoratiu Vultur if (err) { 4073643abd6SHoratiu Vultur NL_SET_ERR_MSG_MOD(f->common.extack, 4083643abd6SHoratiu Vultur "Cannot delete rule"); 4093643abd6SHoratiu Vultur break; 4103643abd6SHoratiu Vultur } 4113643abd6SHoratiu Vultur } 4123643abd6SHoratiu Vultur 4133643abd6SHoratiu Vultur return err; 4143643abd6SHoratiu Vultur } 4153643abd6SHoratiu Vultur 4169ed138ffSHoratiu Vultur static int lan966x_tc_flower_stats(struct lan966x_port *port, 4179ed138ffSHoratiu Vultur struct flow_cls_offload *f, 4189ed138ffSHoratiu Vultur struct vcap_admin *admin) 4199ed138ffSHoratiu Vultur { 4209ed138ffSHoratiu Vultur struct vcap_counter count = {}; 4219ed138ffSHoratiu Vultur int err; 4229ed138ffSHoratiu Vultur 4239ed138ffSHoratiu Vultur err = vcap_get_rule_count_by_cookie(port->lan966x->vcap_ctrl, 4249ed138ffSHoratiu Vultur &count, f->cookie); 4259ed138ffSHoratiu Vultur if (err) 4269ed138ffSHoratiu Vultur return err; 4279ed138ffSHoratiu Vultur 4289ed138ffSHoratiu Vultur flow_stats_update(&f->stats, 0x0, count.value, 0, 0, 4299ed138ffSHoratiu Vultur FLOW_ACTION_HW_STATS_IMMEDIATE); 4309ed138ffSHoratiu Vultur 4319ed138ffSHoratiu Vultur return err; 4329ed138ffSHoratiu Vultur } 4339ed138ffSHoratiu Vultur 4343643abd6SHoratiu Vultur int lan966x_tc_flower(struct lan966x_port *port, 435e7e3f514SSteen Hegelund struct flow_cls_offload *f, 436e7e3f514SSteen Hegelund bool ingress) 4373643abd6SHoratiu Vultur { 4383643abd6SHoratiu Vultur struct vcap_admin *admin; 4393643abd6SHoratiu Vultur 4403643abd6SHoratiu Vultur admin = vcap_find_admin(port->lan966x->vcap_ctrl, 4413643abd6SHoratiu Vultur f->common.chain_index); 4423643abd6SHoratiu Vultur if (!admin) { 4433643abd6SHoratiu Vultur NL_SET_ERR_MSG_MOD(f->common.extack, "Invalid chain"); 4443643abd6SHoratiu Vultur return -EINVAL; 4453643abd6SHoratiu Vultur } 4463643abd6SHoratiu Vultur 4473643abd6SHoratiu Vultur switch (f->command) { 4483643abd6SHoratiu Vultur case FLOW_CLS_REPLACE: 449e7e3f514SSteen Hegelund return lan966x_tc_flower_add(port, f, admin, ingress); 4503643abd6SHoratiu Vultur case FLOW_CLS_DESTROY: 4513643abd6SHoratiu Vultur return lan966x_tc_flower_del(port, f, admin); 4529ed138ffSHoratiu Vultur case FLOW_CLS_STATS: 4539ed138ffSHoratiu Vultur return lan966x_tc_flower_stats(port, f, admin); 4543643abd6SHoratiu Vultur default: 4553643abd6SHoratiu Vultur return -EOPNOTSUPP; 4563643abd6SHoratiu Vultur } 4573643abd6SHoratiu Vultur 4583643abd6SHoratiu Vultur return 0; 4593643abd6SHoratiu Vultur } 460