11f7ea1cdSQi Zhang // SPDX-License-Identifier: GPL-2.0
2*88f7ac6cSPaul Greenwalt /* Copyright (C) 2021-2023, 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 /**
54283c911dcSLingyu Liu * ice_vc_fdir_reset_cnt_all - reset all FDIR counters for this VF FDIR
54383c911dcSLingyu Liu * @fdir: pointer to the VF FDIR structure
54483c911dcSLingyu Liu */
ice_vc_fdir_reset_cnt_all(struct ice_vf_fdir * fdir)54583c911dcSLingyu Liu static void ice_vc_fdir_reset_cnt_all(struct ice_vf_fdir *fdir)
54683c911dcSLingyu Liu {
54783c911dcSLingyu Liu enum ice_fltr_ptype flow;
54883c911dcSLingyu Liu
54983c911dcSLingyu Liu for (flow = ICE_FLTR_PTYPE_NONF_NONE;
55083c911dcSLingyu Liu flow < ICE_FLTR_PTYPE_MAX; flow++) {
55183c911dcSLingyu Liu fdir->fdir_fltr_cnt[flow][0] = 0;
55283c911dcSLingyu Liu fdir->fdir_fltr_cnt[flow][1] = 0;
55383c911dcSLingyu Liu }
554d6238907SAhmed Zaki
555d6238907SAhmed Zaki fdir->fdir_fltr_cnt_total = 0;
55683c911dcSLingyu Liu }
55783c911dcSLingyu Liu
55883c911dcSLingyu Liu /**
55929486b6dSJunfeng Guo * ice_vc_fdir_has_prof_conflict
56029486b6dSJunfeng Guo * @vf: pointer to the VF structure
56129486b6dSJunfeng Guo * @conf: FDIR configuration for each filter
56229486b6dSJunfeng Guo *
56329486b6dSJunfeng Guo * Check if @conf has conflicting profile with existing profiles
56429486b6dSJunfeng Guo *
56529486b6dSJunfeng Guo * Return: true on success, and false on error.
56629486b6dSJunfeng Guo */
56729486b6dSJunfeng Guo static bool
ice_vc_fdir_has_prof_conflict(struct ice_vf * vf,struct virtchnl_fdir_fltr_conf * conf)56829486b6dSJunfeng Guo ice_vc_fdir_has_prof_conflict(struct ice_vf *vf,
56929486b6dSJunfeng Guo struct virtchnl_fdir_fltr_conf *conf)
57029486b6dSJunfeng Guo {
57129486b6dSJunfeng Guo struct ice_fdir_fltr *desc;
57229486b6dSJunfeng Guo
57329486b6dSJunfeng Guo list_for_each_entry(desc, &vf->fdir.fdir_rule_list, fltr_node) {
57429486b6dSJunfeng Guo struct virtchnl_fdir_fltr_conf *existing_conf;
57529486b6dSJunfeng Guo enum ice_fltr_ptype flow_type_a, flow_type_b;
57629486b6dSJunfeng Guo struct ice_fdir_fltr *a, *b;
57729486b6dSJunfeng Guo
57829486b6dSJunfeng Guo existing_conf = to_fltr_conf_from_desc(desc);
57929486b6dSJunfeng Guo a = &existing_conf->input;
58029486b6dSJunfeng Guo b = &conf->input;
58129486b6dSJunfeng Guo flow_type_a = a->flow_type;
58229486b6dSJunfeng Guo flow_type_b = b->flow_type;
58329486b6dSJunfeng Guo
58429486b6dSJunfeng Guo /* No need to compare two rules with different tunnel types or
58529486b6dSJunfeng Guo * with the same protocol type.
58629486b6dSJunfeng Guo */
58729486b6dSJunfeng Guo if (existing_conf->ttype != conf->ttype ||
58829486b6dSJunfeng Guo flow_type_a == flow_type_b)
58929486b6dSJunfeng Guo continue;
59029486b6dSJunfeng Guo
59129486b6dSJunfeng Guo switch (flow_type_a) {
59229486b6dSJunfeng Guo case ICE_FLTR_PTYPE_NONF_IPV4_UDP:
59329486b6dSJunfeng Guo case ICE_FLTR_PTYPE_NONF_IPV4_TCP:
59429486b6dSJunfeng Guo case ICE_FLTR_PTYPE_NONF_IPV4_SCTP:
59529486b6dSJunfeng Guo if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_OTHER)
59629486b6dSJunfeng Guo return true;
59729486b6dSJunfeng Guo break;
59829486b6dSJunfeng Guo case ICE_FLTR_PTYPE_NONF_IPV4_OTHER:
59929486b6dSJunfeng Guo if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_UDP ||
60029486b6dSJunfeng Guo flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_TCP ||
60129486b6dSJunfeng Guo flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_SCTP)
60229486b6dSJunfeng Guo return true;
60329486b6dSJunfeng Guo break;
60429486b6dSJunfeng Guo case ICE_FLTR_PTYPE_NONF_IPV6_UDP:
60529486b6dSJunfeng Guo case ICE_FLTR_PTYPE_NONF_IPV6_TCP:
60629486b6dSJunfeng Guo case ICE_FLTR_PTYPE_NONF_IPV6_SCTP:
60729486b6dSJunfeng Guo if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_OTHER)
60829486b6dSJunfeng Guo return true;
60929486b6dSJunfeng Guo break;
61029486b6dSJunfeng Guo case ICE_FLTR_PTYPE_NONF_IPV6_OTHER:
61129486b6dSJunfeng Guo if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_UDP ||
61229486b6dSJunfeng Guo flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_TCP ||
61329486b6dSJunfeng Guo flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_SCTP)
61429486b6dSJunfeng Guo return true;
61529486b6dSJunfeng Guo break;
61629486b6dSJunfeng Guo default:
61729486b6dSJunfeng Guo break;
61829486b6dSJunfeng Guo }
61929486b6dSJunfeng Guo }
62029486b6dSJunfeng Guo
62129486b6dSJunfeng Guo return false;
62229486b6dSJunfeng Guo }
62329486b6dSJunfeng Guo
62429486b6dSJunfeng Guo /**
6251f7ea1cdSQi Zhang * ice_vc_fdir_write_flow_prof
6261f7ea1cdSQi Zhang * @vf: pointer to the VF structure
6271f7ea1cdSQi Zhang * @flow: filter flow type
6281f7ea1cdSQi Zhang * @seg: array of one or more packet segments that describe the flow
6291f7ea1cdSQi Zhang * @tun: 0 implies non-tunnel type filter, 1 implies tunnel type filter
6301f7ea1cdSQi Zhang *
6311f7ea1cdSQi Zhang * Write the flow's profile config and packet segment into the hardware
6321f7ea1cdSQi Zhang *
6331f7ea1cdSQi Zhang * Return: 0 on success, and other on error.
6341f7ea1cdSQi Zhang */
6351f7ea1cdSQi 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)6361f7ea1cdSQi Zhang ice_vc_fdir_write_flow_prof(struct ice_vf *vf, enum ice_fltr_ptype flow,
6371f7ea1cdSQi Zhang struct ice_flow_seg_info *seg, int tun)
6381f7ea1cdSQi Zhang {
6391f7ea1cdSQi Zhang struct ice_vf_fdir *fdir = &vf->fdir;
6401f7ea1cdSQi Zhang struct ice_vsi *vf_vsi, *ctrl_vsi;
6411f7ea1cdSQi Zhang struct ice_flow_seg_info *old_seg;
6421f7ea1cdSQi Zhang struct ice_flow_prof *prof = NULL;
6431f7ea1cdSQi Zhang struct ice_fd_hw_prof *vf_prof;
6441f7ea1cdSQi Zhang struct device *dev;
6451f7ea1cdSQi Zhang struct ice_pf *pf;
6461f7ea1cdSQi Zhang struct ice_hw *hw;
6471f7ea1cdSQi Zhang u64 entry1_h = 0;
6481f7ea1cdSQi Zhang u64 entry2_h = 0;
6491f7ea1cdSQi Zhang u64 prof_id;
6501f7ea1cdSQi Zhang int ret;
6511f7ea1cdSQi Zhang
6521f7ea1cdSQi Zhang pf = vf->pf;
6531f7ea1cdSQi Zhang dev = ice_pf_to_dev(pf);
6541f7ea1cdSQi Zhang hw = &pf->hw;
655772dec64SBrett Creeley vf_vsi = ice_get_vf_vsi(vf);
6561f7ea1cdSQi Zhang if (!vf_vsi)
6571f7ea1cdSQi Zhang return -EINVAL;
6581f7ea1cdSQi Zhang
6591f7ea1cdSQi Zhang ctrl_vsi = pf->vsi[vf->ctrl_vsi_idx];
6601f7ea1cdSQi Zhang if (!ctrl_vsi)
6611f7ea1cdSQi Zhang return -EINVAL;
6621f7ea1cdSQi Zhang
6631f7ea1cdSQi Zhang vf_prof = fdir->fdir_prof[flow];
6641f7ea1cdSQi Zhang old_seg = vf_prof->fdir_seg[tun];
6651f7ea1cdSQi Zhang if (old_seg) {
6661f7ea1cdSQi Zhang if (!memcmp(old_seg, seg, sizeof(*seg))) {
6671f7ea1cdSQi Zhang dev_dbg(dev, "Duplicated profile for VF %d!\n",
6681f7ea1cdSQi Zhang vf->vf_id);
6691f7ea1cdSQi Zhang return -EEXIST;
6701f7ea1cdSQi Zhang }
6711f7ea1cdSQi Zhang
6721f7ea1cdSQi Zhang if (fdir->fdir_fltr_cnt[flow][tun]) {
6731f7ea1cdSQi Zhang ret = -EINVAL;
6741f7ea1cdSQi Zhang dev_dbg(dev, "Input set conflicts for VF %d\n",
6751f7ea1cdSQi Zhang vf->vf_id);
6761f7ea1cdSQi Zhang goto err_exit;
6771f7ea1cdSQi Zhang }
6781f7ea1cdSQi Zhang
6791f7ea1cdSQi Zhang /* remove previously allocated profile */
6801f7ea1cdSQi Zhang ice_vc_fdir_rem_prof(vf, flow, tun);
6811f7ea1cdSQi Zhang }
6821f7ea1cdSQi Zhang
6831f7ea1cdSQi Zhang prof_id = ICE_FLOW_PROF_FD(vf_vsi->vsi_num, flow,
6841f7ea1cdSQi Zhang tun ? ICE_FLTR_PTYPE_MAX : 0);
6851f7ea1cdSQi Zhang
6862ccc1c1cSTony Nguyen ret = ice_flow_add_prof(hw, ICE_BLK_FD, ICE_FLOW_RX, prof_id, seg,
6871f7ea1cdSQi Zhang tun + 1, &prof);
6881f7ea1cdSQi Zhang if (ret) {
6891f7ea1cdSQi Zhang dev_dbg(dev, "Could not add VSI flow 0x%x for VF %d\n",
6901f7ea1cdSQi Zhang flow, vf->vf_id);
6911f7ea1cdSQi Zhang goto err_exit;
6921f7ea1cdSQi Zhang }
6931f7ea1cdSQi Zhang
6942ccc1c1cSTony Nguyen ret = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id, vf_vsi->idx,
6951f7ea1cdSQi Zhang vf_vsi->idx, ICE_FLOW_PRIO_NORMAL,
6961f7ea1cdSQi Zhang seg, &entry1_h);
6971f7ea1cdSQi Zhang if (ret) {
6981f7ea1cdSQi Zhang dev_dbg(dev, "Could not add flow 0x%x VSI entry for VF %d\n",
6991f7ea1cdSQi Zhang flow, vf->vf_id);
7001f7ea1cdSQi Zhang goto err_prof;
7011f7ea1cdSQi Zhang }
7021f7ea1cdSQi Zhang
7032ccc1c1cSTony Nguyen ret = ice_flow_add_entry(hw, ICE_BLK_FD, prof_id, vf_vsi->idx,
7041f7ea1cdSQi Zhang ctrl_vsi->idx, ICE_FLOW_PRIO_NORMAL,
7051f7ea1cdSQi Zhang seg, &entry2_h);
7061f7ea1cdSQi Zhang if (ret) {
7071f7ea1cdSQi Zhang dev_dbg(dev,
7081f7ea1cdSQi Zhang "Could not add flow 0x%x Ctrl VSI entry for VF %d\n",
7091f7ea1cdSQi Zhang flow, vf->vf_id);
7101f7ea1cdSQi Zhang goto err_entry_1;
7111f7ea1cdSQi Zhang }
7121f7ea1cdSQi Zhang
7131f7ea1cdSQi Zhang vf_prof->fdir_seg[tun] = seg;
7141f7ea1cdSQi Zhang vf_prof->cnt = 0;
7151f7ea1cdSQi Zhang fdir->prof_entry_cnt[flow][tun] = 0;
7161f7ea1cdSQi Zhang
7171f7ea1cdSQi Zhang vf_prof->entry_h[vf_prof->cnt][tun] = entry1_h;
7181f7ea1cdSQi Zhang vf_prof->vsi_h[vf_prof->cnt] = vf_vsi->idx;
7191f7ea1cdSQi Zhang vf_prof->cnt++;
7201f7ea1cdSQi Zhang fdir->prof_entry_cnt[flow][tun]++;
7211f7ea1cdSQi Zhang
7221f7ea1cdSQi Zhang vf_prof->entry_h[vf_prof->cnt][tun] = entry2_h;
7231f7ea1cdSQi Zhang vf_prof->vsi_h[vf_prof->cnt] = ctrl_vsi->idx;
7241f7ea1cdSQi Zhang vf_prof->cnt++;
7251f7ea1cdSQi Zhang fdir->prof_entry_cnt[flow][tun]++;
7261f7ea1cdSQi Zhang
7271f7ea1cdSQi Zhang return 0;
7281f7ea1cdSQi Zhang
7291f7ea1cdSQi Zhang err_entry_1:
7301f7ea1cdSQi Zhang ice_rem_prof_id_flow(hw, ICE_BLK_FD,
7311f7ea1cdSQi Zhang ice_get_hw_vsi_num(hw, vf_vsi->idx), prof_id);
7321f7ea1cdSQi Zhang ice_flow_rem_entry(hw, ICE_BLK_FD, entry1_h);
7331f7ea1cdSQi Zhang err_prof:
7341f7ea1cdSQi Zhang ice_flow_rem_prof(hw, ICE_BLK_FD, prof_id);
7351f7ea1cdSQi Zhang err_exit:
7361f7ea1cdSQi Zhang return ret;
7371f7ea1cdSQi Zhang }
7381f7ea1cdSQi Zhang
7391f7ea1cdSQi Zhang /**
7401f7ea1cdSQi Zhang * ice_vc_fdir_config_input_set
7411f7ea1cdSQi Zhang * @vf: pointer to the VF structure
7421f7ea1cdSQi Zhang * @fltr: virtual channel add cmd buffer
7431f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter
7441f7ea1cdSQi Zhang * @tun: 0 implies non-tunnel type filter, 1 implies tunnel type filter
7451f7ea1cdSQi Zhang *
7461f7ea1cdSQi Zhang * Config the input set type and value for virtual channel add msg buffer
7471f7ea1cdSQi Zhang *
7481f7ea1cdSQi Zhang * Return: 0 on success, and other on error.
7491f7ea1cdSQi Zhang */
7501f7ea1cdSQi 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)7511f7ea1cdSQi Zhang ice_vc_fdir_config_input_set(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
7521f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf, int tun)
7531f7ea1cdSQi Zhang {
7541f7ea1cdSQi Zhang struct ice_fdir_fltr *input = &conf->input;
7551f7ea1cdSQi Zhang struct device *dev = ice_pf_to_dev(vf->pf);
7561f7ea1cdSQi Zhang struct ice_flow_seg_info *seg;
7571f7ea1cdSQi Zhang enum ice_fltr_ptype flow;
7581f7ea1cdSQi Zhang int ret;
7591f7ea1cdSQi Zhang
76029486b6dSJunfeng Guo ret = ice_vc_fdir_has_prof_conflict(vf, conf);
76129486b6dSJunfeng Guo if (ret) {
76229486b6dSJunfeng Guo dev_dbg(dev, "Found flow profile conflict for VF %d\n",
76329486b6dSJunfeng Guo vf->vf_id);
76429486b6dSJunfeng Guo return ret;
76529486b6dSJunfeng Guo }
76629486b6dSJunfeng Guo
7671f7ea1cdSQi Zhang flow = input->flow_type;
7681f7ea1cdSQi Zhang ret = ice_vc_fdir_alloc_prof(vf, flow);
7691f7ea1cdSQi Zhang if (ret) {
7701f7ea1cdSQi Zhang dev_dbg(dev, "Alloc flow prof for VF %d failed\n", vf->vf_id);
7711f7ea1cdSQi Zhang return ret;
7721f7ea1cdSQi Zhang }
7731f7ea1cdSQi Zhang
7741f7ea1cdSQi Zhang seg = devm_kzalloc(dev, sizeof(*seg), GFP_KERNEL);
7751f7ea1cdSQi Zhang if (!seg)
7761f7ea1cdSQi Zhang return -ENOMEM;
7771f7ea1cdSQi Zhang
7781f7ea1cdSQi Zhang ret = ice_vc_fdir_set_flow_fld(vf, fltr, conf, seg);
7791f7ea1cdSQi Zhang if (ret) {
7801f7ea1cdSQi Zhang dev_dbg(dev, "Set flow field for VF %d failed\n", vf->vf_id);
7811f7ea1cdSQi Zhang goto err_exit;
7821f7ea1cdSQi Zhang }
7831f7ea1cdSQi Zhang
7841f7ea1cdSQi Zhang ret = ice_vc_fdir_set_flow_hdr(vf, conf, seg);
7851f7ea1cdSQi Zhang if (ret) {
7861f7ea1cdSQi Zhang dev_dbg(dev, "Set flow hdr for VF %d failed\n", vf->vf_id);
7871f7ea1cdSQi Zhang goto err_exit;
7881f7ea1cdSQi Zhang }
7891f7ea1cdSQi Zhang
7901f7ea1cdSQi Zhang ret = ice_vc_fdir_write_flow_prof(vf, flow, seg, tun);
7911f7ea1cdSQi Zhang if (ret == -EEXIST) {
7921f7ea1cdSQi Zhang devm_kfree(dev, seg);
7931f7ea1cdSQi Zhang } else if (ret) {
7941f7ea1cdSQi Zhang dev_dbg(dev, "Write flow profile for VF %d failed\n",
7951f7ea1cdSQi Zhang vf->vf_id);
7961f7ea1cdSQi Zhang goto err_exit;
7971f7ea1cdSQi Zhang }
7981f7ea1cdSQi Zhang
7991f7ea1cdSQi Zhang return 0;
8001f7ea1cdSQi Zhang
8011f7ea1cdSQi Zhang err_exit:
8021f7ea1cdSQi Zhang devm_kfree(dev, seg);
8031f7ea1cdSQi Zhang return ret;
8041f7ea1cdSQi Zhang }
8051f7ea1cdSQi Zhang
8061f7ea1cdSQi Zhang /**
8070ce332fdSQi Zhang * ice_vc_fdir_parse_pattern
8080ce332fdSQi Zhang * @vf: pointer to the VF info
8090ce332fdSQi Zhang * @fltr: virtual channel add cmd buffer
8100ce332fdSQi Zhang * @conf: FDIR configuration for each filter
8110ce332fdSQi Zhang *
8120ce332fdSQi Zhang * Parse the virtual channel filter's pattern and store them into conf
8130ce332fdSQi Zhang *
8140ce332fdSQi Zhang * Return: 0 on success, and other on error.
8150ce332fdSQi Zhang */
8160ce332fdSQi Zhang static int
ice_vc_fdir_parse_pattern(struct ice_vf * vf,struct virtchnl_fdir_add * fltr,struct virtchnl_fdir_fltr_conf * conf)8170ce332fdSQi Zhang ice_vc_fdir_parse_pattern(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
8180ce332fdSQi Zhang struct virtchnl_fdir_fltr_conf *conf)
8190ce332fdSQi Zhang {
8200ce332fdSQi Zhang struct virtchnl_proto_hdrs *proto = &fltr->rule_cfg.proto_hdrs;
8210ce332fdSQi Zhang enum virtchnl_proto_hdr_type l3 = VIRTCHNL_PROTO_HDR_NONE;
822213528feSQi Zhang enum virtchnl_proto_hdr_type l4 = VIRTCHNL_PROTO_HDR_NONE;
8230ce332fdSQi Zhang struct device *dev = ice_pf_to_dev(vf->pf);
8240ce332fdSQi Zhang struct ice_fdir_fltr *input = &conf->input;
8250ce332fdSQi Zhang int i;
8260ce332fdSQi Zhang
8270ce332fdSQi Zhang if (proto->count > VIRTCHNL_MAX_NUM_PROTO_HDRS) {
8280ce332fdSQi Zhang dev_dbg(dev, "Invalid protocol count:0x%x for VF %d\n",
8290ce332fdSQi Zhang proto->count, vf->vf_id);
8300ce332fdSQi Zhang return -EINVAL;
8310ce332fdSQi Zhang }
8320ce332fdSQi Zhang
8330ce332fdSQi Zhang for (i = 0; i < proto->count; i++) {
8340ce332fdSQi Zhang struct virtchnl_proto_hdr *hdr = &proto->proto_hdr[i];
835213528feSQi Zhang struct ip_esp_hdr *esph;
836213528feSQi Zhang struct ip_auth_hdr *ah;
8370ce332fdSQi Zhang struct sctphdr *sctph;
8380ce332fdSQi Zhang struct ipv6hdr *ip6h;
8390ce332fdSQi Zhang struct udphdr *udph;
8400ce332fdSQi Zhang struct tcphdr *tcph;
84121606584SQi Zhang struct ethhdr *eth;
8420ce332fdSQi Zhang struct iphdr *iph;
843213528feSQi Zhang u8 s_field;
844ef9e4cc5SQi Zhang u8 *rawh;
8450ce332fdSQi Zhang
8460ce332fdSQi Zhang switch (hdr->type) {
8470ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_ETH:
84821606584SQi Zhang eth = (struct ethhdr *)hdr->buffer;
84921606584SQi Zhang input->flow_type = ICE_FLTR_PTYPE_NON_IP_L2;
85021606584SQi Zhang
85121606584SQi Zhang if (hdr->field_selector)
85221606584SQi Zhang input->ext_data.ether_type = eth->h_proto;
8530ce332fdSQi Zhang break;
8540ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_IPV4:
8550ce332fdSQi Zhang iph = (struct iphdr *)hdr->buffer;
8560ce332fdSQi Zhang l3 = VIRTCHNL_PROTO_HDR_IPV4;
8570ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_OTHER;
8580ce332fdSQi Zhang
8590ce332fdSQi Zhang if (hdr->field_selector) {
8600ce332fdSQi Zhang input->ip.v4.src_ip = iph->saddr;
8610ce332fdSQi Zhang input->ip.v4.dst_ip = iph->daddr;
8620ce332fdSQi Zhang input->ip.v4.tos = iph->tos;
8630ce332fdSQi Zhang input->ip.v4.proto = iph->protocol;
8640ce332fdSQi Zhang }
8650ce332fdSQi Zhang break;
8660ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_IPV6:
8670ce332fdSQi Zhang ip6h = (struct ipv6hdr *)hdr->buffer;
8680ce332fdSQi Zhang l3 = VIRTCHNL_PROTO_HDR_IPV6;
8690ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_OTHER;
8700ce332fdSQi Zhang
8710ce332fdSQi Zhang if (hdr->field_selector) {
8720ce332fdSQi Zhang memcpy(input->ip.v6.src_ip,
8730ce332fdSQi Zhang ip6h->saddr.in6_u.u6_addr8,
8740ce332fdSQi Zhang sizeof(ip6h->saddr));
8750ce332fdSQi Zhang memcpy(input->ip.v6.dst_ip,
8760ce332fdSQi Zhang ip6h->daddr.in6_u.u6_addr8,
8770ce332fdSQi Zhang sizeof(ip6h->daddr));
8780ce332fdSQi Zhang input->ip.v6.tc = ((u8)(ip6h->priority) << 4) |
8790ce332fdSQi Zhang (ip6h->flow_lbl[0] >> 4);
8800ce332fdSQi Zhang input->ip.v6.proto = ip6h->nexthdr;
8810ce332fdSQi Zhang }
8820ce332fdSQi Zhang break;
8830ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_TCP:
8840ce332fdSQi Zhang tcph = (struct tcphdr *)hdr->buffer;
8850ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
8860ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_TCP;
8870ce332fdSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
8880ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_TCP;
8890ce332fdSQi Zhang
8900ce332fdSQi Zhang if (hdr->field_selector) {
8910ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) {
8920ce332fdSQi Zhang input->ip.v4.src_port = tcph->source;
8930ce332fdSQi Zhang input->ip.v4.dst_port = tcph->dest;
8940ce332fdSQi Zhang } else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) {
8950ce332fdSQi Zhang input->ip.v6.src_port = tcph->source;
8960ce332fdSQi Zhang input->ip.v6.dst_port = tcph->dest;
8970ce332fdSQi Zhang }
8980ce332fdSQi Zhang }
8990ce332fdSQi Zhang break;
9000ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_UDP:
9010ce332fdSQi Zhang udph = (struct udphdr *)hdr->buffer;
9020ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
9030ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_UDP;
9040ce332fdSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
9050ce332fdSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_UDP;
9060ce332fdSQi Zhang
9070ce332fdSQi Zhang if (hdr->field_selector) {
9080ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) {
9090ce332fdSQi Zhang input->ip.v4.src_port = udph->source;
9100ce332fdSQi Zhang input->ip.v4.dst_port = udph->dest;
9110ce332fdSQi Zhang } else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) {
9120ce332fdSQi Zhang input->ip.v6.src_port = udph->source;
9130ce332fdSQi Zhang input->ip.v6.dst_port = udph->dest;
9140ce332fdSQi Zhang }
9150ce332fdSQi Zhang }
9160ce332fdSQi Zhang break;
9170ce332fdSQi Zhang case VIRTCHNL_PROTO_HDR_SCTP:
9180ce332fdSQi Zhang sctph = (struct sctphdr *)hdr->buffer;
9190ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
9200ce332fdSQi Zhang input->flow_type =
9210ce332fdSQi Zhang ICE_FLTR_PTYPE_NONF_IPV4_SCTP;
9220ce332fdSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
9230ce332fdSQi Zhang input->flow_type =
9240ce332fdSQi Zhang ICE_FLTR_PTYPE_NONF_IPV6_SCTP;
9250ce332fdSQi Zhang
9260ce332fdSQi Zhang if (hdr->field_selector) {
9270ce332fdSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4) {
9280ce332fdSQi Zhang input->ip.v4.src_port = sctph->source;
9290ce332fdSQi Zhang input->ip.v4.dst_port = sctph->dest;
9300ce332fdSQi Zhang } else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) {
9310ce332fdSQi Zhang input->ip.v6.src_port = sctph->source;
9320ce332fdSQi Zhang input->ip.v6.dst_port = sctph->dest;
9330ce332fdSQi Zhang }
9340ce332fdSQi Zhang }
9350ce332fdSQi Zhang break;
936213528feSQi Zhang case VIRTCHNL_PROTO_HDR_L2TPV3:
937213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
938213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_L2TPV3;
939213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
940213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_L2TPV3;
941213528feSQi Zhang
942213528feSQi Zhang if (hdr->field_selector)
943213528feSQi Zhang input->l2tpv3_data.session_id = *((__be32 *)hdr->buffer);
944213528feSQi Zhang break;
945213528feSQi Zhang case VIRTCHNL_PROTO_HDR_ESP:
946213528feSQi Zhang esph = (struct ip_esp_hdr *)hdr->buffer;
947213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4 &&
948213528feSQi Zhang l4 == VIRTCHNL_PROTO_HDR_UDP)
949213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_NAT_T_ESP;
950213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 &&
951213528feSQi Zhang l4 == VIRTCHNL_PROTO_HDR_UDP)
952213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_NAT_T_ESP;
953213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV4 &&
954213528feSQi Zhang l4 == VIRTCHNL_PROTO_HDR_NONE)
955213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_ESP;
956213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 &&
957213528feSQi Zhang l4 == VIRTCHNL_PROTO_HDR_NONE)
958213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_ESP;
959213528feSQi Zhang
960213528feSQi Zhang if (l4 == VIRTCHNL_PROTO_HDR_UDP)
961213528feSQi Zhang conf->inset_flag |= FDIR_INSET_FLAG_ESP_UDP;
962213528feSQi Zhang else
963213528feSQi Zhang conf->inset_flag |= FDIR_INSET_FLAG_ESP_IPSEC;
964213528feSQi Zhang
965213528feSQi Zhang if (hdr->field_selector) {
966213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
967213528feSQi Zhang input->ip.v4.sec_parm_idx = esph->spi;
968213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
969213528feSQi Zhang input->ip.v6.sec_parm_idx = esph->spi;
970213528feSQi Zhang }
971213528feSQi Zhang break;
972213528feSQi Zhang case VIRTCHNL_PROTO_HDR_AH:
973213528feSQi Zhang ah = (struct ip_auth_hdr *)hdr->buffer;
974213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
975213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_AH;
976213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
977213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_AH;
978213528feSQi Zhang
979213528feSQi Zhang if (hdr->field_selector) {
980213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
981213528feSQi Zhang input->ip.v4.sec_parm_idx = ah->spi;
982213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
983213528feSQi Zhang input->ip.v6.sec_parm_idx = ah->spi;
984213528feSQi Zhang }
985213528feSQi Zhang break;
986213528feSQi Zhang case VIRTCHNL_PROTO_HDR_PFCP:
987213528feSQi Zhang rawh = (u8 *)hdr->buffer;
988213528feSQi Zhang s_field = (rawh[0] >> PFCP_S_OFFSET) & PFCP_S_MASK;
989213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && s_field == 0)
990213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_PFCP_NODE;
991213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && s_field == 1)
992213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_PFCP_SESSION;
993213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && s_field == 0)
994213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_PFCP_NODE;
995213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && s_field == 1)
996213528feSQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_PFCP_SESSION;
997213528feSQi Zhang
998213528feSQi Zhang if (hdr->field_selector) {
999213528feSQi Zhang if (l3 == VIRTCHNL_PROTO_HDR_IPV4)
1000213528feSQi Zhang input->ip.v4.dst_port = cpu_to_be16(PFCP_PORT_NR);
1001213528feSQi Zhang else if (l3 == VIRTCHNL_PROTO_HDR_IPV6)
1002213528feSQi Zhang input->ip.v6.dst_port = cpu_to_be16(PFCP_PORT_NR);
1003213528feSQi Zhang }
1004213528feSQi Zhang break;
1005ef9e4cc5SQi Zhang case VIRTCHNL_PROTO_HDR_GTPU_IP:
1006ef9e4cc5SQi Zhang rawh = (u8 *)hdr->buffer;
1007ef9e4cc5SQi Zhang input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER;
1008ef9e4cc5SQi Zhang
1009ef9e4cc5SQi Zhang if (hdr->field_selector)
1010ef9e4cc5SQi Zhang input->gtpu_data.teid = *(__be32 *)(&rawh[GTPU_TEID_OFFSET]);
1011ef9e4cc5SQi Zhang conf->ttype = ICE_FDIR_TUNNEL_TYPE_GTPU;
1012ef9e4cc5SQi Zhang break;
1013ef9e4cc5SQi Zhang case VIRTCHNL_PROTO_HDR_GTPU_EH:
1014ef9e4cc5SQi Zhang rawh = (u8 *)hdr->buffer;
1015ef9e4cc5SQi Zhang
1016ef9e4cc5SQi Zhang if (hdr->field_selector)
1017ef9e4cc5SQi Zhang input->gtpu_data.qfi = rawh[GTPU_EH_QFI_OFFSET] & GTPU_EH_QFI_MASK;
1018ef9e4cc5SQi Zhang conf->ttype = ICE_FDIR_TUNNEL_TYPE_GTPU_EH;
1019ef9e4cc5SQi Zhang break;
10200ce332fdSQi Zhang default:
10210ce332fdSQi Zhang dev_dbg(dev, "Invalid header type 0x:%x for VF %d\n",
10220ce332fdSQi Zhang hdr->type, vf->vf_id);
10230ce332fdSQi Zhang return -EINVAL;
10240ce332fdSQi Zhang }
10250ce332fdSQi Zhang }
10260ce332fdSQi Zhang
10270ce332fdSQi Zhang return 0;
10280ce332fdSQi Zhang }
10290ce332fdSQi Zhang
10300ce332fdSQi Zhang /**
10310ce332fdSQi Zhang * ice_vc_fdir_parse_action
10320ce332fdSQi Zhang * @vf: pointer to the VF info
10330ce332fdSQi Zhang * @fltr: virtual channel add cmd buffer
10340ce332fdSQi Zhang * @conf: FDIR configuration for each filter
10350ce332fdSQi Zhang *
10360ce332fdSQi Zhang * Parse the virtual channel filter's action and store them into conf
10370ce332fdSQi Zhang *
10380ce332fdSQi Zhang * Return: 0 on success, and other on error.
10390ce332fdSQi Zhang */
10400ce332fdSQi Zhang static int
ice_vc_fdir_parse_action(struct ice_vf * vf,struct virtchnl_fdir_add * fltr,struct virtchnl_fdir_fltr_conf * conf)10410ce332fdSQi Zhang ice_vc_fdir_parse_action(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
10420ce332fdSQi Zhang struct virtchnl_fdir_fltr_conf *conf)
10430ce332fdSQi Zhang {
10440ce332fdSQi Zhang struct virtchnl_filter_action_set *as = &fltr->rule_cfg.action_set;
10450ce332fdSQi Zhang struct device *dev = ice_pf_to_dev(vf->pf);
10460ce332fdSQi Zhang struct ice_fdir_fltr *input = &conf->input;
10470ce332fdSQi Zhang u32 dest_num = 0;
10480ce332fdSQi Zhang u32 mark_num = 0;
10490ce332fdSQi Zhang int i;
10500ce332fdSQi Zhang
10510ce332fdSQi Zhang if (as->count > VIRTCHNL_MAX_NUM_ACTIONS) {
10520ce332fdSQi Zhang dev_dbg(dev, "Invalid action numbers:0x%x for VF %d\n",
10530ce332fdSQi Zhang as->count, vf->vf_id);
10540ce332fdSQi Zhang return -EINVAL;
10550ce332fdSQi Zhang }
10560ce332fdSQi Zhang
10570ce332fdSQi Zhang for (i = 0; i < as->count; i++) {
10580ce332fdSQi Zhang struct virtchnl_filter_action *action = &as->actions[i];
10590ce332fdSQi Zhang
10600ce332fdSQi Zhang switch (action->type) {
1061346bf250SQi Zhang case VIRTCHNL_ACTION_PASSTHRU:
1062346bf250SQi Zhang dest_num++;
1063346bf250SQi Zhang input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_OTHER;
1064346bf250SQi Zhang break;
10650ce332fdSQi Zhang case VIRTCHNL_ACTION_DROP:
10660ce332fdSQi Zhang dest_num++;
10670ce332fdSQi Zhang input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DROP_PKT;
10680ce332fdSQi Zhang break;
10690ce332fdSQi Zhang case VIRTCHNL_ACTION_QUEUE:
10700ce332fdSQi Zhang dest_num++;
10710ce332fdSQi Zhang input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QINDEX;
10720ce332fdSQi Zhang input->q_index = action->act_conf.queue.index;
10730ce332fdSQi Zhang break;
1074346bf250SQi Zhang case VIRTCHNL_ACTION_Q_REGION:
1075346bf250SQi Zhang dest_num++;
1076346bf250SQi Zhang input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QGROUP;
1077346bf250SQi Zhang input->q_index = action->act_conf.queue.index;
1078346bf250SQi Zhang input->q_region = action->act_conf.queue.region;
1079346bf250SQi Zhang break;
10800ce332fdSQi Zhang case VIRTCHNL_ACTION_MARK:
10810ce332fdSQi Zhang mark_num++;
10820ce332fdSQi Zhang input->fltr_id = action->act_conf.mark_id;
10830ce332fdSQi Zhang input->fdid_prio = ICE_FXD_FLTR_QW1_FDID_PRI_THREE;
10840ce332fdSQi Zhang break;
10850ce332fdSQi Zhang default:
10860ce332fdSQi Zhang dev_dbg(dev, "Invalid action type:0x%x for VF %d\n",
10870ce332fdSQi Zhang action->type, vf->vf_id);
10880ce332fdSQi Zhang return -EINVAL;
10890ce332fdSQi Zhang }
10900ce332fdSQi Zhang }
10910ce332fdSQi Zhang
10920ce332fdSQi Zhang if (dest_num == 0 || dest_num >= 2) {
10930ce332fdSQi Zhang dev_dbg(dev, "Invalid destination action for VF %d\n",
10940ce332fdSQi Zhang vf->vf_id);
10950ce332fdSQi Zhang return -EINVAL;
10960ce332fdSQi Zhang }
10970ce332fdSQi Zhang
10980ce332fdSQi Zhang if (mark_num >= 2) {
10990ce332fdSQi Zhang dev_dbg(dev, "Too many mark actions for VF %d\n", vf->vf_id);
11000ce332fdSQi Zhang return -EINVAL;
11010ce332fdSQi Zhang }
11020ce332fdSQi Zhang
11030ce332fdSQi Zhang return 0;
11040ce332fdSQi Zhang }
11050ce332fdSQi Zhang
11060ce332fdSQi Zhang /**
11071f7ea1cdSQi Zhang * ice_vc_validate_fdir_fltr - validate the virtual channel filter
11081f7ea1cdSQi Zhang * @vf: pointer to the VF info
11091f7ea1cdSQi Zhang * @fltr: virtual channel add cmd buffer
11101f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter
11111f7ea1cdSQi Zhang *
11121f7ea1cdSQi Zhang * Return: 0 on success, and other on error.
11131f7ea1cdSQi Zhang */
11141f7ea1cdSQi Zhang static int
ice_vc_validate_fdir_fltr(struct ice_vf * vf,struct virtchnl_fdir_add * fltr,struct virtchnl_fdir_fltr_conf * conf)11151f7ea1cdSQi Zhang ice_vc_validate_fdir_fltr(struct ice_vf *vf, struct virtchnl_fdir_add *fltr,
11161f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf)
11171f7ea1cdSQi Zhang {
111860f44fe4SJeff Guo struct virtchnl_proto_hdrs *proto = &fltr->rule_cfg.proto_hdrs;
11190ce332fdSQi Zhang int ret;
11200ce332fdSQi Zhang
112160f44fe4SJeff Guo if (!ice_vc_validate_pattern(vf, proto))
112260f44fe4SJeff Guo return -EINVAL;
11230ce332fdSQi Zhang
11240ce332fdSQi Zhang ret = ice_vc_fdir_parse_pattern(vf, fltr, conf);
11250ce332fdSQi Zhang if (ret)
11260ce332fdSQi Zhang return ret;
11270ce332fdSQi Zhang
11280ce332fdSQi Zhang return ice_vc_fdir_parse_action(vf, fltr, conf);
11291f7ea1cdSQi Zhang }
11301f7ea1cdSQi Zhang
11311f7ea1cdSQi Zhang /**
11321f7ea1cdSQi Zhang * ice_vc_fdir_comp_rules - compare if two filter rules have the same value
11331f7ea1cdSQi Zhang * @conf_a: FDIR configuration for filter a
11341f7ea1cdSQi Zhang * @conf_b: FDIR configuration for filter b
11351f7ea1cdSQi Zhang *
11361f7ea1cdSQi Zhang * Return: 0 on success, and other on error.
11371f7ea1cdSQi Zhang */
11381f7ea1cdSQi Zhang static bool
ice_vc_fdir_comp_rules(struct virtchnl_fdir_fltr_conf * conf_a,struct virtchnl_fdir_fltr_conf * conf_b)11391f7ea1cdSQi Zhang ice_vc_fdir_comp_rules(struct virtchnl_fdir_fltr_conf *conf_a,
11401f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf_b)
11411f7ea1cdSQi Zhang {
11421f7ea1cdSQi Zhang struct ice_fdir_fltr *a = &conf_a->input;
11431f7ea1cdSQi Zhang struct ice_fdir_fltr *b = &conf_b->input;
11441f7ea1cdSQi Zhang
1145ef9e4cc5SQi Zhang if (conf_a->ttype != conf_b->ttype)
1146ef9e4cc5SQi Zhang return false;
11471f7ea1cdSQi Zhang if (a->flow_type != b->flow_type)
11481f7ea1cdSQi Zhang return false;
11491f7ea1cdSQi Zhang if (memcmp(&a->ip, &b->ip, sizeof(a->ip)))
11501f7ea1cdSQi Zhang return false;
11511f7ea1cdSQi Zhang if (memcmp(&a->mask, &b->mask, sizeof(a->mask)))
11521f7ea1cdSQi Zhang return false;
1153ef9e4cc5SQi Zhang if (memcmp(&a->gtpu_data, &b->gtpu_data, sizeof(a->gtpu_data)))
1154ef9e4cc5SQi Zhang return false;
1155ef9e4cc5SQi Zhang if (memcmp(&a->gtpu_mask, &b->gtpu_mask, sizeof(a->gtpu_mask)))
1156ef9e4cc5SQi Zhang return false;
1157213528feSQi Zhang if (memcmp(&a->l2tpv3_data, &b->l2tpv3_data, sizeof(a->l2tpv3_data)))
1158213528feSQi Zhang return false;
1159213528feSQi Zhang if (memcmp(&a->l2tpv3_mask, &b->l2tpv3_mask, sizeof(a->l2tpv3_mask)))
1160213528feSQi Zhang return false;
11611f7ea1cdSQi Zhang if (memcmp(&a->ext_data, &b->ext_data, sizeof(a->ext_data)))
11621f7ea1cdSQi Zhang return false;
11631f7ea1cdSQi Zhang if (memcmp(&a->ext_mask, &b->ext_mask, sizeof(a->ext_mask)))
11641f7ea1cdSQi Zhang return false;
11651f7ea1cdSQi Zhang
11661f7ea1cdSQi Zhang return true;
11671f7ea1cdSQi Zhang }
11681f7ea1cdSQi Zhang
11691f7ea1cdSQi Zhang /**
11701f7ea1cdSQi Zhang * ice_vc_fdir_is_dup_fltr
11711f7ea1cdSQi Zhang * @vf: pointer to the VF info
11721f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter
11731f7ea1cdSQi Zhang *
11741f7ea1cdSQi Zhang * Check if there is duplicated rule with same conf value
11751f7ea1cdSQi Zhang *
11761f7ea1cdSQi Zhang * Return: 0 true success, and false on error.
11771f7ea1cdSQi Zhang */
11781f7ea1cdSQi Zhang static bool
ice_vc_fdir_is_dup_fltr(struct ice_vf * vf,struct virtchnl_fdir_fltr_conf * conf)11791f7ea1cdSQi Zhang ice_vc_fdir_is_dup_fltr(struct ice_vf *vf, struct virtchnl_fdir_fltr_conf *conf)
11801f7ea1cdSQi Zhang {
11811f7ea1cdSQi Zhang struct ice_fdir_fltr *desc;
11821f7ea1cdSQi Zhang bool ret;
11831f7ea1cdSQi Zhang
11841f7ea1cdSQi Zhang list_for_each_entry(desc, &vf->fdir.fdir_rule_list, fltr_node) {
11851f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *node =
11861f7ea1cdSQi Zhang to_fltr_conf_from_desc(desc);
11871f7ea1cdSQi Zhang
11881f7ea1cdSQi Zhang ret = ice_vc_fdir_comp_rules(node, conf);
11891f7ea1cdSQi Zhang if (ret)
11901f7ea1cdSQi Zhang return true;
11911f7ea1cdSQi Zhang }
11921f7ea1cdSQi Zhang
11931f7ea1cdSQi Zhang return false;
11941f7ea1cdSQi Zhang }
11951f7ea1cdSQi Zhang
11961f7ea1cdSQi Zhang /**
11971f7ea1cdSQi Zhang * ice_vc_fdir_insert_entry
11981f7ea1cdSQi Zhang * @vf: pointer to the VF info
11991f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter
12001f7ea1cdSQi Zhang * @id: pointer to ID value allocated by driver
12011f7ea1cdSQi Zhang *
12021f7ea1cdSQi Zhang * Insert FDIR conf entry into list and allocate ID for this filter
12031f7ea1cdSQi Zhang *
12041f7ea1cdSQi Zhang * Return: 0 true success, and other on error.
12051f7ea1cdSQi Zhang */
12061f7ea1cdSQi Zhang static int
ice_vc_fdir_insert_entry(struct ice_vf * vf,struct virtchnl_fdir_fltr_conf * conf,u32 * id)12071f7ea1cdSQi Zhang ice_vc_fdir_insert_entry(struct ice_vf *vf,
12081f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf, u32 *id)
12091f7ea1cdSQi Zhang {
12101f7ea1cdSQi Zhang struct ice_fdir_fltr *input = &conf->input;
12111f7ea1cdSQi Zhang int i;
12121f7ea1cdSQi Zhang
12131f7ea1cdSQi Zhang /* alloc ID corresponding with conf */
12141f7ea1cdSQi Zhang i = idr_alloc(&vf->fdir.fdir_rule_idr, conf, 0,
12151f7ea1cdSQi Zhang ICE_FDIR_MAX_FLTRS, GFP_KERNEL);
12161f7ea1cdSQi Zhang if (i < 0)
12171f7ea1cdSQi Zhang return -EINVAL;
12181f7ea1cdSQi Zhang *id = i;
12191f7ea1cdSQi Zhang
12201f7ea1cdSQi Zhang list_add(&input->fltr_node, &vf->fdir.fdir_rule_list);
12211f7ea1cdSQi Zhang return 0;
12221f7ea1cdSQi Zhang }
12231f7ea1cdSQi Zhang
12241f7ea1cdSQi Zhang /**
12251f7ea1cdSQi Zhang * ice_vc_fdir_remove_entry - remove FDIR conf entry by ID value
12261f7ea1cdSQi Zhang * @vf: pointer to the VF info
12271f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter
12281f7ea1cdSQi Zhang * @id: filter rule's ID
12291f7ea1cdSQi Zhang */
12301f7ea1cdSQi Zhang static void
ice_vc_fdir_remove_entry(struct ice_vf * vf,struct virtchnl_fdir_fltr_conf * conf,u32 id)12311f7ea1cdSQi Zhang ice_vc_fdir_remove_entry(struct ice_vf *vf,
12321f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf, u32 id)
12331f7ea1cdSQi Zhang {
12341f7ea1cdSQi Zhang struct ice_fdir_fltr *input = &conf->input;
12351f7ea1cdSQi Zhang
12361f7ea1cdSQi Zhang idr_remove(&vf->fdir.fdir_rule_idr, id);
12371f7ea1cdSQi Zhang list_del(&input->fltr_node);
12381f7ea1cdSQi Zhang }
12391f7ea1cdSQi Zhang
12401f7ea1cdSQi Zhang /**
12411f7ea1cdSQi Zhang * ice_vc_fdir_lookup_entry - lookup FDIR conf entry by ID value
12421f7ea1cdSQi Zhang * @vf: pointer to the VF info
12431f7ea1cdSQi Zhang * @id: filter rule's ID
12441f7ea1cdSQi Zhang *
12451f7ea1cdSQi Zhang * Return: NULL on error, and other on success.
12461f7ea1cdSQi Zhang */
12471f7ea1cdSQi Zhang static struct virtchnl_fdir_fltr_conf *
ice_vc_fdir_lookup_entry(struct ice_vf * vf,u32 id)12481f7ea1cdSQi Zhang ice_vc_fdir_lookup_entry(struct ice_vf *vf, u32 id)
12491f7ea1cdSQi Zhang {
12501f7ea1cdSQi Zhang return idr_find(&vf->fdir.fdir_rule_idr, id);
12511f7ea1cdSQi Zhang }
12521f7ea1cdSQi Zhang
12531f7ea1cdSQi Zhang /**
12541f7ea1cdSQi Zhang * ice_vc_fdir_flush_entry - remove all FDIR conf entry
12551f7ea1cdSQi Zhang * @vf: pointer to the VF info
12561f7ea1cdSQi Zhang */
ice_vc_fdir_flush_entry(struct ice_vf * vf)12571f7ea1cdSQi Zhang static void ice_vc_fdir_flush_entry(struct ice_vf *vf)
12581f7ea1cdSQi Zhang {
12591f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf;
12601f7ea1cdSQi Zhang struct ice_fdir_fltr *desc, *temp;
12611f7ea1cdSQi Zhang
12621f7ea1cdSQi Zhang list_for_each_entry_safe(desc, temp,
12631f7ea1cdSQi Zhang &vf->fdir.fdir_rule_list, fltr_node) {
12641f7ea1cdSQi Zhang conf = to_fltr_conf_from_desc(desc);
12651f7ea1cdSQi Zhang list_del(&desc->fltr_node);
12661f7ea1cdSQi Zhang devm_kfree(ice_pf_to_dev(vf->pf), conf);
12671f7ea1cdSQi Zhang }
12681f7ea1cdSQi Zhang }
12691f7ea1cdSQi Zhang
12701f7ea1cdSQi Zhang /**
12711f7ea1cdSQi Zhang * ice_vc_fdir_write_fltr - write filter rule into hardware
12721f7ea1cdSQi Zhang * @vf: pointer to the VF info
12731f7ea1cdSQi Zhang * @conf: FDIR configuration for each filter
12741f7ea1cdSQi Zhang * @add: true implies add rule, false implies del rules
12751f7ea1cdSQi Zhang * @is_tun: false implies non-tunnel type filter, true implies tunnel filter
12761f7ea1cdSQi Zhang *
12771f7ea1cdSQi Zhang * Return: 0 on success, and other on error.
12781f7ea1cdSQi Zhang */
ice_vc_fdir_write_fltr(struct ice_vf * vf,struct virtchnl_fdir_fltr_conf * conf,bool add,bool is_tun)12791f7ea1cdSQi Zhang static int ice_vc_fdir_write_fltr(struct ice_vf *vf,
12801f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf,
12811f7ea1cdSQi Zhang bool add, bool is_tun)
12821f7ea1cdSQi Zhang {
12831f7ea1cdSQi Zhang struct ice_fdir_fltr *input = &conf->input;
12841f7ea1cdSQi Zhang struct ice_vsi *vsi, *ctrl_vsi;
12851f7ea1cdSQi Zhang struct ice_fltr_desc desc;
12861f7ea1cdSQi Zhang struct device *dev;
12871f7ea1cdSQi Zhang struct ice_pf *pf;
12881f7ea1cdSQi Zhang struct ice_hw *hw;
12891f7ea1cdSQi Zhang int ret;
12901f7ea1cdSQi Zhang u8 *pkt;
12911f7ea1cdSQi Zhang
12921f7ea1cdSQi Zhang pf = vf->pf;
12931f7ea1cdSQi Zhang dev = ice_pf_to_dev(pf);
12941f7ea1cdSQi Zhang hw = &pf->hw;
1295772dec64SBrett Creeley vsi = ice_get_vf_vsi(vf);
12961f7ea1cdSQi Zhang if (!vsi) {
12971f7ea1cdSQi Zhang dev_dbg(dev, "Invalid vsi for VF %d\n", vf->vf_id);
12981f7ea1cdSQi Zhang return -EINVAL;
12991f7ea1cdSQi Zhang }
13001f7ea1cdSQi Zhang
13011f7ea1cdSQi Zhang input->dest_vsi = vsi->idx;
1302d6218317SQi Zhang input->comp_report = ICE_FXD_FLTR_QW0_COMP_REPORT_SW;
13031f7ea1cdSQi Zhang
13041f7ea1cdSQi Zhang ctrl_vsi = pf->vsi[vf->ctrl_vsi_idx];
13051f7ea1cdSQi Zhang if (!ctrl_vsi) {
13061f7ea1cdSQi Zhang dev_dbg(dev, "Invalid ctrl_vsi for VF %d\n", vf->vf_id);
13071f7ea1cdSQi Zhang return -EINVAL;
13081f7ea1cdSQi Zhang }
13091f7ea1cdSQi Zhang
13101f7ea1cdSQi Zhang pkt = devm_kzalloc(dev, ICE_FDIR_MAX_RAW_PKT_SIZE, GFP_KERNEL);
13111f7ea1cdSQi Zhang if (!pkt)
13121f7ea1cdSQi Zhang return -ENOMEM;
13131f7ea1cdSQi Zhang
13141f7ea1cdSQi Zhang ice_fdir_get_prgm_desc(hw, input, &desc, add);
13152ccc1c1cSTony Nguyen ret = ice_fdir_get_gen_prgm_pkt(hw, input, pkt, false, is_tun);
13161f7ea1cdSQi Zhang if (ret) {
13171f7ea1cdSQi Zhang dev_dbg(dev, "Gen training pkt for VF %d ptype %d failed\n",
13181f7ea1cdSQi Zhang vf->vf_id, input->flow_type);
13191f7ea1cdSQi Zhang goto err_free_pkt;
13201f7ea1cdSQi Zhang }
13211f7ea1cdSQi Zhang
13221f7ea1cdSQi Zhang ret = ice_prgm_fdir_fltr(ctrl_vsi, &desc, pkt);
13231f7ea1cdSQi Zhang if (ret)
13241f7ea1cdSQi Zhang goto err_free_pkt;
13251f7ea1cdSQi Zhang
13261f7ea1cdSQi Zhang return 0;
13271f7ea1cdSQi Zhang
13281f7ea1cdSQi Zhang err_free_pkt:
13291f7ea1cdSQi Zhang devm_kfree(dev, pkt);
13301f7ea1cdSQi Zhang return ret;
13311f7ea1cdSQi Zhang }
13321f7ea1cdSQi Zhang
13331f7ea1cdSQi Zhang /**
1334d6218317SQi Zhang * ice_vf_fdir_timer - FDIR program waiting timer interrupt handler
1335d6218317SQi Zhang * @t: pointer to timer_list
1336d6218317SQi Zhang */
ice_vf_fdir_timer(struct timer_list * t)1337d6218317SQi Zhang static void ice_vf_fdir_timer(struct timer_list *t)
1338d6218317SQi Zhang {
1339d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx_irq = from_timer(ctx_irq, t, rx_tmr);
1340d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx_done;
1341d6218317SQi Zhang struct ice_vf_fdir *fdir;
1342d6218317SQi Zhang unsigned long flags;
1343d6218317SQi Zhang struct ice_vf *vf;
1344d6218317SQi Zhang struct ice_pf *pf;
1345d6218317SQi Zhang
1346d6218317SQi Zhang fdir = container_of(ctx_irq, struct ice_vf_fdir, ctx_irq);
1347d6218317SQi Zhang vf = container_of(fdir, struct ice_vf, fdir);
1348d6218317SQi Zhang ctx_done = &fdir->ctx_done;
1349d6218317SQi Zhang pf = vf->pf;
1350d6218317SQi Zhang spin_lock_irqsave(&fdir->ctx_lock, flags);
1351d6218317SQi Zhang if (!(ctx_irq->flags & ICE_VF_FDIR_CTX_VALID)) {
1352d6218317SQi Zhang spin_unlock_irqrestore(&fdir->ctx_lock, flags);
1353d6218317SQi Zhang WARN_ON_ONCE(1);
1354d6218317SQi Zhang return;
1355d6218317SQi Zhang }
1356d6218317SQi Zhang
1357d6218317SQi Zhang ctx_irq->flags &= ~ICE_VF_FDIR_CTX_VALID;
1358d6218317SQi Zhang
1359d6218317SQi Zhang ctx_done->flags |= ICE_VF_FDIR_CTX_VALID;
1360d6218317SQi Zhang ctx_done->conf = ctx_irq->conf;
1361d6218317SQi Zhang ctx_done->stat = ICE_FDIR_CTX_TIMEOUT;
1362d6218317SQi Zhang ctx_done->v_opcode = ctx_irq->v_opcode;
1363d6218317SQi Zhang spin_unlock_irqrestore(&fdir->ctx_lock, flags);
1364d6218317SQi Zhang
13657e408e07SAnirudh Venkataramanan set_bit(ICE_FD_VF_FLUSH_CTX, pf->state);
1366d6218317SQi Zhang ice_service_task_schedule(pf);
1367d6218317SQi Zhang }
1368d6218317SQi Zhang
1369d6218317SQi Zhang /**
1370d6218317SQi Zhang * ice_vc_fdir_irq_handler - ctrl_vsi Rx queue interrupt handler
1371d6218317SQi Zhang * @ctrl_vsi: pointer to a VF's CTRL VSI
1372d6218317SQi Zhang * @rx_desc: pointer to FDIR Rx queue descriptor
1373d6218317SQi Zhang */
1374d6218317SQi Zhang void
ice_vc_fdir_irq_handler(struct ice_vsi * ctrl_vsi,union ice_32b_rx_flex_desc * rx_desc)1375d6218317SQi Zhang ice_vc_fdir_irq_handler(struct ice_vsi *ctrl_vsi,
1376d6218317SQi Zhang union ice_32b_rx_flex_desc *rx_desc)
1377d6218317SQi Zhang {
1378d6218317SQi Zhang struct ice_pf *pf = ctrl_vsi->back;
1379b03d519dSJacob Keller struct ice_vf *vf = ctrl_vsi->vf;
1380d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx_done;
1381d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx_irq;
1382d6218317SQi Zhang struct ice_vf_fdir *fdir;
1383d6218317SQi Zhang unsigned long flags;
1384d6218317SQi Zhang struct device *dev;
1385d6218317SQi Zhang int ret;
1386d6218317SQi Zhang
1387b03d519dSJacob Keller if (WARN_ON(!vf))
1388b03d519dSJacob Keller return;
1389d6218317SQi Zhang
1390d6218317SQi Zhang fdir = &vf->fdir;
1391d6218317SQi Zhang ctx_done = &fdir->ctx_done;
1392d6218317SQi Zhang ctx_irq = &fdir->ctx_irq;
1393d6218317SQi Zhang dev = ice_pf_to_dev(pf);
1394d6218317SQi Zhang spin_lock_irqsave(&fdir->ctx_lock, flags);
1395d6218317SQi Zhang if (!(ctx_irq->flags & ICE_VF_FDIR_CTX_VALID)) {
1396d6218317SQi Zhang spin_unlock_irqrestore(&fdir->ctx_lock, flags);
1397d6218317SQi Zhang WARN_ON_ONCE(1);
1398d6218317SQi Zhang return;
1399d6218317SQi Zhang }
1400d6218317SQi Zhang
1401d6218317SQi Zhang ctx_irq->flags &= ~ICE_VF_FDIR_CTX_VALID;
1402d6218317SQi Zhang
1403d6218317SQi Zhang ctx_done->flags |= ICE_VF_FDIR_CTX_VALID;
1404d6218317SQi Zhang ctx_done->conf = ctx_irq->conf;
1405d6218317SQi Zhang ctx_done->stat = ICE_FDIR_CTX_IRQ;
1406d6218317SQi Zhang ctx_done->v_opcode = ctx_irq->v_opcode;
1407d6218317SQi Zhang memcpy(&ctx_done->rx_desc, rx_desc, sizeof(*rx_desc));
1408d6218317SQi Zhang spin_unlock_irqrestore(&fdir->ctx_lock, flags);
1409d6218317SQi Zhang
1410d6218317SQi Zhang ret = del_timer(&ctx_irq->rx_tmr);
1411d6218317SQi Zhang if (!ret)
1412d6218317SQi Zhang dev_err(dev, "VF %d: Unexpected inactive timer!\n", vf->vf_id);
1413d6218317SQi Zhang
14147e408e07SAnirudh Venkataramanan set_bit(ICE_FD_VF_FLUSH_CTX, pf->state);
1415d6218317SQi Zhang ice_service_task_schedule(pf);
1416d6218317SQi Zhang }
1417d6218317SQi Zhang
1418d6218317SQi Zhang /**
1419d6218317SQi Zhang * ice_vf_fdir_dump_info - dump FDIR information for diagnosis
1420d6218317SQi Zhang * @vf: pointer to the VF info
1421d6218317SQi Zhang */
ice_vf_fdir_dump_info(struct ice_vf * vf)1422d6218317SQi Zhang static void ice_vf_fdir_dump_info(struct ice_vf *vf)
1423d6218317SQi Zhang {
1424*88f7ac6cSPaul Greenwalt u32 fd_size, fd_cnt, fd_size_g, fd_cnt_g, fd_size_b, fd_cnt_b;
1425d6218317SQi Zhang struct ice_vsi *vf_vsi;
1426d6218317SQi Zhang struct device *dev;
1427d6218317SQi Zhang struct ice_pf *pf;
1428d6218317SQi Zhang struct ice_hw *hw;
1429d6218317SQi Zhang u16 vsi_num;
1430d6218317SQi Zhang
1431d6218317SQi Zhang pf = vf->pf;
1432d6218317SQi Zhang hw = &pf->hw;
1433d6218317SQi Zhang dev = ice_pf_to_dev(pf);
1434baeb705fSJacob Keller vf_vsi = ice_get_vf_vsi(vf);
1435baeb705fSJacob Keller if (!vf_vsi) {
1436baeb705fSJacob Keller dev_dbg(dev, "VF %d: invalid VSI pointer\n", vf->vf_id);
1437baeb705fSJacob Keller return;
1438baeb705fSJacob Keller }
1439baeb705fSJacob Keller
1440d6218317SQi Zhang vsi_num = ice_get_hw_vsi_num(hw, vf_vsi->idx);
1441d6218317SQi Zhang
1442d6218317SQi Zhang fd_size = rd32(hw, VSIQF_FD_SIZE(vsi_num));
1443d6218317SQi Zhang fd_cnt = rd32(hw, VSIQF_FD_CNT(vsi_num));
1444*88f7ac6cSPaul Greenwalt switch (hw->mac_type) {
1445*88f7ac6cSPaul Greenwalt case ICE_MAC_E830:
1446*88f7ac6cSPaul Greenwalt fd_size_g = FIELD_GET(E830_VSIQF_FD_CNT_FD_GCNT_M, fd_size);
1447*88f7ac6cSPaul Greenwalt fd_size_b = FIELD_GET(E830_VSIQF_FD_CNT_FD_BCNT_M, fd_size);
1448*88f7ac6cSPaul Greenwalt fd_cnt_g = FIELD_GET(E830_VSIQF_FD_CNT_FD_GCNT_M, fd_cnt);
1449*88f7ac6cSPaul Greenwalt fd_cnt_b = FIELD_GET(E830_VSIQF_FD_CNT_FD_BCNT_M, fd_cnt);
1450*88f7ac6cSPaul Greenwalt break;
1451*88f7ac6cSPaul Greenwalt case ICE_MAC_E810:
1452*88f7ac6cSPaul Greenwalt default:
1453*88f7ac6cSPaul Greenwalt fd_size_g = FIELD_GET(E800_VSIQF_FD_CNT_FD_GCNT_M, fd_size);
1454*88f7ac6cSPaul Greenwalt fd_size_b = FIELD_GET(E800_VSIQF_FD_CNT_FD_BCNT_M, fd_size);
1455*88f7ac6cSPaul Greenwalt fd_cnt_g = FIELD_GET(E800_VSIQF_FD_CNT_FD_GCNT_M, fd_cnt);
1456*88f7ac6cSPaul Greenwalt fd_cnt_b = FIELD_GET(E800_VSIQF_FD_CNT_FD_BCNT_M, fd_cnt);
1457*88f7ac6cSPaul Greenwalt }
1458*88f7ac6cSPaul Greenwalt
1459*88f7ac6cSPaul Greenwalt dev_dbg(dev, "VF %d: Size in the FD table: guaranteed:0x%x, best effort:0x%x\n",
1460*88f7ac6cSPaul Greenwalt vf->vf_id, fd_size_g, fd_size_b);
1461*88f7ac6cSPaul Greenwalt dev_dbg(dev, "VF %d: Filter counter in the FD table: guaranteed:0x%x, best effort:0x%x\n",
1462*88f7ac6cSPaul Greenwalt vf->vf_id, fd_cnt_g, fd_cnt_b);
1463d6218317SQi Zhang }
1464d6218317SQi Zhang
1465d6218317SQi Zhang /**
1466d6218317SQi Zhang * ice_vf_verify_rx_desc - verify received FDIR programming status descriptor
1467d6218317SQi Zhang * @vf: pointer to the VF info
1468d6218317SQi Zhang * @ctx: FDIR context info for post processing
1469d6218317SQi Zhang * @status: virtchnl FDIR program status
1470d6218317SQi Zhang *
1471d6218317SQi Zhang * Return: 0 on success, and other on error.
1472d6218317SQi Zhang */
1473d6218317SQi Zhang static int
ice_vf_verify_rx_desc(struct ice_vf * vf,struct ice_vf_fdir_ctx * ctx,enum virtchnl_fdir_prgm_status * status)1474d6218317SQi Zhang ice_vf_verify_rx_desc(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx,
1475d6218317SQi Zhang enum virtchnl_fdir_prgm_status *status)
1476d6218317SQi Zhang {
1477d6218317SQi Zhang struct device *dev = ice_pf_to_dev(vf->pf);
1478d6218317SQi Zhang u32 stat_err, error, prog_id;
1479d6218317SQi Zhang int ret;
1480d6218317SQi Zhang
1481d6218317SQi Zhang stat_err = le16_to_cpu(ctx->rx_desc.wb.status_error0);
1482d6218317SQi Zhang if (((stat_err & ICE_FXD_FLTR_WB_QW1_DD_M) >>
1483d6218317SQi Zhang ICE_FXD_FLTR_WB_QW1_DD_S) != ICE_FXD_FLTR_WB_QW1_DD_YES) {
1484d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
1485d6218317SQi Zhang dev_err(dev, "VF %d: Desc Done not set\n", vf->vf_id);
1486d6218317SQi Zhang ret = -EINVAL;
1487d6218317SQi Zhang goto err_exit;
1488d6218317SQi Zhang }
1489d6218317SQi Zhang
1490d6218317SQi Zhang prog_id = (stat_err & ICE_FXD_FLTR_WB_QW1_PROG_ID_M) >>
1491d6218317SQi Zhang ICE_FXD_FLTR_WB_QW1_PROG_ID_S;
1492d6218317SQi Zhang if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_ADD &&
1493d6218317SQi Zhang ctx->v_opcode != VIRTCHNL_OP_ADD_FDIR_FILTER) {
1494d6218317SQi Zhang dev_err(dev, "VF %d: Desc show add, but ctx not",
1495d6218317SQi Zhang vf->vf_id);
1496d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID;
1497d6218317SQi Zhang ret = -EINVAL;
1498d6218317SQi Zhang goto err_exit;
1499d6218317SQi Zhang }
1500d6218317SQi Zhang
1501d6218317SQi Zhang if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_DEL &&
1502d6218317SQi Zhang ctx->v_opcode != VIRTCHNL_OP_DEL_FDIR_FILTER) {
1503d6218317SQi Zhang dev_err(dev, "VF %d: Desc show del, but ctx not",
1504d6218317SQi Zhang vf->vf_id);
1505d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID;
1506d6218317SQi Zhang ret = -EINVAL;
1507d6218317SQi Zhang goto err_exit;
1508d6218317SQi Zhang }
1509d6218317SQi Zhang
1510d6218317SQi Zhang error = (stat_err & ICE_FXD_FLTR_WB_QW1_FAIL_M) >>
1511d6218317SQi Zhang ICE_FXD_FLTR_WB_QW1_FAIL_S;
1512d6218317SQi Zhang if (error == ICE_FXD_FLTR_WB_QW1_FAIL_YES) {
1513d6218317SQi Zhang if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_ADD) {
1514d6218317SQi Zhang dev_err(dev, "VF %d, Failed to add FDIR rule due to no space in the table",
1515d6218317SQi Zhang vf->vf_id);
1516d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
1517d6218317SQi Zhang } else {
1518d6218317SQi Zhang dev_err(dev, "VF %d, Failed to remove FDIR rule, attempt to remove non-existent entry",
1519d6218317SQi Zhang vf->vf_id);
1520d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST;
1521d6218317SQi Zhang }
1522d6218317SQi Zhang ret = -EINVAL;
1523d6218317SQi Zhang goto err_exit;
1524d6218317SQi Zhang }
1525d6218317SQi Zhang
1526d6218317SQi Zhang error = (stat_err & ICE_FXD_FLTR_WB_QW1_FAIL_PROF_M) >>
1527d6218317SQi Zhang ICE_FXD_FLTR_WB_QW1_FAIL_PROF_S;
1528d6218317SQi Zhang if (error == ICE_FXD_FLTR_WB_QW1_FAIL_PROF_YES) {
1529d6218317SQi Zhang dev_err(dev, "VF %d: Profile matching error", vf->vf_id);
1530d6218317SQi Zhang *status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
1531d6218317SQi Zhang ret = -EINVAL;
1532d6218317SQi Zhang goto err_exit;
1533d6218317SQi Zhang }
1534d6218317SQi Zhang
1535d6218317SQi Zhang *status = VIRTCHNL_FDIR_SUCCESS;
1536d6218317SQi Zhang
1537d6218317SQi Zhang return 0;
1538d6218317SQi Zhang
1539d6218317SQi Zhang err_exit:
1540d6218317SQi Zhang ice_vf_fdir_dump_info(vf);
1541d6218317SQi Zhang return ret;
1542d6218317SQi Zhang }
1543d6218317SQi Zhang
1544d6218317SQi Zhang /**
1545d6218317SQi Zhang * ice_vc_add_fdir_fltr_post
1546d6218317SQi Zhang * @vf: pointer to the VF structure
1547d6218317SQi Zhang * @ctx: FDIR context info for post processing
1548d6218317SQi Zhang * @status: virtchnl FDIR program status
1549d6218317SQi Zhang * @success: true implies success, false implies failure
1550d6218317SQi Zhang *
1551d6218317SQi Zhang * Post process for flow director add command. If success, then do post process
1552d6218317SQi Zhang * and send back success msg by virtchnl. Otherwise, do context reversion and
1553d6218317SQi Zhang * send back failure msg by virtchnl.
1554d6218317SQi Zhang *
1555d6218317SQi Zhang * Return: 0 on success, and other on error.
1556d6218317SQi Zhang */
1557d6218317SQi 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)1558d6218317SQi Zhang ice_vc_add_fdir_fltr_post(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx,
1559d6218317SQi Zhang enum virtchnl_fdir_prgm_status status,
1560d6218317SQi Zhang bool success)
1561d6218317SQi Zhang {
1562d6218317SQi Zhang struct virtchnl_fdir_fltr_conf *conf = ctx->conf;
1563d6218317SQi Zhang struct device *dev = ice_pf_to_dev(vf->pf);
1564d6218317SQi Zhang enum virtchnl_status_code v_ret;
1565d6218317SQi Zhang struct virtchnl_fdir_add *resp;
1566d6218317SQi Zhang int ret, len, is_tun;
1567d6218317SQi Zhang
1568d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS;
1569d6218317SQi Zhang len = sizeof(*resp);
1570d6218317SQi Zhang resp = kzalloc(len, GFP_KERNEL);
1571d6218317SQi Zhang if (!resp) {
1572d6218317SQi Zhang len = 0;
1573d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
1574d6218317SQi Zhang dev_dbg(dev, "VF %d: Alloc resp buf fail", vf->vf_id);
1575d6218317SQi Zhang goto err_exit;
1576d6218317SQi Zhang }
1577d6218317SQi Zhang
1578d6218317SQi Zhang if (!success)
1579d6218317SQi Zhang goto err_exit;
1580d6218317SQi Zhang
1581d6218317SQi Zhang is_tun = 0;
1582d6218317SQi Zhang resp->status = status;
1583d6218317SQi Zhang resp->flow_id = conf->flow_id;
1584d6218317SQi Zhang vf->fdir.fdir_fltr_cnt[conf->input.flow_type][is_tun]++;
1585d6238907SAhmed Zaki vf->fdir.fdir_fltr_cnt_total++;
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
1591d6218317SQi Zhang dev_dbg(dev, "VF %d: flow_id:0x%X, FDIR %s success!\n",
1592d6218317SQi Zhang vf->vf_id, conf->flow_id,
1593d6218317SQi Zhang (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) ?
1594d6218317SQi Zhang "add" : "del");
1595d6218317SQi Zhang return ret;
1596d6218317SQi Zhang
1597d6218317SQi Zhang err_exit:
1598d6218317SQi Zhang if (resp)
1599d6218317SQi Zhang resp->status = status;
1600d6218317SQi Zhang ice_vc_fdir_remove_entry(vf, conf, conf->flow_id);
1601d6218317SQi Zhang devm_kfree(dev, conf);
1602d6218317SQi Zhang
1603d6218317SQi Zhang ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret,
1604d6218317SQi Zhang (u8 *)resp, len);
1605d6218317SQi Zhang kfree(resp);
1606d6218317SQi Zhang return ret;
1607d6218317SQi Zhang }
1608d6218317SQi Zhang
1609d6218317SQi Zhang /**
1610d6218317SQi Zhang * ice_vc_del_fdir_fltr_post
1611d6218317SQi Zhang * @vf: pointer to the VF structure
1612d6218317SQi Zhang * @ctx: FDIR context info for post processing
1613d6218317SQi Zhang * @status: virtchnl FDIR program status
1614d6218317SQi Zhang * @success: true implies success, false implies failure
1615d6218317SQi Zhang *
1616d6218317SQi Zhang * Post process for flow director del command. If success, then do post process
1617d6218317SQi Zhang * and send back success msg by virtchnl. Otherwise, do context reversion and
1618d6218317SQi Zhang * send back failure msg by virtchnl.
1619d6218317SQi Zhang *
1620d6218317SQi Zhang * Return: 0 on success, and other on error.
1621d6218317SQi Zhang */
1622d6218317SQi 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)1623d6218317SQi Zhang ice_vc_del_fdir_fltr_post(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx,
1624d6218317SQi Zhang enum virtchnl_fdir_prgm_status status,
1625d6218317SQi Zhang bool success)
1626d6218317SQi Zhang {
1627d6218317SQi Zhang struct virtchnl_fdir_fltr_conf *conf = ctx->conf;
1628d6218317SQi Zhang struct device *dev = ice_pf_to_dev(vf->pf);
1629d6218317SQi Zhang enum virtchnl_status_code v_ret;
1630d6218317SQi Zhang struct virtchnl_fdir_del *resp;
1631d6218317SQi Zhang int ret, len, is_tun;
1632d6218317SQi Zhang
1633d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS;
1634d6218317SQi Zhang len = sizeof(*resp);
1635d6218317SQi Zhang resp = kzalloc(len, GFP_KERNEL);
1636d6218317SQi Zhang if (!resp) {
1637d6218317SQi Zhang len = 0;
1638d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
1639d6218317SQi Zhang dev_dbg(dev, "VF %d: Alloc resp buf fail", vf->vf_id);
1640d6218317SQi Zhang goto err_exit;
1641d6218317SQi Zhang }
1642d6218317SQi Zhang
1643d6218317SQi Zhang if (!success)
1644d6218317SQi Zhang goto err_exit;
1645d6218317SQi Zhang
1646d6218317SQi Zhang is_tun = 0;
1647d6218317SQi Zhang resp->status = status;
1648d6218317SQi Zhang ice_vc_fdir_remove_entry(vf, conf, conf->flow_id);
1649d6218317SQi Zhang vf->fdir.fdir_fltr_cnt[conf->input.flow_type][is_tun]--;
1650d6238907SAhmed Zaki vf->fdir.fdir_fltr_cnt_total--;
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
1656d6218317SQi Zhang dev_dbg(dev, "VF %d: flow_id:0x%X, FDIR %s success!\n",
1657d6218317SQi Zhang vf->vf_id, conf->flow_id,
1658d6218317SQi Zhang (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) ?
1659d6218317SQi Zhang "add" : "del");
1660d6218317SQi Zhang devm_kfree(dev, conf);
1661d6218317SQi Zhang return ret;
1662d6218317SQi Zhang
1663d6218317SQi Zhang err_exit:
1664d6218317SQi Zhang if (resp)
1665d6218317SQi Zhang resp->status = status;
1666d6218317SQi Zhang if (success)
1667d6218317SQi Zhang devm_kfree(dev, conf);
1668d6218317SQi Zhang
1669d6218317SQi Zhang ret = ice_vc_send_msg_to_vf(vf, ctx->v_opcode, v_ret,
1670d6218317SQi Zhang (u8 *)resp, len);
1671d6218317SQi Zhang kfree(resp);
1672d6218317SQi Zhang return ret;
1673d6218317SQi Zhang }
1674d6218317SQi Zhang
1675d6218317SQi Zhang /**
1676d6218317SQi Zhang * ice_flush_fdir_ctx
1677d6218317SQi Zhang * @pf: pointer to the PF structure
1678d6218317SQi Zhang *
1679d6218317SQi Zhang * Flush all the pending event on ctx_done list and process them.
1680d6218317SQi Zhang */
ice_flush_fdir_ctx(struct ice_pf * pf)1681d6218317SQi Zhang void ice_flush_fdir_ctx(struct ice_pf *pf)
1682d6218317SQi Zhang {
1683c4c2c7dbSJacob Keller struct ice_vf *vf;
1684c4c2c7dbSJacob Keller unsigned int bkt;
1685d6218317SQi Zhang
16867e408e07SAnirudh Venkataramanan if (!test_and_clear_bit(ICE_FD_VF_FLUSH_CTX, pf->state))
1687d6218317SQi Zhang return;
1688d6218317SQi Zhang
16893d5985a1SJacob Keller mutex_lock(&pf->vfs.table_lock);
1690c4c2c7dbSJacob Keller ice_for_each_vf(pf, bkt, vf) {
1691d6218317SQi Zhang struct device *dev = ice_pf_to_dev(pf);
1692d6218317SQi Zhang enum virtchnl_fdir_prgm_status status;
1693d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx;
1694d6218317SQi Zhang unsigned long flags;
1695d6218317SQi Zhang int ret;
1696d6218317SQi Zhang
1697d6218317SQi Zhang if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states))
1698d6218317SQi Zhang continue;
1699d6218317SQi Zhang
1700d6218317SQi Zhang if (vf->ctrl_vsi_idx == ICE_NO_VSI)
1701d6218317SQi Zhang continue;
1702d6218317SQi Zhang
1703d6218317SQi Zhang ctx = &vf->fdir.ctx_done;
1704d6218317SQi Zhang spin_lock_irqsave(&vf->fdir.ctx_lock, flags);
1705d6218317SQi Zhang if (!(ctx->flags & ICE_VF_FDIR_CTX_VALID)) {
1706d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1707d6218317SQi Zhang continue;
1708d6218317SQi Zhang }
1709d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1710d6218317SQi Zhang
1711d6218317SQi Zhang WARN_ON(ctx->stat == ICE_FDIR_CTX_READY);
1712d6218317SQi Zhang if (ctx->stat == ICE_FDIR_CTX_TIMEOUT) {
1713d6218317SQi Zhang status = VIRTCHNL_FDIR_FAILURE_RULE_TIMEOUT;
1714d6218317SQi Zhang dev_err(dev, "VF %d: ctrl_vsi irq timeout\n",
1715d6218317SQi Zhang vf->vf_id);
1716d6218317SQi Zhang goto err_exit;
1717d6218317SQi Zhang }
1718d6218317SQi Zhang
1719d6218317SQi Zhang ret = ice_vf_verify_rx_desc(vf, ctx, &status);
1720d6218317SQi Zhang if (ret)
1721d6218317SQi Zhang goto err_exit;
1722d6218317SQi Zhang
1723d6218317SQi Zhang if (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER)
1724d6218317SQi Zhang ice_vc_add_fdir_fltr_post(vf, ctx, status, true);
1725d6218317SQi Zhang else if (ctx->v_opcode == VIRTCHNL_OP_DEL_FDIR_FILTER)
1726d6218317SQi Zhang ice_vc_del_fdir_fltr_post(vf, ctx, status, true);
1727d6218317SQi Zhang else
1728d6218317SQi Zhang dev_err(dev, "VF %d: Unsupported opcode\n", vf->vf_id);
1729d6218317SQi Zhang
1730d6218317SQi Zhang spin_lock_irqsave(&vf->fdir.ctx_lock, flags);
1731d6218317SQi Zhang ctx->flags &= ~ICE_VF_FDIR_CTX_VALID;
1732d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1733d6218317SQi Zhang continue;
1734d6218317SQi Zhang err_exit:
1735d6218317SQi Zhang if (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER)
1736d6218317SQi Zhang ice_vc_add_fdir_fltr_post(vf, ctx, status, false);
1737d6218317SQi Zhang else if (ctx->v_opcode == VIRTCHNL_OP_DEL_FDIR_FILTER)
1738d6218317SQi Zhang ice_vc_del_fdir_fltr_post(vf, ctx, status, false);
1739d6218317SQi Zhang else
1740d6218317SQi Zhang dev_err(dev, "VF %d: Unsupported opcode\n", vf->vf_id);
1741d6218317SQi Zhang
1742d6218317SQi Zhang spin_lock_irqsave(&vf->fdir.ctx_lock, flags);
1743d6218317SQi Zhang ctx->flags &= ~ICE_VF_FDIR_CTX_VALID;
1744d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1745d6218317SQi Zhang }
17463d5985a1SJacob Keller mutex_unlock(&pf->vfs.table_lock);
1747d6218317SQi Zhang }
1748d6218317SQi Zhang
1749d6218317SQi Zhang /**
1750d6218317SQi Zhang * ice_vc_fdir_set_irq_ctx - set FDIR context info for later IRQ handler
1751d6218317SQi Zhang * @vf: pointer to the VF structure
1752d6218317SQi Zhang * @conf: FDIR configuration for each filter
1753d6218317SQi Zhang * @v_opcode: virtual channel operation code
1754d6218317SQi Zhang *
1755d6218317SQi Zhang * Return: 0 on success, and other on error.
1756d6218317SQi Zhang */
1757d6218317SQi Zhang static int
ice_vc_fdir_set_irq_ctx(struct ice_vf * vf,struct virtchnl_fdir_fltr_conf * conf,enum virtchnl_ops v_opcode)1758d6218317SQi Zhang ice_vc_fdir_set_irq_ctx(struct ice_vf *vf, struct virtchnl_fdir_fltr_conf *conf,
1759d6218317SQi Zhang enum virtchnl_ops v_opcode)
1760d6218317SQi Zhang {
1761d6218317SQi Zhang struct device *dev = ice_pf_to_dev(vf->pf);
1762d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx;
1763d6218317SQi Zhang unsigned long flags;
1764d6218317SQi Zhang
1765d6218317SQi Zhang ctx = &vf->fdir.ctx_irq;
1766d6218317SQi Zhang spin_lock_irqsave(&vf->fdir.ctx_lock, flags);
1767d6218317SQi Zhang if ((vf->fdir.ctx_irq.flags & ICE_VF_FDIR_CTX_VALID) ||
1768d6218317SQi Zhang (vf->fdir.ctx_done.flags & ICE_VF_FDIR_CTX_VALID)) {
1769d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1770d6218317SQi Zhang dev_dbg(dev, "VF %d: Last request is still in progress\n",
1771d6218317SQi Zhang vf->vf_id);
1772d6218317SQi Zhang return -EBUSY;
1773d6218317SQi Zhang }
1774d6218317SQi Zhang ctx->flags |= ICE_VF_FDIR_CTX_VALID;
1775d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1776d6218317SQi Zhang
1777d6218317SQi Zhang ctx->conf = conf;
1778d6218317SQi Zhang ctx->v_opcode = v_opcode;
1779d6218317SQi Zhang ctx->stat = ICE_FDIR_CTX_READY;
1780d6218317SQi Zhang timer_setup(&ctx->rx_tmr, ice_vf_fdir_timer, 0);
1781d6218317SQi Zhang
1782d6218317SQi Zhang mod_timer(&ctx->rx_tmr, round_jiffies(msecs_to_jiffies(10) + jiffies));
1783d6218317SQi Zhang
1784d6218317SQi Zhang return 0;
1785d6218317SQi Zhang }
1786d6218317SQi Zhang
1787d6218317SQi Zhang /**
1788d6218317SQi Zhang * ice_vc_fdir_clear_irq_ctx - clear FDIR context info for IRQ handler
1789d6218317SQi Zhang * @vf: pointer to the VF structure
1790d6218317SQi Zhang *
1791d6218317SQi Zhang * Return: 0 on success, and other on error.
1792d6218317SQi Zhang */
ice_vc_fdir_clear_irq_ctx(struct ice_vf * vf)1793d6218317SQi Zhang static void ice_vc_fdir_clear_irq_ctx(struct ice_vf *vf)
1794d6218317SQi Zhang {
1795d6218317SQi Zhang struct ice_vf_fdir_ctx *ctx = &vf->fdir.ctx_irq;
1796d6218317SQi Zhang unsigned long flags;
1797d6218317SQi Zhang
1798d6218317SQi Zhang del_timer(&ctx->rx_tmr);
1799d6218317SQi Zhang spin_lock_irqsave(&vf->fdir.ctx_lock, flags);
1800d6218317SQi Zhang ctx->flags &= ~ICE_VF_FDIR_CTX_VALID;
1801d6218317SQi Zhang spin_unlock_irqrestore(&vf->fdir.ctx_lock, flags);
1802d6218317SQi Zhang }
1803d6218317SQi Zhang
1804d6218317SQi Zhang /**
18051f7ea1cdSQi Zhang * ice_vc_add_fdir_fltr - add a FDIR filter for VF by the msg buffer
18061f7ea1cdSQi Zhang * @vf: pointer to the VF info
18071f7ea1cdSQi Zhang * @msg: pointer to the msg buffer
18081f7ea1cdSQi Zhang *
18091f7ea1cdSQi Zhang * Return: 0 on success, and other on error.
18101f7ea1cdSQi Zhang */
ice_vc_add_fdir_fltr(struct ice_vf * vf,u8 * msg)18111f7ea1cdSQi Zhang int ice_vc_add_fdir_fltr(struct ice_vf *vf, u8 *msg)
18121f7ea1cdSQi Zhang {
18131f7ea1cdSQi Zhang struct virtchnl_fdir_add *fltr = (struct virtchnl_fdir_add *)msg;
18141f7ea1cdSQi Zhang struct virtchnl_fdir_add *stat = NULL;
18151f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf;
18161f7ea1cdSQi Zhang enum virtchnl_status_code v_ret;
1817d6238907SAhmed Zaki struct ice_vsi *vf_vsi;
18181f7ea1cdSQi Zhang struct device *dev;
18191f7ea1cdSQi Zhang struct ice_pf *pf;
18201f7ea1cdSQi Zhang int is_tun = 0;
18211f7ea1cdSQi Zhang int len = 0;
18221f7ea1cdSQi Zhang int ret;
18231f7ea1cdSQi Zhang
18241f7ea1cdSQi Zhang pf = vf->pf;
18251f7ea1cdSQi Zhang dev = ice_pf_to_dev(pf);
1826d6238907SAhmed Zaki vf_vsi = ice_get_vf_vsi(vf);
1827d6238907SAhmed Zaki
1828d6238907SAhmed Zaki #define ICE_VF_MAX_FDIR_FILTERS 128
1829d6238907SAhmed Zaki if (!ice_fdir_num_avail_fltr(&pf->hw, vf_vsi) ||
1830d6238907SAhmed Zaki vf->fdir.fdir_fltr_cnt_total >= ICE_VF_MAX_FDIR_FILTERS) {
1831d6238907SAhmed Zaki v_ret = VIRTCHNL_STATUS_ERR_PARAM;
1832d6238907SAhmed Zaki dev_err(dev, "Max number of FDIR filters for VF %d is reached\n",
1833d6238907SAhmed Zaki vf->vf_id);
1834d6238907SAhmed Zaki goto err_exit;
1835d6238907SAhmed Zaki }
1836d6238907SAhmed Zaki
18371f7ea1cdSQi Zhang ret = ice_vc_fdir_param_check(vf, fltr->vsi_id);
18381f7ea1cdSQi Zhang if (ret) {
18391f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_PARAM;
18401f7ea1cdSQi Zhang dev_dbg(dev, "Parameter check for VF %d failed\n", vf->vf_id);
18411f7ea1cdSQi Zhang goto err_exit;
18421f7ea1cdSQi Zhang }
18431f7ea1cdSQi Zhang
18441f7ea1cdSQi Zhang ret = ice_vf_start_ctrl_vsi(vf);
18451f7ea1cdSQi Zhang if (ret && (ret != -EEXIST)) {
18461f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_PARAM;
18471f7ea1cdSQi Zhang dev_err(dev, "Init FDIR for VF %d failed, ret:%d\n",
18481f7ea1cdSQi Zhang vf->vf_id, ret);
18491f7ea1cdSQi Zhang goto err_exit;
18501f7ea1cdSQi Zhang }
18511f7ea1cdSQi Zhang
18521f7ea1cdSQi Zhang stat = kzalloc(sizeof(*stat), GFP_KERNEL);
18531f7ea1cdSQi Zhang if (!stat) {
18541f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
18551f7ea1cdSQi Zhang dev_dbg(dev, "Alloc stat for VF %d failed\n", vf->vf_id);
18561f7ea1cdSQi Zhang goto err_exit;
18571f7ea1cdSQi Zhang }
18581f7ea1cdSQi Zhang
18591f7ea1cdSQi Zhang conf = devm_kzalloc(dev, sizeof(*conf), GFP_KERNEL);
18601f7ea1cdSQi Zhang if (!conf) {
18611f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
18621f7ea1cdSQi Zhang dev_dbg(dev, "Alloc conf for VF %d failed\n", vf->vf_id);
18631f7ea1cdSQi Zhang goto err_exit;
18641f7ea1cdSQi Zhang }
18651f7ea1cdSQi Zhang
18661f7ea1cdSQi Zhang len = sizeof(*stat);
18671f7ea1cdSQi Zhang ret = ice_vc_validate_fdir_fltr(vf, fltr, conf);
18681f7ea1cdSQi Zhang if (ret) {
18691f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS;
18701f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID;
18711f7ea1cdSQi Zhang dev_dbg(dev, "Invalid FDIR filter from VF %d\n", vf->vf_id);
18721f7ea1cdSQi Zhang goto err_free_conf;
18731f7ea1cdSQi Zhang }
18741f7ea1cdSQi Zhang
18751f7ea1cdSQi Zhang if (fltr->validate_only) {
18761f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS;
18771f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_SUCCESS;
18781f7ea1cdSQi Zhang devm_kfree(dev, conf);
18791f7ea1cdSQi Zhang ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_FDIR_FILTER,
18801f7ea1cdSQi Zhang v_ret, (u8 *)stat, len);
18811f7ea1cdSQi Zhang goto exit;
18821f7ea1cdSQi Zhang }
18831f7ea1cdSQi Zhang
18841f7ea1cdSQi Zhang ret = ice_vc_fdir_config_input_set(vf, fltr, conf, is_tun);
18851f7ea1cdSQi Zhang if (ret) {
18861f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS;
18871f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_CONFLICT;
18881f7ea1cdSQi Zhang dev_err(dev, "VF %d: FDIR input set configure failed, ret:%d\n",
18891f7ea1cdSQi Zhang vf->vf_id, ret);
18901f7ea1cdSQi Zhang goto err_free_conf;
18911f7ea1cdSQi Zhang }
18921f7ea1cdSQi Zhang
18931f7ea1cdSQi Zhang ret = ice_vc_fdir_is_dup_fltr(vf, conf);
18941f7ea1cdSQi Zhang if (ret) {
18951f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS;
18961f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_EXIST;
18971f7ea1cdSQi Zhang dev_dbg(dev, "VF %d: duplicated FDIR rule detected\n",
18981f7ea1cdSQi Zhang vf->vf_id);
18991f7ea1cdSQi Zhang goto err_free_conf;
19001f7ea1cdSQi Zhang }
19011f7ea1cdSQi Zhang
1902d6218317SQi Zhang ret = ice_vc_fdir_insert_entry(vf, conf, &conf->flow_id);
19031f7ea1cdSQi Zhang if (ret) {
19041f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS;
19051f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
19061f7ea1cdSQi Zhang dev_dbg(dev, "VF %d: insert FDIR list failed\n", vf->vf_id);
19071f7ea1cdSQi Zhang goto err_free_conf;
19081f7ea1cdSQi Zhang }
19091f7ea1cdSQi Zhang
1910d6218317SQi Zhang ret = ice_vc_fdir_set_irq_ctx(vf, conf, VIRTCHNL_OP_ADD_FDIR_FILTER);
1911d6218317SQi Zhang if (ret) {
1912d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS;
1913d6218317SQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
1914d6218317SQi Zhang dev_dbg(dev, "VF %d: set FDIR context failed\n", vf->vf_id);
1915b4a01aceSSimei Su goto err_rem_entry;
1916d6218317SQi Zhang }
1917d6218317SQi Zhang
19181f7ea1cdSQi Zhang ret = ice_vc_fdir_write_fltr(vf, conf, true, is_tun);
19191f7ea1cdSQi Zhang if (ret) {
19201f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS;
19211f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
19221f7ea1cdSQi Zhang dev_err(dev, "VF %d: writing FDIR rule failed, ret:%d\n",
19231f7ea1cdSQi Zhang vf->vf_id, ret);
1924b4a01aceSSimei Su goto err_clr_irq;
19251f7ea1cdSQi Zhang }
19261f7ea1cdSQi Zhang
19271f7ea1cdSQi Zhang exit:
19281f7ea1cdSQi Zhang kfree(stat);
19291f7ea1cdSQi Zhang return ret;
19301f7ea1cdSQi Zhang
1931b4a01aceSSimei Su err_clr_irq:
1932d6218317SQi Zhang ice_vc_fdir_clear_irq_ctx(vf);
1933b4a01aceSSimei Su err_rem_entry:
1934d6218317SQi Zhang ice_vc_fdir_remove_entry(vf, conf, conf->flow_id);
19351f7ea1cdSQi Zhang err_free_conf:
19361f7ea1cdSQi Zhang devm_kfree(dev, conf);
19371f7ea1cdSQi Zhang err_exit:
19381f7ea1cdSQi Zhang ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_ADD_FDIR_FILTER, v_ret,
19391f7ea1cdSQi Zhang (u8 *)stat, len);
19401f7ea1cdSQi Zhang kfree(stat);
19411f7ea1cdSQi Zhang return ret;
19421f7ea1cdSQi Zhang }
19431f7ea1cdSQi Zhang
19441f7ea1cdSQi Zhang /**
19451f7ea1cdSQi Zhang * ice_vc_del_fdir_fltr - delete a FDIR filter for VF by the msg buffer
19461f7ea1cdSQi Zhang * @vf: pointer to the VF info
19471f7ea1cdSQi Zhang * @msg: pointer to the msg buffer
19481f7ea1cdSQi Zhang *
19491f7ea1cdSQi Zhang * Return: 0 on success, and other on error.
19501f7ea1cdSQi Zhang */
ice_vc_del_fdir_fltr(struct ice_vf * vf,u8 * msg)19511f7ea1cdSQi Zhang int ice_vc_del_fdir_fltr(struct ice_vf *vf, u8 *msg)
19521f7ea1cdSQi Zhang {
19531f7ea1cdSQi Zhang struct virtchnl_fdir_del *fltr = (struct virtchnl_fdir_del *)msg;
19541f7ea1cdSQi Zhang struct virtchnl_fdir_del *stat = NULL;
19551f7ea1cdSQi Zhang struct virtchnl_fdir_fltr_conf *conf;
19561f7ea1cdSQi Zhang enum virtchnl_status_code v_ret;
19571f7ea1cdSQi Zhang struct device *dev;
19581f7ea1cdSQi Zhang struct ice_pf *pf;
19591f7ea1cdSQi Zhang int is_tun = 0;
19601f7ea1cdSQi Zhang int len = 0;
19611f7ea1cdSQi Zhang int ret;
19621f7ea1cdSQi Zhang
19631f7ea1cdSQi Zhang pf = vf->pf;
19641f7ea1cdSQi Zhang dev = ice_pf_to_dev(pf);
19651f7ea1cdSQi Zhang ret = ice_vc_fdir_param_check(vf, fltr->vsi_id);
19661f7ea1cdSQi Zhang if (ret) {
19671f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_PARAM;
19681f7ea1cdSQi Zhang dev_dbg(dev, "Parameter check for VF %d failed\n", vf->vf_id);
19691f7ea1cdSQi Zhang goto err_exit;
19701f7ea1cdSQi Zhang }
19711f7ea1cdSQi Zhang
19721f7ea1cdSQi Zhang stat = kzalloc(sizeof(*stat), GFP_KERNEL);
19731f7ea1cdSQi Zhang if (!stat) {
19741f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY;
19751f7ea1cdSQi Zhang dev_dbg(dev, "Alloc stat for VF %d failed\n", vf->vf_id);
19761f7ea1cdSQi Zhang goto err_exit;
19771f7ea1cdSQi Zhang }
19781f7ea1cdSQi Zhang
19791f7ea1cdSQi Zhang len = sizeof(*stat);
19801f7ea1cdSQi Zhang
19811f7ea1cdSQi Zhang conf = ice_vc_fdir_lookup_entry(vf, fltr->flow_id);
19821f7ea1cdSQi Zhang if (!conf) {
19831f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS;
19841f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST;
19851f7ea1cdSQi Zhang dev_dbg(dev, "VF %d: FDIR invalid flow_id:0x%X\n",
19861f7ea1cdSQi Zhang vf->vf_id, fltr->flow_id);
19871f7ea1cdSQi Zhang goto err_exit;
19881f7ea1cdSQi Zhang }
19891f7ea1cdSQi Zhang
19901f7ea1cdSQi Zhang /* Just return failure when ctrl_vsi idx is invalid */
19911f7ea1cdSQi Zhang if (vf->ctrl_vsi_idx == ICE_NO_VSI) {
19921f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS;
19931f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
19941f7ea1cdSQi Zhang dev_err(dev, "Invalid FDIR ctrl_vsi for VF %d\n", vf->vf_id);
19951f7ea1cdSQi Zhang goto err_exit;
19961f7ea1cdSQi Zhang }
19971f7ea1cdSQi Zhang
1998d6218317SQi Zhang ret = ice_vc_fdir_set_irq_ctx(vf, conf, VIRTCHNL_OP_DEL_FDIR_FILTER);
1999d6218317SQi Zhang if (ret) {
2000d6218317SQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS;
2001d6218317SQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
2002d6218317SQi Zhang dev_dbg(dev, "VF %d: set FDIR context failed\n", vf->vf_id);
2003d6218317SQi Zhang goto err_exit;
2004d6218317SQi Zhang }
2005d6218317SQi Zhang
20061f7ea1cdSQi Zhang ret = ice_vc_fdir_write_fltr(vf, conf, false, is_tun);
20071f7ea1cdSQi Zhang if (ret) {
20081f7ea1cdSQi Zhang v_ret = VIRTCHNL_STATUS_SUCCESS;
20091f7ea1cdSQi Zhang stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE;
20101f7ea1cdSQi Zhang dev_err(dev, "VF %d: writing FDIR rule failed, ret:%d\n",
20111f7ea1cdSQi Zhang vf->vf_id, ret);
2012d6218317SQi Zhang goto err_del_tmr;
20131f7ea1cdSQi Zhang }
20141f7ea1cdSQi Zhang
2015d6218317SQi Zhang kfree(stat);
20161f7ea1cdSQi Zhang
2017d6218317SQi Zhang return ret;
20181f7ea1cdSQi Zhang
2019d6218317SQi Zhang err_del_tmr:
2020d6218317SQi Zhang ice_vc_fdir_clear_irq_ctx(vf);
20211f7ea1cdSQi Zhang err_exit:
20221f7ea1cdSQi Zhang ret = ice_vc_send_msg_to_vf(vf, VIRTCHNL_OP_DEL_FDIR_FILTER, v_ret,
20231f7ea1cdSQi Zhang (u8 *)stat, len);
20241f7ea1cdSQi Zhang kfree(stat);
20251f7ea1cdSQi Zhang return ret;
20261f7ea1cdSQi Zhang }
20271f7ea1cdSQi Zhang
20281f7ea1cdSQi Zhang /**
20291f7ea1cdSQi Zhang * ice_vf_fdir_init - init FDIR resource for VF
20301f7ea1cdSQi Zhang * @vf: pointer to the VF info
20311f7ea1cdSQi Zhang */
ice_vf_fdir_init(struct ice_vf * vf)20321f7ea1cdSQi Zhang void ice_vf_fdir_init(struct ice_vf *vf)
20331f7ea1cdSQi Zhang {
20341f7ea1cdSQi Zhang struct ice_vf_fdir *fdir = &vf->fdir;
20351f7ea1cdSQi Zhang
20361f7ea1cdSQi Zhang idr_init(&fdir->fdir_rule_idr);
20371f7ea1cdSQi Zhang INIT_LIST_HEAD(&fdir->fdir_rule_list);
2038d6218317SQi Zhang
2039d6218317SQi Zhang spin_lock_init(&fdir->ctx_lock);
2040d6218317SQi Zhang fdir->ctx_irq.flags = 0;
2041d6218317SQi Zhang fdir->ctx_done.flags = 0;
204283c911dcSLingyu Liu ice_vc_fdir_reset_cnt_all(fdir);
20431f7ea1cdSQi Zhang }
20441f7ea1cdSQi Zhang
20451f7ea1cdSQi Zhang /**
20461f7ea1cdSQi Zhang * ice_vf_fdir_exit - destroy FDIR resource for VF
20471f7ea1cdSQi Zhang * @vf: pointer to the VF info
20481f7ea1cdSQi Zhang */
ice_vf_fdir_exit(struct ice_vf * vf)20491f7ea1cdSQi Zhang void ice_vf_fdir_exit(struct ice_vf *vf)
20501f7ea1cdSQi Zhang {
20511f7ea1cdSQi Zhang ice_vc_fdir_flush_entry(vf);
20521f7ea1cdSQi Zhang idr_destroy(&vf->fdir.fdir_rule_idr);
20531f7ea1cdSQi Zhang ice_vc_fdir_rem_prof_all(vf);
20541f7ea1cdSQi Zhang ice_vc_fdir_free_prof_all(vf);
20551f7ea1cdSQi Zhang }
2056