Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2015-2020 Beijing WangXun Technology Co., Ltd.
3 : : * Copyright(c) 2010-2017 Intel Corporation
4 : : */
5 : :
6 : : #include <stdio.h>
7 : : #include <stdint.h>
8 : : #include <stdarg.h>
9 : : #include <errno.h>
10 : : #include <sys/queue.h>
11 : : #include <rte_malloc.h>
12 : :
13 : : #include "txgbe_logs.h"
14 : : #include "base/txgbe.h"
15 : : #include "txgbe_ethdev.h"
16 : :
17 : : #define TXGBE_DEFAULT_FLEXBYTES_OFFSET 12 /*default flexbytes offset in bytes*/
18 : : #define TXGBE_MAX_FLX_SOURCE_OFF 62
19 : : #define TXGBE_FDIRCMD_CMD_INTERVAL_US 10
20 : :
21 : : #define IPV6_ADDR_TO_MASK(ipaddr, ipv6m) do { \
22 : : uint8_t ipv6_addr[16]; \
23 : : uint8_t i; \
24 : : rte_memcpy(ipv6_addr, (ipaddr), sizeof(ipv6_addr));\
25 : : (ipv6m) = 0; \
26 : : for (i = 0; i < sizeof(ipv6_addr); i++) { \
27 : : if (ipv6_addr[i] == UINT8_MAX) \
28 : : (ipv6m) |= 1 << i; \
29 : : else if (ipv6_addr[i] != 0) { \
30 : : PMD_DRV_LOG(ERR, " invalid IPv6 address mask."); \
31 : : return -EINVAL; \
32 : : } \
33 : : } \
34 : : } while (0)
35 : :
36 : : #define IPV6_MASK_TO_ADDR(ipv6m, ipaddr) do { \
37 : : uint8_t ipv6_addr[16]; \
38 : : uint8_t i; \
39 : : for (i = 0; i < sizeof(ipv6_addr); i++) { \
40 : : if ((ipv6m) & (1 << i)) \
41 : : ipv6_addr[i] = UINT8_MAX; \
42 : : else \
43 : : ipv6_addr[i] = 0; \
44 : : } \
45 : : rte_memcpy((ipaddr), ipv6_addr, sizeof(ipv6_addr));\
46 : : } while (0)
47 : :
48 : : /**
49 : : * Initialize Flow Director control registers
50 : : * @hw: pointer to hardware structure
51 : : * @fdirctrl: value to write to flow director control register
52 : : **/
53 : : static int
54 : 0 : txgbe_fdir_enable(struct txgbe_hw *hw, uint32_t fdirctrl)
55 : : {
56 : : int i;
57 : :
58 : 0 : PMD_INIT_FUNC_TRACE();
59 : :
60 : : /* Prime the keys for hashing */
61 : : wr32(hw, TXGBE_FDIRBKTHKEY, TXGBE_ATR_BUCKET_HASH_KEY);
62 : : wr32(hw, TXGBE_FDIRSIGHKEY, TXGBE_ATR_SIGNATURE_HASH_KEY);
63 : :
64 : : /*
65 : : * Continue setup of fdirctrl register bits:
66 : : * Set the maximum length per hash bucket to 0xA filters
67 : : * Send interrupt when 64 filters are left
68 : : */
69 : 0 : fdirctrl |= TXGBE_FDIRCTL_MAXLEN(0xA) |
70 : : TXGBE_FDIRCTL_FULLTHR(4);
71 : :
72 : : /*
73 : : * Poll init-done after we write the register. Estimated times:
74 : : * 10G: PBALLOC = 11b, timing is 60us
75 : : * 1G: PBALLOC = 11b, timing is 600us
76 : : * 100M: PBALLOC = 11b, timing is 6ms
77 : : *
78 : : * Multiple these timings by 4 if under full Rx load
79 : : *
80 : : * So we'll poll for TXGBE_FDIR_INIT_DONE_POLL times, sleeping for
81 : : * 1 msec per poll time. If we're at line rate and drop to 100M, then
82 : : * this might not finish in our poll time, but we can live with that
83 : : * for now.
84 : : */
85 : : wr32(hw, TXGBE_FDIRCTL, fdirctrl);
86 : : txgbe_flush(hw);
87 [ # # ]: 0 : for (i = 0; i < TXGBE_FDIR_INIT_DONE_POLL; i++) {
88 [ # # ]: 0 : if (rd32(hw, TXGBE_FDIRCTL) & TXGBE_FDIRCTL_INITDONE)
89 : : break;
90 : : msec_delay(1);
91 : : }
92 : :
93 [ # # ]: 0 : if (i >= TXGBE_FDIR_INIT_DONE_POLL) {
94 : 0 : PMD_INIT_LOG(ERR, "Flow Director poll time exceeded during enabling!");
95 : 0 : return -ETIMEDOUT;
96 : : }
97 : : return 0;
98 : : }
99 : :
100 : : /*
101 : : * Set appropriate bits in fdirctrl for: variable reporting levels, moving
102 : : * flexbytes matching field, and drop queue (only for perfect matching mode).
103 : : */
104 : : static inline int
105 : 0 : configure_fdir_flags(const struct rte_eth_fdir_conf *conf,
106 : : uint32_t *fdirctrl, uint32_t *flex)
107 : : {
108 : 0 : *fdirctrl = 0;
109 : 0 : *flex = 0;
110 : :
111 [ # # # # ]: 0 : switch (conf->pballoc) {
112 : 0 : case RTE_ETH_FDIR_PBALLOC_64K:
113 : : /* 8k - 1 signature filters */
114 : 0 : *fdirctrl |= TXGBE_FDIRCTL_BUF_64K;
115 : 0 : break;
116 : 0 : case RTE_ETH_FDIR_PBALLOC_128K:
117 : : /* 16k - 1 signature filters */
118 : 0 : *fdirctrl |= TXGBE_FDIRCTL_BUF_128K;
119 : 0 : break;
120 : 0 : case RTE_ETH_FDIR_PBALLOC_256K:
121 : : /* 32k - 1 signature filters */
122 : 0 : *fdirctrl |= TXGBE_FDIRCTL_BUF_256K;
123 : 0 : break;
124 : 0 : default:
125 : : /* bad value */
126 : 0 : PMD_INIT_LOG(ERR, "Invalid fdir_conf->pballoc value");
127 : 0 : return -EINVAL;
128 : : };
129 : :
130 : : /* status flags: write hash & swindex in the rx descriptor */
131 [ # # # # ]: 0 : switch (conf->status) {
132 : : case RTE_FDIR_NO_REPORT_STATUS:
133 : : /* do nothing, default mode */
134 : : break;
135 : 0 : case RTE_FDIR_REPORT_STATUS:
136 : : /* report status when the packet matches a fdir rule */
137 : 0 : *fdirctrl |= TXGBE_FDIRCTL_REPORT_MATCH;
138 : 0 : break;
139 : 0 : case RTE_FDIR_REPORT_STATUS_ALWAYS:
140 : : /* always report status */
141 : 0 : *fdirctrl |= TXGBE_FDIRCTL_REPORT_ALWAYS;
142 : 0 : break;
143 : 0 : default:
144 : : /* bad value */
145 : 0 : PMD_INIT_LOG(ERR, "Invalid fdir_conf->status value");
146 : 0 : return -EINVAL;
147 : : };
148 : :
149 : 0 : *flex |= TXGBE_FDIRFLEXCFG_BASE_MAC;
150 : 0 : *flex |= TXGBE_FDIRFLEXCFG_OFST(TXGBE_DEFAULT_FLEXBYTES_OFFSET / 2);
151 : :
152 [ # # # ]: 0 : switch (conf->mode) {
153 : : case RTE_FDIR_MODE_SIGNATURE:
154 : : break;
155 : 0 : case RTE_FDIR_MODE_PERFECT:
156 : 0 : *fdirctrl |= TXGBE_FDIRCTL_PERFECT;
157 : 0 : *fdirctrl |= TXGBE_FDIRCTL_DROPQP(conf->drop_queue);
158 : 0 : break;
159 : 0 : default:
160 : : /* bad value */
161 : 0 : PMD_INIT_LOG(ERR, "Invalid fdir_conf->mode value");
162 : 0 : return -EINVAL;
163 : : }
164 : :
165 : : return 0;
166 : : }
167 : :
168 : : int
169 : 0 : txgbe_fdir_set_input_mask(struct rte_eth_dev *dev)
170 : : {
171 : 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
172 : : struct txgbe_hw_fdir_info *info = TXGBE_DEV_FDIR(dev);
173 : 0 : enum rte_fdir_mode mode = TXGBE_DEV_FDIR_CONF(dev)->mode;
174 : : /*
175 : : * mask VM pool and DIPv6 since there are currently not supported
176 : : * mask FLEX byte, it will be set in flex_conf
177 : : */
178 : : uint32_t fdirm = TXGBE_FDIRMSK_POOL;
179 : : uint32_t fdirtcpm; /* TCP source and destination port masks. */
180 : : uint32_t fdiripv6m; /* IPv6 source and destination masks. */
181 : :
182 : 0 : PMD_INIT_FUNC_TRACE();
183 : :
184 [ # # ]: 0 : if (mode != RTE_FDIR_MODE_SIGNATURE &&
185 : : mode != RTE_FDIR_MODE_PERFECT) {
186 : 0 : PMD_DRV_LOG(ERR, "Not supported fdir mode - %d!", mode);
187 : 0 : return -ENOTSUP;
188 : : }
189 : :
190 : : /* use the L4 protocol mask for raw IPv4/IPv6 traffic */
191 [ # # ]: 0 : if (info->mask.pkt_type_mask == 0 && info->mask.dst_port_mask == 0 &&
192 : : info->mask.src_port_mask == 0)
193 : 0 : info->mask.pkt_type_mask |= TXGBE_FDIRMSK_L4P;
194 : :
195 : 0 : fdirm |= info->mask.pkt_type_mask;
196 : : wr32(hw, TXGBE_FDIRMSK, fdirm);
197 : :
198 : : /* store the TCP/UDP port masks */
199 [ # # ]: 0 : fdirtcpm = rte_be_to_cpu_16(info->mask.dst_port_mask) << 16;
200 [ # # ]: 0 : fdirtcpm |= rte_be_to_cpu_16(info->mask.src_port_mask);
201 : :
202 : : /* write all the same so that UDP, TCP and SCTP use the same mask
203 : : * (little-endian)
204 : : */
205 : 0 : wr32(hw, TXGBE_FDIRTCPMSK, ~fdirtcpm);
206 : : wr32(hw, TXGBE_FDIRUDPMSK, ~fdirtcpm);
207 : : wr32(hw, TXGBE_FDIRSCTPMSK, ~fdirtcpm);
208 : :
209 : : /* Store source and destination IPv4 masks (big-endian) */
210 : 0 : wr32(hw, TXGBE_FDIRSIP4MSK, ~info->mask.src_ipv4_mask);
211 : 0 : wr32(hw, TXGBE_FDIRDIP4MSK, ~info->mask.dst_ipv4_mask);
212 : :
213 : : /*
214 : : * Store source and destination IPv6 masks (bit reversed)
215 : : */
216 : 0 : fdiripv6m = TXGBE_FDIRIP6MSK_DST(info->mask.dst_ipv6_mask) |
217 : 0 : TXGBE_FDIRIP6MSK_SRC(info->mask.src_ipv6_mask);
218 : 0 : wr32(hw, TXGBE_FDIRIP6MSK, ~fdiripv6m);
219 : :
220 : 0 : return 0;
221 : : }
222 : :
223 : : static int
224 : 0 : txgbe_fdir_store_input_mask(struct rte_eth_dev *dev)
225 : : {
226 : 0 : struct rte_eth_fdir_masks *input_mask = &TXGBE_DEV_FDIR_CONF(dev)->mask;
227 : 0 : enum rte_fdir_mode mode = TXGBE_DEV_FDIR_CONF(dev)->mode;
228 : : struct txgbe_hw_fdir_info *info = TXGBE_DEV_FDIR(dev);
229 : : uint16_t dst_ipv6m = 0;
230 : : uint16_t src_ipv6m = 0;
231 : :
232 [ # # ]: 0 : if (mode != RTE_FDIR_MODE_SIGNATURE &&
233 : : mode != RTE_FDIR_MODE_PERFECT) {
234 : 0 : PMD_DRV_LOG(ERR, "Not supported fdir mode - %d!", mode);
235 : 0 : return -ENOTSUP;
236 : : }
237 : :
238 [ # # ]: 0 : memset(&info->mask, 0, sizeof(struct txgbe_hw_fdir_mask));
239 : 0 : info->mask.vlan_tci_mask = input_mask->vlan_tci_mask;
240 : 0 : info->mask.src_port_mask = input_mask->src_port_mask;
241 : 0 : info->mask.dst_port_mask = input_mask->dst_port_mask;
242 : 0 : info->mask.src_ipv4_mask = input_mask->ipv4_mask.src_ip;
243 : 0 : info->mask.dst_ipv4_mask = input_mask->ipv4_mask.dst_ip;
244 [ # # # # : 0 : IPV6_ADDR_TO_MASK(input_mask->ipv6_mask.src_ip, src_ipv6m);
# # # # ]
245 [ # # # # : 0 : IPV6_ADDR_TO_MASK(input_mask->ipv6_mask.dst_ip, dst_ipv6m);
# # # # ]
246 : 0 : info->mask.src_ipv6_mask = src_ipv6m;
247 : 0 : info->mask.dst_ipv6_mask = dst_ipv6m;
248 : :
249 : 0 : return 0;
250 : : }
251 : :
252 : : uint16_t
253 : 0 : txgbe_fdir_get_flex_base(struct txgbe_fdir_rule *rule)
254 : : {
255 [ # # ]: 0 : if (!rule->flex_relative)
256 : : return TXGBE_FDIRFLEXCFG_BASE_MAC;
257 : :
258 [ # # ]: 0 : if (rule->input.flow_type & TXGBE_ATR_L4TYPE_MASK)
259 : : return TXGBE_FDIRFLEXCFG_BASE_PAY;
260 : :
261 [ # # ]: 0 : if (rule->input.flow_type & TXGBE_ATR_L3TYPE_MASK)
262 : 0 : return TXGBE_FDIRFLEXCFG_BASE_L3;
263 : :
264 : : return TXGBE_FDIRFLEXCFG_BASE_L2;
265 : : }
266 : :
267 : : int
268 : 0 : txgbe_fdir_set_flexbytes_offset(struct rte_eth_dev *dev,
269 : : uint16_t offset, uint16_t flex_base)
270 : : {
271 : 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
272 : : int i;
273 : :
274 [ # # ]: 0 : for (i = 0; i < 64; i++) {
275 : : uint32_t flexreg, flex;
276 : 0 : flexreg = rd32(hw, TXGBE_FDIRFLEXCFG(i / 4));
277 : 0 : flex = flex_base;
278 : 0 : flex |= TXGBE_FDIRFLEXCFG_OFST(offset / 2);
279 : 0 : flexreg &= ~(TXGBE_FDIRFLEXCFG_ALL(~0UL, i % 4));
280 : 0 : flexreg |= TXGBE_FDIRFLEXCFG_ALL(flex, i % 4);
281 : : wr32(hw, TXGBE_FDIRFLEXCFG(i / 4), flexreg);
282 : : }
283 : :
284 : : txgbe_flush(hw);
285 [ # # ]: 0 : for (i = 0; i < TXGBE_FDIR_INIT_DONE_POLL; i++) {
286 [ # # ]: 0 : if (rd32(hw, TXGBE_FDIRCTL) &
287 : : TXGBE_FDIRCTL_INITDONE)
288 : : break;
289 : : msec_delay(1);
290 : : }
291 : 0 : return 0;
292 : : }
293 : :
294 : : /*
295 : : * txgbe_check_fdir_flex_conf -check if the flex payload and mask configuration
296 : : * arguments are valid
297 : : */
298 : : static int
299 : 0 : txgbe_set_fdir_flex_conf(struct rte_eth_dev *dev, uint32_t flex)
300 : : {
301 : : const struct rte_eth_fdir_flex_conf *conf =
302 : 0 : &TXGBE_DEV_FDIR_CONF(dev)->flex_conf;
303 : : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
304 : : struct txgbe_hw_fdir_info *info = TXGBE_DEV_FDIR(dev);
305 : : const struct rte_eth_flex_payload_cfg *flex_cfg;
306 : : const struct rte_eth_fdir_flex_mask *flex_mask;
307 : : uint16_t flexbytes = 0;
308 : : uint16_t i;
309 : :
310 : : if (conf == NULL) {
311 : : PMD_DRV_LOG(ERR, "NULL pointer.");
312 : : return -EINVAL;
313 : : }
314 : :
315 : 0 : flex |= TXGBE_FDIRFLEXCFG_DIA;
316 : :
317 [ # # ]: 0 : for (i = 0; i < conf->nb_payloads; i++) {
318 : 0 : flex_cfg = &conf->flex_set[i];
319 [ # # ]: 0 : if (flex_cfg->type != RTE_ETH_RAW_PAYLOAD) {
320 : 0 : PMD_DRV_LOG(ERR, "unsupported payload type.");
321 : 0 : return -EINVAL;
322 : : }
323 [ # # ]: 0 : if (((flex_cfg->src_offset[0] & 0x1) == 0) &&
324 [ # # # # ]: 0 : (flex_cfg->src_offset[1] == flex_cfg->src_offset[0] + 1) &&
325 : : flex_cfg->src_offset[0] <= TXGBE_MAX_FLX_SOURCE_OFF) {
326 : 0 : flex &= ~TXGBE_FDIRFLEXCFG_OFST_MASK;
327 : 0 : flex |=
328 : 0 : TXGBE_FDIRFLEXCFG_OFST(flex_cfg->src_offset[0] / 2);
329 : : } else {
330 : 0 : PMD_DRV_LOG(ERR, "invalid flexbytes arguments.");
331 : 0 : return -EINVAL;
332 : : }
333 : : }
334 : :
335 [ # # ]: 0 : for (i = 0; i < conf->nb_flexmasks; i++) {
336 : 0 : flex_mask = &conf->flex_mask[i];
337 [ # # ]: 0 : if (flex_mask->flow_type != RTE_ETH_FLOW_UNKNOWN) {
338 : 0 : PMD_DRV_LOG(ERR, "flexmask should be set globally.");
339 : 0 : return -EINVAL;
340 : : }
341 : 0 : flexbytes = (uint16_t)(((flex_mask->mask[1] << 8) & 0xFF00) |
342 : 0 : ((flex_mask->mask[0]) & 0xFF));
343 [ # # ]: 0 : if (flexbytes == UINT16_MAX) {
344 : 0 : flex &= ~TXGBE_FDIRFLEXCFG_DIA;
345 [ # # ]: 0 : } else if (flexbytes != 0) {
346 : : /* TXGBE_FDIRFLEXCFG_DIA is set by default when set mask */
347 : 0 : PMD_DRV_LOG(ERR, " invalid flexbytes mask arguments.");
348 : 0 : return -EINVAL;
349 : : }
350 : : }
351 : :
352 [ # # ]: 0 : info->mask.flex_bytes_mask = flexbytes ? UINT16_MAX : 0;
353 : 0 : info->flex_bytes_offset = (uint8_t)(TXGBD_FDIRFLEXCFG_OFST(flex) * 2);
354 : :
355 [ # # ]: 0 : for (i = 0; i < 64; i++) {
356 : : uint32_t flexreg;
357 : 0 : flexreg = rd32(hw, TXGBE_FDIRFLEXCFG(i / 4));
358 : 0 : flexreg &= ~(TXGBE_FDIRFLEXCFG_ALL(~0UL, i % 4));
359 : 0 : flexreg |= TXGBE_FDIRFLEXCFG_ALL(flex, i % 4);
360 : : wr32(hw, TXGBE_FDIRFLEXCFG(i / 4), flexreg);
361 : : }
362 : : return 0;
363 : : }
364 : :
365 : : int
366 : 0 : txgbe_fdir_configure(struct rte_eth_dev *dev)
367 : : {
368 : 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
369 : : int err;
370 : : uint32_t fdirctrl, flex, pbsize;
371 : : int i;
372 : 0 : enum rte_fdir_mode mode = TXGBE_DEV_FDIR_CONF(dev)->mode;
373 : :
374 : 0 : PMD_INIT_FUNC_TRACE();
375 : :
376 : : /* supports mac-vlan and tunnel mode */
377 [ # # ]: 0 : if (mode != RTE_FDIR_MODE_SIGNATURE &&
378 : : mode != RTE_FDIR_MODE_PERFECT)
379 : : return -ENOSYS;
380 : :
381 : 0 : err = configure_fdir_flags(TXGBE_DEV_FDIR_CONF(dev), &fdirctrl, &flex);
382 [ # # ]: 0 : if (err)
383 : : return err;
384 : :
385 : : /*
386 : : * Before enabling Flow Director, the Rx Packet Buffer size
387 : : * must be reduced. The new value is the current size minus
388 : : * flow director memory usage size.
389 : : */
390 : : pbsize = rd32(hw, TXGBE_PBRXSIZE(0));
391 : 0 : pbsize -= TXGBD_FDIRCTL_BUF_BYTE(fdirctrl);
392 : : wr32(hw, TXGBE_PBRXSIZE(0), pbsize);
393 : :
394 : : /*
395 : : * The defaults in the HW for RX PB 1-7 are not zero and so should be
396 : : * initialized to zero for non DCB mode otherwise actual total RX PB
397 : : * would be bigger than programmed and filter space would run into
398 : : * the PB 0 region.
399 : : */
400 [ # # ]: 0 : for (i = 1; i < 8; i++)
401 : 0 : wr32(hw, TXGBE_PBRXSIZE(i), 0);
402 : :
403 : 0 : err = txgbe_fdir_store_input_mask(dev);
404 [ # # ]: 0 : if (err < 0) {
405 : 0 : PMD_INIT_LOG(ERR, " Error on setting FD mask");
406 : 0 : return err;
407 : : }
408 : :
409 : 0 : err = txgbe_fdir_set_input_mask(dev);
410 [ # # ]: 0 : if (err < 0) {
411 : 0 : PMD_INIT_LOG(ERR, " Error on setting FD mask");
412 : 0 : return err;
413 : : }
414 : :
415 : 0 : err = txgbe_set_fdir_flex_conf(dev, flex);
416 [ # # ]: 0 : if (err < 0) {
417 : 0 : PMD_INIT_LOG(ERR, " Error on setting FD flexible arguments.");
418 : 0 : return err;
419 : : }
420 : :
421 : 0 : err = txgbe_fdir_enable(hw, fdirctrl);
422 [ # # ]: 0 : if (err < 0) {
423 : 0 : PMD_INIT_LOG(ERR, " Error on enabling FD.");
424 : 0 : return err;
425 : : }
426 : : return 0;
427 : : }
428 : :
429 : : /*
430 : : * Note that the bkt_hash field in the txgbe_atr_input structure is also never
431 : : * set.
432 : : *
433 : : * Compute the hashes for SW ATR
434 : : * @stream: input bitstream to compute the hash on
435 : : * @key: 32-bit hash key
436 : : **/
437 : : static uint32_t
438 : 0 : txgbe_atr_compute_hash(struct txgbe_atr_input *atr_input,
439 : : uint32_t key)
440 : : {
441 : : /*
442 : : * The algorithm is as follows:
443 : : * Hash[15:0] = Sum { S[n] x K[n+16] }, n = 0...350
444 : : * where Sum {A[n]}, n = 0...n is bitwise XOR of A[0], A[1]...A[n]
445 : : * and A[n] x B[n] is bitwise AND between same length strings
446 : : *
447 : : * K[n] is 16 bits, defined as:
448 : : * for n modulo 32 >= 15, K[n] = K[n % 32 : (n % 32) - 15]
449 : : * for n modulo 32 < 15, K[n] =
450 : : * K[(n % 32:0) | (31:31 - (14 - (n % 32)))]
451 : : *
452 : : * S[n] is 16 bits, defined as:
453 : : * for n >= 15, S[n] = S[n:n - 15]
454 : : * for n < 15, S[n] = S[(n:0) | (350:350 - (14 - n))]
455 : : *
456 : : * To simplify for programming, the algorithm is implemented
457 : : * in software this way:
458 : : *
459 : : * key[31:0], hi_hash_dword[31:0], lo_hash_dword[31:0], hash[15:0]
460 : : *
461 : : * for (i = 0; i < 352; i+=32)
462 : : * hi_hash_dword[31:0] ^= Stream[(i+31):i];
463 : : *
464 : : * lo_hash_dword[15:0] ^= Stream[15:0];
465 : : * lo_hash_dword[15:0] ^= hi_hash_dword[31:16];
466 : : * lo_hash_dword[31:16] ^= hi_hash_dword[15:0];
467 : : *
468 : : * hi_hash_dword[31:0] ^= Stream[351:320];
469 : : *
470 : : * if (key[0])
471 : : * hash[15:0] ^= Stream[15:0];
472 : : *
473 : : * for (i = 0; i < 16; i++) {
474 : : * if (key[i])
475 : : * hash[15:0] ^= lo_hash_dword[(i+15):i];
476 : : * if (key[i + 16])
477 : : * hash[15:0] ^= hi_hash_dword[(i+15):i];
478 : : * }
479 : : *
480 : : */
481 : : __be32 *dword_stream = (__be32 *)atr_input;
482 : : __be32 common_hash_dword = 0;
483 : : u32 hi_hash_dword, lo_hash_dword, flow_pool_ptid;
484 : : u32 hash_result = 0;
485 : : u8 i;
486 : :
487 : : /* record the flow_vm_vlan bits as they are a key part to the hash */
488 [ # # ]: 0 : flow_pool_ptid = be_to_cpu32(dword_stream[0]);
489 : :
490 : : /* generate common hash dword */
491 [ # # ]: 0 : for (i = 1; i <= 10; i++)
492 : 0 : common_hash_dword ^= dword_stream[i];
493 : :
494 [ # # ]: 0 : hi_hash_dword = be_to_cpu32(common_hash_dword);
495 : :
496 : : /* low dword is word swapped version of common */
497 : 0 : lo_hash_dword = (hi_hash_dword >> 16) | (hi_hash_dword << 16);
498 : :
499 : : /* apply (Flow ID/VM Pool/Packet Type) bits to hash words */
500 : 0 : hi_hash_dword ^= flow_pool_ptid ^ (flow_pool_ptid >> 16);
501 : :
502 : : /* Process bits 0 and 16 */
503 [ # # ]: 0 : if (key & 0x0001)
504 : : hash_result ^= lo_hash_dword;
505 [ # # ]: 0 : if (key & 0x00010000)
506 : 0 : hash_result ^= hi_hash_dword;
507 : :
508 : : /*
509 : : * apply flow ID/VM pool/VLAN ID bits to lo hash dword, we had to
510 : : * delay this because bit 0 of the stream should not be processed
511 : : * so we do not add the vlan until after bit 0 was processed
512 : : */
513 : 0 : lo_hash_dword ^= flow_pool_ptid ^ (flow_pool_ptid << 16);
514 : :
515 : : /* process the remaining 30 bits in the key 2 bits at a time */
516 [ # # ]: 0 : for (i = 15; i; i--) {
517 [ # # ]: 0 : if (key & (0x0001 << i))
518 : 0 : hash_result ^= lo_hash_dword >> i;
519 [ # # ]: 0 : if (key & (0x00010000 << i))
520 : 0 : hash_result ^= hi_hash_dword >> i;
521 : : }
522 : :
523 : 0 : return hash_result;
524 : : }
525 : :
526 : : static uint32_t
527 : : atr_compute_perfect_hash(struct txgbe_atr_input *input,
528 : : enum rte_eth_fdir_pballoc_type pballoc)
529 : : {
530 : : uint32_t bucket_hash;
531 : :
532 : 0 : bucket_hash = txgbe_atr_compute_hash(input,
533 : : TXGBE_ATR_BUCKET_HASH_KEY);
534 [ # # ]: 0 : if (pballoc == RTE_ETH_FDIR_PBALLOC_256K)
535 : 0 : bucket_hash &= PERFECT_BUCKET_256KB_HASH_MASK;
536 [ # # ]: 0 : else if (pballoc == RTE_ETH_FDIR_PBALLOC_128K)
537 : 0 : bucket_hash &= PERFECT_BUCKET_128KB_HASH_MASK;
538 : : else
539 : 0 : bucket_hash &= PERFECT_BUCKET_64KB_HASH_MASK;
540 : :
541 : : return TXGBE_FDIRPIHASH_BKT(bucket_hash);
542 : : }
543 : :
544 : : /**
545 : : * txgbe_fdir_check_cmd_complete - poll to check whether FDIRPICMD is complete
546 : : * @hw: pointer to hardware structure
547 : : */
548 : : static inline int
549 : : txgbe_fdir_check_cmd_complete(struct txgbe_hw *hw, uint32_t *fdircmd)
550 : : {
551 : : int i;
552 : :
553 [ # # # # : 0 : for (i = 0; i < TXGBE_FDIRCMD_CMD_POLL; i++) {
# # # # ]
554 : : *fdircmd = rd32(hw, TXGBE_FDIRPICMD);
555 [ # # # # : 0 : if (!(*fdircmd & TXGBE_FDIRPICMD_OP_MASK))
# # # # ]
556 : : return 0;
557 : 0 : rte_delay_us(TXGBE_FDIRCMD_CMD_INTERVAL_US);
558 : : }
559 : :
560 : : return -ETIMEDOUT;
561 : : }
562 : :
563 : : /*
564 : : * Calculate the hash value needed for signature-match filters. In the FreeBSD
565 : : * driver, this is done by the optimised function
566 : : * txgbe_atr_compute_sig_hash_raptor(). However that can't be used here as it
567 : : * doesn't support calculating a hash for an IPv6 filter.
568 : : */
569 : : static uint32_t
570 : 0 : atr_compute_signature_hash(struct txgbe_atr_input *input,
571 : : enum rte_eth_fdir_pballoc_type pballoc)
572 : : {
573 : : uint32_t bucket_hash, sig_hash;
574 : :
575 : 0 : bucket_hash = txgbe_atr_compute_hash(input,
576 : : TXGBE_ATR_BUCKET_HASH_KEY);
577 [ # # ]: 0 : if (pballoc == RTE_ETH_FDIR_PBALLOC_256K)
578 : 0 : bucket_hash &= SIG_BUCKET_256KB_HASH_MASK;
579 [ # # ]: 0 : else if (pballoc == RTE_ETH_FDIR_PBALLOC_128K)
580 : 0 : bucket_hash &= SIG_BUCKET_128KB_HASH_MASK;
581 : : else
582 : 0 : bucket_hash &= SIG_BUCKET_64KB_HASH_MASK;
583 : :
584 : 0 : sig_hash = txgbe_atr_compute_hash(input,
585 : : TXGBE_ATR_SIGNATURE_HASH_KEY);
586 : :
587 : 0 : return TXGBE_FDIRPIHASH_SIG(sig_hash) |
588 : : TXGBE_FDIRPIHASH_BKT(bucket_hash);
589 : : }
590 : :
591 : : /**
592 : : * With the ability to set extra flags in FDIRPICMD register
593 : : * added, and IPv6 support also added. The hash value is also pre-calculated
594 : : * as the pballoc value is needed to do it.
595 : : */
596 : : static int
597 : 0 : fdir_write_perfect_filter(struct txgbe_hw *hw,
598 : : struct txgbe_atr_input *input, uint8_t queue,
599 : : uint32_t fdircmd, uint32_t fdirhash,
600 : : enum rte_fdir_mode mode)
601 : : {
602 : : uint32_t fdirport, fdirflex;
603 : : int err = 0;
604 : :
605 : : UNREFERENCED_PARAMETER(mode);
606 : :
607 : : /* record the IPv4 address (little-endian)
608 : : * can not use wr32.
609 : : */
610 [ # # ]: 0 : wr32(hw, TXGBE_FDIRPISIP4, be_to_le32(input->src_ip[0]));
611 [ # # ]: 0 : wr32(hw, TXGBE_FDIRPIDIP4, be_to_le32(input->dst_ip[0]));
612 : :
613 : : /* record source and destination port (little-endian)*/
614 [ # # ]: 0 : fdirport = TXGBE_FDIRPIPORT_DST(be_to_le16(input->dst_port));
615 [ # # ]: 0 : fdirport |= TXGBE_FDIRPIPORT_SRC(be_to_le16(input->src_port));
616 : : wr32(hw, TXGBE_FDIRPIPORT, fdirport);
617 : :
618 : : /* record pkt_type (little-endian) and flex_bytes(big-endian) */
619 [ # # ]: 0 : fdirflex = TXGBE_FDIRPIFLEX_FLEX(be_to_npu16(input->flex_bytes));
620 [ # # ]: 0 : fdirflex |= TXGBE_FDIRPIFLEX_PTYPE(be_to_le16(input->pkt_type));
621 : : wr32(hw, TXGBE_FDIRPIFLEX, fdirflex);
622 : :
623 : : /* configure FDIRHASH register */
624 : 0 : fdirhash |= TXGBE_FDIRPIHASH_VLD;
625 : : wr32(hw, TXGBE_FDIRPIHASH, fdirhash);
626 : :
627 : : /*
628 : : * flush all previous writes to make certain registers are
629 : : * programmed prior to issuing the command
630 : : */
631 : : txgbe_flush(hw);
632 : :
633 : : /* configure FDIRPICMD register */
634 : 0 : fdircmd |= TXGBE_FDIRPICMD_OP_ADD |
635 : : TXGBE_FDIRPICMD_UPD |
636 : : TXGBE_FDIRPICMD_LAST |
637 : : TXGBE_FDIRPICMD_QPENA;
638 : 0 : fdircmd |= TXGBE_FDIRPICMD_FT(input->flow_type);
639 : 0 : fdircmd |= TXGBE_FDIRPICMD_QP(queue);
640 : 0 : fdircmd |= TXGBE_FDIRPICMD_POOL(input->vm_pool);
641 : :
642 [ # # ]: 0 : if (input->flow_type & TXGBE_ATR_L3TYPE_IPV6)
643 : 0 : fdircmd |= TXGBE_FDIRPICMD_IP6;
644 : : wr32(hw, TXGBE_FDIRPICMD, fdircmd);
645 : :
646 : 0 : PMD_DRV_LOG(DEBUG, "Rx Queue=%x hash=%x", queue, fdirhash);
647 : :
648 : : err = txgbe_fdir_check_cmd_complete(hw, &fdircmd);
649 [ # # ]: 0 : if (err < 0)
650 : 0 : PMD_DRV_LOG(ERR, "Timeout writing flow director filter.");
651 : :
652 : 0 : return err;
653 : : }
654 : :
655 : : /**
656 : : * This function supports setting extra fields in the FDIRPICMD register, and
657 : : * removes the code that was verifying the flow_type field. According to the
658 : : * documentation, a flow type of 00 (i.e. not TCP, UDP, or SCTP) is not
659 : : * supported, however it appears to work ok...
660 : : * Adds a signature hash filter
661 : : * @hw: pointer to hardware structure
662 : : * @input: unique input dword
663 : : * @queue: queue index to direct traffic to
664 : : * @fdircmd: any extra flags to set in fdircmd register
665 : : * @fdirhash: pre-calculated hash value for the filter
666 : : **/
667 : : static int
668 : 0 : fdir_add_signature_filter(struct txgbe_hw *hw,
669 : : struct txgbe_atr_input *input, uint8_t queue, uint32_t fdircmd,
670 : : uint32_t fdirhash)
671 : : {
672 : : int err = 0;
673 : :
674 : 0 : PMD_INIT_FUNC_TRACE();
675 : :
676 : : /* configure FDIRPICMD register */
677 : 0 : fdircmd |= TXGBE_FDIRPICMD_OP_ADD |
678 : : TXGBE_FDIRPICMD_UPD |
679 : : TXGBE_FDIRPICMD_LAST |
680 : : TXGBE_FDIRPICMD_QPENA;
681 : 0 : fdircmd |= TXGBE_FDIRPICMD_FT(input->flow_type);
682 : 0 : fdircmd |= TXGBE_FDIRPICMD_QP(queue);
683 : :
684 : 0 : fdirhash |= TXGBE_FDIRPIHASH_VLD;
685 : : wr32(hw, TXGBE_FDIRPIHASH, fdirhash);
686 : : wr32(hw, TXGBE_FDIRPICMD, fdircmd);
687 : :
688 : 0 : PMD_DRV_LOG(DEBUG, "Rx Queue=%x hash=%x", queue, fdirhash);
689 : :
690 : : err = txgbe_fdir_check_cmd_complete(hw, &fdircmd);
691 [ # # ]: 0 : if (err < 0)
692 : 0 : PMD_DRV_LOG(ERR, "Timeout writing flow director filter.");
693 : :
694 : 0 : return err;
695 : : }
696 : :
697 : : /*
698 : : * This is modified to take in the hash as a parameter so that
699 : : * it can be used for removing signature and perfect filters.
700 : : */
701 : : static int
702 : 0 : fdir_erase_filter_raptor(struct txgbe_hw *hw, uint32_t fdirhash)
703 : : {
704 : : uint32_t fdircmd = 0;
705 : : int err = 0;
706 : :
707 : : wr32(hw, TXGBE_FDIRPIHASH, fdirhash);
708 : :
709 : : /* flush hash to HW */
710 : : txgbe_flush(hw);
711 : :
712 : : /* Query if filter is present */
713 : : wr32(hw, TXGBE_FDIRPICMD, TXGBE_FDIRPICMD_OP_QRY);
714 : :
715 : : err = txgbe_fdir_check_cmd_complete(hw, &fdircmd);
716 [ # # ]: 0 : if (err < 0) {
717 : 0 : PMD_INIT_LOG(ERR, "Timeout querying for flow director filter.");
718 : 0 : return err;
719 : : }
720 : :
721 : : /* if filter exists in hardware then remove it */
722 [ # # ]: 0 : if (fdircmd & TXGBE_FDIRPICMD_VLD) {
723 : : wr32(hw, TXGBE_FDIRPIHASH, fdirhash);
724 : : txgbe_flush(hw);
725 : : wr32(hw, TXGBE_FDIRPICMD, TXGBE_FDIRPICMD_OP_REM);
726 : : }
727 : :
728 : : err = txgbe_fdir_check_cmd_complete(hw, &fdircmd);
729 [ # # ]: 0 : if (err < 0)
730 : 0 : PMD_INIT_LOG(ERR, "Timeout erasing flow director filter.");
731 : :
732 : : return err;
733 : : }
734 : :
735 : : static inline struct txgbe_fdir_filter *
736 : : txgbe_fdir_filter_lookup(struct txgbe_hw_fdir_info *fdir_info,
737 : : struct txgbe_atr_input *input)
738 : : {
739 : : int ret;
740 : :
741 : 0 : ret = rte_hash_lookup(fdir_info->hash_handle, (const void *)input);
742 [ # # ]: 0 : if (ret < 0)
743 : : return NULL;
744 : :
745 : 0 : return fdir_info->hash_map[ret];
746 : : }
747 : :
748 : : static inline int
749 : 0 : txgbe_insert_fdir_filter(struct txgbe_hw_fdir_info *fdir_info,
750 : : struct txgbe_fdir_filter *fdir_filter)
751 : : {
752 : : int ret;
753 : :
754 : 0 : ret = rte_hash_add_key(fdir_info->hash_handle, &fdir_filter->input);
755 [ # # ]: 0 : if (ret < 0) {
756 : 0 : PMD_DRV_LOG(ERR,
757 : : "Failed to insert fdir filter to hash table %d!",
758 : : ret);
759 : 0 : return ret;
760 : : }
761 : :
762 : 0 : fdir_info->hash_map[ret] = fdir_filter;
763 : :
764 : 0 : TAILQ_INSERT_TAIL(&fdir_info->fdir_list, fdir_filter, entries);
765 : :
766 : 0 : return 0;
767 : : }
768 : :
769 : : static inline int
770 : 0 : txgbe_remove_fdir_filter(struct txgbe_hw_fdir_info *fdir_info,
771 : : struct txgbe_atr_input *input)
772 : : {
773 : : int ret;
774 : : struct txgbe_fdir_filter *fdir_filter;
775 : :
776 : 0 : ret = rte_hash_del_key(fdir_info->hash_handle, input);
777 [ # # ]: 0 : if (ret < 0)
778 : : return ret;
779 : :
780 : 0 : fdir_filter = fdir_info->hash_map[ret];
781 : 0 : fdir_info->hash_map[ret] = NULL;
782 : :
783 [ # # ]: 0 : TAILQ_REMOVE(&fdir_info->fdir_list, fdir_filter, entries);
784 : 0 : rte_free(fdir_filter);
785 : :
786 : 0 : return 0;
787 : : }
788 : :
789 : : int
790 : 0 : txgbe_fdir_filter_program(struct rte_eth_dev *dev,
791 : : struct txgbe_fdir_rule *rule,
792 : : bool del,
793 : : bool update)
794 : : {
795 : 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
796 : : uint32_t fdirhash;
797 : : uint8_t queue;
798 : : bool is_perfect = FALSE;
799 : : int err;
800 : 0 : struct txgbe_hw_fdir_info *info = TXGBE_DEV_FDIR(dev);
801 : 0 : enum rte_fdir_mode fdir_mode = TXGBE_DEV_FDIR_CONF(dev)->mode;
802 : : struct txgbe_fdir_filter *node;
803 : :
804 [ # # ]: 0 : if (fdir_mode == RTE_FDIR_MODE_NONE ||
805 [ # # ]: 0 : fdir_mode != rule->mode)
806 : : return -ENOTSUP;
807 : :
808 [ # # ]: 0 : if (fdir_mode >= RTE_FDIR_MODE_PERFECT)
809 : : is_perfect = TRUE;
810 : :
811 : : if (is_perfect) {
812 : 0 : fdirhash = atr_compute_perfect_hash(&rule->input,
813 : : TXGBE_DEV_FDIR_CONF(dev)->pballoc);
814 : 0 : fdirhash |= TXGBE_FDIRPIHASH_IDX(rule->soft_id);
815 : : } else {
816 : 0 : fdirhash = atr_compute_signature_hash(&rule->input,
817 : : TXGBE_DEV_FDIR_CONF(dev)->pballoc);
818 : : }
819 : :
820 [ # # ]: 0 : if (del) {
821 : 0 : err = txgbe_remove_fdir_filter(info, &rule->input);
822 [ # # ]: 0 : if (err < 0) {
823 : 0 : PMD_DRV_LOG(ERR,
824 : : "No such fdir filter to delete %d!", err);
825 : 0 : return err;
826 : : }
827 : :
828 : 0 : err = fdir_erase_filter_raptor(hw, fdirhash);
829 [ # # ]: 0 : if (err < 0)
830 : 0 : PMD_DRV_LOG(ERR, "Fail to delete FDIR filter!");
831 : : else
832 : 0 : PMD_DRV_LOG(DEBUG, "Success to delete FDIR filter!");
833 : 0 : return err;
834 : : }
835 : :
836 : : /* add or update an fdir filter*/
837 [ # # ]: 0 : if (rule->fdirflags & TXGBE_FDIRPICMD_DROP) {
838 [ # # ]: 0 : if (!is_perfect) {
839 : 0 : PMD_DRV_LOG(ERR, "Drop option is not supported in"
840 : : " signature mode.");
841 : 0 : return -EINVAL;
842 : : }
843 : 0 : queue = TXGBE_DEV_FDIR_CONF(dev)->drop_queue;
844 [ # # ]: 0 : } else if (rule->queue < TXGBE_MAX_RX_QUEUE_NUM) {
845 : : queue = rule->queue;
846 : : } else {
847 : : return -EINVAL;
848 : : }
849 : :
850 [ # # ]: 0 : if (RTE_ETH_DEV_SRIOV(dev).active)
851 : 0 : queue = RTE_ETH_DEV_SRIOV(dev).def_pool_q_idx + queue;
852 : :
853 : 0 : node = txgbe_fdir_filter_lookup(info, &rule->input);
854 [ # # ]: 0 : if (node) {
855 [ # # ]: 0 : if (!update) {
856 : 0 : PMD_DRV_LOG(ERR, "Conflict with existing fdir filter!");
857 : 0 : return -EINVAL;
858 : : }
859 : 0 : node->fdirflags = rule->fdirflags;
860 : 0 : node->fdirhash = fdirhash;
861 : 0 : node->queue = queue;
862 : : } else {
863 : 0 : node = rte_zmalloc("txgbe_fdir",
864 : : sizeof(struct txgbe_fdir_filter), 0);
865 [ # # ]: 0 : if (!node)
866 : : return -ENOMEM;
867 [ # # ]: 0 : rte_memcpy(&node->input, &rule->input,
868 : : sizeof(struct txgbe_atr_input));
869 : 0 : node->fdirflags = rule->fdirflags;
870 : 0 : node->fdirhash = fdirhash;
871 : 0 : node->queue = queue;
872 : :
873 : 0 : err = txgbe_insert_fdir_filter(info, node);
874 [ # # ]: 0 : if (err < 0) {
875 : 0 : rte_free(node);
876 : 0 : return err;
877 : : }
878 : : }
879 : :
880 [ # # ]: 0 : if (is_perfect)
881 : 0 : err = fdir_write_perfect_filter(hw, &node->input,
882 : 0 : node->queue, node->fdirflags,
883 : : node->fdirhash, fdir_mode);
884 : : else
885 : 0 : err = fdir_add_signature_filter(hw, &node->input,
886 : 0 : node->queue, node->fdirflags,
887 : : node->fdirhash);
888 [ # # ]: 0 : if (err < 0) {
889 : 0 : PMD_DRV_LOG(ERR, "Fail to add FDIR filter!");
890 : 0 : txgbe_remove_fdir_filter(info, &rule->input);
891 : : } else {
892 : 0 : PMD_DRV_LOG(DEBUG, "Success to add FDIR filter");
893 : : }
894 : :
895 : : return err;
896 : : }
897 : :
898 : : static int
899 : 0 : txgbe_fdir_flush(struct rte_eth_dev *dev)
900 : : {
901 : 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
902 : : struct txgbe_hw_fdir_info *info = TXGBE_DEV_FDIR(dev);
903 : : int ret;
904 : :
905 : 0 : ret = txgbe_reinit_fdir_tables(hw);
906 [ # # ]: 0 : if (ret < 0) {
907 : 0 : PMD_INIT_LOG(ERR, "Failed to re-initialize FD table.");
908 : 0 : return ret;
909 : : }
910 : :
911 : 0 : info->f_add = 0;
912 : 0 : info->f_remove = 0;
913 : 0 : info->add = 0;
914 : 0 : info->remove = 0;
915 : :
916 : 0 : memset(&info->mask, 0, sizeof(struct txgbe_hw_fdir_mask));
917 : 0 : info->mask_added = false;
918 : 0 : info->flex_relative = false;
919 : 0 : info->flex_bytes_offset = 0;
920 : :
921 : 0 : return ret;
922 : : }
923 : :
924 : : /* restore flow director filter */
925 : : void
926 : 0 : txgbe_fdir_filter_restore(struct rte_eth_dev *dev)
927 : : {
928 : 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
929 : : struct txgbe_hw_fdir_info *fdir_info = TXGBE_DEV_FDIR(dev);
930 : : struct txgbe_fdir_filter *node;
931 : : bool is_perfect = FALSE;
932 : 0 : enum rte_fdir_mode fdir_mode = TXGBE_DEV_FDIR_CONF(dev)->mode;
933 : :
934 [ # # ]: 0 : if (fdir_mode >= RTE_FDIR_MODE_PERFECT &&
935 : : fdir_mode <= RTE_FDIR_MODE_PERFECT_TUNNEL)
936 : : is_perfect = TRUE;
937 : :
938 : : if (is_perfect) {
939 [ # # ]: 0 : TAILQ_FOREACH(node, &fdir_info->fdir_list, entries) {
940 : 0 : (void)fdir_write_perfect_filter(hw,
941 : : &node->input,
942 : 0 : node->queue,
943 : : node->fdirflags,
944 : : node->fdirhash,
945 : : fdir_mode);
946 : : }
947 : : } else {
948 [ # # ]: 0 : TAILQ_FOREACH(node, &fdir_info->fdir_list, entries) {
949 : 0 : (void)fdir_add_signature_filter(hw,
950 : : &node->input,
951 : 0 : node->queue,
952 : : node->fdirflags,
953 : : node->fdirhash);
954 : : }
955 : : }
956 : 0 : }
957 : :
958 : : /* remove all the flow director filters */
959 : : int
960 : 0 : txgbe_clear_all_fdir_filter(struct rte_eth_dev *dev)
961 : : {
962 : 0 : struct txgbe_hw_fdir_info *fdir_info = TXGBE_DEV_FDIR(dev);
963 : : struct txgbe_fdir_filter *fdir_filter;
964 : : struct txgbe_fdir_filter *filter_flag;
965 : : int ret = 0;
966 : :
967 : : /* flush flow director */
968 : 0 : rte_hash_reset(fdir_info->hash_handle);
969 : 0 : memset(fdir_info->hash_map, 0,
970 : : sizeof(struct txgbe_fdir_filter *) * TXGBE_MAX_FDIR_FILTER_NUM);
971 : 0 : filter_flag = TAILQ_FIRST(&fdir_info->fdir_list);
972 [ # # ]: 0 : while ((fdir_filter = TAILQ_FIRST(&fdir_info->fdir_list))) {
973 [ # # ]: 0 : TAILQ_REMOVE(&fdir_info->fdir_list,
974 : : fdir_filter,
975 : : entries);
976 : 0 : rte_free(fdir_filter);
977 : : }
978 : :
979 [ # # ]: 0 : if (filter_flag != NULL)
980 : 0 : ret = txgbe_fdir_flush(dev);
981 : :
982 : 0 : return ret;
983 : : }
|