1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2020 Intel Corporation
3 */
4
5 #include "rte_malloc.h"
6 #include "igc_logs.h"
7 #include "igc_txrx.h"
8 #include "igc_filter.h"
9 #include "igc_flow.h"
10
11 /*
12 * igc_ethertype_filter_lookup - lookup ether-type filter
13 *
14 * @igc, IGC filter pointer
15 * @ethertype, ethernet type
16 * @empty, a place to store the index of empty entry if the item not found
17 * it's not smaller than 0 if valid, otherwise -1 for no empty entry.
18 * empty parameter is only valid if the return value of the function is -1
19 *
20 * Return value
21 * >= 0, item index of the ether-type filter
22 * -1, the item not been found
23 */
24 static inline int
igc_ethertype_filter_lookup(const struct igc_adapter * igc,uint16_t ethertype,int * empty)25 igc_ethertype_filter_lookup(const struct igc_adapter *igc,
26 uint16_t ethertype, int *empty)
27 {
28 int i = 0;
29
30 if (empty) {
31 /* set to invalid valid */
32 *empty = -1;
33
34 /* search the filters array */
35 for (; i < IGC_MAX_ETQF_FILTERS; i++) {
36 if (igc->ethertype_filters[i].ether_type == ethertype)
37 return i;
38 if (igc->ethertype_filters[i].ether_type == 0) {
39 /* get empty entry */
40 *empty = i;
41 i++;
42 break;
43 }
44 }
45 }
46
47 /* search the rest of filters */
48 for (; i < IGC_MAX_ETQF_FILTERS; i++) {
49 if (igc->ethertype_filters[i].ether_type == ethertype)
50 return i; /* filter be found, return index */
51 }
52
53 return -1;
54 }
55
56 int
igc_del_ethertype_filter(struct rte_eth_dev * dev,const struct igc_ethertype_filter * filter)57 igc_del_ethertype_filter(struct rte_eth_dev *dev,
58 const struct igc_ethertype_filter *filter)
59 {
60 struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
61 struct igc_adapter *igc = IGC_DEV_PRIVATE(dev);
62 int ret;
63
64 if (filter->ether_type == 0) {
65 PMD_DRV_LOG(ERR, "Ethertype 0 is not been supported");
66 return -EINVAL;
67 }
68
69 ret = igc_ethertype_filter_lookup(igc, filter->ether_type, NULL);
70 if (ret < 0) {
71 /* not found */
72 PMD_DRV_LOG(ERR,
73 "Ethertype (0x%04x) filter doesn't exist",
74 filter->ether_type);
75 return -ENOENT;
76 }
77
78 igc->ethertype_filters[ret].ether_type = 0;
79
80 IGC_WRITE_REG(hw, IGC_ETQF(ret), 0);
81 IGC_WRITE_FLUSH(hw);
82 return 0;
83 }
84
85 int
igc_add_ethertype_filter(struct rte_eth_dev * dev,const struct igc_ethertype_filter * filter)86 igc_add_ethertype_filter(struct rte_eth_dev *dev,
87 const struct igc_ethertype_filter *filter)
88 {
89 struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
90 struct igc_adapter *igc = IGC_DEV_PRIVATE(dev);
91 uint32_t etqf;
92 int ret, empty;
93
94 if (filter->ether_type == RTE_ETHER_TYPE_IPV4 ||
95 filter->ether_type == RTE_ETHER_TYPE_IPV6 ||
96 filter->ether_type == 0) {
97 PMD_DRV_LOG(ERR,
98 "Unsupported ether_type(0x%04x) in ethertype filter",
99 filter->ether_type);
100 return -EINVAL;
101 }
102
103 ret = igc_ethertype_filter_lookup(igc, filter->ether_type, &empty);
104 if (ret >= 0) {
105 PMD_DRV_LOG(ERR, "ethertype (0x%04x) filter exists.",
106 filter->ether_type);
107 return -EEXIST;
108 }
109
110 if (empty < 0) {
111 PMD_DRV_LOG(ERR, "no ethertype filter entry.");
112 return -ENOSPC;
113 }
114 ret = empty;
115
116 etqf = filter->ether_type;
117 etqf |= IGC_ETQF_FILTER_ENABLE | IGC_ETQF_QUEUE_ENABLE;
118 etqf |= (uint32_t)filter->queue << IGC_ETQF_QUEUE_SHIFT;
119
120 memcpy(&igc->ethertype_filters[ret], filter, sizeof(*filter));
121
122 IGC_WRITE_REG(hw, IGC_ETQF(ret), etqf);
123 IGC_WRITE_FLUSH(hw);
124 return 0;
125 }
126
127 /* clear all the ether type filters */
128 static void
igc_clear_all_ethertype_filter(struct rte_eth_dev * dev)129 igc_clear_all_ethertype_filter(struct rte_eth_dev *dev)
130 {
131 struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
132 struct igc_adapter *igc = IGC_DEV_PRIVATE(dev);
133 int i;
134
135 for (i = 0; i < IGC_MAX_ETQF_FILTERS; i++)
136 IGC_WRITE_REG(hw, IGC_ETQF(i), 0);
137 IGC_WRITE_FLUSH(hw);
138
139 memset(&igc->ethertype_filters, 0, sizeof(igc->ethertype_filters));
140 }
141
142 /*
143 * igc_tuple_filter_lookup - lookup n-tuple filter
144 *
145 * @igc, igc filter pointer
146 * @ntuple, n-tuple filter pointer
147 * @empty, a place to store the index of empty entry if the item not found
148 * it's not smaller than 0 if valid, otherwise -1 for no empty entry.
149 * The value of empty is uncertain if the return value of the function is
150 * not -1.
151 *
152 * Return value
153 * >= 0, item index of the filter
154 * -1, the item not been found
155 */
156 static int
igc_tuple_filter_lookup(const struct igc_adapter * igc,const struct igc_ntuple_filter * ntuple,int * empty)157 igc_tuple_filter_lookup(const struct igc_adapter *igc,
158 const struct igc_ntuple_filter *ntuple,
159 int *empty)
160 {
161 int i = 0;
162
163 if (empty) {
164 /* set initial value */
165 *empty = -1;
166
167 /* search the filter array */
168 for (; i < IGC_MAX_NTUPLE_FILTERS; i++) {
169 if (igc->ntuple_filters[i].hash_val) {
170 /* compare the hase value */
171 if (ntuple->hash_val ==
172 igc->ntuple_filters[i].hash_val)
173 /* filter be found, return index */
174 return i;
175 } else {
176 /* get the empty entry */
177 *empty = i;
178 i++;
179 break;
180 }
181 }
182 }
183
184 /* search the rest of filters */
185 for (; i < IGC_MAX_NTUPLE_FILTERS; i++) {
186 if (ntuple->hash_val == igc->ntuple_filters[i].hash_val)
187 /* filter be found, return index */
188 return i;
189 }
190
191 return -1;
192 }
193
194 /* Set hardware register values */
195 static void
igc_enable_tuple_filter(struct rte_eth_dev * dev,const struct igc_adapter * igc,uint8_t index)196 igc_enable_tuple_filter(struct rte_eth_dev *dev,
197 const struct igc_adapter *igc, uint8_t index)
198 {
199 struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
200 const struct igc_ntuple_filter *filter = &igc->ntuple_filters[index];
201 const struct igc_ntuple_info *info = &filter->tuple_info;
202 uint32_t ttqf, imir, imir_ext = IGC_IMIREXT_SIZE_BP;
203
204 imir = info->dst_port;
205 imir |= (uint32_t)info->priority << IGC_IMIR_PRIORITY_SHIFT;
206
207 /* 0b means not compare. */
208 if (info->dst_port_mask == 0)
209 imir |= IGC_IMIR_PORT_BP;
210
211 ttqf = IGC_TTQF_DISABLE_MASK | IGC_TTQF_QUEUE_ENABLE;
212 ttqf |= (uint32_t)filter->queue << IGC_TTQF_QUEUE_SHIFT;
213 ttqf |= info->proto;
214
215 if (info->proto_mask)
216 ttqf &= ~IGC_TTQF_MASK_ENABLE;
217
218 /* TCP flags bits setting. */
219 if (info->tcp_flags & RTE_NTUPLE_TCP_FLAGS_MASK) {
220 if (info->tcp_flags & RTE_TCP_URG_FLAG)
221 imir_ext |= IGC_IMIREXT_CTRL_URG;
222 if (info->tcp_flags & RTE_TCP_ACK_FLAG)
223 imir_ext |= IGC_IMIREXT_CTRL_ACK;
224 if (info->tcp_flags & RTE_TCP_PSH_FLAG)
225 imir_ext |= IGC_IMIREXT_CTRL_PSH;
226 if (info->tcp_flags & RTE_TCP_RST_FLAG)
227 imir_ext |= IGC_IMIREXT_CTRL_RST;
228 if (info->tcp_flags & RTE_TCP_SYN_FLAG)
229 imir_ext |= IGC_IMIREXT_CTRL_SYN;
230 if (info->tcp_flags & RTE_TCP_FIN_FLAG)
231 imir_ext |= IGC_IMIREXT_CTRL_FIN;
232 } else {
233 imir_ext |= IGC_IMIREXT_CTRL_BP;
234 }
235
236 IGC_WRITE_REG(hw, IGC_IMIR(index), imir);
237 IGC_WRITE_REG(hw, IGC_TTQF(index), ttqf);
238 IGC_WRITE_REG(hw, IGC_IMIREXT(index), imir_ext);
239 IGC_WRITE_FLUSH(hw);
240 }
241
242 /* Reset hardware register values */
243 static void
igc_disable_tuple_filter(struct rte_eth_dev * dev,uint8_t index)244 igc_disable_tuple_filter(struct rte_eth_dev *dev, uint8_t index)
245 {
246 struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
247
248 IGC_WRITE_REG(hw, IGC_TTQF(index), IGC_TTQF_DISABLE_MASK);
249 IGC_WRITE_REG(hw, IGC_IMIR(index), 0);
250 IGC_WRITE_REG(hw, IGC_IMIREXT(index), 0);
251 IGC_WRITE_FLUSH(hw);
252 }
253
254 int
igc_add_ntuple_filter(struct rte_eth_dev * dev,const struct igc_ntuple_filter * ntuple)255 igc_add_ntuple_filter(struct rte_eth_dev *dev,
256 const struct igc_ntuple_filter *ntuple)
257 {
258 struct igc_adapter *igc = IGC_DEV_PRIVATE(dev);
259 int ret, empty;
260
261 ret = igc_tuple_filter_lookup(igc, ntuple, &empty);
262 if (ret >= 0) {
263 PMD_DRV_LOG(ERR, "filter exists.");
264 return -EEXIST;
265 }
266
267 if (empty < 0) {
268 PMD_DRV_LOG(ERR, "filter no entry.");
269 return -ENOSPC;
270 }
271
272 ret = empty;
273 memcpy(&igc->ntuple_filters[ret], ntuple, sizeof(*ntuple));
274 igc_enable_tuple_filter(dev, igc, (uint8_t)ret);
275 return 0;
276 }
277
278 int
igc_del_ntuple_filter(struct rte_eth_dev * dev,const struct igc_ntuple_filter * ntuple)279 igc_del_ntuple_filter(struct rte_eth_dev *dev,
280 const struct igc_ntuple_filter *ntuple)
281 {
282 struct igc_adapter *igc = IGC_DEV_PRIVATE(dev);
283 int ret;
284
285 ret = igc_tuple_filter_lookup(igc, ntuple, NULL);
286 if (ret < 0) {
287 PMD_DRV_LOG(ERR, "filter not exists.");
288 return -ENOENT;
289 }
290
291 memset(&igc->ntuple_filters[ret], 0, sizeof(*ntuple));
292 igc_disable_tuple_filter(dev, (uint8_t)ret);
293 return 0;
294 }
295
296 /* Clear all the n-tuple filters */
297 static void
igc_clear_all_ntuple_filter(struct rte_eth_dev * dev)298 igc_clear_all_ntuple_filter(struct rte_eth_dev *dev)
299 {
300 struct igc_adapter *igc = IGC_DEV_PRIVATE(dev);
301 int i;
302
303 for (i = 0; i < IGC_MAX_NTUPLE_FILTERS; i++)
304 igc_disable_tuple_filter(dev, i);
305
306 memset(&igc->ntuple_filters, 0, sizeof(igc->ntuple_filters));
307 }
308
309 int
igc_set_syn_filter(struct rte_eth_dev * dev,const struct igc_syn_filter * filter)310 igc_set_syn_filter(struct rte_eth_dev *dev,
311 const struct igc_syn_filter *filter)
312 {
313 struct igc_hw *hw;
314 struct igc_adapter *igc;
315 uint32_t synqf, rfctl;
316
317 if (filter->queue >= IGC_QUEUE_PAIRS_NUM) {
318 PMD_DRV_LOG(ERR, "out of range queue %u(max is %u)",
319 filter->queue, IGC_QUEUE_PAIRS_NUM);
320 return -EINVAL;
321 }
322
323 igc = IGC_DEV_PRIVATE(dev);
324
325 if (igc->syn_filter.enable) {
326 PMD_DRV_LOG(ERR, "SYN filter has been enabled before!");
327 return -EEXIST;
328 }
329
330 hw = IGC_DEV_PRIVATE_HW(dev);
331 synqf = (uint32_t)filter->queue << IGC_SYN_FILTER_QUEUE_SHIFT;
332 synqf |= IGC_SYN_FILTER_ENABLE;
333
334 rfctl = IGC_READ_REG(hw, IGC_RFCTL);
335 if (filter->hig_pri)
336 rfctl |= IGC_RFCTL_SYNQFP;
337 else
338 rfctl &= ~IGC_RFCTL_SYNQFP;
339
340 memcpy(&igc->syn_filter, filter, sizeof(igc->syn_filter));
341 igc->syn_filter.enable = 1;
342
343 IGC_WRITE_REG(hw, IGC_RFCTL, rfctl);
344 IGC_WRITE_REG(hw, IGC_SYNQF(0), synqf);
345 IGC_WRITE_FLUSH(hw);
346 return 0;
347 }
348
349 /* clear the SYN filter */
350 void
igc_clear_syn_filter(struct rte_eth_dev * dev)351 igc_clear_syn_filter(struct rte_eth_dev *dev)
352 {
353 struct igc_hw *hw = IGC_DEV_PRIVATE_HW(dev);
354 struct igc_adapter *igc = IGC_DEV_PRIVATE(dev);
355
356 IGC_WRITE_REG(hw, IGC_SYNQF(0), 0);
357 IGC_WRITE_FLUSH(hw);
358
359 memset(&igc->syn_filter, 0, sizeof(igc->syn_filter));
360 }
361
362 void
igc_clear_all_filter(struct rte_eth_dev * dev)363 igc_clear_all_filter(struct rte_eth_dev *dev)
364 {
365 igc_clear_all_ethertype_filter(dev);
366 igc_clear_all_ntuple_filter(dev);
367 igc_clear_syn_filter(dev);
368 igc_clear_rss_filter(dev);
369 }
370
371 int
eth_igc_filter_ctrl(struct rte_eth_dev * dev,enum rte_filter_type filter_type,enum rte_filter_op filter_op,void * arg)372 eth_igc_filter_ctrl(struct rte_eth_dev *dev, enum rte_filter_type filter_type,
373 enum rte_filter_op filter_op, void *arg)
374 {
375 int ret = 0;
376
377 RTE_SET_USED(dev);
378
379 switch (filter_type) {
380 case RTE_ETH_FILTER_GENERIC:
381 if (filter_op != RTE_ETH_FILTER_GET)
382 return -EINVAL;
383 *(const void **)arg = &igc_flow_ops;
384 break;
385 default:
386 PMD_DRV_LOG(WARNING, "Filter type (%d) not supported",
387 filter_type);
388 ret = -EINVAL;
389 }
390
391 return ret;
392 }
393