182092c87SOlivier Matz /* SPDX-License-Identifier: BSD-3-Clause
27f45cb82SAdrien Mazarguil * Copyright 2017 6WIND S.A.
35feecc57SShahaf Shuler * Copyright 2017 Mellanox Technologies, Ltd
47f45cb82SAdrien Mazarguil */
57f45cb82SAdrien Mazarguil
67f45cb82SAdrien Mazarguil /**
77f45cb82SAdrien Mazarguil * @file
87f45cb82SAdrien Mazarguil * Data plane functions for mlx4 driver.
97f45cb82SAdrien Mazarguil */
107f45cb82SAdrien Mazarguil
11028669bcSAnatoly Burakov #include <stdbool.h>
127f45cb82SAdrien Mazarguil #include <stdint.h>
137f45cb82SAdrien Mazarguil #include <string.h>
147f45cb82SAdrien Mazarguil
157f45cb82SAdrien Mazarguil /* Verbs headers do not support -pedantic. */
167f45cb82SAdrien Mazarguil #ifdef PEDANTIC
177f45cb82SAdrien Mazarguil #pragma GCC diagnostic ignored "-Wpedantic"
187f45cb82SAdrien Mazarguil #endif
197f45cb82SAdrien Mazarguil #include <infiniband/verbs.h>
207f45cb82SAdrien Mazarguil #ifdef PEDANTIC
217f45cb82SAdrien Mazarguil #pragma GCC diagnostic error "-Wpedantic"
227f45cb82SAdrien Mazarguil #endif
237f45cb82SAdrien Mazarguil
247f45cb82SAdrien Mazarguil #include <rte_branch_prediction.h>
257f45cb82SAdrien Mazarguil #include <rte_common.h>
26c3c977bbSMoti Haimovsky #include <rte_io.h>
277f45cb82SAdrien Mazarguil #include <rte_mbuf.h>
287f45cb82SAdrien Mazarguil #include <rte_mempool.h>
297f45cb82SAdrien Mazarguil #include <rte_prefetch.h>
307f45cb82SAdrien Mazarguil
317f45cb82SAdrien Mazarguil #include "mlx4.h"
32c3c977bbSMoti Haimovsky #include "mlx4_prm.h"
337f45cb82SAdrien Mazarguil #include "mlx4_rxtx.h"
347f45cb82SAdrien Mazarguil #include "mlx4_utils.h"
357f45cb82SAdrien Mazarguil
367f45cb82SAdrien Mazarguil /**
37c3c977bbSMoti Haimovsky * Pointer-value pair structure used in tx_post_send for saving the first
38c3c977bbSMoti Haimovsky * DWORD (32 byte) of a TXBB.
39c3c977bbSMoti Haimovsky */
40c3c977bbSMoti Haimovsky struct pv {
41ba576975SMoti Haimovsky union {
42b68d92b4SMatan Azrad volatile struct mlx4_wqe_data_seg *dseg;
43ba576975SMoti Haimovsky volatile uint32_t *dst;
44ba576975SMoti Haimovsky };
45c3c977bbSMoti Haimovsky uint32_t val;
46c3c977bbSMoti Haimovsky };
47c3c977bbSMoti Haimovsky
48ba576975SMoti Haimovsky /** A helper structure for TSO packet handling. */
49ba576975SMoti Haimovsky struct tso_info {
50ba576975SMoti Haimovsky /** Pointer to the array of saved first DWORD (32 byte) of a TXBB. */
51ba576975SMoti Haimovsky struct pv *pv;
52ba576975SMoti Haimovsky /** Current entry in the pv array. */
53ba576975SMoti Haimovsky int pv_counter;
54ba576975SMoti Haimovsky /** Total size of the WQE including padding. */
55ba576975SMoti Haimovsky uint32_t wqe_size;
56ba576975SMoti Haimovsky /** Size of TSO header to prepend to each packet to send. */
57ba576975SMoti Haimovsky uint16_t tso_header_size;
58ba576975SMoti Haimovsky /** Total size of the TSO segment in the WQE. */
59ba576975SMoti Haimovsky uint16_t wqe_tso_seg_size;
60ba576975SMoti Haimovsky /** Raw WQE size in units of 16 Bytes and without padding. */
61ba576975SMoti Haimovsky uint8_t fence_size;
62ba576975SMoti Haimovsky };
63ba576975SMoti Haimovsky
64aee4a03fSMoti Haimovsky /** A table to translate Rx completion flags to packet type. */
65*27595cd8STyler Retzlaff alignas(RTE_CACHE_LINE_SIZE) uint32_t mlx4_ptype_table[0x100] = {
66aee4a03fSMoti Haimovsky /*
67aee4a03fSMoti Haimovsky * The index to the array should have:
68aee4a03fSMoti Haimovsky * bit[7] - MLX4_CQE_L2_TUNNEL
69aee4a03fSMoti Haimovsky * bit[6] - MLX4_CQE_L2_TUNNEL_IPV4
70aee4a03fSMoti Haimovsky * bit[5] - MLX4_CQE_STATUS_UDP
71aee4a03fSMoti Haimovsky * bit[4] - MLX4_CQE_STATUS_TCP
72aee4a03fSMoti Haimovsky * bit[3] - MLX4_CQE_STATUS_IPV4OPT
73aee4a03fSMoti Haimovsky * bit[2] - MLX4_CQE_STATUS_IPV6
74c4fbea4bSMoti Haimovsky * bit[1] - MLX4_CQE_STATUS_IPF
75aee4a03fSMoti Haimovsky * bit[0] - MLX4_CQE_STATUS_IPV4
76aee4a03fSMoti Haimovsky * giving a total of up to 256 entries.
77aee4a03fSMoti Haimovsky */
78c4fbea4bSMoti Haimovsky /* L2 */
79aee4a03fSMoti Haimovsky [0x00] = RTE_PTYPE_L2_ETHER,
80c4fbea4bSMoti Haimovsky /* L3 */
81c7aaaecdSMoti Haimovsky [0x01] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
82c7aaaecdSMoti Haimovsky RTE_PTYPE_L4_NONFRAG,
83aee4a03fSMoti Haimovsky [0x02] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
84aee4a03fSMoti Haimovsky RTE_PTYPE_L4_FRAG,
85aee4a03fSMoti Haimovsky [0x03] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
86aee4a03fSMoti Haimovsky RTE_PTYPE_L4_FRAG,
87c4fbea4bSMoti Haimovsky [0x04] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
88c4fbea4bSMoti Haimovsky RTE_PTYPE_L4_NONFRAG,
89c4fbea4bSMoti Haimovsky [0x06] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
90c4fbea4bSMoti Haimovsky RTE_PTYPE_L4_FRAG,
91c4fbea4bSMoti Haimovsky [0x08] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT |
92c4fbea4bSMoti Haimovsky RTE_PTYPE_L4_NONFRAG,
93c4fbea4bSMoti Haimovsky [0x09] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT |
94c4fbea4bSMoti Haimovsky RTE_PTYPE_L4_NONFRAG,
95aee4a03fSMoti Haimovsky [0x0a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT |
96aee4a03fSMoti Haimovsky RTE_PTYPE_L4_FRAG,
97c4fbea4bSMoti Haimovsky [0x0b] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT |
98c4fbea4bSMoti Haimovsky RTE_PTYPE_L4_FRAG,
99c4fbea4bSMoti Haimovsky /* TCP */
100aee4a03fSMoti Haimovsky [0x11] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
101aee4a03fSMoti Haimovsky RTE_PTYPE_L4_TCP,
102aee4a03fSMoti Haimovsky [0x14] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
103aee4a03fSMoti Haimovsky RTE_PTYPE_L4_TCP,
104c4fbea4bSMoti Haimovsky [0x16] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
105c4fbea4bSMoti Haimovsky RTE_PTYPE_L4_FRAG,
106aee4a03fSMoti Haimovsky [0x18] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT |
107aee4a03fSMoti Haimovsky RTE_PTYPE_L4_TCP,
108aee4a03fSMoti Haimovsky [0x19] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT |
109aee4a03fSMoti Haimovsky RTE_PTYPE_L4_TCP,
110c4fbea4bSMoti Haimovsky /* UDP */
111aee4a03fSMoti Haimovsky [0x21] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
112aee4a03fSMoti Haimovsky RTE_PTYPE_L4_UDP,
113aee4a03fSMoti Haimovsky [0x24] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
114aee4a03fSMoti Haimovsky RTE_PTYPE_L4_UDP,
115c4fbea4bSMoti Haimovsky [0x26] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
116c4fbea4bSMoti Haimovsky RTE_PTYPE_L4_FRAG,
117aee4a03fSMoti Haimovsky [0x28] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT |
118aee4a03fSMoti Haimovsky RTE_PTYPE_L4_UDP,
119aee4a03fSMoti Haimovsky [0x29] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT |
120aee4a03fSMoti Haimovsky RTE_PTYPE_L4_UDP,
121aee4a03fSMoti Haimovsky /* Tunneled - L3 IPV6 */
122aee4a03fSMoti Haimovsky [0x80] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN,
123aee4a03fSMoti Haimovsky [0x81] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
124c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
125c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_NONFRAG,
126aee4a03fSMoti Haimovsky [0x82] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
127aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
128aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_FRAG,
129aee4a03fSMoti Haimovsky [0x83] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
130aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
131aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_FRAG,
132aee4a03fSMoti Haimovsky [0x84] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
133c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
134c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_NONFRAG,
135c4fbea4bSMoti Haimovsky [0x86] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
136c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
137c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_FRAG,
138aee4a03fSMoti Haimovsky [0x88] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
139c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT |
140c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_NONFRAG,
141aee4a03fSMoti Haimovsky [0x89] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
142c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT |
143c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_NONFRAG,
144aee4a03fSMoti Haimovsky [0x8a] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
145c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT |
146c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_FRAG,
147c4fbea4bSMoti Haimovsky [0x8b] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
148c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT |
149c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_FRAG,
150aee4a03fSMoti Haimovsky /* Tunneled - L3 IPV6, TCP */
151aee4a03fSMoti Haimovsky [0x91] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
152aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
153aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_TCP,
154aee4a03fSMoti Haimovsky [0x94] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
155aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
156aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_TCP,
157c4fbea4bSMoti Haimovsky [0x96] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
158c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
159c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_FRAG,
160aee4a03fSMoti Haimovsky [0x98] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
161c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_TCP,
162aee4a03fSMoti Haimovsky [0x99] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
163c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT | RTE_PTYPE_INNER_L4_TCP,
164aee4a03fSMoti Haimovsky /* Tunneled - L3 IPV6, UDP */
165c4fbea4bSMoti Haimovsky [0xa1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
166aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
167aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_UDP,
168c4fbea4bSMoti Haimovsky [0xa4] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
169aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
170aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_UDP,
171c4fbea4bSMoti Haimovsky [0xa6] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
172c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
173c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_FRAG,
174c4fbea4bSMoti Haimovsky [0xa8] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
175aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT |
176aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_UDP,
177c4fbea4bSMoti Haimovsky [0xa9] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV6_EXT_UNKNOWN |
178aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT |
179aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_UDP,
180aee4a03fSMoti Haimovsky /* Tunneled - L3 IPV4 */
181aee4a03fSMoti Haimovsky [0xc0] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,
182aee4a03fSMoti Haimovsky [0xc1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
183c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
184c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_NONFRAG,
185aee4a03fSMoti Haimovsky [0xc2] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
186aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
187aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_FRAG,
188aee4a03fSMoti Haimovsky [0xc3] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
189aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
190aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_FRAG,
191aee4a03fSMoti Haimovsky [0xc4] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
192c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
193c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_NONFRAG,
194c4fbea4bSMoti Haimovsky [0xc6] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
195c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
196c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_FRAG,
197aee4a03fSMoti Haimovsky [0xc8] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
198c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT |
199c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_NONFRAG,
200aee4a03fSMoti Haimovsky [0xc9] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
201c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT |
202c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_NONFRAG,
203aee4a03fSMoti Haimovsky [0xca] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
204aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT |
205aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_FRAG,
206c4fbea4bSMoti Haimovsky [0xcb] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
207c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT |
208c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_FRAG,
209aee4a03fSMoti Haimovsky /* Tunneled - L3 IPV4, TCP */
210aee4a03fSMoti Haimovsky [0xd1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
211aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
212aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_TCP,
213aee4a03fSMoti Haimovsky [0xd4] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
214aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
215aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_TCP,
216c4fbea4bSMoti Haimovsky [0xd6] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
217c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
218c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_FRAG,
219aee4a03fSMoti Haimovsky [0xd8] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
220aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT |
221aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_TCP,
222aee4a03fSMoti Haimovsky [0xd9] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
223aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT |
224aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_TCP,
225aee4a03fSMoti Haimovsky /* Tunneled - L3 IPV4, UDP */
226aee4a03fSMoti Haimovsky [0xe1] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
227aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT_UNKNOWN |
228aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_UDP,
229aee4a03fSMoti Haimovsky [0xe4] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
230aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
231aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_UDP,
232c4fbea4bSMoti Haimovsky [0xe6] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
233c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV6_EXT_UNKNOWN |
234c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_FRAG,
235aee4a03fSMoti Haimovsky [0xe8] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
236c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT |
237c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L4_UDP,
238aee4a03fSMoti Haimovsky [0xe9] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
239c4fbea4bSMoti Haimovsky RTE_PTYPE_INNER_L3_IPV4_EXT |
240aee4a03fSMoti Haimovsky RTE_PTYPE_INNER_L4_UDP,
241aee4a03fSMoti Haimovsky };
242aee4a03fSMoti Haimovsky
243c3c977bbSMoti Haimovsky /**
24453387152SMatan Azrad * Stamp TXBB burst so it won't be reused by the HW.
245c3c977bbSMoti Haimovsky *
246c3c977bbSMoti Haimovsky * Routine is used when freeing WQE used by the chip or when failing
247c3c977bbSMoti Haimovsky * building an WQ entry has failed leaving partial information on the queue.
248c3c977bbSMoti Haimovsky *
249c3c977bbSMoti Haimovsky * @param sq
250c3c977bbSMoti Haimovsky * Pointer to the SQ structure.
25153387152SMatan Azrad * @param start
25253387152SMatan Azrad * Pointer to the first TXBB to stamp.
25353387152SMatan Azrad * @param end
25453387152SMatan Azrad * Pointer to the followed end TXBB to stamp.
255c3c977bbSMoti Haimovsky *
256c3c977bbSMoti Haimovsky * @return
25753387152SMatan Azrad * Stamping burst size in byte units.
258c3c977bbSMoti Haimovsky */
25978e81a98SMatan Azrad static uint32_t
mlx4_txq_stamp_freed_wqe(struct mlx4_sq * sq,volatile uint32_t * start,volatile uint32_t * end)26053387152SMatan Azrad mlx4_txq_stamp_freed_wqe(struct mlx4_sq *sq, volatile uint32_t *start,
26153387152SMatan Azrad volatile uint32_t *end)
262c3c977bbSMoti Haimovsky {
26378e81a98SMatan Azrad uint32_t stamp = sq->stamp;
26453387152SMatan Azrad int32_t size = (intptr_t)end - (intptr_t)start;
26578e81a98SMatan Azrad
2668e08df22SAlexander Kozyrev MLX4_ASSERT(start != end);
26753387152SMatan Azrad /* Hold SQ ring wrap around. */
26853387152SMatan Azrad if (size < 0) {
26953387152SMatan Azrad size = (int32_t)sq->size + size;
27078e81a98SMatan Azrad do {
27153387152SMatan Azrad *start = stamp;
27253387152SMatan Azrad start += MLX4_SQ_STAMP_DWORDS;
27353387152SMatan Azrad } while (start != (volatile uint32_t *)sq->eob);
27453387152SMatan Azrad start = (volatile uint32_t *)sq->buf;
27578e81a98SMatan Azrad /* Flip invalid stamping ownership. */
276911bbb0fSAdrien Mazarguil stamp ^= RTE_BE32(1u << MLX4_SQ_OWNER_BIT);
27778e81a98SMatan Azrad sq->stamp = stamp;
27853387152SMatan Azrad if (start == end)
27978e81a98SMatan Azrad return size;
280c3c977bbSMoti Haimovsky }
28153387152SMatan Azrad do {
28253387152SMatan Azrad *start = stamp;
28353387152SMatan Azrad start += MLX4_SQ_STAMP_DWORDS;
28453387152SMatan Azrad } while (start != end);
28553387152SMatan Azrad return (uint32_t)size;
28653387152SMatan Azrad }
287c3c977bbSMoti Haimovsky
288c3c977bbSMoti Haimovsky /**
2897f45cb82SAdrien Mazarguil * Manage Tx completions.
2907f45cb82SAdrien Mazarguil *
2917f45cb82SAdrien Mazarguil * When sending a burst, mlx4_tx_burst() posts several WRs.
2927f45cb82SAdrien Mazarguil * To improve performance, a completion event is only required once every
2937f45cb82SAdrien Mazarguil * MLX4_PMD_TX_PER_COMP_REQ sends. Doing so discards completion information
2947f45cb82SAdrien Mazarguil * for other WRs, but this information would not be used anyway.
2957f45cb82SAdrien Mazarguil *
2967f45cb82SAdrien Mazarguil * @param txq
2977f45cb82SAdrien Mazarguil * Pointer to Tx queue structure.
29850163aecSMatan Azrad * @param elts_m
29950163aecSMatan Azrad * Tx elements number mask.
30050163aecSMatan Azrad * @param sq
30150163aecSMatan Azrad * Pointer to the SQ structure.
3027f45cb82SAdrien Mazarguil */
30378e81a98SMatan Azrad static void
mlx4_txq_complete(struct txq * txq,const unsigned int elts_m,struct mlx4_sq * sq)30450163aecSMatan Azrad mlx4_txq_complete(struct txq *txq, const unsigned int elts_m,
305dae76a67SMatan Azrad struct mlx4_sq *sq)
3067f45cb82SAdrien Mazarguil {
3077f45cb82SAdrien Mazarguil unsigned int elts_tail = txq->elts_tail;
308c3c977bbSMoti Haimovsky struct mlx4_cq *cq = &txq->mcq;
309b68d92b4SMatan Azrad volatile struct mlx4_cqe *cqe;
31053387152SMatan Azrad uint32_t completed;
311c3c977bbSMoti Haimovsky uint32_t cons_index = cq->cons_index;
31253387152SMatan Azrad volatile uint32_t *first_txbb;
31353387152SMatan Azrad
314c3c977bbSMoti Haimovsky /*
315c3c977bbSMoti Haimovsky * Traverse over all CQ entries reported and handle each WQ entry
316c3c977bbSMoti Haimovsky * reported by them.
317c3c977bbSMoti Haimovsky */
318c3c977bbSMoti Haimovsky do {
319b68d92b4SMatan Azrad cqe = (volatile struct mlx4_cqe *)mlx4_get_cqe(cq, cons_index);
320c3c977bbSMoti Haimovsky if (unlikely(!!(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK) ^
321c3c977bbSMoti Haimovsky !!(cons_index & cq->cqe_cnt)))
322c3c977bbSMoti Haimovsky break;
323e99fdaa7SAlexander Kozyrev #ifdef RTE_LIBRTE_MLX4_DEBUG
324c3c977bbSMoti Haimovsky /*
325c3c977bbSMoti Haimovsky * Make sure we read the CQE after we read the ownership bit.
326c3c977bbSMoti Haimovsky */
32789ce4b02SMatan Azrad rte_io_rmb();
328c3c977bbSMoti Haimovsky if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) ==
329c3c977bbSMoti Haimovsky MLX4_CQE_OPCODE_ERROR)) {
330b68d92b4SMatan Azrad volatile struct mlx4_err_cqe *cqe_err =
331b68d92b4SMatan Azrad (volatile struct mlx4_err_cqe *)cqe;
332c3c977bbSMoti Haimovsky ERROR("%p CQE error - vendor syndrome: 0x%x"
333c3c977bbSMoti Haimovsky " syndrome: 0x%x\n",
334c3c977bbSMoti Haimovsky (void *)txq, cqe_err->vendor_err,
335c3c977bbSMoti Haimovsky cqe_err->syndrome);
33678e81a98SMatan Azrad break;
3377f45cb82SAdrien Mazarguil }
338e99fdaa7SAlexander Kozyrev #endif /* RTE_LIBRTE_MLX4_DEBUG */
339c3c977bbSMoti Haimovsky cons_index++;
340c3c977bbSMoti Haimovsky } while (1);
34153387152SMatan Azrad completed = (cons_index - cq->cons_index) * txq->elts_comp_cd_init;
34253387152SMatan Azrad if (unlikely(!completed))
34378e81a98SMatan Azrad return;
34453387152SMatan Azrad /* First stamping address is the end of the last one. */
34550163aecSMatan Azrad first_txbb = (&(*txq->elts)[elts_tail & elts_m])->eocb;
34653387152SMatan Azrad elts_tail += completed;
34753387152SMatan Azrad /* The new tail element holds the end address. */
34853387152SMatan Azrad sq->remain_size += mlx4_txq_stamp_freed_wqe(sq, first_txbb,
34950163aecSMatan Azrad (&(*txq->elts)[elts_tail & elts_m])->eocb);
35078e81a98SMatan Azrad /* Update CQ consumer index. */
351c3c977bbSMoti Haimovsky cq->cons_index = cons_index;
35278e81a98SMatan Azrad *cq->set_ci_db = rte_cpu_to_be_32(cons_index & MLX4_CQ_DB_CI_MASK);
3537f45cb82SAdrien Mazarguil txq->elts_tail = elts_tail;
3547f45cb82SAdrien Mazarguil }
3557f45cb82SAdrien Mazarguil
3567f45cb82SAdrien Mazarguil /**
357673800faSMatan Azrad * Write Tx data segment to the SQ.
358673800faSMatan Azrad *
359673800faSMatan Azrad * @param dseg
360673800faSMatan Azrad * Pointer to data segment in SQ.
361673800faSMatan Azrad * @param lkey
362673800faSMatan Azrad * Memory region lkey.
363673800faSMatan Azrad * @param addr
364673800faSMatan Azrad * Data address.
365673800faSMatan Azrad * @param byte_count
366673800faSMatan Azrad * Big endian bytes count of the data to send.
367673800faSMatan Azrad */
368673800faSMatan Azrad static inline void
mlx4_fill_tx_data_seg(volatile struct mlx4_wqe_data_seg * dseg,uint32_t lkey,uintptr_t addr,rte_be32_t byte_count)369673800faSMatan Azrad mlx4_fill_tx_data_seg(volatile struct mlx4_wqe_data_seg *dseg,
370673800faSMatan Azrad uint32_t lkey, uintptr_t addr, rte_be32_t byte_count)
371673800faSMatan Azrad {
372673800faSMatan Azrad dseg->addr = rte_cpu_to_be_64(addr);
3739797bfccSYongseok Koh dseg->lkey = lkey;
374673800faSMatan Azrad #if RTE_CACHE_LINE_SIZE < 64
375673800faSMatan Azrad /*
376673800faSMatan Azrad * Need a barrier here before writing the byte_count
377673800faSMatan Azrad * fields to make sure that all the data is visible
378673800faSMatan Azrad * before the byte_count field is set.
379673800faSMatan Azrad * Otherwise, if the segment begins a new cacheline,
380673800faSMatan Azrad * the HCA prefetcher could grab the 64-byte chunk and
381673800faSMatan Azrad * get a valid (!= 0xffffffff) byte count but stale
382673800faSMatan Azrad * data, and end up sending the wrong data.
383673800faSMatan Azrad */
384673800faSMatan Azrad rte_io_wmb();
385673800faSMatan Azrad #endif /* RTE_CACHE_LINE_SIZE */
386673800faSMatan Azrad dseg->byte_count = byte_count;
387673800faSMatan Azrad }
388673800faSMatan Azrad
38978e81a98SMatan Azrad /**
390ba576975SMoti Haimovsky * Obtain and calculate TSO information needed for assembling a TSO WQE.
391ba576975SMoti Haimovsky *
392ba576975SMoti Haimovsky * @param buf
393ba576975SMoti Haimovsky * Pointer to the first packet mbuf.
394ba576975SMoti Haimovsky * @param txq
395ba576975SMoti Haimovsky * Pointer to Tx queue structure.
396ba576975SMoti Haimovsky * @param tinfo
397ba576975SMoti Haimovsky * Pointer to a structure to fill the info with.
398ba576975SMoti Haimovsky *
399ba576975SMoti Haimovsky * @return
400ba576975SMoti Haimovsky * 0 on success, negative value upon error.
401ba576975SMoti Haimovsky */
402ba576975SMoti Haimovsky static inline int
mlx4_tx_burst_tso_get_params(struct rte_mbuf * buf,struct txq * txq,struct tso_info * tinfo)403ba576975SMoti Haimovsky mlx4_tx_burst_tso_get_params(struct rte_mbuf *buf,
404ba576975SMoti Haimovsky struct txq *txq,
405ba576975SMoti Haimovsky struct tso_info *tinfo)
406ba576975SMoti Haimovsky {
407ba576975SMoti Haimovsky struct mlx4_sq *sq = &txq->msq;
408ba576975SMoti Haimovsky const uint8_t tunneled = txq->priv->hw_csum_l2tun &&
409daa02b5cSOlivier Matz (buf->ol_flags & RTE_MBUF_F_TX_TUNNEL_MASK);
410ba576975SMoti Haimovsky
411ba576975SMoti Haimovsky tinfo->tso_header_size = buf->l2_len + buf->l3_len + buf->l4_len;
412ba576975SMoti Haimovsky if (tunneled)
413ba576975SMoti Haimovsky tinfo->tso_header_size +=
414ba576975SMoti Haimovsky buf->outer_l2_len + buf->outer_l3_len;
415ba576975SMoti Haimovsky if (unlikely(buf->tso_segsz == 0 ||
416ba576975SMoti Haimovsky tinfo->tso_header_size == 0 ||
417ba576975SMoti Haimovsky tinfo->tso_header_size > MLX4_MAX_TSO_HEADER ||
418ba576975SMoti Haimovsky tinfo->tso_header_size > buf->data_len))
419ba576975SMoti Haimovsky return -EINVAL;
420ba576975SMoti Haimovsky /*
421ba576975SMoti Haimovsky * Calculate the WQE TSO segment size
422ba576975SMoti Haimovsky * Note:
423ba576975SMoti Haimovsky * 1. An LSO segment must be padded such that the subsequent data
424ba576975SMoti Haimovsky * segment is 16-byte aligned.
425ba576975SMoti Haimovsky * 2. The start address of the TSO segment is always 16 Bytes aligned.
426ba576975SMoti Haimovsky */
427ba576975SMoti Haimovsky tinfo->wqe_tso_seg_size = RTE_ALIGN(sizeof(struct mlx4_wqe_lso_seg) +
428ba576975SMoti Haimovsky tinfo->tso_header_size,
429ba576975SMoti Haimovsky sizeof(struct mlx4_wqe_data_seg));
430ba576975SMoti Haimovsky tinfo->fence_size = ((sizeof(struct mlx4_wqe_ctrl_seg) +
431ba576975SMoti Haimovsky tinfo->wqe_tso_seg_size) >> MLX4_SEG_SHIFT) +
432ba576975SMoti Haimovsky buf->nb_segs;
433ba576975SMoti Haimovsky tinfo->wqe_size =
434ba576975SMoti Haimovsky RTE_ALIGN((uint32_t)(tinfo->fence_size << MLX4_SEG_SHIFT),
435ba576975SMoti Haimovsky MLX4_TXBB_SIZE);
436ba576975SMoti Haimovsky /* Validate WQE size and WQE space in the send queue. */
437ba576975SMoti Haimovsky if (sq->remain_size < tinfo->wqe_size ||
438ba576975SMoti Haimovsky tinfo->wqe_size > MLX4_MAX_WQE_SIZE)
439ba576975SMoti Haimovsky return -ENOMEM;
440ba576975SMoti Haimovsky /* Init pv. */
441ba576975SMoti Haimovsky tinfo->pv = (struct pv *)txq->bounce_buf;
442ba576975SMoti Haimovsky tinfo->pv_counter = 0;
443ba576975SMoti Haimovsky return 0;
444ba576975SMoti Haimovsky }
445ba576975SMoti Haimovsky
446ba576975SMoti Haimovsky /**
447ba576975SMoti Haimovsky * Fill the TSO WQE data segments with info on buffers to transmit .
448ba576975SMoti Haimovsky *
449ba576975SMoti Haimovsky * @param buf
450ba576975SMoti Haimovsky * Pointer to the first packet mbuf.
451ba576975SMoti Haimovsky * @param txq
452ba576975SMoti Haimovsky * Pointer to Tx queue structure.
453ba576975SMoti Haimovsky * @param tinfo
454ba576975SMoti Haimovsky * Pointer to TSO info to use.
455ba576975SMoti Haimovsky * @param dseg
456ba576975SMoti Haimovsky * Pointer to the first data segment in the TSO WQE.
457ba576975SMoti Haimovsky * @param ctrl
458ba576975SMoti Haimovsky * Pointer to the control segment in the TSO WQE.
459ba576975SMoti Haimovsky *
460ba576975SMoti Haimovsky * @return
461ba576975SMoti Haimovsky * 0 on success, negative value upon error.
462ba576975SMoti Haimovsky */
463ba576975SMoti Haimovsky static inline volatile struct mlx4_wqe_ctrl_seg *
mlx4_tx_burst_fill_tso_dsegs(struct rte_mbuf * buf,struct txq * txq,struct tso_info * tinfo,volatile struct mlx4_wqe_data_seg * dseg,volatile struct mlx4_wqe_ctrl_seg * ctrl)464ba576975SMoti Haimovsky mlx4_tx_burst_fill_tso_dsegs(struct rte_mbuf *buf,
465ba576975SMoti Haimovsky struct txq *txq,
466ba576975SMoti Haimovsky struct tso_info *tinfo,
467ba576975SMoti Haimovsky volatile struct mlx4_wqe_data_seg *dseg,
468ba576975SMoti Haimovsky volatile struct mlx4_wqe_ctrl_seg *ctrl)
469ba576975SMoti Haimovsky {
470ba576975SMoti Haimovsky uint32_t lkey;
471ba576975SMoti Haimovsky int nb_segs = buf->nb_segs;
472ba576975SMoti Haimovsky int nb_segs_txbb;
473ba576975SMoti Haimovsky struct mlx4_sq *sq = &txq->msq;
474ba576975SMoti Haimovsky struct rte_mbuf *sbuf = buf;
475ba576975SMoti Haimovsky struct pv *pv = tinfo->pv;
476ba576975SMoti Haimovsky int *pv_counter = &tinfo->pv_counter;
477ba576975SMoti Haimovsky volatile struct mlx4_wqe_ctrl_seg *ctrl_next =
478ba576975SMoti Haimovsky (volatile struct mlx4_wqe_ctrl_seg *)
479ba576975SMoti Haimovsky ((volatile uint8_t *)ctrl + tinfo->wqe_size);
480ba576975SMoti Haimovsky uint16_t data_len = sbuf->data_len - tinfo->tso_header_size;
481ba576975SMoti Haimovsky uintptr_t data_addr = rte_pktmbuf_mtod_offset(sbuf, uintptr_t,
482ba576975SMoti Haimovsky tinfo->tso_header_size);
483ba576975SMoti Haimovsky
484ba576975SMoti Haimovsky do {
485ba576975SMoti Haimovsky /* how many dseg entries do we have in the current TXBB ? */
486ba576975SMoti Haimovsky nb_segs_txbb = (MLX4_TXBB_SIZE -
487ba576975SMoti Haimovsky ((uintptr_t)dseg & (MLX4_TXBB_SIZE - 1))) >>
488ba576975SMoti Haimovsky MLX4_SEG_SHIFT;
489ba576975SMoti Haimovsky switch (nb_segs_txbb) {
490e99fdaa7SAlexander Kozyrev #ifdef RTE_LIBRTE_MLX4_DEBUG
491ba576975SMoti Haimovsky default:
492ba576975SMoti Haimovsky /* Should never happen. */
493ba576975SMoti Haimovsky rte_panic("%p: Invalid number of SGEs(%d) for a TXBB",
494ba576975SMoti Haimovsky (void *)txq, nb_segs_txbb);
495ba576975SMoti Haimovsky /* rte_panic never returns. */
496ba576975SMoti Haimovsky break;
497e99fdaa7SAlexander Kozyrev #endif /* RTE_LIBRTE_MLX4_DEBUG */
498ba576975SMoti Haimovsky case 4:
499ba576975SMoti Haimovsky /* Memory region key for this memory pool. */
500ba576975SMoti Haimovsky lkey = mlx4_tx_mb2mr(txq, sbuf);
501ba576975SMoti Haimovsky if (unlikely(lkey == (uint32_t)-1))
502ba576975SMoti Haimovsky goto err;
503ba576975SMoti Haimovsky dseg->addr = rte_cpu_to_be_64(data_addr);
504ba576975SMoti Haimovsky dseg->lkey = lkey;
505ba576975SMoti Haimovsky /*
506ba576975SMoti Haimovsky * This data segment starts at the beginning of a new
507ba576975SMoti Haimovsky * TXBB, so we need to postpone its byte_count writing
508ba576975SMoti Haimovsky * for later.
509ba576975SMoti Haimovsky */
510ba576975SMoti Haimovsky pv[*pv_counter].dseg = dseg;
511ba576975SMoti Haimovsky /*
512ba576975SMoti Haimovsky * Zero length segment is treated as inline segment
513ba576975SMoti Haimovsky * with zero data.
514ba576975SMoti Haimovsky */
515ba576975SMoti Haimovsky pv[(*pv_counter)++].val =
516ba576975SMoti Haimovsky rte_cpu_to_be_32(data_len ?
517ba576975SMoti Haimovsky data_len :
518ba576975SMoti Haimovsky 0x80000000);
519ba576975SMoti Haimovsky if (--nb_segs == 0)
520ba576975SMoti Haimovsky return ctrl_next;
521ba576975SMoti Haimovsky /* Prepare next buf info */
522ba576975SMoti Haimovsky sbuf = sbuf->next;
523ba576975SMoti Haimovsky dseg++;
524ba576975SMoti Haimovsky data_len = sbuf->data_len;
525ba576975SMoti Haimovsky data_addr = rte_pktmbuf_mtod(sbuf, uintptr_t);
526ba576975SMoti Haimovsky /* fallthrough */
527ba576975SMoti Haimovsky case 3:
528ba576975SMoti Haimovsky lkey = mlx4_tx_mb2mr(txq, sbuf);
529ba576975SMoti Haimovsky if (unlikely(lkey == (uint32_t)-1))
530ba576975SMoti Haimovsky goto err;
531ba576975SMoti Haimovsky mlx4_fill_tx_data_seg(dseg, lkey, data_addr,
532ba576975SMoti Haimovsky rte_cpu_to_be_32(data_len ?
533ba576975SMoti Haimovsky data_len :
534ba576975SMoti Haimovsky 0x80000000));
535ba576975SMoti Haimovsky if (--nb_segs == 0)
536ba576975SMoti Haimovsky return ctrl_next;
537ba576975SMoti Haimovsky /* Prepare next buf info */
538ba576975SMoti Haimovsky sbuf = sbuf->next;
539ba576975SMoti Haimovsky dseg++;
540ba576975SMoti Haimovsky data_len = sbuf->data_len;
541ba576975SMoti Haimovsky data_addr = rte_pktmbuf_mtod(sbuf, uintptr_t);
542ba576975SMoti Haimovsky /* fallthrough */
543ba576975SMoti Haimovsky case 2:
544ba576975SMoti Haimovsky lkey = mlx4_tx_mb2mr(txq, sbuf);
545ba576975SMoti Haimovsky if (unlikely(lkey == (uint32_t)-1))
546ba576975SMoti Haimovsky goto err;
547ba576975SMoti Haimovsky mlx4_fill_tx_data_seg(dseg, lkey, data_addr,
548ba576975SMoti Haimovsky rte_cpu_to_be_32(data_len ?
549ba576975SMoti Haimovsky data_len :
550ba576975SMoti Haimovsky 0x80000000));
551ba576975SMoti Haimovsky if (--nb_segs == 0)
552ba576975SMoti Haimovsky return ctrl_next;
553ba576975SMoti Haimovsky /* Prepare next buf info */
554ba576975SMoti Haimovsky sbuf = sbuf->next;
555ba576975SMoti Haimovsky dseg++;
556ba576975SMoti Haimovsky data_len = sbuf->data_len;
557ba576975SMoti Haimovsky data_addr = rte_pktmbuf_mtod(sbuf, uintptr_t);
558ba576975SMoti Haimovsky /* fallthrough */
559ba576975SMoti Haimovsky case 1:
560ba576975SMoti Haimovsky lkey = mlx4_tx_mb2mr(txq, sbuf);
561ba576975SMoti Haimovsky if (unlikely(lkey == (uint32_t)-1))
562ba576975SMoti Haimovsky goto err;
563ba576975SMoti Haimovsky mlx4_fill_tx_data_seg(dseg, lkey, data_addr,
564ba576975SMoti Haimovsky rte_cpu_to_be_32(data_len ?
565ba576975SMoti Haimovsky data_len :
566ba576975SMoti Haimovsky 0x80000000));
567ba576975SMoti Haimovsky if (--nb_segs == 0)
568ba576975SMoti Haimovsky return ctrl_next;
569ba576975SMoti Haimovsky /* Prepare next buf info */
570ba576975SMoti Haimovsky sbuf = sbuf->next;
571ba576975SMoti Haimovsky dseg++;
572ba576975SMoti Haimovsky data_len = sbuf->data_len;
573ba576975SMoti Haimovsky data_addr = rte_pktmbuf_mtod(sbuf, uintptr_t);
574ba576975SMoti Haimovsky /* fallthrough */
575ba576975SMoti Haimovsky }
576ba576975SMoti Haimovsky /* Wrap dseg if it points at the end of the queue. */
577ba576975SMoti Haimovsky if ((volatile uint8_t *)dseg >= sq->eob)
578ba576975SMoti Haimovsky dseg = (volatile struct mlx4_wqe_data_seg *)
579ba576975SMoti Haimovsky ((volatile uint8_t *)dseg - sq->size);
580ba576975SMoti Haimovsky } while (true);
581ba576975SMoti Haimovsky err:
582ba576975SMoti Haimovsky return NULL;
583ba576975SMoti Haimovsky }
584ba576975SMoti Haimovsky
585ba576975SMoti Haimovsky /**
586ba576975SMoti Haimovsky * Fill the packet's l2, l3 and l4 headers to the WQE.
587ba576975SMoti Haimovsky *
588ba576975SMoti Haimovsky * This will be used as the header for each TSO segment that is transmitted.
589ba576975SMoti Haimovsky *
590ba576975SMoti Haimovsky * @param buf
591ba576975SMoti Haimovsky * Pointer to the first packet mbuf.
592ba576975SMoti Haimovsky * @param txq
593ba576975SMoti Haimovsky * Pointer to Tx queue structure.
594ba576975SMoti Haimovsky * @param tinfo
595ba576975SMoti Haimovsky * Pointer to TSO info to use.
596ba576975SMoti Haimovsky * @param ctrl
597ba576975SMoti Haimovsky * Pointer to the control segment in the TSO WQE.
598ba576975SMoti Haimovsky *
599ba576975SMoti Haimovsky * @return
600ba576975SMoti Haimovsky * 0 on success, negative value upon error.
601ba576975SMoti Haimovsky */
602ba576975SMoti Haimovsky static inline volatile struct mlx4_wqe_data_seg *
mlx4_tx_burst_fill_tso_hdr(struct rte_mbuf * buf,struct txq * txq,struct tso_info * tinfo,volatile struct mlx4_wqe_ctrl_seg * ctrl)603ba576975SMoti Haimovsky mlx4_tx_burst_fill_tso_hdr(struct rte_mbuf *buf,
604ba576975SMoti Haimovsky struct txq *txq,
605ba576975SMoti Haimovsky struct tso_info *tinfo,
606ba576975SMoti Haimovsky volatile struct mlx4_wqe_ctrl_seg *ctrl)
607ba576975SMoti Haimovsky {
608ba576975SMoti Haimovsky volatile struct mlx4_wqe_lso_seg *tseg =
609ba576975SMoti Haimovsky (volatile struct mlx4_wqe_lso_seg *)(ctrl + 1);
610ba576975SMoti Haimovsky struct mlx4_sq *sq = &txq->msq;
611ba576975SMoti Haimovsky struct pv *pv = tinfo->pv;
612ba576975SMoti Haimovsky int *pv_counter = &tinfo->pv_counter;
613ba576975SMoti Haimovsky int remain_size = tinfo->tso_header_size;
614ba576975SMoti Haimovsky char *from = rte_pktmbuf_mtod(buf, char *);
615ba576975SMoti Haimovsky uint16_t txbb_avail_space;
616ba576975SMoti Haimovsky /* Union to overcome volatile constraints when copying TSO header. */
617ba576975SMoti Haimovsky union {
618ba576975SMoti Haimovsky volatile uint8_t *vto;
619ba576975SMoti Haimovsky uint8_t *to;
620ba576975SMoti Haimovsky } thdr = { .vto = (volatile uint8_t *)tseg->header, };
621ba576975SMoti Haimovsky
622ba576975SMoti Haimovsky /*
623ba576975SMoti Haimovsky * TSO data always starts at offset 20 from the beginning of the TXBB
624ba576975SMoti Haimovsky * (16 byte ctrl + 4byte TSO desc). Since each TXBB is 64Byte aligned
625ba576975SMoti Haimovsky * we can write the first 44 TSO header bytes without worry for TxQ
626ba576975SMoti Haimovsky * wrapping or overwriting the first TXBB 32bit word.
627ba576975SMoti Haimovsky */
628ba576975SMoti Haimovsky txbb_avail_space = MLX4_TXBB_SIZE -
629ba576975SMoti Haimovsky (sizeof(struct mlx4_wqe_ctrl_seg) +
630ba576975SMoti Haimovsky sizeof(struct mlx4_wqe_lso_seg));
631ba576975SMoti Haimovsky while (remain_size >= (int)(txbb_avail_space + sizeof(uint32_t))) {
632ba576975SMoti Haimovsky /* Copy to end of txbb. */
633ba576975SMoti Haimovsky rte_memcpy(thdr.to, from, txbb_avail_space);
634ba576975SMoti Haimovsky from += txbb_avail_space;
635ba576975SMoti Haimovsky thdr.to += txbb_avail_space;
636ba576975SMoti Haimovsky /* New TXBB, Check for TxQ wrap. */
637ba576975SMoti Haimovsky if (thdr.to >= sq->eob)
638ba576975SMoti Haimovsky thdr.vto = sq->buf;
639ba576975SMoti Haimovsky /* New TXBB, stash the first 32bits for later use. */
640ba576975SMoti Haimovsky pv[*pv_counter].dst = (volatile uint32_t *)thdr.to;
641ba576975SMoti Haimovsky pv[(*pv_counter)++].val = *(uint32_t *)from,
642ba576975SMoti Haimovsky from += sizeof(uint32_t);
643ba576975SMoti Haimovsky thdr.to += sizeof(uint32_t);
644ba576975SMoti Haimovsky remain_size -= txbb_avail_space + sizeof(uint32_t);
645ba576975SMoti Haimovsky /* Avail space in new TXBB is TXBB size - 4 */
646ba576975SMoti Haimovsky txbb_avail_space = MLX4_TXBB_SIZE - sizeof(uint32_t);
647ba576975SMoti Haimovsky }
648ba576975SMoti Haimovsky if (remain_size > txbb_avail_space) {
649ba576975SMoti Haimovsky rte_memcpy(thdr.to, from, txbb_avail_space);
650ba576975SMoti Haimovsky from += txbb_avail_space;
651ba576975SMoti Haimovsky thdr.to += txbb_avail_space;
652ba576975SMoti Haimovsky remain_size -= txbb_avail_space;
653ba576975SMoti Haimovsky /* New TXBB, Check for TxQ wrap. */
654ba576975SMoti Haimovsky if (thdr.to >= sq->eob)
655ba576975SMoti Haimovsky thdr.vto = sq->buf;
656ba576975SMoti Haimovsky pv[*pv_counter].dst = (volatile uint32_t *)thdr.to;
657ba576975SMoti Haimovsky rte_memcpy(&pv[*pv_counter].val, from, remain_size);
658ba576975SMoti Haimovsky (*pv_counter)++;
659ba576975SMoti Haimovsky } else if (remain_size) {
660ba576975SMoti Haimovsky rte_memcpy(thdr.to, from, remain_size);
661ba576975SMoti Haimovsky }
662ba576975SMoti Haimovsky tseg->mss_hdr_size = rte_cpu_to_be_32((buf->tso_segsz << 16) |
663ba576975SMoti Haimovsky tinfo->tso_header_size);
664ba576975SMoti Haimovsky /* Calculate data segment location */
665ba576975SMoti Haimovsky return (volatile struct mlx4_wqe_data_seg *)
666ba576975SMoti Haimovsky ((uintptr_t)tseg + tinfo->wqe_tso_seg_size);
667ba576975SMoti Haimovsky }
668ba576975SMoti Haimovsky
669ba576975SMoti Haimovsky /**
670ba576975SMoti Haimovsky * Write data segments and header for TSO uni/multi segment packet.
671ba576975SMoti Haimovsky *
672ba576975SMoti Haimovsky * @param buf
673ba576975SMoti Haimovsky * Pointer to the first packet mbuf.
674ba576975SMoti Haimovsky * @param txq
675ba576975SMoti Haimovsky * Pointer to Tx queue structure.
676ba576975SMoti Haimovsky * @param ctrl
677ba576975SMoti Haimovsky * Pointer to the WQE control segment.
678ba576975SMoti Haimovsky *
679ba576975SMoti Haimovsky * @return
680ba576975SMoti Haimovsky * Pointer to the next WQE control segment on success, NULL otherwise.
681ba576975SMoti Haimovsky */
682ba576975SMoti Haimovsky static volatile struct mlx4_wqe_ctrl_seg *
mlx4_tx_burst_tso(struct rte_mbuf * buf,struct txq * txq,volatile struct mlx4_wqe_ctrl_seg * ctrl)683ba576975SMoti Haimovsky mlx4_tx_burst_tso(struct rte_mbuf *buf, struct txq *txq,
684ba576975SMoti Haimovsky volatile struct mlx4_wqe_ctrl_seg *ctrl)
685ba576975SMoti Haimovsky {
686ba576975SMoti Haimovsky volatile struct mlx4_wqe_data_seg *dseg;
687ba576975SMoti Haimovsky volatile struct mlx4_wqe_ctrl_seg *ctrl_next;
688ba576975SMoti Haimovsky struct mlx4_sq *sq = &txq->msq;
689ba576975SMoti Haimovsky struct tso_info tinfo;
690ba576975SMoti Haimovsky struct pv *pv;
691ba576975SMoti Haimovsky int pv_counter;
692ba576975SMoti Haimovsky int ret;
693ba576975SMoti Haimovsky
694ba576975SMoti Haimovsky ret = mlx4_tx_burst_tso_get_params(buf, txq, &tinfo);
695ba576975SMoti Haimovsky if (unlikely(ret))
696ba576975SMoti Haimovsky goto error;
697ba576975SMoti Haimovsky dseg = mlx4_tx_burst_fill_tso_hdr(buf, txq, &tinfo, ctrl);
698ba576975SMoti Haimovsky if (unlikely(dseg == NULL))
699ba576975SMoti Haimovsky goto error;
700ba576975SMoti Haimovsky if ((uintptr_t)dseg >= (uintptr_t)sq->eob)
701ba576975SMoti Haimovsky dseg = (volatile struct mlx4_wqe_data_seg *)
702ba576975SMoti Haimovsky ((uintptr_t)dseg - sq->size);
703ba576975SMoti Haimovsky ctrl_next = mlx4_tx_burst_fill_tso_dsegs(buf, txq, &tinfo, dseg, ctrl);
704ba576975SMoti Haimovsky if (unlikely(ctrl_next == NULL))
705ba576975SMoti Haimovsky goto error;
706ba576975SMoti Haimovsky /* Write the first DWORD of each TXBB save earlier. */
707ba576975SMoti Haimovsky if (likely(tinfo.pv_counter)) {
708ba576975SMoti Haimovsky pv = tinfo.pv;
709ba576975SMoti Haimovsky pv_counter = tinfo.pv_counter;
710ba576975SMoti Haimovsky /* Need a barrier here before writing the first TXBB word. */
711ba576975SMoti Haimovsky rte_io_wmb();
712ba576975SMoti Haimovsky do {
713ba576975SMoti Haimovsky --pv_counter;
714ba576975SMoti Haimovsky *pv[pv_counter].dst = pv[pv_counter].val;
715ba576975SMoti Haimovsky } while (pv_counter > 0);
716ba576975SMoti Haimovsky }
717ba576975SMoti Haimovsky ctrl->fence_size = tinfo.fence_size;
718ba576975SMoti Haimovsky sq->remain_size -= tinfo.wqe_size;
719ba576975SMoti Haimovsky return ctrl_next;
720ba576975SMoti Haimovsky error:
721ba576975SMoti Haimovsky txq->stats.odropped++;
722ba576975SMoti Haimovsky return NULL;
723ba576975SMoti Haimovsky }
724ba576975SMoti Haimovsky
725ba576975SMoti Haimovsky /**
72678e81a98SMatan Azrad * Write data segments of multi-segment packet.
72778e81a98SMatan Azrad *
72878e81a98SMatan Azrad * @param buf
72978e81a98SMatan Azrad * Pointer to the first packet mbuf.
73078e81a98SMatan Azrad * @param txq
73178e81a98SMatan Azrad * Pointer to Tx queue structure.
73278e81a98SMatan Azrad * @param ctrl
73378e81a98SMatan Azrad * Pointer to the WQE control segment.
73478e81a98SMatan Azrad *
73578e81a98SMatan Azrad * @return
73678e81a98SMatan Azrad * Pointer to the next WQE control segment on success, NULL otherwise.
73778e81a98SMatan Azrad */
73878e81a98SMatan Azrad static volatile struct mlx4_wqe_ctrl_seg *
mlx4_tx_burst_segs(struct rte_mbuf * buf,struct txq * txq,volatile struct mlx4_wqe_ctrl_seg * ctrl)739dae76a67SMatan Azrad mlx4_tx_burst_segs(struct rte_mbuf *buf, struct txq *txq,
74078e81a98SMatan Azrad volatile struct mlx4_wqe_ctrl_seg *ctrl)
741dae76a67SMatan Azrad {
742dae76a67SMatan Azrad struct pv *pv = (struct pv *)txq->bounce_buf;
743dae76a67SMatan Azrad struct mlx4_sq *sq = &txq->msq;
744673800faSMatan Azrad struct rte_mbuf *sbuf = buf;
745dae76a67SMatan Azrad uint32_t lkey;
746dae76a67SMatan Azrad int pv_counter = 0;
747673800faSMatan Azrad int nb_segs = buf->nb_segs;
74878e81a98SMatan Azrad uint32_t wqe_size;
74978e81a98SMatan Azrad volatile struct mlx4_wqe_data_seg *dseg =
75078e81a98SMatan Azrad (volatile struct mlx4_wqe_data_seg *)(ctrl + 1);
751dae76a67SMatan Azrad
75278e81a98SMatan Azrad ctrl->fence_size = 1 + nb_segs;
75378e81a98SMatan Azrad wqe_size = RTE_ALIGN((uint32_t)(ctrl->fence_size << MLX4_SEG_SHIFT),
75478e81a98SMatan Azrad MLX4_TXBB_SIZE);
75578e81a98SMatan Azrad /* Validate WQE size and WQE space in the send queue. */
75678e81a98SMatan Azrad if (sq->remain_size < wqe_size ||
75778e81a98SMatan Azrad wqe_size > MLX4_MAX_WQE_SIZE)
75878e81a98SMatan Azrad return NULL;
759673800faSMatan Azrad /*
760673800faSMatan Azrad * Fill the data segments with buffer information.
761673800faSMatan Azrad * First WQE TXBB head segment is always control segment,
762673800faSMatan Azrad * so jump to tail TXBB data segments code for the first
763673800faSMatan Azrad * WQE data segments filling.
764673800faSMatan Azrad */
765673800faSMatan Azrad goto txbb_tail_segs;
766673800faSMatan Azrad txbb_head_seg:
767dae76a67SMatan Azrad /* Memory region key (big endian) for this memory pool. */
7689797bfccSYongseok Koh lkey = mlx4_tx_mb2mr(txq, sbuf);
769673800faSMatan Azrad if (unlikely(lkey == (uint32_t)-1)) {
770dae76a67SMatan Azrad DEBUG("%p: unable to get MP <-> MR association",
771dae76a67SMatan Azrad (void *)txq);
77278e81a98SMatan Azrad return NULL;
773dae76a67SMatan Azrad }
7746e1a01b2SMatan Azrad /* Handle WQE wraparound. */
7756e1a01b2SMatan Azrad if (dseg >=
7766e1a01b2SMatan Azrad (volatile struct mlx4_wqe_data_seg *)sq->eob)
7776e1a01b2SMatan Azrad dseg = (volatile struct mlx4_wqe_data_seg *)
7786e1a01b2SMatan Azrad sq->buf;
779673800faSMatan Azrad dseg->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(sbuf, uintptr_t));
7809797bfccSYongseok Koh dseg->lkey = lkey;
781673800faSMatan Azrad /*
782673800faSMatan Azrad * This data segment starts at the beginning of a new
783673800faSMatan Azrad * TXBB, so we need to postpone its byte_count writing
784673800faSMatan Azrad * for later.
785673800faSMatan Azrad */
786dae76a67SMatan Azrad pv[pv_counter].dseg = dseg;
787673800faSMatan Azrad /*
788673800faSMatan Azrad * Zero length segment is treated as inline segment
789673800faSMatan Azrad * with zero data.
790673800faSMatan Azrad */
791673800faSMatan Azrad pv[pv_counter++].val = rte_cpu_to_be_32(sbuf->data_len ?
792673800faSMatan Azrad sbuf->data_len : 0x80000000);
793673800faSMatan Azrad sbuf = sbuf->next;
794673800faSMatan Azrad dseg++;
795673800faSMatan Azrad nb_segs--;
796673800faSMatan Azrad txbb_tail_segs:
797673800faSMatan Azrad /* Jump to default if there are more than two segments remaining. */
798673800faSMatan Azrad switch (nb_segs) {
799673800faSMatan Azrad default:
8009797bfccSYongseok Koh lkey = mlx4_tx_mb2mr(txq, sbuf);
801673800faSMatan Azrad if (unlikely(lkey == (uint32_t)-1)) {
802673800faSMatan Azrad DEBUG("%p: unable to get MP <-> MR association",
803673800faSMatan Azrad (void *)txq);
80478e81a98SMatan Azrad return NULL;
805dae76a67SMatan Azrad }
806673800faSMatan Azrad mlx4_fill_tx_data_seg(dseg, lkey,
807673800faSMatan Azrad rte_pktmbuf_mtod(sbuf, uintptr_t),
808673800faSMatan Azrad rte_cpu_to_be_32(sbuf->data_len ?
809673800faSMatan Azrad sbuf->data_len :
810673800faSMatan Azrad 0x80000000));
811673800faSMatan Azrad sbuf = sbuf->next;
812673800faSMatan Azrad dseg++;
813673800faSMatan Azrad nb_segs--;
814673800faSMatan Azrad /* fallthrough */
815673800faSMatan Azrad case 2:
8169797bfccSYongseok Koh lkey = mlx4_tx_mb2mr(txq, sbuf);
817673800faSMatan Azrad if (unlikely(lkey == (uint32_t)-1)) {
818673800faSMatan Azrad DEBUG("%p: unable to get MP <-> MR association",
819673800faSMatan Azrad (void *)txq);
82078e81a98SMatan Azrad return NULL;
821673800faSMatan Azrad }
822673800faSMatan Azrad mlx4_fill_tx_data_seg(dseg, lkey,
823673800faSMatan Azrad rte_pktmbuf_mtod(sbuf, uintptr_t),
824673800faSMatan Azrad rte_cpu_to_be_32(sbuf->data_len ?
825673800faSMatan Azrad sbuf->data_len :
826673800faSMatan Azrad 0x80000000));
827673800faSMatan Azrad sbuf = sbuf->next;
828673800faSMatan Azrad dseg++;
829673800faSMatan Azrad nb_segs--;
830673800faSMatan Azrad /* fallthrough */
831673800faSMatan Azrad case 1:
8329797bfccSYongseok Koh lkey = mlx4_tx_mb2mr(txq, sbuf);
833673800faSMatan Azrad if (unlikely(lkey == (uint32_t)-1)) {
834673800faSMatan Azrad DEBUG("%p: unable to get MP <-> MR association",
835673800faSMatan Azrad (void *)txq);
83678e81a98SMatan Azrad return NULL;
837673800faSMatan Azrad }
838673800faSMatan Azrad mlx4_fill_tx_data_seg(dseg, lkey,
839673800faSMatan Azrad rte_pktmbuf_mtod(sbuf, uintptr_t),
840673800faSMatan Azrad rte_cpu_to_be_32(sbuf->data_len ?
841673800faSMatan Azrad sbuf->data_len :
842673800faSMatan Azrad 0x80000000));
843673800faSMatan Azrad nb_segs--;
844673800faSMatan Azrad if (nb_segs) {
845673800faSMatan Azrad sbuf = sbuf->next;
846673800faSMatan Azrad dseg++;
847673800faSMatan Azrad goto txbb_head_seg;
848673800faSMatan Azrad }
849673800faSMatan Azrad /* fallthrough */
850673800faSMatan Azrad case 0:
851673800faSMatan Azrad break;
852dae76a67SMatan Azrad }
853dae76a67SMatan Azrad /* Write the first DWORD of each TXBB save earlier. */
854dae76a67SMatan Azrad if (pv_counter) {
855dae76a67SMatan Azrad /* Need a barrier here before writing the byte_count. */
856dae76a67SMatan Azrad rte_io_wmb();
857dae76a67SMatan Azrad for (--pv_counter; pv_counter >= 0; pv_counter--)
858dae76a67SMatan Azrad pv[pv_counter].dseg->byte_count = pv[pv_counter].val;
859dae76a67SMatan Azrad }
86078e81a98SMatan Azrad sq->remain_size -= wqe_size;
86178e81a98SMatan Azrad /* Align next WQE address to the next TXBB. */
86278e81a98SMatan Azrad return (volatile struct mlx4_wqe_ctrl_seg *)
86378e81a98SMatan Azrad ((volatile uint8_t *)ctrl + wqe_size);
864dae76a67SMatan Azrad }
865dae76a67SMatan Azrad
8667f45cb82SAdrien Mazarguil /**
8677f45cb82SAdrien Mazarguil * DPDK callback for Tx.
8687f45cb82SAdrien Mazarguil *
8697f45cb82SAdrien Mazarguil * @param dpdk_txq
8707f45cb82SAdrien Mazarguil * Generic pointer to Tx queue structure.
8717f45cb82SAdrien Mazarguil * @param[in] pkts
8727f45cb82SAdrien Mazarguil * Packets to transmit.
8737f45cb82SAdrien Mazarguil * @param pkts_n
8747f45cb82SAdrien Mazarguil * Number of packets in array.
8757f45cb82SAdrien Mazarguil *
8767f45cb82SAdrien Mazarguil * @return
8777f45cb82SAdrien Mazarguil * Number of packets successfully transmitted (<= pkts_n).
8787f45cb82SAdrien Mazarguil */
8797f45cb82SAdrien Mazarguil uint16_t
mlx4_tx_burst(void * dpdk_txq,struct rte_mbuf ** pkts,uint16_t pkts_n)8807f45cb82SAdrien Mazarguil mlx4_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n)
8817f45cb82SAdrien Mazarguil {
8827f45cb82SAdrien Mazarguil struct txq *txq = (struct txq *)dpdk_txq;
8837f45cb82SAdrien Mazarguil unsigned int elts_head = txq->elts_head;
8847f45cb82SAdrien Mazarguil const unsigned int elts_n = txq->elts_n;
88550163aecSMatan Azrad const unsigned int elts_m = elts_n - 1;
886c3c977bbSMoti Haimovsky unsigned int bytes_sent = 0;
8877f45cb82SAdrien Mazarguil unsigned int i;
888ec82dddaSMatan Azrad unsigned int max = elts_head - txq->elts_tail;
889afe67d2cSMatan Azrad struct mlx4_sq *sq = &txq->msq;
89078e81a98SMatan Azrad volatile struct mlx4_wqe_ctrl_seg *ctrl;
89178e81a98SMatan Azrad struct txq_elt *elt;
8927f45cb82SAdrien Mazarguil
8938e08df22SAlexander Kozyrev MLX4_ASSERT(txq->elts_comp_cd != 0);
894ec82dddaSMatan Azrad if (likely(max >= txq->elts_comp_cd_init))
89550163aecSMatan Azrad mlx4_txq_complete(txq, elts_m, sq);
896ec82dddaSMatan Azrad max = elts_n - max;
8978e08df22SAlexander Kozyrev MLX4_ASSERT(max >= 1);
8988e08df22SAlexander Kozyrev MLX4_ASSERT(max <= elts_n);
8997f45cb82SAdrien Mazarguil /* Always leave one free entry in the ring. */
9007f45cb82SAdrien Mazarguil --max;
9017f45cb82SAdrien Mazarguil if (max > pkts_n)
9027f45cb82SAdrien Mazarguil max = pkts_n;
90350163aecSMatan Azrad elt = &(*txq->elts)[elts_head & elts_m];
90453387152SMatan Azrad /* First Tx burst element saves the next WQE control segment. */
90578e81a98SMatan Azrad ctrl = elt->wqe;
9067f45cb82SAdrien Mazarguil for (i = 0; (i != max); ++i) {
9077f45cb82SAdrien Mazarguil struct rte_mbuf *buf = pkts[i];
90850163aecSMatan Azrad struct txq_elt *elt_next = &(*txq->elts)[++elts_head & elts_m];
90978e81a98SMatan Azrad uint32_t owner_opcode = sq->owner_opcode;
91078e81a98SMatan Azrad volatile struct mlx4_wqe_data_seg *dseg =
91178e81a98SMatan Azrad (volatile struct mlx4_wqe_data_seg *)(ctrl + 1);
91278e81a98SMatan Azrad volatile struct mlx4_wqe_ctrl_seg *ctrl_next;
913afe67d2cSMatan Azrad union {
914afe67d2cSMatan Azrad uint32_t flags;
915afe67d2cSMatan Azrad uint16_t flags16[2];
916afe67d2cSMatan Azrad } srcrb;
917afe67d2cSMatan Azrad uint32_t lkey;
918daa02b5cSOlivier Matz bool tso = txq->priv->tso && (buf->ol_flags & RTE_MBUF_F_TX_TCP_SEG);
9197f45cb82SAdrien Mazarguil
9207f45cb82SAdrien Mazarguil /* Clean up old buffer. */
9217f45cb82SAdrien Mazarguil if (likely(elt->buf != NULL)) {
9227f45cb82SAdrien Mazarguil struct rte_mbuf *tmp = elt->buf;
9237f45cb82SAdrien Mazarguil
9247f45cb82SAdrien Mazarguil /* Faster than rte_pktmbuf_free(). */
9257f45cb82SAdrien Mazarguil do {
9267f45cb82SAdrien Mazarguil struct rte_mbuf *next = tmp->next;
9277f45cb82SAdrien Mazarguil
9287f45cb82SAdrien Mazarguil rte_pktmbuf_free_seg(tmp);
9297f45cb82SAdrien Mazarguil tmp = next;
9307f45cb82SAdrien Mazarguil } while (tmp != NULL);
9317f45cb82SAdrien Mazarguil }
932c3c977bbSMoti Haimovsky RTE_MBUF_PREFETCH_TO_FREE(elt_next->buf);
933ba576975SMoti Haimovsky if (tso) {
934ba576975SMoti Haimovsky /* Change opcode to TSO */
935ba576975SMoti Haimovsky owner_opcode &= ~MLX4_OPCODE_CONFIG_CMD;
936ba576975SMoti Haimovsky owner_opcode |= MLX4_OPCODE_LSO | MLX4_WQE_CTRL_RR;
937ba576975SMoti Haimovsky ctrl_next = mlx4_tx_burst_tso(buf, txq, ctrl);
938ba576975SMoti Haimovsky if (!ctrl_next) {
939ba576975SMoti Haimovsky elt->buf = NULL;
940ba576975SMoti Haimovsky break;
941ba576975SMoti Haimovsky }
942ba576975SMoti Haimovsky } else if (buf->nb_segs == 1) {
94378e81a98SMatan Azrad /* Validate WQE space in the send queue. */
94478e81a98SMatan Azrad if (sq->remain_size < MLX4_TXBB_SIZE) {
9457f45cb82SAdrien Mazarguil elt->buf = NULL;
946afe67d2cSMatan Azrad break;
9477f45cb82SAdrien Mazarguil }
9489797bfccSYongseok Koh lkey = mlx4_tx_mb2mr(txq, buf);
949673800faSMatan Azrad if (unlikely(lkey == (uint32_t)-1)) {
950afe67d2cSMatan Azrad /* MR does not exist. */
951afe67d2cSMatan Azrad DEBUG("%p: unable to get MP <-> MR association",
952afe67d2cSMatan Azrad (void *)txq);
953afe67d2cSMatan Azrad elt->buf = NULL;
954afe67d2cSMatan Azrad break;
955afe67d2cSMatan Azrad }
95678e81a98SMatan Azrad mlx4_fill_tx_data_seg(dseg++, lkey,
957673800faSMatan Azrad rte_pktmbuf_mtod(buf, uintptr_t),
958673800faSMatan Azrad rte_cpu_to_be_32(buf->data_len));
95978e81a98SMatan Azrad /* Set WQE size in 16-byte units. */
96078e81a98SMatan Azrad ctrl->fence_size = 0x2;
96178e81a98SMatan Azrad sq->remain_size -= MLX4_TXBB_SIZE;
96278e81a98SMatan Azrad /* Align next WQE address to the next TXBB. */
96378e81a98SMatan Azrad ctrl_next = ctrl + 0x4;
964dae76a67SMatan Azrad } else {
96578e81a98SMatan Azrad ctrl_next = mlx4_tx_burst_segs(buf, txq, ctrl);
96678e81a98SMatan Azrad if (!ctrl_next) {
967dae76a67SMatan Azrad elt->buf = NULL;
968dae76a67SMatan Azrad break;
969dae76a67SMatan Azrad }
970dae76a67SMatan Azrad }
97178e81a98SMatan Azrad /* Hold SQ ring wrap around. */
97278e81a98SMatan Azrad if ((volatile uint8_t *)ctrl_next >= sq->eob) {
97378e81a98SMatan Azrad ctrl_next = (volatile struct mlx4_wqe_ctrl_seg *)
97478e81a98SMatan Azrad ((volatile uint8_t *)ctrl_next - sq->size);
97578e81a98SMatan Azrad /* Flip HW valid ownership. */
976911bbb0fSAdrien Mazarguil sq->owner_opcode ^= 1u << MLX4_SQ_OWNER_BIT;
97778e81a98SMatan Azrad }
978afe67d2cSMatan Azrad /*
979afe67d2cSMatan Azrad * For raw Ethernet, the SOLICIT flag is used to indicate
980afe67d2cSMatan Azrad * that no ICRC should be calculated.
981afe67d2cSMatan Azrad */
98278e81a98SMatan Azrad if (--txq->elts_comp_cd == 0) {
98353387152SMatan Azrad /* Save the completion burst end address. */
98453387152SMatan Azrad elt_next->eocb = (volatile uint32_t *)ctrl_next;
985afe67d2cSMatan Azrad txq->elts_comp_cd = txq->elts_comp_cd_init;
986afe67d2cSMatan Azrad srcrb.flags = RTE_BE32(MLX4_WQE_CTRL_SOLICIT |
987afe67d2cSMatan Azrad MLX4_WQE_CTRL_CQ_UPDATE);
988afe67d2cSMatan Azrad } else {
989afe67d2cSMatan Azrad srcrb.flags = RTE_BE32(MLX4_WQE_CTRL_SOLICIT);
990afe67d2cSMatan Azrad }
991afe67d2cSMatan Azrad /* Enable HW checksum offload if requested */
992afe67d2cSMatan Azrad if (txq->csum &&
993afe67d2cSMatan Azrad (buf->ol_flags &
994daa02b5cSOlivier Matz (RTE_MBUF_F_TX_IP_CKSUM | RTE_MBUF_F_TX_TCP_CKSUM | RTE_MBUF_F_TX_UDP_CKSUM))) {
995afe67d2cSMatan Azrad const uint64_t is_tunneled = (buf->ol_flags &
996daa02b5cSOlivier Matz (RTE_MBUF_F_TX_TUNNEL_GRE |
997daa02b5cSOlivier Matz RTE_MBUF_F_TX_TUNNEL_VXLAN));
998afe67d2cSMatan Azrad
999afe67d2cSMatan Azrad if (is_tunneled && txq->csum_l2tun) {
1000afe67d2cSMatan Azrad owner_opcode |= MLX4_WQE_CTRL_IIP_HDR_CSUM |
1001afe67d2cSMatan Azrad MLX4_WQE_CTRL_IL4_HDR_CSUM;
1002daa02b5cSOlivier Matz if (buf->ol_flags & RTE_MBUF_F_TX_OUTER_IP_CKSUM)
1003afe67d2cSMatan Azrad srcrb.flags |=
1004afe67d2cSMatan Azrad RTE_BE32(MLX4_WQE_CTRL_IP_HDR_CSUM);
1005afe67d2cSMatan Azrad } else {
1006afe67d2cSMatan Azrad srcrb.flags |=
1007afe67d2cSMatan Azrad RTE_BE32(MLX4_WQE_CTRL_IP_HDR_CSUM |
1008afe67d2cSMatan Azrad MLX4_WQE_CTRL_TCP_UDP_CSUM);
1009afe67d2cSMatan Azrad }
1010afe67d2cSMatan Azrad }
1011afe67d2cSMatan Azrad if (txq->lb) {
1012afe67d2cSMatan Azrad /*
1013afe67d2cSMatan Azrad * Copy destination MAC address to the WQE, this allows
1014afe67d2cSMatan Azrad * loopback in eSwitch, so that VFs and PF can
1015afe67d2cSMatan Azrad * communicate with each other.
1016afe67d2cSMatan Azrad */
1017afe67d2cSMatan Azrad srcrb.flags16[0] = *(rte_pktmbuf_mtod(buf, uint16_t *));
1018afe67d2cSMatan Azrad ctrl->imm = *(rte_pktmbuf_mtod_offset(buf, uint32_t *,
1019afe67d2cSMatan Azrad sizeof(uint16_t)));
1020afe67d2cSMatan Azrad } else {
1021afe67d2cSMatan Azrad ctrl->imm = 0;
1022afe67d2cSMatan Azrad }
1023afe67d2cSMatan Azrad ctrl->srcrb_flags = srcrb.flags;
1024afe67d2cSMatan Azrad /*
1025afe67d2cSMatan Azrad * Make sure descriptor is fully written before
1026afe67d2cSMatan Azrad * setting ownership bit (because HW can start
1027afe67d2cSMatan Azrad * executing as soon as we do).
1028afe67d2cSMatan Azrad */
102989ce4b02SMatan Azrad rte_io_wmb();
103078e81a98SMatan Azrad ctrl->owner_opcode = rte_cpu_to_be_32(owner_opcode);
10317f45cb82SAdrien Mazarguil elt->buf = buf;
1032c3c977bbSMoti Haimovsky bytes_sent += buf->pkt_len;
103378e81a98SMatan Azrad ctrl = ctrl_next;
103478e81a98SMatan Azrad elt = elt_next;
10357f45cb82SAdrien Mazarguil }
10367f45cb82SAdrien Mazarguil /* Take a shortcut if nothing must be sent. */
10377f45cb82SAdrien Mazarguil if (unlikely(i == 0))
10387f45cb82SAdrien Mazarguil return 0;
103953387152SMatan Azrad /* Save WQE address of the next Tx burst element. */
104053387152SMatan Azrad elt->wqe = ctrl;
1041c3c977bbSMoti Haimovsky /* Increment send statistics counters. */
10427f45cb82SAdrien Mazarguil txq->stats.opackets += i;
1043c3c977bbSMoti Haimovsky txq->stats.obytes += bytes_sent;
1044c3c977bbSMoti Haimovsky /* Make sure that descriptors are written before doorbell record. */
1045c3c977bbSMoti Haimovsky rte_wmb();
10467f45cb82SAdrien Mazarguil /* Ring QP doorbell. */
104797d37d2cSYongseok Koh rte_write32(txq->msq.doorbell_qpn, MLX4_TX_BFREG(txq));
104850163aecSMatan Azrad txq->elts_head += i;
10497f45cb82SAdrien Mazarguil return i;
10507f45cb82SAdrien Mazarguil }
10517f45cb82SAdrien Mazarguil
10527f45cb82SAdrien Mazarguil /**
10539f57340aSMoti Haimovsky * Translate Rx completion flags to packet type.
10549f57340aSMoti Haimovsky *
1055aee4a03fSMoti Haimovsky * @param[in] cqe
1056aee4a03fSMoti Haimovsky * Pointer to CQE.
10579f57340aSMoti Haimovsky *
10589f57340aSMoti Haimovsky * @return
1059aee4a03fSMoti Haimovsky * Packet type for struct rte_mbuf.
10609f57340aSMoti Haimovsky */
10619f57340aSMoti Haimovsky static inline uint32_t
rxq_cq_to_pkt_type(volatile struct mlx4_cqe * cqe,uint32_t l2tun_offload)106278214fb8SMoti Haimovsky rxq_cq_to_pkt_type(volatile struct mlx4_cqe *cqe,
106378214fb8SMoti Haimovsky uint32_t l2tun_offload)
10649f57340aSMoti Haimovsky {
1065aee4a03fSMoti Haimovsky uint8_t idx = 0;
1066aee4a03fSMoti Haimovsky uint32_t pinfo = rte_be_to_cpu_32(cqe->vlan_my_qpn);
1067aee4a03fSMoti Haimovsky uint32_t status = rte_be_to_cpu_32(cqe->status);
10689f57340aSMoti Haimovsky
1069aee4a03fSMoti Haimovsky /*
1070aee4a03fSMoti Haimovsky * The index to the array should have:
1071aee4a03fSMoti Haimovsky * bit[7] - MLX4_CQE_L2_TUNNEL
1072aee4a03fSMoti Haimovsky * bit[6] - MLX4_CQE_L2_TUNNEL_IPV4
1073aee4a03fSMoti Haimovsky */
107478214fb8SMoti Haimovsky if (l2tun_offload && (pinfo & MLX4_CQE_L2_TUNNEL))
1075aee4a03fSMoti Haimovsky idx |= ((pinfo & MLX4_CQE_L2_TUNNEL) >> 20) |
1076aee4a03fSMoti Haimovsky ((pinfo & MLX4_CQE_L2_TUNNEL_IPV4) >> 19);
1077aee4a03fSMoti Haimovsky /*
1078aee4a03fSMoti Haimovsky * The index to the array should have:
1079aee4a03fSMoti Haimovsky * bit[5] - MLX4_CQE_STATUS_UDP
1080aee4a03fSMoti Haimovsky * bit[4] - MLX4_CQE_STATUS_TCP
1081aee4a03fSMoti Haimovsky * bit[3] - MLX4_CQE_STATUS_IPV4OPT
1082aee4a03fSMoti Haimovsky * bit[2] - MLX4_CQE_STATUS_IPV6
1083c4fbea4bSMoti Haimovsky * bit[1] - MLX4_CQE_STATUS_IPF
1084aee4a03fSMoti Haimovsky * bit[0] - MLX4_CQE_STATUS_IPV4
1085aee4a03fSMoti Haimovsky * giving a total of up to 256 entries.
1086aee4a03fSMoti Haimovsky */
1087aee4a03fSMoti Haimovsky idx |= ((status & MLX4_CQE_STATUS_PTYPE_MASK) >> 22);
1088c4fbea4bSMoti Haimovsky if (status & MLX4_CQE_STATUS_IPV6)
1089c4fbea4bSMoti Haimovsky idx |= ((status & MLX4_CQE_STATUS_IPV6F) >> 11);
1090aee4a03fSMoti Haimovsky return mlx4_ptype_table[idx];
10919f57340aSMoti Haimovsky }
10929f57340aSMoti Haimovsky
10939f57340aSMoti Haimovsky /**
10949f57340aSMoti Haimovsky * Translate Rx completion flags to offload flags.
10959f57340aSMoti Haimovsky *
10969f57340aSMoti Haimovsky * @param flags
10979f57340aSMoti Haimovsky * Rx completion flags returned by mlx4_cqe_flags().
10989f57340aSMoti Haimovsky * @param csum
10999f57340aSMoti Haimovsky * Whether Rx checksums are enabled.
11009f57340aSMoti Haimovsky * @param csum_l2tun
11019f57340aSMoti Haimovsky * Whether Rx L2 tunnel checksums are enabled.
11029f57340aSMoti Haimovsky *
11039f57340aSMoti Haimovsky * @return
11049f57340aSMoti Haimovsky * Offload flags (ol_flags) in mbuf format.
11059f57340aSMoti Haimovsky */
11069f57340aSMoti Haimovsky static inline uint32_t
rxq_cq_to_ol_flags(uint32_t flags,int csum,int csum_l2tun)11079f57340aSMoti Haimovsky rxq_cq_to_ol_flags(uint32_t flags, int csum, int csum_l2tun)
11089f57340aSMoti Haimovsky {
11099f57340aSMoti Haimovsky uint32_t ol_flags = 0;
11109f57340aSMoti Haimovsky
11119f57340aSMoti Haimovsky if (csum)
11129f57340aSMoti Haimovsky ol_flags |=
11139f57340aSMoti Haimovsky mlx4_transpose(flags,
11149f57340aSMoti Haimovsky MLX4_CQE_STATUS_IP_HDR_CSUM_OK,
1115daa02b5cSOlivier Matz RTE_MBUF_F_RX_IP_CKSUM_GOOD) |
11169f57340aSMoti Haimovsky mlx4_transpose(flags,
11179f57340aSMoti Haimovsky MLX4_CQE_STATUS_TCP_UDP_CSUM_OK,
1118daa02b5cSOlivier Matz RTE_MBUF_F_RX_L4_CKSUM_GOOD);
11199f57340aSMoti Haimovsky if ((flags & MLX4_CQE_L2_TUNNEL) && csum_l2tun)
11209f57340aSMoti Haimovsky ol_flags |=
11219f57340aSMoti Haimovsky mlx4_transpose(flags,
11229f57340aSMoti Haimovsky MLX4_CQE_L2_TUNNEL_IPOK,
1123daa02b5cSOlivier Matz RTE_MBUF_F_RX_IP_CKSUM_GOOD) |
11249f57340aSMoti Haimovsky mlx4_transpose(flags,
11259f57340aSMoti Haimovsky MLX4_CQE_L2_TUNNEL_L4_CSUM,
1126daa02b5cSOlivier Matz RTE_MBUF_F_RX_L4_CKSUM_GOOD);
11279f57340aSMoti Haimovsky return ol_flags;
11289f57340aSMoti Haimovsky }
11299f57340aSMoti Haimovsky
11309f57340aSMoti Haimovsky /**
11319f57340aSMoti Haimovsky * Extract checksum information from CQE flags.
11329f57340aSMoti Haimovsky *
11339f57340aSMoti Haimovsky * @param cqe
11349f57340aSMoti Haimovsky * Pointer to CQE structure.
11359f57340aSMoti Haimovsky * @param csum
11369f57340aSMoti Haimovsky * Whether Rx checksums are enabled.
11379f57340aSMoti Haimovsky * @param csum_l2tun
11389f57340aSMoti Haimovsky * Whether Rx L2 tunnel checksums are enabled.
11399f57340aSMoti Haimovsky *
11409f57340aSMoti Haimovsky * @return
11419f57340aSMoti Haimovsky * CQE checksum information.
11429f57340aSMoti Haimovsky */
11439f57340aSMoti Haimovsky static inline uint32_t
mlx4_cqe_flags(volatile struct mlx4_cqe * cqe,int csum,int csum_l2tun)1144b68d92b4SMatan Azrad mlx4_cqe_flags(volatile struct mlx4_cqe *cqe, int csum, int csum_l2tun)
11459f57340aSMoti Haimovsky {
11469f57340aSMoti Haimovsky uint32_t flags = 0;
11479f57340aSMoti Haimovsky
11489f57340aSMoti Haimovsky /*
11499f57340aSMoti Haimovsky * The relevant bits are in different locations on their
11509f57340aSMoti Haimovsky * CQE fields therefore we can join them in one 32bit
11519f57340aSMoti Haimovsky * variable.
11529f57340aSMoti Haimovsky */
11539f57340aSMoti Haimovsky if (csum)
11549f57340aSMoti Haimovsky flags = (rte_be_to_cpu_32(cqe->status) &
11559f57340aSMoti Haimovsky MLX4_CQE_STATUS_IPV4_CSUM_OK);
11569f57340aSMoti Haimovsky if (csum_l2tun)
11579f57340aSMoti Haimovsky flags |= (rte_be_to_cpu_32(cqe->vlan_my_qpn) &
11589f57340aSMoti Haimovsky (MLX4_CQE_L2_TUNNEL |
11599f57340aSMoti Haimovsky MLX4_CQE_L2_TUNNEL_IPOK |
11609f57340aSMoti Haimovsky MLX4_CQE_L2_TUNNEL_L4_CSUM |
11619f57340aSMoti Haimovsky MLX4_CQE_L2_TUNNEL_IPV4));
11629f57340aSMoti Haimovsky return flags;
11639f57340aSMoti Haimovsky }
11649f57340aSMoti Haimovsky
11659f57340aSMoti Haimovsky /**
11666681b845SMoti Haimovsky * Poll one CQE from CQ.
11677f45cb82SAdrien Mazarguil *
11686681b845SMoti Haimovsky * @param rxq
11696681b845SMoti Haimovsky * Pointer to the receive queue structure.
11706681b845SMoti Haimovsky * @param[out] out
11716681b845SMoti Haimovsky * Just polled CQE.
11726681b845SMoti Haimovsky *
11736681b845SMoti Haimovsky * @return
11746681b845SMoti Haimovsky * Number of bytes of the CQE, 0 in case there is no completion.
11756681b845SMoti Haimovsky */
11766681b845SMoti Haimovsky static unsigned int
mlx4_cq_poll_one(struct rxq * rxq,volatile struct mlx4_cqe ** out)1177b68d92b4SMatan Azrad mlx4_cq_poll_one(struct rxq *rxq, volatile struct mlx4_cqe **out)
11786681b845SMoti Haimovsky {
11796681b845SMoti Haimovsky int ret = 0;
1180b68d92b4SMatan Azrad volatile struct mlx4_cqe *cqe = NULL;
11816681b845SMoti Haimovsky struct mlx4_cq *cq = &rxq->mcq;
11826681b845SMoti Haimovsky
1183b68d92b4SMatan Azrad cqe = (volatile struct mlx4_cqe *)mlx4_get_cqe(cq, cq->cons_index);
11846681b845SMoti Haimovsky if (!!(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK) ^
11856681b845SMoti Haimovsky !!(cq->cons_index & cq->cqe_cnt))
11866681b845SMoti Haimovsky goto out;
11876681b845SMoti Haimovsky /*
11886681b845SMoti Haimovsky * Make sure we read CQ entry contents after we've checked the
11896681b845SMoti Haimovsky * ownership bit.
11906681b845SMoti Haimovsky */
11916681b845SMoti Haimovsky rte_rmb();
11928e08df22SAlexander Kozyrev MLX4_ASSERT(!(cqe->owner_sr_opcode & MLX4_CQE_IS_SEND_MASK));
11938e08df22SAlexander Kozyrev MLX4_ASSERT((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) !=
11946681b845SMoti Haimovsky MLX4_CQE_OPCODE_ERROR);
11956681b845SMoti Haimovsky ret = rte_be_to_cpu_32(cqe->byte_cnt);
11966681b845SMoti Haimovsky ++cq->cons_index;
11976681b845SMoti Haimovsky out:
11986681b845SMoti Haimovsky *out = cqe;
11996681b845SMoti Haimovsky return ret;
12006681b845SMoti Haimovsky }
12016681b845SMoti Haimovsky
12026681b845SMoti Haimovsky /**
12036681b845SMoti Haimovsky * DPDK callback for Rx with scattered packets support.
12047f45cb82SAdrien Mazarguil *
12057f45cb82SAdrien Mazarguil * @param dpdk_rxq
12067f45cb82SAdrien Mazarguil * Generic pointer to Rx queue structure.
12077f45cb82SAdrien Mazarguil * @param[out] pkts
12087f45cb82SAdrien Mazarguil * Array to store received packets.
12097f45cb82SAdrien Mazarguil * @param pkts_n
12107f45cb82SAdrien Mazarguil * Maximum number of packets in array.
12117f45cb82SAdrien Mazarguil *
12127f45cb82SAdrien Mazarguil * @return
12137f45cb82SAdrien Mazarguil * Number of packets successfully received (<= pkts_n).
12147f45cb82SAdrien Mazarguil */
12157f45cb82SAdrien Mazarguil uint16_t
mlx4_rx_burst(void * dpdk_rxq,struct rte_mbuf ** pkts,uint16_t pkts_n)12167f45cb82SAdrien Mazarguil mlx4_rx_burst(void *dpdk_rxq, struct rte_mbuf **pkts, uint16_t pkts_n)
12177f45cb82SAdrien Mazarguil {
12186681b845SMoti Haimovsky struct rxq *rxq = dpdk_rxq;
12196681b845SMoti Haimovsky const uint32_t wr_cnt = (1 << rxq->elts_n) - 1;
12206681b845SMoti Haimovsky const uint16_t sges_n = rxq->sges_n;
12216681b845SMoti Haimovsky struct rte_mbuf *pkt = NULL;
12226681b845SMoti Haimovsky struct rte_mbuf *seg = NULL;
12236681b845SMoti Haimovsky unsigned int i = 0;
12246681b845SMoti Haimovsky uint32_t rq_ci = rxq->rq_ci << sges_n;
12256681b845SMoti Haimovsky int len = 0;
12267f45cb82SAdrien Mazarguil
12276681b845SMoti Haimovsky while (pkts_n) {
1228b68d92b4SMatan Azrad volatile struct mlx4_cqe *cqe;
12296681b845SMoti Haimovsky uint32_t idx = rq_ci & wr_cnt;
12306681b845SMoti Haimovsky struct rte_mbuf *rep = (*rxq->elts)[idx];
12316681b845SMoti Haimovsky volatile struct mlx4_wqe_data_seg *scat = &(*rxq->wqes)[idx];
12327f45cb82SAdrien Mazarguil
12336681b845SMoti Haimovsky /* Update the 'next' pointer of the previous segment. */
12346681b845SMoti Haimovsky if (pkt)
12356681b845SMoti Haimovsky seg->next = rep;
12366681b845SMoti Haimovsky seg = rep;
12376681b845SMoti Haimovsky rte_prefetch0(seg);
12386681b845SMoti Haimovsky rte_prefetch0(scat);
12397f45cb82SAdrien Mazarguil rep = rte_mbuf_raw_alloc(rxq->mp);
12407f45cb82SAdrien Mazarguil if (unlikely(rep == NULL)) {
12417f45cb82SAdrien Mazarguil ++rxq->stats.rx_nombuf;
12426681b845SMoti Haimovsky if (!pkt) {
12436681b845SMoti Haimovsky /*
12446681b845SMoti Haimovsky * No buffers before we even started,
12456681b845SMoti Haimovsky * bail out silently.
12466681b845SMoti Haimovsky */
12476681b845SMoti Haimovsky break;
12487f45cb82SAdrien Mazarguil }
12496681b845SMoti Haimovsky while (pkt != seg) {
12508e08df22SAlexander Kozyrev MLX4_ASSERT(pkt != (*rxq->elts)[idx]);
12516681b845SMoti Haimovsky rep = pkt->next;
12526681b845SMoti Haimovsky pkt->next = NULL;
12536681b845SMoti Haimovsky pkt->nb_segs = 1;
12546681b845SMoti Haimovsky rte_mbuf_raw_free(pkt);
12556681b845SMoti Haimovsky pkt = rep;
12566681b845SMoti Haimovsky }
12576681b845SMoti Haimovsky break;
12586681b845SMoti Haimovsky }
12596681b845SMoti Haimovsky if (!pkt) {
12606681b845SMoti Haimovsky /* Looking for the new packet. */
12616681b845SMoti Haimovsky len = mlx4_cq_poll_one(rxq, &cqe);
12626681b845SMoti Haimovsky if (!len) {
12636681b845SMoti Haimovsky rte_mbuf_raw_free(rep);
12646681b845SMoti Haimovsky break;
12656681b845SMoti Haimovsky }
12666681b845SMoti Haimovsky if (unlikely(len < 0)) {
12676681b845SMoti Haimovsky /* Rx error, packet is likely too large. */
12686681b845SMoti Haimovsky rte_mbuf_raw_free(rep);
12696681b845SMoti Haimovsky ++rxq->stats.idropped;
12706681b845SMoti Haimovsky goto skip;
12716681b845SMoti Haimovsky }
12726681b845SMoti Haimovsky pkt = seg;
12738e08df22SAlexander Kozyrev MLX4_ASSERT(len >= (rxq->crc_present << 2));
1274aee4a03fSMoti Haimovsky /* Update packet information. */
127578214fb8SMoti Haimovsky pkt->packet_type =
127678214fb8SMoti Haimovsky rxq_cq_to_pkt_type(cqe, rxq->l2tun_offload);
1277daa02b5cSOlivier Matz pkt->ol_flags = RTE_MBUF_F_RX_RSS_HASH;
12788937c9f1SRaslan Darawsheh pkt->hash.rss = cqe->immed_rss_invalid;
1279de1df14eSOphir Munk if (rxq->crc_present)
128035b2d13fSOlivier Matz len -= RTE_ETHER_CRC_LEN;
1281aee4a03fSMoti Haimovsky pkt->pkt_len = len;
12829f57340aSMoti Haimovsky if (rxq->csum | rxq->csum_l2tun) {
12839f57340aSMoti Haimovsky uint32_t flags =
12849f57340aSMoti Haimovsky mlx4_cqe_flags(cqe,
12859f57340aSMoti Haimovsky rxq->csum,
12869f57340aSMoti Haimovsky rxq->csum_l2tun);
12879f57340aSMoti Haimovsky
12889f57340aSMoti Haimovsky pkt->ol_flags =
12899f57340aSMoti Haimovsky rxq_cq_to_ol_flags(flags,
12909f57340aSMoti Haimovsky rxq->csum,
12919f57340aSMoti Haimovsky rxq->csum_l2tun);
12929f57340aSMoti Haimovsky }
12936681b845SMoti Haimovsky }
12946681b845SMoti Haimovsky rep->nb_segs = 1;
12956681b845SMoti Haimovsky rep->port = rxq->port_id;
12966681b845SMoti Haimovsky rep->data_len = seg->data_len;
12976681b845SMoti Haimovsky rep->data_off = seg->data_off;
12986681b845SMoti Haimovsky (*rxq->elts)[idx] = rep;
12996681b845SMoti Haimovsky /*
13006681b845SMoti Haimovsky * Fill NIC descriptor with the new buffer. The lkey and size
13016681b845SMoti Haimovsky * of the buffers are already known, only the buffer address
13026681b845SMoti Haimovsky * changes.
13036681b845SMoti Haimovsky */
13046681b845SMoti Haimovsky scat->addr = rte_cpu_to_be_64(rte_pktmbuf_mtod(rep, uintptr_t));
13059797bfccSYongseok Koh /* If there's only one MR, no need to replace LKey in WQE. */
13069797bfccSYongseok Koh if (unlikely(mlx4_mr_btree_len(&rxq->mr_ctrl.cache_bh) > 1))
13079797bfccSYongseok Koh scat->lkey = mlx4_rx_mb2mr(rxq, rep);
13086681b845SMoti Haimovsky if (len > seg->data_len) {
13096681b845SMoti Haimovsky len -= seg->data_len;
13106681b845SMoti Haimovsky ++pkt->nb_segs;
13116681b845SMoti Haimovsky ++rq_ci;
13127f45cb82SAdrien Mazarguil continue;
13137f45cb82SAdrien Mazarguil }
13146681b845SMoti Haimovsky /* The last segment. */
13156681b845SMoti Haimovsky seg->data_len = len;
13166681b845SMoti Haimovsky /* Increment bytes counter. */
13176681b845SMoti Haimovsky rxq->stats.ibytes += pkt->pkt_len;
13186681b845SMoti Haimovsky /* Return packet. */
13196681b845SMoti Haimovsky *(pkts++) = pkt;
13206681b845SMoti Haimovsky pkt = NULL;
13216681b845SMoti Haimovsky --pkts_n;
13226681b845SMoti Haimovsky ++i;
13236681b845SMoti Haimovsky skip:
13246681b845SMoti Haimovsky /* Align consumer index to the next stride. */
13256681b845SMoti Haimovsky rq_ci >>= sges_n;
13266681b845SMoti Haimovsky ++rq_ci;
13276681b845SMoti Haimovsky rq_ci <<= sges_n;
13287f45cb82SAdrien Mazarguil }
13296681b845SMoti Haimovsky if (unlikely(i == 0 && (rq_ci >> sges_n) == rxq->rq_ci))
13306681b845SMoti Haimovsky return 0;
13316681b845SMoti Haimovsky /* Update the consumer index. */
13326681b845SMoti Haimovsky rxq->rq_ci = rq_ci >> sges_n;
13336681b845SMoti Haimovsky rte_wmb();
13346681b845SMoti Haimovsky *rxq->rq_db = rte_cpu_to_be_32(rxq->rq_ci);
133509613458SMoti Haimovsky *rxq->mcq.set_ci_db =
133609613458SMoti Haimovsky rte_cpu_to_be_32(rxq->mcq.cons_index & MLX4_CQ_DB_CI_MASK);
13376681b845SMoti Haimovsky /* Increment packets counter. */
13386681b845SMoti Haimovsky rxq->stats.ipackets += i;
13396681b845SMoti Haimovsky return i;
13407f45cb82SAdrien Mazarguil }
1341