11f7ea1cdSQi Zhang // SPDX-License-Identifier: GPL-2.0
21f7ea1cdSQi Zhang /* Copyright (C) 2021, Intel Corporation. */
31f7ea1cdSQi Zhang 
41f7ea1cdSQi Zhang #include "ice.h"
51f7ea1cdSQi Zhang #include "ice_base.h"
61f7ea1cdSQi Zhang #include "ice_lib.h"
71f7ea1cdSQi Zhang #include "ice_flow.h"
8109aba47SJacob Keller #include "ice_vf_lib_private.h"
91f7ea1cdSQi Zhang 
101f7ea1cdSQi Zhang #define to_fltr_conf_from_desc(p) \
111f7ea1cdSQi Zhang 	container_of(p, struct virtchnl_fdir_fltr_conf, input)
121f7ea1cdSQi Zhang 
131f7ea1cdSQi Zhang #define ICE_FLOW_PROF_TYPE_S	0
141f7ea1cdSQi Zhang #define ICE_FLOW_PROF_TYPE_M	(0xFFFFFFFFULL << ICE_FLOW_PROF_TYPE_S)
151f7ea1cdSQi Zhang #define ICE_FLOW_PROF_VSI_S	32
161f7ea1cdSQi Zhang #define ICE_FLOW_PROF_VSI_M	(0xFFFFFFFFULL << ICE_FLOW_PROF_VSI_S)
171f7ea1cdSQi Zhang 
181f7ea1cdSQi Zhang /* Flow profile ID format:
191f7ea1cdSQi Zhang  * [0:31] - flow type, flow + tun_offs
201f7ea1cdSQi Zhang  * [32:63] - VSI index
211f7ea1cdSQi Zhang  */
221f7ea1cdSQi Zhang #define ICE_FLOW_PROF_FD(vsi, flow, tun_offs) \
231f7ea1cdSQi Zhang 	((u64)(((((flow) + (tun_offs)) & ICE_FLOW_PROF_TYPE_M)) | \
241f7ea1cdSQi Zhang 	      (((u64)(vsi) << ICE_FLOW_PROF_VSI_S) & ICE_FLOW_PROF_VSI_M)))
251f7ea1cdSQi Zhang 
26ef9e4cc5SQi Zhang #define GTPU_TEID_OFFSET 4
27ef9e4cc5SQi Zhang #define GTPU_EH_QFI_OFFSET 1
28ef9e4cc5SQi Zhang #define GTPU_EH_QFI_MASK 0x3F
29213528feSQi Zhang #define PFCP_S_OFFSET 0
30213528feSQi Zhang #define PFCP_S_MASK 0x1
31213528feSQi Zhang #define PFCP_PORT_NR 8805
32213528feSQi Zhang 
33213528feSQi Zhang #define FDIR_INSET_FLAG_ESP_S 0
34213528feSQi Zhang #define FDIR_INSET_FLAG_ESP_M BIT_ULL(FDIR_INSET_FLAG_ESP_S)
35213528feSQi Zhang #define FDIR_INSET_FLAG_ESP_UDP BIT_ULL(FDIR_INSET_FLAG_ESP_S)
36213528feSQi Zhang #define FDIR_INSET_FLAG_ESP_IPSEC (0ULL << FDIR_INSET_FLAG_ESP_S)
37ef9e4cc5SQi Zhang 
38ef9e4cc5SQi Zhang enum ice_fdir_tunnel_type {
39ef9e4cc5SQi Zhang 	ICE_FDIR_TUNNEL_TYPE_NONE = 0,
40ef9e4cc5SQi Zhang 	ICE_FDIR_TUNNEL_TYPE_GTPU,
41ef9e4cc5SQi Zhang 	ICE_FDIR_TUNNEL_TYPE_GTPU_EH,
42ef9e4cc5SQi Zhang };
43ef9e4cc5SQi Zhang 
441f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf {
451f7ea1cdSQi Zhang 	struct ice_fdir_fltr input;
46ef9e4cc5SQi Zhang 	enum ice_fdir_tunnel_type ttype;
47213528feSQi Zhang 	u64 inset_flag;
48d6218317SQi Zhang 	u32 flow_id;
491f7ea1cdSQi Zhang };
501f7ea1cdSQi Zhang 
511f7ea1cdSQi Zhang struct virtchnl_fdir_inset_map {
521f7ea1cdSQi Zhang 	enum virtchnl_proto_hdr_field field;
531f7ea1cdSQi Zhang 	enum ice_flow_field fld;
54213528feSQi Zhang 	u64 flag;
55213528feSQi Zhang 	u64 mask;
561f7ea1cdSQi Zhang };
571f7ea1cdSQi Zhang 
581f7ea1cdSQi Zhang static const struct virtchnl_fdir_inset_map fdir_inset_map[] = {
59213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_ETH_ETHERTYPE, ICE_FLOW_FIELD_IDX_ETH_TYPE, 0, 0},
60213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_IPV4_SRC, ICE_FLOW_FIELD_IDX_IPV4_SA, 0, 0},
61213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_IPV4_DST, ICE_FLOW_FIELD_IDX_IPV4_DA, 0, 0},
62213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_IPV4_DSCP, ICE_FLOW_FIELD_IDX_IPV4_DSCP, 0, 0},
63213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_IPV4_TTL, ICE_FLOW_FIELD_IDX_IPV4_TTL, 0, 0},
64213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_IPV4_PROT, ICE_FLOW_FIELD_IDX_IPV4_PROT, 0, 0},
65213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_IPV6_SRC, ICE_FLOW_FIELD_IDX_IPV6_SA, 0, 0},
66213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_IPV6_DST, ICE_FLOW_FIELD_IDX_IPV6_DA, 0, 0},
67213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_IPV6_TC, ICE_FLOW_FIELD_IDX_IPV6_DSCP, 0, 0},
68213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_IPV6_HOP_LIMIT, ICE_FLOW_FIELD_IDX_IPV6_TTL, 0, 0},
69213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_IPV6_PROT, ICE_FLOW_FIELD_IDX_IPV6_PROT, 0, 0},
70213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_UDP_SRC_PORT, ICE_FLOW_FIELD_IDX_UDP_SRC_PORT, 0, 0},
71213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_UDP_DST_PORT, ICE_FLOW_FIELD_IDX_UDP_DST_PORT, 0, 0},
72213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_TCP_SRC_PORT, ICE_FLOW_FIELD_IDX_TCP_SRC_PORT, 0, 0},
73213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_TCP_DST_PORT, ICE_FLOW_FIELD_IDX_TCP_DST_PORT, 0, 0},
74213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT, ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT, 0, 0},
75213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_SCTP_DST_PORT, ICE_FLOW_FIELD_IDX_SCTP_DST_PORT, 0, 0},
76213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_GTPU_IP_TEID, ICE_FLOW_FIELD_IDX_GTPU_IP_TEID, 0, 0},
77213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_GTPU_EH_QFI, ICE_FLOW_FIELD_IDX_GTPU_EH_QFI, 0, 0},
78213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_ESP_SPI, ICE_FLOW_FIELD_IDX_ESP_SPI,
79213528feSQi Zhang 		FDIR_INSET_FLAG_ESP_IPSEC, FDIR_INSET_FLAG_ESP_M},
80213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_ESP_SPI, ICE_FLOW_FIELD_IDX_NAT_T_ESP_SPI,
81213528feSQi Zhang 		FDIR_INSET_FLAG_ESP_UDP, FDIR_INSET_FLAG_ESP_M},
82213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_AH_SPI, ICE_FLOW_FIELD_IDX_AH_SPI, 0, 0},
83213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_L2TPV3_SESS_ID, ICE_FLOW_FIELD_IDX_L2TPV3_SESS_ID, 0, 0},
84213528feSQi Zhang 	{VIRTCHNL_PROTO_HDR_PFCP_S_FIELD, ICE_FLOW_FIELD_IDX_UDP_DST_PORT, 0, 0},
851f7ea1cdSQi Zhang };
861f7ea1cdSQi Zhang 
871f7ea1cdSQi Zhang /**
881f7ea1cdSQi Zhang  * ice_vc_fdir_param_check
891f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
901f7ea1cdSQi Zhang  * @vsi_id: VF relative VSI ID
911f7ea1cdSQi Zhang  *
921f7ea1cdSQi Zhang  * Check for the valid VSI ID, PF's state and VF's state
931f7ea1cdSQi Zhang  *
941f7ea1cdSQi Zhang  * Return: 0 on success, and -EINVAL on error.
951f7ea1cdSQi Zhang  */
961f7ea1cdSQi Zhang static int
971f7ea1cdSQi Zhang ice_vc_fdir_param_check(struct ice_vf *vf, u16 vsi_id)
981f7ea1cdSQi Zhang {
991f7ea1cdSQi Zhang 	struct ice_pf *pf = vf->pf;
1001f7ea1cdSQi Zhang 
1011f7ea1cdSQi Zhang 	if (!test_bit(ICE_FLAG_FD_ENA, pf->flags))
1021f7ea1cdSQi Zhang 		return -EINVAL;
1031f7ea1cdSQi Zhang 
1041f7ea1cdSQi Zhang 	if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states))
1051f7ea1cdSQi Zhang 		return -EINVAL;
1061f7ea1cdSQi Zhang 
1071f7ea1cdSQi Zhang 	if (!(vf->driver_caps & VIRTCHNL_VF_OFFLOAD_FDIR_PF))
1081f7ea1cdSQi Zhang 		return -EINVAL;
1091f7ea1cdSQi Zhang 
1101f7ea1cdSQi Zhang 	if (vsi_id != vf->lan_vsi_num)
1111f7ea1cdSQi Zhang 		return -EINVAL;
1121f7ea1cdSQi Zhang 
1131f7ea1cdSQi Zhang 	if (!ice_vc_isvalid_vsi_id(vf, vsi_id))
1141f7ea1cdSQi Zhang 		return -EINVAL;
1151f7ea1cdSQi Zhang 
116772dec64SBrett Creeley 	if (!ice_get_vf_vsi(vf))
1171f7ea1cdSQi Zhang 		return -EINVAL;
1181f7ea1cdSQi Zhang 
1191f7ea1cdSQi Zhang 	return 0;
1201f7ea1cdSQi Zhang }
1211f7ea1cdSQi Zhang 
1221f7ea1cdSQi Zhang /**
1231f7ea1cdSQi Zhang  * ice_vf_start_ctrl_vsi
1241f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
1251f7ea1cdSQi Zhang  *
1261f7ea1cdSQi Zhang  * Allocate ctrl_vsi for the first time and open the ctrl_vsi port for VF
1271f7ea1cdSQi Zhang  *
1281f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
1291f7ea1cdSQi Zhang  */
1301f7ea1cdSQi Zhang static int ice_vf_start_ctrl_vsi(struct ice_vf *vf)
1311f7ea1cdSQi Zhang {
1321f7ea1cdSQi Zhang 	struct ice_pf *pf = vf->pf;
1331f7ea1cdSQi Zhang 	struct ice_vsi *ctrl_vsi;
1341f7ea1cdSQi Zhang 	struct device *dev;
1351f7ea1cdSQi Zhang 	int err;
1361f7ea1cdSQi Zhang 
1371f7ea1cdSQi Zhang 	dev = ice_pf_to_dev(pf);
1381f7ea1cdSQi Zhang 	if (vf->ctrl_vsi_idx != ICE_NO_VSI)
1391f7ea1cdSQi Zhang 		return -EEXIST;
1401f7ea1cdSQi Zhang 
1411f7ea1cdSQi Zhang 	ctrl_vsi = ice_vf_ctrl_vsi_setup(vf);
1421f7ea1cdSQi Zhang 	if (!ctrl_vsi) {
1431f7ea1cdSQi Zhang 		dev_dbg(dev, "Could not setup control VSI for VF %d\n",
1441f7ea1cdSQi Zhang 			vf->vf_id);
1451f7ea1cdSQi Zhang 		return -ENOMEM;
1461f7ea1cdSQi Zhang 	}
1471f7ea1cdSQi Zhang 
1481f7ea1cdSQi Zhang 	err = ice_vsi_open_ctrl(ctrl_vsi);
1491f7ea1cdSQi Zhang 	if (err) {
1501f7ea1cdSQi Zhang 		dev_dbg(dev, "Could not open control VSI for VF %d\n",
1511f7ea1cdSQi Zhang 			vf->vf_id);
1521f7ea1cdSQi Zhang 		goto err_vsi_open;
1531f7ea1cdSQi Zhang 	}
1541f7ea1cdSQi Zhang 
1551f7ea1cdSQi Zhang 	return 0;
1561f7ea1cdSQi Zhang 
1571f7ea1cdSQi Zhang err_vsi_open:
1581f7ea1cdSQi Zhang 	ice_vsi_release(ctrl_vsi);
1591f7ea1cdSQi Zhang 	if (vf->ctrl_vsi_idx != ICE_NO_VSI) {
1601f7ea1cdSQi Zhang 		pf->vsi[vf->ctrl_vsi_idx] = NULL;
1611f7ea1cdSQi Zhang 		vf->ctrl_vsi_idx = ICE_NO_VSI;
1621f7ea1cdSQi Zhang 	}
1631f7ea1cdSQi Zhang 	return err;
1641f7ea1cdSQi Zhang }
1651f7ea1cdSQi Zhang 
1661f7ea1cdSQi Zhang /**
1671f7ea1cdSQi Zhang  * ice_vc_fdir_alloc_prof - allocate profile for this filter flow type
1681f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
1691f7ea1cdSQi Zhang  * @flow: filter flow type
1701f7ea1cdSQi Zhang  *
1711f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
1721f7ea1cdSQi Zhang  */
1731f7ea1cdSQi Zhang static int
1741f7ea1cdSQi Zhang ice_vc_fdir_alloc_prof(struct ice_vf *vf, enum ice_fltr_ptype flow)
1751f7ea1cdSQi Zhang {
1761f7ea1cdSQi Zhang 	struct ice_vf_fdir *fdir = &vf->fdir;
1771f7ea1cdSQi Zhang 
1781f7ea1cdSQi Zhang 	if (!fdir->fdir_prof) {
1791f7ea1cdSQi Zhang 		fdir->fdir_prof = devm_kcalloc(ice_pf_to_dev(vf->pf),
1801f7ea1cdSQi Zhang 					       ICE_FLTR_PTYPE_MAX,
1811f7ea1cdSQi Zhang 					       sizeof(*fdir->fdir_prof),
1821f7ea1cdSQi Zhang 					       GFP_KERNEL);
1831f7ea1cdSQi Zhang 		if (!fdir->fdir_prof)
1841f7ea1cdSQi Zhang 			return -ENOMEM;
1851f7ea1cdSQi Zhang 	}
1861f7ea1cdSQi Zhang 
1871f7ea1cdSQi Zhang 	if (!fdir->fdir_prof[flow]) {
1881f7ea1cdSQi Zhang 		fdir->fdir_prof[flow] = devm_kzalloc(ice_pf_to_dev(vf->pf),
1891f7ea1cdSQi Zhang 						     sizeof(**fdir->fdir_prof),
1901f7ea1cdSQi Zhang 						     GFP_KERNEL);
1911f7ea1cdSQi Zhang 		if (!fdir->fdir_prof[flow])
1921f7ea1cdSQi Zhang 			return -ENOMEM;
1931f7ea1cdSQi Zhang 	}
1941f7ea1cdSQi Zhang 
1951f7ea1cdSQi Zhang 	return 0;
1961f7ea1cdSQi Zhang }
1971f7ea1cdSQi Zhang 
1981f7ea1cdSQi Zhang /**
1991f7ea1cdSQi Zhang  * ice_vc_fdir_free_prof - free profile for this filter flow type
2001f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
2011f7ea1cdSQi Zhang  * @flow: filter flow type
2021f7ea1cdSQi Zhang  */
2031f7ea1cdSQi Zhang static void
2041f7ea1cdSQi Zhang ice_vc_fdir_free_prof(struct ice_vf *vf, enum ice_fltr_ptype flow)
2051f7ea1cdSQi Zhang {
2061f7ea1cdSQi Zhang 	struct ice_vf_fdir *fdir = &vf->fdir;
2071f7ea1cdSQi Zhang 
2081f7ea1cdSQi Zhang 	if (!fdir->fdir_prof)
2091f7ea1cdSQi Zhang 		return;
2101f7ea1cdSQi Zhang 
2111f7ea1cdSQi Zhang 	if (!fdir->fdir_prof[flow])
2121f7ea1cdSQi Zhang 		return;
2131f7ea1cdSQi Zhang 
2141f7ea1cdSQi Zhang 	devm_kfree(ice_pf_to_dev(vf->pf), fdir->fdir_prof[flow]);
2151f7ea1cdSQi Zhang 	fdir->fdir_prof[flow] = NULL;
2161f7ea1cdSQi Zhang }
2171f7ea1cdSQi Zhang 
2181f7ea1cdSQi Zhang /**
2191f7ea1cdSQi Zhang  * ice_vc_fdir_free_prof_all - free all the profile for this VF
2201f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
2211f7ea1cdSQi Zhang  */
2221f7ea1cdSQi Zhang static void ice_vc_fdir_free_prof_all(struct ice_vf *vf)
2231f7ea1cdSQi Zhang {
2241f7ea1cdSQi Zhang 	struct ice_vf_fdir *fdir = &vf->fdir;
2251f7ea1cdSQi Zhang 	enum ice_fltr_ptype flow;
2261f7ea1cdSQi Zhang 
2271f7ea1cdSQi Zhang 	if (!fdir->fdir_prof)
2281f7ea1cdSQi Zhang 		return;
2291f7ea1cdSQi Zhang 
2301f7ea1cdSQi Zhang 	for (flow = ICE_FLTR_PTYPE_NONF_NONE; flow < ICE_FLTR_PTYPE_MAX; flow++)
2311f7ea1cdSQi Zhang 		ice_vc_fdir_free_prof(vf, flow);
2321f7ea1cdSQi Zhang 
2331f7ea1cdSQi Zhang 	devm_kfree(ice_pf_to_dev(vf->pf), fdir->fdir_prof);
2341f7ea1cdSQi Zhang 	fdir->fdir_prof = NULL;
2351f7ea1cdSQi Zhang }
2361f7ea1cdSQi Zhang 
2371f7ea1cdSQi Zhang /**
2381f7ea1cdSQi Zhang  * ice_vc_fdir_parse_flow_fld
2391f7ea1cdSQi Zhang  * @proto_hdr: virtual channel protocol filter header
2401f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
2411f7ea1cdSQi Zhang  * @fld: field type array
2421f7ea1cdSQi Zhang  * @fld_cnt: field counter
2431f7ea1cdSQi Zhang  *
2441f7ea1cdSQi Zhang  * Parse the virtual channel filter header and store them into field type array
2451f7ea1cdSQi Zhang  *
2461f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
2471f7ea1cdSQi Zhang  */
2481f7ea1cdSQi Zhang static int
2491f7ea1cdSQi Zhang ice_vc_fdir_parse_flow_fld(struct virtchnl_proto_hdr *proto_hdr,
2501f7ea1cdSQi Zhang 			   struct virtchnl_fdir_fltr_conf *conf,
2511f7ea1cdSQi Zhang 			   enum ice_flow_field *fld, int *fld_cnt)
2521f7ea1cdSQi Zhang {
2531f7ea1cdSQi Zhang 	struct virtchnl_proto_hdr hdr;
2541f7ea1cdSQi Zhang 	u32 i;
2551f7ea1cdSQi Zhang 
2561f7ea1cdSQi Zhang 	memcpy(&hdr, proto_hdr, sizeof(hdr));
2571f7ea1cdSQi Zhang 
2581f7ea1cdSQi Zhang 	for (i = 0; (i < ARRAY_SIZE(fdir_inset_map)) &&
2591f7ea1cdSQi Zhang 	     VIRTCHNL_GET_PROTO_HDR_FIELD(&hdr); i++)
2601f7ea1cdSQi Zhang 		if (VIRTCHNL_TEST_PROTO_HDR(&hdr, fdir_inset_map[i].field)) {
261213528feSQi Zhang 			if (fdir_inset_map[i].mask &&
262213528feSQi Zhang 			    ((fdir_inset_map[i].mask & conf->inset_flag) !=
263213528feSQi Zhang 			     fdir_inset_map[i].flag))
264213528feSQi Zhang 				continue;
265213528feSQi Zhang 
2661f7ea1cdSQi Zhang 			fld[*fld_cnt] = fdir_inset_map[i].fld;
2671f7ea1cdSQi Zhang 			*fld_cnt += 1;
2681f7ea1cdSQi Zhang 			if (*fld_cnt >= ICE_FLOW_FIELD_IDX_MAX)
2691f7ea1cdSQi Zhang 				return -EINVAL;
2701f7ea1cdSQi Zhang 			VIRTCHNL_DEL_PROTO_HDR_FIELD(&hdr,
2711f7ea1cdSQi Zhang 						     fdir_inset_map[i].field);
2721f7ea1cdSQi Zhang 		}
2731f7ea1cdSQi Zhang 
2741f7ea1cdSQi Zhang 	return 0;
2751f7ea1cdSQi Zhang }
2761f7ea1cdSQi Zhang 
2771f7ea1cdSQi Zhang /**
2781f7ea1cdSQi Zhang  * ice_vc_fdir_set_flow_fld
2791f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
2801f7ea1cdSQi Zhang  * @fltr: virtual channel add cmd buffer
2811f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
2821f7ea1cdSQi Zhang  * @seg: array of one or more packet segments that describe the flow
2831f7ea1cdSQi Zhang  *
2841f7ea1cdSQi Zhang  * Parse the virtual channel add msg buffer's field vector and store them into
2851f7ea1cdSQi Zhang  * flow's packet segment field
2861f7ea1cdSQi Zhang  *
2871f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
2881f7ea1cdSQi Zhang  */
2891f7ea1cdSQi Zhang static int
2901f7ea1cdSQi Zhang ice_vc_fdir_set_flow_fld(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
2911f7ea1cdSQi Zhang 			 struct virtchnl_fdir_fltr_conf *conf,
2921f7ea1cdSQi Zhang 			 struct ice_flow_seg_info *seg)
2931f7ea1cdSQi Zhang {
2941f7ea1cdSQi Zhang 	struct virtchnl_fdir_rule *rule = &fltr->rule_cfg;
2951f7ea1cdSQi Zhang 	enum ice_flow_field fld[ICE_FLOW_FIELD_IDX_MAX];
2961f7ea1cdSQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
2971f7ea1cdSQi Zhang 	struct virtchnl_proto_hdrs *proto;
2981f7ea1cdSQi Zhang 	int fld_cnt = 0;
2991f7ea1cdSQi Zhang 	int i;
3001f7ea1cdSQi Zhang 
3011f7ea1cdSQi Zhang 	proto = &rule->proto_hdrs;
3021f7ea1cdSQi Zhang 	for (i = 0; i < proto->count; i++) {
3031f7ea1cdSQi Zhang 		struct virtchnl_proto_hdr *hdr = &proto->proto_hdr[i];
3041f7ea1cdSQi Zhang 		int ret;
3051f7ea1cdSQi Zhang 
3061f7ea1cdSQi Zhang 		ret = ice_vc_fdir_parse_flow_fld(hdr, conf, fld, &fld_cnt);
3071f7ea1cdSQi Zhang 		if (ret)
3081f7ea1cdSQi Zhang 			return ret;
3091f7ea1cdSQi Zhang 	}
3101f7ea1cdSQi Zhang 
3111f7ea1cdSQi Zhang 	if (fld_cnt == 0) {
3121f7ea1cdSQi Zhang 		dev_dbg(dev, "Empty input set for VF %d\n", vf->vf_id);
3131f7ea1cdSQi Zhang 		return -EINVAL;
3141f7ea1cdSQi Zhang 	}
3151f7ea1cdSQi Zhang 
3161f7ea1cdSQi Zhang 	for (i = 0; i < fld_cnt; i++)
3171f7ea1cdSQi Zhang 		ice_flow_set_fld(seg, fld[i],
3181f7ea1cdSQi Zhang 				 ICE_FLOW_FLD_OFF_INVAL,
3191f7ea1cdSQi Zhang 				 ICE_FLOW_FLD_OFF_INVAL,
3201f7ea1cdSQi Zhang 				 ICE_FLOW_FLD_OFF_INVAL, false);
3211f7ea1cdSQi Zhang 
3221f7ea1cdSQi Zhang 	return 0;
3231f7ea1cdSQi Zhang }
3241f7ea1cdSQi Zhang 
3251f7ea1cdSQi Zhang /**
3261f7ea1cdSQi Zhang  * ice_vc_fdir_set_flow_hdr - config the flow's packet segment header
3271f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
3281f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
3291f7ea1cdSQi Zhang  * @seg: array of one or more packet segments that describe the flow
3301f7ea1cdSQi Zhang  *
3311f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
3321f7ea1cdSQi Zhang  */
3331f7ea1cdSQi Zhang static int
3341f7ea1cdSQi Zhang ice_vc_fdir_set_flow_hdr(struct ice_vf *vf,
3351f7ea1cdSQi Zhang 			 struct virtchnl_fdir_fltr_conf *conf,
3361f7ea1cdSQi Zhang 			 struct ice_flow_seg_info *seg)
3371f7ea1cdSQi Zhang {
3381f7ea1cdSQi Zhang 	enum ice_fltr_ptype flow = conf->input.flow_type;
339ef9e4cc5SQi Zhang 	enum ice_fdir_tunnel_type ttype = conf->ttype;
3401f7ea1cdSQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
3411f7ea1cdSQi Zhang 
3421f7ea1cdSQi Zhang 	switch (flow) {
34321606584SQi Zhang 	case ICE_FLTR_PTYPE_NON_IP_L2:
34421606584SQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ETH_NON_IP);
34521606584SQi Zhang 		break;
346213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV3:
347213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_L2TPV3 |
348213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
349213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
350213528feSQi Zhang 		break;
351213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_ESP:
352213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ESP |
353213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
354213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
355213528feSQi Zhang 		break;
356213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_AH:
357213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_AH |
358213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
359213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
360213528feSQi Zhang 		break;
361213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_NAT_T_ESP:
362213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_NAT_T_ESP |
363213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
364213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
365213528feSQi Zhang 		break;
366213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_PFCP_NODE:
367213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_PFCP_NODE |
368213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
369213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
370213528feSQi Zhang 		break;
371213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_PFCP_SESSION:
372213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_PFCP_SESSION |
373213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
374213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
375213528feSQi Zhang 		break;
3761f7ea1cdSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_OTHER:
3771f7ea1cdSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4 |
3781f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
3791f7ea1cdSQi Zhang 		break;
3801f7ea1cdSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_TCP:
3811f7ea1cdSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_TCP |
3821f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
3831f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
3841f7ea1cdSQi Zhang 		break;
3851f7ea1cdSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_UDP:
3861f7ea1cdSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_UDP |
3871f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
3881f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
3891f7ea1cdSQi Zhang 		break;
390ef9e4cc5SQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_UDP:
391ef9e4cc5SQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_TCP:
392ef9e4cc5SQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_ICMP:
393ef9e4cc5SQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER:
394ef9e4cc5SQi Zhang 		if (ttype == ICE_FDIR_TUNNEL_TYPE_GTPU) {
395ef9e4cc5SQi Zhang 			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_IP |
396ef9e4cc5SQi Zhang 					  ICE_FLOW_SEG_HDR_IPV4 |
397ef9e4cc5SQi Zhang 					  ICE_FLOW_SEG_HDR_IPV_OTHER);
398ef9e4cc5SQi Zhang 		} else if (ttype == ICE_FDIR_TUNNEL_TYPE_GTPU_EH) {
399ef9e4cc5SQi Zhang 			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_EH |
400ef9e4cc5SQi Zhang 					  ICE_FLOW_SEG_HDR_GTPU_IP |
401ef9e4cc5SQi Zhang 					  ICE_FLOW_SEG_HDR_IPV4 |
402ef9e4cc5SQi Zhang 					  ICE_FLOW_SEG_HDR_IPV_OTHER);
403ef9e4cc5SQi Zhang 		} else {
404ef9e4cc5SQi Zhang 			dev_dbg(dev, "Invalid tunnel type 0x%x for VF %d\n",
405ef9e4cc5SQi Zhang 				flow, vf->vf_id);
406ef9e4cc5SQi Zhang 			return -EINVAL;
407ef9e4cc5SQi Zhang 		}
408ef9e4cc5SQi Zhang 		break;
4091f7ea1cdSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_SCTP:
4101f7ea1cdSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_SCTP |
4111f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
4121f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
4131f7ea1cdSQi Zhang 		break;
414213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV3:
415213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_L2TPV3 |
416213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
417213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
418213528feSQi Zhang 		break;
419213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_ESP:
420213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ESP |
421213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
422213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
423213528feSQi Zhang 		break;
424213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_AH:
425213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_AH |
426213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
427213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
428213528feSQi Zhang 		break;
429213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_NAT_T_ESP:
430213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_NAT_T_ESP |
431213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
432213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
433213528feSQi Zhang 		break;
434213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_PFCP_NODE:
435213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_PFCP_NODE |
436213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
437213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
438213528feSQi Zhang 		break;
439213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_PFCP_SESSION:
440213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_PFCP_SESSION |
441213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
442213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
443213528feSQi Zhang 		break;
4441f7ea1cdSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_OTHER:
4451f7ea1cdSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV6 |
4461f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
4471f7ea1cdSQi Zhang 		break;
4481f7ea1cdSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_TCP:
4491f7ea1cdSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_TCP |
4501f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
4511f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
4521f7ea1cdSQi Zhang 		break;
4531f7ea1cdSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_UDP:
4541f7ea1cdSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_UDP |
4551f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
4561f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
4571f7ea1cdSQi Zhang 		break;
4581f7ea1cdSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_SCTP:
4591f7ea1cdSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_SCTP |
4601f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
4611f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
4621f7ea1cdSQi Zhang 		break;
4631f7ea1cdSQi Zhang 	default:
4641f7ea1cdSQi Zhang 		dev_dbg(dev, "Invalid flow type 0x%x for VF %d failed\n",
4651f7ea1cdSQi Zhang 			flow, vf->vf_id);
4661f7ea1cdSQi Zhang 		return -EINVAL;
4671f7ea1cdSQi Zhang 	}
4681f7ea1cdSQi Zhang 
4691f7ea1cdSQi Zhang 	return 0;
4701f7ea1cdSQi Zhang }
4711f7ea1cdSQi Zhang 
4721f7ea1cdSQi Zhang /**
4731f7ea1cdSQi Zhang  * ice_vc_fdir_rem_prof - remove profile for this filter flow type
4741f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
4751f7ea1cdSQi Zhang  * @flow: filter flow type
4761f7ea1cdSQi Zhang  * @tun: 0 implies non-tunnel type filter, 1 implies tunnel type filter
4771f7ea1cdSQi Zhang  */
4781f7ea1cdSQi Zhang static void
4791f7ea1cdSQi Zhang ice_vc_fdir_rem_prof(struct ice_vf *vf, enum ice_fltr_ptype flow, int tun)
4801f7ea1cdSQi Zhang {
4811f7ea1cdSQi Zhang 	struct ice_vf_fdir *fdir = &vf->fdir;
4821f7ea1cdSQi Zhang 	struct ice_fd_hw_prof *vf_prof;
4831f7ea1cdSQi Zhang 	struct ice_pf *pf = vf->pf;
4841f7ea1cdSQi Zhang 	struct ice_vsi *vf_vsi;
4851f7ea1cdSQi Zhang 	struct device *dev;
4861f7ea1cdSQi Zhang 	struct ice_hw *hw;
4871f7ea1cdSQi Zhang 	u64 prof_id;
4881f7ea1cdSQi Zhang 	int i;
4891f7ea1cdSQi Zhang 
4901f7ea1cdSQi Zhang 	dev = ice_pf_to_dev(pf);
4911f7ea1cdSQi Zhang 	hw = &pf->hw;
4921f7ea1cdSQi Zhang 	if (!fdir->fdir_prof || !fdir->fdir_prof[flow])
4931f7ea1cdSQi Zhang 		return;
4941f7ea1cdSQi Zhang 
4951f7ea1cdSQi Zhang 	vf_prof = fdir->fdir_prof[flow];
4961f7ea1cdSQi Zhang 
497772dec64SBrett Creeley 	vf_vsi = ice_get_vf_vsi(vf);
4981f7ea1cdSQi Zhang 	if (!vf_vsi) {
4991f7ea1cdSQi Zhang 		dev_dbg(dev, "NULL vf %d vsi pointer\n", vf->vf_id);
5001f7ea1cdSQi Zhang 		return;
5011f7ea1cdSQi Zhang 	}
5021f7ea1cdSQi Zhang 
5031f7ea1cdSQi Zhang 	if (!fdir->prof_entry_cnt[flow][tun])
5041f7ea1cdSQi Zhang 		return;
5051f7ea1cdSQi Zhang 
5061f7ea1cdSQi Zhang 	prof_id = ICE_FLOW_PROF_FD(vf_vsi->vsi_num,
5071f7ea1cdSQi Zhang 				   flow, tun ? ICE_FLTR_PTYPE_MAX : 0);
5081f7ea1cdSQi Zhang 
5091f7ea1cdSQi Zhang 	for (i = 0; i < fdir->prof_entry_cnt[flow][tun]; i++)
5101f7ea1cdSQi Zhang 		if (vf_prof->entry_h[i][tun]) {
5111f7ea1cdSQi Zhang 			u16 vsi_num = ice_get_hw_vsi_num(hw, vf_prof->vsi_h[i]);
5121f7ea1cdSQi Zhang 
5131f7ea1cdSQi Zhang 			ice_rem_prof_id_flow(hw, ICE_BLK_FD, vsi_num, prof_id);
5141f7ea1cdSQi Zhang 			ice_flow_rem_entry(hw, ICE_BLK_FD,
5151f7ea1cdSQi Zhang 					   vf_prof->entry_h[i][tun]);
5161f7ea1cdSQi Zhang 			vf_prof->entry_h[i][tun] = 0;
5171f7ea1cdSQi Zhang 		}
5181f7ea1cdSQi Zhang 
5191f7ea1cdSQi Zhang 	ice_flow_rem_prof(hw, ICE_BLK_FD, prof_id);
5201f7ea1cdSQi Zhang 	devm_kfree(dev, vf_prof->fdir_seg[tun]);
5211f7ea1cdSQi Zhang 	vf_prof->fdir_seg[tun] = NULL;
5221f7ea1cdSQi Zhang 
5231f7ea1cdSQi Zhang 	for (i = 0; i < vf_prof->cnt; i++)
5241f7ea1cdSQi Zhang 		vf_prof->vsi_h[i] = 0;
5251f7ea1cdSQi Zhang 
5261f7ea1cdSQi Zhang 	fdir->prof_entry_cnt[flow][tun] = 0;
5271f7ea1cdSQi Zhang }
5281f7ea1cdSQi Zhang 
5291f7ea1cdSQi Zhang /**
5301f7ea1cdSQi Zhang  * ice_vc_fdir_rem_prof_all - remove profile for this VF
5311f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
5321f7ea1cdSQi Zhang  */
5331f7ea1cdSQi Zhang static void ice_vc_fdir_rem_prof_all(struct ice_vf *vf)
5341f7ea1cdSQi Zhang {
5351f7ea1cdSQi Zhang 	enum ice_fltr_ptype flow;
5361f7ea1cdSQi Zhang 
5371f7ea1cdSQi Zhang 	for (flow = ICE_FLTR_PTYPE_NONF_NONE;
5381f7ea1cdSQi Zhang 	     flow < ICE_FLTR_PTYPE_MAX; flow++) {
5391f7ea1cdSQi Zhang 		ice_vc_fdir_rem_prof(vf, flow, 0);
5401f7ea1cdSQi Zhang 		ice_vc_fdir_rem_prof(vf, flow, 1);
5411f7ea1cdSQi Zhang 	}
5421f7ea1cdSQi Zhang }
5431f7ea1cdSQi Zhang 
5441f7ea1cdSQi Zhang /**
54529486b6dSJunfeng Guo  * ice_vc_fdir_has_prof_conflict
54629486b6dSJunfeng Guo  * @vf: pointer to the VF structure
54729486b6dSJunfeng Guo  * @conf: FDIR configuration for each filter
54829486b6dSJunfeng Guo  *
54929486b6dSJunfeng Guo  * Check if @conf has conflicting profile with existing profiles
55029486b6dSJunfeng Guo  *
55129486b6dSJunfeng Guo  * Return: true on success, and false on error.
55229486b6dSJunfeng Guo  */
55329486b6dSJunfeng Guo static bool
55429486b6dSJunfeng Guo ice_vc_fdir_has_prof_conflict(struct ice_vf *vf,
55529486b6dSJunfeng Guo 			      struct virtchnl_fdir_fltr_conf *conf)
55629486b6dSJunfeng Guo {
55729486b6dSJunfeng Guo 	struct ice_fdir_fltr *desc;
55829486b6dSJunfeng Guo 
55929486b6dSJunfeng Guo 	list_for_each_entry(desc, &vf->fdir.fdir_rule_list, fltr_node) {
56029486b6dSJunfeng Guo 		struct virtchnl_fdir_fltr_conf *existing_conf;
56129486b6dSJunfeng Guo 		enum ice_fltr_ptype flow_type_a, flow_type_b;
56229486b6dSJunfeng Guo 		struct ice_fdir_fltr *a, *b;
56329486b6dSJunfeng Guo 
56429486b6dSJunfeng Guo 		existing_conf = to_fltr_conf_from_desc(desc);
56529486b6dSJunfeng Guo 		a = &existing_conf->input;
56629486b6dSJunfeng Guo 		b = &conf->input;
56729486b6dSJunfeng Guo 		flow_type_a = a->flow_type;
56829486b6dSJunfeng Guo 		flow_type_b = b->flow_type;
56929486b6dSJunfeng Guo 
57029486b6dSJunfeng Guo 		/* No need to compare two rules with different tunnel types or
57129486b6dSJunfeng Guo 		 * with the same protocol type.
57229486b6dSJunfeng Guo 		 */
57329486b6dSJunfeng Guo 		if (existing_conf->ttype != conf->ttype ||
57429486b6dSJunfeng Guo 		    flow_type_a == flow_type_b)
57529486b6dSJunfeng Guo 			continue;
57629486b6dSJunfeng Guo 
57729486b6dSJunfeng Guo 		switch (flow_type_a) {
57829486b6dSJunfeng Guo 		case ICE_FLTR_PTYPE_NONF_IPV4_UDP:
57929486b6dSJunfeng Guo 		case ICE_FLTR_PTYPE_NONF_IPV4_TCP:
58029486b6dSJunfeng Guo 		case ICE_FLTR_PTYPE_NONF_IPV4_SCTP:
58129486b6dSJunfeng Guo 			if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_OTHER)
58229486b6dSJunfeng Guo 				return true;
58329486b6dSJunfeng Guo 			break;
58429486b6dSJunfeng Guo 		case ICE_FLTR_PTYPE_NONF_IPV4_OTHER:
58529486b6dSJunfeng Guo 			if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_UDP ||
58629486b6dSJunfeng Guo 			    flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_TCP ||
58729486b6dSJunfeng Guo 			    flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_SCTP)
58829486b6dSJunfeng Guo 				return true;
58929486b6dSJunfeng Guo 			break;
59029486b6dSJunfeng Guo 		case ICE_FLTR_PTYPE_NONF_IPV6_UDP:
59129486b6dSJunfeng Guo 		case ICE_FLTR_PTYPE_NONF_IPV6_TCP:
59229486b6dSJunfeng Guo 		case ICE_FLTR_PTYPE_NONF_IPV6_SCTP:
59329486b6dSJunfeng Guo 			if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_OTHER)
59429486b6dSJunfeng Guo 				return true;
59529486b6dSJunfeng Guo 			break;
59629486b6dSJunfeng Guo 		case ICE_FLTR_PTYPE_NONF_IPV6_OTHER:
59729486b6dSJunfeng Guo 			if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_UDP ||
59829486b6dSJunfeng Guo 			    flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_TCP ||
59929486b6dSJunfeng Guo 			    flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_SCTP)
60029486b6dSJunfeng Guo 				return true;
60129486b6dSJunfeng Guo 			break;
60229486b6dSJunfeng Guo 		default:
60329486b6dSJunfeng Guo 			break;
60429486b6dSJunfeng Guo 		}
60529486b6dSJunfeng Guo 	}
60629486b6dSJunfeng Guo 
60729486b6dSJunfeng Guo 	return false;
60829486b6dSJunfeng Guo }
60929486b6dSJunfeng Guo 
61029486b6dSJunfeng Guo /**
6111f7ea1cdSQi Zhang  * ice_vc_fdir_write_flow_prof
6121f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
6131f7ea1cdSQi Zhang  * @flow: filter flow type
6141f7ea1cdSQi Zhang  * @seg: array of one or more packet segments that describe the flow
6151f7ea1cdSQi Zhang  * @tun: 0 implies non-tunnel type filter, 1 implies tunnel type filter
6161f7ea1cdSQi Zhang  *
6171f7ea1cdSQi Zhang  * Write the flow's profile config and packet segment into the hardware
6181f7ea1cdSQi Zhang  *
6191f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
6201f7ea1cdSQi Zhang  */
6211f7ea1cdSQi Zhang static int
6221f7ea1cdSQi Zhang ice_vc_fdir_write_flow_prof(struct ice_vf *vf, enum ice_fltr_ptype flow,
6231f7ea1cdSQi Zhang 			    struct ice_flow_seg_info *seg, int tun)
6241f7ea1cdSQi Zhang {
6251f7ea1cdSQi Zhang 	struct ice_vf_fdir *fdir = &vf->fdir;
6261f7ea1cdSQi Zhang 	struct ice_vsi *vf_vsi, *ctrl_vsi;
6271f7ea1cdSQi Zhang 	struct ice_flow_seg_info *old_seg;
6281f7ea1cdSQi Zhang 	struct ice_flow_prof *prof = NULL;
6291f7ea1cdSQi Zhang 	struct ice_fd_hw_prof *vf_prof;
6301f7ea1cdSQi Zhang 	struct device *dev;
6311f7ea1cdSQi Zhang 	struct ice_pf *pf;
6321f7ea1cdSQi Zhang 	struct ice_hw *hw;
6331f7ea1cdSQi Zhang 	u64 entry1_h = 0;
6341f7ea1cdSQi Zhang 	u64 entry2_h = 0;
6351f7ea1cdSQi Zhang 	u64 prof_id;
6361f7ea1cdSQi Zhang 	int ret;
6371f7ea1cdSQi Zhang 
6381f7ea1cdSQi Zhang 	pf = vf->pf;
6391f7ea1cdSQi Zhang 	dev = ice_pf_to_dev(pf);
6401f7ea1cdSQi Zhang 	hw = &pf->hw;
641772dec64SBrett Creeley 	vf_vsi = ice_get_vf_vsi(vf);
6421f7ea1cdSQi Zhang 	if (!vf_vsi)
6431f7ea1cdSQi Zhang 		return -EINVAL;
6441f7ea1cdSQi Zhang 
6451f7ea1cdSQi Zhang 	ctrl_vsi = pf->vsi[vf->ctrl_vsi_idx];
6461f7ea1cdSQi Zhang 	if (!ctrl_vsi)
6471f7ea1cdSQi Zhang 		return -EINVAL;
6481f7ea1cdSQi Zhang 
6491f7ea1cdSQi Zhang 	vf_prof = fdir->fdir_prof[flow];
6501f7ea1cdSQi Zhang 	old_seg = vf_prof->fdir_seg[tun];
6511f7ea1cdSQi Zhang 	if (old_seg) {
6521f7ea1cdSQi Zhang 		if (!memcmp(old_seg, seg, sizeof(*seg))) {
6531f7ea1cdSQi Zhang 			dev_dbg(dev, "Duplicated profile for VF %d!\n",
6541f7ea1cdSQi Zhang 				vf->vf_id);
6551f7ea1cdSQi Zhang 			return -EEXIST;
6561f7ea1cdSQi Zhang 		}
6571f7ea1cdSQi Zhang 
6581f7ea1cdSQi Zhang 		if (fdir->fdir_fltr_cnt[flow][tun]) {
6591f7ea1cdSQi Zhang 			ret = -EINVAL;
6601f7ea1cdSQi Zhang 			dev_dbg(dev, "Input set conflicts for VF %d\n",
6611f7ea1cdSQi Zhang 				vf->vf_id);
6621f7ea1cdSQi Zhang 			goto err_exit;
6631f7ea1cdSQi Zhang 		}
6641f7ea1cdSQi Zhang 
6651f7ea1cdSQi Zhang 		/* remove previously allocated profile */
6661f7ea1cdSQi Zhang 		ice_vc_fdir_rem_prof(vf, flow, tun);
6671f7ea1cdSQi Zhang 	}
6681f7ea1cdSQi Zhang 
6691f7ea1cdSQi Zhang 	prof_id = ICE_FLOW_PROF_FD(vf_vsi->vsi_num, flow,
6701f7ea1cdSQi Zhang 				   tun ? ICE_FLTR_PTYPE_MAX : 0);
6711f7ea1cdSQi Zhang 
6722ccc1c1cSTony Nguyen 	ret = ice_flow_add_prof(hw, ICE_BLK_FD, ICE_FLOW_RX, prof_id, seg,
6731f7ea1cdSQi Zhang 				tun + 1, &prof);
6741f7ea1cdSQi Zhang 	if (ret) {
6751f7ea1cdSQi Zhang 		dev_dbg(dev, "Could not add VSI flow 0x%x for VF %d\n",
6761f7ea1cdSQi Zhang 			flow, vf->vf_id);
6771f7ea1cdSQi Zhang 		goto err_exit;
6781f7ea1cdSQi Zhang 	}
6791f7ea1cdSQi Zhang 
6802ccc1c1cSTony Nguyen 	ret = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id, vf_vsi->idx,
6811f7ea1cdSQi Zhang 				 vf_vsi->idx, ICE_FLOW_PRIO_NORMAL,
6821f7ea1cdSQi Zhang 				 seg, &entry1_h);
6831f7ea1cdSQi Zhang 	if (ret) {
6841f7ea1cdSQi Zhang 		dev_dbg(dev, "Could not add flow 0x%x VSI entry for VF %d\n",
6851f7ea1cdSQi Zhang 			flow, vf->vf_id);
6861f7ea1cdSQi Zhang 		goto err_prof;
6871f7ea1cdSQi Zhang 	}
6881f7ea1cdSQi Zhang 
6892ccc1c1cSTony Nguyen 	ret = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id, vf_vsi->idx,
6901f7ea1cdSQi Zhang 				 ctrl_vsi->idx, ICE_FLOW_PRIO_NORMAL,
6911f7ea1cdSQi Zhang 				 seg, &entry2_h);
6921f7ea1cdSQi Zhang 	if (ret) {
6931f7ea1cdSQi Zhang 		dev_dbg(dev,
6941f7ea1cdSQi Zhang 			"Could not add flow 0x%x Ctrl VSI entry for VF %d\n",
6951f7ea1cdSQi Zhang 			flow, vf->vf_id);
6961f7ea1cdSQi Zhang 		goto err_entry_1;
6971f7ea1cdSQi Zhang 	}
6981f7ea1cdSQi Zhang 
6991f7ea1cdSQi Zhang 	vf_prof->fdir_seg[tun] = seg;
7001f7ea1cdSQi Zhang 	vf_prof->cnt = 0;
7011f7ea1cdSQi Zhang 	fdir->prof_entry_cnt[flow][tun] = 0;
7021f7ea1cdSQi Zhang 
7031f7ea1cdSQi Zhang 	vf_prof->entry_h[vf_prof->cnt][tun] = entry1_h;
7041f7ea1cdSQi Zhang 	vf_prof->vsi_h[vf_prof->cnt] = vf_vsi->idx;
7051f7ea1cdSQi Zhang 	vf_prof->cnt++;
7061f7ea1cdSQi Zhang 	fdir->prof_entry_cnt[flow][tun]++;
7071f7ea1cdSQi Zhang 
7081f7ea1cdSQi Zhang 	vf_prof->entry_h[vf_prof->cnt][tun] = entry2_h;
7091f7ea1cdSQi Zhang 	vf_prof->vsi_h[vf_prof->cnt] = ctrl_vsi->idx;
7101f7ea1cdSQi Zhang 	vf_prof->cnt++;
7111f7ea1cdSQi Zhang 	fdir->prof_entry_cnt[flow][tun]++;
7121f7ea1cdSQi Zhang 
7131f7ea1cdSQi Zhang 	return 0;
7141f7ea1cdSQi Zhang 
7151f7ea1cdSQi Zhang err_entry_1:
7161f7ea1cdSQi Zhang 	ice_rem_prof_id_flow(hw, ICE_BLK_FD,
7171f7ea1cdSQi Zhang 			     ice_get_hw_vsi_num(hw, vf_vsi->idx), prof_id);
7181f7ea1cdSQi Zhang 	ice_flow_rem_entry(hw, ICE_BLK_FD, entry1_h);
7191f7ea1cdSQi Zhang err_prof:
7201f7ea1cdSQi Zhang 	ice_flow_rem_prof(hw, ICE_BLK_FD, prof_id);
7211f7ea1cdSQi Zhang err_exit:
7221f7ea1cdSQi Zhang 	return ret;
7231f7ea1cdSQi Zhang }
7241f7ea1cdSQi Zhang 
7251f7ea1cdSQi Zhang /**
7261f7ea1cdSQi Zhang  * ice_vc_fdir_config_input_set
7271f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
7281f7ea1cdSQi Zhang  * @fltr: virtual channel add cmd buffer
7291f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
7301f7ea1cdSQi Zhang  * @tun: 0 implies non-tunnel type filter, 1 implies tunnel type filter
7311f7ea1cdSQi Zhang  *
7321f7ea1cdSQi Zhang  * Config the input set type and value for virtual channel add msg buffer
7331f7ea1cdSQi Zhang  *
7341f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
7351f7ea1cdSQi Zhang  */
7361f7ea1cdSQi Zhang static int
7371f7ea1cdSQi Zhang ice_vc_fdir_config_input_set(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
7381f7ea1cdSQi Zhang 			     struct virtchnl_fdir_fltr_conf *conf, int tun)
7391f7ea1cdSQi Zhang {
7401f7ea1cdSQi Zhang 	struct ice_fdir_fltr *input = &conf->input;
7411f7ea1cdSQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
7421f7ea1cdSQi Zhang 	struct ice_flow_seg_info *seg;
7431f7ea1cdSQi Zhang 	enum ice_fltr_ptype flow;
7441f7ea1cdSQi Zhang 	int ret;
7451f7ea1cdSQi Zhang 
74629486b6dSJunfeng Guo 	ret = ice_vc_fdir_has_prof_conflict(vf, conf);
74729486b6dSJunfeng Guo 	if (ret) {
74829486b6dSJunfeng Guo 		dev_dbg(dev, "Found flow profile conflict for VF %d\n",
74929486b6dSJunfeng Guo 			vf->vf_id);
75029486b6dSJunfeng Guo 		return ret;
75129486b6dSJunfeng Guo 	}
75229486b6dSJunfeng Guo 
7531f7ea1cdSQi Zhang 	flow = input->flow_type;
7541f7ea1cdSQi Zhang 	ret = ice_vc_fdir_alloc_prof(vf, flow);
7551f7ea1cdSQi Zhang 	if (ret) {
7561f7ea1cdSQi Zhang 		dev_dbg(dev, "Alloc flow prof for VF %d failed\n", vf->vf_id);
7571f7ea1cdSQi Zhang 		return ret;
7581f7ea1cdSQi Zhang 	}
7591f7ea1cdSQi Zhang 
7601f7ea1cdSQi Zhang 	seg = devm_kzalloc(dev, sizeof(*seg), GFP_KERNEL);
7611f7ea1cdSQi Zhang 	if (!seg)
7621f7ea1cdSQi Zhang 		return -ENOMEM;
7631f7ea1cdSQi Zhang 
7641f7ea1cdSQi Zhang 	ret = ice_vc_fdir_set_flow_fld(vf, fltr, conf, seg);
7651f7ea1cdSQi Zhang 	if (ret) {
7661f7ea1cdSQi Zhang 		dev_dbg(dev, "Set flow field for VF %d failed\n", vf->vf_id);
7671f7ea1cdSQi Zhang 		goto err_exit;
7681f7ea1cdSQi Zhang 	}
7691f7ea1cdSQi Zhang 
7701f7ea1cdSQi Zhang 	ret = ice_vc_fdir_set_flow_hdr(vf, conf, seg);
7711f7ea1cdSQi Zhang 	if (ret) {
7721f7ea1cdSQi Zhang 		dev_dbg(dev, "Set flow hdr for VF %d failed\n", vf->vf_id);
7731f7ea1cdSQi Zhang 		goto err_exit;
7741f7ea1cdSQi Zhang 	}
7751f7ea1cdSQi Zhang 
7761f7ea1cdSQi Zhang 	ret = ice_vc_fdir_write_flow_prof(vf, flow, seg, tun);
7771f7ea1cdSQi Zhang 	if (ret == -EEXIST) {
7781f7ea1cdSQi Zhang 		devm_kfree(dev, seg);
7791f7ea1cdSQi Zhang 	} else if (ret) {
7801f7ea1cdSQi Zhang 		dev_dbg(dev, "Write flow profile for VF %d failed\n",
7811f7ea1cdSQi Zhang 			vf->vf_id);
7821f7ea1cdSQi Zhang 		goto err_exit;
7831f7ea1cdSQi Zhang 	}
7841f7ea1cdSQi Zhang 
7851f7ea1cdSQi Zhang 	return 0;
7861f7ea1cdSQi Zhang 
7871f7ea1cdSQi Zhang err_exit:
7881f7ea1cdSQi Zhang 	devm_kfree(dev, seg);
7891f7ea1cdSQi Zhang 	return ret;
7901f7ea1cdSQi Zhang }
7911f7ea1cdSQi Zhang 
7921f7ea1cdSQi Zhang /**
7930ce332fdSQi Zhang  * ice_vc_fdir_parse_pattern
7940ce332fdSQi Zhang  * @vf: pointer to the VF info
7950ce332fdSQi Zhang  * @fltr: virtual channel add cmd buffer
7960ce332fdSQi Zhang  * @conf: FDIR configuration for each filter
7970ce332fdSQi Zhang  *
7980ce332fdSQi Zhang  * Parse the virtual channel filter's pattern and store them into conf
7990ce332fdSQi Zhang  *
8000ce332fdSQi Zhang  * Return: 0 on success, and other on error.
8010ce332fdSQi Zhang  */
8020ce332fdSQi Zhang static int
8030ce332fdSQi Zhang ice_vc_fdir_parse_pattern(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
8040ce332fdSQi Zhang 			  struct virtchnl_fdir_fltr_conf *conf)
8050ce332fdSQi Zhang {
8060ce332fdSQi Zhang 	struct virtchnl_proto_hdrs *proto = &fltr->rule_cfg.proto_hdrs;
8070ce332fdSQi Zhang 	enum virtchnl_proto_hdr_type l3 = VIRTCHNL_PROTO_HDR_NONE;
808213528feSQi Zhang 	enum virtchnl_proto_hdr_type l4 = VIRTCHNL_PROTO_HDR_NONE;
8090ce332fdSQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
8100ce332fdSQi Zhang 	struct ice_fdir_fltr *input = &conf->input;
8110ce332fdSQi Zhang 	int i;
8120ce332fdSQi Zhang 
8130ce332fdSQi Zhang 	if (proto->count > VIRTCHNL_MAX_NUM_PROTO_HDRS) {
8140ce332fdSQi Zhang 		dev_dbg(dev, "Invalid protocol count:0x%x for VF %d\n",
8150ce332fdSQi Zhang 			proto->count, vf->vf_id);
8160ce332fdSQi Zhang 		return -EINVAL;
8170ce332fdSQi Zhang 	}
8180ce332fdSQi Zhang 
8190ce332fdSQi Zhang 	for (i = 0; i < proto->count; i++) {
8200ce332fdSQi Zhang 		struct virtchnl_proto_hdr *hdr = &proto->proto_hdr[i];
821213528feSQi Zhang 		struct ip_esp_hdr *esph;
822213528feSQi Zhang 		struct ip_auth_hdr *ah;
8230ce332fdSQi Zhang 		struct sctphdr *sctph;
8240ce332fdSQi Zhang 		struct ipv6hdr *ip6h;
8250ce332fdSQi Zhang 		struct udphdr *udph;
8260ce332fdSQi Zhang 		struct tcphdr *tcph;
82721606584SQi Zhang 		struct ethhdr *eth;
8280ce332fdSQi Zhang 		struct iphdr *iph;
829213528feSQi Zhang 		u8 s_field;
830ef9e4cc5SQi Zhang 		u8 *rawh;
8310ce332fdSQi Zhang 
8320ce332fdSQi Zhang 		switch (hdr->type) {
8330ce332fdSQi Zhang 		case VIRTCHNL_PROTO_HDR_ETH:
83421606584SQi Zhang 			eth = (struct ethhdr *)hdr->buffer;
83521606584SQi Zhang 			input->flow_type = ICE_FLTR_PTYPE_NON_IP_L2;
83621606584SQi Zhang 
83721606584SQi Zhang 			if (hdr->field_selector)
83821606584SQi Zhang 				input->ext_data.ether_type = eth->h_proto;
8390ce332fdSQi Zhang 			break;
8400ce332fdSQi Zhang 		case VIRTCHNL_PROTO_HDR_IPV4:
8410ce332fdSQi Zhang 			iph = (struct iphdr *)hdr->buffer;
8420ce332fdSQi Zhang 			l3 = VIRTCHNL_PROTO_HDR_IPV4;
8430ce332fdSQi Zhang 			input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_OTHER;
8440ce332fdSQi Zhang 
8450ce332fdSQi Zhang 			if (hdr->field_selector) {
8460ce332fdSQi Zhang 				input->ip.v4.src_ip = iph->saddr;
8470ce332fdSQi Zhang 				input->ip.v4.dst_ip = iph->daddr;
8480ce332fdSQi Zhang 				input->ip.v4.tos = iph->tos;
8490ce332fdSQi Zhang 				input->ip.v4.proto = iph->protocol;
8500ce332fdSQi Zhang 			}
8510ce332fdSQi Zhang 			break;
8520ce332fdSQi Zhang 		case VIRTCHNL_PROTO_HDR_IPV6:
8530ce332fdSQi Zhang 			ip6h = (struct ipv6hdr *)hdr->buffer;
8540ce332fdSQi Zhang 			l3 = VIRTCHNL_PROTO_HDR_IPV6;
8550ce332fdSQi Zhang 			input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_OTHER;
8560ce332fdSQi Zhang 
8570ce332fdSQi Zhang 			if (hdr->field_selector) {
8580ce332fdSQi Zhang 				memcpy(input->ip.v6.src_ip,
8590ce332fdSQi Zhang 				       ip6h->saddr.in6_u.u6_addr8,
8600ce332fdSQi Zhang 				       sizeof(ip6h->saddr));
8610ce332fdSQi Zhang 				memcpy(input->ip.v6.dst_ip,
8620ce332fdSQi Zhang 				       ip6h->daddr.in6_u.u6_addr8,
8630ce332fdSQi Zhang 				       sizeof(ip6h->daddr));
8640ce332fdSQi Zhang 				input->ip.v6.tc = ((u8)(ip6h->priority) << 4) |
8650ce332fdSQi Zhang 						  (ip6h->flow_lbl[0] >> 4);
8660ce332fdSQi Zhang 				input->ip.v6.proto = ip6h->nexthdr;
8670ce332fdSQi Zhang 			}
8680ce332fdSQi Zhang 			break;
8690ce332fdSQi Zhang 		case VIRTCHNL_PROTO_HDR_TCP:
8700ce332fdSQi Zhang 			tcph = (struct tcphdr *)hdr->buffer;
8710ce332fdSQi Zhang 			if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
8720ce332fdSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_TCP;
8730ce332fdSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
8740ce332fdSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_TCP;
8750ce332fdSQi Zhang 
8760ce332fdSQi Zhang 			if (hdr->field_selector) {
8770ce332fdSQi Zhang 				if (l3 == VIRTCHNL_PROTO_HDR_IPV4) {
8780ce332fdSQi Zhang 					input->ip.v4.src_port = tcph->source;
8790ce332fdSQi Zhang 					input->ip.v4.dst_port = tcph->dest;
8800ce332fdSQi Zhang 				} else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) {
8810ce332fdSQi Zhang 					input->ip.v6.src_port = tcph->source;
8820ce332fdSQi Zhang 					input->ip.v6.dst_port = tcph->dest;
8830ce332fdSQi Zhang 				}
8840ce332fdSQi Zhang 			}
8850ce332fdSQi Zhang 			break;
8860ce332fdSQi Zhang 		case VIRTCHNL_PROTO_HDR_UDP:
8870ce332fdSQi Zhang 			udph = (struct udphdr *)hdr->buffer;
8880ce332fdSQi Zhang 			if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
8890ce332fdSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_UDP;
8900ce332fdSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
8910ce332fdSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_UDP;
8920ce332fdSQi Zhang 
8930ce332fdSQi Zhang 			if (hdr->field_selector) {
8940ce332fdSQi Zhang 				if (l3 == VIRTCHNL_PROTO_HDR_IPV4) {
8950ce332fdSQi Zhang 					input->ip.v4.src_port = udph->source;
8960ce332fdSQi Zhang 					input->ip.v4.dst_port = udph->dest;
8970ce332fdSQi Zhang 				} else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) {
8980ce332fdSQi Zhang 					input->ip.v6.src_port = udph->source;
8990ce332fdSQi Zhang 					input->ip.v6.dst_port = udph->dest;
9000ce332fdSQi Zhang 				}
9010ce332fdSQi Zhang 			}
9020ce332fdSQi Zhang 			break;
9030ce332fdSQi Zhang 		case VIRTCHNL_PROTO_HDR_SCTP:
9040ce332fdSQi Zhang 			sctph = (struct sctphdr *)hdr->buffer;
9050ce332fdSQi Zhang 			if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
9060ce332fdSQi Zhang 				input->flow_type =
9070ce332fdSQi Zhang 					ICE_FLTR_PTYPE_NONF_IPV4_SCTP;
9080ce332fdSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
9090ce332fdSQi Zhang 				input->flow_type =
9100ce332fdSQi Zhang 					ICE_FLTR_PTYPE_NONF_IPV6_SCTP;
9110ce332fdSQi Zhang 
9120ce332fdSQi Zhang 			if (hdr->field_selector) {
9130ce332fdSQi Zhang 				if (l3 == VIRTCHNL_PROTO_HDR_IPV4) {
9140ce332fdSQi Zhang 					input->ip.v4.src_port = sctph->source;
9150ce332fdSQi Zhang 					input->ip.v4.dst_port = sctph->dest;
9160ce332fdSQi Zhang 				} else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) {
9170ce332fdSQi Zhang 					input->ip.v6.src_port = sctph->source;
9180ce332fdSQi Zhang 					input->ip.v6.dst_port = sctph->dest;
9190ce332fdSQi Zhang 				}
9200ce332fdSQi Zhang 			}
9210ce332fdSQi Zhang 			break;
922213528feSQi Zhang 		case VIRTCHNL_PROTO_HDR_L2TPV3:
923213528feSQi Zhang 			if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
924213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_L2TPV3;
925213528feSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
926213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_L2TPV3;
927213528feSQi Zhang 
928213528feSQi Zhang 			if (hdr->field_selector)
929213528feSQi Zhang 				input->l2tpv3_data.session_id = *((__be32 *)hdr->buffer);
930213528feSQi Zhang 			break;
931213528feSQi Zhang 		case VIRTCHNL_PROTO_HDR_ESP:
932213528feSQi Zhang 			esph = (struct ip_esp_hdr *)hdr->buffer;
933213528feSQi Zhang 			if (l3 == VIRTCHNL_PROTO_HDR_IPV4 &&
934213528feSQi Zhang 			    l4 == VIRTCHNL_PROTO_HDR_UDP)
935213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_NAT_T_ESP;
936213528feSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 &&
937213528feSQi Zhang 				 l4 == VIRTCHNL_PROTO_HDR_UDP)
938213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_NAT_T_ESP;
939213528feSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV4 &&
940213528feSQi Zhang 				 l4 == VIRTCHNL_PROTO_HDR_NONE)
941213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_ESP;
942213528feSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 &&
943213528feSQi Zhang 				 l4 == VIRTCHNL_PROTO_HDR_NONE)
944213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_ESP;
945213528feSQi Zhang 
946213528feSQi Zhang 			if (l4 == VIRTCHNL_PROTO_HDR_UDP)
947213528feSQi Zhang 				conf->inset_flag |= FDIR_INSET_FLAG_ESP_UDP;
948213528feSQi Zhang 			else
949213528feSQi Zhang 				conf->inset_flag |= FDIR_INSET_FLAG_ESP_IPSEC;
950213528feSQi Zhang 
951213528feSQi Zhang 			if (hdr->field_selector) {
952213528feSQi Zhang 				if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
953213528feSQi Zhang 					input->ip.v4.sec_parm_idx = esph->spi;
954213528feSQi Zhang 				else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
955213528feSQi Zhang 					input->ip.v6.sec_parm_idx = esph->spi;
956213528feSQi Zhang 			}
957213528feSQi Zhang 			break;
958213528feSQi Zhang 		case VIRTCHNL_PROTO_HDR_AH:
959213528feSQi Zhang 			ah = (struct ip_auth_hdr *)hdr->buffer;
960213528feSQi Zhang 			if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
961213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_AH;
962213528feSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
963213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_AH;
964213528feSQi Zhang 
965213528feSQi Zhang 			if (hdr->field_selector) {
966213528feSQi Zhang 				if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
967213528feSQi Zhang 					input->ip.v4.sec_parm_idx = ah->spi;
968213528feSQi Zhang 				else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
969213528feSQi Zhang 					input->ip.v6.sec_parm_idx = ah->spi;
970213528feSQi Zhang 			}
971213528feSQi Zhang 			break;
972213528feSQi Zhang 		case VIRTCHNL_PROTO_HDR_PFCP:
973213528feSQi Zhang 			rawh = (u8 *)hdr->buffer;
974213528feSQi Zhang 			s_field = (rawh[0] >> PFCP_S_OFFSET) & PFCP_S_MASK;
975213528feSQi Zhang 			if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && s_field == 0)
976213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_PFCP_NODE;
977213528feSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && s_field == 1)
978213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_PFCP_SESSION;
979213528feSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && s_field == 0)
980213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_PFCP_NODE;
981213528feSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && s_field == 1)
982213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_PFCP_SESSION;
983213528feSQi Zhang 
984213528feSQi Zhang 			if (hdr->field_selector) {
985213528feSQi Zhang 				if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
986213528feSQi Zhang 					input->ip.v4.dst_port = cpu_to_be16(PFCP_PORT_NR);
987213528feSQi Zhang 				else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
988213528feSQi Zhang 					input->ip.v6.dst_port = cpu_to_be16(PFCP_PORT_NR);
989213528feSQi Zhang 			}
990213528feSQi Zhang 			break;
991ef9e4cc5SQi Zhang 		case VIRTCHNL_PROTO_HDR_GTPU_IP:
992ef9e4cc5SQi Zhang 			rawh = (u8 *)hdr->buffer;
993ef9e4cc5SQi Zhang 			input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER;
994ef9e4cc5SQi Zhang 
995ef9e4cc5SQi Zhang 			if (hdr->field_selector)
996ef9e4cc5SQi Zhang 				input->gtpu_data.teid = *(__be32 *)(&rawh[GTPU_TEID_OFFSET]);
997ef9e4cc5SQi Zhang 			conf->ttype = ICE_FDIR_TUNNEL_TYPE_GTPU;
998ef9e4cc5SQi Zhang 			break;
999ef9e4cc5SQi Zhang 		case VIRTCHNL_PROTO_HDR_GTPU_EH:
1000ef9e4cc5SQi Zhang 			rawh = (u8 *)hdr->buffer;
1001ef9e4cc5SQi Zhang 
1002ef9e4cc5SQi Zhang 			if (hdr->field_selector)
1003ef9e4cc5SQi Zhang 				input->gtpu_data.qfi = rawh[GTPU_EH_QFI_OFFSET] & GTPU_EH_QFI_MASK;
1004ef9e4cc5SQi Zhang 			conf->ttype = ICE_FDIR_TUNNEL_TYPE_GTPU_EH;
1005ef9e4cc5SQi Zhang 			break;
10060ce332fdSQi Zhang 		default:
10070ce332fdSQi Zhang 			dev_dbg(dev, "Invalid header type 0x:%x for VF %d\n",
10080ce332fdSQi Zhang 				hdr->type, vf->vf_id);
10090ce332fdSQi Zhang 			return -EINVAL;
10100ce332fdSQi Zhang 		}
10110ce332fdSQi Zhang 	}
10120ce332fdSQi Zhang 
10130ce332fdSQi Zhang 	return 0;
10140ce332fdSQi Zhang }
10150ce332fdSQi Zhang 
10160ce332fdSQi Zhang /**
10170ce332fdSQi Zhang  * ice_vc_fdir_parse_action
10180ce332fdSQi Zhang  * @vf: pointer to the VF info
10190ce332fdSQi Zhang  * @fltr: virtual channel add cmd buffer
10200ce332fdSQi Zhang  * @conf: FDIR configuration for each filter
10210ce332fdSQi Zhang  *
10220ce332fdSQi Zhang  * Parse the virtual channel filter's action and store them into conf
10230ce332fdSQi Zhang  *
10240ce332fdSQi Zhang  * Return: 0 on success, and other on error.
10250ce332fdSQi Zhang  */
10260ce332fdSQi Zhang static int
10270ce332fdSQi Zhang ice_vc_fdir_parse_action(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
10280ce332fdSQi Zhang 			 struct virtchnl_fdir_fltr_conf *conf)
10290ce332fdSQi Zhang {
10300ce332fdSQi Zhang 	struct virtchnl_filter_action_set *as = &fltr->rule_cfg.action_set;
10310ce332fdSQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
10320ce332fdSQi Zhang 	struct ice_fdir_fltr *input = &conf->input;
10330ce332fdSQi Zhang 	u32 dest_num = 0;
10340ce332fdSQi Zhang 	u32 mark_num = 0;
10350ce332fdSQi Zhang 	int i;
10360ce332fdSQi Zhang 
10370ce332fdSQi Zhang 	if (as->count > VIRTCHNL_MAX_NUM_ACTIONS) {
10380ce332fdSQi Zhang 		dev_dbg(dev, "Invalid action numbers:0x%x for VF %d\n",
10390ce332fdSQi Zhang 			as->count, vf->vf_id);
10400ce332fdSQi Zhang 		return -EINVAL;
10410ce332fdSQi Zhang 	}
10420ce332fdSQi Zhang 
10430ce332fdSQi Zhang 	for (i = 0; i < as->count; i++) {
10440ce332fdSQi Zhang 		struct virtchnl_filter_action *action = &as->actions[i];
10450ce332fdSQi Zhang 
10460ce332fdSQi Zhang 		switch (action->type) {
1047346bf250SQi Zhang 		case VIRTCHNL_ACTION_PASSTHRU:
1048346bf250SQi Zhang 			dest_num++;
1049346bf250SQi Zhang 			input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_OTHER;
1050346bf250SQi Zhang 			break;
10510ce332fdSQi Zhang 		case VIRTCHNL_ACTION_DROP:
10520ce332fdSQi Zhang 			dest_num++;
10530ce332fdSQi Zhang 			input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DROP_PKT;
10540ce332fdSQi Zhang 			break;
10550ce332fdSQi Zhang 		case VIRTCHNL_ACTION_QUEUE:
10560ce332fdSQi Zhang 			dest_num++;
10570ce332fdSQi Zhang 			input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QINDEX;
10580ce332fdSQi Zhang 			input->q_index = action->act_conf.queue.index;
10590ce332fdSQi Zhang 			break;
1060346bf250SQi Zhang 		case VIRTCHNL_ACTION_Q_REGION:
1061346bf250SQi Zhang 			dest_num++;
1062346bf250SQi Zhang 			input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QGROUP;
1063346bf250SQi Zhang 			input->q_index = action->act_conf.queue.index;
1064346bf250SQi Zhang 			input->q_region = action->act_conf.queue.region;
1065346bf250SQi Zhang 			break;
10660ce332fdSQi Zhang 		case VIRTCHNL_ACTION_MARK:
10670ce332fdSQi Zhang 			mark_num++;
10680ce332fdSQi Zhang 			input->fltr_id = action->act_conf.mark_id;
10690ce332fdSQi Zhang 			input->fdid_prio = ICE_FXD_FLTR_QW1_FDID_PRI_THREE;
10700ce332fdSQi Zhang 			break;
10710ce332fdSQi Zhang 		default:
10720ce332fdSQi Zhang 			dev_dbg(dev, "Invalid action type:0x%x for VF %d\n",
10730ce332fdSQi Zhang 				action->type, vf->vf_id);
10740ce332fdSQi Zhang 			return -EINVAL;
10750ce332fdSQi Zhang 		}
10760ce332fdSQi Zhang 	}
10770ce332fdSQi Zhang 
10780ce332fdSQi Zhang 	if (dest_num == 0 || dest_num >= 2) {
10790ce332fdSQi Zhang 		dev_dbg(dev, "Invalid destination action for VF %d\n",
10800ce332fdSQi Zhang 			vf->vf_id);
10810ce332fdSQi Zhang 		return -EINVAL;
10820ce332fdSQi Zhang 	}
10830ce332fdSQi Zhang 
10840ce332fdSQi Zhang 	if (mark_num >= 2) {
10850ce332fdSQi Zhang 		dev_dbg(dev, "Too many mark actions for VF %d\n", vf->vf_id);
10860ce332fdSQi Zhang 		return -EINVAL;
10870ce332fdSQi Zhang 	}
10880ce332fdSQi Zhang 
10890ce332fdSQi Zhang 	return 0;
10900ce332fdSQi Zhang }
10910ce332fdSQi Zhang 
10920ce332fdSQi Zhang /**
10931f7ea1cdSQi Zhang  * ice_vc_validate_fdir_fltr - validate the virtual channel filter
10941f7ea1cdSQi Zhang  * @vf: pointer to the VF info
10951f7ea1cdSQi Zhang  * @fltr: virtual channel add cmd buffer
10961f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
10971f7ea1cdSQi Zhang  *
10981f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
10991f7ea1cdSQi Zhang  */
11001f7ea1cdSQi Zhang static int
11011f7ea1cdSQi Zhang ice_vc_validate_fdir_fltr(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
11021f7ea1cdSQi Zhang 			  struct virtchnl_fdir_fltr_conf *conf)
11031f7ea1cdSQi Zhang {
110460f44fe4SJeff Guo 	struct virtchnl_proto_hdrs *proto = &fltr->rule_cfg.proto_hdrs;
11050ce332fdSQi Zhang 	int ret;
11060ce332fdSQi Zhang 
110760f44fe4SJeff Guo 	if (!ice_vc_validate_pattern(vf, proto))
110860f44fe4SJeff Guo 		return -EINVAL;
11090ce332fdSQi Zhang 
11100ce332fdSQi Zhang 	ret = ice_vc_fdir_parse_pattern(vf, fltr, conf);
11110ce332fdSQi Zhang 	if (ret)
11120ce332fdSQi Zhang 		return ret;
11130ce332fdSQi Zhang 
11140ce332fdSQi Zhang 	return ice_vc_fdir_parse_action(vf, fltr, conf);
11151f7ea1cdSQi Zhang }
11161f7ea1cdSQi Zhang 
11171f7ea1cdSQi Zhang /**
11181f7ea1cdSQi Zhang  * ice_vc_fdir_comp_rules - compare if two filter rules have the same value
11191f7ea1cdSQi Zhang  * @conf_a: FDIR configuration for filter a
11201f7ea1cdSQi Zhang  * @conf_b: FDIR configuration for filter b
11211f7ea1cdSQi Zhang  *
11221f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
11231f7ea1cdSQi Zhang  */
11241f7ea1cdSQi Zhang static bool
11251f7ea1cdSQi Zhang ice_vc_fdir_comp_rules(struct virtchnl_fdir_fltr_conf *conf_a,
11261f7ea1cdSQi Zhang 		       struct virtchnl_fdir_fltr_conf *conf_b)
11271f7ea1cdSQi Zhang {
11281f7ea1cdSQi Zhang 	struct ice_fdir_fltr *a = &conf_a->input;
11291f7ea1cdSQi Zhang 	struct ice_fdir_fltr *b = &conf_b->input;
11301f7ea1cdSQi Zhang 
1131ef9e4cc5SQi Zhang 	if (conf_a->ttype != conf_b->ttype)
1132ef9e4cc5SQi Zhang 		return false;
11331f7ea1cdSQi Zhang 	if (a->flow_type != b->flow_type)
11341f7ea1cdSQi Zhang 		return false;
11351f7ea1cdSQi Zhang 	if (memcmp(&a->ip, &b->ip, sizeof(a->ip)))
11361f7ea1cdSQi Zhang 		return false;
11371f7ea1cdSQi Zhang 	if (memcmp(&a->mask, &b->mask, sizeof(a->mask)))
11381f7ea1cdSQi Zhang 		return false;
1139ef9e4cc5SQi Zhang 	if (memcmp(&a->gtpu_data, &b->gtpu_data, sizeof(a->gtpu_data)))
1140ef9e4cc5SQi Zhang 		return false;
1141ef9e4cc5SQi Zhang 	if (memcmp(&a->gtpu_mask, &b->gtpu_mask, sizeof(a->gtpu_mask)))
1142ef9e4cc5SQi Zhang 		return false;
1143213528feSQi Zhang 	if (memcmp(&a->l2tpv3_data, &b->l2tpv3_data, sizeof(a->l2tpv3_data)))
1144213528feSQi Zhang 		return false;
1145213528feSQi Zhang 	if (memcmp(&a->l2tpv3_mask, &b->l2tpv3_mask, sizeof(a->l2tpv3_mask)))
1146213528feSQi Zhang 		return false;
11471f7ea1cdSQi Zhang 	if (memcmp(&a->ext_data, &b->ext_data, sizeof(a->ext_data)))
11481f7ea1cdSQi Zhang 		return false;
11491f7ea1cdSQi Zhang 	if (memcmp(&a->ext_mask, &b->ext_mask, sizeof(a->ext_mask)))
11501f7ea1cdSQi Zhang 		return false;
11511f7ea1cdSQi Zhang 
11521f7ea1cdSQi Zhang 	return true;
11531f7ea1cdSQi Zhang }
11541f7ea1cdSQi Zhang 
11551f7ea1cdSQi Zhang /**
11561f7ea1cdSQi Zhang  * ice_vc_fdir_is_dup_fltr
11571f7ea1cdSQi Zhang  * @vf: pointer to the VF info
11581f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
11591f7ea1cdSQi Zhang  *
11601f7ea1cdSQi Zhang  * Check if there is duplicated rule with same conf value
11611f7ea1cdSQi Zhang  *
11621f7ea1cdSQi Zhang  * Return: 0 true success, and false on error.
11631f7ea1cdSQi Zhang  */
11641f7ea1cdSQi Zhang static bool
11651f7ea1cdSQi Zhang ice_vc_fdir_is_dup_fltr(struct ice_vf *vf, struct virtchnl_fdir_fltr_conf *conf)
11661f7ea1cdSQi Zhang {
11671f7ea1cdSQi Zhang 	struct ice_fdir_fltr *desc;
11681f7ea1cdSQi Zhang 	bool ret;
11691f7ea1cdSQi Zhang 
11701f7ea1cdSQi Zhang 	list_for_each_entry(desc, &vf->fdir.fdir_rule_list, fltr_node) {
11711f7ea1cdSQi Zhang 		struct virtchnl_fdir_fltr_conf *node =
11721f7ea1cdSQi Zhang 				to_fltr_conf_from_desc(desc);
11731f7ea1cdSQi Zhang 
11741f7ea1cdSQi Zhang 		ret = ice_vc_fdir_comp_rules(node, conf);
11751f7ea1cdSQi Zhang 		if (ret)
11761f7ea1cdSQi Zhang 			return true;
11771f7ea1cdSQi Zhang 	}
11781f7ea1cdSQi Zhang 
11791f7ea1cdSQi Zhang 	return false;
11801f7ea1cdSQi Zhang }
11811f7ea1cdSQi Zhang 
11821f7ea1cdSQi Zhang /**
11831f7ea1cdSQi Zhang  * ice_vc_fdir_insert_entry
11841f7ea1cdSQi Zhang  * @vf: pointer to the VF info
11851f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
11861f7ea1cdSQi Zhang  * @id: pointer to ID value allocated by driver
11871f7ea1cdSQi Zhang  *
11881f7ea1cdSQi Zhang  * Insert FDIR conf entry into list and allocate ID for this filter
11891f7ea1cdSQi Zhang  *
11901f7ea1cdSQi Zhang  * Return: 0 true success, and other on error.
11911f7ea1cdSQi Zhang  */
11921f7ea1cdSQi Zhang static int
11931f7ea1cdSQi Zhang ice_vc_fdir_insert_entry(struct ice_vf *vf,
11941f7ea1cdSQi Zhang 			 struct virtchnl_fdir_fltr_conf *conf, u32 *id)
11951f7ea1cdSQi Zhang {
11961f7ea1cdSQi Zhang 	struct ice_fdir_fltr *input = &conf->input;
11971f7ea1cdSQi Zhang 	int i;
11981f7ea1cdSQi Zhang 
11991f7ea1cdSQi Zhang 	/* alloc ID corresponding with conf */
12001f7ea1cdSQi Zhang 	i = idr_alloc(&vf->fdir.fdir_rule_idr, conf, 0,
12011f7ea1cdSQi Zhang 		      ICE_FDIR_MAX_FLTRS, GFP_KERNEL);
12021f7ea1cdSQi Zhang 	if (i < 0)
12031f7ea1cdSQi Zhang 		return -EINVAL;
12041f7ea1cdSQi Zhang 	*id = i;
12051f7ea1cdSQi Zhang 
12061f7ea1cdSQi Zhang 	list_add(&input->fltr_node, &vf->fdir.fdir_rule_list);
12071f7ea1cdSQi Zhang 	return 0;
12081f7ea1cdSQi Zhang }
12091f7ea1cdSQi Zhang 
12101f7ea1cdSQi Zhang /**
12111f7ea1cdSQi Zhang  * ice_vc_fdir_remove_entry - remove FDIR conf entry by ID value
12121f7ea1cdSQi Zhang  * @vf: pointer to the VF info
12131f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
12141f7ea1cdSQi Zhang  * @id: filter rule's ID
12151f7ea1cdSQi Zhang  */
12161f7ea1cdSQi Zhang static void
12171f7ea1cdSQi Zhang ice_vc_fdir_remove_entry(struct ice_vf *vf,
12181f7ea1cdSQi Zhang 			 struct virtchnl_fdir_fltr_conf *conf, u32 id)
12191f7ea1cdSQi Zhang {
12201f7ea1cdSQi Zhang 	struct ice_fdir_fltr *input = &conf->input;
12211f7ea1cdSQi Zhang 
12221f7ea1cdSQi Zhang 	idr_remove(&vf->fdir.fdir_rule_idr, id);
12231f7ea1cdSQi Zhang 	list_del(&input->fltr_node);
12241f7ea1cdSQi Zhang }
12251f7ea1cdSQi Zhang 
12261f7ea1cdSQi Zhang /**
12271f7ea1cdSQi Zhang  * ice_vc_fdir_lookup_entry - lookup FDIR conf entry by ID value
12281f7ea1cdSQi Zhang  * @vf: pointer to the VF info
12291f7ea1cdSQi Zhang  * @id: filter rule's ID
12301f7ea1cdSQi Zhang  *
12311f7ea1cdSQi Zhang  * Return: NULL on error, and other on success.
12321f7ea1cdSQi Zhang  */
12331f7ea1cdSQi Zhang static struct virtchnl_fdir_fltr_conf *
12341f7ea1cdSQi Zhang ice_vc_fdir_lookup_entry(struct ice_vf *vf, u32 id)
12351f7ea1cdSQi Zhang {
12361f7ea1cdSQi Zhang 	return idr_find(&vf->fdir.fdir_rule_idr, id);
12371f7ea1cdSQi Zhang }
12381f7ea1cdSQi Zhang 
12391f7ea1cdSQi Zhang /**
12401f7ea1cdSQi Zhang  * ice_vc_fdir_flush_entry - remove all FDIR conf entry
12411f7ea1cdSQi Zhang  * @vf: pointer to the VF info
12421f7ea1cdSQi Zhang  */
12431f7ea1cdSQi Zhang static void ice_vc_fdir_flush_entry(struct ice_vf *vf)
12441f7ea1cdSQi Zhang {
12451f7ea1cdSQi Zhang 	struct virtchnl_fdir_fltr_conf *conf;
12461f7ea1cdSQi Zhang 	struct ice_fdir_fltr *desc, *temp;
12471f7ea1cdSQi Zhang 
12481f7ea1cdSQi Zhang 	list_for_each_entry_safe(desc, temp,
12491f7ea1cdSQi Zhang 				 &vf->fdir.fdir_rule_list, fltr_node) {
12501f7ea1cdSQi Zhang 		conf = to_fltr_conf_from_desc(desc);
12511f7ea1cdSQi Zhang 		list_del(&desc->fltr_node);
12521f7ea1cdSQi Zhang 		devm_kfree(ice_pf_to_dev(vf->pf), conf);
12531f7ea1cdSQi Zhang 	}
12541f7ea1cdSQi Zhang }
12551f7ea1cdSQi Zhang 
12561f7ea1cdSQi Zhang /**
12571f7ea1cdSQi Zhang  * ice_vc_fdir_write_fltr - write filter rule into hardware
12581f7ea1cdSQi Zhang  * @vf: pointer to the VF info
12591f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
12601f7ea1cdSQi Zhang  * @add: true implies add rule, false implies del rules
12611f7ea1cdSQi Zhang  * @is_tun: false implies non-tunnel type filter, true implies tunnel filter
12621f7ea1cdSQi Zhang  *
12631f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
12641f7ea1cdSQi Zhang  */
12651f7ea1cdSQi Zhang static int ice_vc_fdir_write_fltr(struct ice_vf *vf,
12661f7ea1cdSQi Zhang 				  struct virtchnl_fdir_fltr_conf *conf,
12671f7ea1cdSQi Zhang 				  bool add, bool is_tun)
12681f7ea1cdSQi Zhang {
12691f7ea1cdSQi Zhang 	struct ice_fdir_fltr *input = &conf->input;
12701f7ea1cdSQi Zhang 	struct ice_vsi *vsi, *ctrl_vsi;
12711f7ea1cdSQi Zhang 	struct ice_fltr_desc desc;
12721f7ea1cdSQi Zhang 	struct device *dev;
12731f7ea1cdSQi Zhang 	struct ice_pf *pf;
12741f7ea1cdSQi Zhang 	struct ice_hw *hw;
12751f7ea1cdSQi Zhang 	int ret;
12761f7ea1cdSQi Zhang 	u8 *pkt;
12771f7ea1cdSQi Zhang 
12781f7ea1cdSQi Zhang 	pf = vf->pf;
12791f7ea1cdSQi Zhang 	dev = ice_pf_to_dev(pf);
12801f7ea1cdSQi Zhang 	hw = &pf->hw;
1281772dec64SBrett Creeley 	vsi = ice_get_vf_vsi(vf);
12821f7ea1cdSQi Zhang 	if (!vsi) {
12831f7ea1cdSQi Zhang 		dev_dbg(dev, "Invalid vsi for VF %d\n", vf->vf_id);
12841f7ea1cdSQi Zhang 		return -EINVAL;
12851f7ea1cdSQi Zhang 	}
12861f7ea1cdSQi Zhang 
12871f7ea1cdSQi Zhang 	input->dest_vsi = vsi->idx;
1288d6218317SQi Zhang 	input->comp_report = ICE_FXD_FLTR_QW0_COMP_REPORT_SW;
12891f7ea1cdSQi Zhang 
12901f7ea1cdSQi Zhang 	ctrl_vsi = pf->vsi[vf->ctrl_vsi_idx];
12911f7ea1cdSQi Zhang 	if (!ctrl_vsi) {
12921f7ea1cdSQi Zhang 		dev_dbg(dev, "Invalid ctrl_vsi for VF %d\n", vf->vf_id);
12931f7ea1cdSQi Zhang 		return -EINVAL;
12941f7ea1cdSQi Zhang 	}
12951f7ea1cdSQi Zhang 
12961f7ea1cdSQi Zhang 	pkt = devm_kzalloc(dev, ICE_FDIR_MAX_RAW_PKT_SIZE, GFP_KERNEL);
12971f7ea1cdSQi Zhang 	if (!pkt)
12981f7ea1cdSQi Zhang 		return -ENOMEM;
12991f7ea1cdSQi Zhang 
13001f7ea1cdSQi Zhang 	ice_fdir_get_prgm_desc(hw, input, &desc, add);
13012ccc1c1cSTony Nguyen 	ret = ice_fdir_get_gen_prgm_pkt(hw, input, pkt, false, is_tun);
13021f7ea1cdSQi Zhang 	if (ret) {
13031f7ea1cdSQi Zhang 		dev_dbg(dev, "Gen training pkt for VF %d ptype %d failed\n",
13041f7ea1cdSQi Zhang 			vf->vf_id, input->flow_type);
13051f7ea1cdSQi Zhang 		goto err_free_pkt;
13061f7ea1cdSQi Zhang 	}
13071f7ea1cdSQi Zhang 
13081f7ea1cdSQi Zhang 	ret = ice_prgm_fdir_fltr(ctrl_vsi, &desc, pkt);
13091f7ea1cdSQi Zhang 	if (ret)
13101f7ea1cdSQi Zhang 		goto err_free_pkt;
13111f7ea1cdSQi Zhang 
13121f7ea1cdSQi Zhang 	return 0;
13131f7ea1cdSQi Zhang 
13141f7ea1cdSQi Zhang err_free_pkt:
13151f7ea1cdSQi Zhang 	devm_kfree(dev, pkt);
13161f7ea1cdSQi Zhang 	return ret;
13171f7ea1cdSQi Zhang }
13181f7ea1cdSQi Zhang 
13191f7ea1cdSQi Zhang /**
1320d6218317SQi Zhang  * ice_vf_fdir_timer - FDIR program waiting timer interrupt handler
1321d6218317SQi Zhang  * @t: pointer to timer_list
1322d6218317SQi Zhang  */
1323d6218317SQi Zhang static void ice_vf_fdir_timer(struct timer_list *t)
1324d6218317SQi Zhang {
1325d6218317SQi Zhang 	struct ice_vf_fdir_ctx *ctx_irq = from_timer(ctx_irq, t, rx_tmr);
1326d6218317SQi Zhang 	struct ice_vf_fdir_ctx *ctx_done;
1327d6218317SQi Zhang 	struct ice_vf_fdir *fdir;
1328d6218317SQi Zhang 	unsigned long flags;
1329d6218317SQi Zhang 	struct ice_vf *vf;
1330d6218317SQi Zhang 	struct ice_pf *pf;
1331d6218317SQi Zhang 
1332d6218317SQi Zhang 	fdir = container_of(ctx_irq, struct ice_vf_fdir, ctx_irq);
1333d6218317SQi Zhang 	vf = container_of(fdir, struct ice_vf, fdir);
1334d6218317SQi Zhang 	ctx_done = &fdir->ctx_done;
1335d6218317SQi Zhang 	pf = vf->pf;
1336d6218317SQi Zhang 	spin_lock_irqsave(&fdir->ctx_lock, flags);
1337d6218317SQi Zhang 	if (!(ctx_irq->flags & ICE_VF_FDIR_CTX_VALID)) {
1338d6218317SQi Zhang 		spin_unlock_irqrestore(&fdir->ctx_lock, flags);
1339d6218317SQi Zhang 		WARN_ON_ONCE(1);
1340d6218317SQi Zhang 		return;
1341d6218317SQi Zhang 	}
1342d6218317SQi Zhang 
1343d6218317SQi Zhang 	ctx_irq->flags &= ~ICE_VF_FDIR_CTX_VALID;
1344d6218317SQi Zhang 
1345d6218317SQi Zhang 	ctx_done->flags |= ICE_VF_FDIR_CTX_VALID;
1346d6218317SQi Zhang 	ctx_done->conf = ctx_irq->conf;
1347d6218317SQi Zhang 	ctx_done->stat = ICE_FDIR_CTX_TIMEOUT;
1348d6218317SQi Zhang 	ctx_done->v_opcode = ctx_irq->v_opcode;
1349d6218317SQi Zhang 	spin_unlock_irqrestore(&fdir->ctx_lock, flags);
1350d6218317SQi Zhang 
13517e408e07SAnirudh Venkataramanan 	set_bit(ICE_FD_VF_FLUSH_CTX, pf->state);
1352d6218317SQi Zhang 	ice_service_task_schedule(pf);
1353d6218317SQi Zhang }
1354d6218317SQi Zhang 
1355d6218317SQi Zhang /**
1356d6218317SQi Zhang  * ice_vc_fdir_irq_handler - ctrl_vsi Rx queue interrupt handler
1357d6218317SQi Zhang  * @ctrl_vsi: pointer to a VF's CTRL VSI
1358d6218317SQi Zhang  * @rx_desc: pointer to FDIR Rx queue descriptor
1359d6218317SQi Zhang  */
1360d6218317SQi Zhang void
1361d6218317SQi Zhang ice_vc_fdir_irq_handler(struct ice_vsi *ctrl_vsi,
1362d6218317SQi Zhang 			union ice_32b_rx_flex_desc *rx_desc)
1363d6218317SQi Zhang {
1364d6218317SQi Zhang 	struct ice_pf *pf = ctrl_vsi->back;
1365b03d519dSJacob Keller 	struct ice_vf *vf = ctrl_vsi->vf;
1366d6218317SQi Zhang 	struct ice_vf_fdir_ctx *ctx_done;
1367d6218317SQi Zhang 	struct ice_vf_fdir_ctx *ctx_irq;
1368d6218317SQi Zhang 	struct ice_vf_fdir *fdir;
1369d6218317SQi Zhang 	unsigned long flags;
1370d6218317SQi Zhang 	struct device *dev;
1371d6218317SQi Zhang 	int ret;
1372d6218317SQi Zhang 
1373b03d519dSJacob Keller 	if (WARN_ON(!vf))
1374b03d519dSJacob Keller 		return;
1375d6218317SQi Zhang 
1376d6218317SQi Zhang 	fdir = &vf->fdir;
1377d6218317SQi Zhang 	ctx_done = &fdir->ctx_done;
1378d6218317SQi Zhang 	ctx_irq = &fdir->ctx_irq;
1379d6218317SQi Zhang 	dev = ice_pf_to_dev(pf);
1380d6218317SQi Zhang 	spin_lock_irqsave(&fdir->ctx_lock, flags);
1381d6218317SQi Zhang 	if (!(ctx_irq->flags & ICE_VF_FDIR_CTX_VALID)) {
1382d6218317SQi Zhang 		spin_unlock_irqrestore(&fdir->ctx_lock, flags);
1383d6218317SQi Zhang 		WARN_ON_ONCE(1);
1384d6218317SQi Zhang 		return;
1385d6218317SQi Zhang 	}
1386d6218317SQi Zhang 
1387d6218317SQi Zhang 	ctx_irq->flags &= ~ICE_VF_FDIR_CTX_VALID;
1388d6218317SQi Zhang 
1389d6218317SQi Zhang 	ctx_done->flags |= ICE_VF_FDIR_CTX_VALID;
1390d6218317SQi Zhang 	ctx_done->conf = ctx_irq->conf;
1391d6218317SQi Zhang 	ctx_done->stat = ICE_FDIR_CTX_IRQ;
1392d6218317SQi Zhang 	ctx_done->v_opcode = ctx_irq->v_opcode;
1393d6218317SQi Zhang 	memcpy(&ctx_done->rx_desc, rx_desc, sizeof(*rx_desc));
1394d6218317SQi Zhang 	spin_unlock_irqrestore(&fdir->ctx_lock, flags);
1395d6218317SQi Zhang 
1396d6218317SQi Zhang 	ret = del_timer(&ctx_irq->rx_tmr);
1397d6218317SQi Zhang 	if (!ret)
1398d6218317SQi Zhang 		dev_err(dev, "VF %d: Unexpected inactive timer!\n", vf->vf_id);
1399d6218317SQi Zhang 
14007e408e07SAnirudh Venkataramanan 	set_bit(ICE_FD_VF_FLUSH_CTX, pf->state);
1401d6218317SQi Zhang 	ice_service_task_schedule(pf);
1402d6218317SQi Zhang }
1403d6218317SQi Zhang 
1404d6218317SQi Zhang /**
1405d6218317SQi Zhang  * ice_vf_fdir_dump_info - dump FDIR information for diagnosis
1406d6218317SQi Zhang  * @vf: pointer to the VF info
1407d6218317SQi Zhang  */
1408d6218317SQi Zhang static void ice_vf_fdir_dump_info(struct ice_vf *vf)
1409d6218317SQi Zhang {
1410d6218317SQi Zhang 	struct ice_vsi *vf_vsi;
1411d6218317SQi Zhang 	u32 fd_size, fd_cnt;
1412d6218317SQi Zhang 	struct device *dev;
1413d6218317SQi Zhang 	struct ice_pf *pf;
1414d6218317SQi Zhang 	struct ice_hw *hw;
1415d6218317SQi Zhang 	u16 vsi_num;
1416d6218317SQi Zhang 
1417d6218317SQi Zhang 	pf = vf->pf;
1418d6218317SQi Zhang 	hw = &pf->hw;
1419d6218317SQi Zhang 	dev = ice_pf_to_dev(pf);
1420baeb705fSJacob Keller 	vf_vsi = ice_get_vf_vsi(vf);
1421baeb705fSJacob Keller 	if (!vf_vsi) {
1422baeb705fSJacob Keller 		dev_dbg(dev, "VF %d: invalid VSI pointer\n", vf->vf_id);
1423baeb705fSJacob Keller 		return;
1424baeb705fSJacob Keller 	}
1425baeb705fSJacob Keller 
1426d6218317SQi Zhang 	vsi_num = ice_get_hw_vsi_num(hw, vf_vsi->idx);
1427d6218317SQi Zhang 
1428d6218317SQi Zhang 	fd_size = rd32(hw, VSIQF_FD_SIZE(vsi_num));
1429d6218317SQi Zhang 	fd_cnt = rd32(hw, VSIQF_FD_CNT(vsi_num));
14309880d3d6SJacob Keller 	dev_dbg(dev, "VF %d: space allocated: guar:0x%x, be:0x%x, space consumed: guar:0x%x, be:0x%x\n",
1431d6218317SQi Zhang 		vf->vf_id,
1432d6218317SQi Zhang 		(fd_size & VSIQF_FD_CNT_FD_GCNT_M) >> VSIQF_FD_CNT_FD_GCNT_S,
1433d6218317SQi Zhang 		(fd_size & VSIQF_FD_CNT_FD_BCNT_M) >> VSIQF_FD_CNT_FD_BCNT_S,
1434d6218317SQi Zhang 		(fd_cnt & VSIQF_FD_CNT_FD_GCNT_M) >> VSIQF_FD_CNT_FD_GCNT_S,
1435d6218317SQi Zhang 		(fd_cnt & VSIQF_FD_CNT_FD_BCNT_M) >> VSIQF_FD_CNT_FD_BCNT_S);
1436d6218317SQi Zhang }
1437d6218317SQi Zhang 
1438d6218317SQi Zhang /**
1439d6218317SQi Zhang  * ice_vf_verify_rx_desc - verify received FDIR programming status descriptor
1440d6218317SQi Zhang  * @vf: pointer to the VF info
1441d6218317SQi Zhang  * @ctx: FDIR context info for post processing
1442d6218317SQi Zhang  * @status: virtchnl FDIR program status
1443d6218317SQi Zhang  *
1444d6218317SQi Zhang  * Return: 0 on success, and other on error.
1445d6218317SQi Zhang  */
1446d6218317SQi Zhang static int
1447d6218317SQi Zhang ice_vf_verify_rx_desc(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx,
1448d6218317SQi Zhang 		      enum virtchnl_fdir_prgm_status *status)
1449d6218317SQi Zhang {
1450d6218317SQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
1451d6218317SQi Zhang 	u32 stat_err, error, prog_id;
1452d6218317SQi Zhang 	int ret;
1453d6218317SQi Zhang 
1454d6218317SQi Zhang 	stat_err = le16_to_cpu(ctx->rx_desc.wb.status_error0);
1455d6218317SQi Zhang 	if (((stat_err & ICE_FXD_FLTR_WB_QW1_DD_M) >>
1456d6218317SQi Zhang 	    ICE_FXD_FLTR_WB_QW1_DD_S) != ICE_FXD_FLTR_WB_QW1_DD_YES) {
1457d6218317SQi Zhang 		*status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
1458d6218317SQi Zhang 		dev_err(dev, "VF %d: Desc Done not set\n", vf->vf_id);
1459d6218317SQi Zhang 		ret = -EINVAL;
1460d6218317SQi Zhang 		goto err_exit;
1461d6218317SQi Zhang 	}
1462d6218317SQi Zhang 
1463d6218317SQi Zhang 	prog_id = (stat_err & ICE_FXD_FLTR_WB_QW1_PROG_ID_M) >>
1464d6218317SQi Zhang 		ICE_FXD_FLTR_WB_QW1_PROG_ID_S;
1465d6218317SQi Zhang 	if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_ADD &&
1466d6218317SQi Zhang 	    ctx->v_opcode != VIRTCHNL_OP_ADD_FDIR_FILTER) {
1467d6218317SQi Zhang 		dev_err(dev, "VF %d: Desc show add, but ctx not",
1468d6218317SQi Zhang 			vf->vf_id);
1469d6218317SQi Zhang 		*status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID;
1470d6218317SQi Zhang 		ret = -EINVAL;
1471d6218317SQi Zhang 		goto err_exit;
1472d6218317SQi Zhang 	}
1473d6218317SQi Zhang 
1474d6218317SQi Zhang 	if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_DEL &&
1475d6218317SQi Zhang 	    ctx->v_opcode != VIRTCHNL_OP_DEL_FDIR_FILTER) {
1476d6218317SQi Zhang 		dev_err(dev, "VF %d: Desc show del, but ctx not",
1477d6218317SQi Zhang 			vf->vf_id);
1478d6218317SQi Zhang 		*status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID;
1479d6218317SQi Zhang 		ret = -EINVAL;
1480d6218317SQi Zhang 		goto err_exit;
1481d6218317SQi Zhang 	}
1482d6218317SQi Zhang 
1483d6218317SQi Zhang 	error = (stat_err & ICE_FXD_FLTR_WB_QW1_FAIL_M) >>
1484d6218317SQi Zhang 		ICE_FXD_FLTR_WB_QW1_FAIL_S;
1485d6218317SQi Zhang 	if (error == ICE_FXD_FLTR_WB_QW1_FAIL_YES) {
1486d6218317SQi Zhang 		if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_ADD) {
1487d6218317SQi Zhang 			dev_err(dev, "VF %d, Failed to add FDIR rule due to no space in the table",
1488d6218317SQi Zhang 				vf->vf_id);
1489d6218317SQi Zhang 			*status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
1490d6218317SQi Zhang 		} else {
1491d6218317SQi Zhang 			dev_err(dev, "VF %d, Failed to remove FDIR rule, attempt to remove non-existent entry",
1492d6218317SQi Zhang 				vf->vf_id);
1493d6218317SQi Zhang 			*status = VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST;
1494d6218317SQi Zhang 		}
1495d6218317SQi Zhang 		ret = -EINVAL;
1496d6218317SQi Zhang 		goto err_exit;
1497d6218317SQi Zhang 	}
1498d6218317SQi Zhang 
1499d6218317SQi Zhang 	error = (stat_err & ICE_FXD_FLTR_WB_QW1_FAIL_PROF_M) >>
1500d6218317SQi Zhang 		ICE_FXD_FLTR_WB_QW1_FAIL_PROF_S;
1501d6218317SQi Zhang 	if (error == ICE_FXD_FLTR_WB_QW1_FAIL_PROF_YES) {
1502d6218317SQi Zhang 		dev_err(dev, "VF %d: Profile matching error", vf->vf_id);
1503d6218317SQi Zhang 		*status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
1504d6218317SQi Zhang 		ret = -EINVAL;
1505d6218317SQi Zhang 		goto err_exit;
1506d6218317SQi Zhang 	}
1507d6218317SQi Zhang 
1508d6218317SQi Zhang 	*status = VIRTCHNL_FDIR_SUCCESS;
1509d6218317SQi Zhang 
1510d6218317SQi Zhang 	return 0;
1511d6218317SQi Zhang 
1512d6218317SQi Zhang err_exit:
1513d6218317SQi Zhang 	ice_vf_fdir_dump_info(vf);
1514d6218317SQi Zhang 	return ret;
1515d6218317SQi Zhang }
1516d6218317SQi Zhang 
1517d6218317SQi Zhang /**
1518d6218317SQi Zhang  * ice_vc_add_fdir_fltr_post
1519d6218317SQi Zhang  * @vf: pointer to the VF structure
1520d6218317SQi Zhang  * @ctx: FDIR context info for post processing
1521d6218317SQi Zhang  * @status: virtchnl FDIR program status
1522d6218317SQi Zhang  * @success: true implies success, false implies failure
1523d6218317SQi Zhang  *
1524d6218317SQi Zhang  * Post process for flow director add command. If success, then do post process
1525d6218317SQi Zhang  * and send back success msg by virtchnl. Otherwise, do context reversion and
1526d6218317SQi Zhang  * send back failure msg by virtchnl.
1527d6218317SQi Zhang  *
1528d6218317SQi Zhang  * Return: 0 on success, and other on error.
1529d6218317SQi Zhang  */
1530d6218317SQi Zhang static int
1531d6218317SQi Zhang ice_vc_add_fdir_fltr_post(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx,
1532d6218317SQi Zhang 			  enum virtchnl_fdir_prgm_status status,
1533d6218317SQi Zhang 			  bool success)
1534d6218317SQi Zhang {
1535d6218317SQi Zhang 	struct virtchnl_fdir_fltr_conf *conf = ctx->conf;
1536d6218317SQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
1537d6218317SQi Zhang 	enum virtchnl_status_code v_ret;
1538d6218317SQi Zhang 	struct virtchnl_fdir_add *resp;
1539d6218317SQi Zhang 	int ret, len, is_tun;
1540d6218317SQi Zhang 
1541d6218317SQi Zhang 	v_ret = VIRTCHNL_STATUS_SUCCESS;
1542d6218317SQi Zhang 	len = sizeof(*resp);
1543d6218317SQi Zhang 	resp = kzalloc(len, GFP_KERNEL);
1544d6218317SQi Zhang 	if (!resp) {
1545d6218317SQi Zhang 		len = 0;
1546d6218317SQi Zhang 		v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
1547d6218317SQi Zhang 		dev_dbg(dev, "VF %d: Alloc resp buf fail", vf->vf_id);
1548d6218317SQi Zhang 		goto err_exit;
1549d6218317SQi Zhang 	}
1550d6218317SQi Zhang 
1551d6218317SQi Zhang 	if (!success)
1552d6218317SQi Zhang 		goto err_exit;
1553d6218317SQi Zhang 
1554d6218317SQi Zhang 	is_tun = 0;
1555d6218317SQi Zhang 	resp->status = status;
1556d6218317SQi Zhang 	resp->flow_id = conf->flow_id;
1557d6218317SQi Zhang 	vf->fdir.fdir_fltr_cnt[conf->input.flow_type][is_tun]++;
1558d6218317SQi Zhang 
1559d6218317SQi Zhang 	ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret,
1560d6218317SQi Zhang 				    (u8 *)resp, len);
1561d6218317SQi Zhang 	kfree(resp);
1562d6218317SQi Zhang 
1563d6218317SQi Zhang 	dev_dbg(dev, "VF %d: flow_id:0x%X, FDIR %s success!\n",
1564d6218317SQi Zhang 		vf->vf_id, conf->flow_id,
1565d6218317SQi Zhang 		(ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) ?
1566d6218317SQi Zhang 		"add" : "del");
1567d6218317SQi Zhang 	return ret;
1568d6218317SQi Zhang 
1569d6218317SQi Zhang err_exit:
1570d6218317SQi Zhang 	if (resp)
1571d6218317SQi Zhang 		resp->status = status;
1572d6218317SQi Zhang 	ice_vc_fdir_remove_entry(vf, conf, conf->flow_id);
1573d6218317SQi Zhang 	devm_kfree(dev, conf);
1574d6218317SQi Zhang 
1575d6218317SQi Zhang 	ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret,
1576d6218317SQi Zhang 				    (u8 *)resp, len);
1577d6218317SQi Zhang 	kfree(resp);
1578d6218317SQi Zhang 	return ret;
1579d6218317SQi Zhang }
1580d6218317SQi Zhang 
1581d6218317SQi Zhang /**
1582d6218317SQi Zhang  * ice_vc_del_fdir_fltr_post
1583d6218317SQi Zhang  * @vf: pointer to the VF structure
1584d6218317SQi Zhang  * @ctx: FDIR context info for post processing
1585d6218317SQi Zhang  * @status: virtchnl FDIR program status
1586d6218317SQi Zhang  * @success: true implies success, false implies failure
1587d6218317SQi Zhang  *
1588d6218317SQi Zhang  * Post process for flow director del command. If success, then do post process
1589d6218317SQi Zhang  * and send back success msg by virtchnl. Otherwise, do context reversion and
1590d6218317SQi Zhang  * send back failure msg by virtchnl.
1591d6218317SQi Zhang  *
1592d6218317SQi Zhang  * Return: 0 on success, and other on error.
1593d6218317SQi Zhang  */
1594d6218317SQi Zhang static int
1595d6218317SQi Zhang ice_vc_del_fdir_fltr_post(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx,
1596d6218317SQi Zhang 			  enum virtchnl_fdir_prgm_status status,
1597d6218317SQi Zhang 			  bool success)
1598d6218317SQi Zhang {
1599d6218317SQi Zhang 	struct virtchnl_fdir_fltr_conf *conf = ctx->conf;
1600d6218317SQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
1601d6218317SQi Zhang 	enum virtchnl_status_code v_ret;
1602d6218317SQi Zhang 	struct virtchnl_fdir_del *resp;
1603d6218317SQi Zhang 	int ret, len, is_tun;
1604d6218317SQi Zhang 
1605d6218317SQi Zhang 	v_ret = VIRTCHNL_STATUS_SUCCESS;
1606d6218317SQi Zhang 	len = sizeof(*resp);
1607d6218317SQi Zhang 	resp = kzalloc(len, GFP_KERNEL);
1608d6218317SQi Zhang 	if (!resp) {
1609d6218317SQi Zhang 		len = 0;
1610d6218317SQi Zhang 		v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
1611d6218317SQi Zhang 		dev_dbg(dev, "VF %d: Alloc resp buf fail", vf->vf_id);
1612d6218317SQi Zhang 		goto err_exit;
1613d6218317SQi Zhang 	}
1614d6218317SQi Zhang 
1615d6218317SQi Zhang 	if (!success)
1616d6218317SQi Zhang 		goto err_exit;
1617d6218317SQi Zhang 
1618d6218317SQi Zhang 	is_tun = 0;
1619d6218317SQi Zhang 	resp->status = status;
1620d6218317SQi Zhang 	ice_vc_fdir_remove_entry(vf, conf, conf->flow_id);
1621d6218317SQi Zhang 	vf->fdir.fdir_fltr_cnt[conf->input.flow_type][is_tun]--;
1622d6218317SQi Zhang 
1623d6218317SQi Zhang 	ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret,
1624d6218317SQi Zhang 				    (u8 *)resp, len);
1625d6218317SQi Zhang 	kfree(resp);
1626d6218317SQi Zhang 
1627d6218317SQi Zhang 	dev_dbg(dev, "VF %d: flow_id:0x%X, FDIR %s success!\n",
1628d6218317SQi Zhang 		vf->vf_id, conf->flow_id,
1629d6218317SQi Zhang 		(ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) ?
1630d6218317SQi Zhang 		"add" : "del");
1631d6218317SQi Zhang 	devm_kfree(dev, conf);
1632d6218317SQi Zhang 	return ret;
1633d6218317SQi Zhang 
1634d6218317SQi Zhang err_exit:
1635d6218317SQi Zhang 	if (resp)
1636d6218317SQi Zhang 		resp->status = status;
1637d6218317SQi Zhang 	if (success)
1638d6218317SQi Zhang 		devm_kfree(dev, conf);
1639d6218317SQi Zhang 
1640d6218317SQi Zhang 	ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret,
1641d6218317SQi Zhang 				    (u8 *)resp, len);
1642d6218317SQi Zhang 	kfree(resp);
1643d6218317SQi Zhang 	return ret;
1644d6218317SQi Zhang }
1645d6218317SQi Zhang 
1646d6218317SQi Zhang /**
1647d6218317SQi Zhang  * ice_flush_fdir_ctx
1648d6218317SQi Zhang  * @pf: pointer to the PF structure
1649d6218317SQi Zhang  *
1650d6218317SQi Zhang  * Flush all the pending event on ctx_done list and process them.
1651d6218317SQi Zhang  */
1652d6218317SQi Zhang void ice_flush_fdir_ctx(struct ice_pf *pf)
1653d6218317SQi Zhang {
1654c4c2c7dbSJacob Keller 	struct ice_vf *vf;
1655c4c2c7dbSJacob Keller 	unsigned int bkt;
1656d6218317SQi Zhang 
16577e408e07SAnirudh Venkataramanan 	if (!test_and_clear_bit(ICE_FD_VF_FLUSH_CTX, pf->state))
1658d6218317SQi Zhang 		return;
1659d6218317SQi Zhang 
16603d5985a1SJacob Keller 	mutex_lock(&pf->vfs.table_lock);
1661c4c2c7dbSJacob Keller 	ice_for_each_vf(pf, bkt, vf) {
1662d6218317SQi Zhang 		struct device *dev = ice_pf_to_dev(pf);
1663d6218317SQi Zhang 		enum virtchnl_fdir_prgm_status status;
1664d6218317SQi Zhang 		struct ice_vf_fdir_ctx *ctx;
1665d6218317SQi Zhang 		unsigned long flags;
1666d6218317SQi Zhang 		int ret;
1667d6218317SQi Zhang 
1668d6218317SQi Zhang 		if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states))
1669d6218317SQi Zhang 			continue;
1670d6218317SQi Zhang 
1671d6218317SQi Zhang 		if (vf->ctrl_vsi_idx == ICE_NO_VSI)
1672d6218317SQi Zhang 			continue;
1673d6218317SQi Zhang 
1674d6218317SQi Zhang 		ctx = &vf->fdir.ctx_done;
1675d6218317SQi Zhang 		spin_lock_irqsave(&vf->fdir.ctx_lock, flags);
1676d6218317SQi Zhang 		if (!(ctx->flags & ICE_VF_FDIR_CTX_VALID)) {
1677d6218317SQi Zhang 			spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1678d6218317SQi Zhang 			continue;
1679d6218317SQi Zhang 		}
1680d6218317SQi Zhang 		spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1681d6218317SQi Zhang 
1682d6218317SQi Zhang 		WARN_ON(ctx->stat == ICE_FDIR_CTX_READY);
1683d6218317SQi Zhang 		if (ctx->stat == ICE_FDIR_CTX_TIMEOUT) {
1684d6218317SQi Zhang 			status = VIRTCHNL_FDIR_FAILURE_RULE_TIMEOUT;
1685d6218317SQi Zhang 			dev_err(dev, "VF %d: ctrl_vsi irq timeout\n",
1686d6218317SQi Zhang 				vf->vf_id);
1687d6218317SQi Zhang 			goto err_exit;
1688d6218317SQi Zhang 		}
1689d6218317SQi Zhang 
1690d6218317SQi Zhang 		ret = ice_vf_verify_rx_desc(vf, ctx, &status);
1691d6218317SQi Zhang 		if (ret)
1692d6218317SQi Zhang 			goto err_exit;
1693d6218317SQi Zhang 
1694d6218317SQi Zhang 		if (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER)
1695d6218317SQi Zhang 			ice_vc_add_fdir_fltr_post(vf, ctx, status, true);
1696d6218317SQi Zhang 		else if (ctx->v_opcode == VIRTCHNL_OP_DEL_FDIR_FILTER)
1697d6218317SQi Zhang 			ice_vc_del_fdir_fltr_post(vf, ctx, status, true);
1698d6218317SQi Zhang 		else
1699d6218317SQi Zhang 			dev_err(dev, "VF %d: Unsupported opcode\n", vf->vf_id);
1700d6218317SQi Zhang 
1701d6218317SQi Zhang 		spin_lock_irqsave(&vf->fdir.ctx_lock, flags);
1702d6218317SQi Zhang 		ctx->flags &= ~ICE_VF_FDIR_CTX_VALID;
1703d6218317SQi Zhang 		spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1704d6218317SQi Zhang 		continue;
1705d6218317SQi Zhang err_exit:
1706d6218317SQi Zhang 		if (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER)
1707d6218317SQi Zhang 			ice_vc_add_fdir_fltr_post(vf, ctx, status, false);
1708d6218317SQi Zhang 		else if (ctx->v_opcode == VIRTCHNL_OP_DEL_FDIR_FILTER)
1709d6218317SQi Zhang 			ice_vc_del_fdir_fltr_post(vf, ctx, status, false);
1710d6218317SQi Zhang 		else
1711d6218317SQi Zhang 			dev_err(dev, "VF %d: Unsupported opcode\n", vf->vf_id);
1712d6218317SQi Zhang 
1713d6218317SQi Zhang 		spin_lock_irqsave(&vf->fdir.ctx_lock, flags);
1714d6218317SQi Zhang 		ctx->flags &= ~ICE_VF_FDIR_CTX_VALID;
1715d6218317SQi Zhang 		spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1716d6218317SQi Zhang 	}
17173d5985a1SJacob Keller 	mutex_unlock(&pf->vfs.table_lock);
1718d6218317SQi Zhang }
1719d6218317SQi Zhang 
1720d6218317SQi Zhang /**
1721d6218317SQi Zhang  * ice_vc_fdir_set_irq_ctx - set FDIR context info for later IRQ handler
1722d6218317SQi Zhang  * @vf: pointer to the VF structure
1723d6218317SQi Zhang  * @conf: FDIR configuration for each filter
1724d6218317SQi Zhang  * @v_opcode: virtual channel operation code
1725d6218317SQi Zhang  *
1726d6218317SQi Zhang  * Return: 0 on success, and other on error.
1727d6218317SQi Zhang  */
1728d6218317SQi Zhang static int
1729d6218317SQi Zhang ice_vc_fdir_set_irq_ctx(struct ice_vf *vf, struct virtchnl_fdir_fltr_conf *conf,
1730d6218317SQi Zhang 			enum virtchnl_ops v_opcode)
1731d6218317SQi Zhang {
1732d6218317SQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
1733d6218317SQi Zhang 	struct ice_vf_fdir_ctx *ctx;
1734d6218317SQi Zhang 	unsigned long flags;
1735d6218317SQi Zhang 
1736d6218317SQi Zhang 	ctx = &vf->fdir.ctx_irq;
1737d6218317SQi Zhang 	spin_lock_irqsave(&vf->fdir.ctx_lock, flags);
1738d6218317SQi Zhang 	if ((vf->fdir.ctx_irq.flags & ICE_VF_FDIR_CTX_VALID) ||
1739d6218317SQi Zhang 	    (vf->fdir.ctx_done.flags & ICE_VF_FDIR_CTX_VALID)) {
1740d6218317SQi Zhang 		spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1741d6218317SQi Zhang 		dev_dbg(dev, "VF %d: Last request is still in progress\n",
1742d6218317SQi Zhang 			vf->vf_id);
1743d6218317SQi Zhang 		return -EBUSY;
1744d6218317SQi Zhang 	}
1745d6218317SQi Zhang 	ctx->flags |= ICE_VF_FDIR_CTX_VALID;
1746d6218317SQi Zhang 	spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1747d6218317SQi Zhang 
1748d6218317SQi Zhang 	ctx->conf = conf;
1749d6218317SQi Zhang 	ctx->v_opcode = v_opcode;
1750d6218317SQi Zhang 	ctx->stat = ICE_FDIR_CTX_READY;
1751d6218317SQi Zhang 	timer_setup(&ctx->rx_tmr, ice_vf_fdir_timer, 0);
1752d6218317SQi Zhang 
1753d6218317SQi Zhang 	mod_timer(&ctx->rx_tmr, round_jiffies(msecs_to_jiffies(10) + jiffies));
1754d6218317SQi Zhang 
1755d6218317SQi Zhang 	return 0;
1756d6218317SQi Zhang }
1757d6218317SQi Zhang 
1758d6218317SQi Zhang /**
1759d6218317SQi Zhang  * ice_vc_fdir_clear_irq_ctx - clear FDIR context info for IRQ handler
1760d6218317SQi Zhang  * @vf: pointer to the VF structure
1761d6218317SQi Zhang  *
1762d6218317SQi Zhang  * Return: 0 on success, and other on error.
1763d6218317SQi Zhang  */
1764d6218317SQi Zhang static void ice_vc_fdir_clear_irq_ctx(struct ice_vf *vf)
1765d6218317SQi Zhang {
1766d6218317SQi Zhang 	struct ice_vf_fdir_ctx *ctx = &vf->fdir.ctx_irq;
1767d6218317SQi Zhang 	unsigned long flags;
1768d6218317SQi Zhang 
1769d6218317SQi Zhang 	del_timer(&ctx->rx_tmr);
1770d6218317SQi Zhang 	spin_lock_irqsave(&vf->fdir.ctx_lock, flags);
1771d6218317SQi Zhang 	ctx->flags &= ~ICE_VF_FDIR_CTX_VALID;
1772d6218317SQi Zhang 	spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1773d6218317SQi Zhang }
1774d6218317SQi Zhang 
1775d6218317SQi Zhang /**
17761f7ea1cdSQi Zhang  * ice_vc_add_fdir_fltr - add a FDIR filter for VF by the msg buffer
17771f7ea1cdSQi Zhang  * @vf: pointer to the VF info
17781f7ea1cdSQi Zhang  * @msg: pointer to the msg buffer
17791f7ea1cdSQi Zhang  *
17801f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
17811f7ea1cdSQi Zhang  */
17821f7ea1cdSQi Zhang int ice_vc_add_fdir_fltr(struct ice_vf *vf, u8 *msg)
17831f7ea1cdSQi Zhang {
17841f7ea1cdSQi Zhang 	struct virtchnl_fdir_add *fltr = (struct virtchnl_fdir_add *)msg;
17851f7ea1cdSQi Zhang 	struct virtchnl_fdir_add *stat = NULL;
17861f7ea1cdSQi Zhang 	struct virtchnl_fdir_fltr_conf *conf;
17871f7ea1cdSQi Zhang 	enum virtchnl_status_code v_ret;
17881f7ea1cdSQi Zhang 	struct device *dev;
17891f7ea1cdSQi Zhang 	struct ice_pf *pf;
17901f7ea1cdSQi Zhang 	int is_tun = 0;
17911f7ea1cdSQi Zhang 	int len = 0;
17921f7ea1cdSQi Zhang 	int ret;
17931f7ea1cdSQi Zhang 
17941f7ea1cdSQi Zhang 	pf = vf->pf;
17951f7ea1cdSQi Zhang 	dev = ice_pf_to_dev(pf);
17961f7ea1cdSQi Zhang 	ret = ice_vc_fdir_param_check(vf, fltr->vsi_id);
17971f7ea1cdSQi Zhang 	if (ret) {
17981f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_ERR_PARAM;
17991f7ea1cdSQi Zhang 		dev_dbg(dev, "Parameter check for VF %d failed\n", vf->vf_id);
18001f7ea1cdSQi Zhang 		goto err_exit;
18011f7ea1cdSQi Zhang 	}
18021f7ea1cdSQi Zhang 
18031f7ea1cdSQi Zhang 	ret = ice_vf_start_ctrl_vsi(vf);
18041f7ea1cdSQi Zhang 	if (ret && (ret != -EEXIST)) {
18051f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_ERR_PARAM;
18061f7ea1cdSQi Zhang 		dev_err(dev, "Init FDIR for VF %d failed, ret:%d\n",
18071f7ea1cdSQi Zhang 			vf->vf_id, ret);
18081f7ea1cdSQi Zhang 		goto err_exit;
18091f7ea1cdSQi Zhang 	}
18101f7ea1cdSQi Zhang 
18111f7ea1cdSQi Zhang 	stat = kzalloc(sizeof(*stat), GFP_KERNEL);
18121f7ea1cdSQi Zhang 	if (!stat) {
18131f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
18141f7ea1cdSQi Zhang 		dev_dbg(dev, "Alloc stat for VF %d failed\n", vf->vf_id);
18151f7ea1cdSQi Zhang 		goto err_exit;
18161f7ea1cdSQi Zhang 	}
18171f7ea1cdSQi Zhang 
18181f7ea1cdSQi Zhang 	conf = devm_kzalloc(dev, sizeof(*conf), GFP_KERNEL);
18191f7ea1cdSQi Zhang 	if (!conf) {
18201f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
18211f7ea1cdSQi Zhang 		dev_dbg(dev, "Alloc conf for VF %d failed\n", vf->vf_id);
18221f7ea1cdSQi Zhang 		goto err_exit;
18231f7ea1cdSQi Zhang 	}
18241f7ea1cdSQi Zhang 
18251f7ea1cdSQi Zhang 	len = sizeof(*stat);
18261f7ea1cdSQi Zhang 	ret = ice_vc_validate_fdir_fltr(vf, fltr, conf);
18271f7ea1cdSQi Zhang 	if (ret) {
18281f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
18291f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID;
18301f7ea1cdSQi Zhang 		dev_dbg(dev, "Invalid FDIR filter from VF %d\n", vf->vf_id);
18311f7ea1cdSQi Zhang 		goto err_free_conf;
18321f7ea1cdSQi Zhang 	}
18331f7ea1cdSQi Zhang 
18341f7ea1cdSQi Zhang 	if (fltr->validate_only) {
18351f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
18361f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_SUCCESS;
18371f7ea1cdSQi Zhang 		devm_kfree(dev, conf);
18381f7ea1cdSQi Zhang 		ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_FDIR_FILTER,
18391f7ea1cdSQi Zhang 					    v_ret, (u8 *)stat, len);
18401f7ea1cdSQi Zhang 		goto exit;
18411f7ea1cdSQi Zhang 	}
18421f7ea1cdSQi Zhang 
18431f7ea1cdSQi Zhang 	ret = ice_vc_fdir_config_input_set(vf, fltr, conf, is_tun);
18441f7ea1cdSQi Zhang 	if (ret) {
18451f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
18461f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_CONFLICT;
18471f7ea1cdSQi Zhang 		dev_err(dev, "VF %d: FDIR input set configure failed, ret:%d\n",
18481f7ea1cdSQi Zhang 			vf->vf_id, ret);
18491f7ea1cdSQi Zhang 		goto err_free_conf;
18501f7ea1cdSQi Zhang 	}
18511f7ea1cdSQi Zhang 
18521f7ea1cdSQi Zhang 	ret = ice_vc_fdir_is_dup_fltr(vf, conf);
18531f7ea1cdSQi Zhang 	if (ret) {
18541f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
18551f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_EXIST;
18561f7ea1cdSQi Zhang 		dev_dbg(dev, "VF %d: duplicated FDIR rule detected\n",
18571f7ea1cdSQi Zhang 			vf->vf_id);
18581f7ea1cdSQi Zhang 		goto err_free_conf;
18591f7ea1cdSQi Zhang 	}
18601f7ea1cdSQi Zhang 
1861d6218317SQi Zhang 	ret = ice_vc_fdir_insert_entry(vf, conf, &conf->flow_id);
18621f7ea1cdSQi Zhang 	if (ret) {
18631f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
18641f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
18651f7ea1cdSQi Zhang 		dev_dbg(dev, "VF %d: insert FDIR list failed\n", vf->vf_id);
18661f7ea1cdSQi Zhang 		goto err_free_conf;
18671f7ea1cdSQi Zhang 	}
18681f7ea1cdSQi Zhang 
1869d6218317SQi Zhang 	ret = ice_vc_fdir_set_irq_ctx(vf, conf, VIRTCHNL_OP_ADD_FDIR_FILTER);
1870d6218317SQi Zhang 	if (ret) {
1871d6218317SQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
1872d6218317SQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
1873d6218317SQi Zhang 		dev_dbg(dev, "VF %d: set FDIR context failed\n", vf->vf_id);
1874*b4a01aceSSimei Su 		goto err_rem_entry;
1875d6218317SQi Zhang 	}
1876d6218317SQi Zhang 
18771f7ea1cdSQi Zhang 	ret = ice_vc_fdir_write_fltr(vf, conf, true, is_tun);
18781f7ea1cdSQi Zhang 	if (ret) {
18791f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
18801f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
18811f7ea1cdSQi Zhang 		dev_err(dev, "VF %d: writing FDIR rule failed, ret:%d\n",
18821f7ea1cdSQi Zhang 			vf->vf_id, ret);
1883*b4a01aceSSimei Su 		goto err_clr_irq;
18841f7ea1cdSQi Zhang 	}
18851f7ea1cdSQi Zhang 
18861f7ea1cdSQi Zhang exit:
18871f7ea1cdSQi Zhang 	kfree(stat);
18881f7ea1cdSQi Zhang 	return ret;
18891f7ea1cdSQi Zhang 
1890*b4a01aceSSimei Su err_clr_irq:
1891d6218317SQi Zhang 	ice_vc_fdir_clear_irq_ctx(vf);
1892*b4a01aceSSimei Su err_rem_entry:
1893d6218317SQi Zhang 	ice_vc_fdir_remove_entry(vf, conf, conf->flow_id);
18941f7ea1cdSQi Zhang err_free_conf:
18951f7ea1cdSQi Zhang 	devm_kfree(dev, conf);
18961f7ea1cdSQi Zhang err_exit:
18971f7ea1cdSQi Zhang 	ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_FDIR_FILTER, v_ret,
18981f7ea1cdSQi Zhang 				    (u8 *)stat, len);
18991f7ea1cdSQi Zhang 	kfree(stat);
19001f7ea1cdSQi Zhang 	return ret;
19011f7ea1cdSQi Zhang }
19021f7ea1cdSQi Zhang 
19031f7ea1cdSQi Zhang /**
19041f7ea1cdSQi Zhang  * ice_vc_del_fdir_fltr - delete a FDIR filter for VF by the msg buffer
19051f7ea1cdSQi Zhang  * @vf: pointer to the VF info
19061f7ea1cdSQi Zhang  * @msg: pointer to the msg buffer
19071f7ea1cdSQi Zhang  *
19081f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
19091f7ea1cdSQi Zhang  */
19101f7ea1cdSQi Zhang int ice_vc_del_fdir_fltr(struct ice_vf *vf, u8 *msg)
19111f7ea1cdSQi Zhang {
19121f7ea1cdSQi Zhang 	struct virtchnl_fdir_del *fltr = (struct virtchnl_fdir_del *)msg;
19131f7ea1cdSQi Zhang 	struct virtchnl_fdir_del *stat = NULL;
19141f7ea1cdSQi Zhang 	struct virtchnl_fdir_fltr_conf *conf;
19151f7ea1cdSQi Zhang 	enum virtchnl_status_code v_ret;
19161f7ea1cdSQi Zhang 	struct device *dev;
19171f7ea1cdSQi Zhang 	struct ice_pf *pf;
19181f7ea1cdSQi Zhang 	int is_tun = 0;
19191f7ea1cdSQi Zhang 	int len = 0;
19201f7ea1cdSQi Zhang 	int ret;
19211f7ea1cdSQi Zhang 
19221f7ea1cdSQi Zhang 	pf = vf->pf;
19231f7ea1cdSQi Zhang 	dev = ice_pf_to_dev(pf);
19241f7ea1cdSQi Zhang 	ret = ice_vc_fdir_param_check(vf, fltr->vsi_id);
19251f7ea1cdSQi Zhang 	if (ret) {
19261f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_ERR_PARAM;
19271f7ea1cdSQi Zhang 		dev_dbg(dev, "Parameter check for VF %d failed\n", vf->vf_id);
19281f7ea1cdSQi Zhang 		goto err_exit;
19291f7ea1cdSQi Zhang 	}
19301f7ea1cdSQi Zhang 
19311f7ea1cdSQi Zhang 	stat = kzalloc(sizeof(*stat), GFP_KERNEL);
19321f7ea1cdSQi Zhang 	if (!stat) {
19331f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
19341f7ea1cdSQi Zhang 		dev_dbg(dev, "Alloc stat for VF %d failed\n", vf->vf_id);
19351f7ea1cdSQi Zhang 		goto err_exit;
19361f7ea1cdSQi Zhang 	}
19371f7ea1cdSQi Zhang 
19381f7ea1cdSQi Zhang 	len = sizeof(*stat);
19391f7ea1cdSQi Zhang 
19401f7ea1cdSQi Zhang 	conf = ice_vc_fdir_lookup_entry(vf, fltr->flow_id);
19411f7ea1cdSQi Zhang 	if (!conf) {
19421f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
19431f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST;
19441f7ea1cdSQi Zhang 		dev_dbg(dev, "VF %d: FDIR invalid flow_id:0x%X\n",
19451f7ea1cdSQi Zhang 			vf->vf_id, fltr->flow_id);
19461f7ea1cdSQi Zhang 		goto err_exit;
19471f7ea1cdSQi Zhang 	}
19481f7ea1cdSQi Zhang 
19491f7ea1cdSQi Zhang 	/* Just return failure when ctrl_vsi idx is invalid */
19501f7ea1cdSQi Zhang 	if (vf->ctrl_vsi_idx == ICE_NO_VSI) {
19511f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
19521f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
19531f7ea1cdSQi Zhang 		dev_err(dev, "Invalid FDIR ctrl_vsi for VF %d\n", vf->vf_id);
19541f7ea1cdSQi Zhang 		goto err_exit;
19551f7ea1cdSQi Zhang 	}
19561f7ea1cdSQi Zhang 
1957d6218317SQi Zhang 	ret = ice_vc_fdir_set_irq_ctx(vf, conf, VIRTCHNL_OP_DEL_FDIR_FILTER);
1958d6218317SQi Zhang 	if (ret) {
1959d6218317SQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
1960d6218317SQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
1961d6218317SQi Zhang 		dev_dbg(dev, "VF %d: set FDIR context failed\n", vf->vf_id);
1962d6218317SQi Zhang 		goto err_exit;
1963d6218317SQi Zhang 	}
1964d6218317SQi Zhang 
19651f7ea1cdSQi Zhang 	ret = ice_vc_fdir_write_fltr(vf, conf, false, is_tun);
19661f7ea1cdSQi Zhang 	if (ret) {
19671f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
19681f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
19691f7ea1cdSQi Zhang 		dev_err(dev, "VF %d: writing FDIR rule failed, ret:%d\n",
19701f7ea1cdSQi Zhang 			vf->vf_id, ret);
1971d6218317SQi Zhang 		goto err_del_tmr;
19721f7ea1cdSQi Zhang 	}
19731f7ea1cdSQi Zhang 
1974d6218317SQi Zhang 	kfree(stat);
19751f7ea1cdSQi Zhang 
1976d6218317SQi Zhang 	return ret;
19771f7ea1cdSQi Zhang 
1978d6218317SQi Zhang err_del_tmr:
1979d6218317SQi Zhang 	ice_vc_fdir_clear_irq_ctx(vf);
19801f7ea1cdSQi Zhang err_exit:
19811f7ea1cdSQi Zhang 	ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DEL_FDIR_FILTER, v_ret,
19821f7ea1cdSQi Zhang 				    (u8 *)stat, len);
19831f7ea1cdSQi Zhang 	kfree(stat);
19841f7ea1cdSQi Zhang 	return ret;
19851f7ea1cdSQi Zhang }
19861f7ea1cdSQi Zhang 
19871f7ea1cdSQi Zhang /**
19881f7ea1cdSQi Zhang  * ice_vf_fdir_init - init FDIR resource for VF
19891f7ea1cdSQi Zhang  * @vf: pointer to the VF info
19901f7ea1cdSQi Zhang  */
19911f7ea1cdSQi Zhang void ice_vf_fdir_init(struct ice_vf *vf)
19921f7ea1cdSQi Zhang {
19931f7ea1cdSQi Zhang 	struct ice_vf_fdir *fdir = &vf->fdir;
19941f7ea1cdSQi Zhang 
19951f7ea1cdSQi Zhang 	idr_init(&fdir->fdir_rule_idr);
19961f7ea1cdSQi Zhang 	INIT_LIST_HEAD(&fdir->fdir_rule_list);
1997d6218317SQi Zhang 
1998d6218317SQi Zhang 	spin_lock_init(&fdir->ctx_lock);
1999d6218317SQi Zhang 	fdir->ctx_irq.flags = 0;
2000d6218317SQi Zhang 	fdir->ctx_done.flags = 0;
20011f7ea1cdSQi Zhang }
20021f7ea1cdSQi Zhang 
20031f7ea1cdSQi Zhang /**
20041f7ea1cdSQi Zhang  * ice_vf_fdir_exit - destroy FDIR resource for VF
20051f7ea1cdSQi Zhang  * @vf: pointer to the VF info
20061f7ea1cdSQi Zhang  */
20071f7ea1cdSQi Zhang void ice_vf_fdir_exit(struct ice_vf *vf)
20081f7ea1cdSQi Zhang {
20091f7ea1cdSQi Zhang 	ice_vc_fdir_flush_entry(vf);
20101f7ea1cdSQi Zhang 	idr_destroy(&vf->fdir.fdir_rule_idr);
20111f7ea1cdSQi Zhang 	ice_vc_fdir_rem_prof_all(vf);
20121f7ea1cdSQi Zhang 	ice_vc_fdir_free_prof_all(vf);
20131f7ea1cdSQi Zhang }
2014