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
ice_vc_fdir_param_check(struct ice_vf * vf,u16 vsi_id)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 (!ice_vc_isvalid_vsi_id(vf, vsi_id))
1111f7ea1cdSQi Zhang 		return -EINVAL;
1121f7ea1cdSQi Zhang 
113772dec64SBrett Creeley 	if (!ice_get_vf_vsi(vf))
1141f7ea1cdSQi Zhang 		return -EINVAL;
1151f7ea1cdSQi Zhang 
1161f7ea1cdSQi Zhang 	return 0;
1171f7ea1cdSQi Zhang }
1181f7ea1cdSQi Zhang 
1191f7ea1cdSQi Zhang /**
1201f7ea1cdSQi Zhang  * ice_vf_start_ctrl_vsi
1211f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
1221f7ea1cdSQi Zhang  *
1231f7ea1cdSQi Zhang  * Allocate ctrl_vsi for the first time and open the ctrl_vsi port for VF
1241f7ea1cdSQi Zhang  *
1251f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
1261f7ea1cdSQi Zhang  */
ice_vf_start_ctrl_vsi(struct ice_vf * vf)1271f7ea1cdSQi Zhang static int ice_vf_start_ctrl_vsi(struct ice_vf *vf)
1281f7ea1cdSQi Zhang {
1291f7ea1cdSQi Zhang 	struct ice_pf *pf = vf->pf;
1301f7ea1cdSQi Zhang 	struct ice_vsi *ctrl_vsi;
1311f7ea1cdSQi Zhang 	struct device *dev;
1321f7ea1cdSQi Zhang 	int err;
1331f7ea1cdSQi Zhang 
1341f7ea1cdSQi Zhang 	dev = ice_pf_to_dev(pf);
1351f7ea1cdSQi Zhang 	if (vf->ctrl_vsi_idx != ICE_NO_VSI)
1361f7ea1cdSQi Zhang 		return -EEXIST;
1371f7ea1cdSQi Zhang 
1381f7ea1cdSQi Zhang 	ctrl_vsi = ice_vf_ctrl_vsi_setup(vf);
1391f7ea1cdSQi Zhang 	if (!ctrl_vsi) {
1401f7ea1cdSQi Zhang 		dev_dbg(dev, "Could not setup control VSI for VF %d\n",
1411f7ea1cdSQi Zhang 			vf->vf_id);
1421f7ea1cdSQi Zhang 		return -ENOMEM;
1431f7ea1cdSQi Zhang 	}
1441f7ea1cdSQi Zhang 
1451f7ea1cdSQi Zhang 	err = ice_vsi_open_ctrl(ctrl_vsi);
1461f7ea1cdSQi Zhang 	if (err) {
1471f7ea1cdSQi Zhang 		dev_dbg(dev, "Could not open control VSI for VF %d\n",
1481f7ea1cdSQi Zhang 			vf->vf_id);
1491f7ea1cdSQi Zhang 		goto err_vsi_open;
1501f7ea1cdSQi Zhang 	}
1511f7ea1cdSQi Zhang 
1521f7ea1cdSQi Zhang 	return 0;
1531f7ea1cdSQi Zhang 
1541f7ea1cdSQi Zhang err_vsi_open:
1551f7ea1cdSQi Zhang 	ice_vsi_release(ctrl_vsi);
1561f7ea1cdSQi Zhang 	if (vf->ctrl_vsi_idx != ICE_NO_VSI) {
1571f7ea1cdSQi Zhang 		pf->vsi[vf->ctrl_vsi_idx] = NULL;
1581f7ea1cdSQi Zhang 		vf->ctrl_vsi_idx = ICE_NO_VSI;
1591f7ea1cdSQi Zhang 	}
1601f7ea1cdSQi Zhang 	return err;
1611f7ea1cdSQi Zhang }
1621f7ea1cdSQi Zhang 
1631f7ea1cdSQi Zhang /**
1641f7ea1cdSQi Zhang  * ice_vc_fdir_alloc_prof - allocate profile for this filter flow type
1651f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
1661f7ea1cdSQi Zhang  * @flow: filter flow type
1671f7ea1cdSQi Zhang  *
1681f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
1691f7ea1cdSQi Zhang  */
1701f7ea1cdSQi Zhang static int
ice_vc_fdir_alloc_prof(struct ice_vf * vf,enum ice_fltr_ptype flow)1711f7ea1cdSQi Zhang ice_vc_fdir_alloc_prof(struct ice_vf *vf, enum ice_fltr_ptype flow)
1721f7ea1cdSQi Zhang {
1731f7ea1cdSQi Zhang 	struct ice_vf_fdir *fdir = &vf->fdir;
1741f7ea1cdSQi Zhang 
1751f7ea1cdSQi Zhang 	if (!fdir->fdir_prof) {
1761f7ea1cdSQi Zhang 		fdir->fdir_prof = devm_kcalloc(ice_pf_to_dev(vf->pf),
1771f7ea1cdSQi Zhang 					       ICE_FLTR_PTYPE_MAX,
1781f7ea1cdSQi Zhang 					       sizeof(*fdir->fdir_prof),
1791f7ea1cdSQi Zhang 					       GFP_KERNEL);
1801f7ea1cdSQi Zhang 		if (!fdir->fdir_prof)
1811f7ea1cdSQi Zhang 			return -ENOMEM;
1821f7ea1cdSQi Zhang 	}
1831f7ea1cdSQi Zhang 
1841f7ea1cdSQi Zhang 	if (!fdir->fdir_prof[flow]) {
1851f7ea1cdSQi Zhang 		fdir->fdir_prof[flow] = devm_kzalloc(ice_pf_to_dev(vf->pf),
1861f7ea1cdSQi Zhang 						     sizeof(**fdir->fdir_prof),
1871f7ea1cdSQi Zhang 						     GFP_KERNEL);
1881f7ea1cdSQi Zhang 		if (!fdir->fdir_prof[flow])
1891f7ea1cdSQi Zhang 			return -ENOMEM;
1901f7ea1cdSQi Zhang 	}
1911f7ea1cdSQi Zhang 
1921f7ea1cdSQi Zhang 	return 0;
1931f7ea1cdSQi Zhang }
1941f7ea1cdSQi Zhang 
1951f7ea1cdSQi Zhang /**
1961f7ea1cdSQi Zhang  * ice_vc_fdir_free_prof - free profile for this filter flow type
1971f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
1981f7ea1cdSQi Zhang  * @flow: filter flow type
1991f7ea1cdSQi Zhang  */
2001f7ea1cdSQi Zhang static void
ice_vc_fdir_free_prof(struct ice_vf * vf,enum ice_fltr_ptype flow)2011f7ea1cdSQi Zhang ice_vc_fdir_free_prof(struct ice_vf *vf, enum ice_fltr_ptype flow)
2021f7ea1cdSQi Zhang {
2031f7ea1cdSQi Zhang 	struct ice_vf_fdir *fdir = &vf->fdir;
2041f7ea1cdSQi Zhang 
2051f7ea1cdSQi Zhang 	if (!fdir->fdir_prof)
2061f7ea1cdSQi Zhang 		return;
2071f7ea1cdSQi Zhang 
2081f7ea1cdSQi Zhang 	if (!fdir->fdir_prof[flow])
2091f7ea1cdSQi Zhang 		return;
2101f7ea1cdSQi Zhang 
2111f7ea1cdSQi Zhang 	devm_kfree(ice_pf_to_dev(vf->pf), fdir->fdir_prof[flow]);
2121f7ea1cdSQi Zhang 	fdir->fdir_prof[flow] = NULL;
2131f7ea1cdSQi Zhang }
2141f7ea1cdSQi Zhang 
2151f7ea1cdSQi Zhang /**
2161f7ea1cdSQi Zhang  * ice_vc_fdir_free_prof_all - free all the profile for this VF
2171f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
2181f7ea1cdSQi Zhang  */
ice_vc_fdir_free_prof_all(struct ice_vf * vf)2191f7ea1cdSQi Zhang static void ice_vc_fdir_free_prof_all(struct ice_vf *vf)
2201f7ea1cdSQi Zhang {
2211f7ea1cdSQi Zhang 	struct ice_vf_fdir *fdir = &vf->fdir;
2221f7ea1cdSQi Zhang 	enum ice_fltr_ptype flow;
2231f7ea1cdSQi Zhang 
2241f7ea1cdSQi Zhang 	if (!fdir->fdir_prof)
2251f7ea1cdSQi Zhang 		return;
2261f7ea1cdSQi Zhang 
2271f7ea1cdSQi Zhang 	for (flow = ICE_FLTR_PTYPE_NONF_NONE; flow < ICE_FLTR_PTYPE_MAX; flow++)
2281f7ea1cdSQi Zhang 		ice_vc_fdir_free_prof(vf, flow);
2291f7ea1cdSQi Zhang 
2301f7ea1cdSQi Zhang 	devm_kfree(ice_pf_to_dev(vf->pf), fdir->fdir_prof);
2311f7ea1cdSQi Zhang 	fdir->fdir_prof = NULL;
2321f7ea1cdSQi Zhang }
2331f7ea1cdSQi Zhang 
2341f7ea1cdSQi Zhang /**
2351f7ea1cdSQi Zhang  * ice_vc_fdir_parse_flow_fld
2361f7ea1cdSQi Zhang  * @proto_hdr: virtual channel protocol filter header
2371f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
2381f7ea1cdSQi Zhang  * @fld: field type array
2391f7ea1cdSQi Zhang  * @fld_cnt: field counter
2401f7ea1cdSQi Zhang  *
2411f7ea1cdSQi Zhang  * Parse the virtual channel filter header and store them into field type array
2421f7ea1cdSQi Zhang  *
2431f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
2441f7ea1cdSQi Zhang  */
2451f7ea1cdSQi Zhang static int
ice_vc_fdir_parse_flow_fld(struct virtchnl_proto_hdr * proto_hdr,struct virtchnl_fdir_fltr_conf * conf,enum ice_flow_field * fld,int * fld_cnt)2461f7ea1cdSQi Zhang ice_vc_fdir_parse_flow_fld(struct virtchnl_proto_hdr *proto_hdr,
2471f7ea1cdSQi Zhang 			   struct virtchnl_fdir_fltr_conf *conf,
2481f7ea1cdSQi Zhang 			   enum ice_flow_field *fld, int *fld_cnt)
2491f7ea1cdSQi Zhang {
2501f7ea1cdSQi Zhang 	struct virtchnl_proto_hdr hdr;
2511f7ea1cdSQi Zhang 	u32 i;
2521f7ea1cdSQi Zhang 
2531f7ea1cdSQi Zhang 	memcpy(&hdr, proto_hdr, sizeof(hdr));
2541f7ea1cdSQi Zhang 
2551f7ea1cdSQi Zhang 	for (i = 0; (i < ARRAY_SIZE(fdir_inset_map)) &&
2561f7ea1cdSQi Zhang 	     VIRTCHNL_GET_PROTO_HDR_FIELD(&hdr); i++)
2571f7ea1cdSQi Zhang 		if (VIRTCHNL_TEST_PROTO_HDR(&hdr, fdir_inset_map[i].field)) {
258213528feSQi Zhang 			if (fdir_inset_map[i].mask &&
259213528feSQi Zhang 			    ((fdir_inset_map[i].mask & conf->inset_flag) !=
260213528feSQi Zhang 			     fdir_inset_map[i].flag))
261213528feSQi Zhang 				continue;
262213528feSQi Zhang 
2631f7ea1cdSQi Zhang 			fld[*fld_cnt] = fdir_inset_map[i].fld;
2641f7ea1cdSQi Zhang 			*fld_cnt += 1;
2651f7ea1cdSQi Zhang 			if (*fld_cnt >= ICE_FLOW_FIELD_IDX_MAX)
2661f7ea1cdSQi Zhang 				return -EINVAL;
2671f7ea1cdSQi Zhang 			VIRTCHNL_DEL_PROTO_HDR_FIELD(&hdr,
2681f7ea1cdSQi Zhang 						     fdir_inset_map[i].field);
2691f7ea1cdSQi Zhang 		}
2701f7ea1cdSQi Zhang 
2711f7ea1cdSQi Zhang 	return 0;
2721f7ea1cdSQi Zhang }
2731f7ea1cdSQi Zhang 
2741f7ea1cdSQi Zhang /**
2751f7ea1cdSQi Zhang  * ice_vc_fdir_set_flow_fld
2761f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
2771f7ea1cdSQi Zhang  * @fltr: virtual channel add cmd buffer
2781f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
2791f7ea1cdSQi Zhang  * @seg: array of one or more packet segments that describe the flow
2801f7ea1cdSQi Zhang  *
2811f7ea1cdSQi Zhang  * Parse the virtual channel add msg buffer's field vector and store them into
2821f7ea1cdSQi Zhang  * flow's packet segment field
2831f7ea1cdSQi Zhang  *
2841f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
2851f7ea1cdSQi Zhang  */
2861f7ea1cdSQi Zhang static int
ice_vc_fdir_set_flow_fld(struct ice_vf * vf,struct virtchnl_fdir_add * fltr,struct virtchnl_fdir_fltr_conf * conf,struct ice_flow_seg_info * seg)2871f7ea1cdSQi Zhang ice_vc_fdir_set_flow_fld(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
2881f7ea1cdSQi Zhang 			 struct virtchnl_fdir_fltr_conf *conf,
2891f7ea1cdSQi Zhang 			 struct ice_flow_seg_info *seg)
2901f7ea1cdSQi Zhang {
2911f7ea1cdSQi Zhang 	struct virtchnl_fdir_rule *rule = &fltr->rule_cfg;
2921f7ea1cdSQi Zhang 	enum ice_flow_field fld[ICE_FLOW_FIELD_IDX_MAX];
2931f7ea1cdSQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
2941f7ea1cdSQi Zhang 	struct virtchnl_proto_hdrs *proto;
2951f7ea1cdSQi Zhang 	int fld_cnt = 0;
2961f7ea1cdSQi Zhang 	int i;
2971f7ea1cdSQi Zhang 
2981f7ea1cdSQi Zhang 	proto = &rule->proto_hdrs;
2991f7ea1cdSQi Zhang 	for (i = 0; i < proto->count; i++) {
3001f7ea1cdSQi Zhang 		struct virtchnl_proto_hdr *hdr = &proto->proto_hdr[i];
3011f7ea1cdSQi Zhang 		int ret;
3021f7ea1cdSQi Zhang 
3031f7ea1cdSQi Zhang 		ret = ice_vc_fdir_parse_flow_fld(hdr, conf, fld, &fld_cnt);
3041f7ea1cdSQi Zhang 		if (ret)
3051f7ea1cdSQi Zhang 			return ret;
3061f7ea1cdSQi Zhang 	}
3071f7ea1cdSQi Zhang 
3081f7ea1cdSQi Zhang 	if (fld_cnt == 0) {
3091f7ea1cdSQi Zhang 		dev_dbg(dev, "Empty input set for VF %d\n", vf->vf_id);
3101f7ea1cdSQi Zhang 		return -EINVAL;
3111f7ea1cdSQi Zhang 	}
3121f7ea1cdSQi Zhang 
3131f7ea1cdSQi Zhang 	for (i = 0; i < fld_cnt; i++)
3141f7ea1cdSQi Zhang 		ice_flow_set_fld(seg, fld[i],
3151f7ea1cdSQi Zhang 				 ICE_FLOW_FLD_OFF_INVAL,
3161f7ea1cdSQi Zhang 				 ICE_FLOW_FLD_OFF_INVAL,
3171f7ea1cdSQi Zhang 				 ICE_FLOW_FLD_OFF_INVAL, false);
3181f7ea1cdSQi Zhang 
3191f7ea1cdSQi Zhang 	return 0;
3201f7ea1cdSQi Zhang }
3211f7ea1cdSQi Zhang 
3221f7ea1cdSQi Zhang /**
3231f7ea1cdSQi Zhang  * ice_vc_fdir_set_flow_hdr - config the flow's packet segment header
3241f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
3251f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
3261f7ea1cdSQi Zhang  * @seg: array of one or more packet segments that describe the flow
3271f7ea1cdSQi Zhang  *
3281f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
3291f7ea1cdSQi Zhang  */
3301f7ea1cdSQi Zhang static int
ice_vc_fdir_set_flow_hdr(struct ice_vf * vf,struct virtchnl_fdir_fltr_conf * conf,struct ice_flow_seg_info * seg)3311f7ea1cdSQi Zhang ice_vc_fdir_set_flow_hdr(struct ice_vf *vf,
3321f7ea1cdSQi Zhang 			 struct virtchnl_fdir_fltr_conf *conf,
3331f7ea1cdSQi Zhang 			 struct ice_flow_seg_info *seg)
3341f7ea1cdSQi Zhang {
3351f7ea1cdSQi Zhang 	enum ice_fltr_ptype flow = conf->input.flow_type;
336ef9e4cc5SQi Zhang 	enum ice_fdir_tunnel_type ttype = conf->ttype;
3371f7ea1cdSQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
3381f7ea1cdSQi Zhang 
3391f7ea1cdSQi Zhang 	switch (flow) {
34021606584SQi Zhang 	case ICE_FLTR_PTYPE_NON_IP_L2:
34121606584SQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ETH_NON_IP);
34221606584SQi Zhang 		break;
343213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV3:
344213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_L2TPV3 |
345213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
346213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
347213528feSQi Zhang 		break;
348213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_ESP:
349213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ESP |
350213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
351213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
352213528feSQi Zhang 		break;
353213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_AH:
354213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_AH |
355213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
356213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
357213528feSQi Zhang 		break;
358213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_NAT_T_ESP:
359213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_NAT_T_ESP |
360213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
361213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
362213528feSQi Zhang 		break;
363213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_PFCP_NODE:
364213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_PFCP_NODE |
365213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
366213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
367213528feSQi Zhang 		break;
368213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_PFCP_SESSION:
369213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_PFCP_SESSION |
370213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
371213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
372213528feSQi Zhang 		break;
3731f7ea1cdSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_OTHER:
3741f7ea1cdSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4 |
3751f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
3761f7ea1cdSQi Zhang 		break;
3771f7ea1cdSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_TCP:
3781f7ea1cdSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_TCP |
3791f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
3801f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
3811f7ea1cdSQi Zhang 		break;
3821f7ea1cdSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_UDP:
3831f7ea1cdSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_UDP |
3841f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
3851f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
3861f7ea1cdSQi Zhang 		break;
387ef9e4cc5SQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_UDP:
388ef9e4cc5SQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_TCP:
389ef9e4cc5SQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_ICMP:
390ef9e4cc5SQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER:
391ef9e4cc5SQi Zhang 		if (ttype == ICE_FDIR_TUNNEL_TYPE_GTPU) {
392ef9e4cc5SQi Zhang 			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_IP |
393ef9e4cc5SQi Zhang 					  ICE_FLOW_SEG_HDR_IPV4 |
394ef9e4cc5SQi Zhang 					  ICE_FLOW_SEG_HDR_IPV_OTHER);
395ef9e4cc5SQi Zhang 		} else if (ttype == ICE_FDIR_TUNNEL_TYPE_GTPU_EH) {
396ef9e4cc5SQi Zhang 			ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_EH |
397ef9e4cc5SQi Zhang 					  ICE_FLOW_SEG_HDR_GTPU_IP |
398ef9e4cc5SQi Zhang 					  ICE_FLOW_SEG_HDR_IPV4 |
399ef9e4cc5SQi Zhang 					  ICE_FLOW_SEG_HDR_IPV_OTHER);
400ef9e4cc5SQi Zhang 		} else {
401ef9e4cc5SQi Zhang 			dev_dbg(dev, "Invalid tunnel type 0x%x for VF %d\n",
402ef9e4cc5SQi Zhang 				flow, vf->vf_id);
403ef9e4cc5SQi Zhang 			return -EINVAL;
404ef9e4cc5SQi Zhang 		}
405ef9e4cc5SQi Zhang 		break;
4061f7ea1cdSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV4_SCTP:
4071f7ea1cdSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_SCTP |
4081f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV4 |
4091f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
4101f7ea1cdSQi Zhang 		break;
411213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV3:
412213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_L2TPV3 |
413213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
414213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
415213528feSQi Zhang 		break;
416213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_ESP:
417213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ESP |
418213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
419213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
420213528feSQi Zhang 		break;
421213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_AH:
422213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_AH |
423213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
424213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
425213528feSQi Zhang 		break;
426213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_NAT_T_ESP:
427213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_NAT_T_ESP |
428213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
429213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
430213528feSQi Zhang 		break;
431213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_PFCP_NODE:
432213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_PFCP_NODE |
433213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
434213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
435213528feSQi Zhang 		break;
436213528feSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_PFCP_SESSION:
437213528feSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_PFCP_SESSION |
438213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
439213528feSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
440213528feSQi Zhang 		break;
4411f7ea1cdSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_OTHER:
4421f7ea1cdSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV6 |
4431f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
4441f7ea1cdSQi Zhang 		break;
4451f7ea1cdSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_TCP:
4461f7ea1cdSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_TCP |
4471f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
4481f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
4491f7ea1cdSQi Zhang 		break;
4501f7ea1cdSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_UDP:
4511f7ea1cdSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_UDP |
4521f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
4531f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
4541f7ea1cdSQi Zhang 		break;
4551f7ea1cdSQi Zhang 	case ICE_FLTR_PTYPE_NONF_IPV6_SCTP:
4561f7ea1cdSQi Zhang 		ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_SCTP |
4571f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV6 |
4581f7ea1cdSQi Zhang 				  ICE_FLOW_SEG_HDR_IPV_OTHER);
4591f7ea1cdSQi Zhang 		break;
4601f7ea1cdSQi Zhang 	default:
4611f7ea1cdSQi Zhang 		dev_dbg(dev, "Invalid flow type 0x%x for VF %d failed\n",
4621f7ea1cdSQi Zhang 			flow, vf->vf_id);
4631f7ea1cdSQi Zhang 		return -EINVAL;
4641f7ea1cdSQi Zhang 	}
4651f7ea1cdSQi Zhang 
4661f7ea1cdSQi Zhang 	return 0;
4671f7ea1cdSQi Zhang }
4681f7ea1cdSQi Zhang 
4691f7ea1cdSQi Zhang /**
4701f7ea1cdSQi Zhang  * ice_vc_fdir_rem_prof - remove profile for this filter flow type
4711f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
4721f7ea1cdSQi Zhang  * @flow: filter flow type
4731f7ea1cdSQi Zhang  * @tun: 0 implies non-tunnel type filter, 1 implies tunnel type filter
4741f7ea1cdSQi Zhang  */
4751f7ea1cdSQi Zhang static void
ice_vc_fdir_rem_prof(struct ice_vf * vf,enum ice_fltr_ptype flow,int tun)4761f7ea1cdSQi Zhang ice_vc_fdir_rem_prof(struct ice_vf *vf, enum ice_fltr_ptype flow, int tun)
4771f7ea1cdSQi Zhang {
4781f7ea1cdSQi Zhang 	struct ice_vf_fdir *fdir = &vf->fdir;
4791f7ea1cdSQi Zhang 	struct ice_fd_hw_prof *vf_prof;
4801f7ea1cdSQi Zhang 	struct ice_pf *pf = vf->pf;
4811f7ea1cdSQi Zhang 	struct ice_vsi *vf_vsi;
4821f7ea1cdSQi Zhang 	struct device *dev;
4831f7ea1cdSQi Zhang 	struct ice_hw *hw;
4841f7ea1cdSQi Zhang 	u64 prof_id;
4851f7ea1cdSQi Zhang 	int i;
4861f7ea1cdSQi Zhang 
4871f7ea1cdSQi Zhang 	dev = ice_pf_to_dev(pf);
4881f7ea1cdSQi Zhang 	hw = &pf->hw;
4891f7ea1cdSQi Zhang 	if (!fdir->fdir_prof || !fdir->fdir_prof[flow])
4901f7ea1cdSQi Zhang 		return;
4911f7ea1cdSQi Zhang 
4921f7ea1cdSQi Zhang 	vf_prof = fdir->fdir_prof[flow];
4931f7ea1cdSQi Zhang 
494772dec64SBrett Creeley 	vf_vsi = ice_get_vf_vsi(vf);
4951f7ea1cdSQi Zhang 	if (!vf_vsi) {
4961f7ea1cdSQi Zhang 		dev_dbg(dev, "NULL vf %d vsi pointer\n", vf->vf_id);
4971f7ea1cdSQi Zhang 		return;
4981f7ea1cdSQi Zhang 	}
4991f7ea1cdSQi Zhang 
5001f7ea1cdSQi Zhang 	if (!fdir->prof_entry_cnt[flow][tun])
5011f7ea1cdSQi Zhang 		return;
5021f7ea1cdSQi Zhang 
5031f7ea1cdSQi Zhang 	prof_id = ICE_FLOW_PROF_FD(vf_vsi->vsi_num,
5041f7ea1cdSQi Zhang 				   flow, tun ? ICE_FLTR_PTYPE_MAX : 0);
5051f7ea1cdSQi Zhang 
5061f7ea1cdSQi Zhang 	for (i = 0; i < fdir->prof_entry_cnt[flow][tun]; i++)
5071f7ea1cdSQi Zhang 		if (vf_prof->entry_h[i][tun]) {
5081f7ea1cdSQi Zhang 			u16 vsi_num = ice_get_hw_vsi_num(hw, vf_prof->vsi_h[i]);
5091f7ea1cdSQi Zhang 
5101f7ea1cdSQi Zhang 			ice_rem_prof_id_flow(hw, ICE_BLK_FD, vsi_num, prof_id);
5111f7ea1cdSQi Zhang 			ice_flow_rem_entry(hw, ICE_BLK_FD,
5121f7ea1cdSQi Zhang 					   vf_prof->entry_h[i][tun]);
5131f7ea1cdSQi Zhang 			vf_prof->entry_h[i][tun] = 0;
5141f7ea1cdSQi Zhang 		}
5151f7ea1cdSQi Zhang 
5161f7ea1cdSQi Zhang 	ice_flow_rem_prof(hw, ICE_BLK_FD, prof_id);
5171f7ea1cdSQi Zhang 	devm_kfree(dev, vf_prof->fdir_seg[tun]);
5181f7ea1cdSQi Zhang 	vf_prof->fdir_seg[tun] = NULL;
5191f7ea1cdSQi Zhang 
5201f7ea1cdSQi Zhang 	for (i = 0; i < vf_prof->cnt; i++)
5211f7ea1cdSQi Zhang 		vf_prof->vsi_h[i] = 0;
5221f7ea1cdSQi Zhang 
5231f7ea1cdSQi Zhang 	fdir->prof_entry_cnt[flow][tun] = 0;
5241f7ea1cdSQi Zhang }
5251f7ea1cdSQi Zhang 
5261f7ea1cdSQi Zhang /**
5271f7ea1cdSQi Zhang  * ice_vc_fdir_rem_prof_all - remove profile for this VF
5281f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
5291f7ea1cdSQi Zhang  */
ice_vc_fdir_rem_prof_all(struct ice_vf * vf)5301f7ea1cdSQi Zhang static void ice_vc_fdir_rem_prof_all(struct ice_vf *vf)
5311f7ea1cdSQi Zhang {
5321f7ea1cdSQi Zhang 	enum ice_fltr_ptype flow;
5331f7ea1cdSQi Zhang 
5341f7ea1cdSQi Zhang 	for (flow = ICE_FLTR_PTYPE_NONF_NONE;
5351f7ea1cdSQi Zhang 	     flow < ICE_FLTR_PTYPE_MAX; flow++) {
5361f7ea1cdSQi Zhang 		ice_vc_fdir_rem_prof(vf, flow, 0);
5371f7ea1cdSQi Zhang 		ice_vc_fdir_rem_prof(vf, flow, 1);
5381f7ea1cdSQi Zhang 	}
5391f7ea1cdSQi Zhang }
5401f7ea1cdSQi Zhang 
5411f7ea1cdSQi Zhang /**
542*83c911dcSLingyu Liu  * ice_vc_fdir_reset_cnt_all - reset all FDIR counters for this VF FDIR
543*83c911dcSLingyu Liu  * @fdir: pointer to the VF FDIR structure
544*83c911dcSLingyu Liu  */
ice_vc_fdir_reset_cnt_all(struct ice_vf_fdir * fdir)545*83c911dcSLingyu Liu static void ice_vc_fdir_reset_cnt_all(struct ice_vf_fdir *fdir)
546*83c911dcSLingyu Liu {
547*83c911dcSLingyu Liu 	enum ice_fltr_ptype flow;
548*83c911dcSLingyu Liu 
549*83c911dcSLingyu Liu 	for (flow = ICE_FLTR_PTYPE_NONF_NONE;
550*83c911dcSLingyu Liu 	     flow < ICE_FLTR_PTYPE_MAX; flow++) {
551*83c911dcSLingyu Liu 		fdir->fdir_fltr_cnt[flow][0] = 0;
552*83c911dcSLingyu Liu 		fdir->fdir_fltr_cnt[flow][1] = 0;
553*83c911dcSLingyu Liu 	}
554*83c911dcSLingyu Liu }
555*83c911dcSLingyu Liu 
556*83c911dcSLingyu Liu /**
55729486b6dSJunfeng Guo  * ice_vc_fdir_has_prof_conflict
55829486b6dSJunfeng Guo  * @vf: pointer to the VF structure
55929486b6dSJunfeng Guo  * @conf: FDIR configuration for each filter
56029486b6dSJunfeng Guo  *
56129486b6dSJunfeng Guo  * Check if @conf has conflicting profile with existing profiles
56229486b6dSJunfeng Guo  *
56329486b6dSJunfeng Guo  * Return: true on success, and false on error.
56429486b6dSJunfeng Guo  */
56529486b6dSJunfeng Guo static bool
ice_vc_fdir_has_prof_conflict(struct ice_vf * vf,struct virtchnl_fdir_fltr_conf * conf)56629486b6dSJunfeng Guo ice_vc_fdir_has_prof_conflict(struct ice_vf *vf,
56729486b6dSJunfeng Guo 			      struct virtchnl_fdir_fltr_conf *conf)
56829486b6dSJunfeng Guo {
56929486b6dSJunfeng Guo 	struct ice_fdir_fltr *desc;
57029486b6dSJunfeng Guo 
57129486b6dSJunfeng Guo 	list_for_each_entry(desc, &vf->fdir.fdir_rule_list, fltr_node) {
57229486b6dSJunfeng Guo 		struct virtchnl_fdir_fltr_conf *existing_conf;
57329486b6dSJunfeng Guo 		enum ice_fltr_ptype flow_type_a, flow_type_b;
57429486b6dSJunfeng Guo 		struct ice_fdir_fltr *a, *b;
57529486b6dSJunfeng Guo 
57629486b6dSJunfeng Guo 		existing_conf = to_fltr_conf_from_desc(desc);
57729486b6dSJunfeng Guo 		a = &existing_conf->input;
57829486b6dSJunfeng Guo 		b = &conf->input;
57929486b6dSJunfeng Guo 		flow_type_a = a->flow_type;
58029486b6dSJunfeng Guo 		flow_type_b = b->flow_type;
58129486b6dSJunfeng Guo 
58229486b6dSJunfeng Guo 		/* No need to compare two rules with different tunnel types or
58329486b6dSJunfeng Guo 		 * with the same protocol type.
58429486b6dSJunfeng Guo 		 */
58529486b6dSJunfeng Guo 		if (existing_conf->ttype != conf->ttype ||
58629486b6dSJunfeng Guo 		    flow_type_a == flow_type_b)
58729486b6dSJunfeng Guo 			continue;
58829486b6dSJunfeng Guo 
58929486b6dSJunfeng Guo 		switch (flow_type_a) {
59029486b6dSJunfeng Guo 		case ICE_FLTR_PTYPE_NONF_IPV4_UDP:
59129486b6dSJunfeng Guo 		case ICE_FLTR_PTYPE_NONF_IPV4_TCP:
59229486b6dSJunfeng Guo 		case ICE_FLTR_PTYPE_NONF_IPV4_SCTP:
59329486b6dSJunfeng Guo 			if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_OTHER)
59429486b6dSJunfeng Guo 				return true;
59529486b6dSJunfeng Guo 			break;
59629486b6dSJunfeng Guo 		case ICE_FLTR_PTYPE_NONF_IPV4_OTHER:
59729486b6dSJunfeng Guo 			if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_UDP ||
59829486b6dSJunfeng Guo 			    flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_TCP ||
59929486b6dSJunfeng Guo 			    flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_SCTP)
60029486b6dSJunfeng Guo 				return true;
60129486b6dSJunfeng Guo 			break;
60229486b6dSJunfeng Guo 		case ICE_FLTR_PTYPE_NONF_IPV6_UDP:
60329486b6dSJunfeng Guo 		case ICE_FLTR_PTYPE_NONF_IPV6_TCP:
60429486b6dSJunfeng Guo 		case ICE_FLTR_PTYPE_NONF_IPV6_SCTP:
60529486b6dSJunfeng Guo 			if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_OTHER)
60629486b6dSJunfeng Guo 				return true;
60729486b6dSJunfeng Guo 			break;
60829486b6dSJunfeng Guo 		case ICE_FLTR_PTYPE_NONF_IPV6_OTHER:
60929486b6dSJunfeng Guo 			if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_UDP ||
61029486b6dSJunfeng Guo 			    flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_TCP ||
61129486b6dSJunfeng Guo 			    flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_SCTP)
61229486b6dSJunfeng Guo 				return true;
61329486b6dSJunfeng Guo 			break;
61429486b6dSJunfeng Guo 		default:
61529486b6dSJunfeng Guo 			break;
61629486b6dSJunfeng Guo 		}
61729486b6dSJunfeng Guo 	}
61829486b6dSJunfeng Guo 
61929486b6dSJunfeng Guo 	return false;
62029486b6dSJunfeng Guo }
62129486b6dSJunfeng Guo 
62229486b6dSJunfeng Guo /**
6231f7ea1cdSQi Zhang  * ice_vc_fdir_write_flow_prof
6241f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
6251f7ea1cdSQi Zhang  * @flow: filter flow type
6261f7ea1cdSQi Zhang  * @seg: array of one or more packet segments that describe the flow
6271f7ea1cdSQi Zhang  * @tun: 0 implies non-tunnel type filter, 1 implies tunnel type filter
6281f7ea1cdSQi Zhang  *
6291f7ea1cdSQi Zhang  * Write the flow's profile config and packet segment into the hardware
6301f7ea1cdSQi Zhang  *
6311f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
6321f7ea1cdSQi Zhang  */
6331f7ea1cdSQi Zhang static int
ice_vc_fdir_write_flow_prof(struct ice_vf * vf,enum ice_fltr_ptype flow,struct ice_flow_seg_info * seg,int tun)6341f7ea1cdSQi Zhang ice_vc_fdir_write_flow_prof(struct ice_vf *vf, enum ice_fltr_ptype flow,
6351f7ea1cdSQi Zhang 			    struct ice_flow_seg_info *seg, int tun)
6361f7ea1cdSQi Zhang {
6371f7ea1cdSQi Zhang 	struct ice_vf_fdir *fdir = &vf->fdir;
6381f7ea1cdSQi Zhang 	struct ice_vsi *vf_vsi, *ctrl_vsi;
6391f7ea1cdSQi Zhang 	struct ice_flow_seg_info *old_seg;
6401f7ea1cdSQi Zhang 	struct ice_flow_prof *prof = NULL;
6411f7ea1cdSQi Zhang 	struct ice_fd_hw_prof *vf_prof;
6421f7ea1cdSQi Zhang 	struct device *dev;
6431f7ea1cdSQi Zhang 	struct ice_pf *pf;
6441f7ea1cdSQi Zhang 	struct ice_hw *hw;
6451f7ea1cdSQi Zhang 	u64 entry1_h = 0;
6461f7ea1cdSQi Zhang 	u64 entry2_h = 0;
6471f7ea1cdSQi Zhang 	u64 prof_id;
6481f7ea1cdSQi Zhang 	int ret;
6491f7ea1cdSQi Zhang 
6501f7ea1cdSQi Zhang 	pf = vf->pf;
6511f7ea1cdSQi Zhang 	dev = ice_pf_to_dev(pf);
6521f7ea1cdSQi Zhang 	hw = &pf->hw;
653772dec64SBrett Creeley 	vf_vsi = ice_get_vf_vsi(vf);
6541f7ea1cdSQi Zhang 	if (!vf_vsi)
6551f7ea1cdSQi Zhang 		return -EINVAL;
6561f7ea1cdSQi Zhang 
6571f7ea1cdSQi Zhang 	ctrl_vsi = pf->vsi[vf->ctrl_vsi_idx];
6581f7ea1cdSQi Zhang 	if (!ctrl_vsi)
6591f7ea1cdSQi Zhang 		return -EINVAL;
6601f7ea1cdSQi Zhang 
6611f7ea1cdSQi Zhang 	vf_prof = fdir->fdir_prof[flow];
6621f7ea1cdSQi Zhang 	old_seg = vf_prof->fdir_seg[tun];
6631f7ea1cdSQi Zhang 	if (old_seg) {
6641f7ea1cdSQi Zhang 		if (!memcmp(old_seg, seg, sizeof(*seg))) {
6651f7ea1cdSQi Zhang 			dev_dbg(dev, "Duplicated profile for VF %d!\n",
6661f7ea1cdSQi Zhang 				vf->vf_id);
6671f7ea1cdSQi Zhang 			return -EEXIST;
6681f7ea1cdSQi Zhang 		}
6691f7ea1cdSQi Zhang 
6701f7ea1cdSQi Zhang 		if (fdir->fdir_fltr_cnt[flow][tun]) {
6711f7ea1cdSQi Zhang 			ret = -EINVAL;
6721f7ea1cdSQi Zhang 			dev_dbg(dev, "Input set conflicts for VF %d\n",
6731f7ea1cdSQi Zhang 				vf->vf_id);
6741f7ea1cdSQi Zhang 			goto err_exit;
6751f7ea1cdSQi Zhang 		}
6761f7ea1cdSQi Zhang 
6771f7ea1cdSQi Zhang 		/* remove previously allocated profile */
6781f7ea1cdSQi Zhang 		ice_vc_fdir_rem_prof(vf, flow, tun);
6791f7ea1cdSQi Zhang 	}
6801f7ea1cdSQi Zhang 
6811f7ea1cdSQi Zhang 	prof_id = ICE_FLOW_PROF_FD(vf_vsi->vsi_num, flow,
6821f7ea1cdSQi Zhang 				   tun ? ICE_FLTR_PTYPE_MAX : 0);
6831f7ea1cdSQi Zhang 
6842ccc1c1cSTony Nguyen 	ret = ice_flow_add_prof(hw, ICE_BLK_FD, ICE_FLOW_RX, prof_id, seg,
6851f7ea1cdSQi Zhang 				tun + 1, &prof);
6861f7ea1cdSQi Zhang 	if (ret) {
6871f7ea1cdSQi Zhang 		dev_dbg(dev, "Could not add VSI flow 0x%x for VF %d\n",
6881f7ea1cdSQi Zhang 			flow, vf->vf_id);
6891f7ea1cdSQi Zhang 		goto err_exit;
6901f7ea1cdSQi Zhang 	}
6911f7ea1cdSQi Zhang 
6922ccc1c1cSTony Nguyen 	ret = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id, vf_vsi->idx,
6931f7ea1cdSQi Zhang 				 vf_vsi->idx, ICE_FLOW_PRIO_NORMAL,
6941f7ea1cdSQi Zhang 				 seg, &entry1_h);
6951f7ea1cdSQi Zhang 	if (ret) {
6961f7ea1cdSQi Zhang 		dev_dbg(dev, "Could not add flow 0x%x VSI entry for VF %d\n",
6971f7ea1cdSQi Zhang 			flow, vf->vf_id);
6981f7ea1cdSQi Zhang 		goto err_prof;
6991f7ea1cdSQi Zhang 	}
7001f7ea1cdSQi Zhang 
7012ccc1c1cSTony Nguyen 	ret = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id, vf_vsi->idx,
7021f7ea1cdSQi Zhang 				 ctrl_vsi->idx, ICE_FLOW_PRIO_NORMAL,
7031f7ea1cdSQi Zhang 				 seg, &entry2_h);
7041f7ea1cdSQi Zhang 	if (ret) {
7051f7ea1cdSQi Zhang 		dev_dbg(dev,
7061f7ea1cdSQi Zhang 			"Could not add flow 0x%x Ctrl VSI entry for VF %d\n",
7071f7ea1cdSQi Zhang 			flow, vf->vf_id);
7081f7ea1cdSQi Zhang 		goto err_entry_1;
7091f7ea1cdSQi Zhang 	}
7101f7ea1cdSQi Zhang 
7111f7ea1cdSQi Zhang 	vf_prof->fdir_seg[tun] = seg;
7121f7ea1cdSQi Zhang 	vf_prof->cnt = 0;
7131f7ea1cdSQi Zhang 	fdir->prof_entry_cnt[flow][tun] = 0;
7141f7ea1cdSQi Zhang 
7151f7ea1cdSQi Zhang 	vf_prof->entry_h[vf_prof->cnt][tun] = entry1_h;
7161f7ea1cdSQi Zhang 	vf_prof->vsi_h[vf_prof->cnt] = vf_vsi->idx;
7171f7ea1cdSQi Zhang 	vf_prof->cnt++;
7181f7ea1cdSQi Zhang 	fdir->prof_entry_cnt[flow][tun]++;
7191f7ea1cdSQi Zhang 
7201f7ea1cdSQi Zhang 	vf_prof->entry_h[vf_prof->cnt][tun] = entry2_h;
7211f7ea1cdSQi Zhang 	vf_prof->vsi_h[vf_prof->cnt] = ctrl_vsi->idx;
7221f7ea1cdSQi Zhang 	vf_prof->cnt++;
7231f7ea1cdSQi Zhang 	fdir->prof_entry_cnt[flow][tun]++;
7241f7ea1cdSQi Zhang 
7251f7ea1cdSQi Zhang 	return 0;
7261f7ea1cdSQi Zhang 
7271f7ea1cdSQi Zhang err_entry_1:
7281f7ea1cdSQi Zhang 	ice_rem_prof_id_flow(hw, ICE_BLK_FD,
7291f7ea1cdSQi Zhang 			     ice_get_hw_vsi_num(hw, vf_vsi->idx), prof_id);
7301f7ea1cdSQi Zhang 	ice_flow_rem_entry(hw, ICE_BLK_FD, entry1_h);
7311f7ea1cdSQi Zhang err_prof:
7321f7ea1cdSQi Zhang 	ice_flow_rem_prof(hw, ICE_BLK_FD, prof_id);
7331f7ea1cdSQi Zhang err_exit:
7341f7ea1cdSQi Zhang 	return ret;
7351f7ea1cdSQi Zhang }
7361f7ea1cdSQi Zhang 
7371f7ea1cdSQi Zhang /**
7381f7ea1cdSQi Zhang  * ice_vc_fdir_config_input_set
7391f7ea1cdSQi Zhang  * @vf: pointer to the VF structure
7401f7ea1cdSQi Zhang  * @fltr: virtual channel add cmd buffer
7411f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
7421f7ea1cdSQi Zhang  * @tun: 0 implies non-tunnel type filter, 1 implies tunnel type filter
7431f7ea1cdSQi Zhang  *
7441f7ea1cdSQi Zhang  * Config the input set type and value for virtual channel add msg buffer
7451f7ea1cdSQi Zhang  *
7461f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
7471f7ea1cdSQi Zhang  */
7481f7ea1cdSQi Zhang static int
ice_vc_fdir_config_input_set(struct ice_vf * vf,struct virtchnl_fdir_add * fltr,struct virtchnl_fdir_fltr_conf * conf,int tun)7491f7ea1cdSQi Zhang ice_vc_fdir_config_input_set(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
7501f7ea1cdSQi Zhang 			     struct virtchnl_fdir_fltr_conf *conf, int tun)
7511f7ea1cdSQi Zhang {
7521f7ea1cdSQi Zhang 	struct ice_fdir_fltr *input = &conf->input;
7531f7ea1cdSQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
7541f7ea1cdSQi Zhang 	struct ice_flow_seg_info *seg;
7551f7ea1cdSQi Zhang 	enum ice_fltr_ptype flow;
7561f7ea1cdSQi Zhang 	int ret;
7571f7ea1cdSQi Zhang 
75829486b6dSJunfeng Guo 	ret = ice_vc_fdir_has_prof_conflict(vf, conf);
75929486b6dSJunfeng Guo 	if (ret) {
76029486b6dSJunfeng Guo 		dev_dbg(dev, "Found flow profile conflict for VF %d\n",
76129486b6dSJunfeng Guo 			vf->vf_id);
76229486b6dSJunfeng Guo 		return ret;
76329486b6dSJunfeng Guo 	}
76429486b6dSJunfeng Guo 
7651f7ea1cdSQi Zhang 	flow = input->flow_type;
7661f7ea1cdSQi Zhang 	ret = ice_vc_fdir_alloc_prof(vf, flow);
7671f7ea1cdSQi Zhang 	if (ret) {
7681f7ea1cdSQi Zhang 		dev_dbg(dev, "Alloc flow prof for VF %d failed\n", vf->vf_id);
7691f7ea1cdSQi Zhang 		return ret;
7701f7ea1cdSQi Zhang 	}
7711f7ea1cdSQi Zhang 
7721f7ea1cdSQi Zhang 	seg = devm_kzalloc(dev, sizeof(*seg), GFP_KERNEL);
7731f7ea1cdSQi Zhang 	if (!seg)
7741f7ea1cdSQi Zhang 		return -ENOMEM;
7751f7ea1cdSQi Zhang 
7761f7ea1cdSQi Zhang 	ret = ice_vc_fdir_set_flow_fld(vf, fltr, conf, seg);
7771f7ea1cdSQi Zhang 	if (ret) {
7781f7ea1cdSQi Zhang 		dev_dbg(dev, "Set flow field for VF %d failed\n", vf->vf_id);
7791f7ea1cdSQi Zhang 		goto err_exit;
7801f7ea1cdSQi Zhang 	}
7811f7ea1cdSQi Zhang 
7821f7ea1cdSQi Zhang 	ret = ice_vc_fdir_set_flow_hdr(vf, conf, seg);
7831f7ea1cdSQi Zhang 	if (ret) {
7841f7ea1cdSQi Zhang 		dev_dbg(dev, "Set flow hdr for VF %d failed\n", vf->vf_id);
7851f7ea1cdSQi Zhang 		goto err_exit;
7861f7ea1cdSQi Zhang 	}
7871f7ea1cdSQi Zhang 
7881f7ea1cdSQi Zhang 	ret = ice_vc_fdir_write_flow_prof(vf, flow, seg, tun);
7891f7ea1cdSQi Zhang 	if (ret == -EEXIST) {
7901f7ea1cdSQi Zhang 		devm_kfree(dev, seg);
7911f7ea1cdSQi Zhang 	} else if (ret) {
7921f7ea1cdSQi Zhang 		dev_dbg(dev, "Write flow profile for VF %d failed\n",
7931f7ea1cdSQi Zhang 			vf->vf_id);
7941f7ea1cdSQi Zhang 		goto err_exit;
7951f7ea1cdSQi Zhang 	}
7961f7ea1cdSQi Zhang 
7971f7ea1cdSQi Zhang 	return 0;
7981f7ea1cdSQi Zhang 
7991f7ea1cdSQi Zhang err_exit:
8001f7ea1cdSQi Zhang 	devm_kfree(dev, seg);
8011f7ea1cdSQi Zhang 	return ret;
8021f7ea1cdSQi Zhang }
8031f7ea1cdSQi Zhang 
8041f7ea1cdSQi Zhang /**
8050ce332fdSQi Zhang  * ice_vc_fdir_parse_pattern
8060ce332fdSQi Zhang  * @vf: pointer to the VF info
8070ce332fdSQi Zhang  * @fltr: virtual channel add cmd buffer
8080ce332fdSQi Zhang  * @conf: FDIR configuration for each filter
8090ce332fdSQi Zhang  *
8100ce332fdSQi Zhang  * Parse the virtual channel filter's pattern and store them into conf
8110ce332fdSQi Zhang  *
8120ce332fdSQi Zhang  * Return: 0 on success, and other on error.
8130ce332fdSQi Zhang  */
8140ce332fdSQi Zhang static int
ice_vc_fdir_parse_pattern(struct ice_vf * vf,struct virtchnl_fdir_add * fltr,struct virtchnl_fdir_fltr_conf * conf)8150ce332fdSQi Zhang ice_vc_fdir_parse_pattern(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
8160ce332fdSQi Zhang 			  struct virtchnl_fdir_fltr_conf *conf)
8170ce332fdSQi Zhang {
8180ce332fdSQi Zhang 	struct virtchnl_proto_hdrs *proto = &fltr->rule_cfg.proto_hdrs;
8190ce332fdSQi Zhang 	enum virtchnl_proto_hdr_type l3 = VIRTCHNL_PROTO_HDR_NONE;
820213528feSQi Zhang 	enum virtchnl_proto_hdr_type l4 = VIRTCHNL_PROTO_HDR_NONE;
8210ce332fdSQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
8220ce332fdSQi Zhang 	struct ice_fdir_fltr *input = &conf->input;
8230ce332fdSQi Zhang 	int i;
8240ce332fdSQi Zhang 
8250ce332fdSQi Zhang 	if (proto->count > VIRTCHNL_MAX_NUM_PROTO_HDRS) {
8260ce332fdSQi Zhang 		dev_dbg(dev, "Invalid protocol count:0x%x for VF %d\n",
8270ce332fdSQi Zhang 			proto->count, vf->vf_id);
8280ce332fdSQi Zhang 		return -EINVAL;
8290ce332fdSQi Zhang 	}
8300ce332fdSQi Zhang 
8310ce332fdSQi Zhang 	for (i = 0; i < proto->count; i++) {
8320ce332fdSQi Zhang 		struct virtchnl_proto_hdr *hdr = &proto->proto_hdr[i];
833213528feSQi Zhang 		struct ip_esp_hdr *esph;
834213528feSQi Zhang 		struct ip_auth_hdr *ah;
8350ce332fdSQi Zhang 		struct sctphdr *sctph;
8360ce332fdSQi Zhang 		struct ipv6hdr *ip6h;
8370ce332fdSQi Zhang 		struct udphdr *udph;
8380ce332fdSQi Zhang 		struct tcphdr *tcph;
83921606584SQi Zhang 		struct ethhdr *eth;
8400ce332fdSQi Zhang 		struct iphdr *iph;
841213528feSQi Zhang 		u8 s_field;
842ef9e4cc5SQi Zhang 		u8 *rawh;
8430ce332fdSQi Zhang 
8440ce332fdSQi Zhang 		switch (hdr->type) {
8450ce332fdSQi Zhang 		case VIRTCHNL_PROTO_HDR_ETH:
84621606584SQi Zhang 			eth = (struct ethhdr *)hdr->buffer;
84721606584SQi Zhang 			input->flow_type = ICE_FLTR_PTYPE_NON_IP_L2;
84821606584SQi Zhang 
84921606584SQi Zhang 			if (hdr->field_selector)
85021606584SQi Zhang 				input->ext_data.ether_type = eth->h_proto;
8510ce332fdSQi Zhang 			break;
8520ce332fdSQi Zhang 		case VIRTCHNL_PROTO_HDR_IPV4:
8530ce332fdSQi Zhang 			iph = (struct iphdr *)hdr->buffer;
8540ce332fdSQi Zhang 			l3 = VIRTCHNL_PROTO_HDR_IPV4;
8550ce332fdSQi Zhang 			input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_OTHER;
8560ce332fdSQi Zhang 
8570ce332fdSQi Zhang 			if (hdr->field_selector) {
8580ce332fdSQi Zhang 				input->ip.v4.src_ip = iph->saddr;
8590ce332fdSQi Zhang 				input->ip.v4.dst_ip = iph->daddr;
8600ce332fdSQi Zhang 				input->ip.v4.tos = iph->tos;
8610ce332fdSQi Zhang 				input->ip.v4.proto = iph->protocol;
8620ce332fdSQi Zhang 			}
8630ce332fdSQi Zhang 			break;
8640ce332fdSQi Zhang 		case VIRTCHNL_PROTO_HDR_IPV6:
8650ce332fdSQi Zhang 			ip6h = (struct ipv6hdr *)hdr->buffer;
8660ce332fdSQi Zhang 			l3 = VIRTCHNL_PROTO_HDR_IPV6;
8670ce332fdSQi Zhang 			input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_OTHER;
8680ce332fdSQi Zhang 
8690ce332fdSQi Zhang 			if (hdr->field_selector) {
8700ce332fdSQi Zhang 				memcpy(input->ip.v6.src_ip,
8710ce332fdSQi Zhang 				       ip6h->saddr.in6_u.u6_addr8,
8720ce332fdSQi Zhang 				       sizeof(ip6h->saddr));
8730ce332fdSQi Zhang 				memcpy(input->ip.v6.dst_ip,
8740ce332fdSQi Zhang 				       ip6h->daddr.in6_u.u6_addr8,
8750ce332fdSQi Zhang 				       sizeof(ip6h->daddr));
8760ce332fdSQi Zhang 				input->ip.v6.tc = ((u8)(ip6h->priority) << 4) |
8770ce332fdSQi Zhang 						  (ip6h->flow_lbl[0] >> 4);
8780ce332fdSQi Zhang 				input->ip.v6.proto = ip6h->nexthdr;
8790ce332fdSQi Zhang 			}
8800ce332fdSQi Zhang 			break;
8810ce332fdSQi Zhang 		case VIRTCHNL_PROTO_HDR_TCP:
8820ce332fdSQi Zhang 			tcph = (struct tcphdr *)hdr->buffer;
8830ce332fdSQi Zhang 			if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
8840ce332fdSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_TCP;
8850ce332fdSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
8860ce332fdSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_TCP;
8870ce332fdSQi Zhang 
8880ce332fdSQi Zhang 			if (hdr->field_selector) {
8890ce332fdSQi Zhang 				if (l3 == VIRTCHNL_PROTO_HDR_IPV4) {
8900ce332fdSQi Zhang 					input->ip.v4.src_port = tcph->source;
8910ce332fdSQi Zhang 					input->ip.v4.dst_port = tcph->dest;
8920ce332fdSQi Zhang 				} else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) {
8930ce332fdSQi Zhang 					input->ip.v6.src_port = tcph->source;
8940ce332fdSQi Zhang 					input->ip.v6.dst_port = tcph->dest;
8950ce332fdSQi Zhang 				}
8960ce332fdSQi Zhang 			}
8970ce332fdSQi Zhang 			break;
8980ce332fdSQi Zhang 		case VIRTCHNL_PROTO_HDR_UDP:
8990ce332fdSQi Zhang 			udph = (struct udphdr *)hdr->buffer;
9000ce332fdSQi Zhang 			if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
9010ce332fdSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_UDP;
9020ce332fdSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
9030ce332fdSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_UDP;
9040ce332fdSQi Zhang 
9050ce332fdSQi Zhang 			if (hdr->field_selector) {
9060ce332fdSQi Zhang 				if (l3 == VIRTCHNL_PROTO_HDR_IPV4) {
9070ce332fdSQi Zhang 					input->ip.v4.src_port = udph->source;
9080ce332fdSQi Zhang 					input->ip.v4.dst_port = udph->dest;
9090ce332fdSQi Zhang 				} else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) {
9100ce332fdSQi Zhang 					input->ip.v6.src_port = udph->source;
9110ce332fdSQi Zhang 					input->ip.v6.dst_port = udph->dest;
9120ce332fdSQi Zhang 				}
9130ce332fdSQi Zhang 			}
9140ce332fdSQi Zhang 			break;
9150ce332fdSQi Zhang 		case VIRTCHNL_PROTO_HDR_SCTP:
9160ce332fdSQi Zhang 			sctph = (struct sctphdr *)hdr->buffer;
9170ce332fdSQi Zhang 			if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
9180ce332fdSQi Zhang 				input->flow_type =
9190ce332fdSQi Zhang 					ICE_FLTR_PTYPE_NONF_IPV4_SCTP;
9200ce332fdSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
9210ce332fdSQi Zhang 				input->flow_type =
9220ce332fdSQi Zhang 					ICE_FLTR_PTYPE_NONF_IPV6_SCTP;
9230ce332fdSQi Zhang 
9240ce332fdSQi Zhang 			if (hdr->field_selector) {
9250ce332fdSQi Zhang 				if (l3 == VIRTCHNL_PROTO_HDR_IPV4) {
9260ce332fdSQi Zhang 					input->ip.v4.src_port = sctph->source;
9270ce332fdSQi Zhang 					input->ip.v4.dst_port = sctph->dest;
9280ce332fdSQi Zhang 				} else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) {
9290ce332fdSQi Zhang 					input->ip.v6.src_port = sctph->source;
9300ce332fdSQi Zhang 					input->ip.v6.dst_port = sctph->dest;
9310ce332fdSQi Zhang 				}
9320ce332fdSQi Zhang 			}
9330ce332fdSQi Zhang 			break;
934213528feSQi Zhang 		case VIRTCHNL_PROTO_HDR_L2TPV3:
935213528feSQi Zhang 			if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
936213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_L2TPV3;
937213528feSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
938213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_L2TPV3;
939213528feSQi Zhang 
940213528feSQi Zhang 			if (hdr->field_selector)
941213528feSQi Zhang 				input->l2tpv3_data.session_id = *((__be32 *)hdr->buffer);
942213528feSQi Zhang 			break;
943213528feSQi Zhang 		case VIRTCHNL_PROTO_HDR_ESP:
944213528feSQi Zhang 			esph = (struct ip_esp_hdr *)hdr->buffer;
945213528feSQi Zhang 			if (l3 == VIRTCHNL_PROTO_HDR_IPV4 &&
946213528feSQi Zhang 			    l4 == VIRTCHNL_PROTO_HDR_UDP)
947213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_NAT_T_ESP;
948213528feSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 &&
949213528feSQi Zhang 				 l4 == VIRTCHNL_PROTO_HDR_UDP)
950213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_NAT_T_ESP;
951213528feSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV4 &&
952213528feSQi Zhang 				 l4 == VIRTCHNL_PROTO_HDR_NONE)
953213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_ESP;
954213528feSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 &&
955213528feSQi Zhang 				 l4 == VIRTCHNL_PROTO_HDR_NONE)
956213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_ESP;
957213528feSQi Zhang 
958213528feSQi Zhang 			if (l4 == VIRTCHNL_PROTO_HDR_UDP)
959213528feSQi Zhang 				conf->inset_flag |= FDIR_INSET_FLAG_ESP_UDP;
960213528feSQi Zhang 			else
961213528feSQi Zhang 				conf->inset_flag |= FDIR_INSET_FLAG_ESP_IPSEC;
962213528feSQi Zhang 
963213528feSQi Zhang 			if (hdr->field_selector) {
964213528feSQi Zhang 				if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
965213528feSQi Zhang 					input->ip.v4.sec_parm_idx = esph->spi;
966213528feSQi Zhang 				else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
967213528feSQi Zhang 					input->ip.v6.sec_parm_idx = esph->spi;
968213528feSQi Zhang 			}
969213528feSQi Zhang 			break;
970213528feSQi Zhang 		case VIRTCHNL_PROTO_HDR_AH:
971213528feSQi Zhang 			ah = (struct ip_auth_hdr *)hdr->buffer;
972213528feSQi Zhang 			if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
973213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_AH;
974213528feSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
975213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_AH;
976213528feSQi Zhang 
977213528feSQi Zhang 			if (hdr->field_selector) {
978213528feSQi Zhang 				if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
979213528feSQi Zhang 					input->ip.v4.sec_parm_idx = ah->spi;
980213528feSQi Zhang 				else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
981213528feSQi Zhang 					input->ip.v6.sec_parm_idx = ah->spi;
982213528feSQi Zhang 			}
983213528feSQi Zhang 			break;
984213528feSQi Zhang 		case VIRTCHNL_PROTO_HDR_PFCP:
985213528feSQi Zhang 			rawh = (u8 *)hdr->buffer;
986213528feSQi Zhang 			s_field = (rawh[0] >> PFCP_S_OFFSET) & PFCP_S_MASK;
987213528feSQi Zhang 			if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && s_field == 0)
988213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_PFCP_NODE;
989213528feSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && s_field == 1)
990213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_PFCP_SESSION;
991213528feSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && s_field == 0)
992213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_PFCP_NODE;
993213528feSQi Zhang 			else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && s_field == 1)
994213528feSQi Zhang 				input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_PFCP_SESSION;
995213528feSQi Zhang 
996213528feSQi Zhang 			if (hdr->field_selector) {
997213528feSQi Zhang 				if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
998213528feSQi Zhang 					input->ip.v4.dst_port = cpu_to_be16(PFCP_PORT_NR);
999213528feSQi Zhang 				else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
1000213528feSQi Zhang 					input->ip.v6.dst_port = cpu_to_be16(PFCP_PORT_NR);
1001213528feSQi Zhang 			}
1002213528feSQi Zhang 			break;
1003ef9e4cc5SQi Zhang 		case VIRTCHNL_PROTO_HDR_GTPU_IP:
1004ef9e4cc5SQi Zhang 			rawh = (u8 *)hdr->buffer;
1005ef9e4cc5SQi Zhang 			input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER;
1006ef9e4cc5SQi Zhang 
1007ef9e4cc5SQi Zhang 			if (hdr->field_selector)
1008ef9e4cc5SQi Zhang 				input->gtpu_data.teid = *(__be32 *)(&rawh[GTPU_TEID_OFFSET]);
1009ef9e4cc5SQi Zhang 			conf->ttype = ICE_FDIR_TUNNEL_TYPE_GTPU;
1010ef9e4cc5SQi Zhang 			break;
1011ef9e4cc5SQi Zhang 		case VIRTCHNL_PROTO_HDR_GTPU_EH:
1012ef9e4cc5SQi Zhang 			rawh = (u8 *)hdr->buffer;
1013ef9e4cc5SQi Zhang 
1014ef9e4cc5SQi Zhang 			if (hdr->field_selector)
1015ef9e4cc5SQi Zhang 				input->gtpu_data.qfi = rawh[GTPU_EH_QFI_OFFSET] & GTPU_EH_QFI_MASK;
1016ef9e4cc5SQi Zhang 			conf->ttype = ICE_FDIR_TUNNEL_TYPE_GTPU_EH;
1017ef9e4cc5SQi Zhang 			break;
10180ce332fdSQi Zhang 		default:
10190ce332fdSQi Zhang 			dev_dbg(dev, "Invalid header type 0x:%x for VF %d\n",
10200ce332fdSQi Zhang 				hdr->type, vf->vf_id);
10210ce332fdSQi Zhang 			return -EINVAL;
10220ce332fdSQi Zhang 		}
10230ce332fdSQi Zhang 	}
10240ce332fdSQi Zhang 
10250ce332fdSQi Zhang 	return 0;
10260ce332fdSQi Zhang }
10270ce332fdSQi Zhang 
10280ce332fdSQi Zhang /**
10290ce332fdSQi Zhang  * ice_vc_fdir_parse_action
10300ce332fdSQi Zhang  * @vf: pointer to the VF info
10310ce332fdSQi Zhang  * @fltr: virtual channel add cmd buffer
10320ce332fdSQi Zhang  * @conf: FDIR configuration for each filter
10330ce332fdSQi Zhang  *
10340ce332fdSQi Zhang  * Parse the virtual channel filter's action and store them into conf
10350ce332fdSQi Zhang  *
10360ce332fdSQi Zhang  * Return: 0 on success, and other on error.
10370ce332fdSQi Zhang  */
10380ce332fdSQi Zhang static int
ice_vc_fdir_parse_action(struct ice_vf * vf,struct virtchnl_fdir_add * fltr,struct virtchnl_fdir_fltr_conf * conf)10390ce332fdSQi Zhang ice_vc_fdir_parse_action(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
10400ce332fdSQi Zhang 			 struct virtchnl_fdir_fltr_conf *conf)
10410ce332fdSQi Zhang {
10420ce332fdSQi Zhang 	struct virtchnl_filter_action_set *as = &fltr->rule_cfg.action_set;
10430ce332fdSQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
10440ce332fdSQi Zhang 	struct ice_fdir_fltr *input = &conf->input;
10450ce332fdSQi Zhang 	u32 dest_num = 0;
10460ce332fdSQi Zhang 	u32 mark_num = 0;
10470ce332fdSQi Zhang 	int i;
10480ce332fdSQi Zhang 
10490ce332fdSQi Zhang 	if (as->count > VIRTCHNL_MAX_NUM_ACTIONS) {
10500ce332fdSQi Zhang 		dev_dbg(dev, "Invalid action numbers:0x%x for VF %d\n",
10510ce332fdSQi Zhang 			as->count, vf->vf_id);
10520ce332fdSQi Zhang 		return -EINVAL;
10530ce332fdSQi Zhang 	}
10540ce332fdSQi Zhang 
10550ce332fdSQi Zhang 	for (i = 0; i < as->count; i++) {
10560ce332fdSQi Zhang 		struct virtchnl_filter_action *action = &as->actions[i];
10570ce332fdSQi Zhang 
10580ce332fdSQi Zhang 		switch (action->type) {
1059346bf250SQi Zhang 		case VIRTCHNL_ACTION_PASSTHRU:
1060346bf250SQi Zhang 			dest_num++;
1061346bf250SQi Zhang 			input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_OTHER;
1062346bf250SQi Zhang 			break;
10630ce332fdSQi Zhang 		case VIRTCHNL_ACTION_DROP:
10640ce332fdSQi Zhang 			dest_num++;
10650ce332fdSQi Zhang 			input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DROP_PKT;
10660ce332fdSQi Zhang 			break;
10670ce332fdSQi Zhang 		case VIRTCHNL_ACTION_QUEUE:
10680ce332fdSQi Zhang 			dest_num++;
10690ce332fdSQi Zhang 			input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QINDEX;
10700ce332fdSQi Zhang 			input->q_index = action->act_conf.queue.index;
10710ce332fdSQi Zhang 			break;
1072346bf250SQi Zhang 		case VIRTCHNL_ACTION_Q_REGION:
1073346bf250SQi Zhang 			dest_num++;
1074346bf250SQi Zhang 			input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QGROUP;
1075346bf250SQi Zhang 			input->q_index = action->act_conf.queue.index;
1076346bf250SQi Zhang 			input->q_region = action->act_conf.queue.region;
1077346bf250SQi Zhang 			break;
10780ce332fdSQi Zhang 		case VIRTCHNL_ACTION_MARK:
10790ce332fdSQi Zhang 			mark_num++;
10800ce332fdSQi Zhang 			input->fltr_id = action->act_conf.mark_id;
10810ce332fdSQi Zhang 			input->fdid_prio = ICE_FXD_FLTR_QW1_FDID_PRI_THREE;
10820ce332fdSQi Zhang 			break;
10830ce332fdSQi Zhang 		default:
10840ce332fdSQi Zhang 			dev_dbg(dev, "Invalid action type:0x%x for VF %d\n",
10850ce332fdSQi Zhang 				action->type, vf->vf_id);
10860ce332fdSQi Zhang 			return -EINVAL;
10870ce332fdSQi Zhang 		}
10880ce332fdSQi Zhang 	}
10890ce332fdSQi Zhang 
10900ce332fdSQi Zhang 	if (dest_num == 0 || dest_num >= 2) {
10910ce332fdSQi Zhang 		dev_dbg(dev, "Invalid destination action for VF %d\n",
10920ce332fdSQi Zhang 			vf->vf_id);
10930ce332fdSQi Zhang 		return -EINVAL;
10940ce332fdSQi Zhang 	}
10950ce332fdSQi Zhang 
10960ce332fdSQi Zhang 	if (mark_num >= 2) {
10970ce332fdSQi Zhang 		dev_dbg(dev, "Too many mark actions for VF %d\n", vf->vf_id);
10980ce332fdSQi Zhang 		return -EINVAL;
10990ce332fdSQi Zhang 	}
11000ce332fdSQi Zhang 
11010ce332fdSQi Zhang 	return 0;
11020ce332fdSQi Zhang }
11030ce332fdSQi Zhang 
11040ce332fdSQi Zhang /**
11051f7ea1cdSQi Zhang  * ice_vc_validate_fdir_fltr - validate the virtual channel filter
11061f7ea1cdSQi Zhang  * @vf: pointer to the VF info
11071f7ea1cdSQi Zhang  * @fltr: virtual channel add cmd buffer
11081f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
11091f7ea1cdSQi Zhang  *
11101f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
11111f7ea1cdSQi Zhang  */
11121f7ea1cdSQi Zhang static int
ice_vc_validate_fdir_fltr(struct ice_vf * vf,struct virtchnl_fdir_add * fltr,struct virtchnl_fdir_fltr_conf * conf)11131f7ea1cdSQi Zhang ice_vc_validate_fdir_fltr(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
11141f7ea1cdSQi Zhang 			  struct virtchnl_fdir_fltr_conf *conf)
11151f7ea1cdSQi Zhang {
111660f44fe4SJeff Guo 	struct virtchnl_proto_hdrs *proto = &fltr->rule_cfg.proto_hdrs;
11170ce332fdSQi Zhang 	int ret;
11180ce332fdSQi Zhang 
111960f44fe4SJeff Guo 	if (!ice_vc_validate_pattern(vf, proto))
112060f44fe4SJeff Guo 		return -EINVAL;
11210ce332fdSQi Zhang 
11220ce332fdSQi Zhang 	ret = ice_vc_fdir_parse_pattern(vf, fltr, conf);
11230ce332fdSQi Zhang 	if (ret)
11240ce332fdSQi Zhang 		return ret;
11250ce332fdSQi Zhang 
11260ce332fdSQi Zhang 	return ice_vc_fdir_parse_action(vf, fltr, conf);
11271f7ea1cdSQi Zhang }
11281f7ea1cdSQi Zhang 
11291f7ea1cdSQi Zhang /**
11301f7ea1cdSQi Zhang  * ice_vc_fdir_comp_rules - compare if two filter rules have the same value
11311f7ea1cdSQi Zhang  * @conf_a: FDIR configuration for filter a
11321f7ea1cdSQi Zhang  * @conf_b: FDIR configuration for filter b
11331f7ea1cdSQi Zhang  *
11341f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
11351f7ea1cdSQi Zhang  */
11361f7ea1cdSQi Zhang static bool
ice_vc_fdir_comp_rules(struct virtchnl_fdir_fltr_conf * conf_a,struct virtchnl_fdir_fltr_conf * conf_b)11371f7ea1cdSQi Zhang ice_vc_fdir_comp_rules(struct virtchnl_fdir_fltr_conf *conf_a,
11381f7ea1cdSQi Zhang 		       struct virtchnl_fdir_fltr_conf *conf_b)
11391f7ea1cdSQi Zhang {
11401f7ea1cdSQi Zhang 	struct ice_fdir_fltr *a = &conf_a->input;
11411f7ea1cdSQi Zhang 	struct ice_fdir_fltr *b = &conf_b->input;
11421f7ea1cdSQi Zhang 
1143ef9e4cc5SQi Zhang 	if (conf_a->ttype != conf_b->ttype)
1144ef9e4cc5SQi Zhang 		return false;
11451f7ea1cdSQi Zhang 	if (a->flow_type != b->flow_type)
11461f7ea1cdSQi Zhang 		return false;
11471f7ea1cdSQi Zhang 	if (memcmp(&a->ip, &b->ip, sizeof(a->ip)))
11481f7ea1cdSQi Zhang 		return false;
11491f7ea1cdSQi Zhang 	if (memcmp(&a->mask, &b->mask, sizeof(a->mask)))
11501f7ea1cdSQi Zhang 		return false;
1151ef9e4cc5SQi Zhang 	if (memcmp(&a->gtpu_data, &b->gtpu_data, sizeof(a->gtpu_data)))
1152ef9e4cc5SQi Zhang 		return false;
1153ef9e4cc5SQi Zhang 	if (memcmp(&a->gtpu_mask, &b->gtpu_mask, sizeof(a->gtpu_mask)))
1154ef9e4cc5SQi Zhang 		return false;
1155213528feSQi Zhang 	if (memcmp(&a->l2tpv3_data, &b->l2tpv3_data, sizeof(a->l2tpv3_data)))
1156213528feSQi Zhang 		return false;
1157213528feSQi Zhang 	if (memcmp(&a->l2tpv3_mask, &b->l2tpv3_mask, sizeof(a->l2tpv3_mask)))
1158213528feSQi Zhang 		return false;
11591f7ea1cdSQi Zhang 	if (memcmp(&a->ext_data, &b->ext_data, sizeof(a->ext_data)))
11601f7ea1cdSQi Zhang 		return false;
11611f7ea1cdSQi Zhang 	if (memcmp(&a->ext_mask, &b->ext_mask, sizeof(a->ext_mask)))
11621f7ea1cdSQi Zhang 		return false;
11631f7ea1cdSQi Zhang 
11641f7ea1cdSQi Zhang 	return true;
11651f7ea1cdSQi Zhang }
11661f7ea1cdSQi Zhang 
11671f7ea1cdSQi Zhang /**
11681f7ea1cdSQi Zhang  * ice_vc_fdir_is_dup_fltr
11691f7ea1cdSQi Zhang  * @vf: pointer to the VF info
11701f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
11711f7ea1cdSQi Zhang  *
11721f7ea1cdSQi Zhang  * Check if there is duplicated rule with same conf value
11731f7ea1cdSQi Zhang  *
11741f7ea1cdSQi Zhang  * Return: 0 true success, and false on error.
11751f7ea1cdSQi Zhang  */
11761f7ea1cdSQi Zhang static bool
ice_vc_fdir_is_dup_fltr(struct ice_vf * vf,struct virtchnl_fdir_fltr_conf * conf)11771f7ea1cdSQi Zhang ice_vc_fdir_is_dup_fltr(struct ice_vf *vf, struct virtchnl_fdir_fltr_conf *conf)
11781f7ea1cdSQi Zhang {
11791f7ea1cdSQi Zhang 	struct ice_fdir_fltr *desc;
11801f7ea1cdSQi Zhang 	bool ret;
11811f7ea1cdSQi Zhang 
11821f7ea1cdSQi Zhang 	list_for_each_entry(desc, &vf->fdir.fdir_rule_list, fltr_node) {
11831f7ea1cdSQi Zhang 		struct virtchnl_fdir_fltr_conf *node =
11841f7ea1cdSQi Zhang 				to_fltr_conf_from_desc(desc);
11851f7ea1cdSQi Zhang 
11861f7ea1cdSQi Zhang 		ret = ice_vc_fdir_comp_rules(node, conf);
11871f7ea1cdSQi Zhang 		if (ret)
11881f7ea1cdSQi Zhang 			return true;
11891f7ea1cdSQi Zhang 	}
11901f7ea1cdSQi Zhang 
11911f7ea1cdSQi Zhang 	return false;
11921f7ea1cdSQi Zhang }
11931f7ea1cdSQi Zhang 
11941f7ea1cdSQi Zhang /**
11951f7ea1cdSQi Zhang  * ice_vc_fdir_insert_entry
11961f7ea1cdSQi Zhang  * @vf: pointer to the VF info
11971f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
11981f7ea1cdSQi Zhang  * @id: pointer to ID value allocated by driver
11991f7ea1cdSQi Zhang  *
12001f7ea1cdSQi Zhang  * Insert FDIR conf entry into list and allocate ID for this filter
12011f7ea1cdSQi Zhang  *
12021f7ea1cdSQi Zhang  * Return: 0 true success, and other on error.
12031f7ea1cdSQi Zhang  */
12041f7ea1cdSQi Zhang static int
ice_vc_fdir_insert_entry(struct ice_vf * vf,struct virtchnl_fdir_fltr_conf * conf,u32 * id)12051f7ea1cdSQi Zhang ice_vc_fdir_insert_entry(struct ice_vf *vf,
12061f7ea1cdSQi Zhang 			 struct virtchnl_fdir_fltr_conf *conf, u32 *id)
12071f7ea1cdSQi Zhang {
12081f7ea1cdSQi Zhang 	struct ice_fdir_fltr *input = &conf->input;
12091f7ea1cdSQi Zhang 	int i;
12101f7ea1cdSQi Zhang 
12111f7ea1cdSQi Zhang 	/* alloc ID corresponding with conf */
12121f7ea1cdSQi Zhang 	i = idr_alloc(&vf->fdir.fdir_rule_idr, conf, 0,
12131f7ea1cdSQi Zhang 		      ICE_FDIR_MAX_FLTRS, GFP_KERNEL);
12141f7ea1cdSQi Zhang 	if (i < 0)
12151f7ea1cdSQi Zhang 		return -EINVAL;
12161f7ea1cdSQi Zhang 	*id = i;
12171f7ea1cdSQi Zhang 
12181f7ea1cdSQi Zhang 	list_add(&input->fltr_node, &vf->fdir.fdir_rule_list);
12191f7ea1cdSQi Zhang 	return 0;
12201f7ea1cdSQi Zhang }
12211f7ea1cdSQi Zhang 
12221f7ea1cdSQi Zhang /**
12231f7ea1cdSQi Zhang  * ice_vc_fdir_remove_entry - remove FDIR conf entry by ID value
12241f7ea1cdSQi Zhang  * @vf: pointer to the VF info
12251f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
12261f7ea1cdSQi Zhang  * @id: filter rule's ID
12271f7ea1cdSQi Zhang  */
12281f7ea1cdSQi Zhang static void
ice_vc_fdir_remove_entry(struct ice_vf * vf,struct virtchnl_fdir_fltr_conf * conf,u32 id)12291f7ea1cdSQi Zhang ice_vc_fdir_remove_entry(struct ice_vf *vf,
12301f7ea1cdSQi Zhang 			 struct virtchnl_fdir_fltr_conf *conf, u32 id)
12311f7ea1cdSQi Zhang {
12321f7ea1cdSQi Zhang 	struct ice_fdir_fltr *input = &conf->input;
12331f7ea1cdSQi Zhang 
12341f7ea1cdSQi Zhang 	idr_remove(&vf->fdir.fdir_rule_idr, id);
12351f7ea1cdSQi Zhang 	list_del(&input->fltr_node);
12361f7ea1cdSQi Zhang }
12371f7ea1cdSQi Zhang 
12381f7ea1cdSQi Zhang /**
12391f7ea1cdSQi Zhang  * ice_vc_fdir_lookup_entry - lookup FDIR conf entry by ID value
12401f7ea1cdSQi Zhang  * @vf: pointer to the VF info
12411f7ea1cdSQi Zhang  * @id: filter rule's ID
12421f7ea1cdSQi Zhang  *
12431f7ea1cdSQi Zhang  * Return: NULL on error, and other on success.
12441f7ea1cdSQi Zhang  */
12451f7ea1cdSQi Zhang static struct virtchnl_fdir_fltr_conf *
ice_vc_fdir_lookup_entry(struct ice_vf * vf,u32 id)12461f7ea1cdSQi Zhang ice_vc_fdir_lookup_entry(struct ice_vf *vf, u32 id)
12471f7ea1cdSQi Zhang {
12481f7ea1cdSQi Zhang 	return idr_find(&vf->fdir.fdir_rule_idr, id);
12491f7ea1cdSQi Zhang }
12501f7ea1cdSQi Zhang 
12511f7ea1cdSQi Zhang /**
12521f7ea1cdSQi Zhang  * ice_vc_fdir_flush_entry - remove all FDIR conf entry
12531f7ea1cdSQi Zhang  * @vf: pointer to the VF info
12541f7ea1cdSQi Zhang  */
ice_vc_fdir_flush_entry(struct ice_vf * vf)12551f7ea1cdSQi Zhang static void ice_vc_fdir_flush_entry(struct ice_vf *vf)
12561f7ea1cdSQi Zhang {
12571f7ea1cdSQi Zhang 	struct virtchnl_fdir_fltr_conf *conf;
12581f7ea1cdSQi Zhang 	struct ice_fdir_fltr *desc, *temp;
12591f7ea1cdSQi Zhang 
12601f7ea1cdSQi Zhang 	list_for_each_entry_safe(desc, temp,
12611f7ea1cdSQi Zhang 				 &vf->fdir.fdir_rule_list, fltr_node) {
12621f7ea1cdSQi Zhang 		conf = to_fltr_conf_from_desc(desc);
12631f7ea1cdSQi Zhang 		list_del(&desc->fltr_node);
12641f7ea1cdSQi Zhang 		devm_kfree(ice_pf_to_dev(vf->pf), conf);
12651f7ea1cdSQi Zhang 	}
12661f7ea1cdSQi Zhang }
12671f7ea1cdSQi Zhang 
12681f7ea1cdSQi Zhang /**
12691f7ea1cdSQi Zhang  * ice_vc_fdir_write_fltr - write filter rule into hardware
12701f7ea1cdSQi Zhang  * @vf: pointer to the VF info
12711f7ea1cdSQi Zhang  * @conf: FDIR configuration for each filter
12721f7ea1cdSQi Zhang  * @add: true implies add rule, false implies del rules
12731f7ea1cdSQi Zhang  * @is_tun: false implies non-tunnel type filter, true implies tunnel filter
12741f7ea1cdSQi Zhang  *
12751f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
12761f7ea1cdSQi Zhang  */
ice_vc_fdir_write_fltr(struct ice_vf * vf,struct virtchnl_fdir_fltr_conf * conf,bool add,bool is_tun)12771f7ea1cdSQi Zhang static int ice_vc_fdir_write_fltr(struct ice_vf *vf,
12781f7ea1cdSQi Zhang 				  struct virtchnl_fdir_fltr_conf *conf,
12791f7ea1cdSQi Zhang 				  bool add, bool is_tun)
12801f7ea1cdSQi Zhang {
12811f7ea1cdSQi Zhang 	struct ice_fdir_fltr *input = &conf->input;
12821f7ea1cdSQi Zhang 	struct ice_vsi *vsi, *ctrl_vsi;
12831f7ea1cdSQi Zhang 	struct ice_fltr_desc desc;
12841f7ea1cdSQi Zhang 	struct device *dev;
12851f7ea1cdSQi Zhang 	struct ice_pf *pf;
12861f7ea1cdSQi Zhang 	struct ice_hw *hw;
12871f7ea1cdSQi Zhang 	int ret;
12881f7ea1cdSQi Zhang 	u8 *pkt;
12891f7ea1cdSQi Zhang 
12901f7ea1cdSQi Zhang 	pf = vf->pf;
12911f7ea1cdSQi Zhang 	dev = ice_pf_to_dev(pf);
12921f7ea1cdSQi Zhang 	hw = &pf->hw;
1293772dec64SBrett Creeley 	vsi = ice_get_vf_vsi(vf);
12941f7ea1cdSQi Zhang 	if (!vsi) {
12951f7ea1cdSQi Zhang 		dev_dbg(dev, "Invalid vsi for VF %d\n", vf->vf_id);
12961f7ea1cdSQi Zhang 		return -EINVAL;
12971f7ea1cdSQi Zhang 	}
12981f7ea1cdSQi Zhang 
12991f7ea1cdSQi Zhang 	input->dest_vsi = vsi->idx;
1300d6218317SQi Zhang 	input->comp_report = ICE_FXD_FLTR_QW0_COMP_REPORT_SW;
13011f7ea1cdSQi Zhang 
13021f7ea1cdSQi Zhang 	ctrl_vsi = pf->vsi[vf->ctrl_vsi_idx];
13031f7ea1cdSQi Zhang 	if (!ctrl_vsi) {
13041f7ea1cdSQi Zhang 		dev_dbg(dev, "Invalid ctrl_vsi for VF %d\n", vf->vf_id);
13051f7ea1cdSQi Zhang 		return -EINVAL;
13061f7ea1cdSQi Zhang 	}
13071f7ea1cdSQi Zhang 
13081f7ea1cdSQi Zhang 	pkt = devm_kzalloc(dev, ICE_FDIR_MAX_RAW_PKT_SIZE, GFP_KERNEL);
13091f7ea1cdSQi Zhang 	if (!pkt)
13101f7ea1cdSQi Zhang 		return -ENOMEM;
13111f7ea1cdSQi Zhang 
13121f7ea1cdSQi Zhang 	ice_fdir_get_prgm_desc(hw, input, &desc, add);
13132ccc1c1cSTony Nguyen 	ret = ice_fdir_get_gen_prgm_pkt(hw, input, pkt, false, is_tun);
13141f7ea1cdSQi Zhang 	if (ret) {
13151f7ea1cdSQi Zhang 		dev_dbg(dev, "Gen training pkt for VF %d ptype %d failed\n",
13161f7ea1cdSQi Zhang 			vf->vf_id, input->flow_type);
13171f7ea1cdSQi Zhang 		goto err_free_pkt;
13181f7ea1cdSQi Zhang 	}
13191f7ea1cdSQi Zhang 
13201f7ea1cdSQi Zhang 	ret = ice_prgm_fdir_fltr(ctrl_vsi, &desc, pkt);
13211f7ea1cdSQi Zhang 	if (ret)
13221f7ea1cdSQi Zhang 		goto err_free_pkt;
13231f7ea1cdSQi Zhang 
13241f7ea1cdSQi Zhang 	return 0;
13251f7ea1cdSQi Zhang 
13261f7ea1cdSQi Zhang err_free_pkt:
13271f7ea1cdSQi Zhang 	devm_kfree(dev, pkt);
13281f7ea1cdSQi Zhang 	return ret;
13291f7ea1cdSQi Zhang }
13301f7ea1cdSQi Zhang 
13311f7ea1cdSQi Zhang /**
1332d6218317SQi Zhang  * ice_vf_fdir_timer - FDIR program waiting timer interrupt handler
1333d6218317SQi Zhang  * @t: pointer to timer_list
1334d6218317SQi Zhang  */
ice_vf_fdir_timer(struct timer_list * t)1335d6218317SQi Zhang static void ice_vf_fdir_timer(struct timer_list *t)
1336d6218317SQi Zhang {
1337d6218317SQi Zhang 	struct ice_vf_fdir_ctx *ctx_irq = from_timer(ctx_irq, t, rx_tmr);
1338d6218317SQi Zhang 	struct ice_vf_fdir_ctx *ctx_done;
1339d6218317SQi Zhang 	struct ice_vf_fdir *fdir;
1340d6218317SQi Zhang 	unsigned long flags;
1341d6218317SQi Zhang 	struct ice_vf *vf;
1342d6218317SQi Zhang 	struct ice_pf *pf;
1343d6218317SQi Zhang 
1344d6218317SQi Zhang 	fdir = container_of(ctx_irq, struct ice_vf_fdir, ctx_irq);
1345d6218317SQi Zhang 	vf = container_of(fdir, struct ice_vf, fdir);
1346d6218317SQi Zhang 	ctx_done = &fdir->ctx_done;
1347d6218317SQi Zhang 	pf = vf->pf;
1348d6218317SQi Zhang 	spin_lock_irqsave(&fdir->ctx_lock, flags);
1349d6218317SQi Zhang 	if (!(ctx_irq->flags & ICE_VF_FDIR_CTX_VALID)) {
1350d6218317SQi Zhang 		spin_unlock_irqrestore(&fdir->ctx_lock, flags);
1351d6218317SQi Zhang 		WARN_ON_ONCE(1);
1352d6218317SQi Zhang 		return;
1353d6218317SQi Zhang 	}
1354d6218317SQi Zhang 
1355d6218317SQi Zhang 	ctx_irq->flags &= ~ICE_VF_FDIR_CTX_VALID;
1356d6218317SQi Zhang 
1357d6218317SQi Zhang 	ctx_done->flags |= ICE_VF_FDIR_CTX_VALID;
1358d6218317SQi Zhang 	ctx_done->conf = ctx_irq->conf;
1359d6218317SQi Zhang 	ctx_done->stat = ICE_FDIR_CTX_TIMEOUT;
1360d6218317SQi Zhang 	ctx_done->v_opcode = ctx_irq->v_opcode;
1361d6218317SQi Zhang 	spin_unlock_irqrestore(&fdir->ctx_lock, flags);
1362d6218317SQi Zhang 
13637e408e07SAnirudh Venkataramanan 	set_bit(ICE_FD_VF_FLUSH_CTX, pf->state);
1364d6218317SQi Zhang 	ice_service_task_schedule(pf);
1365d6218317SQi Zhang }
1366d6218317SQi Zhang 
1367d6218317SQi Zhang /**
1368d6218317SQi Zhang  * ice_vc_fdir_irq_handler - ctrl_vsi Rx queue interrupt handler
1369d6218317SQi Zhang  * @ctrl_vsi: pointer to a VF's CTRL VSI
1370d6218317SQi Zhang  * @rx_desc: pointer to FDIR Rx queue descriptor
1371d6218317SQi Zhang  */
1372d6218317SQi Zhang void
ice_vc_fdir_irq_handler(struct ice_vsi * ctrl_vsi,union ice_32b_rx_flex_desc * rx_desc)1373d6218317SQi Zhang ice_vc_fdir_irq_handler(struct ice_vsi *ctrl_vsi,
1374d6218317SQi Zhang 			union ice_32b_rx_flex_desc *rx_desc)
1375d6218317SQi Zhang {
1376d6218317SQi Zhang 	struct ice_pf *pf = ctrl_vsi->back;
1377b03d519dSJacob Keller 	struct ice_vf *vf = ctrl_vsi->vf;
1378d6218317SQi Zhang 	struct ice_vf_fdir_ctx *ctx_done;
1379d6218317SQi Zhang 	struct ice_vf_fdir_ctx *ctx_irq;
1380d6218317SQi Zhang 	struct ice_vf_fdir *fdir;
1381d6218317SQi Zhang 	unsigned long flags;
1382d6218317SQi Zhang 	struct device *dev;
1383d6218317SQi Zhang 	int ret;
1384d6218317SQi Zhang 
1385b03d519dSJacob Keller 	if (WARN_ON(!vf))
1386b03d519dSJacob Keller 		return;
1387d6218317SQi Zhang 
1388d6218317SQi Zhang 	fdir = &vf->fdir;
1389d6218317SQi Zhang 	ctx_done = &fdir->ctx_done;
1390d6218317SQi Zhang 	ctx_irq = &fdir->ctx_irq;
1391d6218317SQi Zhang 	dev = ice_pf_to_dev(pf);
1392d6218317SQi Zhang 	spin_lock_irqsave(&fdir->ctx_lock, flags);
1393d6218317SQi Zhang 	if (!(ctx_irq->flags & ICE_VF_FDIR_CTX_VALID)) {
1394d6218317SQi Zhang 		spin_unlock_irqrestore(&fdir->ctx_lock, flags);
1395d6218317SQi Zhang 		WARN_ON_ONCE(1);
1396d6218317SQi Zhang 		return;
1397d6218317SQi Zhang 	}
1398d6218317SQi Zhang 
1399d6218317SQi Zhang 	ctx_irq->flags &= ~ICE_VF_FDIR_CTX_VALID;
1400d6218317SQi Zhang 
1401d6218317SQi Zhang 	ctx_done->flags |= ICE_VF_FDIR_CTX_VALID;
1402d6218317SQi Zhang 	ctx_done->conf = ctx_irq->conf;
1403d6218317SQi Zhang 	ctx_done->stat = ICE_FDIR_CTX_IRQ;
1404d6218317SQi Zhang 	ctx_done->v_opcode = ctx_irq->v_opcode;
1405d6218317SQi Zhang 	memcpy(&ctx_done->rx_desc, rx_desc, sizeof(*rx_desc));
1406d6218317SQi Zhang 	spin_unlock_irqrestore(&fdir->ctx_lock, flags);
1407d6218317SQi Zhang 
1408d6218317SQi Zhang 	ret = del_timer(&ctx_irq->rx_tmr);
1409d6218317SQi Zhang 	if (!ret)
1410d6218317SQi Zhang 		dev_err(dev, "VF %d: Unexpected inactive timer!\n", vf->vf_id);
1411d6218317SQi Zhang 
14127e408e07SAnirudh Venkataramanan 	set_bit(ICE_FD_VF_FLUSH_CTX, pf->state);
1413d6218317SQi Zhang 	ice_service_task_schedule(pf);
1414d6218317SQi Zhang }
1415d6218317SQi Zhang 
1416d6218317SQi Zhang /**
1417d6218317SQi Zhang  * ice_vf_fdir_dump_info - dump FDIR information for diagnosis
1418d6218317SQi Zhang  * @vf: pointer to the VF info
1419d6218317SQi Zhang  */
ice_vf_fdir_dump_info(struct ice_vf * vf)1420d6218317SQi Zhang static void ice_vf_fdir_dump_info(struct ice_vf *vf)
1421d6218317SQi Zhang {
1422d6218317SQi Zhang 	struct ice_vsi *vf_vsi;
1423d6218317SQi Zhang 	u32 fd_size, fd_cnt;
1424d6218317SQi Zhang 	struct device *dev;
1425d6218317SQi Zhang 	struct ice_pf *pf;
1426d6218317SQi Zhang 	struct ice_hw *hw;
1427d6218317SQi Zhang 	u16 vsi_num;
1428d6218317SQi Zhang 
1429d6218317SQi Zhang 	pf = vf->pf;
1430d6218317SQi Zhang 	hw = &pf->hw;
1431d6218317SQi Zhang 	dev = ice_pf_to_dev(pf);
1432baeb705fSJacob Keller 	vf_vsi = ice_get_vf_vsi(vf);
1433baeb705fSJacob Keller 	if (!vf_vsi) {
1434baeb705fSJacob Keller 		dev_dbg(dev, "VF %d: invalid VSI pointer\n", vf->vf_id);
1435baeb705fSJacob Keller 		return;
1436baeb705fSJacob Keller 	}
1437baeb705fSJacob Keller 
1438d6218317SQi Zhang 	vsi_num = ice_get_hw_vsi_num(hw, vf_vsi->idx);
1439d6218317SQi Zhang 
1440d6218317SQi Zhang 	fd_size = rd32(hw, VSIQF_FD_SIZE(vsi_num));
1441d6218317SQi Zhang 	fd_cnt = rd32(hw, VSIQF_FD_CNT(vsi_num));
14429880d3d6SJacob Keller 	dev_dbg(dev, "VF %d: space allocated: guar:0x%x, be:0x%x, space consumed: guar:0x%x, be:0x%x\n",
1443d6218317SQi Zhang 		vf->vf_id,
1444d6218317SQi Zhang 		(fd_size & VSIQF_FD_CNT_FD_GCNT_M) >> VSIQF_FD_CNT_FD_GCNT_S,
1445d6218317SQi Zhang 		(fd_size & VSIQF_FD_CNT_FD_BCNT_M) >> VSIQF_FD_CNT_FD_BCNT_S,
1446d6218317SQi Zhang 		(fd_cnt & VSIQF_FD_CNT_FD_GCNT_M) >> VSIQF_FD_CNT_FD_GCNT_S,
1447d6218317SQi Zhang 		(fd_cnt & VSIQF_FD_CNT_FD_BCNT_M) >> VSIQF_FD_CNT_FD_BCNT_S);
1448d6218317SQi Zhang }
1449d6218317SQi Zhang 
1450d6218317SQi Zhang /**
1451d6218317SQi Zhang  * ice_vf_verify_rx_desc - verify received FDIR programming status descriptor
1452d6218317SQi Zhang  * @vf: pointer to the VF info
1453d6218317SQi Zhang  * @ctx: FDIR context info for post processing
1454d6218317SQi Zhang  * @status: virtchnl FDIR program status
1455d6218317SQi Zhang  *
1456d6218317SQi Zhang  * Return: 0 on success, and other on error.
1457d6218317SQi Zhang  */
1458d6218317SQi Zhang static int
ice_vf_verify_rx_desc(struct ice_vf * vf,struct ice_vf_fdir_ctx * ctx,enum virtchnl_fdir_prgm_status * status)1459d6218317SQi Zhang ice_vf_verify_rx_desc(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx,
1460d6218317SQi Zhang 		      enum virtchnl_fdir_prgm_status *status)
1461d6218317SQi Zhang {
1462d6218317SQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
1463d6218317SQi Zhang 	u32 stat_err, error, prog_id;
1464d6218317SQi Zhang 	int ret;
1465d6218317SQi Zhang 
1466d6218317SQi Zhang 	stat_err = le16_to_cpu(ctx->rx_desc.wb.status_error0);
1467d6218317SQi Zhang 	if (((stat_err & ICE_FXD_FLTR_WB_QW1_DD_M) >>
1468d6218317SQi Zhang 	    ICE_FXD_FLTR_WB_QW1_DD_S) != ICE_FXD_FLTR_WB_QW1_DD_YES) {
1469d6218317SQi Zhang 		*status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
1470d6218317SQi Zhang 		dev_err(dev, "VF %d: Desc Done not set\n", vf->vf_id);
1471d6218317SQi Zhang 		ret = -EINVAL;
1472d6218317SQi Zhang 		goto err_exit;
1473d6218317SQi Zhang 	}
1474d6218317SQi Zhang 
1475d6218317SQi Zhang 	prog_id = (stat_err & ICE_FXD_FLTR_WB_QW1_PROG_ID_M) >>
1476d6218317SQi Zhang 		ICE_FXD_FLTR_WB_QW1_PROG_ID_S;
1477d6218317SQi Zhang 	if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_ADD &&
1478d6218317SQi Zhang 	    ctx->v_opcode != VIRTCHNL_OP_ADD_FDIR_FILTER) {
1479d6218317SQi Zhang 		dev_err(dev, "VF %d: Desc show add, but ctx not",
1480d6218317SQi Zhang 			vf->vf_id);
1481d6218317SQi Zhang 		*status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID;
1482d6218317SQi Zhang 		ret = -EINVAL;
1483d6218317SQi Zhang 		goto err_exit;
1484d6218317SQi Zhang 	}
1485d6218317SQi Zhang 
1486d6218317SQi Zhang 	if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_DEL &&
1487d6218317SQi Zhang 	    ctx->v_opcode != VIRTCHNL_OP_DEL_FDIR_FILTER) {
1488d6218317SQi Zhang 		dev_err(dev, "VF %d: Desc show del, but ctx not",
1489d6218317SQi Zhang 			vf->vf_id);
1490d6218317SQi Zhang 		*status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID;
1491d6218317SQi Zhang 		ret = -EINVAL;
1492d6218317SQi Zhang 		goto err_exit;
1493d6218317SQi Zhang 	}
1494d6218317SQi Zhang 
1495d6218317SQi Zhang 	error = (stat_err & ICE_FXD_FLTR_WB_QW1_FAIL_M) >>
1496d6218317SQi Zhang 		ICE_FXD_FLTR_WB_QW1_FAIL_S;
1497d6218317SQi Zhang 	if (error == ICE_FXD_FLTR_WB_QW1_FAIL_YES) {
1498d6218317SQi Zhang 		if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_ADD) {
1499d6218317SQi Zhang 			dev_err(dev, "VF %d, Failed to add FDIR rule due to no space in the table",
1500d6218317SQi Zhang 				vf->vf_id);
1501d6218317SQi Zhang 			*status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
1502d6218317SQi Zhang 		} else {
1503d6218317SQi Zhang 			dev_err(dev, "VF %d, Failed to remove FDIR rule, attempt to remove non-existent entry",
1504d6218317SQi Zhang 				vf->vf_id);
1505d6218317SQi Zhang 			*status = VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST;
1506d6218317SQi Zhang 		}
1507d6218317SQi Zhang 		ret = -EINVAL;
1508d6218317SQi Zhang 		goto err_exit;
1509d6218317SQi Zhang 	}
1510d6218317SQi Zhang 
1511d6218317SQi Zhang 	error = (stat_err & ICE_FXD_FLTR_WB_QW1_FAIL_PROF_M) >>
1512d6218317SQi Zhang 		ICE_FXD_FLTR_WB_QW1_FAIL_PROF_S;
1513d6218317SQi Zhang 	if (error == ICE_FXD_FLTR_WB_QW1_FAIL_PROF_YES) {
1514d6218317SQi Zhang 		dev_err(dev, "VF %d: Profile matching error", vf->vf_id);
1515d6218317SQi Zhang 		*status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
1516d6218317SQi Zhang 		ret = -EINVAL;
1517d6218317SQi Zhang 		goto err_exit;
1518d6218317SQi Zhang 	}
1519d6218317SQi Zhang 
1520d6218317SQi Zhang 	*status = VIRTCHNL_FDIR_SUCCESS;
1521d6218317SQi Zhang 
1522d6218317SQi Zhang 	return 0;
1523d6218317SQi Zhang 
1524d6218317SQi Zhang err_exit:
1525d6218317SQi Zhang 	ice_vf_fdir_dump_info(vf);
1526d6218317SQi Zhang 	return ret;
1527d6218317SQi Zhang }
1528d6218317SQi Zhang 
1529d6218317SQi Zhang /**
1530d6218317SQi Zhang  * ice_vc_add_fdir_fltr_post
1531d6218317SQi Zhang  * @vf: pointer to the VF structure
1532d6218317SQi Zhang  * @ctx: FDIR context info for post processing
1533d6218317SQi Zhang  * @status: virtchnl FDIR program status
1534d6218317SQi Zhang  * @success: true implies success, false implies failure
1535d6218317SQi Zhang  *
1536d6218317SQi Zhang  * Post process for flow director add command. If success, then do post process
1537d6218317SQi Zhang  * and send back success msg by virtchnl. Otherwise, do context reversion and
1538d6218317SQi Zhang  * send back failure msg by virtchnl.
1539d6218317SQi Zhang  *
1540d6218317SQi Zhang  * Return: 0 on success, and other on error.
1541d6218317SQi Zhang  */
1542d6218317SQi Zhang static int
ice_vc_add_fdir_fltr_post(struct ice_vf * vf,struct ice_vf_fdir_ctx * ctx,enum virtchnl_fdir_prgm_status status,bool success)1543d6218317SQi Zhang ice_vc_add_fdir_fltr_post(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx,
1544d6218317SQi Zhang 			  enum virtchnl_fdir_prgm_status status,
1545d6218317SQi Zhang 			  bool success)
1546d6218317SQi Zhang {
1547d6218317SQi Zhang 	struct virtchnl_fdir_fltr_conf *conf = ctx->conf;
1548d6218317SQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
1549d6218317SQi Zhang 	enum virtchnl_status_code v_ret;
1550d6218317SQi Zhang 	struct virtchnl_fdir_add *resp;
1551d6218317SQi Zhang 	int ret, len, is_tun;
1552d6218317SQi Zhang 
1553d6218317SQi Zhang 	v_ret = VIRTCHNL_STATUS_SUCCESS;
1554d6218317SQi Zhang 	len = sizeof(*resp);
1555d6218317SQi Zhang 	resp = kzalloc(len, GFP_KERNEL);
1556d6218317SQi Zhang 	if (!resp) {
1557d6218317SQi Zhang 		len = 0;
1558d6218317SQi Zhang 		v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
1559d6218317SQi Zhang 		dev_dbg(dev, "VF %d: Alloc resp buf fail", vf->vf_id);
1560d6218317SQi Zhang 		goto err_exit;
1561d6218317SQi Zhang 	}
1562d6218317SQi Zhang 
1563d6218317SQi Zhang 	if (!success)
1564d6218317SQi Zhang 		goto err_exit;
1565d6218317SQi Zhang 
1566d6218317SQi Zhang 	is_tun = 0;
1567d6218317SQi Zhang 	resp->status = status;
1568d6218317SQi Zhang 	resp->flow_id = conf->flow_id;
1569d6218317SQi Zhang 	vf->fdir.fdir_fltr_cnt[conf->input.flow_type][is_tun]++;
1570d6218317SQi Zhang 
1571d6218317SQi Zhang 	ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret,
1572d6218317SQi Zhang 				    (u8 *)resp, len);
1573d6218317SQi Zhang 	kfree(resp);
1574d6218317SQi Zhang 
1575d6218317SQi Zhang 	dev_dbg(dev, "VF %d: flow_id:0x%X, FDIR %s success!\n",
1576d6218317SQi Zhang 		vf->vf_id, conf->flow_id,
1577d6218317SQi Zhang 		(ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) ?
1578d6218317SQi Zhang 		"add" : "del");
1579d6218317SQi Zhang 	return ret;
1580d6218317SQi Zhang 
1581d6218317SQi Zhang err_exit:
1582d6218317SQi Zhang 	if (resp)
1583d6218317SQi Zhang 		resp->status = status;
1584d6218317SQi Zhang 	ice_vc_fdir_remove_entry(vf, conf, conf->flow_id);
1585d6218317SQi Zhang 	devm_kfree(dev, conf);
1586d6218317SQi Zhang 
1587d6218317SQi Zhang 	ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret,
1588d6218317SQi Zhang 				    (u8 *)resp, len);
1589d6218317SQi Zhang 	kfree(resp);
1590d6218317SQi Zhang 	return ret;
1591d6218317SQi Zhang }
1592d6218317SQi Zhang 
1593d6218317SQi Zhang /**
1594d6218317SQi Zhang  * ice_vc_del_fdir_fltr_post
1595d6218317SQi Zhang  * @vf: pointer to the VF structure
1596d6218317SQi Zhang  * @ctx: FDIR context info for post processing
1597d6218317SQi Zhang  * @status: virtchnl FDIR program status
1598d6218317SQi Zhang  * @success: true implies success, false implies failure
1599d6218317SQi Zhang  *
1600d6218317SQi Zhang  * Post process for flow director del command. If success, then do post process
1601d6218317SQi Zhang  * and send back success msg by virtchnl. Otherwise, do context reversion and
1602d6218317SQi Zhang  * send back failure msg by virtchnl.
1603d6218317SQi Zhang  *
1604d6218317SQi Zhang  * Return: 0 on success, and other on error.
1605d6218317SQi Zhang  */
1606d6218317SQi Zhang static int
ice_vc_del_fdir_fltr_post(struct ice_vf * vf,struct ice_vf_fdir_ctx * ctx,enum virtchnl_fdir_prgm_status status,bool success)1607d6218317SQi Zhang ice_vc_del_fdir_fltr_post(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx,
1608d6218317SQi Zhang 			  enum virtchnl_fdir_prgm_status status,
1609d6218317SQi Zhang 			  bool success)
1610d6218317SQi Zhang {
1611d6218317SQi Zhang 	struct virtchnl_fdir_fltr_conf *conf = ctx->conf;
1612d6218317SQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
1613d6218317SQi Zhang 	enum virtchnl_status_code v_ret;
1614d6218317SQi Zhang 	struct virtchnl_fdir_del *resp;
1615d6218317SQi Zhang 	int ret, len, is_tun;
1616d6218317SQi Zhang 
1617d6218317SQi Zhang 	v_ret = VIRTCHNL_STATUS_SUCCESS;
1618d6218317SQi Zhang 	len = sizeof(*resp);
1619d6218317SQi Zhang 	resp = kzalloc(len, GFP_KERNEL);
1620d6218317SQi Zhang 	if (!resp) {
1621d6218317SQi Zhang 		len = 0;
1622d6218317SQi Zhang 		v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
1623d6218317SQi Zhang 		dev_dbg(dev, "VF %d: Alloc resp buf fail", vf->vf_id);
1624d6218317SQi Zhang 		goto err_exit;
1625d6218317SQi Zhang 	}
1626d6218317SQi Zhang 
1627d6218317SQi Zhang 	if (!success)
1628d6218317SQi Zhang 		goto err_exit;
1629d6218317SQi Zhang 
1630d6218317SQi Zhang 	is_tun = 0;
1631d6218317SQi Zhang 	resp->status = status;
1632d6218317SQi Zhang 	ice_vc_fdir_remove_entry(vf, conf, conf->flow_id);
1633d6218317SQi Zhang 	vf->fdir.fdir_fltr_cnt[conf->input.flow_type][is_tun]--;
1634d6218317SQi Zhang 
1635d6218317SQi Zhang 	ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret,
1636d6218317SQi Zhang 				    (u8 *)resp, len);
1637d6218317SQi Zhang 	kfree(resp);
1638d6218317SQi Zhang 
1639d6218317SQi Zhang 	dev_dbg(dev, "VF %d: flow_id:0x%X, FDIR %s success!\n",
1640d6218317SQi Zhang 		vf->vf_id, conf->flow_id,
1641d6218317SQi Zhang 		(ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) ?
1642d6218317SQi Zhang 		"add" : "del");
1643d6218317SQi Zhang 	devm_kfree(dev, conf);
1644d6218317SQi Zhang 	return ret;
1645d6218317SQi Zhang 
1646d6218317SQi Zhang err_exit:
1647d6218317SQi Zhang 	if (resp)
1648d6218317SQi Zhang 		resp->status = status;
1649d6218317SQi Zhang 	if (success)
1650d6218317SQi Zhang 		devm_kfree(dev, conf);
1651d6218317SQi Zhang 
1652d6218317SQi Zhang 	ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret,
1653d6218317SQi Zhang 				    (u8 *)resp, len);
1654d6218317SQi Zhang 	kfree(resp);
1655d6218317SQi Zhang 	return ret;
1656d6218317SQi Zhang }
1657d6218317SQi Zhang 
1658d6218317SQi Zhang /**
1659d6218317SQi Zhang  * ice_flush_fdir_ctx
1660d6218317SQi Zhang  * @pf: pointer to the PF structure
1661d6218317SQi Zhang  *
1662d6218317SQi Zhang  * Flush all the pending event on ctx_done list and process them.
1663d6218317SQi Zhang  */
ice_flush_fdir_ctx(struct ice_pf * pf)1664d6218317SQi Zhang void ice_flush_fdir_ctx(struct ice_pf *pf)
1665d6218317SQi Zhang {
1666c4c2c7dbSJacob Keller 	struct ice_vf *vf;
1667c4c2c7dbSJacob Keller 	unsigned int bkt;
1668d6218317SQi Zhang 
16697e408e07SAnirudh Venkataramanan 	if (!test_and_clear_bit(ICE_FD_VF_FLUSH_CTX, pf->state))
1670d6218317SQi Zhang 		return;
1671d6218317SQi Zhang 
16723d5985a1SJacob Keller 	mutex_lock(&pf->vfs.table_lock);
1673c4c2c7dbSJacob Keller 	ice_for_each_vf(pf, bkt, vf) {
1674d6218317SQi Zhang 		struct device *dev = ice_pf_to_dev(pf);
1675d6218317SQi Zhang 		enum virtchnl_fdir_prgm_status status;
1676d6218317SQi Zhang 		struct ice_vf_fdir_ctx *ctx;
1677d6218317SQi Zhang 		unsigned long flags;
1678d6218317SQi Zhang 		int ret;
1679d6218317SQi Zhang 
1680d6218317SQi Zhang 		if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states))
1681d6218317SQi Zhang 			continue;
1682d6218317SQi Zhang 
1683d6218317SQi Zhang 		if (vf->ctrl_vsi_idx == ICE_NO_VSI)
1684d6218317SQi Zhang 			continue;
1685d6218317SQi Zhang 
1686d6218317SQi Zhang 		ctx = &vf->fdir.ctx_done;
1687d6218317SQi Zhang 		spin_lock_irqsave(&vf->fdir.ctx_lock, flags);
1688d6218317SQi Zhang 		if (!(ctx->flags & ICE_VF_FDIR_CTX_VALID)) {
1689d6218317SQi Zhang 			spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1690d6218317SQi Zhang 			continue;
1691d6218317SQi Zhang 		}
1692d6218317SQi Zhang 		spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1693d6218317SQi Zhang 
1694d6218317SQi Zhang 		WARN_ON(ctx->stat == ICE_FDIR_CTX_READY);
1695d6218317SQi Zhang 		if (ctx->stat == ICE_FDIR_CTX_TIMEOUT) {
1696d6218317SQi Zhang 			status = VIRTCHNL_FDIR_FAILURE_RULE_TIMEOUT;
1697d6218317SQi Zhang 			dev_err(dev, "VF %d: ctrl_vsi irq timeout\n",
1698d6218317SQi Zhang 				vf->vf_id);
1699d6218317SQi Zhang 			goto err_exit;
1700d6218317SQi Zhang 		}
1701d6218317SQi Zhang 
1702d6218317SQi Zhang 		ret = ice_vf_verify_rx_desc(vf, ctx, &status);
1703d6218317SQi Zhang 		if (ret)
1704d6218317SQi Zhang 			goto err_exit;
1705d6218317SQi Zhang 
1706d6218317SQi Zhang 		if (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER)
1707d6218317SQi Zhang 			ice_vc_add_fdir_fltr_post(vf, ctx, status, true);
1708d6218317SQi Zhang 		else if (ctx->v_opcode == VIRTCHNL_OP_DEL_FDIR_FILTER)
1709d6218317SQi Zhang 			ice_vc_del_fdir_fltr_post(vf, ctx, status, true);
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 		continue;
1717d6218317SQi Zhang err_exit:
1718d6218317SQi Zhang 		if (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER)
1719d6218317SQi Zhang 			ice_vc_add_fdir_fltr_post(vf, ctx, status, false);
1720d6218317SQi Zhang 		else if (ctx->v_opcode == VIRTCHNL_OP_DEL_FDIR_FILTER)
1721d6218317SQi Zhang 			ice_vc_del_fdir_fltr_post(vf, ctx, status, false);
1722d6218317SQi Zhang 		else
1723d6218317SQi Zhang 			dev_err(dev, "VF %d: Unsupported opcode\n", vf->vf_id);
1724d6218317SQi Zhang 
1725d6218317SQi Zhang 		spin_lock_irqsave(&vf->fdir.ctx_lock, flags);
1726d6218317SQi Zhang 		ctx->flags &= ~ICE_VF_FDIR_CTX_VALID;
1727d6218317SQi Zhang 		spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1728d6218317SQi Zhang 	}
17293d5985a1SJacob Keller 	mutex_unlock(&pf->vfs.table_lock);
1730d6218317SQi Zhang }
1731d6218317SQi Zhang 
1732d6218317SQi Zhang /**
1733d6218317SQi Zhang  * ice_vc_fdir_set_irq_ctx - set FDIR context info for later IRQ handler
1734d6218317SQi Zhang  * @vf: pointer to the VF structure
1735d6218317SQi Zhang  * @conf: FDIR configuration for each filter
1736d6218317SQi Zhang  * @v_opcode: virtual channel operation code
1737d6218317SQi Zhang  *
1738d6218317SQi Zhang  * Return: 0 on success, and other on error.
1739d6218317SQi Zhang  */
1740d6218317SQi Zhang static int
ice_vc_fdir_set_irq_ctx(struct ice_vf * vf,struct virtchnl_fdir_fltr_conf * conf,enum virtchnl_ops v_opcode)1741d6218317SQi Zhang ice_vc_fdir_set_irq_ctx(struct ice_vf *vf, struct virtchnl_fdir_fltr_conf *conf,
1742d6218317SQi Zhang 			enum virtchnl_ops v_opcode)
1743d6218317SQi Zhang {
1744d6218317SQi Zhang 	struct device *dev = ice_pf_to_dev(vf->pf);
1745d6218317SQi Zhang 	struct ice_vf_fdir_ctx *ctx;
1746d6218317SQi Zhang 	unsigned long flags;
1747d6218317SQi Zhang 
1748d6218317SQi Zhang 	ctx = &vf->fdir.ctx_irq;
1749d6218317SQi Zhang 	spin_lock_irqsave(&vf->fdir.ctx_lock, flags);
1750d6218317SQi Zhang 	if ((vf->fdir.ctx_irq.flags & ICE_VF_FDIR_CTX_VALID) ||
1751d6218317SQi Zhang 	    (vf->fdir.ctx_done.flags & ICE_VF_FDIR_CTX_VALID)) {
1752d6218317SQi Zhang 		spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1753d6218317SQi Zhang 		dev_dbg(dev, "VF %d: Last request is still in progress\n",
1754d6218317SQi Zhang 			vf->vf_id);
1755d6218317SQi Zhang 		return -EBUSY;
1756d6218317SQi Zhang 	}
1757d6218317SQi Zhang 	ctx->flags |= ICE_VF_FDIR_CTX_VALID;
1758d6218317SQi Zhang 	spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1759d6218317SQi Zhang 
1760d6218317SQi Zhang 	ctx->conf = conf;
1761d6218317SQi Zhang 	ctx->v_opcode = v_opcode;
1762d6218317SQi Zhang 	ctx->stat = ICE_FDIR_CTX_READY;
1763d6218317SQi Zhang 	timer_setup(&ctx->rx_tmr, ice_vf_fdir_timer, 0);
1764d6218317SQi Zhang 
1765d6218317SQi Zhang 	mod_timer(&ctx->rx_tmr, round_jiffies(msecs_to_jiffies(10) + jiffies));
1766d6218317SQi Zhang 
1767d6218317SQi Zhang 	return 0;
1768d6218317SQi Zhang }
1769d6218317SQi Zhang 
1770d6218317SQi Zhang /**
1771d6218317SQi Zhang  * ice_vc_fdir_clear_irq_ctx - clear FDIR context info for IRQ handler
1772d6218317SQi Zhang  * @vf: pointer to the VF structure
1773d6218317SQi Zhang  *
1774d6218317SQi Zhang  * Return: 0 on success, and other on error.
1775d6218317SQi Zhang  */
ice_vc_fdir_clear_irq_ctx(struct ice_vf * vf)1776d6218317SQi Zhang static void ice_vc_fdir_clear_irq_ctx(struct ice_vf *vf)
1777d6218317SQi Zhang {
1778d6218317SQi Zhang 	struct ice_vf_fdir_ctx *ctx = &vf->fdir.ctx_irq;
1779d6218317SQi Zhang 	unsigned long flags;
1780d6218317SQi Zhang 
1781d6218317SQi Zhang 	del_timer(&ctx->rx_tmr);
1782d6218317SQi Zhang 	spin_lock_irqsave(&vf->fdir.ctx_lock, flags);
1783d6218317SQi Zhang 	ctx->flags &= ~ICE_VF_FDIR_CTX_VALID;
1784d6218317SQi Zhang 	spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1785d6218317SQi Zhang }
1786d6218317SQi Zhang 
1787d6218317SQi Zhang /**
17881f7ea1cdSQi Zhang  * ice_vc_add_fdir_fltr - add a FDIR filter for VF by the msg buffer
17891f7ea1cdSQi Zhang  * @vf: pointer to the VF info
17901f7ea1cdSQi Zhang  * @msg: pointer to the msg buffer
17911f7ea1cdSQi Zhang  *
17921f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
17931f7ea1cdSQi Zhang  */
ice_vc_add_fdir_fltr(struct ice_vf * vf,u8 * msg)17941f7ea1cdSQi Zhang int ice_vc_add_fdir_fltr(struct ice_vf *vf, u8 *msg)
17951f7ea1cdSQi Zhang {
17961f7ea1cdSQi Zhang 	struct virtchnl_fdir_add *fltr = (struct virtchnl_fdir_add *)msg;
17971f7ea1cdSQi Zhang 	struct virtchnl_fdir_add *stat = NULL;
17981f7ea1cdSQi Zhang 	struct virtchnl_fdir_fltr_conf *conf;
17991f7ea1cdSQi Zhang 	enum virtchnl_status_code v_ret;
18001f7ea1cdSQi Zhang 	struct device *dev;
18011f7ea1cdSQi Zhang 	struct ice_pf *pf;
18021f7ea1cdSQi Zhang 	int is_tun = 0;
18031f7ea1cdSQi Zhang 	int len = 0;
18041f7ea1cdSQi Zhang 	int ret;
18051f7ea1cdSQi Zhang 
18061f7ea1cdSQi Zhang 	pf = vf->pf;
18071f7ea1cdSQi Zhang 	dev = ice_pf_to_dev(pf);
18081f7ea1cdSQi Zhang 	ret = ice_vc_fdir_param_check(vf, fltr->vsi_id);
18091f7ea1cdSQi Zhang 	if (ret) {
18101f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_ERR_PARAM;
18111f7ea1cdSQi Zhang 		dev_dbg(dev, "Parameter check for VF %d failed\n", vf->vf_id);
18121f7ea1cdSQi Zhang 		goto err_exit;
18131f7ea1cdSQi Zhang 	}
18141f7ea1cdSQi Zhang 
18151f7ea1cdSQi Zhang 	ret = ice_vf_start_ctrl_vsi(vf);
18161f7ea1cdSQi Zhang 	if (ret && (ret != -EEXIST)) {
18171f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_ERR_PARAM;
18181f7ea1cdSQi Zhang 		dev_err(dev, "Init FDIR for VF %d failed, ret:%d\n",
18191f7ea1cdSQi Zhang 			vf->vf_id, ret);
18201f7ea1cdSQi Zhang 		goto err_exit;
18211f7ea1cdSQi Zhang 	}
18221f7ea1cdSQi Zhang 
18231f7ea1cdSQi Zhang 	stat = kzalloc(sizeof(*stat), GFP_KERNEL);
18241f7ea1cdSQi Zhang 	if (!stat) {
18251f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
18261f7ea1cdSQi Zhang 		dev_dbg(dev, "Alloc stat for VF %d failed\n", vf->vf_id);
18271f7ea1cdSQi Zhang 		goto err_exit;
18281f7ea1cdSQi Zhang 	}
18291f7ea1cdSQi Zhang 
18301f7ea1cdSQi Zhang 	conf = devm_kzalloc(dev, sizeof(*conf), GFP_KERNEL);
18311f7ea1cdSQi Zhang 	if (!conf) {
18321f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
18331f7ea1cdSQi Zhang 		dev_dbg(dev, "Alloc conf for VF %d failed\n", vf->vf_id);
18341f7ea1cdSQi Zhang 		goto err_exit;
18351f7ea1cdSQi Zhang 	}
18361f7ea1cdSQi Zhang 
18371f7ea1cdSQi Zhang 	len = sizeof(*stat);
18381f7ea1cdSQi Zhang 	ret = ice_vc_validate_fdir_fltr(vf, fltr, conf);
18391f7ea1cdSQi Zhang 	if (ret) {
18401f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
18411f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID;
18421f7ea1cdSQi Zhang 		dev_dbg(dev, "Invalid FDIR filter from VF %d\n", vf->vf_id);
18431f7ea1cdSQi Zhang 		goto err_free_conf;
18441f7ea1cdSQi Zhang 	}
18451f7ea1cdSQi Zhang 
18461f7ea1cdSQi Zhang 	if (fltr->validate_only) {
18471f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
18481f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_SUCCESS;
18491f7ea1cdSQi Zhang 		devm_kfree(dev, conf);
18501f7ea1cdSQi Zhang 		ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_FDIR_FILTER,
18511f7ea1cdSQi Zhang 					    v_ret, (u8 *)stat, len);
18521f7ea1cdSQi Zhang 		goto exit;
18531f7ea1cdSQi Zhang 	}
18541f7ea1cdSQi Zhang 
18551f7ea1cdSQi Zhang 	ret = ice_vc_fdir_config_input_set(vf, fltr, conf, is_tun);
18561f7ea1cdSQi Zhang 	if (ret) {
18571f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
18581f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_CONFLICT;
18591f7ea1cdSQi Zhang 		dev_err(dev, "VF %d: FDIR input set configure failed, ret:%d\n",
18601f7ea1cdSQi Zhang 			vf->vf_id, ret);
18611f7ea1cdSQi Zhang 		goto err_free_conf;
18621f7ea1cdSQi Zhang 	}
18631f7ea1cdSQi Zhang 
18641f7ea1cdSQi Zhang 	ret = ice_vc_fdir_is_dup_fltr(vf, conf);
18651f7ea1cdSQi Zhang 	if (ret) {
18661f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
18671f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_EXIST;
18681f7ea1cdSQi Zhang 		dev_dbg(dev, "VF %d: duplicated FDIR rule detected\n",
18691f7ea1cdSQi Zhang 			vf->vf_id);
18701f7ea1cdSQi Zhang 		goto err_free_conf;
18711f7ea1cdSQi Zhang 	}
18721f7ea1cdSQi Zhang 
1873d6218317SQi Zhang 	ret = ice_vc_fdir_insert_entry(vf, conf, &conf->flow_id);
18741f7ea1cdSQi Zhang 	if (ret) {
18751f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
18761f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
18771f7ea1cdSQi Zhang 		dev_dbg(dev, "VF %d: insert FDIR list failed\n", vf->vf_id);
18781f7ea1cdSQi Zhang 		goto err_free_conf;
18791f7ea1cdSQi Zhang 	}
18801f7ea1cdSQi Zhang 
1881d6218317SQi Zhang 	ret = ice_vc_fdir_set_irq_ctx(vf, conf, VIRTCHNL_OP_ADD_FDIR_FILTER);
1882d6218317SQi Zhang 	if (ret) {
1883d6218317SQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
1884d6218317SQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
1885d6218317SQi Zhang 		dev_dbg(dev, "VF %d: set FDIR context failed\n", vf->vf_id);
1886b4a01aceSSimei Su 		goto err_rem_entry;
1887d6218317SQi Zhang 	}
1888d6218317SQi Zhang 
18891f7ea1cdSQi Zhang 	ret = ice_vc_fdir_write_fltr(vf, conf, true, is_tun);
18901f7ea1cdSQi Zhang 	if (ret) {
18911f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
18921f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
18931f7ea1cdSQi Zhang 		dev_err(dev, "VF %d: writing FDIR rule failed, ret:%d\n",
18941f7ea1cdSQi Zhang 			vf->vf_id, ret);
1895b4a01aceSSimei Su 		goto err_clr_irq;
18961f7ea1cdSQi Zhang 	}
18971f7ea1cdSQi Zhang 
18981f7ea1cdSQi Zhang exit:
18991f7ea1cdSQi Zhang 	kfree(stat);
19001f7ea1cdSQi Zhang 	return ret;
19011f7ea1cdSQi Zhang 
1902b4a01aceSSimei Su err_clr_irq:
1903d6218317SQi Zhang 	ice_vc_fdir_clear_irq_ctx(vf);
1904b4a01aceSSimei Su err_rem_entry:
1905d6218317SQi Zhang 	ice_vc_fdir_remove_entry(vf, conf, conf->flow_id);
19061f7ea1cdSQi Zhang err_free_conf:
19071f7ea1cdSQi Zhang 	devm_kfree(dev, conf);
19081f7ea1cdSQi Zhang err_exit:
19091f7ea1cdSQi Zhang 	ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_FDIR_FILTER, v_ret,
19101f7ea1cdSQi Zhang 				    (u8 *)stat, len);
19111f7ea1cdSQi Zhang 	kfree(stat);
19121f7ea1cdSQi Zhang 	return ret;
19131f7ea1cdSQi Zhang }
19141f7ea1cdSQi Zhang 
19151f7ea1cdSQi Zhang /**
19161f7ea1cdSQi Zhang  * ice_vc_del_fdir_fltr - delete a FDIR filter for VF by the msg buffer
19171f7ea1cdSQi Zhang  * @vf: pointer to the VF info
19181f7ea1cdSQi Zhang  * @msg: pointer to the msg buffer
19191f7ea1cdSQi Zhang  *
19201f7ea1cdSQi Zhang  * Return: 0 on success, and other on error.
19211f7ea1cdSQi Zhang  */
ice_vc_del_fdir_fltr(struct ice_vf * vf,u8 * msg)19221f7ea1cdSQi Zhang int ice_vc_del_fdir_fltr(struct ice_vf *vf, u8 *msg)
19231f7ea1cdSQi Zhang {
19241f7ea1cdSQi Zhang 	struct virtchnl_fdir_del *fltr = (struct virtchnl_fdir_del *)msg;
19251f7ea1cdSQi Zhang 	struct virtchnl_fdir_del *stat = NULL;
19261f7ea1cdSQi Zhang 	struct virtchnl_fdir_fltr_conf *conf;
19271f7ea1cdSQi Zhang 	enum virtchnl_status_code v_ret;
19281f7ea1cdSQi Zhang 	struct device *dev;
19291f7ea1cdSQi Zhang 	struct ice_pf *pf;
19301f7ea1cdSQi Zhang 	int is_tun = 0;
19311f7ea1cdSQi Zhang 	int len = 0;
19321f7ea1cdSQi Zhang 	int ret;
19331f7ea1cdSQi Zhang 
19341f7ea1cdSQi Zhang 	pf = vf->pf;
19351f7ea1cdSQi Zhang 	dev = ice_pf_to_dev(pf);
19361f7ea1cdSQi Zhang 	ret = ice_vc_fdir_param_check(vf, fltr->vsi_id);
19371f7ea1cdSQi Zhang 	if (ret) {
19381f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_ERR_PARAM;
19391f7ea1cdSQi Zhang 		dev_dbg(dev, "Parameter check for VF %d failed\n", vf->vf_id);
19401f7ea1cdSQi Zhang 		goto err_exit;
19411f7ea1cdSQi Zhang 	}
19421f7ea1cdSQi Zhang 
19431f7ea1cdSQi Zhang 	stat = kzalloc(sizeof(*stat), GFP_KERNEL);
19441f7ea1cdSQi Zhang 	if (!stat) {
19451f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
19461f7ea1cdSQi Zhang 		dev_dbg(dev, "Alloc stat for VF %d failed\n", vf->vf_id);
19471f7ea1cdSQi Zhang 		goto err_exit;
19481f7ea1cdSQi Zhang 	}
19491f7ea1cdSQi Zhang 
19501f7ea1cdSQi Zhang 	len = sizeof(*stat);
19511f7ea1cdSQi Zhang 
19521f7ea1cdSQi Zhang 	conf = ice_vc_fdir_lookup_entry(vf, fltr->flow_id);
19531f7ea1cdSQi Zhang 	if (!conf) {
19541f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
19551f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST;
19561f7ea1cdSQi Zhang 		dev_dbg(dev, "VF %d: FDIR invalid flow_id:0x%X\n",
19571f7ea1cdSQi Zhang 			vf->vf_id, fltr->flow_id);
19581f7ea1cdSQi Zhang 		goto err_exit;
19591f7ea1cdSQi Zhang 	}
19601f7ea1cdSQi Zhang 
19611f7ea1cdSQi Zhang 	/* Just return failure when ctrl_vsi idx is invalid */
19621f7ea1cdSQi Zhang 	if (vf->ctrl_vsi_idx == ICE_NO_VSI) {
19631f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
19641f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
19651f7ea1cdSQi Zhang 		dev_err(dev, "Invalid FDIR ctrl_vsi for VF %d\n", vf->vf_id);
19661f7ea1cdSQi Zhang 		goto err_exit;
19671f7ea1cdSQi Zhang 	}
19681f7ea1cdSQi Zhang 
1969d6218317SQi Zhang 	ret = ice_vc_fdir_set_irq_ctx(vf, conf, VIRTCHNL_OP_DEL_FDIR_FILTER);
1970d6218317SQi Zhang 	if (ret) {
1971d6218317SQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
1972d6218317SQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
1973d6218317SQi Zhang 		dev_dbg(dev, "VF %d: set FDIR context failed\n", vf->vf_id);
1974d6218317SQi Zhang 		goto err_exit;
1975d6218317SQi Zhang 	}
1976d6218317SQi Zhang 
19771f7ea1cdSQi Zhang 	ret = ice_vc_fdir_write_fltr(vf, conf, false, is_tun);
19781f7ea1cdSQi Zhang 	if (ret) {
19791f7ea1cdSQi Zhang 		v_ret = VIRTCHNL_STATUS_SUCCESS;
19801f7ea1cdSQi Zhang 		stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
19811f7ea1cdSQi Zhang 		dev_err(dev, "VF %d: writing FDIR rule failed, ret:%d\n",
19821f7ea1cdSQi Zhang 			vf->vf_id, ret);
1983d6218317SQi Zhang 		goto err_del_tmr;
19841f7ea1cdSQi Zhang 	}
19851f7ea1cdSQi Zhang 
1986d6218317SQi Zhang 	kfree(stat);
19871f7ea1cdSQi Zhang 
1988d6218317SQi Zhang 	return ret;
19891f7ea1cdSQi Zhang 
1990d6218317SQi Zhang err_del_tmr:
1991d6218317SQi Zhang 	ice_vc_fdir_clear_irq_ctx(vf);
19921f7ea1cdSQi Zhang err_exit:
19931f7ea1cdSQi Zhang 	ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DEL_FDIR_FILTER, v_ret,
19941f7ea1cdSQi Zhang 				    (u8 *)stat, len);
19951f7ea1cdSQi Zhang 	kfree(stat);
19961f7ea1cdSQi Zhang 	return ret;
19971f7ea1cdSQi Zhang }
19981f7ea1cdSQi Zhang 
19991f7ea1cdSQi Zhang /**
20001f7ea1cdSQi Zhang  * ice_vf_fdir_init - init FDIR resource for VF
20011f7ea1cdSQi Zhang  * @vf: pointer to the VF info
20021f7ea1cdSQi Zhang  */
ice_vf_fdir_init(struct ice_vf * vf)20031f7ea1cdSQi Zhang void ice_vf_fdir_init(struct ice_vf *vf)
20041f7ea1cdSQi Zhang {
20051f7ea1cdSQi Zhang 	struct ice_vf_fdir *fdir = &vf->fdir;
20061f7ea1cdSQi Zhang 
20071f7ea1cdSQi Zhang 	idr_init(&fdir->fdir_rule_idr);
20081f7ea1cdSQi Zhang 	INIT_LIST_HEAD(&fdir->fdir_rule_list);
2009d6218317SQi Zhang 
2010d6218317SQi Zhang 	spin_lock_init(&fdir->ctx_lock);
2011d6218317SQi Zhang 	fdir->ctx_irq.flags = 0;
2012d6218317SQi Zhang 	fdir->ctx_done.flags = 0;
2013*83c911dcSLingyu Liu 	ice_vc_fdir_reset_cnt_all(fdir);
20141f7ea1cdSQi Zhang }
20151f7ea1cdSQi Zhang 
20161f7ea1cdSQi Zhang /**
20171f7ea1cdSQi Zhang  * ice_vf_fdir_exit - destroy FDIR resource for VF
20181f7ea1cdSQi Zhang  * @vf: pointer to the VF info
20191f7ea1cdSQi Zhang  */
ice_vf_fdir_exit(struct ice_vf * vf)20201f7ea1cdSQi Zhang void ice_vf_fdir_exit(struct ice_vf *vf)
20211f7ea1cdSQi Zhang {
20221f7ea1cdSQi Zhang 	ice_vc_fdir_flush_entry(vf);
20231f7ea1cdSQi Zhang 	idr_destroy(&vf->fdir.fdir_rule_idr);
20241f7ea1cdSQi Zhang 	ice_vc_fdir_rem_prof_all(vf);
20251f7ea1cdSQi Zhang 	ice_vc_fdir_free_prof_all(vf);
20261f7ea1cdSQi Zhang }
2027