1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* Copyright (C) 2021-2023, Intel Corporation. */ |
3 | |
4 | #include "ice.h" |
5 | #include "ice_base.h" |
6 | #include "ice_lib.h" |
7 | #include "ice_flow.h" |
8 | #include "ice_vf_lib_private.h" |
9 | |
10 | #define to_fltr_conf_from_desc(p) \ |
11 | container_of(p, struct virtchnl_fdir_fltr_conf, input) |
12 | |
13 | #define GTPU_TEID_OFFSET 4 |
14 | #define GTPU_EH_QFI_OFFSET 1 |
15 | #define GTPU_EH_QFI_MASK 0x3F |
16 | #define PFCP_S_OFFSET 0 |
17 | #define PFCP_S_MASK 0x1 |
18 | #define PFCP_PORT_NR 8805 |
19 | |
20 | #define FDIR_INSET_FLAG_ESP_S 0 |
21 | #define FDIR_INSET_FLAG_ESP_M BIT_ULL(FDIR_INSET_FLAG_ESP_S) |
22 | #define FDIR_INSET_FLAG_ESP_UDP BIT_ULL(FDIR_INSET_FLAG_ESP_S) |
23 | #define FDIR_INSET_FLAG_ESP_IPSEC (0ULL << FDIR_INSET_FLAG_ESP_S) |
24 | |
25 | enum ice_fdir_tunnel_type { |
26 | ICE_FDIR_TUNNEL_TYPE_NONE = 0, |
27 | ICE_FDIR_TUNNEL_TYPE_GTPU, |
28 | ICE_FDIR_TUNNEL_TYPE_GTPU_EH, |
29 | }; |
30 | |
31 | struct virtchnl_fdir_fltr_conf { |
32 | struct ice_fdir_fltr input; |
33 | enum ice_fdir_tunnel_type ttype; |
34 | u64 inset_flag; |
35 | u32 flow_id; |
36 | }; |
37 | |
38 | struct virtchnl_fdir_inset_map { |
39 | enum virtchnl_proto_hdr_field field; |
40 | enum ice_flow_field fld; |
41 | u64 flag; |
42 | u64 mask; |
43 | }; |
44 | |
45 | static const struct virtchnl_fdir_inset_map fdir_inset_map[] = { |
46 | {VIRTCHNL_PROTO_HDR_ETH_ETHERTYPE, ICE_FLOW_FIELD_IDX_ETH_TYPE, 0, 0}, |
47 | {VIRTCHNL_PROTO_HDR_IPV4_SRC, ICE_FLOW_FIELD_IDX_IPV4_SA, 0, 0}, |
48 | {VIRTCHNL_PROTO_HDR_IPV4_DST, ICE_FLOW_FIELD_IDX_IPV4_DA, 0, 0}, |
49 | {VIRTCHNL_PROTO_HDR_IPV4_DSCP, ICE_FLOW_FIELD_IDX_IPV4_DSCP, 0, 0}, |
50 | {VIRTCHNL_PROTO_HDR_IPV4_TTL, ICE_FLOW_FIELD_IDX_IPV4_TTL, 0, 0}, |
51 | {VIRTCHNL_PROTO_HDR_IPV4_PROT, ICE_FLOW_FIELD_IDX_IPV4_PROT, 0, 0}, |
52 | {VIRTCHNL_PROTO_HDR_IPV6_SRC, ICE_FLOW_FIELD_IDX_IPV6_SA, 0, 0}, |
53 | {VIRTCHNL_PROTO_HDR_IPV6_DST, ICE_FLOW_FIELD_IDX_IPV6_DA, 0, 0}, |
54 | {VIRTCHNL_PROTO_HDR_IPV6_TC, ICE_FLOW_FIELD_IDX_IPV6_DSCP, 0, 0}, |
55 | {VIRTCHNL_PROTO_HDR_IPV6_HOP_LIMIT, ICE_FLOW_FIELD_IDX_IPV6_TTL, 0, 0}, |
56 | {VIRTCHNL_PROTO_HDR_IPV6_PROT, ICE_FLOW_FIELD_IDX_IPV6_PROT, 0, 0}, |
57 | {VIRTCHNL_PROTO_HDR_UDP_SRC_PORT, ICE_FLOW_FIELD_IDX_UDP_SRC_PORT, 0, 0}, |
58 | {VIRTCHNL_PROTO_HDR_UDP_DST_PORT, ICE_FLOW_FIELD_IDX_UDP_DST_PORT, 0, 0}, |
59 | {VIRTCHNL_PROTO_HDR_TCP_SRC_PORT, ICE_FLOW_FIELD_IDX_TCP_SRC_PORT, 0, 0}, |
60 | {VIRTCHNL_PROTO_HDR_TCP_DST_PORT, ICE_FLOW_FIELD_IDX_TCP_DST_PORT, 0, 0}, |
61 | {VIRTCHNL_PROTO_HDR_SCTP_SRC_PORT, ICE_FLOW_FIELD_IDX_SCTP_SRC_PORT, 0, 0}, |
62 | {VIRTCHNL_PROTO_HDR_SCTP_DST_PORT, ICE_FLOW_FIELD_IDX_SCTP_DST_PORT, 0, 0}, |
63 | {VIRTCHNL_PROTO_HDR_GTPU_IP_TEID, ICE_FLOW_FIELD_IDX_GTPU_IP_TEID, 0, 0}, |
64 | {VIRTCHNL_PROTO_HDR_GTPU_EH_QFI, ICE_FLOW_FIELD_IDX_GTPU_EH_QFI, 0, 0}, |
65 | {VIRTCHNL_PROTO_HDR_ESP_SPI, ICE_FLOW_FIELD_IDX_ESP_SPI, |
66 | FDIR_INSET_FLAG_ESP_IPSEC, FDIR_INSET_FLAG_ESP_M}, |
67 | {VIRTCHNL_PROTO_HDR_ESP_SPI, ICE_FLOW_FIELD_IDX_NAT_T_ESP_SPI, |
68 | FDIR_INSET_FLAG_ESP_UDP, FDIR_INSET_FLAG_ESP_M}, |
69 | {VIRTCHNL_PROTO_HDR_AH_SPI, ICE_FLOW_FIELD_IDX_AH_SPI, 0, 0}, |
70 | {VIRTCHNL_PROTO_HDR_L2TPV3_SESS_ID, ICE_FLOW_FIELD_IDX_L2TPV3_SESS_ID, 0, 0}, |
71 | {VIRTCHNL_PROTO_HDR_PFCP_S_FIELD, ICE_FLOW_FIELD_IDX_UDP_DST_PORT, 0, 0}, |
72 | }; |
73 | |
74 | /** |
75 | * ice_vc_fdir_param_check |
76 | * @vf: pointer to the VF structure |
77 | * @vsi_id: VF relative VSI ID |
78 | * |
79 | * Check for the valid VSI ID, PF's state and VF's state |
80 | * |
81 | * Return: 0 on success, and -EINVAL on error. |
82 | */ |
83 | static int |
84 | ice_vc_fdir_param_check(struct ice_vf *vf, u16 vsi_id) |
85 | { |
86 | struct ice_pf *pf = vf->pf; |
87 | |
88 | if (!test_bit(ICE_FLAG_FD_ENA, pf->flags)) |
89 | return -EINVAL; |
90 | |
91 | if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) |
92 | return -EINVAL; |
93 | |
94 | if (!(vf->driver_caps & VIRTCHNL_VF_OFFLOAD_FDIR_PF)) |
95 | return -EINVAL; |
96 | |
97 | if (!ice_vc_isvalid_vsi_id(vf, vsi_id)) |
98 | return -EINVAL; |
99 | |
100 | if (!ice_get_vf_vsi(vf)) |
101 | return -EINVAL; |
102 | |
103 | return 0; |
104 | } |
105 | |
106 | /** |
107 | * ice_vf_start_ctrl_vsi |
108 | * @vf: pointer to the VF structure |
109 | * |
110 | * Allocate ctrl_vsi for the first time and open the ctrl_vsi port for VF |
111 | * |
112 | * Return: 0 on success, and other on error. |
113 | */ |
114 | static int ice_vf_start_ctrl_vsi(struct ice_vf *vf) |
115 | { |
116 | struct ice_pf *pf = vf->pf; |
117 | struct ice_vsi *ctrl_vsi; |
118 | struct device *dev; |
119 | int err; |
120 | |
121 | dev = ice_pf_to_dev(pf); |
122 | if (vf->ctrl_vsi_idx != ICE_NO_VSI) |
123 | return -EEXIST; |
124 | |
125 | ctrl_vsi = ice_vf_ctrl_vsi_setup(vf); |
126 | if (!ctrl_vsi) { |
127 | dev_dbg(dev, "Could not setup control VSI for VF %d\n" , |
128 | vf->vf_id); |
129 | return -ENOMEM; |
130 | } |
131 | |
132 | err = ice_vsi_open_ctrl(vsi: ctrl_vsi); |
133 | if (err) { |
134 | dev_dbg(dev, "Could not open control VSI for VF %d\n" , |
135 | vf->vf_id); |
136 | goto err_vsi_open; |
137 | } |
138 | |
139 | return 0; |
140 | |
141 | err_vsi_open: |
142 | ice_vsi_release(vsi: ctrl_vsi); |
143 | if (vf->ctrl_vsi_idx != ICE_NO_VSI) { |
144 | pf->vsi[vf->ctrl_vsi_idx] = NULL; |
145 | vf->ctrl_vsi_idx = ICE_NO_VSI; |
146 | } |
147 | return err; |
148 | } |
149 | |
150 | /** |
151 | * ice_vc_fdir_alloc_prof - allocate profile for this filter flow type |
152 | * @vf: pointer to the VF structure |
153 | * @flow: filter flow type |
154 | * |
155 | * Return: 0 on success, and other on error. |
156 | */ |
157 | static int |
158 | ice_vc_fdir_alloc_prof(struct ice_vf *vf, enum ice_fltr_ptype flow) |
159 | { |
160 | struct ice_vf_fdir *fdir = &vf->fdir; |
161 | |
162 | if (!fdir->fdir_prof) { |
163 | fdir->fdir_prof = devm_kcalloc(ice_pf_to_dev(vf->pf), |
164 | n: ICE_FLTR_PTYPE_MAX, |
165 | size: sizeof(*fdir->fdir_prof), |
166 | GFP_KERNEL); |
167 | if (!fdir->fdir_prof) |
168 | return -ENOMEM; |
169 | } |
170 | |
171 | if (!fdir->fdir_prof[flow]) { |
172 | fdir->fdir_prof[flow] = devm_kzalloc(ice_pf_to_dev(vf->pf), |
173 | size: sizeof(**fdir->fdir_prof), |
174 | GFP_KERNEL); |
175 | if (!fdir->fdir_prof[flow]) |
176 | return -ENOMEM; |
177 | } |
178 | |
179 | return 0; |
180 | } |
181 | |
182 | /** |
183 | * ice_vc_fdir_free_prof - free profile for this filter flow type |
184 | * @vf: pointer to the VF structure |
185 | * @flow: filter flow type |
186 | */ |
187 | static void |
188 | ice_vc_fdir_free_prof(struct ice_vf *vf, enum ice_fltr_ptype flow) |
189 | { |
190 | struct ice_vf_fdir *fdir = &vf->fdir; |
191 | |
192 | if (!fdir->fdir_prof) |
193 | return; |
194 | |
195 | if (!fdir->fdir_prof[flow]) |
196 | return; |
197 | |
198 | devm_kfree(ice_pf_to_dev(vf->pf), p: fdir->fdir_prof[flow]); |
199 | fdir->fdir_prof[flow] = NULL; |
200 | } |
201 | |
202 | /** |
203 | * ice_vc_fdir_free_prof_all - free all the profile for this VF |
204 | * @vf: pointer to the VF structure |
205 | */ |
206 | static void ice_vc_fdir_free_prof_all(struct ice_vf *vf) |
207 | { |
208 | struct ice_vf_fdir *fdir = &vf->fdir; |
209 | enum ice_fltr_ptype flow; |
210 | |
211 | if (!fdir->fdir_prof) |
212 | return; |
213 | |
214 | for (flow = ICE_FLTR_PTYPE_NONF_NONE; flow < ICE_FLTR_PTYPE_MAX; flow++) |
215 | ice_vc_fdir_free_prof(vf, flow); |
216 | |
217 | devm_kfree(ice_pf_to_dev(vf->pf), p: fdir->fdir_prof); |
218 | fdir->fdir_prof = NULL; |
219 | } |
220 | |
221 | /** |
222 | * ice_vc_fdir_parse_flow_fld |
223 | * @proto_hdr: virtual channel protocol filter header |
224 | * @conf: FDIR configuration for each filter |
225 | * @fld: field type array |
226 | * @fld_cnt: field counter |
227 | * |
228 | * Parse the virtual channel filter header and store them into field type array |
229 | * |
230 | * Return: 0 on success, and other on error. |
231 | */ |
232 | static int |
233 | ice_vc_fdir_parse_flow_fld(struct virtchnl_proto_hdr *proto_hdr, |
234 | struct virtchnl_fdir_fltr_conf *conf, |
235 | enum ice_flow_field *fld, int *fld_cnt) |
236 | { |
237 | struct virtchnl_proto_hdr hdr; |
238 | u32 i; |
239 | |
240 | memcpy(&hdr, proto_hdr, sizeof(hdr)); |
241 | |
242 | for (i = 0; (i < ARRAY_SIZE(fdir_inset_map)) && |
243 | VIRTCHNL_GET_PROTO_HDR_FIELD(&hdr); i++) |
244 | if (VIRTCHNL_TEST_PROTO_HDR(&hdr, fdir_inset_map[i].field)) { |
245 | if (fdir_inset_map[i].mask && |
246 | ((fdir_inset_map[i].mask & conf->inset_flag) != |
247 | fdir_inset_map[i].flag)) |
248 | continue; |
249 | |
250 | fld[*fld_cnt] = fdir_inset_map[i].fld; |
251 | *fld_cnt += 1; |
252 | if (*fld_cnt >= ICE_FLOW_FIELD_IDX_MAX) |
253 | return -EINVAL; |
254 | VIRTCHNL_DEL_PROTO_HDR_FIELD(&hdr, |
255 | fdir_inset_map[i].field); |
256 | } |
257 | |
258 | return 0; |
259 | } |
260 | |
261 | /** |
262 | * ice_vc_fdir_set_flow_fld |
263 | * @vf: pointer to the VF structure |
264 | * @fltr: virtual channel add cmd buffer |
265 | * @conf: FDIR configuration for each filter |
266 | * @seg: array of one or more packet segments that describe the flow |
267 | * |
268 | * Parse the virtual channel add msg buffer's field vector and store them into |
269 | * flow's packet segment field |
270 | * |
271 | * Return: 0 on success, and other on error. |
272 | */ |
273 | static int |
274 | ice_vc_fdir_set_flow_fld(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, |
275 | struct virtchnl_fdir_fltr_conf *conf, |
276 | struct ice_flow_seg_info *seg) |
277 | { |
278 | struct virtchnl_fdir_rule *rule = &fltr->rule_cfg; |
279 | enum ice_flow_field fld[ICE_FLOW_FIELD_IDX_MAX]; |
280 | struct device *dev = ice_pf_to_dev(vf->pf); |
281 | struct virtchnl_proto_hdrs *proto; |
282 | int fld_cnt = 0; |
283 | int i; |
284 | |
285 | proto = &rule->proto_hdrs; |
286 | for (i = 0; i < proto->count; i++) { |
287 | struct virtchnl_proto_hdr *hdr = &proto->proto_hdr[i]; |
288 | int ret; |
289 | |
290 | ret = ice_vc_fdir_parse_flow_fld(proto_hdr: hdr, conf, fld, fld_cnt: &fld_cnt); |
291 | if (ret) |
292 | return ret; |
293 | } |
294 | |
295 | if (fld_cnt == 0) { |
296 | dev_dbg(dev, "Empty input set for VF %d\n" , vf->vf_id); |
297 | return -EINVAL; |
298 | } |
299 | |
300 | for (i = 0; i < fld_cnt; i++) |
301 | ice_flow_set_fld(seg, fld: fld[i], |
302 | ICE_FLOW_FLD_OFF_INVAL, |
303 | ICE_FLOW_FLD_OFF_INVAL, |
304 | ICE_FLOW_FLD_OFF_INVAL, range: false); |
305 | |
306 | return 0; |
307 | } |
308 | |
309 | /** |
310 | * ice_vc_fdir_set_flow_hdr - config the flow's packet segment header |
311 | * @vf: pointer to the VF structure |
312 | * @conf: FDIR configuration for each filter |
313 | * @seg: array of one or more packet segments that describe the flow |
314 | * |
315 | * Return: 0 on success, and other on error. |
316 | */ |
317 | static int |
318 | ice_vc_fdir_set_flow_hdr(struct ice_vf *vf, |
319 | struct virtchnl_fdir_fltr_conf *conf, |
320 | struct ice_flow_seg_info *seg) |
321 | { |
322 | enum ice_fltr_ptype flow = conf->input.flow_type; |
323 | enum ice_fdir_tunnel_type ttype = conf->ttype; |
324 | struct device *dev = ice_pf_to_dev(vf->pf); |
325 | |
326 | switch (flow) { |
327 | case ICE_FLTR_PTYPE_NON_IP_L2: |
328 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ETH_NON_IP); |
329 | break; |
330 | case ICE_FLTR_PTYPE_NONF_IPV4_L2TPV3: |
331 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_L2TPV3 | |
332 | ICE_FLOW_SEG_HDR_IPV4 | |
333 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
334 | break; |
335 | case ICE_FLTR_PTYPE_NONF_IPV4_ESP: |
336 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ESP | |
337 | ICE_FLOW_SEG_HDR_IPV4 | |
338 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
339 | break; |
340 | case ICE_FLTR_PTYPE_NONF_IPV4_AH: |
341 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_AH | |
342 | ICE_FLOW_SEG_HDR_IPV4 | |
343 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
344 | break; |
345 | case ICE_FLTR_PTYPE_NONF_IPV4_NAT_T_ESP: |
346 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_NAT_T_ESP | |
347 | ICE_FLOW_SEG_HDR_IPV4 | |
348 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
349 | break; |
350 | case ICE_FLTR_PTYPE_NONF_IPV4_PFCP_NODE: |
351 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_PFCP_NODE | |
352 | ICE_FLOW_SEG_HDR_IPV4 | |
353 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
354 | break; |
355 | case ICE_FLTR_PTYPE_NONF_IPV4_PFCP_SESSION: |
356 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_PFCP_SESSION | |
357 | ICE_FLOW_SEG_HDR_IPV4 | |
358 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
359 | break; |
360 | case ICE_FLTR_PTYPE_NONF_IPV4_OTHER: |
361 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV4 | |
362 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
363 | break; |
364 | case ICE_FLTR_PTYPE_NONF_IPV4_TCP: |
365 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_TCP | |
366 | ICE_FLOW_SEG_HDR_IPV4 | |
367 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
368 | break; |
369 | case ICE_FLTR_PTYPE_NONF_IPV4_UDP: |
370 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_UDP | |
371 | ICE_FLOW_SEG_HDR_IPV4 | |
372 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
373 | break; |
374 | case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_UDP: |
375 | case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_TCP: |
376 | case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_ICMP: |
377 | case ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER: |
378 | if (ttype == ICE_FDIR_TUNNEL_TYPE_GTPU) { |
379 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_IP | |
380 | ICE_FLOW_SEG_HDR_IPV4 | |
381 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
382 | } else if (ttype == ICE_FDIR_TUNNEL_TYPE_GTPU_EH) { |
383 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_GTPU_EH | |
384 | ICE_FLOW_SEG_HDR_GTPU_IP | |
385 | ICE_FLOW_SEG_HDR_IPV4 | |
386 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
387 | } else { |
388 | dev_dbg(dev, "Invalid tunnel type 0x%x for VF %d\n" , |
389 | flow, vf->vf_id); |
390 | return -EINVAL; |
391 | } |
392 | break; |
393 | case ICE_FLTR_PTYPE_NONF_IPV4_SCTP: |
394 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_SCTP | |
395 | ICE_FLOW_SEG_HDR_IPV4 | |
396 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
397 | break; |
398 | case ICE_FLTR_PTYPE_NONF_IPV6_L2TPV3: |
399 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_L2TPV3 | |
400 | ICE_FLOW_SEG_HDR_IPV6 | |
401 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
402 | break; |
403 | case ICE_FLTR_PTYPE_NONF_IPV6_ESP: |
404 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_ESP | |
405 | ICE_FLOW_SEG_HDR_IPV6 | |
406 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
407 | break; |
408 | case ICE_FLTR_PTYPE_NONF_IPV6_AH: |
409 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_AH | |
410 | ICE_FLOW_SEG_HDR_IPV6 | |
411 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
412 | break; |
413 | case ICE_FLTR_PTYPE_NONF_IPV6_NAT_T_ESP: |
414 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_NAT_T_ESP | |
415 | ICE_FLOW_SEG_HDR_IPV6 | |
416 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
417 | break; |
418 | case ICE_FLTR_PTYPE_NONF_IPV6_PFCP_NODE: |
419 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_PFCP_NODE | |
420 | ICE_FLOW_SEG_HDR_IPV6 | |
421 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
422 | break; |
423 | case ICE_FLTR_PTYPE_NONF_IPV6_PFCP_SESSION: |
424 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_PFCP_SESSION | |
425 | ICE_FLOW_SEG_HDR_IPV6 | |
426 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
427 | break; |
428 | case ICE_FLTR_PTYPE_NONF_IPV6_OTHER: |
429 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_IPV6 | |
430 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
431 | break; |
432 | case ICE_FLTR_PTYPE_NONF_IPV6_TCP: |
433 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_TCP | |
434 | ICE_FLOW_SEG_HDR_IPV6 | |
435 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
436 | break; |
437 | case ICE_FLTR_PTYPE_NONF_IPV6_UDP: |
438 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_UDP | |
439 | ICE_FLOW_SEG_HDR_IPV6 | |
440 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
441 | break; |
442 | case ICE_FLTR_PTYPE_NONF_IPV6_SCTP: |
443 | ICE_FLOW_SET_HDRS(seg, ICE_FLOW_SEG_HDR_SCTP | |
444 | ICE_FLOW_SEG_HDR_IPV6 | |
445 | ICE_FLOW_SEG_HDR_IPV_OTHER); |
446 | break; |
447 | default: |
448 | dev_dbg(dev, "Invalid flow type 0x%x for VF %d failed\n" , |
449 | flow, vf->vf_id); |
450 | return -EINVAL; |
451 | } |
452 | |
453 | return 0; |
454 | } |
455 | |
456 | /** |
457 | * ice_vc_fdir_rem_prof - remove profile for this filter flow type |
458 | * @vf: pointer to the VF structure |
459 | * @flow: filter flow type |
460 | * @tun: 0 implies non-tunnel type filter, 1 implies tunnel type filter |
461 | */ |
462 | static void |
463 | ice_vc_fdir_rem_prof(struct ice_vf *vf, enum ice_fltr_ptype flow, int tun) |
464 | { |
465 | struct ice_vf_fdir *fdir = &vf->fdir; |
466 | struct ice_fd_hw_prof *vf_prof; |
467 | struct ice_pf *pf = vf->pf; |
468 | struct ice_vsi *vf_vsi; |
469 | struct device *dev; |
470 | struct ice_hw *hw; |
471 | u64 prof_id; |
472 | int i; |
473 | |
474 | dev = ice_pf_to_dev(pf); |
475 | hw = &pf->hw; |
476 | if (!fdir->fdir_prof || !fdir->fdir_prof[flow]) |
477 | return; |
478 | |
479 | vf_prof = fdir->fdir_prof[flow]; |
480 | prof_id = vf_prof->prof_id[tun]; |
481 | |
482 | vf_vsi = ice_get_vf_vsi(vf); |
483 | if (!vf_vsi) { |
484 | dev_dbg(dev, "NULL vf %d vsi pointer\n" , vf->vf_id); |
485 | return; |
486 | } |
487 | |
488 | if (!fdir->prof_entry_cnt[flow][tun]) |
489 | return; |
490 | |
491 | for (i = 0; i < fdir->prof_entry_cnt[flow][tun]; i++) |
492 | if (vf_prof->entry_h[i][tun]) { |
493 | u16 vsi_num = ice_get_hw_vsi_num(hw, vsi_handle: vf_prof->vsi_h[i]); |
494 | |
495 | ice_rem_prof_id_flow(hw, blk: ICE_BLK_FD, vsi: vsi_num, hdl: prof_id); |
496 | ice_flow_rem_entry(hw, blk: ICE_BLK_FD, |
497 | entry_h: vf_prof->entry_h[i][tun]); |
498 | vf_prof->entry_h[i][tun] = 0; |
499 | } |
500 | |
501 | ice_flow_rem_prof(hw, blk: ICE_BLK_FD, prof_id); |
502 | devm_kfree(dev, p: vf_prof->fdir_seg[tun]); |
503 | vf_prof->fdir_seg[tun] = NULL; |
504 | |
505 | for (i = 0; i < vf_prof->cnt; i++) |
506 | vf_prof->vsi_h[i] = 0; |
507 | |
508 | fdir->prof_entry_cnt[flow][tun] = 0; |
509 | } |
510 | |
511 | /** |
512 | * ice_vc_fdir_rem_prof_all - remove profile for this VF |
513 | * @vf: pointer to the VF structure |
514 | */ |
515 | static void ice_vc_fdir_rem_prof_all(struct ice_vf *vf) |
516 | { |
517 | enum ice_fltr_ptype flow; |
518 | |
519 | for (flow = ICE_FLTR_PTYPE_NONF_NONE; |
520 | flow < ICE_FLTR_PTYPE_MAX; flow++) { |
521 | ice_vc_fdir_rem_prof(vf, flow, tun: 0); |
522 | ice_vc_fdir_rem_prof(vf, flow, tun: 1); |
523 | } |
524 | } |
525 | |
526 | /** |
527 | * ice_vc_fdir_reset_cnt_all - reset all FDIR counters for this VF FDIR |
528 | * @fdir: pointer to the VF FDIR structure |
529 | */ |
530 | static void ice_vc_fdir_reset_cnt_all(struct ice_vf_fdir *fdir) |
531 | { |
532 | enum ice_fltr_ptype flow; |
533 | |
534 | for (flow = ICE_FLTR_PTYPE_NONF_NONE; |
535 | flow < ICE_FLTR_PTYPE_MAX; flow++) { |
536 | fdir->fdir_fltr_cnt[flow][0] = 0; |
537 | fdir->fdir_fltr_cnt[flow][1] = 0; |
538 | } |
539 | } |
540 | |
541 | /** |
542 | * ice_vc_fdir_has_prof_conflict |
543 | * @vf: pointer to the VF structure |
544 | * @conf: FDIR configuration for each filter |
545 | * |
546 | * Check if @conf has conflicting profile with existing profiles |
547 | * |
548 | * Return: true on success, and false on error. |
549 | */ |
550 | static bool |
551 | ice_vc_fdir_has_prof_conflict(struct ice_vf *vf, |
552 | struct virtchnl_fdir_fltr_conf *conf) |
553 | { |
554 | struct ice_fdir_fltr *desc; |
555 | |
556 | list_for_each_entry(desc, &vf->fdir.fdir_rule_list, fltr_node) { |
557 | struct virtchnl_fdir_fltr_conf *existing_conf; |
558 | enum ice_fltr_ptype flow_type_a, flow_type_b; |
559 | struct ice_fdir_fltr *a, *b; |
560 | |
561 | existing_conf = to_fltr_conf_from_desc(desc); |
562 | a = &existing_conf->input; |
563 | b = &conf->input; |
564 | flow_type_a = a->flow_type; |
565 | flow_type_b = b->flow_type; |
566 | |
567 | /* No need to compare two rules with different tunnel types or |
568 | * with the same protocol type. |
569 | */ |
570 | if (existing_conf->ttype != conf->ttype || |
571 | flow_type_a == flow_type_b) |
572 | continue; |
573 | |
574 | switch (flow_type_a) { |
575 | case ICE_FLTR_PTYPE_NONF_IPV4_UDP: |
576 | case ICE_FLTR_PTYPE_NONF_IPV4_TCP: |
577 | case ICE_FLTR_PTYPE_NONF_IPV4_SCTP: |
578 | if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_OTHER) |
579 | return true; |
580 | break; |
581 | case ICE_FLTR_PTYPE_NONF_IPV4_OTHER: |
582 | if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_UDP || |
583 | flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_TCP || |
584 | flow_type_b == ICE_FLTR_PTYPE_NONF_IPV4_SCTP) |
585 | return true; |
586 | break; |
587 | case ICE_FLTR_PTYPE_NONF_IPV6_UDP: |
588 | case ICE_FLTR_PTYPE_NONF_IPV6_TCP: |
589 | case ICE_FLTR_PTYPE_NONF_IPV6_SCTP: |
590 | if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_OTHER) |
591 | return true; |
592 | break; |
593 | case ICE_FLTR_PTYPE_NONF_IPV6_OTHER: |
594 | if (flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_UDP || |
595 | flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_TCP || |
596 | flow_type_b == ICE_FLTR_PTYPE_NONF_IPV6_SCTP) |
597 | return true; |
598 | break; |
599 | default: |
600 | break; |
601 | } |
602 | } |
603 | |
604 | return false; |
605 | } |
606 | |
607 | /** |
608 | * ice_vc_fdir_write_flow_prof |
609 | * @vf: pointer to the VF structure |
610 | * @flow: filter flow type |
611 | * @seg: array of one or more packet segments that describe the flow |
612 | * @tun: 0 implies non-tunnel type filter, 1 implies tunnel type filter |
613 | * |
614 | * Write the flow's profile config and packet segment into the hardware |
615 | * |
616 | * Return: 0 on success, and other on error. |
617 | */ |
618 | static int |
619 | ice_vc_fdir_write_flow_prof(struct ice_vf *vf, enum ice_fltr_ptype flow, |
620 | struct ice_flow_seg_info *seg, int tun) |
621 | { |
622 | struct ice_vf_fdir *fdir = &vf->fdir; |
623 | struct ice_vsi *vf_vsi, *ctrl_vsi; |
624 | struct ice_flow_seg_info *old_seg; |
625 | struct ice_flow_prof *prof = NULL; |
626 | struct ice_fd_hw_prof *vf_prof; |
627 | struct device *dev; |
628 | struct ice_pf *pf; |
629 | struct ice_hw *hw; |
630 | u64 entry1_h = 0; |
631 | u64 entry2_h = 0; |
632 | int ret; |
633 | |
634 | pf = vf->pf; |
635 | dev = ice_pf_to_dev(pf); |
636 | hw = &pf->hw; |
637 | vf_vsi = ice_get_vf_vsi(vf); |
638 | if (!vf_vsi) |
639 | return -EINVAL; |
640 | |
641 | ctrl_vsi = pf->vsi[vf->ctrl_vsi_idx]; |
642 | if (!ctrl_vsi) |
643 | return -EINVAL; |
644 | |
645 | vf_prof = fdir->fdir_prof[flow]; |
646 | old_seg = vf_prof->fdir_seg[tun]; |
647 | if (old_seg) { |
648 | if (!memcmp(p: old_seg, q: seg, size: sizeof(*seg))) { |
649 | dev_dbg(dev, "Duplicated profile for VF %d!\n" , |
650 | vf->vf_id); |
651 | return -EEXIST; |
652 | } |
653 | |
654 | if (fdir->fdir_fltr_cnt[flow][tun]) { |
655 | ret = -EINVAL; |
656 | dev_dbg(dev, "Input set conflicts for VF %d\n" , |
657 | vf->vf_id); |
658 | goto err_exit; |
659 | } |
660 | |
661 | /* remove previously allocated profile */ |
662 | ice_vc_fdir_rem_prof(vf, flow, tun); |
663 | } |
664 | |
665 | ret = ice_flow_add_prof(hw, blk: ICE_BLK_FD, dir: ICE_FLOW_RX, segs: seg, |
666 | segs_cnt: tun + 1, symm: false, prof: &prof); |
667 | if (ret) { |
668 | dev_dbg(dev, "Could not add VSI flow 0x%x for VF %d\n" , |
669 | flow, vf->vf_id); |
670 | goto err_exit; |
671 | } |
672 | |
673 | ret = ice_flow_add_entry(hw, blk: ICE_BLK_FD, prof_id: prof->id, entry_id: vf_vsi->idx, |
674 | vsi: vf_vsi->idx, prio: ICE_FLOW_PRIO_NORMAL, |
675 | data: seg, entry_h: &entry1_h); |
676 | if (ret) { |
677 | dev_dbg(dev, "Could not add flow 0x%x VSI entry for VF %d\n" , |
678 | flow, vf->vf_id); |
679 | goto err_prof; |
680 | } |
681 | |
682 | ret = ice_flow_add_entry(hw, blk: ICE_BLK_FD, prof_id: prof->id, entry_id: vf_vsi->idx, |
683 | vsi: ctrl_vsi->idx, prio: ICE_FLOW_PRIO_NORMAL, |
684 | data: seg, entry_h: &entry2_h); |
685 | if (ret) { |
686 | dev_dbg(dev, |
687 | "Could not add flow 0x%x Ctrl VSI entry for VF %d\n" , |
688 | flow, vf->vf_id); |
689 | goto err_entry_1; |
690 | } |
691 | |
692 | vf_prof->fdir_seg[tun] = seg; |
693 | vf_prof->cnt = 0; |
694 | fdir->prof_entry_cnt[flow][tun] = 0; |
695 | |
696 | vf_prof->entry_h[vf_prof->cnt][tun] = entry1_h; |
697 | vf_prof->vsi_h[vf_prof->cnt] = vf_vsi->idx; |
698 | vf_prof->cnt++; |
699 | fdir->prof_entry_cnt[flow][tun]++; |
700 | |
701 | vf_prof->entry_h[vf_prof->cnt][tun] = entry2_h; |
702 | vf_prof->vsi_h[vf_prof->cnt] = ctrl_vsi->idx; |
703 | vf_prof->cnt++; |
704 | fdir->prof_entry_cnt[flow][tun]++; |
705 | |
706 | vf_prof->prof_id[tun] = prof->id; |
707 | |
708 | return 0; |
709 | |
710 | err_entry_1: |
711 | ice_rem_prof_id_flow(hw, blk: ICE_BLK_FD, |
712 | vsi: ice_get_hw_vsi_num(hw, vsi_handle: vf_vsi->idx), hdl: prof->id); |
713 | ice_flow_rem_entry(hw, blk: ICE_BLK_FD, entry_h: entry1_h); |
714 | err_prof: |
715 | ice_flow_rem_prof(hw, blk: ICE_BLK_FD, prof_id: prof->id); |
716 | err_exit: |
717 | return ret; |
718 | } |
719 | |
720 | /** |
721 | * ice_vc_fdir_config_input_set |
722 | * @vf: pointer to the VF structure |
723 | * @fltr: virtual channel add cmd buffer |
724 | * @conf: FDIR configuration for each filter |
725 | * @tun: 0 implies non-tunnel type filter, 1 implies tunnel type filter |
726 | * |
727 | * Config the input set type and value for virtual channel add msg buffer |
728 | * |
729 | * Return: 0 on success, and other on error. |
730 | */ |
731 | static int |
732 | ice_vc_fdir_config_input_set(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, |
733 | struct virtchnl_fdir_fltr_conf *conf, int tun) |
734 | { |
735 | struct ice_fdir_fltr *input = &conf->input; |
736 | struct device *dev = ice_pf_to_dev(vf->pf); |
737 | struct ice_flow_seg_info *seg; |
738 | enum ice_fltr_ptype flow; |
739 | int ret; |
740 | |
741 | ret = ice_vc_fdir_has_prof_conflict(vf, conf); |
742 | if (ret) { |
743 | dev_dbg(dev, "Found flow profile conflict for VF %d\n" , |
744 | vf->vf_id); |
745 | return ret; |
746 | } |
747 | |
748 | flow = input->flow_type; |
749 | ret = ice_vc_fdir_alloc_prof(vf, flow); |
750 | if (ret) { |
751 | dev_dbg(dev, "Alloc flow prof for VF %d failed\n" , vf->vf_id); |
752 | return ret; |
753 | } |
754 | |
755 | seg = devm_kzalloc(dev, size: sizeof(*seg), GFP_KERNEL); |
756 | if (!seg) |
757 | return -ENOMEM; |
758 | |
759 | ret = ice_vc_fdir_set_flow_fld(vf, fltr, conf, seg); |
760 | if (ret) { |
761 | dev_dbg(dev, "Set flow field for VF %d failed\n" , vf->vf_id); |
762 | goto err_exit; |
763 | } |
764 | |
765 | ret = ice_vc_fdir_set_flow_hdr(vf, conf, seg); |
766 | if (ret) { |
767 | dev_dbg(dev, "Set flow hdr for VF %d failed\n" , vf->vf_id); |
768 | goto err_exit; |
769 | } |
770 | |
771 | ret = ice_vc_fdir_write_flow_prof(vf, flow, seg, tun); |
772 | if (ret == -EEXIST) { |
773 | devm_kfree(dev, p: seg); |
774 | } else if (ret) { |
775 | dev_dbg(dev, "Write flow profile for VF %d failed\n" , |
776 | vf->vf_id); |
777 | goto err_exit; |
778 | } |
779 | |
780 | return 0; |
781 | |
782 | err_exit: |
783 | devm_kfree(dev, p: seg); |
784 | return ret; |
785 | } |
786 | |
787 | /** |
788 | * ice_vc_fdir_parse_pattern |
789 | * @vf: pointer to the VF info |
790 | * @fltr: virtual channel add cmd buffer |
791 | * @conf: FDIR configuration for each filter |
792 | * |
793 | * Parse the virtual channel filter's pattern and store them into conf |
794 | * |
795 | * Return: 0 on success, and other on error. |
796 | */ |
797 | static int |
798 | ice_vc_fdir_parse_pattern(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, |
799 | struct virtchnl_fdir_fltr_conf *conf) |
800 | { |
801 | struct virtchnl_proto_hdrs *proto = &fltr->rule_cfg.proto_hdrs; |
802 | enum virtchnl_proto_hdr_type l3 = VIRTCHNL_PROTO_HDR_NONE; |
803 | enum virtchnl_proto_hdr_type l4 = VIRTCHNL_PROTO_HDR_NONE; |
804 | struct device *dev = ice_pf_to_dev(vf->pf); |
805 | struct ice_fdir_fltr *input = &conf->input; |
806 | int i; |
807 | |
808 | if (proto->count > VIRTCHNL_MAX_NUM_PROTO_HDRS) { |
809 | dev_dbg(dev, "Invalid protocol count:0x%x for VF %d\n" , |
810 | proto->count, vf->vf_id); |
811 | return -EINVAL; |
812 | } |
813 | |
814 | for (i = 0; i < proto->count; i++) { |
815 | struct virtchnl_proto_hdr *hdr = &proto->proto_hdr[i]; |
816 | struct ip_esp_hdr *esph; |
817 | struct ip_auth_hdr *ah; |
818 | struct sctphdr *sctph; |
819 | struct ipv6hdr *ip6h; |
820 | struct udphdr *udph; |
821 | struct tcphdr *tcph; |
822 | struct ethhdr *eth; |
823 | struct iphdr *iph; |
824 | u8 s_field; |
825 | u8 *rawh; |
826 | |
827 | switch (hdr->type) { |
828 | case VIRTCHNL_PROTO_HDR_ETH: |
829 | eth = (struct ethhdr *)hdr->buffer; |
830 | input->flow_type = ICE_FLTR_PTYPE_NON_IP_L2; |
831 | |
832 | if (hdr->field_selector) |
833 | input->ext_data.ether_type = eth->h_proto; |
834 | break; |
835 | case VIRTCHNL_PROTO_HDR_IPV4: |
836 | iph = (struct iphdr *)hdr->buffer; |
837 | l3 = VIRTCHNL_PROTO_HDR_IPV4; |
838 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_OTHER; |
839 | |
840 | if (hdr->field_selector) { |
841 | input->ip.v4.src_ip = iph->saddr; |
842 | input->ip.v4.dst_ip = iph->daddr; |
843 | input->ip.v4.tos = iph->tos; |
844 | input->ip.v4.proto = iph->protocol; |
845 | } |
846 | break; |
847 | case VIRTCHNL_PROTO_HDR_IPV6: |
848 | ip6h = (struct ipv6hdr *)hdr->buffer; |
849 | l3 = VIRTCHNL_PROTO_HDR_IPV6; |
850 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_OTHER; |
851 | |
852 | if (hdr->field_selector) { |
853 | memcpy(input->ip.v6.src_ip, |
854 | ip6h->saddr.in6_u.u6_addr8, |
855 | sizeof(ip6h->saddr)); |
856 | memcpy(input->ip.v6.dst_ip, |
857 | ip6h->daddr.in6_u.u6_addr8, |
858 | sizeof(ip6h->daddr)); |
859 | input->ip.v6.tc = ((u8)(ip6h->priority) << 4) | |
860 | (ip6h->flow_lbl[0] >> 4); |
861 | input->ip.v6.proto = ip6h->nexthdr; |
862 | } |
863 | break; |
864 | case VIRTCHNL_PROTO_HDR_TCP: |
865 | tcph = (struct tcphdr *)hdr->buffer; |
866 | if (l3 == VIRTCHNL_PROTO_HDR_IPV4) |
867 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_TCP; |
868 | else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) |
869 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_TCP; |
870 | |
871 | if (hdr->field_selector) { |
872 | if (l3 == VIRTCHNL_PROTO_HDR_IPV4) { |
873 | input->ip.v4.src_port = tcph->source; |
874 | input->ip.v4.dst_port = tcph->dest; |
875 | } else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) { |
876 | input->ip.v6.src_port = tcph->source; |
877 | input->ip.v6.dst_port = tcph->dest; |
878 | } |
879 | } |
880 | break; |
881 | case VIRTCHNL_PROTO_HDR_UDP: |
882 | udph = (struct udphdr *)hdr->buffer; |
883 | if (l3 == VIRTCHNL_PROTO_HDR_IPV4) |
884 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_UDP; |
885 | else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) |
886 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_UDP; |
887 | |
888 | if (hdr->field_selector) { |
889 | if (l3 == VIRTCHNL_PROTO_HDR_IPV4) { |
890 | input->ip.v4.src_port = udph->source; |
891 | input->ip.v4.dst_port = udph->dest; |
892 | } else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) { |
893 | input->ip.v6.src_port = udph->source; |
894 | input->ip.v6.dst_port = udph->dest; |
895 | } |
896 | } |
897 | break; |
898 | case VIRTCHNL_PROTO_HDR_SCTP: |
899 | sctph = (struct sctphdr *)hdr->buffer; |
900 | if (l3 == VIRTCHNL_PROTO_HDR_IPV4) |
901 | input->flow_type = |
902 | ICE_FLTR_PTYPE_NONF_IPV4_SCTP; |
903 | else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) |
904 | input->flow_type = |
905 | ICE_FLTR_PTYPE_NONF_IPV6_SCTP; |
906 | |
907 | if (hdr->field_selector) { |
908 | if (l3 == VIRTCHNL_PROTO_HDR_IPV4) { |
909 | input->ip.v4.src_port = sctph->source; |
910 | input->ip.v4.dst_port = sctph->dest; |
911 | } else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) { |
912 | input->ip.v6.src_port = sctph->source; |
913 | input->ip.v6.dst_port = sctph->dest; |
914 | } |
915 | } |
916 | break; |
917 | case VIRTCHNL_PROTO_HDR_L2TPV3: |
918 | if (l3 == VIRTCHNL_PROTO_HDR_IPV4) |
919 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_L2TPV3; |
920 | else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) |
921 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_L2TPV3; |
922 | |
923 | if (hdr->field_selector) |
924 | input->l2tpv3_data.session_id = *((__be32 *)hdr->buffer); |
925 | break; |
926 | case VIRTCHNL_PROTO_HDR_ESP: |
927 | esph = (struct ip_esp_hdr *)hdr->buffer; |
928 | if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && |
929 | l4 == VIRTCHNL_PROTO_HDR_UDP) |
930 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_NAT_T_ESP; |
931 | else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && |
932 | l4 == VIRTCHNL_PROTO_HDR_UDP) |
933 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_NAT_T_ESP; |
934 | else if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && |
935 | l4 == VIRTCHNL_PROTO_HDR_NONE) |
936 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_ESP; |
937 | else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && |
938 | l4 == VIRTCHNL_PROTO_HDR_NONE) |
939 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_ESP; |
940 | |
941 | if (l4 == VIRTCHNL_PROTO_HDR_UDP) |
942 | conf->inset_flag |= FDIR_INSET_FLAG_ESP_UDP; |
943 | else |
944 | conf->inset_flag |= FDIR_INSET_FLAG_ESP_IPSEC; |
945 | |
946 | if (hdr->field_selector) { |
947 | if (l3 == VIRTCHNL_PROTO_HDR_IPV4) |
948 | input->ip.v4.sec_parm_idx = esph->spi; |
949 | else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) |
950 | input->ip.v6.sec_parm_idx = esph->spi; |
951 | } |
952 | break; |
953 | case VIRTCHNL_PROTO_HDR_AH: |
954 | ah = (struct ip_auth_hdr *)hdr->buffer; |
955 | if (l3 == VIRTCHNL_PROTO_HDR_IPV4) |
956 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_AH; |
957 | else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) |
958 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_AH; |
959 | |
960 | if (hdr->field_selector) { |
961 | if (l3 == VIRTCHNL_PROTO_HDR_IPV4) |
962 | input->ip.v4.sec_parm_idx = ah->spi; |
963 | else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) |
964 | input->ip.v6.sec_parm_idx = ah->spi; |
965 | } |
966 | break; |
967 | case VIRTCHNL_PROTO_HDR_PFCP: |
968 | rawh = (u8 *)hdr->buffer; |
969 | s_field = (rawh[0] >> PFCP_S_OFFSET) & PFCP_S_MASK; |
970 | if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && s_field == 0) |
971 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_PFCP_NODE; |
972 | else if (l3 == VIRTCHNL_PROTO_HDR_IPV4 && s_field == 1) |
973 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_PFCP_SESSION; |
974 | else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && s_field == 0) |
975 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_PFCP_NODE; |
976 | else if (l3 == VIRTCHNL_PROTO_HDR_IPV6 && s_field == 1) |
977 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV6_PFCP_SESSION; |
978 | |
979 | if (hdr->field_selector) { |
980 | if (l3 == VIRTCHNL_PROTO_HDR_IPV4) |
981 | input->ip.v4.dst_port = cpu_to_be16(PFCP_PORT_NR); |
982 | else if (l3 == VIRTCHNL_PROTO_HDR_IPV6) |
983 | input->ip.v6.dst_port = cpu_to_be16(PFCP_PORT_NR); |
984 | } |
985 | break; |
986 | case VIRTCHNL_PROTO_HDR_GTPU_IP: |
987 | rawh = (u8 *)hdr->buffer; |
988 | input->flow_type = ICE_FLTR_PTYPE_NONF_IPV4_GTPU_IPV4_OTHER; |
989 | |
990 | if (hdr->field_selector) |
991 | input->gtpu_data.teid = *(__be32 *)(&rawh[GTPU_TEID_OFFSET]); |
992 | conf->ttype = ICE_FDIR_TUNNEL_TYPE_GTPU; |
993 | break; |
994 | case VIRTCHNL_PROTO_HDR_GTPU_EH: |
995 | rawh = (u8 *)hdr->buffer; |
996 | |
997 | if (hdr->field_selector) |
998 | input->gtpu_data.qfi = rawh[GTPU_EH_QFI_OFFSET] & GTPU_EH_QFI_MASK; |
999 | conf->ttype = ICE_FDIR_TUNNEL_TYPE_GTPU_EH; |
1000 | break; |
1001 | default: |
1002 | dev_dbg(dev, "Invalid header type 0x:%x for VF %d\n" , |
1003 | hdr->type, vf->vf_id); |
1004 | return -EINVAL; |
1005 | } |
1006 | } |
1007 | |
1008 | return 0; |
1009 | } |
1010 | |
1011 | /** |
1012 | * ice_vc_fdir_parse_action |
1013 | * @vf: pointer to the VF info |
1014 | * @fltr: virtual channel add cmd buffer |
1015 | * @conf: FDIR configuration for each filter |
1016 | * |
1017 | * Parse the virtual channel filter's action and store them into conf |
1018 | * |
1019 | * Return: 0 on success, and other on error. |
1020 | */ |
1021 | static int |
1022 | ice_vc_fdir_parse_action(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, |
1023 | struct virtchnl_fdir_fltr_conf *conf) |
1024 | { |
1025 | struct virtchnl_filter_action_set *as = &fltr->rule_cfg.action_set; |
1026 | struct device *dev = ice_pf_to_dev(vf->pf); |
1027 | struct ice_fdir_fltr *input = &conf->input; |
1028 | u32 dest_num = 0; |
1029 | u32 mark_num = 0; |
1030 | int i; |
1031 | |
1032 | if (as->count > VIRTCHNL_MAX_NUM_ACTIONS) { |
1033 | dev_dbg(dev, "Invalid action numbers:0x%x for VF %d\n" , |
1034 | as->count, vf->vf_id); |
1035 | return -EINVAL; |
1036 | } |
1037 | |
1038 | for (i = 0; i < as->count; i++) { |
1039 | struct virtchnl_filter_action *action = &as->actions[i]; |
1040 | |
1041 | switch (action->type) { |
1042 | case VIRTCHNL_ACTION_PASSTHRU: |
1043 | dest_num++; |
1044 | input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_OTHER; |
1045 | break; |
1046 | case VIRTCHNL_ACTION_DROP: |
1047 | dest_num++; |
1048 | input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DROP_PKT; |
1049 | break; |
1050 | case VIRTCHNL_ACTION_QUEUE: |
1051 | dest_num++; |
1052 | input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QINDEX; |
1053 | input->q_index = action->act_conf.queue.index; |
1054 | break; |
1055 | case VIRTCHNL_ACTION_Q_REGION: |
1056 | dest_num++; |
1057 | input->dest_ctl = ICE_FLTR_PRGM_DESC_DEST_DIRECT_PKT_QGROUP; |
1058 | input->q_index = action->act_conf.queue.index; |
1059 | input->q_region = action->act_conf.queue.region; |
1060 | break; |
1061 | case VIRTCHNL_ACTION_MARK: |
1062 | mark_num++; |
1063 | input->fltr_id = action->act_conf.mark_id; |
1064 | input->fdid_prio = ICE_FXD_FLTR_QW1_FDID_PRI_THREE; |
1065 | break; |
1066 | default: |
1067 | dev_dbg(dev, "Invalid action type:0x%x for VF %d\n" , |
1068 | action->type, vf->vf_id); |
1069 | return -EINVAL; |
1070 | } |
1071 | } |
1072 | |
1073 | if (dest_num == 0 || dest_num >= 2) { |
1074 | dev_dbg(dev, "Invalid destination action for VF %d\n" , |
1075 | vf->vf_id); |
1076 | return -EINVAL; |
1077 | } |
1078 | |
1079 | if (mark_num >= 2) { |
1080 | dev_dbg(dev, "Too many mark actions for VF %d\n" , vf->vf_id); |
1081 | return -EINVAL; |
1082 | } |
1083 | |
1084 | return 0; |
1085 | } |
1086 | |
1087 | /** |
1088 | * ice_vc_validate_fdir_fltr - validate the virtual channel filter |
1089 | * @vf: pointer to the VF info |
1090 | * @fltr: virtual channel add cmd buffer |
1091 | * @conf: FDIR configuration for each filter |
1092 | * |
1093 | * Return: 0 on success, and other on error. |
1094 | */ |
1095 | static int |
1096 | ice_vc_validate_fdir_fltr(struct ice_vf *vf, struct virtchnl_fdir_add *fltr, |
1097 | struct virtchnl_fdir_fltr_conf *conf) |
1098 | { |
1099 | struct virtchnl_proto_hdrs *proto = &fltr->rule_cfg.proto_hdrs; |
1100 | int ret; |
1101 | |
1102 | if (!ice_vc_validate_pattern(vf, proto)) |
1103 | return -EINVAL; |
1104 | |
1105 | ret = ice_vc_fdir_parse_pattern(vf, fltr, conf); |
1106 | if (ret) |
1107 | return ret; |
1108 | |
1109 | return ice_vc_fdir_parse_action(vf, fltr, conf); |
1110 | } |
1111 | |
1112 | /** |
1113 | * ice_vc_fdir_comp_rules - compare if two filter rules have the same value |
1114 | * @conf_a: FDIR configuration for filter a |
1115 | * @conf_b: FDIR configuration for filter b |
1116 | * |
1117 | * Return: 0 on success, and other on error. |
1118 | */ |
1119 | static bool |
1120 | ice_vc_fdir_comp_rules(struct virtchnl_fdir_fltr_conf *conf_a, |
1121 | struct virtchnl_fdir_fltr_conf *conf_b) |
1122 | { |
1123 | struct ice_fdir_fltr *a = &conf_a->input; |
1124 | struct ice_fdir_fltr *b = &conf_b->input; |
1125 | |
1126 | if (conf_a->ttype != conf_b->ttype) |
1127 | return false; |
1128 | if (a->flow_type != b->flow_type) |
1129 | return false; |
1130 | if (memcmp(p: &a->ip, q: &b->ip, size: sizeof(a->ip))) |
1131 | return false; |
1132 | if (memcmp(p: &a->mask, q: &b->mask, size: sizeof(a->mask))) |
1133 | return false; |
1134 | if (memcmp(p: &a->gtpu_data, q: &b->gtpu_data, size: sizeof(a->gtpu_data))) |
1135 | return false; |
1136 | if (memcmp(p: &a->gtpu_mask, q: &b->gtpu_mask, size: sizeof(a->gtpu_mask))) |
1137 | return false; |
1138 | if (memcmp(p: &a->l2tpv3_data, q: &b->l2tpv3_data, size: sizeof(a->l2tpv3_data))) |
1139 | return false; |
1140 | if (memcmp(p: &a->l2tpv3_mask, q: &b->l2tpv3_mask, size: sizeof(a->l2tpv3_mask))) |
1141 | return false; |
1142 | if (memcmp(p: &a->ext_data, q: &b->ext_data, size: sizeof(a->ext_data))) |
1143 | return false; |
1144 | if (memcmp(p: &a->ext_mask, q: &b->ext_mask, size: sizeof(a->ext_mask))) |
1145 | return false; |
1146 | |
1147 | return true; |
1148 | } |
1149 | |
1150 | /** |
1151 | * ice_vc_fdir_is_dup_fltr |
1152 | * @vf: pointer to the VF info |
1153 | * @conf: FDIR configuration for each filter |
1154 | * |
1155 | * Check if there is duplicated rule with same conf value |
1156 | * |
1157 | * Return: 0 true success, and false on error. |
1158 | */ |
1159 | static bool |
1160 | ice_vc_fdir_is_dup_fltr(struct ice_vf *vf, struct virtchnl_fdir_fltr_conf *conf) |
1161 | { |
1162 | struct ice_fdir_fltr *desc; |
1163 | bool ret; |
1164 | |
1165 | list_for_each_entry(desc, &vf->fdir.fdir_rule_list, fltr_node) { |
1166 | struct virtchnl_fdir_fltr_conf *node = |
1167 | to_fltr_conf_from_desc(desc); |
1168 | |
1169 | ret = ice_vc_fdir_comp_rules(conf_a: node, conf_b: conf); |
1170 | if (ret) |
1171 | return true; |
1172 | } |
1173 | |
1174 | return false; |
1175 | } |
1176 | |
1177 | /** |
1178 | * ice_vc_fdir_insert_entry |
1179 | * @vf: pointer to the VF info |
1180 | * @conf: FDIR configuration for each filter |
1181 | * @id: pointer to ID value allocated by driver |
1182 | * |
1183 | * Insert FDIR conf entry into list and allocate ID for this filter |
1184 | * |
1185 | * Return: 0 true success, and other on error. |
1186 | */ |
1187 | static int |
1188 | ice_vc_fdir_insert_entry(struct ice_vf *vf, |
1189 | struct virtchnl_fdir_fltr_conf *conf, u32 *id) |
1190 | { |
1191 | struct ice_fdir_fltr *input = &conf->input; |
1192 | int i; |
1193 | |
1194 | /* alloc ID corresponding with conf */ |
1195 | i = idr_alloc(&vf->fdir.fdir_rule_idr, ptr: conf, start: 0, |
1196 | ICE_FDIR_MAX_FLTRS, GFP_KERNEL); |
1197 | if (i < 0) |
1198 | return -EINVAL; |
1199 | *id = i; |
1200 | |
1201 | list_add(new: &input->fltr_node, head: &vf->fdir.fdir_rule_list); |
1202 | return 0; |
1203 | } |
1204 | |
1205 | /** |
1206 | * ice_vc_fdir_remove_entry - remove FDIR conf entry by ID value |
1207 | * @vf: pointer to the VF info |
1208 | * @conf: FDIR configuration for each filter |
1209 | * @id: filter rule's ID |
1210 | */ |
1211 | static void |
1212 | ice_vc_fdir_remove_entry(struct ice_vf *vf, |
1213 | struct virtchnl_fdir_fltr_conf *conf, u32 id) |
1214 | { |
1215 | struct ice_fdir_fltr *input = &conf->input; |
1216 | |
1217 | idr_remove(&vf->fdir.fdir_rule_idr, id); |
1218 | list_del(entry: &input->fltr_node); |
1219 | } |
1220 | |
1221 | /** |
1222 | * ice_vc_fdir_lookup_entry - lookup FDIR conf entry by ID value |
1223 | * @vf: pointer to the VF info |
1224 | * @id: filter rule's ID |
1225 | * |
1226 | * Return: NULL on error, and other on success. |
1227 | */ |
1228 | static struct virtchnl_fdir_fltr_conf * |
1229 | ice_vc_fdir_lookup_entry(struct ice_vf *vf, u32 id) |
1230 | { |
1231 | return idr_find(&vf->fdir.fdir_rule_idr, id); |
1232 | } |
1233 | |
1234 | /** |
1235 | * ice_vc_fdir_flush_entry - remove all FDIR conf entry |
1236 | * @vf: pointer to the VF info |
1237 | */ |
1238 | static void ice_vc_fdir_flush_entry(struct ice_vf *vf) |
1239 | { |
1240 | struct virtchnl_fdir_fltr_conf *conf; |
1241 | struct ice_fdir_fltr *desc, *temp; |
1242 | |
1243 | list_for_each_entry_safe(desc, temp, |
1244 | &vf->fdir.fdir_rule_list, fltr_node) { |
1245 | conf = to_fltr_conf_from_desc(desc); |
1246 | list_del(entry: &desc->fltr_node); |
1247 | devm_kfree(ice_pf_to_dev(vf->pf), p: conf); |
1248 | } |
1249 | } |
1250 | |
1251 | /** |
1252 | * ice_vc_fdir_write_fltr - write filter rule into hardware |
1253 | * @vf: pointer to the VF info |
1254 | * @conf: FDIR configuration for each filter |
1255 | * @add: true implies add rule, false implies del rules |
1256 | * @is_tun: false implies non-tunnel type filter, true implies tunnel filter |
1257 | * |
1258 | * Return: 0 on success, and other on error. |
1259 | */ |
1260 | static int ice_vc_fdir_write_fltr(struct ice_vf *vf, |
1261 | struct virtchnl_fdir_fltr_conf *conf, |
1262 | bool add, bool is_tun) |
1263 | { |
1264 | struct ice_fdir_fltr *input = &conf->input; |
1265 | struct ice_vsi *vsi, *ctrl_vsi; |
1266 | struct ice_fltr_desc desc; |
1267 | struct device *dev; |
1268 | struct ice_pf *pf; |
1269 | struct ice_hw *hw; |
1270 | int ret; |
1271 | u8 *pkt; |
1272 | |
1273 | pf = vf->pf; |
1274 | dev = ice_pf_to_dev(pf); |
1275 | hw = &pf->hw; |
1276 | vsi = ice_get_vf_vsi(vf); |
1277 | if (!vsi) { |
1278 | dev_dbg(dev, "Invalid vsi for VF %d\n" , vf->vf_id); |
1279 | return -EINVAL; |
1280 | } |
1281 | |
1282 | input->dest_vsi = vsi->idx; |
1283 | input->comp_report = ICE_FXD_FLTR_QW0_COMP_REPORT_SW; |
1284 | |
1285 | ctrl_vsi = pf->vsi[vf->ctrl_vsi_idx]; |
1286 | if (!ctrl_vsi) { |
1287 | dev_dbg(dev, "Invalid ctrl_vsi for VF %d\n" , vf->vf_id); |
1288 | return -EINVAL; |
1289 | } |
1290 | |
1291 | pkt = devm_kzalloc(dev, ICE_FDIR_MAX_RAW_PKT_SIZE, GFP_KERNEL); |
1292 | if (!pkt) |
1293 | return -ENOMEM; |
1294 | |
1295 | ice_fdir_get_prgm_desc(hw, input, fdesc: &desc, add); |
1296 | ret = ice_fdir_get_gen_prgm_pkt(hw, input, pkt, frag: false, tun: is_tun); |
1297 | if (ret) { |
1298 | dev_dbg(dev, "Gen training pkt for VF %d ptype %d failed\n" , |
1299 | vf->vf_id, input->flow_type); |
1300 | goto err_free_pkt; |
1301 | } |
1302 | |
1303 | ret = ice_prgm_fdir_fltr(vsi: ctrl_vsi, fdir_desc: &desc, raw_packet: pkt); |
1304 | if (ret) |
1305 | goto err_free_pkt; |
1306 | |
1307 | return 0; |
1308 | |
1309 | err_free_pkt: |
1310 | devm_kfree(dev, p: pkt); |
1311 | return ret; |
1312 | } |
1313 | |
1314 | /** |
1315 | * ice_vf_fdir_timer - FDIR program waiting timer interrupt handler |
1316 | * @t: pointer to timer_list |
1317 | */ |
1318 | static void ice_vf_fdir_timer(struct timer_list *t) |
1319 | { |
1320 | struct ice_vf_fdir_ctx *ctx_irq = from_timer(ctx_irq, t, rx_tmr); |
1321 | struct ice_vf_fdir_ctx *ctx_done; |
1322 | struct ice_vf_fdir *fdir; |
1323 | unsigned long flags; |
1324 | struct ice_vf *vf; |
1325 | struct ice_pf *pf; |
1326 | |
1327 | fdir = container_of(ctx_irq, struct ice_vf_fdir, ctx_irq); |
1328 | vf = container_of(fdir, struct ice_vf, fdir); |
1329 | ctx_done = &fdir->ctx_done; |
1330 | pf = vf->pf; |
1331 | spin_lock_irqsave(&fdir->ctx_lock, flags); |
1332 | if (!(ctx_irq->flags & ICE_VF_FDIR_CTX_VALID)) { |
1333 | spin_unlock_irqrestore(lock: &fdir->ctx_lock, flags); |
1334 | WARN_ON_ONCE(1); |
1335 | return; |
1336 | } |
1337 | |
1338 | ctx_irq->flags &= ~ICE_VF_FDIR_CTX_VALID; |
1339 | |
1340 | ctx_done->flags |= ICE_VF_FDIR_CTX_VALID; |
1341 | ctx_done->conf = ctx_irq->conf; |
1342 | ctx_done->stat = ICE_FDIR_CTX_TIMEOUT; |
1343 | ctx_done->v_opcode = ctx_irq->v_opcode; |
1344 | spin_unlock_irqrestore(lock: &fdir->ctx_lock, flags); |
1345 | |
1346 | set_bit(nr: ICE_FD_VF_FLUSH_CTX, addr: pf->state); |
1347 | ice_service_task_schedule(pf); |
1348 | } |
1349 | |
1350 | /** |
1351 | * ice_vc_fdir_irq_handler - ctrl_vsi Rx queue interrupt handler |
1352 | * @ctrl_vsi: pointer to a VF's CTRL VSI |
1353 | * @rx_desc: pointer to FDIR Rx queue descriptor |
1354 | */ |
1355 | void |
1356 | ice_vc_fdir_irq_handler(struct ice_vsi *ctrl_vsi, |
1357 | union ice_32b_rx_flex_desc *rx_desc) |
1358 | { |
1359 | struct ice_pf *pf = ctrl_vsi->back; |
1360 | struct ice_vf *vf = ctrl_vsi->vf; |
1361 | struct ice_vf_fdir_ctx *ctx_done; |
1362 | struct ice_vf_fdir_ctx *ctx_irq; |
1363 | struct ice_vf_fdir *fdir; |
1364 | unsigned long flags; |
1365 | struct device *dev; |
1366 | int ret; |
1367 | |
1368 | if (WARN_ON(!vf)) |
1369 | return; |
1370 | |
1371 | fdir = &vf->fdir; |
1372 | ctx_done = &fdir->ctx_done; |
1373 | ctx_irq = &fdir->ctx_irq; |
1374 | dev = ice_pf_to_dev(pf); |
1375 | spin_lock_irqsave(&fdir->ctx_lock, flags); |
1376 | if (!(ctx_irq->flags & ICE_VF_FDIR_CTX_VALID)) { |
1377 | spin_unlock_irqrestore(lock: &fdir->ctx_lock, flags); |
1378 | WARN_ON_ONCE(1); |
1379 | return; |
1380 | } |
1381 | |
1382 | ctx_irq->flags &= ~ICE_VF_FDIR_CTX_VALID; |
1383 | |
1384 | ctx_done->flags |= ICE_VF_FDIR_CTX_VALID; |
1385 | ctx_done->conf = ctx_irq->conf; |
1386 | ctx_done->stat = ICE_FDIR_CTX_IRQ; |
1387 | ctx_done->v_opcode = ctx_irq->v_opcode; |
1388 | memcpy(&ctx_done->rx_desc, rx_desc, sizeof(*rx_desc)); |
1389 | spin_unlock_irqrestore(lock: &fdir->ctx_lock, flags); |
1390 | |
1391 | ret = del_timer(timer: &ctx_irq->rx_tmr); |
1392 | if (!ret) |
1393 | dev_err(dev, "VF %d: Unexpected inactive timer!\n" , vf->vf_id); |
1394 | |
1395 | set_bit(nr: ICE_FD_VF_FLUSH_CTX, addr: pf->state); |
1396 | ice_service_task_schedule(pf); |
1397 | } |
1398 | |
1399 | /** |
1400 | * ice_vf_fdir_dump_info - dump FDIR information for diagnosis |
1401 | * @vf: pointer to the VF info |
1402 | */ |
1403 | static void ice_vf_fdir_dump_info(struct ice_vf *vf) |
1404 | { |
1405 | u32 fd_size, fd_cnt, fd_size_g, fd_cnt_g, fd_size_b, fd_cnt_b; |
1406 | struct ice_vsi *vf_vsi; |
1407 | struct device *dev; |
1408 | struct ice_pf *pf; |
1409 | struct ice_hw *hw; |
1410 | u16 vsi_num; |
1411 | |
1412 | pf = vf->pf; |
1413 | hw = &pf->hw; |
1414 | dev = ice_pf_to_dev(pf); |
1415 | vf_vsi = ice_get_vf_vsi(vf); |
1416 | if (!vf_vsi) { |
1417 | dev_dbg(dev, "VF %d: invalid VSI pointer\n" , vf->vf_id); |
1418 | return; |
1419 | } |
1420 | |
1421 | vsi_num = ice_get_hw_vsi_num(hw, vsi_handle: vf_vsi->idx); |
1422 | |
1423 | fd_size = rd32(hw, VSIQF_FD_SIZE(vsi_num)); |
1424 | fd_cnt = rd32(hw, VSIQF_FD_CNT(vsi_num)); |
1425 | switch (hw->mac_type) { |
1426 | case ICE_MAC_E830: |
1427 | fd_size_g = FIELD_GET(E830_VSIQF_FD_CNT_FD_GCNT_M, fd_size); |
1428 | fd_size_b = FIELD_GET(E830_VSIQF_FD_CNT_FD_BCNT_M, fd_size); |
1429 | fd_cnt_g = FIELD_GET(E830_VSIQF_FD_CNT_FD_GCNT_M, fd_cnt); |
1430 | fd_cnt_b = FIELD_GET(E830_VSIQF_FD_CNT_FD_BCNT_M, fd_cnt); |
1431 | break; |
1432 | case ICE_MAC_E810: |
1433 | default: |
1434 | fd_size_g = FIELD_GET(E800_VSIQF_FD_CNT_FD_GCNT_M, fd_size); |
1435 | fd_size_b = FIELD_GET(E800_VSIQF_FD_CNT_FD_BCNT_M, fd_size); |
1436 | fd_cnt_g = FIELD_GET(E800_VSIQF_FD_CNT_FD_GCNT_M, fd_cnt); |
1437 | fd_cnt_b = FIELD_GET(E800_VSIQF_FD_CNT_FD_BCNT_M, fd_cnt); |
1438 | } |
1439 | |
1440 | dev_dbg(dev, "VF %d: Size in the FD table: guaranteed:0x%x, best effort:0x%x\n" , |
1441 | vf->vf_id, fd_size_g, fd_size_b); |
1442 | dev_dbg(dev, "VF %d: Filter counter in the FD table: guaranteed:0x%x, best effort:0x%x\n" , |
1443 | vf->vf_id, fd_cnt_g, fd_cnt_b); |
1444 | } |
1445 | |
1446 | /** |
1447 | * ice_vf_verify_rx_desc - verify received FDIR programming status descriptor |
1448 | * @vf: pointer to the VF info |
1449 | * @ctx: FDIR context info for post processing |
1450 | * @status: virtchnl FDIR program status |
1451 | * |
1452 | * Return: 0 on success, and other on error. |
1453 | */ |
1454 | static int |
1455 | ice_vf_verify_rx_desc(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx, |
1456 | enum virtchnl_fdir_prgm_status *status) |
1457 | { |
1458 | struct device *dev = ice_pf_to_dev(vf->pf); |
1459 | u32 stat_err, error, prog_id; |
1460 | int ret; |
1461 | |
1462 | stat_err = le16_to_cpu(ctx->rx_desc.wb.status_error0); |
1463 | if (FIELD_GET(ICE_FXD_FLTR_WB_QW1_DD_M, stat_err) != |
1464 | ICE_FXD_FLTR_WB_QW1_DD_YES) { |
1465 | *status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; |
1466 | dev_err(dev, "VF %d: Desc Done not set\n" , vf->vf_id); |
1467 | ret = -EINVAL; |
1468 | goto err_exit; |
1469 | } |
1470 | |
1471 | prog_id = FIELD_GET(ICE_FXD_FLTR_WB_QW1_PROG_ID_M, stat_err); |
1472 | if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_ADD && |
1473 | ctx->v_opcode != VIRTCHNL_OP_ADD_FDIR_FILTER) { |
1474 | dev_err(dev, "VF %d: Desc show add, but ctx not" , |
1475 | vf->vf_id); |
1476 | *status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID; |
1477 | ret = -EINVAL; |
1478 | goto err_exit; |
1479 | } |
1480 | |
1481 | if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_DEL && |
1482 | ctx->v_opcode != VIRTCHNL_OP_DEL_FDIR_FILTER) { |
1483 | dev_err(dev, "VF %d: Desc show del, but ctx not" , |
1484 | vf->vf_id); |
1485 | *status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID; |
1486 | ret = -EINVAL; |
1487 | goto err_exit; |
1488 | } |
1489 | |
1490 | error = FIELD_GET(ICE_FXD_FLTR_WB_QW1_FAIL_M, stat_err); |
1491 | if (error == ICE_FXD_FLTR_WB_QW1_FAIL_YES) { |
1492 | if (prog_id == ICE_FXD_FLTR_WB_QW1_PROG_ADD) { |
1493 | dev_err(dev, "VF %d, Failed to add FDIR rule due to no space in the table" , |
1494 | vf->vf_id); |
1495 | *status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; |
1496 | } else { |
1497 | dev_err(dev, "VF %d, Failed to remove FDIR rule, attempt to remove non-existent entry" , |
1498 | vf->vf_id); |
1499 | *status = VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST; |
1500 | } |
1501 | ret = -EINVAL; |
1502 | goto err_exit; |
1503 | } |
1504 | |
1505 | error = FIELD_GET(ICE_FXD_FLTR_WB_QW1_FAIL_PROF_M, stat_err); |
1506 | if (error == ICE_FXD_FLTR_WB_QW1_FAIL_PROF_YES) { |
1507 | dev_err(dev, "VF %d: Profile matching error" , vf->vf_id); |
1508 | *status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; |
1509 | ret = -EINVAL; |
1510 | goto err_exit; |
1511 | } |
1512 | |
1513 | *status = VIRTCHNL_FDIR_SUCCESS; |
1514 | |
1515 | return 0; |
1516 | |
1517 | err_exit: |
1518 | ice_vf_fdir_dump_info(vf); |
1519 | return ret; |
1520 | } |
1521 | |
1522 | /** |
1523 | * ice_vc_add_fdir_fltr_post |
1524 | * @vf: pointer to the VF structure |
1525 | * @ctx: FDIR context info for post processing |
1526 | * @status: virtchnl FDIR program status |
1527 | * @success: true implies success, false implies failure |
1528 | * |
1529 | * Post process for flow director add command. If success, then do post process |
1530 | * and send back success msg by virtchnl. Otherwise, do context reversion and |
1531 | * send back failure msg by virtchnl. |
1532 | * |
1533 | * Return: 0 on success, and other on error. |
1534 | */ |
1535 | static int |
1536 | ice_vc_add_fdir_fltr_post(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx, |
1537 | enum virtchnl_fdir_prgm_status status, |
1538 | bool success) |
1539 | { |
1540 | struct virtchnl_fdir_fltr_conf *conf = ctx->conf; |
1541 | struct device *dev = ice_pf_to_dev(vf->pf); |
1542 | enum virtchnl_status_code v_ret; |
1543 | struct virtchnl_fdir_add *resp; |
1544 | int ret, len, is_tun; |
1545 | |
1546 | v_ret = VIRTCHNL_STATUS_SUCCESS; |
1547 | len = sizeof(*resp); |
1548 | resp = kzalloc(size: len, GFP_KERNEL); |
1549 | if (!resp) { |
1550 | len = 0; |
1551 | v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; |
1552 | dev_dbg(dev, "VF %d: Alloc resp buf fail" , vf->vf_id); |
1553 | goto err_exit; |
1554 | } |
1555 | |
1556 | if (!success) |
1557 | goto err_exit; |
1558 | |
1559 | is_tun = 0; |
1560 | resp->status = status; |
1561 | resp->flow_id = conf->flow_id; |
1562 | vf->fdir.fdir_fltr_cnt[conf->input.flow_type][is_tun]++; |
1563 | |
1564 | ret = ice_vc_send_msg_to_vf(vf, v_opcode: ctx->v_opcode, v_retval: v_ret, |
1565 | msg: (u8 *)resp, msglen: len); |
1566 | kfree(objp: resp); |
1567 | |
1568 | dev_dbg(dev, "VF %d: flow_id:0x%X, FDIR %s success!\n" , |
1569 | vf->vf_id, conf->flow_id, |
1570 | (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) ? |
1571 | "add" : "del" ); |
1572 | return ret; |
1573 | |
1574 | err_exit: |
1575 | if (resp) |
1576 | resp->status = status; |
1577 | ice_vc_fdir_remove_entry(vf, conf, id: conf->flow_id); |
1578 | devm_kfree(dev, p: conf); |
1579 | |
1580 | ret = ice_vc_send_msg_to_vf(vf, v_opcode: ctx->v_opcode, v_retval: v_ret, |
1581 | msg: (u8 *)resp, msglen: len); |
1582 | kfree(objp: resp); |
1583 | return ret; |
1584 | } |
1585 | |
1586 | /** |
1587 | * ice_vc_del_fdir_fltr_post |
1588 | * @vf: pointer to the VF structure |
1589 | * @ctx: FDIR context info for post processing |
1590 | * @status: virtchnl FDIR program status |
1591 | * @success: true implies success, false implies failure |
1592 | * |
1593 | * Post process for flow director del command. If success, then do post process |
1594 | * and send back success msg by virtchnl. Otherwise, do context reversion and |
1595 | * send back failure msg by virtchnl. |
1596 | * |
1597 | * Return: 0 on success, and other on error. |
1598 | */ |
1599 | static int |
1600 | ice_vc_del_fdir_fltr_post(struct ice_vf *vf, struct ice_vf_fdir_ctx *ctx, |
1601 | enum virtchnl_fdir_prgm_status status, |
1602 | bool success) |
1603 | { |
1604 | struct virtchnl_fdir_fltr_conf *conf = ctx->conf; |
1605 | struct device *dev = ice_pf_to_dev(vf->pf); |
1606 | enum virtchnl_status_code v_ret; |
1607 | struct virtchnl_fdir_del *resp; |
1608 | int ret, len, is_tun; |
1609 | |
1610 | v_ret = VIRTCHNL_STATUS_SUCCESS; |
1611 | len = sizeof(*resp); |
1612 | resp = kzalloc(size: len, GFP_KERNEL); |
1613 | if (!resp) { |
1614 | len = 0; |
1615 | v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; |
1616 | dev_dbg(dev, "VF %d: Alloc resp buf fail" , vf->vf_id); |
1617 | goto err_exit; |
1618 | } |
1619 | |
1620 | if (!success) |
1621 | goto err_exit; |
1622 | |
1623 | is_tun = 0; |
1624 | resp->status = status; |
1625 | ice_vc_fdir_remove_entry(vf, conf, id: conf->flow_id); |
1626 | vf->fdir.fdir_fltr_cnt[conf->input.flow_type][is_tun]--; |
1627 | |
1628 | ret = ice_vc_send_msg_to_vf(vf, v_opcode: ctx->v_opcode, v_retval: v_ret, |
1629 | msg: (u8 *)resp, msglen: len); |
1630 | kfree(objp: resp); |
1631 | |
1632 | dev_dbg(dev, "VF %d: flow_id:0x%X, FDIR %s success!\n" , |
1633 | vf->vf_id, conf->flow_id, |
1634 | (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) ? |
1635 | "add" : "del" ); |
1636 | devm_kfree(dev, p: conf); |
1637 | return ret; |
1638 | |
1639 | err_exit: |
1640 | if (resp) |
1641 | resp->status = status; |
1642 | if (success) |
1643 | devm_kfree(dev, p: conf); |
1644 | |
1645 | ret = ice_vc_send_msg_to_vf(vf, v_opcode: ctx->v_opcode, v_retval: v_ret, |
1646 | msg: (u8 *)resp, msglen: len); |
1647 | kfree(objp: resp); |
1648 | return ret; |
1649 | } |
1650 | |
1651 | /** |
1652 | * ice_flush_fdir_ctx |
1653 | * @pf: pointer to the PF structure |
1654 | * |
1655 | * Flush all the pending event on ctx_done list and process them. |
1656 | */ |
1657 | void ice_flush_fdir_ctx(struct ice_pf *pf) |
1658 | { |
1659 | struct ice_vf *vf; |
1660 | unsigned int bkt; |
1661 | |
1662 | if (!test_and_clear_bit(nr: ICE_FD_VF_FLUSH_CTX, addr: pf->state)) |
1663 | return; |
1664 | |
1665 | mutex_lock(&pf->vfs.table_lock); |
1666 | ice_for_each_vf(pf, bkt, vf) { |
1667 | struct device *dev = ice_pf_to_dev(pf); |
1668 | enum virtchnl_fdir_prgm_status status; |
1669 | struct ice_vf_fdir_ctx *ctx; |
1670 | unsigned long flags; |
1671 | int ret; |
1672 | |
1673 | if (!test_bit(ICE_VF_STATE_ACTIVE, vf->vf_states)) |
1674 | continue; |
1675 | |
1676 | if (vf->ctrl_vsi_idx == ICE_NO_VSI) |
1677 | continue; |
1678 | |
1679 | ctx = &vf->fdir.ctx_done; |
1680 | spin_lock_irqsave(&vf->fdir.ctx_lock, flags); |
1681 | if (!(ctx->flags & ICE_VF_FDIR_CTX_VALID)) { |
1682 | spin_unlock_irqrestore(lock: &vf->fdir.ctx_lock, flags); |
1683 | continue; |
1684 | } |
1685 | spin_unlock_irqrestore(lock: &vf->fdir.ctx_lock, flags); |
1686 | |
1687 | WARN_ON(ctx->stat == ICE_FDIR_CTX_READY); |
1688 | if (ctx->stat == ICE_FDIR_CTX_TIMEOUT) { |
1689 | status = VIRTCHNL_FDIR_FAILURE_RULE_TIMEOUT; |
1690 | dev_err(dev, "VF %d: ctrl_vsi irq timeout\n" , |
1691 | vf->vf_id); |
1692 | goto err_exit; |
1693 | } |
1694 | |
1695 | ret = ice_vf_verify_rx_desc(vf, ctx, status: &status); |
1696 | if (ret) |
1697 | goto err_exit; |
1698 | |
1699 | if (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) |
1700 | ice_vc_add_fdir_fltr_post(vf, ctx, status, success: true); |
1701 | else if (ctx->v_opcode == VIRTCHNL_OP_DEL_FDIR_FILTER) |
1702 | ice_vc_del_fdir_fltr_post(vf, ctx, status, success: true); |
1703 | else |
1704 | dev_err(dev, "VF %d: Unsupported opcode\n" , vf->vf_id); |
1705 | |
1706 | spin_lock_irqsave(&vf->fdir.ctx_lock, flags); |
1707 | ctx->flags &= ~ICE_VF_FDIR_CTX_VALID; |
1708 | spin_unlock_irqrestore(lock: &vf->fdir.ctx_lock, flags); |
1709 | continue; |
1710 | err_exit: |
1711 | if (ctx->v_opcode == VIRTCHNL_OP_ADD_FDIR_FILTER) |
1712 | ice_vc_add_fdir_fltr_post(vf, ctx, status, success: false); |
1713 | else if (ctx->v_opcode == VIRTCHNL_OP_DEL_FDIR_FILTER) |
1714 | ice_vc_del_fdir_fltr_post(vf, ctx, status, success: false); |
1715 | else |
1716 | dev_err(dev, "VF %d: Unsupported opcode\n" , vf->vf_id); |
1717 | |
1718 | spin_lock_irqsave(&vf->fdir.ctx_lock, flags); |
1719 | ctx->flags &= ~ICE_VF_FDIR_CTX_VALID; |
1720 | spin_unlock_irqrestore(lock: &vf->fdir.ctx_lock, flags); |
1721 | } |
1722 | mutex_unlock(lock: &pf->vfs.table_lock); |
1723 | } |
1724 | |
1725 | /** |
1726 | * ice_vc_fdir_set_irq_ctx - set FDIR context info for later IRQ handler |
1727 | * @vf: pointer to the VF structure |
1728 | * @conf: FDIR configuration for each filter |
1729 | * @v_opcode: virtual channel operation code |
1730 | * |
1731 | * Return: 0 on success, and other on error. |
1732 | */ |
1733 | static int |
1734 | ice_vc_fdir_set_irq_ctx(struct ice_vf *vf, struct virtchnl_fdir_fltr_conf *conf, |
1735 | enum virtchnl_ops v_opcode) |
1736 | { |
1737 | struct device *dev = ice_pf_to_dev(vf->pf); |
1738 | struct ice_vf_fdir_ctx *ctx; |
1739 | unsigned long flags; |
1740 | |
1741 | ctx = &vf->fdir.ctx_irq; |
1742 | spin_lock_irqsave(&vf->fdir.ctx_lock, flags); |
1743 | if ((vf->fdir.ctx_irq.flags & ICE_VF_FDIR_CTX_VALID) || |
1744 | (vf->fdir.ctx_done.flags & ICE_VF_FDIR_CTX_VALID)) { |
1745 | spin_unlock_irqrestore(lock: &vf->fdir.ctx_lock, flags); |
1746 | dev_dbg(dev, "VF %d: Last request is still in progress\n" , |
1747 | vf->vf_id); |
1748 | return -EBUSY; |
1749 | } |
1750 | ctx->flags |= ICE_VF_FDIR_CTX_VALID; |
1751 | spin_unlock_irqrestore(lock: &vf->fdir.ctx_lock, flags); |
1752 | |
1753 | ctx->conf = conf; |
1754 | ctx->v_opcode = v_opcode; |
1755 | ctx->stat = ICE_FDIR_CTX_READY; |
1756 | timer_setup(&ctx->rx_tmr, ice_vf_fdir_timer, 0); |
1757 | |
1758 | mod_timer(timer: &ctx->rx_tmr, expires: round_jiffies(j: msecs_to_jiffies(m: 10) + jiffies)); |
1759 | |
1760 | return 0; |
1761 | } |
1762 | |
1763 | /** |
1764 | * ice_vc_fdir_clear_irq_ctx - clear FDIR context info for IRQ handler |
1765 | * @vf: pointer to the VF structure |
1766 | * |
1767 | * Return: 0 on success, and other on error. |
1768 | */ |
1769 | static void ice_vc_fdir_clear_irq_ctx(struct ice_vf *vf) |
1770 | { |
1771 | struct ice_vf_fdir_ctx *ctx = &vf->fdir.ctx_irq; |
1772 | unsigned long flags; |
1773 | |
1774 | del_timer(timer: &ctx->rx_tmr); |
1775 | spin_lock_irqsave(&vf->fdir.ctx_lock, flags); |
1776 | ctx->flags &= ~ICE_VF_FDIR_CTX_VALID; |
1777 | spin_unlock_irqrestore(lock: &vf->fdir.ctx_lock, flags); |
1778 | } |
1779 | |
1780 | /** |
1781 | * ice_vc_add_fdir_fltr - add a FDIR filter for VF by the msg buffer |
1782 | * @vf: pointer to the VF info |
1783 | * @msg: pointer to the msg buffer |
1784 | * |
1785 | * Return: 0 on success, and other on error. |
1786 | */ |
1787 | int ice_vc_add_fdir_fltr(struct ice_vf *vf, u8 *msg) |
1788 | { |
1789 | struct virtchnl_fdir_add *fltr = (struct virtchnl_fdir_add *)msg; |
1790 | struct virtchnl_fdir_add *stat = NULL; |
1791 | struct virtchnl_fdir_fltr_conf *conf; |
1792 | enum virtchnl_status_code v_ret; |
1793 | struct device *dev; |
1794 | struct ice_pf *pf; |
1795 | int is_tun = 0; |
1796 | int len = 0; |
1797 | int ret; |
1798 | |
1799 | pf = vf->pf; |
1800 | dev = ice_pf_to_dev(pf); |
1801 | ret = ice_vc_fdir_param_check(vf, vsi_id: fltr->vsi_id); |
1802 | if (ret) { |
1803 | v_ret = VIRTCHNL_STATUS_ERR_PARAM; |
1804 | dev_dbg(dev, "Parameter check for VF %d failed\n" , vf->vf_id); |
1805 | goto err_exit; |
1806 | } |
1807 | |
1808 | ret = ice_vf_start_ctrl_vsi(vf); |
1809 | if (ret && (ret != -EEXIST)) { |
1810 | v_ret = VIRTCHNL_STATUS_ERR_PARAM; |
1811 | dev_err(dev, "Init FDIR for VF %d failed, ret:%d\n" , |
1812 | vf->vf_id, ret); |
1813 | goto err_exit; |
1814 | } |
1815 | |
1816 | stat = kzalloc(size: sizeof(*stat), GFP_KERNEL); |
1817 | if (!stat) { |
1818 | v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; |
1819 | dev_dbg(dev, "Alloc stat for VF %d failed\n" , vf->vf_id); |
1820 | goto err_exit; |
1821 | } |
1822 | |
1823 | conf = devm_kzalloc(dev, size: sizeof(*conf), GFP_KERNEL); |
1824 | if (!conf) { |
1825 | v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; |
1826 | dev_dbg(dev, "Alloc conf for VF %d failed\n" , vf->vf_id); |
1827 | goto err_exit; |
1828 | } |
1829 | |
1830 | len = sizeof(*stat); |
1831 | ret = ice_vc_validate_fdir_fltr(vf, fltr, conf); |
1832 | if (ret) { |
1833 | v_ret = VIRTCHNL_STATUS_SUCCESS; |
1834 | stat->status = VIRTCHNL_FDIR_FAILURE_RULE_INVALID; |
1835 | dev_dbg(dev, "Invalid FDIR filter from VF %d\n" , vf->vf_id); |
1836 | goto err_free_conf; |
1837 | } |
1838 | |
1839 | if (fltr->validate_only) { |
1840 | v_ret = VIRTCHNL_STATUS_SUCCESS; |
1841 | stat->status = VIRTCHNL_FDIR_SUCCESS; |
1842 | devm_kfree(dev, p: conf); |
1843 | ret = ice_vc_send_msg_to_vf(vf, v_opcode: VIRTCHNL_OP_ADD_FDIR_FILTER, |
1844 | v_retval: v_ret, msg: (u8 *)stat, msglen: len); |
1845 | goto exit; |
1846 | } |
1847 | |
1848 | ret = ice_vc_fdir_config_input_set(vf, fltr, conf, tun: is_tun); |
1849 | if (ret) { |
1850 | v_ret = VIRTCHNL_STATUS_SUCCESS; |
1851 | stat->status = VIRTCHNL_FDIR_FAILURE_RULE_CONFLICT; |
1852 | dev_err(dev, "VF %d: FDIR input set configure failed, ret:%d\n" , |
1853 | vf->vf_id, ret); |
1854 | goto err_free_conf; |
1855 | } |
1856 | |
1857 | ret = ice_vc_fdir_is_dup_fltr(vf, conf); |
1858 | if (ret) { |
1859 | v_ret = VIRTCHNL_STATUS_SUCCESS; |
1860 | stat->status = VIRTCHNL_FDIR_FAILURE_RULE_EXIST; |
1861 | dev_dbg(dev, "VF %d: duplicated FDIR rule detected\n" , |
1862 | vf->vf_id); |
1863 | goto err_free_conf; |
1864 | } |
1865 | |
1866 | ret = ice_vc_fdir_insert_entry(vf, conf, id: &conf->flow_id); |
1867 | if (ret) { |
1868 | v_ret = VIRTCHNL_STATUS_SUCCESS; |
1869 | stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; |
1870 | dev_dbg(dev, "VF %d: insert FDIR list failed\n" , vf->vf_id); |
1871 | goto err_free_conf; |
1872 | } |
1873 | |
1874 | ret = ice_vc_fdir_set_irq_ctx(vf, conf, v_opcode: VIRTCHNL_OP_ADD_FDIR_FILTER); |
1875 | if (ret) { |
1876 | v_ret = VIRTCHNL_STATUS_SUCCESS; |
1877 | stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; |
1878 | dev_dbg(dev, "VF %d: set FDIR context failed\n" , vf->vf_id); |
1879 | goto err_rem_entry; |
1880 | } |
1881 | |
1882 | ret = ice_vc_fdir_write_fltr(vf, conf, add: true, is_tun); |
1883 | if (ret) { |
1884 | v_ret = VIRTCHNL_STATUS_SUCCESS; |
1885 | stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; |
1886 | dev_err(dev, "VF %d: writing FDIR rule failed, ret:%d\n" , |
1887 | vf->vf_id, ret); |
1888 | goto err_clr_irq; |
1889 | } |
1890 | |
1891 | exit: |
1892 | kfree(objp: stat); |
1893 | return ret; |
1894 | |
1895 | err_clr_irq: |
1896 | ice_vc_fdir_clear_irq_ctx(vf); |
1897 | err_rem_entry: |
1898 | ice_vc_fdir_remove_entry(vf, conf, id: conf->flow_id); |
1899 | err_free_conf: |
1900 | devm_kfree(dev, p: conf); |
1901 | err_exit: |
1902 | ret = ice_vc_send_msg_to_vf(vf, v_opcode: VIRTCHNL_OP_ADD_FDIR_FILTER, v_retval: v_ret, |
1903 | msg: (u8 *)stat, msglen: len); |
1904 | kfree(objp: stat); |
1905 | return ret; |
1906 | } |
1907 | |
1908 | /** |
1909 | * ice_vc_del_fdir_fltr - delete a FDIR filter for VF by the msg buffer |
1910 | * @vf: pointer to the VF info |
1911 | * @msg: pointer to the msg buffer |
1912 | * |
1913 | * Return: 0 on success, and other on error. |
1914 | */ |
1915 | int ice_vc_del_fdir_fltr(struct ice_vf *vf, u8 *msg) |
1916 | { |
1917 | struct virtchnl_fdir_del *fltr = (struct virtchnl_fdir_del *)msg; |
1918 | struct virtchnl_fdir_del *stat = NULL; |
1919 | struct virtchnl_fdir_fltr_conf *conf; |
1920 | enum virtchnl_status_code v_ret; |
1921 | struct device *dev; |
1922 | struct ice_pf *pf; |
1923 | int is_tun = 0; |
1924 | int len = 0; |
1925 | int ret; |
1926 | |
1927 | pf = vf->pf; |
1928 | dev = ice_pf_to_dev(pf); |
1929 | ret = ice_vc_fdir_param_check(vf, vsi_id: fltr->vsi_id); |
1930 | if (ret) { |
1931 | v_ret = VIRTCHNL_STATUS_ERR_PARAM; |
1932 | dev_dbg(dev, "Parameter check for VF %d failed\n" , vf->vf_id); |
1933 | goto err_exit; |
1934 | } |
1935 | |
1936 | stat = kzalloc(size: sizeof(*stat), GFP_KERNEL); |
1937 | if (!stat) { |
1938 | v_ret = VIRTCHNL_STATUS_ERR_NO_MEMORY; |
1939 | dev_dbg(dev, "Alloc stat for VF %d failed\n" , vf->vf_id); |
1940 | goto err_exit; |
1941 | } |
1942 | |
1943 | len = sizeof(*stat); |
1944 | |
1945 | conf = ice_vc_fdir_lookup_entry(vf, id: fltr->flow_id); |
1946 | if (!conf) { |
1947 | v_ret = VIRTCHNL_STATUS_SUCCESS; |
1948 | stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NONEXIST; |
1949 | dev_dbg(dev, "VF %d: FDIR invalid flow_id:0x%X\n" , |
1950 | vf->vf_id, fltr->flow_id); |
1951 | goto err_exit; |
1952 | } |
1953 | |
1954 | /* Just return failure when ctrl_vsi idx is invalid */ |
1955 | if (vf->ctrl_vsi_idx == ICE_NO_VSI) { |
1956 | v_ret = VIRTCHNL_STATUS_SUCCESS; |
1957 | stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; |
1958 | dev_err(dev, "Invalid FDIR ctrl_vsi for VF %d\n" , vf->vf_id); |
1959 | goto err_exit; |
1960 | } |
1961 | |
1962 | ret = ice_vc_fdir_set_irq_ctx(vf, conf, v_opcode: VIRTCHNL_OP_DEL_FDIR_FILTER); |
1963 | if (ret) { |
1964 | v_ret = VIRTCHNL_STATUS_SUCCESS; |
1965 | stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; |
1966 | dev_dbg(dev, "VF %d: set FDIR context failed\n" , vf->vf_id); |
1967 | goto err_exit; |
1968 | } |
1969 | |
1970 | ret = ice_vc_fdir_write_fltr(vf, conf, add: false, is_tun); |
1971 | if (ret) { |
1972 | v_ret = VIRTCHNL_STATUS_SUCCESS; |
1973 | stat->status = VIRTCHNL_FDIR_FAILURE_RULE_NORESOURCE; |
1974 | dev_err(dev, "VF %d: writing FDIR rule failed, ret:%d\n" , |
1975 | vf->vf_id, ret); |
1976 | goto err_del_tmr; |
1977 | } |
1978 | |
1979 | kfree(objp: stat); |
1980 | |
1981 | return ret; |
1982 | |
1983 | err_del_tmr: |
1984 | ice_vc_fdir_clear_irq_ctx(vf); |
1985 | err_exit: |
1986 | ret = ice_vc_send_msg_to_vf(vf, v_opcode: VIRTCHNL_OP_DEL_FDIR_FILTER, v_retval: v_ret, |
1987 | msg: (u8 *)stat, msglen: len); |
1988 | kfree(objp: stat); |
1989 | return ret; |
1990 | } |
1991 | |
1992 | /** |
1993 | * ice_vf_fdir_init - init FDIR resource for VF |
1994 | * @vf: pointer to the VF info |
1995 | */ |
1996 | void ice_vf_fdir_init(struct ice_vf *vf) |
1997 | { |
1998 | struct ice_vf_fdir *fdir = &vf->fdir; |
1999 | |
2000 | idr_init(idr: &fdir->fdir_rule_idr); |
2001 | INIT_LIST_HEAD(list: &fdir->fdir_rule_list); |
2002 | |
2003 | spin_lock_init(&fdir->ctx_lock); |
2004 | fdir->ctx_irq.flags = 0; |
2005 | fdir->ctx_done.flags = 0; |
2006 | ice_vc_fdir_reset_cnt_all(fdir); |
2007 | } |
2008 | |
2009 | /** |
2010 | * ice_vf_fdir_exit - destroy FDIR resource for VF |
2011 | * @vf: pointer to the VF info |
2012 | */ |
2013 | void ice_vf_fdir_exit(struct ice_vf *vf) |
2014 | { |
2015 | ice_vc_fdir_flush_entry(vf); |
2016 | idr_destroy(&vf->fdir.fdir_rule_idr); |
2017 | ice_vc_fdir_rem_prof_all(vf); |
2018 | ice_vc_fdir_free_prof_all(vf); |
2019 | } |
2020 | |