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
885f05000SHoratiu Vultur #define LAN966X_FORCE_UNTAGED 3
985f05000SHoratiu Vultur
lan966x_tc_is_known_etype(struct vcap_tc_flower_parse_usage * st,u16 etype)1044d706fdSHoratiu Vultur static bool lan966x_tc_is_known_etype(struct vcap_tc_flower_parse_usage *st,
1144d706fdSHoratiu Vultur u16 etype)
123643abd6SHoratiu Vultur {
1344d706fdSHoratiu Vultur switch (st->admin->vtype) {
1444d706fdSHoratiu Vultur case VCAP_TYPE_IS1:
1547400aaeSHoratiu Vultur switch (etype) {
1647400aaeSHoratiu Vultur case ETH_P_ALL:
1747400aaeSHoratiu Vultur case ETH_P_ARP:
1847400aaeSHoratiu Vultur case ETH_P_IP:
1947400aaeSHoratiu Vultur case ETH_P_IPV6:
2047400aaeSHoratiu Vultur return true;
2147400aaeSHoratiu Vultur }
2244d706fdSHoratiu Vultur break;
2344d706fdSHoratiu Vultur case VCAP_TYPE_IS2:
2444d706fdSHoratiu Vultur switch (etype) {
2544d706fdSHoratiu Vultur case ETH_P_ALL:
2644d706fdSHoratiu Vultur case ETH_P_ARP:
2744d706fdSHoratiu Vultur case ETH_P_IP:
2844d706fdSHoratiu Vultur case ETH_P_IPV6:
2944d706fdSHoratiu Vultur case ETH_P_SNAP:
3044d706fdSHoratiu Vultur case ETH_P_802_2:
3144d706fdSHoratiu Vultur return true;
3244d706fdSHoratiu Vultur }
3344d706fdSHoratiu Vultur break;
3485f05000SHoratiu Vultur case VCAP_TYPE_ES0:
3585f05000SHoratiu Vultur return true;
3644d706fdSHoratiu Vultur default:
3744d706fdSHoratiu Vultur NL_SET_ERR_MSG_MOD(st->fco->common.extack,
3844d706fdSHoratiu Vultur "VCAP type not supported");
3944d706fdSHoratiu Vultur return false;
4044d706fdSHoratiu Vultur }
4147400aaeSHoratiu Vultur
4247400aaeSHoratiu Vultur return false;
4347400aaeSHoratiu Vultur }
4447400aaeSHoratiu Vultur
4547400aaeSHoratiu Vultur static int
lan966x_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage * st)4647400aaeSHoratiu Vultur lan966x_tc_flower_handler_control_usage(struct vcap_tc_flower_parse_usage *st)
4747400aaeSHoratiu Vultur {
4847400aaeSHoratiu Vultur struct flow_match_control match;
493643abd6SHoratiu Vultur int err = 0;
503643abd6SHoratiu Vultur
5147400aaeSHoratiu Vultur flow_rule_match_control(st->frule, &match);
5247400aaeSHoratiu Vultur if (match.mask->flags & FLOW_DIS_IS_FRAGMENT) {
5347400aaeSHoratiu Vultur if (match.key->flags & FLOW_DIS_IS_FRAGMENT)
5447400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule,
5547400aaeSHoratiu Vultur VCAP_KF_L3_FRAGMENT,
5647400aaeSHoratiu Vultur VCAP_BIT_1);
5747400aaeSHoratiu Vultur else
5847400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule,
5947400aaeSHoratiu Vultur VCAP_KF_L3_FRAGMENT,
6047400aaeSHoratiu Vultur VCAP_BIT_0);
613643abd6SHoratiu Vultur if (err)
623643abd6SHoratiu Vultur goto out;
633643abd6SHoratiu Vultur }
643643abd6SHoratiu Vultur
6547400aaeSHoratiu Vultur if (match.mask->flags & FLOW_DIS_FIRST_FRAG) {
6647400aaeSHoratiu Vultur if (match.key->flags & FLOW_DIS_FIRST_FRAG)
6747400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule,
6847400aaeSHoratiu Vultur VCAP_KF_L3_FRAG_OFS_GT0,
6947400aaeSHoratiu Vultur VCAP_BIT_0);
7047400aaeSHoratiu Vultur else
7147400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule,
7247400aaeSHoratiu Vultur VCAP_KF_L3_FRAG_OFS_GT0,
7347400aaeSHoratiu Vultur VCAP_BIT_1);
743643abd6SHoratiu Vultur if (err)
753643abd6SHoratiu Vultur goto out;
763643abd6SHoratiu Vultur }
773643abd6SHoratiu Vultur
78*2b3082c6SRatheesh Kannoth st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_CONTROL);
793643abd6SHoratiu Vultur
803643abd6SHoratiu Vultur return err;
813643abd6SHoratiu Vultur
823643abd6SHoratiu Vultur out:
8347400aaeSHoratiu Vultur NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_frag parse error");
843643abd6SHoratiu Vultur return err;
853643abd6SHoratiu Vultur }
863643abd6SHoratiu Vultur
873643abd6SHoratiu Vultur static int
lan966x_tc_flower_handler_basic_usage(struct vcap_tc_flower_parse_usage * st)8847400aaeSHoratiu Vultur lan966x_tc_flower_handler_basic_usage(struct vcap_tc_flower_parse_usage *st)
8947400aaeSHoratiu Vultur {
9047400aaeSHoratiu Vultur struct flow_match_basic match;
9147400aaeSHoratiu Vultur int err = 0;
9247400aaeSHoratiu Vultur
9347400aaeSHoratiu Vultur flow_rule_match_basic(st->frule, &match);
9447400aaeSHoratiu Vultur if (match.mask->n_proto) {
9547400aaeSHoratiu Vultur st->l3_proto = be16_to_cpu(match.key->n_proto);
9644d706fdSHoratiu Vultur if (!lan966x_tc_is_known_etype(st, st->l3_proto)) {
9747400aaeSHoratiu Vultur err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE,
9847400aaeSHoratiu Vultur st->l3_proto, ~0);
9947400aaeSHoratiu Vultur if (err)
10047400aaeSHoratiu Vultur goto out;
10147400aaeSHoratiu Vultur } else if (st->l3_proto == ETH_P_IP) {
10247400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule, VCAP_KF_IP4_IS,
10347400aaeSHoratiu Vultur VCAP_BIT_1);
10447400aaeSHoratiu Vultur if (err)
10547400aaeSHoratiu Vultur goto out;
106135c2116SHoratiu Vultur } else if (st->l3_proto == ETH_P_IPV6 &&
107135c2116SHoratiu Vultur st->admin->vtype == VCAP_TYPE_IS1) {
108135c2116SHoratiu Vultur /* Don't set any keys in this case */
109135c2116SHoratiu Vultur } else if (st->l3_proto == ETH_P_SNAP &&
110135c2116SHoratiu Vultur st->admin->vtype == VCAP_TYPE_IS1) {
111135c2116SHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule,
112135c2116SHoratiu Vultur VCAP_KF_ETYPE_LEN_IS,
113135c2116SHoratiu Vultur VCAP_BIT_0);
114135c2116SHoratiu Vultur if (err)
115135c2116SHoratiu Vultur goto out;
116135c2116SHoratiu Vultur
117135c2116SHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule,
118135c2116SHoratiu Vultur VCAP_KF_IP_SNAP_IS,
119135c2116SHoratiu Vultur VCAP_BIT_1);
120135c2116SHoratiu Vultur if (err)
121135c2116SHoratiu Vultur goto out;
122135c2116SHoratiu Vultur } else if (st->admin->vtype == VCAP_TYPE_IS1) {
123135c2116SHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule,
124135c2116SHoratiu Vultur VCAP_KF_ETYPE_LEN_IS,
125135c2116SHoratiu Vultur VCAP_BIT_1);
126135c2116SHoratiu Vultur if (err)
127135c2116SHoratiu Vultur goto out;
128135c2116SHoratiu Vultur
129135c2116SHoratiu Vultur err = vcap_rule_add_key_u32(st->vrule, VCAP_KF_ETYPE,
130135c2116SHoratiu Vultur st->l3_proto, ~0);
131135c2116SHoratiu Vultur if (err)
132135c2116SHoratiu Vultur goto out;
13347400aaeSHoratiu Vultur }
13447400aaeSHoratiu Vultur }
13547400aaeSHoratiu Vultur if (match.mask->ip_proto) {
13647400aaeSHoratiu Vultur st->l4_proto = match.key->ip_proto;
13747400aaeSHoratiu Vultur
13847400aaeSHoratiu Vultur if (st->l4_proto == IPPROTO_TCP) {
139135c2116SHoratiu Vultur if (st->admin->vtype == VCAP_TYPE_IS1) {
140135c2116SHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule,
141135c2116SHoratiu Vultur VCAP_KF_TCP_UDP_IS,
142135c2116SHoratiu Vultur VCAP_BIT_1);
143135c2116SHoratiu Vultur if (err)
144135c2116SHoratiu Vultur goto out;
145135c2116SHoratiu Vultur }
146135c2116SHoratiu Vultur
14747400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule,
14847400aaeSHoratiu Vultur VCAP_KF_TCP_IS,
14947400aaeSHoratiu Vultur VCAP_BIT_1);
15047400aaeSHoratiu Vultur if (err)
15147400aaeSHoratiu Vultur goto out;
15247400aaeSHoratiu Vultur } else if (st->l4_proto == IPPROTO_UDP) {
153135c2116SHoratiu Vultur if (st->admin->vtype == VCAP_TYPE_IS1) {
154135c2116SHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule,
155135c2116SHoratiu Vultur VCAP_KF_TCP_UDP_IS,
156135c2116SHoratiu Vultur VCAP_BIT_1);
157135c2116SHoratiu Vultur if (err)
158135c2116SHoratiu Vultur goto out;
159135c2116SHoratiu Vultur }
160135c2116SHoratiu Vultur
16147400aaeSHoratiu Vultur err = vcap_rule_add_key_bit(st->vrule,
16247400aaeSHoratiu Vultur VCAP_KF_TCP_IS,
16347400aaeSHoratiu Vultur VCAP_BIT_0);
16447400aaeSHoratiu Vultur if (err)
16547400aaeSHoratiu Vultur goto out;
16647400aaeSHoratiu Vultur } else {
16747400aaeSHoratiu Vultur err = vcap_rule_add_key_u32(st->vrule,
16847400aaeSHoratiu Vultur VCAP_KF_L3_IP_PROTO,
16947400aaeSHoratiu Vultur st->l4_proto, ~0);
17047400aaeSHoratiu Vultur if (err)
17147400aaeSHoratiu Vultur goto out;
17247400aaeSHoratiu Vultur }
17347400aaeSHoratiu Vultur }
17447400aaeSHoratiu Vultur
175*2b3082c6SRatheesh Kannoth st->used_keys |= BIT_ULL(FLOW_DISSECTOR_KEY_BASIC);
17647400aaeSHoratiu Vultur return err;
17747400aaeSHoratiu Vultur out:
17847400aaeSHoratiu Vultur NL_SET_ERR_MSG_MOD(st->fco->common.extack, "ip_proto parse error");
17947400aaeSHoratiu Vultur return err;
18047400aaeSHoratiu Vultur }
18147400aaeSHoratiu Vultur
18247400aaeSHoratiu Vultur static int
lan966x_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage * st)183135c2116SHoratiu Vultur lan966x_tc_flower_handler_cvlan_usage(struct vcap_tc_flower_parse_usage *st)
184135c2116SHoratiu Vultur {
185135c2116SHoratiu Vultur if (st->admin->vtype != VCAP_TYPE_IS1) {
186135c2116SHoratiu Vultur NL_SET_ERR_MSG_MOD(st->fco->common.extack,
187135c2116SHoratiu Vultur "cvlan not supported in this VCAP");
188135c2116SHoratiu Vultur return -EINVAL;
189135c2116SHoratiu Vultur }
190135c2116SHoratiu Vultur
191135c2116SHoratiu Vultur return vcap_tc_flower_handler_cvlan_usage(st);
192135c2116SHoratiu Vultur }
193135c2116SHoratiu Vultur
194135c2116SHoratiu Vultur static int
lan966x_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage * st)19547400aaeSHoratiu Vultur lan966x_tc_flower_handler_vlan_usage(struct vcap_tc_flower_parse_usage *st)
19647400aaeSHoratiu Vultur {
197135c2116SHoratiu Vultur enum vcap_key_field vid_key = VCAP_KF_8021Q_VID_CLS;
198135c2116SHoratiu Vultur enum vcap_key_field pcp_key = VCAP_KF_8021Q_PCP_CLS;
199135c2116SHoratiu Vultur
200135c2116SHoratiu Vultur if (st->admin->vtype == VCAP_TYPE_IS1) {
201135c2116SHoratiu Vultur vid_key = VCAP_KF_8021Q_VID0;
202135c2116SHoratiu Vultur pcp_key = VCAP_KF_8021Q_PCP0;
203135c2116SHoratiu Vultur }
204135c2116SHoratiu Vultur
205135c2116SHoratiu Vultur return vcap_tc_flower_handler_vlan_usage(st, vid_key, pcp_key);
20647400aaeSHoratiu Vultur }
20747400aaeSHoratiu Vultur
20847400aaeSHoratiu Vultur static int
20947400aaeSHoratiu Vultur (*lan966x_tc_flower_handlers_usage[])(struct vcap_tc_flower_parse_usage *st) = {
21047400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_ETH_ADDRS] = vcap_tc_flower_handler_ethaddr_usage,
21147400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_IPV4_ADDRS] = vcap_tc_flower_handler_ipv4_usage,
21247400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_IPV6_ADDRS] = vcap_tc_flower_handler_ipv6_usage,
21347400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_CONTROL] = lan966x_tc_flower_handler_control_usage,
21447400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_PORTS] = vcap_tc_flower_handler_portnum_usage,
21547400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_BASIC] = lan966x_tc_flower_handler_basic_usage,
216135c2116SHoratiu Vultur [FLOW_DISSECTOR_KEY_CVLAN] = lan966x_tc_flower_handler_cvlan_usage,
21747400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_VLAN] = lan966x_tc_flower_handler_vlan_usage,
21847400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_TCP] = vcap_tc_flower_handler_tcp_usage,
21947400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_ARP] = vcap_tc_flower_handler_arp_usage,
22047400aaeSHoratiu Vultur [FLOW_DISSECTOR_KEY_IP] = vcap_tc_flower_handler_ip_usage,
2213643abd6SHoratiu Vultur };
2223643abd6SHoratiu Vultur
lan966x_tc_flower_use_dissectors(struct flow_cls_offload * f,struct vcap_admin * admin,struct vcap_rule * vrule,u16 * l3_proto)2233643abd6SHoratiu Vultur static int lan966x_tc_flower_use_dissectors(struct flow_cls_offload *f,
2243643abd6SHoratiu Vultur struct vcap_admin *admin,
2253643abd6SHoratiu Vultur struct vcap_rule *vrule,
2263643abd6SHoratiu Vultur u16 *l3_proto)
2273643abd6SHoratiu Vultur {
22847400aaeSHoratiu Vultur struct vcap_tc_flower_parse_usage state = {
22947400aaeSHoratiu Vultur .fco = f,
2303643abd6SHoratiu Vultur .vrule = vrule,
2313643abd6SHoratiu Vultur .l3_proto = ETH_P_ALL,
232135c2116SHoratiu Vultur .admin = admin,
2333643abd6SHoratiu Vultur };
2343643abd6SHoratiu Vultur int err = 0;
2353643abd6SHoratiu Vultur
2363643abd6SHoratiu Vultur state.frule = flow_cls_offload_flow_rule(f);
2373643abd6SHoratiu Vultur for (int i = 0; i < ARRAY_SIZE(lan966x_tc_flower_handlers_usage); ++i) {
2383643abd6SHoratiu Vultur if (!flow_rule_match_key(state.frule, i) ||
2393643abd6SHoratiu Vultur !lan966x_tc_flower_handlers_usage[i])
2403643abd6SHoratiu Vultur continue;
2413643abd6SHoratiu Vultur
2423643abd6SHoratiu Vultur err = lan966x_tc_flower_handlers_usage[i](&state);
2433643abd6SHoratiu Vultur if (err)
2443643abd6SHoratiu Vultur return err;
2453643abd6SHoratiu Vultur }
2463643abd6SHoratiu Vultur
2473643abd6SHoratiu Vultur if (l3_proto)
2483643abd6SHoratiu Vultur *l3_proto = state.l3_proto;
2493643abd6SHoratiu Vultur
2503643abd6SHoratiu Vultur return err;
2513643abd6SHoratiu Vultur }
2523643abd6SHoratiu Vultur
lan966x_tc_flower_action_check(struct vcap_control * vctrl,struct net_device * dev,struct flow_cls_offload * fco,bool ingress)2533643abd6SHoratiu Vultur static int lan966x_tc_flower_action_check(struct vcap_control *vctrl,
254784c3067SSteen Hegelund struct net_device *dev,
255e7e3f514SSteen Hegelund struct flow_cls_offload *fco,
256e7e3f514SSteen Hegelund bool ingress)
2573643abd6SHoratiu Vultur {
2583643abd6SHoratiu Vultur struct flow_rule *rule = flow_cls_offload_flow_rule(fco);
2593643abd6SHoratiu Vultur struct flow_action_entry *actent, *last_actent = NULL;
2603643abd6SHoratiu Vultur struct flow_action *act = &rule->action;
2613643abd6SHoratiu Vultur u64 action_mask = 0;
2623643abd6SHoratiu Vultur int idx;
2633643abd6SHoratiu Vultur
2643643abd6SHoratiu Vultur if (!flow_action_has_entries(act)) {
2653643abd6SHoratiu Vultur NL_SET_ERR_MSG_MOD(fco->common.extack, "No actions");
2663643abd6SHoratiu Vultur return -EINVAL;
2673643abd6SHoratiu Vultur }
2683643abd6SHoratiu Vultur
2693643abd6SHoratiu Vultur if (!flow_action_basic_hw_stats_check(act, fco->common.extack))
2703643abd6SHoratiu Vultur return -EOPNOTSUPP;
2713643abd6SHoratiu Vultur
2723643abd6SHoratiu Vultur flow_action_for_each(idx, actent, act) {
2733643abd6SHoratiu Vultur if (action_mask & BIT(actent->id)) {
2743643abd6SHoratiu Vultur NL_SET_ERR_MSG_MOD(fco->common.extack,
2753643abd6SHoratiu Vultur "More actions of the same type");
2763643abd6SHoratiu Vultur return -EINVAL;
2773643abd6SHoratiu Vultur }
2783643abd6SHoratiu Vultur action_mask |= BIT(actent->id);
2793643abd6SHoratiu Vultur last_actent = actent; /* Save last action for later check */
2803643abd6SHoratiu Vultur }
2813643abd6SHoratiu Vultur
282784c3067SSteen Hegelund /* Check that last action is a goto
283784c3067SSteen Hegelund * The last chain/lookup does not need to have goto action
284784c3067SSteen Hegelund */
285784c3067SSteen Hegelund if (last_actent->id == FLOW_ACTION_GOTO) {
286784c3067SSteen Hegelund /* Check if the destination chain is in one of the VCAPs */
2873643abd6SHoratiu Vultur if (!vcap_is_next_lookup(vctrl, fco->common.chain_index,
2883643abd6SHoratiu Vultur last_actent->chain_index)) {
2893643abd6SHoratiu Vultur NL_SET_ERR_MSG_MOD(fco->common.extack,
2903643abd6SHoratiu Vultur "Invalid goto chain");
2913643abd6SHoratiu Vultur return -EINVAL;
2923643abd6SHoratiu Vultur }
293e7e3f514SSteen Hegelund } else if (!vcap_is_last_chain(vctrl, fco->common.chain_index,
294e7e3f514SSteen Hegelund ingress)) {
295784c3067SSteen Hegelund NL_SET_ERR_MSG_MOD(fco->common.extack,
296784c3067SSteen Hegelund "Last action must be 'goto'");
297784c3067SSteen Hegelund return -EINVAL;
298784c3067SSteen Hegelund }
2993643abd6SHoratiu Vultur
3003643abd6SHoratiu Vultur /* Catch unsupported combinations of actions */
3013643abd6SHoratiu Vultur if (action_mask & BIT(FLOW_ACTION_TRAP) &&
3023643abd6SHoratiu Vultur action_mask & BIT(FLOW_ACTION_ACCEPT)) {
3033643abd6SHoratiu Vultur NL_SET_ERR_MSG_MOD(fco->common.extack,
3043643abd6SHoratiu Vultur "Cannot combine pass and trap action");
3053643abd6SHoratiu Vultur return -EOPNOTSUPP;
3063643abd6SHoratiu Vultur }
3073643abd6SHoratiu Vultur
3083643abd6SHoratiu Vultur return 0;
3093643abd6SHoratiu Vultur }
3103643abd6SHoratiu Vultur
311135c2116SHoratiu Vultur /* Add the actionset that is the default for the VCAP type */
lan966x_tc_set_actionset(struct vcap_admin * admin,struct vcap_rule * vrule)312135c2116SHoratiu Vultur static int lan966x_tc_set_actionset(struct vcap_admin *admin,
313135c2116SHoratiu Vultur struct vcap_rule *vrule)
314135c2116SHoratiu Vultur {
315135c2116SHoratiu Vultur enum vcap_actionfield_set aset;
316135c2116SHoratiu Vultur int err = 0;
317135c2116SHoratiu Vultur
318135c2116SHoratiu Vultur switch (admin->vtype) {
319135c2116SHoratiu Vultur case VCAP_TYPE_IS1:
320135c2116SHoratiu Vultur aset = VCAP_AFS_S1;
321135c2116SHoratiu Vultur break;
322135c2116SHoratiu Vultur case VCAP_TYPE_IS2:
323135c2116SHoratiu Vultur aset = VCAP_AFS_BASE_TYPE;
324135c2116SHoratiu Vultur break;
32585f05000SHoratiu Vultur case VCAP_TYPE_ES0:
32685f05000SHoratiu Vultur aset = VCAP_AFS_VID;
32785f05000SHoratiu Vultur break;
328135c2116SHoratiu Vultur default:
329135c2116SHoratiu Vultur return -EINVAL;
330135c2116SHoratiu Vultur }
331135c2116SHoratiu Vultur
332135c2116SHoratiu Vultur /* Do not overwrite any current actionset */
333135c2116SHoratiu Vultur if (vrule->actionset == VCAP_AFS_NO_VALUE)
334135c2116SHoratiu Vultur err = vcap_set_rule_set_actionset(vrule, aset);
335135c2116SHoratiu Vultur
336135c2116SHoratiu Vultur return err;
337135c2116SHoratiu Vultur }
338135c2116SHoratiu Vultur
lan966x_tc_add_rule_link_target(struct vcap_admin * admin,struct vcap_rule * vrule,int target_cid)339b3762a9dSHoratiu Vultur static int lan966x_tc_add_rule_link_target(struct vcap_admin *admin,
340b3762a9dSHoratiu Vultur struct vcap_rule *vrule,
341b3762a9dSHoratiu Vultur int target_cid)
342b3762a9dSHoratiu Vultur {
343b3762a9dSHoratiu Vultur int link_val = target_cid % VCAP_CID_LOOKUP_SIZE;
344b3762a9dSHoratiu Vultur int err;
345b3762a9dSHoratiu Vultur
346b3762a9dSHoratiu Vultur if (!link_val)
347b3762a9dSHoratiu Vultur return 0;
348b3762a9dSHoratiu Vultur
349b3762a9dSHoratiu Vultur switch (admin->vtype) {
350b3762a9dSHoratiu Vultur case VCAP_TYPE_IS1:
351b3762a9dSHoratiu Vultur /* Choose IS1 specific NXT_IDX key (for chaining rules from IS1) */
352b3762a9dSHoratiu Vultur err = vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX_SEL,
353b3762a9dSHoratiu Vultur 1, ~0);
354b3762a9dSHoratiu Vultur if (err)
355b3762a9dSHoratiu Vultur return err;
356b3762a9dSHoratiu Vultur
357b3762a9dSHoratiu Vultur return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_GEN_IDX,
358b3762a9dSHoratiu Vultur link_val, ~0);
359b3762a9dSHoratiu Vultur case VCAP_TYPE_IS2:
360b3762a9dSHoratiu Vultur /* Add IS2 specific PAG key (for chaining rules from IS1) */
361b3762a9dSHoratiu Vultur return vcap_rule_add_key_u32(vrule, VCAP_KF_LOOKUP_PAG,
362b3762a9dSHoratiu Vultur link_val, ~0);
36385f05000SHoratiu Vultur case VCAP_TYPE_ES0:
36485f05000SHoratiu Vultur /* Add ES0 specific ISDX key (for chaining rules from IS1) */
36585f05000SHoratiu Vultur return vcap_rule_add_key_u32(vrule, VCAP_KF_ISDX_CLS,
36685f05000SHoratiu Vultur link_val, ~0);
367b3762a9dSHoratiu Vultur default:
368b3762a9dSHoratiu Vultur break;
369b3762a9dSHoratiu Vultur }
370b3762a9dSHoratiu Vultur return 0;
371b3762a9dSHoratiu Vultur }
372b3762a9dSHoratiu Vultur
lan966x_tc_add_rule_link(struct vcap_control * vctrl,struct vcap_admin * admin,struct vcap_rule * vrule,struct flow_cls_offload * f,int to_cid)373b3762a9dSHoratiu Vultur static int lan966x_tc_add_rule_link(struct vcap_control *vctrl,
374b3762a9dSHoratiu Vultur struct vcap_admin *admin,
375b3762a9dSHoratiu Vultur struct vcap_rule *vrule,
376b3762a9dSHoratiu Vultur struct flow_cls_offload *f,
377b3762a9dSHoratiu Vultur int to_cid)
378b3762a9dSHoratiu Vultur {
379b3762a9dSHoratiu Vultur struct vcap_admin *to_admin = vcap_find_admin(vctrl, to_cid);
380b3762a9dSHoratiu Vultur int diff, err = 0;
381b3762a9dSHoratiu Vultur
382b3762a9dSHoratiu Vultur if (!to_admin) {
383b3762a9dSHoratiu Vultur NL_SET_ERR_MSG_MOD(f->common.extack,
384b3762a9dSHoratiu Vultur "Unknown destination chain");
385b3762a9dSHoratiu Vultur return -EINVAL;
386b3762a9dSHoratiu Vultur }
387b3762a9dSHoratiu Vultur
388b3762a9dSHoratiu Vultur diff = vcap_chain_offset(vctrl, f->common.chain_index, to_cid);
389b3762a9dSHoratiu Vultur if (!diff)
390b3762a9dSHoratiu Vultur return 0;
391b3762a9dSHoratiu Vultur
392b3762a9dSHoratiu Vultur /* Between IS1 and IS2 the PAG value is used */
393b3762a9dSHoratiu Vultur if (admin->vtype == VCAP_TYPE_IS1 && to_admin->vtype == VCAP_TYPE_IS2) {
394b3762a9dSHoratiu Vultur /* This works for IS1->IS2 */
395b3762a9dSHoratiu Vultur err = vcap_rule_add_action_u32(vrule, VCAP_AF_PAG_VAL, diff);
396b3762a9dSHoratiu Vultur if (err)
397b3762a9dSHoratiu Vultur return err;
398b3762a9dSHoratiu Vultur
399b3762a9dSHoratiu Vultur err = vcap_rule_add_action_u32(vrule, VCAP_AF_PAG_OVERRIDE_MASK,
400b3762a9dSHoratiu Vultur 0xff);
401b3762a9dSHoratiu Vultur if (err)
402b3762a9dSHoratiu Vultur return err;
40385f05000SHoratiu Vultur } else if (admin->vtype == VCAP_TYPE_IS1 &&
40485f05000SHoratiu Vultur to_admin->vtype == VCAP_TYPE_ES0) {
40585f05000SHoratiu Vultur /* This works for IS1->ES0 */
40685f05000SHoratiu Vultur err = vcap_rule_add_action_u32(vrule, VCAP_AF_ISDX_ADD_VAL,
40785f05000SHoratiu Vultur diff);
40885f05000SHoratiu Vultur if (err)
40985f05000SHoratiu Vultur return err;
41085f05000SHoratiu Vultur
41185f05000SHoratiu Vultur err = vcap_rule_add_action_bit(vrule, VCAP_AF_ISDX_REPLACE_ENA,
41285f05000SHoratiu Vultur VCAP_BIT_1);
41385f05000SHoratiu Vultur if (err)
41485f05000SHoratiu Vultur return err;
415b3762a9dSHoratiu Vultur } else {
416b3762a9dSHoratiu Vultur NL_SET_ERR_MSG_MOD(f->common.extack,
417b3762a9dSHoratiu Vultur "Unsupported chain destination");
418b3762a9dSHoratiu Vultur return -EOPNOTSUPP;
419b3762a9dSHoratiu Vultur }
420b3762a9dSHoratiu Vultur
421b3762a9dSHoratiu Vultur return err;
422b3762a9dSHoratiu Vultur }
423b3762a9dSHoratiu Vultur
lan966x_tc_add_rule_counter(struct vcap_admin * admin,struct vcap_rule * vrule)42485f05000SHoratiu Vultur static int lan966x_tc_add_rule_counter(struct vcap_admin *admin,
42585f05000SHoratiu Vultur struct vcap_rule *vrule)
42685f05000SHoratiu Vultur {
42785f05000SHoratiu Vultur int err = 0;
42885f05000SHoratiu Vultur
42985f05000SHoratiu Vultur switch (admin->vtype) {
43085f05000SHoratiu Vultur case VCAP_TYPE_ES0:
43185f05000SHoratiu Vultur err = vcap_rule_mod_action_u32(vrule, VCAP_AF_ESDX,
43285f05000SHoratiu Vultur vrule->id);
43385f05000SHoratiu Vultur break;
43485f05000SHoratiu Vultur default:
43585f05000SHoratiu Vultur break;
43685f05000SHoratiu Vultur }
43785f05000SHoratiu Vultur
43885f05000SHoratiu Vultur return err;
43985f05000SHoratiu Vultur }
44085f05000SHoratiu Vultur
lan966x_tc_flower_add(struct lan966x_port * port,struct flow_cls_offload * f,struct vcap_admin * admin,bool ingress)4413643abd6SHoratiu Vultur static int lan966x_tc_flower_add(struct lan966x_port *port,
4423643abd6SHoratiu Vultur struct flow_cls_offload *f,
443e7e3f514SSteen Hegelund struct vcap_admin *admin,
444e7e3f514SSteen Hegelund bool ingress)
4453643abd6SHoratiu Vultur {
4463643abd6SHoratiu Vultur struct flow_action_entry *act;
4473643abd6SHoratiu Vultur u16 l3_proto = ETH_P_ALL;
4483643abd6SHoratiu Vultur struct flow_rule *frule;
4493643abd6SHoratiu Vultur struct vcap_rule *vrule;
4503643abd6SHoratiu Vultur int err, idx;
4513643abd6SHoratiu Vultur
452784c3067SSteen Hegelund err = lan966x_tc_flower_action_check(port->lan966x->vcap_ctrl,
453e7e3f514SSteen Hegelund port->dev, f, ingress);
4543643abd6SHoratiu Vultur if (err)
4553643abd6SHoratiu Vultur return err;
4563643abd6SHoratiu Vultur
4573643abd6SHoratiu Vultur vrule = vcap_alloc_rule(port->lan966x->vcap_ctrl, port->dev,
4583643abd6SHoratiu Vultur f->common.chain_index, VCAP_USER_TC,
4593643abd6SHoratiu Vultur f->common.prio, 0);
4603643abd6SHoratiu Vultur if (IS_ERR(vrule))
4613643abd6SHoratiu Vultur return PTR_ERR(vrule);
4623643abd6SHoratiu Vultur
4633643abd6SHoratiu Vultur vrule->cookie = f->cookie;
4643643abd6SHoratiu Vultur err = lan966x_tc_flower_use_dissectors(f, admin, vrule, &l3_proto);
4653643abd6SHoratiu Vultur if (err)
4663643abd6SHoratiu Vultur goto out;
4673643abd6SHoratiu Vultur
468b3762a9dSHoratiu Vultur err = lan966x_tc_add_rule_link_target(admin, vrule,
469b3762a9dSHoratiu Vultur f->common.chain_index);
470b3762a9dSHoratiu Vultur if (err)
471b3762a9dSHoratiu Vultur goto out;
472b3762a9dSHoratiu Vultur
4733643abd6SHoratiu Vultur frule = flow_cls_offload_flow_rule(f);
4743643abd6SHoratiu Vultur
4753643abd6SHoratiu Vultur flow_action_for_each(idx, act, &frule->action) {
4763643abd6SHoratiu Vultur switch (act->id) {
4773643abd6SHoratiu Vultur case FLOW_ACTION_TRAP:
478135c2116SHoratiu Vultur if (admin->vtype != VCAP_TYPE_IS2) {
479135c2116SHoratiu Vultur NL_SET_ERR_MSG_MOD(f->common.extack,
480135c2116SHoratiu Vultur "Trap action not supported in this VCAP");
481135c2116SHoratiu Vultur err = -EOPNOTSUPP;
482135c2116SHoratiu Vultur goto out;
483135c2116SHoratiu Vultur }
484135c2116SHoratiu Vultur
4853643abd6SHoratiu Vultur err = vcap_rule_add_action_bit(vrule,
4863643abd6SHoratiu Vultur VCAP_AF_CPU_COPY_ENA,
4873643abd6SHoratiu Vultur VCAP_BIT_1);
4883643abd6SHoratiu Vultur err |= vcap_rule_add_action_u32(vrule,
4893643abd6SHoratiu Vultur VCAP_AF_CPU_QUEUE_NUM,
4903643abd6SHoratiu Vultur 0);
4913643abd6SHoratiu Vultur err |= vcap_rule_add_action_u32(vrule, VCAP_AF_MASK_MODE,
4923643abd6SHoratiu Vultur LAN966X_PMM_REPLACE);
4933643abd6SHoratiu Vultur if (err)
4943643abd6SHoratiu Vultur goto out;
4953643abd6SHoratiu Vultur
4963643abd6SHoratiu Vultur break;
4973643abd6SHoratiu Vultur case FLOW_ACTION_GOTO:
498135c2116SHoratiu Vultur err = lan966x_tc_set_actionset(admin, vrule);
499135c2116SHoratiu Vultur if (err)
500135c2116SHoratiu Vultur goto out;
501135c2116SHoratiu Vultur
502b3762a9dSHoratiu Vultur err = lan966x_tc_add_rule_link(port->lan966x->vcap_ctrl,
503b3762a9dSHoratiu Vultur admin, vrule,
504b3762a9dSHoratiu Vultur f, act->chain_index);
505b3762a9dSHoratiu Vultur if (err)
506b3762a9dSHoratiu Vultur goto out;
507b3762a9dSHoratiu Vultur
5083643abd6SHoratiu Vultur break;
50985f05000SHoratiu Vultur case FLOW_ACTION_VLAN_POP:
51085f05000SHoratiu Vultur if (admin->vtype != VCAP_TYPE_ES0) {
51185f05000SHoratiu Vultur NL_SET_ERR_MSG_MOD(f->common.extack,
51285f05000SHoratiu Vultur "Cannot use vlan pop on non es0");
51385f05000SHoratiu Vultur err = -EOPNOTSUPP;
51485f05000SHoratiu Vultur goto out;
51585f05000SHoratiu Vultur }
51685f05000SHoratiu Vultur
51785f05000SHoratiu Vultur /* Force untag */
51885f05000SHoratiu Vultur err = vcap_rule_add_action_u32(vrule, VCAP_AF_PUSH_OUTER_TAG,
51985f05000SHoratiu Vultur LAN966X_FORCE_UNTAGED);
52085f05000SHoratiu Vultur if (err)
52185f05000SHoratiu Vultur goto out;
52285f05000SHoratiu Vultur
52385f05000SHoratiu Vultur break;
5243643abd6SHoratiu Vultur default:
5253643abd6SHoratiu Vultur NL_SET_ERR_MSG_MOD(f->common.extack,
5263643abd6SHoratiu Vultur "Unsupported TC action");
5273643abd6SHoratiu Vultur err = -EOPNOTSUPP;
5283643abd6SHoratiu Vultur goto out;
5293643abd6SHoratiu Vultur }
5303643abd6SHoratiu Vultur }
5313643abd6SHoratiu Vultur
53285f05000SHoratiu Vultur err = lan966x_tc_add_rule_counter(admin, vrule);
53385f05000SHoratiu Vultur if (err) {
53485f05000SHoratiu Vultur vcap_set_tc_exterr(f, vrule);
53585f05000SHoratiu Vultur goto out;
53685f05000SHoratiu Vultur }
53785f05000SHoratiu Vultur
5383643abd6SHoratiu Vultur err = vcap_val_rule(vrule, l3_proto);
5393643abd6SHoratiu Vultur if (err) {
5403643abd6SHoratiu Vultur vcap_set_tc_exterr(f, vrule);
5413643abd6SHoratiu Vultur goto out;
5423643abd6SHoratiu Vultur }
5433643abd6SHoratiu Vultur
5443643abd6SHoratiu Vultur err = vcap_add_rule(vrule);
5453643abd6SHoratiu Vultur if (err)
5463643abd6SHoratiu Vultur NL_SET_ERR_MSG_MOD(f->common.extack,
5473643abd6SHoratiu Vultur "Could not add the filter");
5483643abd6SHoratiu Vultur out:
5493643abd6SHoratiu Vultur vcap_free_rule(vrule);
5503643abd6SHoratiu Vultur return err;
5513643abd6SHoratiu Vultur }
5523643abd6SHoratiu Vultur
lan966x_tc_flower_del(struct lan966x_port * port,struct flow_cls_offload * f,struct vcap_admin * admin)5533643abd6SHoratiu Vultur static int lan966x_tc_flower_del(struct lan966x_port *port,
5543643abd6SHoratiu Vultur struct flow_cls_offload *f,
5553643abd6SHoratiu Vultur struct vcap_admin *admin)
5563643abd6SHoratiu Vultur {
5573643abd6SHoratiu Vultur struct vcap_control *vctrl;
5583643abd6SHoratiu Vultur int err = -ENOENT, rule_id;
5593643abd6SHoratiu Vultur
5603643abd6SHoratiu Vultur vctrl = port->lan966x->vcap_ctrl;
5613643abd6SHoratiu Vultur while (true) {
5623643abd6SHoratiu Vultur rule_id = vcap_lookup_rule_by_cookie(vctrl, f->cookie);
5633643abd6SHoratiu Vultur if (rule_id <= 0)
5643643abd6SHoratiu Vultur break;
5653643abd6SHoratiu Vultur
5663643abd6SHoratiu Vultur err = vcap_del_rule(vctrl, port->dev, rule_id);
5673643abd6SHoratiu Vultur if (err) {
5683643abd6SHoratiu Vultur NL_SET_ERR_MSG_MOD(f->common.extack,
5693643abd6SHoratiu Vultur "Cannot delete rule");
5703643abd6SHoratiu Vultur break;
5713643abd6SHoratiu Vultur }
5723643abd6SHoratiu Vultur }
5733643abd6SHoratiu Vultur
5743643abd6SHoratiu Vultur return err;
5753643abd6SHoratiu Vultur }
5763643abd6SHoratiu Vultur
lan966x_tc_flower_stats(struct lan966x_port * port,struct flow_cls_offload * f,struct vcap_admin * admin)5779ed138ffSHoratiu Vultur static int lan966x_tc_flower_stats(struct lan966x_port *port,
5789ed138ffSHoratiu Vultur struct flow_cls_offload *f,
5799ed138ffSHoratiu Vultur struct vcap_admin *admin)
5809ed138ffSHoratiu Vultur {
5819ed138ffSHoratiu Vultur struct vcap_counter count = {};
5829ed138ffSHoratiu Vultur int err;
5839ed138ffSHoratiu Vultur
5849ed138ffSHoratiu Vultur err = vcap_get_rule_count_by_cookie(port->lan966x->vcap_ctrl,
5859ed138ffSHoratiu Vultur &count, f->cookie);
5869ed138ffSHoratiu Vultur if (err)
5879ed138ffSHoratiu Vultur return err;
5889ed138ffSHoratiu Vultur
5899ed138ffSHoratiu Vultur flow_stats_update(&f->stats, 0x0, count.value, 0, 0,
5909ed138ffSHoratiu Vultur FLOW_ACTION_HW_STATS_IMMEDIATE);
5919ed138ffSHoratiu Vultur
5929ed138ffSHoratiu Vultur return err;
5939ed138ffSHoratiu Vultur }
5949ed138ffSHoratiu Vultur
lan966x_tc_flower(struct lan966x_port * port,struct flow_cls_offload * f,bool ingress)5953643abd6SHoratiu Vultur int lan966x_tc_flower(struct lan966x_port *port,
596e7e3f514SSteen Hegelund struct flow_cls_offload *f,
597e7e3f514SSteen Hegelund bool ingress)
5983643abd6SHoratiu Vultur {
5993643abd6SHoratiu Vultur struct vcap_admin *admin;
6003643abd6SHoratiu Vultur
6013643abd6SHoratiu Vultur admin = vcap_find_admin(port->lan966x->vcap_ctrl,
6023643abd6SHoratiu Vultur f->common.chain_index);
6033643abd6SHoratiu Vultur if (!admin) {
6043643abd6SHoratiu Vultur NL_SET_ERR_MSG_MOD(f->common.extack, "Invalid chain");
6053643abd6SHoratiu Vultur return -EINVAL;
6063643abd6SHoratiu Vultur }
6073643abd6SHoratiu Vultur
6083643abd6SHoratiu Vultur switch (f->command) {
6093643abd6SHoratiu Vultur case FLOW_CLS_REPLACE:
610e7e3f514SSteen Hegelund return lan966x_tc_flower_add(port, f, admin, ingress);
6113643abd6SHoratiu Vultur case FLOW_CLS_DESTROY:
6123643abd6SHoratiu Vultur return lan966x_tc_flower_del(port, f, admin);
6139ed138ffSHoratiu Vultur case FLOW_CLS_STATS:
6149ed138ffSHoratiu Vultur return lan966x_tc_flower_stats(port, f, admin);
6153643abd6SHoratiu Vultur default:
6163643abd6SHoratiu Vultur return -EOPNOTSUPP;
6173643abd6SHoratiu Vultur }
6183643abd6SHoratiu Vultur
6193643abd6SHoratiu Vultur return 0;
6203643abd6SHoratiu Vultur }
621