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 : : static inline uint16_t
169 : 0 : txgbe_reverse_fdir_bitmasks(uint16_t mask)
170 : : {
171 : 0 : mask = ((mask & 0x5555) << 1) | ((mask & 0xAAAA) >> 1);
172 : 0 : mask = ((mask & 0x3333) << 2) | ((mask & 0xCCCC) >> 2);
173 : 0 : mask = ((mask & 0x0F0F) << 4) | ((mask & 0xF0F0) >> 4);
174 : 0 : return ((mask & 0x00FF) << 8) | ((mask & 0xFF00) >> 8);
175 : : }
176 : :
177 : : int
178 : 0 : txgbe_fdir_set_input_mask(struct rte_eth_dev *dev)
179 : : {
180 : 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
181 : : struct txgbe_hw_fdir_info *info = TXGBE_DEV_FDIR(dev);
182 : 0 : enum rte_fdir_mode mode = TXGBE_DEV_FDIR_CONF(dev)->mode;
183 : : /*
184 : : * mask VM pool and DIPv6 since there are currently not supported
185 : : * mask FLEX byte, it will be set in flex_conf
186 : : */
187 : : uint32_t fdirm = TXGBE_FDIRMSK_POOL;
188 : : uint32_t fdirtcpm; /* TCP source and destination port masks. */
189 : : uint32_t fdiripv6m; /* IPv6 source and destination masks. */
190 : :
191 : 0 : PMD_INIT_FUNC_TRACE();
192 : :
193 [ # # ]: 0 : if (mode != RTE_FDIR_MODE_SIGNATURE &&
194 : : mode != RTE_FDIR_MODE_PERFECT) {
195 : 0 : PMD_DRV_LOG(ERR, "Not supported fdir mode - %d!", mode);
196 : 0 : return -ENOTSUP;
197 : : }
198 : :
199 : : /* use the L4 protocol mask for raw IPv4/IPv6 traffic */
200 [ # # ]: 0 : if (info->mask.pkt_type_mask == 0 && info->mask.dst_port_mask == 0 &&
201 : : info->mask.src_port_mask == 0)
202 : 0 : info->mask.pkt_type_mask |= TXGBE_FDIRMSK_L4P;
203 : :
204 : 0 : fdirm |= info->mask.pkt_type_mask;
205 : : wr32(hw, TXGBE_FDIRMSK, fdirm);
206 : :
207 : : /* store the TCP/UDP port masks */
208 [ # # ]: 0 : fdirtcpm = rte_be_to_cpu_16(info->mask.dst_port_mask) << 16;
209 [ # # ]: 0 : fdirtcpm |= rte_be_to_cpu_16(info->mask.src_port_mask);
210 : :
211 : : /* write all the same so that UDP, TCP and SCTP use the same mask
212 : : * (little-endian)
213 : : */
214 : 0 : wr32(hw, TXGBE_FDIRTCPMSK, ~fdirtcpm);
215 : : wr32(hw, TXGBE_FDIRUDPMSK, ~fdirtcpm);
216 : : wr32(hw, TXGBE_FDIRSCTPMSK, ~fdirtcpm);
217 : :
218 : : /* Store source and destination IPv4 masks (little-endian) */
219 [ # # ]: 0 : wr32(hw, TXGBE_FDIRSIP4MSK, rte_be_to_cpu_32(~info->mask.src_ipv4_mask));
220 [ # # ]: 0 : wr32(hw, TXGBE_FDIRDIP4MSK, rte_be_to_cpu_32(~info->mask.dst_ipv4_mask));
221 : :
222 : : /*
223 : : * Store source and destination IPv6 masks (bit reversed)
224 : : */
225 : 0 : fdiripv6m = txgbe_reverse_fdir_bitmasks(info->mask.dst_ipv6_mask) << 16;
226 : 0 : fdiripv6m |= txgbe_reverse_fdir_bitmasks(info->mask.src_ipv6_mask);
227 : 0 : wr32(hw, TXGBE_FDIRIP6MSK, ~fdiripv6m);
228 : :
229 : 0 : return 0;
230 : : }
231 : :
232 : : static int
233 : 0 : txgbe_fdir_store_input_mask(struct rte_eth_dev *dev)
234 : : {
235 : 0 : struct rte_eth_fdir_masks *input_mask = &TXGBE_DEV_FDIR_CONF(dev)->mask;
236 : 0 : enum rte_fdir_mode mode = TXGBE_DEV_FDIR_CONF(dev)->mode;
237 : : struct txgbe_hw_fdir_info *info = TXGBE_DEV_FDIR(dev);
238 : : uint16_t dst_ipv6m = 0;
239 : : uint16_t src_ipv6m = 0;
240 : :
241 [ # # ]: 0 : if (mode != RTE_FDIR_MODE_SIGNATURE &&
242 : : mode != RTE_FDIR_MODE_PERFECT) {
243 : 0 : PMD_DRV_LOG(ERR, "Not supported fdir mode - %d!", mode);
244 : 0 : return -ENOTSUP;
245 : : }
246 : :
247 [ # # ]: 0 : memset(&info->mask, 0, sizeof(struct txgbe_hw_fdir_mask));
248 : 0 : info->mask.vlan_tci_mask = input_mask->vlan_tci_mask;
249 : 0 : info->mask.src_port_mask = input_mask->src_port_mask;
250 : 0 : info->mask.dst_port_mask = input_mask->dst_port_mask;
251 : 0 : info->mask.src_ipv4_mask = input_mask->ipv4_mask.src_ip;
252 : 0 : info->mask.dst_ipv4_mask = input_mask->ipv4_mask.dst_ip;
253 [ # # # # : 0 : IPV6_ADDR_TO_MASK(input_mask->ipv6_mask.src_ip, src_ipv6m);
# # # # ]
254 [ # # # # : 0 : IPV6_ADDR_TO_MASK(input_mask->ipv6_mask.dst_ip, dst_ipv6m);
# # # # ]
255 : 0 : info->mask.src_ipv6_mask = src_ipv6m;
256 : 0 : info->mask.dst_ipv6_mask = dst_ipv6m;
257 : :
258 : 0 : return 0;
259 : : }
260 : :
261 : : uint16_t
262 : 0 : txgbe_fdir_get_flex_base(struct txgbe_fdir_rule *rule)
263 : : {
264 [ # # ]: 0 : if (!rule->flex_relative)
265 : : return TXGBE_FDIRFLEXCFG_BASE_MAC;
266 : :
267 [ # # ]: 0 : if (rule->input.flow_type & TXGBE_ATR_L4TYPE_MASK)
268 : 0 : return TXGBE_FDIRFLEXCFG_BASE_PAY;
269 : :
270 : : return TXGBE_FDIRFLEXCFG_BASE_L3;
271 : : }
272 : :
273 : : int
274 : 0 : txgbe_fdir_set_flexbytes_offset(struct rte_eth_dev *dev,
275 : : uint16_t offset, uint16_t flex_base)
276 : : {
277 : 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
278 : : int i;
279 : :
280 [ # # ]: 0 : for (i = 0; i < 64; i++) {
281 : : uint32_t flexreg, flex;
282 : 0 : flexreg = rd32(hw, TXGBE_FDIRFLEXCFG(i / 4));
283 : 0 : flex = flex_base;
284 : 0 : flex |= TXGBE_FDIRFLEXCFG_OFST(offset / 2);
285 : 0 : flexreg &= ~(TXGBE_FDIRFLEXCFG_ALL(~0UL, i % 4));
286 : 0 : flexreg |= TXGBE_FDIRFLEXCFG_ALL(flex, i % 4);
287 : : wr32(hw, TXGBE_FDIRFLEXCFG(i / 4), flexreg);
288 : : }
289 : :
290 : : txgbe_flush(hw);
291 [ # # ]: 0 : for (i = 0; i < TXGBE_FDIR_INIT_DONE_POLL; i++) {
292 [ # # ]: 0 : if (rd32(hw, TXGBE_FDIRCTL) &
293 : : TXGBE_FDIRCTL_INITDONE)
294 : : break;
295 : : msec_delay(1);
296 : : }
297 : 0 : return 0;
298 : : }
299 : :
300 : : /*
301 : : * txgbe_check_fdir_flex_conf -check if the flex payload and mask configuration
302 : : * arguments are valid
303 : : */
304 : : static int
305 : 0 : txgbe_set_fdir_flex_conf(struct rte_eth_dev *dev, uint32_t flex)
306 : : {
307 : : const struct rte_eth_fdir_flex_conf *conf =
308 : 0 : &TXGBE_DEV_FDIR_CONF(dev)->flex_conf;
309 : : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
310 : : struct txgbe_hw_fdir_info *info = TXGBE_DEV_FDIR(dev);
311 : : const struct rte_eth_flex_payload_cfg *flex_cfg;
312 : : const struct rte_eth_fdir_flex_mask *flex_mask;
313 : : uint16_t flexbytes = 0;
314 : : uint16_t i;
315 : :
316 : : if (conf == NULL) {
317 : : PMD_DRV_LOG(ERR, "NULL pointer.");
318 : : return -EINVAL;
319 : : }
320 : :
321 : 0 : flex |= TXGBE_FDIRFLEXCFG_DIA;
322 : :
323 [ # # ]: 0 : for (i = 0; i < conf->nb_payloads; i++) {
324 : 0 : flex_cfg = &conf->flex_set[i];
325 [ # # ]: 0 : if (flex_cfg->type != RTE_ETH_RAW_PAYLOAD) {
326 : 0 : PMD_DRV_LOG(ERR, "unsupported payload type.");
327 : 0 : return -EINVAL;
328 : : }
329 [ # # ]: 0 : if (((flex_cfg->src_offset[0] & 0x1) == 0) &&
330 [ # # # # ]: 0 : (flex_cfg->src_offset[1] == flex_cfg->src_offset[0] + 1) &&
331 : : flex_cfg->src_offset[0] <= TXGBE_MAX_FLX_SOURCE_OFF) {
332 : 0 : flex &= ~TXGBE_FDIRFLEXCFG_OFST_MASK;
333 : 0 : flex |=
334 : 0 : TXGBE_FDIRFLEXCFG_OFST(flex_cfg->src_offset[0] / 2);
335 : : } else {
336 : 0 : PMD_DRV_LOG(ERR, "invalid flexbytes arguments.");
337 : 0 : return -EINVAL;
338 : : }
339 : : }
340 : :
341 [ # # ]: 0 : for (i = 0; i < conf->nb_flexmasks; i++) {
342 : 0 : flex_mask = &conf->flex_mask[i];
343 [ # # ]: 0 : if (flex_mask->flow_type != RTE_ETH_FLOW_UNKNOWN) {
344 : 0 : PMD_DRV_LOG(ERR, "flexmask should be set globally.");
345 : 0 : return -EINVAL;
346 : : }
347 : 0 : flexbytes = (uint16_t)(((flex_mask->mask[1] << 8) & 0xFF00) |
348 : 0 : ((flex_mask->mask[0]) & 0xFF));
349 [ # # ]: 0 : if (flexbytes == UINT16_MAX) {
350 : 0 : flex &= ~TXGBE_FDIRFLEXCFG_DIA;
351 [ # # ]: 0 : } else if (flexbytes != 0) {
352 : : /* TXGBE_FDIRFLEXCFG_DIA is set by default when set mask */
353 : 0 : PMD_DRV_LOG(ERR, " invalid flexbytes mask arguments.");
354 : 0 : return -EINVAL;
355 : : }
356 : : }
357 : :
358 [ # # ]: 0 : info->mask.flex_bytes_mask = flexbytes ? UINT16_MAX : 0;
359 : 0 : info->flex_bytes_offset = (uint8_t)(TXGBD_FDIRFLEXCFG_OFST(flex) * 2);
360 : :
361 [ # # ]: 0 : for (i = 0; i < 64; i++) {
362 : : uint32_t flexreg;
363 : 0 : flexreg = rd32(hw, TXGBE_FDIRFLEXCFG(i / 4));
364 : 0 : flexreg &= ~(TXGBE_FDIRFLEXCFG_ALL(~0UL, i % 4));
365 : 0 : flexreg |= TXGBE_FDIRFLEXCFG_ALL(flex, i % 4);
366 : : wr32(hw, TXGBE_FDIRFLEXCFG(i / 4), flexreg);
367 : : }
368 : : return 0;
369 : : }
370 : :
371 : : int
372 : 0 : txgbe_fdir_configure(struct rte_eth_dev *dev)
373 : : {
374 : 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
375 : : int err;
376 : : uint32_t fdirctrl, flex, pbsize;
377 : : int i;
378 : 0 : enum rte_fdir_mode mode = TXGBE_DEV_FDIR_CONF(dev)->mode;
379 : :
380 : 0 : PMD_INIT_FUNC_TRACE();
381 : :
382 : : /* supports mac-vlan and tunnel mode */
383 [ # # ]: 0 : if (mode != RTE_FDIR_MODE_SIGNATURE &&
384 : : mode != RTE_FDIR_MODE_PERFECT)
385 : : return -ENOSYS;
386 : :
387 : 0 : err = configure_fdir_flags(TXGBE_DEV_FDIR_CONF(dev), &fdirctrl, &flex);
388 [ # # ]: 0 : if (err)
389 : : return err;
390 : :
391 : : /*
392 : : * Before enabling Flow Director, the Rx Packet Buffer size
393 : : * must be reduced. The new value is the current size minus
394 : : * flow director memory usage size.
395 : : */
396 : : pbsize = rd32(hw, TXGBE_PBRXSIZE(0));
397 : 0 : pbsize -= TXGBD_FDIRCTL_BUF_BYTE(fdirctrl);
398 : : wr32(hw, TXGBE_PBRXSIZE(0), pbsize);
399 : :
400 : : /*
401 : : * The defaults in the HW for RX PB 1-7 are not zero and so should be
402 : : * initialized to zero for non DCB mode otherwise actual total RX PB
403 : : * would be bigger than programmed and filter space would run into
404 : : * the PB 0 region.
405 : : */
406 [ # # ]: 0 : for (i = 1; i < 8; i++)
407 : 0 : wr32(hw, TXGBE_PBRXSIZE(i), 0);
408 : :
409 : 0 : err = txgbe_fdir_store_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_fdir_set_input_mask(dev);
416 [ # # ]: 0 : if (err < 0) {
417 : 0 : PMD_INIT_LOG(ERR, " Error on setting FD mask");
418 : 0 : return err;
419 : : }
420 : :
421 : 0 : err = txgbe_set_fdir_flex_conf(dev, flex);
422 [ # # ]: 0 : if (err < 0) {
423 : 0 : PMD_INIT_LOG(ERR, " Error on setting FD flexible arguments.");
424 : 0 : return err;
425 : : }
426 : :
427 : 0 : err = txgbe_fdir_enable(hw, fdirctrl);
428 [ # # ]: 0 : if (err < 0) {
429 : 0 : PMD_INIT_LOG(ERR, " Error on enabling FD.");
430 : 0 : return err;
431 : : }
432 : : return 0;
433 : : }
434 : :
435 : : /*
436 : : * Note that the bkt_hash field in the txgbe_atr_input structure is also never
437 : : * set.
438 : : *
439 : : * Compute the hashes for SW ATR
440 : : * @stream: input bitstream to compute the hash on
441 : : * @key: 32-bit hash key
442 : : **/
443 : : static uint32_t
444 : 0 : txgbe_atr_compute_hash(struct txgbe_atr_input *atr_input,
445 : : uint32_t key)
446 : : {
447 : : /*
448 : : * The algorithm is as follows:
449 : : * Hash[15:0] = Sum { S[n] x K[n+16] }, n = 0...350
450 : : * where Sum {A[n]}, n = 0...n is bitwise XOR of A[0], A[1]...A[n]
451 : : * and A[n] x B[n] is bitwise AND between same length strings
452 : : *
453 : : * K[n] is 16 bits, defined as:
454 : : * for n modulo 32 >= 15, K[n] = K[n % 32 : (n % 32) - 15]
455 : : * for n modulo 32 < 15, K[n] =
456 : : * K[(n % 32:0) | (31:31 - (14 - (n % 32)))]
457 : : *
458 : : * S[n] is 16 bits, defined as:
459 : : * for n >= 15, S[n] = S[n:n - 15]
460 : : * for n < 15, S[n] = S[(n:0) | (350:350 - (14 - n))]
461 : : *
462 : : * To simplify for programming, the algorithm is implemented
463 : : * in software this way:
464 : : *
465 : : * key[31:0], hi_hash_dword[31:0], lo_hash_dword[31:0], hash[15:0]
466 : : *
467 : : * for (i = 0; i < 352; i+=32)
468 : : * hi_hash_dword[31:0] ^= Stream[(i+31):i];
469 : : *
470 : : * lo_hash_dword[15:0] ^= Stream[15:0];
471 : : * lo_hash_dword[15:0] ^= hi_hash_dword[31:16];
472 : : * lo_hash_dword[31:16] ^= hi_hash_dword[15:0];
473 : : *
474 : : * hi_hash_dword[31:0] ^= Stream[351:320];
475 : : *
476 : : * if (key[0])
477 : : * hash[15:0] ^= Stream[15:0];
478 : : *
479 : : * for (i = 0; i < 16; i++) {
480 : : * if (key[i])
481 : : * hash[15:0] ^= lo_hash_dword[(i+15):i];
482 : : * if (key[i + 16])
483 : : * hash[15:0] ^= hi_hash_dword[(i+15):i];
484 : : * }
485 : : *
486 : : */
487 : : __be32 *dword_stream = (__be32 *)atr_input;
488 : : __be32 common_hash_dword = 0;
489 : : u32 hi_hash_dword, lo_hash_dword, flow_pool_ptid;
490 : : u32 hash_result = 0;
491 : : u8 i;
492 : :
493 : : /* record the flow_vm_vlan bits as they are a key part to the hash */
494 [ # # ]: 0 : flow_pool_ptid = be_to_cpu32(dword_stream[0]);
495 : :
496 : : /* generate common hash dword */
497 [ # # ]: 0 : for (i = 1; i <= 10; i++)
498 : 0 : common_hash_dword ^= dword_stream[i];
499 : :
500 [ # # ]: 0 : hi_hash_dword = be_to_cpu32(common_hash_dword);
501 : :
502 : : /* low dword is word swapped version of common */
503 : 0 : lo_hash_dword = (hi_hash_dword >> 16) | (hi_hash_dword << 16);
504 : :
505 : : /* apply (Flow ID/VM Pool/Packet Type) bits to hash words */
506 : 0 : hi_hash_dword ^= flow_pool_ptid ^ (flow_pool_ptid >> 16);
507 : :
508 : : /* Process bits 0 and 16 */
509 [ # # ]: 0 : if (key & 0x0001)
510 : : hash_result ^= lo_hash_dword;
511 [ # # ]: 0 : if (key & 0x00010000)
512 : 0 : hash_result ^= hi_hash_dword;
513 : :
514 : : /*
515 : : * apply flow ID/VM pool/VLAN ID bits to lo hash dword, we had to
516 : : * delay this because bit 0 of the stream should not be processed
517 : : * so we do not add the vlan until after bit 0 was processed
518 : : */
519 : 0 : lo_hash_dword ^= flow_pool_ptid ^ (flow_pool_ptid << 16);
520 : :
521 : : /* process the remaining 30 bits in the key 2 bits at a time */
522 [ # # ]: 0 : for (i = 15; i; i--) {
523 [ # # ]: 0 : if (key & (0x0001 << i))
524 : 0 : hash_result ^= lo_hash_dword >> i;
525 [ # # ]: 0 : if (key & (0x00010000 << i))
526 : 0 : hash_result ^= hi_hash_dword >> i;
527 : : }
528 : :
529 : 0 : return hash_result;
530 : : }
531 : :
532 : : static uint32_t
533 : : atr_compute_perfect_hash(struct txgbe_atr_input *input,
534 : : enum rte_eth_fdir_pballoc_type pballoc)
535 : : {
536 : : uint32_t bucket_hash;
537 : :
538 : 0 : bucket_hash = txgbe_atr_compute_hash(input,
539 : : TXGBE_ATR_BUCKET_HASH_KEY);
540 [ # # # # ]: 0 : if (pballoc == RTE_ETH_FDIR_PBALLOC_256K)
541 : 0 : bucket_hash &= PERFECT_BUCKET_256KB_HASH_MASK;
542 [ # # # # ]: 0 : else if (pballoc == RTE_ETH_FDIR_PBALLOC_128K)
543 : 0 : bucket_hash &= PERFECT_BUCKET_128KB_HASH_MASK;
544 : : else
545 : 0 : bucket_hash &= PERFECT_BUCKET_64KB_HASH_MASK;
546 : :
547 : : return TXGBE_FDIRPIHASH_BKT(bucket_hash);
548 : : }
549 : :
550 : : /**
551 : : * txgbe_fdir_check_cmd_complete - poll to check whether FDIRPICMD is complete
552 : : * @hw: pointer to hardware structure
553 : : */
554 : : static inline int
555 : : txgbe_fdir_check_cmd_complete(struct txgbe_hw *hw, uint32_t *fdircmd)
556 : : {
557 : : int i;
558 : :
559 [ # # # # : 0 : for (i = 0; i < TXGBE_FDIRCMD_CMD_POLL; i++) {
# # # # ]
560 : : *fdircmd = rd32(hw, TXGBE_FDIRPICMD);
561 [ # # # # : 0 : if (!(*fdircmd & TXGBE_FDIRPICMD_OP_MASK))
# # # # ]
562 : : return 0;
563 : 0 : rte_delay_us(TXGBE_FDIRCMD_CMD_INTERVAL_US);
564 : : }
565 : :
566 : : return -ETIMEDOUT;
567 : : }
568 : :
569 : : /*
570 : : * Calculate the hash value needed for signature-match filters. In the FreeBSD
571 : : * driver, this is done by the optimised function
572 : : * txgbe_atr_compute_sig_hash_raptor(). However that can't be used here as it
573 : : * doesn't support calculating a hash for an IPv6 filter.
574 : : */
575 : : static uint32_t
576 : 0 : atr_compute_signature_hash(struct txgbe_atr_input *input,
577 : : enum rte_eth_fdir_pballoc_type pballoc)
578 : : {
579 : : uint32_t bucket_hash, sig_hash;
580 : :
581 : 0 : bucket_hash = txgbe_atr_compute_hash(input,
582 : : TXGBE_ATR_BUCKET_HASH_KEY);
583 [ # # ]: 0 : if (pballoc == RTE_ETH_FDIR_PBALLOC_256K)
584 : 0 : bucket_hash &= SIG_BUCKET_256KB_HASH_MASK;
585 [ # # ]: 0 : else if (pballoc == RTE_ETH_FDIR_PBALLOC_128K)
586 : 0 : bucket_hash &= SIG_BUCKET_128KB_HASH_MASK;
587 : : else
588 : 0 : bucket_hash &= SIG_BUCKET_64KB_HASH_MASK;
589 : :
590 : 0 : sig_hash = txgbe_atr_compute_hash(input,
591 : : TXGBE_ATR_SIGNATURE_HASH_KEY);
592 : :
593 : 0 : return TXGBE_FDIRPIHASH_SIG(sig_hash) |
594 : : TXGBE_FDIRPIHASH_BKT(bucket_hash);
595 : : }
596 : :
597 : : /**
598 : : * With the ability to set extra flags in FDIRPICMD register
599 : : * added, and IPv6 support also added. The hash value is also pre-calculated
600 : : * as the pballoc value is needed to do it.
601 : : */
602 : : static int
603 : 0 : fdir_write_perfect_filter(struct txgbe_hw *hw,
604 : : struct txgbe_atr_input *input, uint8_t queue,
605 : : uint32_t fdircmd, uint32_t fdirhash,
606 : : enum rte_fdir_mode mode)
607 : : {
608 : : uint32_t fdirport, fdirflex;
609 : : int err = 0;
610 : :
611 : : UNREFERENCED_PARAMETER(mode);
612 : :
613 : : /* record the IPv4 address (little-endian)
614 : : * can not use wr32.
615 : : */
616 [ # # ]: 0 : wr32(hw, TXGBE_FDIRPISIP4, be_to_le32(input->src_ip[0]));
617 [ # # ]: 0 : wr32(hw, TXGBE_FDIRPIDIP4, be_to_le32(input->dst_ip[0]));
618 : :
619 : : /* record source and destination port (little-endian)*/
620 [ # # ]: 0 : fdirport = TXGBE_FDIRPIPORT_DST(be_to_le16(input->dst_port));
621 [ # # ]: 0 : fdirport |= TXGBE_FDIRPIPORT_SRC(be_to_le16(input->src_port));
622 : : wr32(hw, TXGBE_FDIRPIPORT, fdirport);
623 : :
624 : : /* record pkt_type (little-endian) and flex_bytes(big-endian) */
625 [ # # ]: 0 : fdirflex = TXGBE_FDIRPIFLEX_FLEX(be_to_npu16(input->flex_bytes));
626 [ # # ]: 0 : fdirflex |= TXGBE_FDIRPIFLEX_PTYPE(be_to_le16(input->pkt_type));
627 : : wr32(hw, TXGBE_FDIRPIFLEX, fdirflex);
628 : :
629 : : /* configure FDIRHASH register */
630 : 0 : fdirhash |= TXGBE_FDIRPIHASH_VLD;
631 : : wr32(hw, TXGBE_FDIRPIHASH, fdirhash);
632 : :
633 : : /*
634 : : * flush all previous writes to make certain registers are
635 : : * programmed prior to issuing the command
636 : : */
637 : : txgbe_flush(hw);
638 : :
639 : : /* configure FDIRPICMD register */
640 : 0 : fdircmd |= TXGBE_FDIRPICMD_OP_ADD |
641 : : TXGBE_FDIRPICMD_UPD |
642 : : TXGBE_FDIRPICMD_LAST |
643 : : TXGBE_FDIRPICMD_QPENA;
644 : 0 : fdircmd |= TXGBE_FDIRPICMD_FT(input->flow_type);
645 : 0 : fdircmd |= TXGBE_FDIRPICMD_QP(queue);
646 : 0 : fdircmd |= TXGBE_FDIRPICMD_POOL(input->vm_pool);
647 : :
648 [ # # ]: 0 : if (input->flow_type & TXGBE_ATR_L3TYPE_IPV6) {
649 : : /* use SIP4 to store LS Dword of the Source iPv6 address */
650 [ # # ]: 0 : wr32(hw, TXGBE_FDIRPISIP4, be_to_le32(input->src_ip[3]));
651 [ # # ]: 0 : wr32(hw, TXGBE_FDIRPISIP6(0), be_to_le32(input->src_ip[2]));
652 [ # # ]: 0 : wr32(hw, TXGBE_FDIRPISIP6(1), be_to_le32(input->src_ip[1]));
653 [ # # ]: 0 : wr32(hw, TXGBE_FDIRPISIP6(2), be_to_le32(input->src_ip[0]));
654 : 0 : fdircmd |= TXGBE_FDIRPICMD_IP6;
655 : : }
656 : : wr32(hw, TXGBE_FDIRPICMD, fdircmd);
657 : :
658 : 0 : PMD_DRV_LOG(DEBUG, "Rx Queue=%x hash=%x", queue, fdirhash);
659 : :
660 : : err = txgbe_fdir_check_cmd_complete(hw, &fdircmd);
661 [ # # ]: 0 : if (err < 0)
662 : 0 : PMD_DRV_LOG(ERR, "Timeout writing flow director filter.");
663 : :
664 : 0 : return err;
665 : : }
666 : :
667 : : /**
668 : : * This function supports setting extra fields in the FDIRPICMD register, and
669 : : * removes the code that was verifying the flow_type field. According to the
670 : : * documentation, a flow type of 00 (i.e. not TCP, UDP, or SCTP) is not
671 : : * supported, however it appears to work ok...
672 : : * Adds a signature hash filter
673 : : * @hw: pointer to hardware structure
674 : : * @input: unique input dword
675 : : * @queue: queue index to direct traffic to
676 : : * @fdircmd: any extra flags to set in fdircmd register
677 : : * @fdirhash: pre-calculated hash value for the filter
678 : : **/
679 : : static int
680 : 0 : fdir_add_signature_filter(struct txgbe_hw *hw,
681 : : struct txgbe_atr_input *input, uint8_t queue, uint32_t fdircmd,
682 : : uint32_t fdirhash)
683 : : {
684 : : int err = 0;
685 : :
686 : 0 : PMD_INIT_FUNC_TRACE();
687 : :
688 : : /* configure FDIRPICMD register */
689 : 0 : fdircmd |= TXGBE_FDIRPICMD_OP_ADD |
690 : : TXGBE_FDIRPICMD_UPD |
691 : : TXGBE_FDIRPICMD_LAST |
692 : : TXGBE_FDIRPICMD_QPENA;
693 : 0 : fdircmd |= TXGBE_FDIRPICMD_FT(input->flow_type);
694 : 0 : fdircmd |= TXGBE_FDIRPICMD_QP(queue);
695 : :
696 : 0 : fdirhash |= TXGBE_FDIRPIHASH_VLD;
697 : : wr32(hw, TXGBE_FDIRPIHASH, fdirhash);
698 : : wr32(hw, TXGBE_FDIRPICMD, fdircmd);
699 : :
700 : 0 : PMD_DRV_LOG(DEBUG, "Rx Queue=%x hash=%x", queue, fdirhash);
701 : :
702 : : err = txgbe_fdir_check_cmd_complete(hw, &fdircmd);
703 [ # # ]: 0 : if (err < 0)
704 : 0 : PMD_DRV_LOG(ERR, "Timeout writing flow director filter.");
705 : :
706 : 0 : return err;
707 : : }
708 : :
709 : : /*
710 : : * This is modified to take in the hash as a parameter so that
711 : : * it can be used for removing signature and perfect filters.
712 : : */
713 : : static int
714 : 0 : fdir_erase_filter_raptor(struct txgbe_hw *hw, uint32_t fdirhash)
715 : : {
716 : : uint32_t fdircmd = 0;
717 : : int err = 0;
718 : :
719 : : wr32(hw, TXGBE_FDIRPIHASH, fdirhash);
720 : :
721 : : /* flush hash to HW */
722 : : txgbe_flush(hw);
723 : :
724 : : /* Query if filter is present */
725 : : wr32(hw, TXGBE_FDIRPICMD, TXGBE_FDIRPICMD_OP_QRY);
726 : :
727 : : err = txgbe_fdir_check_cmd_complete(hw, &fdircmd);
728 [ # # ]: 0 : if (err < 0) {
729 : 0 : PMD_INIT_LOG(ERR, "Timeout querying for flow director filter.");
730 : 0 : return err;
731 : : }
732 : :
733 : : /* if filter exists in hardware then remove it */
734 [ # # ]: 0 : if (fdircmd & TXGBE_FDIRPICMD_VLD) {
735 : : wr32(hw, TXGBE_FDIRPIHASH, fdirhash);
736 : : txgbe_flush(hw);
737 : : wr32(hw, TXGBE_FDIRPICMD, TXGBE_FDIRPICMD_OP_REM);
738 : : }
739 : :
740 : : err = txgbe_fdir_check_cmd_complete(hw, &fdircmd);
741 [ # # ]: 0 : if (err < 0)
742 : 0 : PMD_INIT_LOG(ERR, "Timeout erasing flow director filter.");
743 : :
744 : : return err;
745 : : }
746 : :
747 : : static inline struct txgbe_fdir_filter *
748 : : txgbe_fdir_filter_lookup(struct txgbe_hw_fdir_info *fdir_info,
749 : : struct txgbe_atr_input *input)
750 : : {
751 : : int ret;
752 : :
753 : 0 : ret = rte_hash_lookup(fdir_info->hash_handle, (const void *)input);
754 [ # # ]: 0 : if (ret < 0)
755 : : return NULL;
756 : :
757 : 0 : return fdir_info->hash_map[ret];
758 : : }
759 : :
760 : : static inline int
761 : 0 : txgbe_insert_fdir_filter(struct txgbe_hw_fdir_info *fdir_info,
762 : : struct txgbe_fdir_filter *fdir_filter)
763 : : {
764 : : int ret;
765 : :
766 : 0 : ret = rte_hash_add_key(fdir_info->hash_handle, &fdir_filter->input);
767 [ # # ]: 0 : if (ret < 0) {
768 : 0 : PMD_DRV_LOG(ERR,
769 : : "Failed to insert fdir filter to hash table %d!",
770 : : ret);
771 : 0 : return ret;
772 : : }
773 : :
774 : 0 : fdir_info->hash_map[ret] = fdir_filter;
775 : :
776 : 0 : TAILQ_INSERT_TAIL(&fdir_info->fdir_list, fdir_filter, entries);
777 : :
778 : 0 : return ret;
779 : : }
780 : :
781 : : static inline int
782 : 0 : txgbe_remove_fdir_filter(struct txgbe_hw_fdir_info *fdir_info,
783 : : struct txgbe_atr_input *input)
784 : : {
785 : : int ret;
786 : : struct txgbe_fdir_filter *fdir_filter;
787 : :
788 : 0 : ret = rte_hash_del_key(fdir_info->hash_handle, input);
789 [ # # ]: 0 : if (ret < 0)
790 : : return ret;
791 : :
792 : 0 : fdir_filter = fdir_info->hash_map[ret];
793 : 0 : fdir_info->hash_map[ret] = NULL;
794 : :
795 [ # # ]: 0 : TAILQ_REMOVE(&fdir_info->fdir_list, fdir_filter, entries);
796 : 0 : rte_free(fdir_filter);
797 : :
798 : 0 : return ret;
799 : : }
800 : :
801 : : static void
802 : 0 : txgbe_fdir_mask_input(struct txgbe_hw_fdir_mask *mask,
803 : : struct txgbe_atr_input *input)
804 : : {
805 : : int i;
806 : :
807 [ # # ]: 0 : if (input->flow_type & TXGBE_ATR_L3TYPE_IPV6) {
808 [ # # ]: 0 : for (i = 0; i < 16; i++) {
809 [ # # ]: 0 : if (!(mask->src_ipv6_mask & (1 << i)))
810 : 0 : input->src_ip[i / 4] &= ~(0xFF << ((i % 4) * 8));
811 : : }
812 : : } else {
813 : 0 : input->src_ip[0] &= mask->src_ipv4_mask;
814 : 0 : input->dst_ip[0] &= mask->dst_ipv4_mask;
815 : : }
816 : :
817 : 0 : input->src_port &= mask->src_port_mask;
818 : 0 : input->dst_port &= mask->dst_port_mask;
819 : 0 : }
820 : :
821 : : int
822 : 0 : txgbe_fdir_filter_program(struct rte_eth_dev *dev,
823 : : struct txgbe_fdir_rule *rule,
824 : : bool del,
825 : : bool update)
826 : : {
827 : 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
828 : : uint32_t fdirhash;
829 : : uint8_t queue;
830 : : bool is_perfect = FALSE;
831 : : int err;
832 : 0 : struct txgbe_hw_fdir_info *info = TXGBE_DEV_FDIR(dev);
833 : 0 : enum rte_fdir_mode fdir_mode = TXGBE_DEV_FDIR_CONF(dev)->mode;
834 : : struct txgbe_fdir_filter *node;
835 : :
836 [ # # ]: 0 : if (fdir_mode == RTE_FDIR_MODE_NONE ||
837 [ # # ]: 0 : fdir_mode != rule->mode)
838 : : return -ENOTSUP;
839 : :
840 [ # # ]: 0 : if (fdir_mode >= RTE_FDIR_MODE_PERFECT)
841 : : is_perfect = TRUE;
842 : :
843 : 0 : txgbe_fdir_mask_input(&info->mask, &rule->input);
844 : :
845 [ # # ]: 0 : if (is_perfect) {
846 : 0 : fdirhash = atr_compute_perfect_hash(&rule->input,
847 : : TXGBE_DEV_FDIR_CONF(dev)->pballoc);
848 : 0 : fdirhash |= TXGBE_FDIRPIHASH_IDX(rule->soft_id);
849 : : } else {
850 : 0 : fdirhash = atr_compute_signature_hash(&rule->input,
851 : : TXGBE_DEV_FDIR_CONF(dev)->pballoc);
852 : : }
853 : :
854 [ # # ]: 0 : if (del) {
855 : 0 : err = txgbe_remove_fdir_filter(info, &rule->input);
856 [ # # ]: 0 : if (err < 0) {
857 : 0 : PMD_DRV_LOG(ERR,
858 : : "No such fdir filter to delete %d!", err);
859 : 0 : return err;
860 : : }
861 : :
862 : 0 : err = fdir_erase_filter_raptor(hw, fdirhash);
863 [ # # ]: 0 : if (err < 0)
864 : 0 : PMD_DRV_LOG(ERR, "Fail to delete FDIR filter!");
865 : : else
866 : 0 : PMD_DRV_LOG(DEBUG, "Success to delete FDIR filter!");
867 : 0 : return err;
868 : : }
869 : :
870 : : /* add or update an fdir filter*/
871 [ # # ]: 0 : if (rule->fdirflags & TXGBE_FDIRPICMD_DROP) {
872 [ # # ]: 0 : if (!is_perfect) {
873 : 0 : PMD_DRV_LOG(ERR, "Drop option is not supported in"
874 : : " signature mode.");
875 : 0 : return -EINVAL;
876 : : }
877 : 0 : queue = TXGBE_DEV_FDIR_CONF(dev)->drop_queue;
878 [ # # ]: 0 : } else if (rule->queue < TXGBE_MAX_RX_QUEUE_NUM) {
879 : : queue = rule->queue;
880 : : } else {
881 : : return -EINVAL;
882 : : }
883 : :
884 [ # # ]: 0 : if (RTE_ETH_DEV_SRIOV(dev).active)
885 : 0 : queue = RTE_ETH_DEV_SRIOV(dev).def_pool_q_idx + queue;
886 : :
887 : : node = txgbe_fdir_filter_lookup(info, &rule->input);
888 [ # # ]: 0 : if (node) {
889 [ # # ]: 0 : if (!update) {
890 : 0 : PMD_DRV_LOG(ERR, "Conflict with existing fdir filter!");
891 : 0 : return -EINVAL;
892 : : }
893 : 0 : node->fdirflags = rule->fdirflags;
894 : 0 : node->fdirhash = fdirhash;
895 : 0 : node->queue = queue;
896 : : } else {
897 : 0 : node = rte_zmalloc("txgbe_fdir",
898 : : sizeof(struct txgbe_fdir_filter), 0);
899 [ # # ]: 0 : if (!node)
900 : : return -ENOMEM;
901 [ # # ]: 0 : rte_memcpy(&node->input, &rule->input,
902 : : sizeof(struct txgbe_atr_input));
903 : 0 : node->fdirflags = rule->fdirflags;
904 : 0 : node->fdirhash = fdirhash;
905 : 0 : node->queue = queue;
906 : :
907 : 0 : err = txgbe_insert_fdir_filter(info, node);
908 [ # # ]: 0 : if (err < 0) {
909 : 0 : rte_free(node);
910 : 0 : return err;
911 : : }
912 : : }
913 : :
914 [ # # ]: 0 : if (is_perfect)
915 : 0 : err = fdir_write_perfect_filter(hw, &node->input,
916 : 0 : node->queue, node->fdirflags,
917 : : node->fdirhash, fdir_mode);
918 : : else
919 : 0 : err = fdir_add_signature_filter(hw, &node->input,
920 : 0 : node->queue, node->fdirflags,
921 : : node->fdirhash);
922 [ # # ]: 0 : if (err < 0) {
923 : 0 : PMD_DRV_LOG(ERR, "Fail to add FDIR filter!");
924 : 0 : txgbe_remove_fdir_filter(info, &rule->input);
925 : : } else {
926 : 0 : PMD_DRV_LOG(DEBUG, "Success to add FDIR filter");
927 : : }
928 : :
929 : : return err;
930 : : }
931 : :
932 : : static void
933 : : txgbevf_flush_fdir_filter(struct rte_eth_dev *dev)
934 : : {
935 : 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
936 : 0 : uint32_t msg[2] = {0, 0};
937 : :
938 : : /* flush bit */
939 : 0 : msg[TXGBEVF_FDIR_CMD] = 1 << 16;
940 : :
941 : 0 : txgbevf_set_fdir(hw, msg, FALSE);
942 : : }
943 : :
944 : : static int
945 : 0 : txgbevf_del_fdir_filter(struct rte_eth_dev *dev,
946 : : struct txgbe_fdir_rule *rule,
947 : : int id)
948 : : {
949 : 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
950 : 0 : struct txgbe_hw_fdir_info *info = TXGBE_DEV_FDIR(dev);
951 : 0 : uint32_t msg[2] = {0, 0};
952 : : int ret = 0;
953 : :
954 : : /* node id [15:0] */
955 : 0 : msg[TXGBEVF_FDIR_CMD] = id;
956 : :
957 : 0 : ret = txgbevf_set_fdir(hw, msg, FALSE);
958 [ # # ]: 0 : if (ret) {
959 : 0 : PMD_DRV_LOG(ERR, "VF request PF to delete FDIR filters failed.");
960 : 0 : return ret;
961 : : }
962 : :
963 : 0 : ret = txgbe_remove_fdir_filter(info, &rule->input);
964 [ # # ]: 0 : if (ret < 0)
965 : 0 : PMD_DRV_LOG(ERR, "Fail to delete FDIR filter!");
966 : :
967 : : return 0;
968 : : }
969 : :
970 : : static int
971 : 0 : txgbevf_add_fdir_filter(struct rte_eth_dev *dev,
972 : : struct txgbe_fdir_rule *rule,
973 : : int id)
974 : : {
975 [ # # ]: 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
976 : : uint32_t msg[TXGBEVF_FDIR_MAX];
977 : : int ret = 0;
978 : :
979 : : memset(msg, 0, sizeof(msg));
980 : :
981 : : /* node id [15:0] */
982 : 0 : msg[TXGBEVF_FDIR_CMD] = id;
983 : : /* ring_idx [23:16] */
984 : 0 : msg[TXGBEVF_FDIR_CMD] |= rule->queue << 16;
985 : : /* flow_type [30:24] */
986 : 0 : msg[TXGBEVF_FDIR_CMD] |= rule->input.flow_type << 24;
987 : :
988 : 0 : msg[TXGBEVF_FDIR_IP4SA] = rule->input.src_ip[0];
989 : 0 : msg[TXGBEVF_FDIR_IP4DA] = rule->input.dst_ip[0];
990 : 0 : msg[TXGBEVF_FDIR_PORT] = (rule->input.dst_port << 16) |
991 : 0 : rule->input.src_port;
992 [ # # ]: 0 : if (rule->mask.flex_bytes_mask) {
993 : : /* base [1:0] */
994 : 0 : msg[TXGBEVF_FDIR_FLEX] = txgbe_fdir_get_flex_base(rule);
995 : : /* offset [7:3] */
996 : 0 : msg[TXGBEVF_FDIR_FLEX] |=
997 : 0 : TXGBE_FDIRFLEXCFG_OFST(rule->flex_bytes_offset / 2);
998 : : /* flex bytes [31:16]*/
999 : 0 : msg[TXGBEVF_FDIR_FLEX] |= rule->input.flex_bytes << 16;
1000 : : }
1001 : 0 : msg[TXGBEVF_FDIR_IP4SM] = rule->mask.src_ipv4_mask;
1002 : 0 : msg[TXGBEVF_FDIR_IP4DM] = rule->mask.dst_ipv4_mask;
1003 : 0 : msg[TXGBEVF_FDIR_PORTM] = (rule->mask.dst_port_mask << 16) |
1004 : 0 : rule->mask.src_port_mask;
1005 : :
1006 : 0 : ret = txgbevf_set_fdir(hw, msg, TRUE);
1007 [ # # ]: 0 : if (ret)
1008 : 0 : PMD_DRV_LOG(ERR, "VF request PF to add FDIR filters failed.");
1009 : :
1010 : 0 : return ret;
1011 : : }
1012 : :
1013 : : int
1014 : 0 : txgbevf_fdir_filter_program(struct rte_eth_dev *dev,
1015 : : struct txgbe_fdir_rule *rule,
1016 : : bool del)
1017 : : {
1018 : 0 : struct txgbe_hw_fdir_info *info = TXGBE_DEV_FDIR(dev);
1019 : 0 : struct txgbe_atr_input *input = &rule->input;
1020 : : struct txgbe_fdir_filter *node;
1021 : : uint32_t fdirhash;
1022 : : int ret;
1023 : :
1024 [ # # ]: 0 : if (rule->mode != RTE_FDIR_MODE_PERFECT ||
1025 [ # # ]: 0 : rule->fdirflags == TXGBE_FDIRPICMD_DROP)
1026 : : return -ENOTSUP;
1027 : :
1028 [ # # ]: 0 : if (input->flow_type & TXGBE_ATR_FLOW_TYPE_IPV6)
1029 : : return -ENOTSUP;
1030 : :
1031 : 0 : fdirhash = atr_compute_perfect_hash(input,
1032 : : TXGBE_DEV_FDIR_CONF(dev)->pballoc);
1033 : :
1034 : 0 : ret = rte_hash_lookup(info->hash_handle, (const void *)input);
1035 [ # # ]: 0 : if (ret < 0) {
1036 [ # # ]: 0 : if (del) {
1037 : 0 : PMD_DRV_LOG(ERR, "No such fdir filter to delete!");
1038 : 0 : return ret;
1039 : : }
1040 : : } else {
1041 [ # # ]: 0 : if (!del) {
1042 : 0 : PMD_DRV_LOG(ERR, "Conflict with existing fdir filter!");
1043 : 0 : return -EINVAL;
1044 : : }
1045 : : }
1046 : :
1047 [ # # ]: 0 : if (del)
1048 : 0 : return txgbevf_del_fdir_filter(dev, rule, ret);
1049 : :
1050 : 0 : node = rte_zmalloc("txgbe_fdir",
1051 : : sizeof(struct txgbe_fdir_filter), 0);
1052 [ # # ]: 0 : if (!node)
1053 : : return -ENOMEM;
1054 [ # # ]: 0 : rte_memcpy(&node->input, input,
1055 : : sizeof(struct txgbe_atr_input));
1056 : 0 : node->fdirflags = rule->fdirflags;
1057 : 0 : node->fdirhash = fdirhash;
1058 : 0 : node->queue = rule->queue;
1059 : :
1060 : 0 : ret = txgbe_insert_fdir_filter(info, node);
1061 [ # # ]: 0 : if (ret < 0) {
1062 : 0 : rte_free(node);
1063 : 0 : return ret;
1064 : : }
1065 : :
1066 : 0 : ret = txgbevf_add_fdir_filter(dev, rule, ret);
1067 [ # # ]: 0 : if (ret)
1068 : 0 : txgbe_remove_fdir_filter(info, input);
1069 : :
1070 : : return ret;
1071 : : }
1072 : :
1073 : : static int
1074 : 0 : txgbe_fdir_flush(struct rte_eth_dev *dev)
1075 : : {
1076 : 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
1077 : : struct txgbe_hw_fdir_info *info = TXGBE_DEV_FDIR(dev);
1078 : : int ret;
1079 : :
1080 [ # # ]: 0 : if (!txgbe_is_pf(hw)) {
1081 : : txgbevf_flush_fdir_filter(dev);
1082 : 0 : return 0;
1083 : : }
1084 : :
1085 : 0 : ret = txgbe_reinit_fdir_tables(hw);
1086 [ # # ]: 0 : if (ret < 0) {
1087 : 0 : PMD_INIT_LOG(ERR, "Failed to re-initialize FD table.");
1088 : 0 : return ret;
1089 : : }
1090 : :
1091 : 0 : info->f_add = 0;
1092 : 0 : info->f_remove = 0;
1093 : 0 : info->add = 0;
1094 : 0 : info->remove = 0;
1095 : :
1096 : 0 : memset(&info->mask, 0, sizeof(struct txgbe_hw_fdir_mask));
1097 : 0 : info->mask_added = false;
1098 : 0 : info->flex_relative = false;
1099 : 0 : info->flex_bytes_offset = 0;
1100 : :
1101 : 0 : return ret;
1102 : : }
1103 : :
1104 : : /* restore flow director filter */
1105 : : void
1106 : 0 : txgbe_fdir_filter_restore(struct rte_eth_dev *dev)
1107 : : {
1108 : 0 : struct txgbe_hw *hw = TXGBE_DEV_HW(dev);
1109 : : struct txgbe_hw_fdir_info *fdir_info = TXGBE_DEV_FDIR(dev);
1110 : : struct txgbe_fdir_filter *node;
1111 : : bool is_perfect = FALSE;
1112 : 0 : enum rte_fdir_mode fdir_mode = TXGBE_DEV_FDIR_CONF(dev)->mode;
1113 : :
1114 [ # # ]: 0 : if (fdir_mode >= RTE_FDIR_MODE_PERFECT &&
1115 : : fdir_mode <= RTE_FDIR_MODE_PERFECT_TUNNEL)
1116 : : is_perfect = TRUE;
1117 : :
1118 : : if (is_perfect) {
1119 [ # # ]: 0 : TAILQ_FOREACH(node, &fdir_info->fdir_list, entries) {
1120 : 0 : (void)fdir_write_perfect_filter(hw,
1121 : : &node->input,
1122 : 0 : node->queue,
1123 : : node->fdirflags,
1124 : : node->fdirhash,
1125 : : fdir_mode);
1126 : : }
1127 : : } else {
1128 [ # # ]: 0 : TAILQ_FOREACH(node, &fdir_info->fdir_list, entries) {
1129 : 0 : (void)fdir_add_signature_filter(hw,
1130 : : &node->input,
1131 : 0 : node->queue,
1132 : : node->fdirflags,
1133 : : node->fdirhash);
1134 : : }
1135 : : }
1136 : 0 : }
1137 : :
1138 : : /* remove all the flow director filters */
1139 : : int
1140 : 0 : txgbe_clear_all_fdir_filter(struct rte_eth_dev *dev)
1141 : : {
1142 : 0 : struct rte_eth_fdir_conf *fdir_conf = TXGBE_DEV_FDIR_CONF(dev);
1143 : : struct txgbe_hw_fdir_info *fdir_info = TXGBE_DEV_FDIR(dev);
1144 : : struct txgbe_fdir_filter *fdir_filter;
1145 : : struct txgbe_fdir_filter *filter_flag;
1146 : : int ret = 0;
1147 : :
1148 : : /* flush flow director */
1149 : 0 : rte_hash_reset(fdir_info->hash_handle);
1150 : 0 : memset(fdir_info->hash_map, 0,
1151 : : sizeof(struct txgbe_fdir_filter *) *
1152 : 0 : ((1024 << (fdir_conf->pballoc + 1)) - 2));
1153 : 0 : fdir_conf->mode = RTE_FDIR_MODE_NONE;
1154 : 0 : filter_flag = TAILQ_FIRST(&fdir_info->fdir_list);
1155 [ # # ]: 0 : while ((fdir_filter = TAILQ_FIRST(&fdir_info->fdir_list))) {
1156 [ # # ]: 0 : TAILQ_REMOVE(&fdir_info->fdir_list,
1157 : : fdir_filter,
1158 : : entries);
1159 : 0 : rte_free(fdir_filter);
1160 : : }
1161 : :
1162 [ # # ]: 0 : if (filter_flag != NULL)
1163 : 0 : ret = txgbe_fdir_flush(dev);
1164 : :
1165 : 0 : return ret;
1166 : : }
|