net/mlx4: add new memory region support
[dpdk.git] / drivers / net / mlx4 / mlx4_rxtx.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2017 6WIND S.A.
3  * Copyright 2017 Mellanox Technologies, Ltd
4  */
5
6 /**
7  * @file
8  * Data plane functions for mlx4 driver.
9  */
10
11 #include <assert.h>
12 #include <stdint.h>
13 #include <string.h>
14
15 /* Verbs headers do not support -pedantic. */
16 #ifdef PEDANTIC
17 #pragma GCC diagnostic ignored "-Wpedantic"
18 #endif
19 #include <infiniband/verbs.h>
20 #ifdef PEDANTIC
21 #pragma GCC diagnostic error "-Wpedantic"
22 #endif
23
24 #include <rte_branch_prediction.h>
25 #include <rte_common.h>
26 #include <rte_io.h>
27 #include <rte_mbuf.h>
28 #include <rte_mempool.h>
29 #include <rte_prefetch.h>
30
31 #include "mlx4.h"
32 #include "mlx4_prm.h"
33 #include "mlx4_rxtx.h"
34 #include "mlx4_utils.h"
35
36 /**
37  * Pointer-value pair structure used in tx_post_send for saving the first
38  * DWORD (32 byte) of a TXBB.
39  */
40 struct pv {
41         volatile struct mlx4_wqe_data_seg *dseg;
42         uint32_t val;
43 };
44
45 /** A table to translate Rx completion flags to packet type. */
46 uint32_t mlx4_ptype_table[0x100] __rte_cache_aligned = {
47         /*
48          * The index to the array should have:
49          *  bit[7] - MLX4_CQE_L2_TUNNEL
50          *  bit[6] - MLX4_CQE_L2_TUNNEL_IPV4
51          *  bit[5] - MLX4_CQE_STATUS_UDP
52          *  bit[4] - MLX4_CQE_STATUS_TCP
53          *  bit[3] - MLX4_CQE_STATUS_IPV4OPT
54          *  bit[2] - MLX4_CQE_STATUS_IPV6
55          *  bit[1] - MLX4_CQE_STATUS_IPV4F
56          *  bit[0] - MLX4_CQE_STATUS_IPV4
57          * giving a total of up to 256 entries.
58          */
59         [0x00] = RTE_PTYPE_L2_ETHER,
60         [0x01] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
61                      RTE_PTYPE_L4_NONFRAG,
62         [0x02] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
63                      RTE_PTYPE_L4_FRAG,
64         [0x03] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
65                      RTE_PTYPE_L4_FRAG,
66         [0x04] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN,
67         [0x09] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT,
68         [0x0a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT |
69                      RTE_PTYPE_L4_FRAG,
70         [0x11] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
71                      RTE_PTYPE_L4_TCP,
72         [0x12] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
73                      RTE_PTYPE_L4_TCP,
74         [0x14] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
75                      RTE_PTYPE_L4_TCP,
76         [0x18] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT |
77                      RTE_PTYPE_L4_TCP,
78         [0x19] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT |
79                      RTE_PTYPE_L4_TCP,
80         [0x1a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT |
81                      RTE_PTYPE_L4_TCP,
82         [0x21] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
83                      RTE_PTYPE_L4_UDP,
84         [0x22] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
85                      RTE_PTYPE_L4_UDP,
86         [0x24] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
87                      RTE_PTYPE_L4_UDP,
88         [0x28] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT |
89                      RTE_PTYPE_L4_UDP,
90         [0x29] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT |
91                      RTE_PTYPE_L4_UDP,
92         [0x2a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT |
93                      RTE_PTYPE_L4_UDP,
94         /* Tunneled - L3 IPV6 */
95         [0x80] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN,
96         [0x81] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
97                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN,
98         [0x82] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
99                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
100                      RTE_PTYPE_INNER_L4_FRAG,
101         [0x83] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
102                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
103                      RTE_PTYPE_INNER_L4_FRAG,
104         [0x84] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
105                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN,
106         [0x88] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
107                      RTE_PTYPE_INNER_L3_IPV4_EXT,
108         [0x89] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
109                      RTE_PTYPE_INNER_L3_IPV4_EXT,
110         [0x8a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
111                      RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_FRAG,
112         /* Tunneled - L3 IPV6, TCP */
113         [0x91] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
114                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
115                      RTE_PTYPE_INNER_L4_TCP,
116         [0x92] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
117                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
118                      RTE_PTYPE_INNER_L4_FRAG |
119                      RTE_PTYPE_INNER_L4_TCP,
120         [0x93] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
121                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
122                      RTE_PTYPE_INNER_L4_FRAG |
123                      RTE_PTYPE_INNER_L4_TCP,
124         [0x94] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
125                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
126                      RTE_PTYPE_INNER_L4_TCP,
127         [0x98] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
128                      RTE_PTYPE_INNER_L3_IPV4_EXT |
129                      RTE_PTYPE_INNER_L4_TCP,
130         [0x99] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
131                      RTE_PTYPE_INNER_L3_IPV4_EXT |
132                      RTE_PTYPE_INNER_L4_TCP,
133         [0x9a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
134                      RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_FRAG |
135                      RTE_PTYPE_INNER_L4_TCP,
136         /* Tunneled - L3 IPV6, UDP */
137         [0xa1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
138                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
139                      RTE_PTYPE_INNER_L4_UDP,
140         [0xa2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
141                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
142                      RTE_PTYPE_INNER_L4_FRAG |
143                      RTE_PTYPE_INNER_L4_UDP,
144         [0xa3] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
145                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
146                      RTE_PTYPE_INNER_L4_FRAG |
147                      RTE_PTYPE_INNER_L4_UDP,
148         [0xa4] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
149                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
150                      RTE_PTYPE_INNER_L4_UDP,
151         [0xa8] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
152                      RTE_PTYPE_INNER_L3_IPV4_EXT |
153                      RTE_PTYPE_INNER_L4_UDP,
154         [0xa9] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
155                      RTE_PTYPE_INNER_L3_IPV4_EXT |
156                      RTE_PTYPE_INNER_L4_UDP,
157         [0xaa] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
158                      RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_FRAG |
159                      RTE_PTYPE_INNER_L4_UDP,
160         /* Tunneled - L3 IPV4 */
161         [0xc0] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,
162         [0xc1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
163                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN,
164         [0xc2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
165                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
166                      RTE_PTYPE_INNER_L4_FRAG,
167         [0xc3] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
168                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
169                      RTE_PTYPE_INNER_L4_FRAG,
170         [0xc4] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
171                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN,
172         [0xc8] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
173                      RTE_PTYPE_INNER_L3_IPV4_EXT,
174         [0xc9] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
175                      RTE_PTYPE_INNER_L3_IPV4_EXT,
176         [0xca] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
177                      RTE_PTYPE_INNER_L3_IPV4_EXT |
178                      RTE_PTYPE_INNER_L4_FRAG,
179         /* Tunneled - L3 IPV4, TCP */
180         [0xd0] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
181                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
182                      RTE_PTYPE_INNER_L4_TCP,
183         [0xd1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
184                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
185                      RTE_PTYPE_INNER_L4_TCP,
186         [0xd2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
187                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
188                      RTE_PTYPE_INNER_L4_FRAG |
189                      RTE_PTYPE_INNER_L4_TCP,
190         [0xd3] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
191                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
192                      RTE_PTYPE_INNER_L4_FRAG |
193                      RTE_PTYPE_INNER_L4_TCP,
194         [0xd4] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
195                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
196                      RTE_PTYPE_INNER_L4_TCP,
197         [0xd8] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
198                      RTE_PTYPE_INNER_L3_IPV4_EXT |
199                      RTE_PTYPE_INNER_L4_TCP,
200         [0xd9] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
201                      RTE_PTYPE_INNER_L3_IPV4_EXT |
202                      RTE_PTYPE_INNER_L4_TCP,
203         [0xda] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
204                      RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_FRAG |
205                      RTE_PTYPE_INNER_L4_TCP,
206         /* Tunneled - L3 IPV4, UDP */
207         [0xe0] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
208                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
209                      RTE_PTYPE_INNER_L4_UDP,
210         [0xe1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
211                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
212                      RTE_PTYPE_INNER_L4_UDP,
213         [0xe2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
214                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
215                      RTE_PTYPE_INNER_L4_FRAG |
216                      RTE_PTYPE_INNER_L4_UDP,
217         [0xe3] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
218                      RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
219                      RTE_PTYPE_INNER_L4_FRAG |
220                      RTE_PTYPE_INNER_L4_UDP,
221         [0xe4] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
222                      RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
223                      RTE_PTYPE_INNER_L4_UDP,
224         [0xe8] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
225                      RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP,
226         [0xe9] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
227                      RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_UDP,
228         [0xea] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
229                      RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_FRAG |
230                      RTE_PTYPE_INNER_L4_UDP,
231 };
232
233 /**
234  * Stamp TXBB burst so it won't be reused by the HW.
235  *
236  * Routine is used when freeing WQE used by the chip or when failing
237  * building an WQ entry has failed leaving partial information on the queue.
238  *
239  * @param sq
240  *   Pointer to the SQ structure.
241  * @param start
242  *   Pointer to the first TXBB to stamp.
243  * @param end
244  *   Pointer to the followed end TXBB to stamp.
245  *
246  * @return
247  *   Stamping burst size in byte units.
248  */
249 static uint32_t
250 mlx4_txq_stamp_freed_wqe(struct mlx4_sq *sq, volatile uint32_t *start,
251                          volatile uint32_t *end)
252 {
253         uint32_t stamp = sq->stamp;
254         int32_t size = (intptr_t)end - (intptr_t)start;
255
256         assert(start != end);
257         /* Hold SQ ring wrap around. */
258         if (size < 0) {
259                 size = (int32_t)sq->size + size;
260                 do {
261                         *start = stamp;
262                         start += MLX4_SQ_STAMP_DWORDS;
263                 } while (start != (volatile uint32_t *)sq->eob);
264                 start = (volatile uint32_t *)sq->buf;
265                 /* Flip invalid stamping ownership. */
266                 stamp ^= RTE_BE32(0x1 << MLX4_SQ_OWNER_BIT);
267                 sq->stamp = stamp;
268                 if (start == end)
269                         return size;
270         }
271         do {
272                 *start = stamp;
273                 start += MLX4_SQ_STAMP_DWORDS;
274         } while (start != end);
275         return (uint32_t)size;
276 }
277
278 /**
279  * Manage Tx completions.
280  *
281  * When sending a burst, mlx4_tx_burst() posts several WRs.
282  * To improve performance, a completion event is only required once every
283  * MLX4_PMD_TX_PER_COMP_REQ sends. Doing so discards completion information
284  * for other WRs, but this information would not be used anyway.
285  *
286  * @param txq
287  *   Pointer to Tx queue structure.
288  * @param elts_m
289  *   Tx elements number mask.
290  * @param sq
291  *   Pointer to the SQ structure.
292  */
293 static void
294 mlx4_txq_complete(struct txq *txq, const unsigned int elts_m,
295                   struct mlx4_sq *sq)
296 {
297         unsigned int elts_tail = txq->elts_tail;
298         struct mlx4_cq *cq = &txq->mcq;
299         volatile struct mlx4_cqe *cqe;
300         uint32_t completed;
301         uint32_t cons_index = cq->cons_index;
302         volatile uint32_t *first_txbb;
303
304         /*
305          * Traverse over all CQ entries reported and handle each WQ entry
306          * reported by them.
307          */
308         do {
309                 cqe = (volatile struct mlx4_cqe *)mlx4_get_cqe(cq, cons_index);
310                 if (unlikely(!!(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK) ^
311                     !!(cons_index & cq->cqe_cnt)))
312                         break;
313 #ifndef NDEBUG
314                 /*
315                  * Make sure we read the CQE after we read the ownership bit.
316                  */
317                 rte_io_rmb();
318                 if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) ==
319                              MLX4_CQE_OPCODE_ERROR)) {
320                         volatile struct mlx4_err_cqe *cqe_err =
321                                 (volatile struct mlx4_err_cqe *)cqe;
322                         ERROR("%p CQE error - vendor syndrome: 0x%x"
323                               " syndrome: 0x%x\n",
324                               (void *)txq, cqe_err->vendor_err,
325                               cqe_err->syndrome);
326                         break;
327                 }
328 #endif /* NDEBUG */
329                 cons_index++;
330         } while (1);
331         completed = (cons_index - cq->cons_index) * txq->elts_comp_cd_init;
332         if (unlikely(!completed))
333                 return;
334         /* First stamping address is the end of the last one. */
335         first_txbb = (&(*txq->elts)[elts_tail & elts_m])->eocb;
336         elts_tail += completed;
337         /* The new tail element holds the end address. */
338         sq->remain_size += mlx4_txq_stamp_freed_wqe(sq, first_txbb,
339                 (&(*txq->elts)[elts_tail & elts_m])->eocb);
340         /* Update CQ consumer index. */
341         cq->cons_index = cons_index;
342         *cq->set_ci_db = rte_cpu_to_be_32(cons_index & MLX4_CQ_DB_CI_MASK);
343         txq->elts_tail = elts_tail;
344 }
345
346 /**
347  * Write Tx data segment to the SQ.
348  *
349  * @param dseg
350  *   Pointer to data segment in SQ.
351  * @param lkey
352  *   Memory region lkey.
353  * @param addr
354  *   Data address.
355  * @param byte_count
356  *   Big endian bytes count of the data to send.
357  */
358 static inline void
359 mlx4_fill_tx_data_seg(volatile struct mlx4_wqe_data_seg *dseg,
360                        uint32_t lkey, uintptr_t addr, rte_be32_t  byte_count)
361 {
362         dseg->addr = rte_cpu_to_be_64(addr);
363         dseg->lkey = lkey;
364 #if RTE_CACHE_LINE_SIZE < 64
365         /*
366          * Need a barrier here before writing the byte_count
367          * fields to make sure that all the data is visible
368          * before the byte_count field is set.
369          * Otherwise, if the segment begins a new cacheline,
370          * the HCA prefetcher could grab the 64-byte chunk and
371          * get a valid (!= 0xffffffff) byte count but stale
372          * data, and end up sending the wrong data.
373          */
374         rte_io_wmb();
375 #endif /* RTE_CACHE_LINE_SIZE */
376         dseg->byte_count = byte_count;
377 }
378
379 /**
380  * Write data segments of multi-segment packet.
381  *
382  * @param buf
383  *   Pointer to the first packet mbuf.
384  * @param txq
385  *   Pointer to Tx queue structure.
386  * @param ctrl
387  *   Pointer to the WQE control segment.
388  *
389  * @return
390  *   Pointer to the next WQE control segment on success, NULL otherwise.
391  */
392 static volatile struct mlx4_wqe_ctrl_seg *
393 mlx4_tx_burst_segs(struct rte_mbuf *buf, struct txq *txq,
394                    volatile struct mlx4_wqe_ctrl_seg *ctrl)
395 {
396         struct pv *pv = (struct pv *)txq->bounce_buf;
397         struct mlx4_sq *sq = &txq->msq;
398         struct rte_mbuf *sbuf = buf;
399         uint32_t lkey;
400         int pv_counter = 0;
401         int nb_segs = buf->nb_segs;
402         uint32_t wqe_size;
403         volatile struct mlx4_wqe_data_seg *dseg =
404                 (volatile struct mlx4_wqe_data_seg *)(ctrl + 1);
405
406         ctrl->fence_size = 1 + nb_segs;
407         wqe_size = RTE_ALIGN((uint32_t)(ctrl->fence_size << MLX4_SEG_SHIFT),
408                              MLX4_TXBB_SIZE);
409         /* Validate WQE size and WQE space in the send queue. */
410         if (sq->remain_size < wqe_size ||
411             wqe_size > MLX4_MAX_WQE_SIZE)
412                 return NULL;
413         /*
414          * Fill the data segments with buffer information.
415          * First WQE TXBB head segment is always control segment,
416          * so jump to tail TXBB data segments code for the first
417          * WQE data segments filling.
418          */
419         goto txbb_tail_segs;
420 txbb_head_seg:
421         /* Memory region key (big endian) for this memory pool. */
422         lkey = mlx4_tx_mb2mr(txq, sbuf);
423         if (unlikely(lkey == (uint32_t)-1)) {
424                 DEBUG("%p: unable to get MP <-> MR association",
425                       (void *)txq);
426                 return NULL;
427         }
428         /* Handle WQE wraparound. */
429         if (dseg >=
430                 (volatile struct mlx4_wqe_data_seg *)sq->eob)
431                 dseg = (volatile struct mlx4_wqe_data_seg *)
432                         sq->buf;
433         dseg->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(sbuf, uintptr_t));
434         dseg->lkey = lkey;
435         /*
436          * This data segment starts at the beginning of a new
437          * TXBB, so we need to postpone its byte_count writing
438          * for later.
439          */
440         pv[pv_counter].dseg = dseg;
441         /*
442          * Zero length segment is treated as inline segment
443          * with zero data.
444          */
445         pv[pv_counter++].val = rte_cpu_to_be_32(sbuf->data_len ?
446                                                 sbuf->data_len : 0x80000000);
447         sbuf = sbuf->next;
448         dseg++;
449         nb_segs--;
450 txbb_tail_segs:
451         /* Jump to default if there are more than two segments remaining. */
452         switch (nb_segs) {
453         default:
454                 lkey = mlx4_tx_mb2mr(txq, sbuf);
455                 if (unlikely(lkey == (uint32_t)-1)) {
456                         DEBUG("%p: unable to get MP <-> MR association",
457                               (void *)txq);
458                         return NULL;
459                 }
460                 mlx4_fill_tx_data_seg(dseg, lkey,
461                                       rte_pktmbuf_mtod(sbuf, uintptr_t),
462                                       rte_cpu_to_be_32(sbuf->data_len ?
463                                                        sbuf->data_len :
464                                                        0x80000000));
465                 sbuf = sbuf->next;
466                 dseg++;
467                 nb_segs--;
468                 /* fallthrough */
469         case 2:
470                 lkey = mlx4_tx_mb2mr(txq, sbuf);
471                 if (unlikely(lkey == (uint32_t)-1)) {
472                         DEBUG("%p: unable to get MP <-> MR association",
473                               (void *)txq);
474                         return NULL;
475                 }
476                 mlx4_fill_tx_data_seg(dseg, lkey,
477                                       rte_pktmbuf_mtod(sbuf, uintptr_t),
478                                       rte_cpu_to_be_32(sbuf->data_len ?
479                                                        sbuf->data_len :
480                                                        0x80000000));
481                 sbuf = sbuf->next;
482                 dseg++;
483                 nb_segs--;
484                 /* fallthrough */
485         case 1:
486                 lkey = mlx4_tx_mb2mr(txq, sbuf);
487                 if (unlikely(lkey == (uint32_t)-1)) {
488                         DEBUG("%p: unable to get MP <-> MR association",
489                               (void *)txq);
490                         return NULL;
491                 }
492                 mlx4_fill_tx_data_seg(dseg, lkey,
493                                       rte_pktmbuf_mtod(sbuf, uintptr_t),
494                                       rte_cpu_to_be_32(sbuf->data_len ?
495                                                        sbuf->data_len :
496                                                        0x80000000));
497                 nb_segs--;
498                 if (nb_segs) {
499                         sbuf = sbuf->next;
500                         dseg++;
501                         goto txbb_head_seg;
502                 }
503                 /* fallthrough */
504         case 0:
505                 break;
506         }
507         /* Write the first DWORD of each TXBB save earlier. */
508         if (pv_counter) {
509                 /* Need a barrier here before writing the byte_count. */
510                 rte_io_wmb();
511                 for (--pv_counter; pv_counter  >= 0; pv_counter--)
512                         pv[pv_counter].dseg->byte_count = pv[pv_counter].val;
513         }
514         sq->remain_size -= wqe_size;
515         /* Align next WQE address to the next TXBB. */
516         return (volatile struct mlx4_wqe_ctrl_seg *)
517                 ((volatile uint8_t *)ctrl + wqe_size);
518 }
519
520 /**
521  * DPDK callback for Tx.
522  *
523  * @param dpdk_txq
524  *   Generic pointer to Tx queue structure.
525  * @param[in] pkts
526  *   Packets to transmit.
527  * @param pkts_n
528  *   Number of packets in array.
529  *
530  * @return
531  *   Number of packets successfully transmitted (<= pkts_n).
532  */
533 uint16_t
534 mlx4_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
535 {
536         struct txq *txq = (struct txq *)dpdk_txq;
537         unsigned int elts_head = txq->elts_head;
538         const unsigned int elts_n = txq->elts_n;
539         const unsigned int elts_m = elts_n - 1;
540         unsigned int bytes_sent = 0;
541         unsigned int i;
542         unsigned int max = elts_head - txq->elts_tail;
543         struct mlx4_sq *sq = &txq->msq;
544         volatile struct mlx4_wqe_ctrl_seg *ctrl;
545         struct txq_elt *elt;
546
547         assert(txq->elts_comp_cd != 0);
548         if (likely(max >= txq->elts_comp_cd_init))
549                 mlx4_txq_complete(txq, elts_m, sq);
550         max = elts_n - max;
551         assert(max >= 1);
552         assert(max <= elts_n);
553         /* Always leave one free entry in the ring. */
554         --max;
555         if (max > pkts_n)
556                 max = pkts_n;
557         elt = &(*txq->elts)[elts_head & elts_m];
558         /* First Tx burst element saves the next WQE control segment. */
559         ctrl = elt->wqe;
560         for (i = 0; (i != max); ++i) {
561                 struct rte_mbuf *buf = pkts[i];
562                 struct txq_elt *elt_next = &(*txq->elts)[++elts_head & elts_m];
563                 uint32_t owner_opcode = sq->owner_opcode;
564                 volatile struct mlx4_wqe_data_seg *dseg =
565                                 (volatile struct mlx4_wqe_data_seg *)(ctrl + 1);
566                 volatile struct mlx4_wqe_ctrl_seg *ctrl_next;
567                 union {
568                         uint32_t flags;
569                         uint16_t flags16[2];
570                 } srcrb;
571                 uint32_t lkey;
572
573                 /* Clean up old buffer. */
574                 if (likely(elt->buf != NULL)) {
575                         struct rte_mbuf *tmp = elt->buf;
576
577 #ifndef NDEBUG
578                         /* Poisoning. */
579                         memset(&elt->buf, 0x66, sizeof(struct rte_mbuf *));
580 #endif
581                         /* Faster than rte_pktmbuf_free(). */
582                         do {
583                                 struct rte_mbuf *next = tmp->next;
584
585                                 rte_pktmbuf_free_seg(tmp);
586                                 tmp = next;
587                         } while (tmp != NULL);
588                 }
589                 RTE_MBUF_PREFETCH_TO_FREE(elt_next->buf);
590                 if (buf->nb_segs == 1) {
591                         /* Validate WQE space in the send queue. */
592                         if (sq->remain_size < MLX4_TXBB_SIZE) {
593                                 elt->buf = NULL;
594                                 break;
595                         }
596                         lkey = mlx4_tx_mb2mr(txq, buf);
597                         if (unlikely(lkey == (uint32_t)-1)) {
598                                 /* MR does not exist. */
599                                 DEBUG("%p: unable to get MP <-> MR association",
600                                       (void *)txq);
601                                 elt->buf = NULL;
602                                 break;
603                         }
604                         mlx4_fill_tx_data_seg(dseg++, lkey,
605                                               rte_pktmbuf_mtod(buf, uintptr_t),
606                                               rte_cpu_to_be_32(buf->data_len));
607                         /* Set WQE size in 16-byte units. */
608                         ctrl->fence_size = 0x2;
609                         sq->remain_size -= MLX4_TXBB_SIZE;
610                         /* Align next WQE address to the next TXBB. */
611                         ctrl_next = ctrl + 0x4;
612                 } else {
613                         ctrl_next = mlx4_tx_burst_segs(buf, txq, ctrl);
614                         if (!ctrl_next) {
615                                 elt->buf = NULL;
616                                 break;
617                         }
618                 }
619                 /* Hold SQ ring wrap around. */
620                 if ((volatile uint8_t *)ctrl_next >= sq->eob) {
621                         ctrl_next = (volatile struct mlx4_wqe_ctrl_seg *)
622                                 ((volatile uint8_t *)ctrl_next - sq->size);
623                         /* Flip HW valid ownership. */
624                         sq->owner_opcode ^= 0x1 << MLX4_SQ_OWNER_BIT;
625                 }
626                 /*
627                  * For raw Ethernet, the SOLICIT flag is used to indicate
628                  * that no ICRC should be calculated.
629                  */
630                 if (--txq->elts_comp_cd == 0) {
631                         /* Save the completion burst end address. */
632                         elt_next->eocb = (volatile uint32_t *)ctrl_next;
633                         txq->elts_comp_cd = txq->elts_comp_cd_init;
634                         srcrb.flags = RTE_BE32(MLX4_WQE_CTRL_SOLICIT |
635                                                MLX4_WQE_CTRL_CQ_UPDATE);
636                 } else {
637                         srcrb.flags = RTE_BE32(MLX4_WQE_CTRL_SOLICIT);
638                 }
639                 /* Enable HW checksum offload if requested */
640                 if (txq->csum &&
641                     (buf->ol_flags &
642                      (PKT_TX_IP_CKSUM | PKT_TX_TCP_CKSUM | PKT_TX_UDP_CKSUM))) {
643                         const uint64_t is_tunneled = (buf->ol_flags &
644                                                       (PKT_TX_TUNNEL_GRE |
645                                                        PKT_TX_TUNNEL_VXLAN));
646
647                         if (is_tunneled && txq->csum_l2tun) {
648                                 owner_opcode |= MLX4_WQE_CTRL_IIP_HDR_CSUM |
649                                                 MLX4_WQE_CTRL_IL4_HDR_CSUM;
650                                 if (buf->ol_flags & PKT_TX_OUTER_IP_CKSUM)
651                                         srcrb.flags |=
652                                             RTE_BE32(MLX4_WQE_CTRL_IP_HDR_CSUM);
653                         } else {
654                                 srcrb.flags |=
655                                         RTE_BE32(MLX4_WQE_CTRL_IP_HDR_CSUM |
656                                                 MLX4_WQE_CTRL_TCP_UDP_CSUM);
657                         }
658                 }
659                 if (txq->lb) {
660                         /*
661                          * Copy destination MAC address to the WQE, this allows
662                          * loopback in eSwitch, so that VFs and PF can
663                          * communicate with each other.
664                          */
665                         srcrb.flags16[0] = *(rte_pktmbuf_mtod(buf, uint16_t *));
666                         ctrl->imm = *(rte_pktmbuf_mtod_offset(buf, uint32_t *,
667                                               sizeof(uint16_t)));
668                 } else {
669                         ctrl->imm = 0;
670                 }
671                 ctrl->srcrb_flags = srcrb.flags;
672                 /*
673                  * Make sure descriptor is fully written before
674                  * setting ownership bit (because HW can start
675                  * executing as soon as we do).
676                  */
677                 rte_io_wmb();
678                 ctrl->owner_opcode = rte_cpu_to_be_32(owner_opcode);
679                 elt->buf = buf;
680                 bytes_sent += buf->pkt_len;
681                 ctrl = ctrl_next;
682                 elt = elt_next;
683         }
684         /* Take a shortcut if nothing must be sent. */
685         if (unlikely(i == 0))
686                 return 0;
687         /* Save WQE address of the next Tx burst element. */
688         elt->wqe = ctrl;
689         /* Increment send statistics counters. */
690         txq->stats.opackets += i;
691         txq->stats.obytes += bytes_sent;
692         /* Make sure that descriptors are written before doorbell record. */
693         rte_wmb();
694         /* Ring QP doorbell. */
695         rte_write32(txq->msq.doorbell_qpn, txq->msq.db);
696         txq->elts_head += i;
697         return i;
698 }
699
700 /**
701  * Translate Rx completion flags to packet type.
702  *
703  * @param[in] cqe
704  *   Pointer to CQE.
705  *
706  * @return
707  *   Packet type for struct rte_mbuf.
708  */
709 static inline uint32_t
710 rxq_cq_to_pkt_type(volatile struct mlx4_cqe *cqe,
711                    uint32_t l2tun_offload)
712 {
713         uint8_t idx = 0;
714         uint32_t pinfo = rte_be_to_cpu_32(cqe->vlan_my_qpn);
715         uint32_t status = rte_be_to_cpu_32(cqe->status);
716
717         /*
718          * The index to the array should have:
719          *  bit[7] - MLX4_CQE_L2_TUNNEL
720          *  bit[6] - MLX4_CQE_L2_TUNNEL_IPV4
721          */
722         if (l2tun_offload && (pinfo & MLX4_CQE_L2_TUNNEL))
723                 idx |= ((pinfo & MLX4_CQE_L2_TUNNEL) >> 20) |
724                        ((pinfo & MLX4_CQE_L2_TUNNEL_IPV4) >> 19);
725         /*
726          * The index to the array should have:
727          *  bit[5] - MLX4_CQE_STATUS_UDP
728          *  bit[4] - MLX4_CQE_STATUS_TCP
729          *  bit[3] - MLX4_CQE_STATUS_IPV4OPT
730          *  bit[2] - MLX4_CQE_STATUS_IPV6
731          *  bit[1] - MLX4_CQE_STATUS_IPV4F
732          *  bit[0] - MLX4_CQE_STATUS_IPV4
733          * giving a total of up to 256 entries.
734          */
735         idx |= ((status & MLX4_CQE_STATUS_PTYPE_MASK) >> 22);
736         return mlx4_ptype_table[idx];
737 }
738
739 /**
740  * Translate Rx completion flags to offload flags.
741  *
742  * @param flags
743  *   Rx completion flags returned by mlx4_cqe_flags().
744  * @param csum
745  *   Whether Rx checksums are enabled.
746  * @param csum_l2tun
747  *   Whether Rx L2 tunnel checksums are enabled.
748  *
749  * @return
750  *   Offload flags (ol_flags) in mbuf format.
751  */
752 static inline uint32_t
753 rxq_cq_to_ol_flags(uint32_t flags, int csum, int csum_l2tun)
754 {
755         uint32_t ol_flags = 0;
756
757         if (csum)
758                 ol_flags |=
759                         mlx4_transpose(flags,
760                                        MLX4_CQE_STATUS_IP_HDR_CSUM_OK,
761                                        PKT_RX_IP_CKSUM_GOOD) |
762                         mlx4_transpose(flags,
763                                        MLX4_CQE_STATUS_TCP_UDP_CSUM_OK,
764                                        PKT_RX_L4_CKSUM_GOOD);
765         if ((flags & MLX4_CQE_L2_TUNNEL) && csum_l2tun)
766                 ol_flags |=
767                         mlx4_transpose(flags,
768                                        MLX4_CQE_L2_TUNNEL_IPOK,
769                                        PKT_RX_IP_CKSUM_GOOD) |
770                         mlx4_transpose(flags,
771                                        MLX4_CQE_L2_TUNNEL_L4_CSUM,
772                                        PKT_RX_L4_CKSUM_GOOD);
773         return ol_flags;
774 }
775
776 /**
777  * Extract checksum information from CQE flags.
778  *
779  * @param cqe
780  *   Pointer to CQE structure.
781  * @param csum
782  *   Whether Rx checksums are enabled.
783  * @param csum_l2tun
784  *   Whether Rx L2 tunnel checksums are enabled.
785  *
786  * @return
787  *   CQE checksum information.
788  */
789 static inline uint32_t
790 mlx4_cqe_flags(volatile struct mlx4_cqe *cqe, int csum, int csum_l2tun)
791 {
792         uint32_t flags = 0;
793
794         /*
795          * The relevant bits are in different locations on their
796          * CQE fields therefore we can join them in one 32bit
797          * variable.
798          */
799         if (csum)
800                 flags = (rte_be_to_cpu_32(cqe->status) &
801                          MLX4_CQE_STATUS_IPV4_CSUM_OK);
802         if (csum_l2tun)
803                 flags |= (rte_be_to_cpu_32(cqe->vlan_my_qpn) &
804                           (MLX4_CQE_L2_TUNNEL |
805                            MLX4_CQE_L2_TUNNEL_IPOK |
806                            MLX4_CQE_L2_TUNNEL_L4_CSUM |
807                            MLX4_CQE_L2_TUNNEL_IPV4));
808         return flags;
809 }
810
811 /**
812  * Poll one CQE from CQ.
813  *
814  * @param rxq
815  *   Pointer to the receive queue structure.
816  * @param[out] out
817  *   Just polled CQE.
818  *
819  * @return
820  *   Number of bytes of the CQE, 0 in case there is no completion.
821  */
822 static unsigned int
823 mlx4_cq_poll_one(struct rxq *rxq, volatile struct mlx4_cqe **out)
824 {
825         int ret = 0;
826         volatile struct mlx4_cqe *cqe = NULL;
827         struct mlx4_cq *cq = &rxq->mcq;
828
829         cqe = (volatile struct mlx4_cqe *)mlx4_get_cqe(cq, cq->cons_index);
830         if (!!(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK) ^
831             !!(cq->cons_index & cq->cqe_cnt))
832                 goto out;
833         /*
834          * Make sure we read CQ entry contents after we've checked the
835          * ownership bit.
836          */
837         rte_rmb();
838         assert(!(cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK));
839         assert((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) !=
840                MLX4_CQE_OPCODE_ERROR);
841         ret = rte_be_to_cpu_32(cqe->byte_cnt);
842         ++cq->cons_index;
843 out:
844         *out = cqe;
845         return ret;
846 }
847
848 /**
849  * DPDK callback for Rx with scattered packets support.
850  *
851  * @param dpdk_rxq
852  *   Generic pointer to Rx queue structure.
853  * @param[out] pkts
854  *   Array to store received packets.
855  * @param pkts_n
856  *   Maximum number of packets in array.
857  *
858  * @return
859  *   Number of packets successfully received (<= pkts_n).
860  */
861 uint16_t
862 mlx4_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
863 {
864         struct rxq *rxq = dpdk_rxq;
865         const uint32_t wr_cnt = (1 << rxq->elts_n) - 1;
866         const uint16_t sges_n = rxq->sges_n;
867         struct rte_mbuf *pkt = NULL;
868         struct rte_mbuf *seg = NULL;
869         unsigned int i = 0;
870         uint32_t rq_ci = rxq->rq_ci << sges_n;
871         int len = 0;
872
873         while (pkts_n) {
874                 volatile struct mlx4_cqe *cqe;
875                 uint32_t idx = rq_ci & wr_cnt;
876                 struct rte_mbuf *rep = (*rxq->elts)[idx];
877                 volatile struct mlx4_wqe_data_seg *scat = &(*rxq->wqes)[idx];
878
879                 /* Update the 'next' pointer of the previous segment. */
880                 if (pkt)
881                         seg->next = rep;
882                 seg = rep;
883                 rte_prefetch0(seg);
884                 rte_prefetch0(scat);
885                 rep = rte_mbuf_raw_alloc(rxq->mp);
886                 if (unlikely(rep == NULL)) {
887                         ++rxq->stats.rx_nombuf;
888                         if (!pkt) {
889                                 /*
890                                  * No buffers before we even started,
891                                  * bail out silently.
892                                  */
893                                 break;
894                         }
895                         while (pkt != seg) {
896                                 assert(pkt != (*rxq->elts)[idx]);
897                                 rep = pkt->next;
898                                 pkt->next = NULL;
899                                 pkt->nb_segs = 1;
900                                 rte_mbuf_raw_free(pkt);
901                                 pkt = rep;
902                         }
903                         break;
904                 }
905                 if (!pkt) {
906                         /* Looking for the new packet. */
907                         len = mlx4_cq_poll_one(rxq, &cqe);
908                         if (!len) {
909                                 rte_mbuf_raw_free(rep);
910                                 break;
911                         }
912                         if (unlikely(len < 0)) {
913                                 /* Rx error, packet is likely too large. */
914                                 rte_mbuf_raw_free(rep);
915                                 ++rxq->stats.idropped;
916                                 goto skip;
917                         }
918                         pkt = seg;
919                         assert(len >= (rxq->crc_present << 2));
920                         /* Update packet information. */
921                         pkt->packet_type =
922                                 rxq_cq_to_pkt_type(cqe, rxq->l2tun_offload);
923                         pkt->ol_flags = PKT_RX_RSS_HASH;
924                         pkt->hash.rss = cqe->immed_rss_invalid;
925                         if (rxq->crc_present)
926                                 len -= ETHER_CRC_LEN;
927                         pkt->pkt_len = len;
928                         if (rxq->csum | rxq->csum_l2tun) {
929                                 uint32_t flags =
930                                         mlx4_cqe_flags(cqe,
931                                                        rxq->csum,
932                                                        rxq->csum_l2tun);
933
934                                 pkt->ol_flags =
935                                         rxq_cq_to_ol_flags(flags,
936                                                            rxq->csum,
937                                                            rxq->csum_l2tun);
938                         }
939                 }
940                 rep->nb_segs = 1;
941                 rep->port = rxq->port_id;
942                 rep->data_len = seg->data_len;
943                 rep->data_off = seg->data_off;
944                 (*rxq->elts)[idx] = rep;
945                 /*
946                  * Fill NIC descriptor with the new buffer. The lkey and size
947                  * of the buffers are already known, only the buffer address
948                  * changes.
949                  */
950                 scat->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t));
951                 /* If there's only one MR, no need to replace LKey in WQE. */
952                 if (unlikely(mlx4_mr_btree_len(&rxq->mr_ctrl.cache_bh) > 1))
953                         scat->lkey = mlx4_rx_mb2mr(rxq, rep);
954                 if (len > seg->data_len) {
955                         len -= seg->data_len;
956                         ++pkt->nb_segs;
957                         ++rq_ci;
958                         continue;
959                 }
960                 /* The last segment. */
961                 seg->data_len = len;
962                 /* Increment bytes counter. */
963                 rxq->stats.ibytes += pkt->pkt_len;
964                 /* Return packet. */
965                 *(pkts++) = pkt;
966                 pkt = NULL;
967                 --pkts_n;
968                 ++i;
969 skip:
970                 /* Align consumer index to the next stride. */
971                 rq_ci >>= sges_n;
972                 ++rq_ci;
973                 rq_ci <<= sges_n;
974         }
975         if (unlikely(i == 0 && (rq_ci >> sges_n) == rxq->rq_ci))
976                 return 0;
977         /* Update the consumer index. */
978         rxq->rq_ci = rq_ci >> sges_n;
979         rte_wmb();
980         *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
981         *rxq->mcq.set_ci_db =
982                 rte_cpu_to_be_32(rxq->mcq.cons_index & MLX4_CQ_DB_CI_MASK);
983         /* Increment packets counter. */
984         rxq->stats.ipackets += i;
985         return i;
986 }
987
988 /**
989  * Dummy DPDK callback for Tx.
990  *
991  * This function is used to temporarily replace the real callback during
992  * unsafe control operations on the queue, or in case of error.
993  *
994  * @param dpdk_txq
995  *   Generic pointer to Tx queue structure.
996  * @param[in] pkts
997  *   Packets to transmit.
998  * @param pkts_n
999  *   Number of packets in array.
1000  *
1001  * @return
1002  *   Number of packets successfully transmitted (<= pkts_n).
1003  */
1004 uint16_t
1005 mlx4_tx_burst_removed(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
1006 {
1007         (void)dpdk_txq;
1008         (void)pkts;
1009         (void)pkts_n;
1010         return 0;
1011 }
1012
1013 /**
1014  * Dummy DPDK callback for Rx.
1015  *
1016  * This function is used to temporarily replace the real callback during
1017  * unsafe control operations on the queue, or in case of error.
1018  *
1019  * @param dpdk_rxq
1020  *   Generic pointer to Rx queue structure.
1021  * @param[out] pkts
1022  *   Array to store received packets.
1023  * @param pkts_n
1024  *   Maximum number of packets in array.
1025  *
1026  * @return
1027  *   Number of packets successfully received (<= pkts_n).
1028  */
1029 uint16_t
1030 mlx4_rx_burst_removed(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
1031 {
1032         (void)dpdk_rxq;
1033         (void)pkts;
1034         (void)pkts_n;
1035         return 0;
1036 }