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