xref: /dpdk/drivers/net/mlx4/mlx4_rxtx.c (revision 27595cd83053b2d39634a159d6709b3ce3cdf3b0)
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