1 /*
2 * Copyright (c) 2017 Mellanox Technologies, Inc. All rights reserved.
3 *
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
9 *
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions are met:
13 *
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 */
32
33 #ifndef _MLX5DV_H_
34 #define _MLX5DV_H_
35
36 #include <infiniband/types.h> /* For the __be64 type */
37 #include <infiniband/endian.h>
38
39 #if defined(__SSE3__)
40 #include <emmintrin.h>
41 #include <tmmintrin.h>
42 #endif /* defined(__SSE3__) */
43
44 #include <infiniband/verbs.h>
45
46 /* Always inline the functions */
47 #ifdef __GNUC__
48 #define MLX5DV_ALWAYS_INLINE inline __attribute__((always_inline))
49 #else
50 #define MLX5DV_ALWAYS_INLINE inline
51 #endif
52
53 enum {
54 MLX5_RCV_DBR = 0,
55 MLX5_SND_DBR = 1,
56 };
57
58 enum mlx5dv_context_comp_mask {
59 MLX5DV_CONTEXT_MASK_CQE_COMPRESION = 1 << 0,
60 MLX5DV_CONTEXT_MASK_RESERVED = 1 << 1,
61 };
62
63 struct mlx5dv_cqe_comp_caps {
64 uint32_t max_num;
65 uint32_t supported_format; /* enum mlx5dv_cqe_comp_res_format */
66 };
67
68 /*
69 * Direct verbs device-specific attributes
70 */
71 struct mlx5dv_context {
72 uint8_t version;
73 uint64_t flags;
74 uint64_t comp_mask;
75 struct mlx5dv_cqe_comp_caps cqe_comp_caps;
76 };
77
78 enum mlx5dv_context_flags {
79 /*
80 * This flag indicates if CQE version 0 or 1 is needed.
81 */
82 MLX5DV_CONTEXT_FLAGS_CQE_V1 = (1 << 0),
83 MLX5DV_CONTEXT_FLAGS_MPW = (1 << 1),
84 };
85
86 enum mlx5dv_cq_init_attr_mask {
87 MLX5DV_CQ_INIT_ATTR_MASK_COMPRESSED_CQE = 1 << 0,
88 MLX5DV_CQ_INIT_ATTR_MASK_RESERVED = 1 << 1,
89 };
90
91 struct mlx5dv_cq_init_attr {
92 uint64_t comp_mask; /* Use enum mlx5dv_cq_init_attr_mask */
93 uint8_t cqe_comp_res_format; /* Use enum mlx5dv_cqe_comp_res_format */
94 };
95
96 struct ibv_cq_ex *mlx5dv_create_cq(struct ibv_context *context,
97 struct ibv_cq_init_attr_ex *cq_attr,
98 struct mlx5dv_cq_init_attr *mlx5_cq_attr);
99 /*
100 * Most device capabilities are exported by ibv_query_device(...),
101 * but there is HW device-specific information which is important
102 * for data-path, but isn't provided.
103 *
104 * Return 0 on success.
105 */
106 int mlx5dv_query_device(struct ibv_context *ctx_in,
107 struct mlx5dv_context *attrs_out);
108
109 struct mlx5dv_qp {
110 uint32_t *dbrec;
111 struct {
112 void *buf;
113 uint32_t wqe_cnt;
114 uint32_t stride;
115 } sq;
116 struct {
117 void *buf;
118 uint32_t wqe_cnt;
119 uint32_t stride;
120 } rq;
121 struct {
122 void *reg;
123 uint32_t size;
124 } bf;
125 uint64_t comp_mask;
126 };
127
128 struct mlx5dv_cq {
129 void *buf;
130 uint32_t *dbrec;
131 uint32_t cqe_cnt;
132 uint32_t cqe_size;
133 void *uar;
134 uint32_t cqn;
135 uint64_t comp_mask;
136 };
137
138 struct mlx5dv_srq {
139 void *buf;
140 uint32_t *dbrec;
141 uint32_t stride;
142 uint32_t head;
143 uint32_t tail;
144 uint64_t comp_mask;
145 };
146
147 struct mlx5dv_rwq {
148 void *buf;
149 uint32_t *dbrec;
150 uint32_t wqe_cnt;
151 uint32_t stride;
152 uint64_t comp_mask;
153 };
154
155 struct mlx5dv_obj {
156 struct {
157 struct ibv_qp *in;
158 struct mlx5dv_qp *out;
159 } qp;
160 struct {
161 struct ibv_cq *in;
162 struct mlx5dv_cq *out;
163 } cq;
164 struct {
165 struct ibv_srq *in;
166 struct mlx5dv_srq *out;
167 } srq;
168 struct {
169 struct ibv_wq *in;
170 struct mlx5dv_rwq *out;
171 } rwq;
172 };
173
174 enum mlx5dv_obj_type {
175 MLX5DV_OBJ_QP = 1 << 0,
176 MLX5DV_OBJ_CQ = 1 << 1,
177 MLX5DV_OBJ_SRQ = 1 << 2,
178 MLX5DV_OBJ_RWQ = 1 << 3,
179 };
180
181 /*
182 * This function will initialize mlx5dv_xxx structs based on supplied type.
183 * The information for initialization is taken from ibv_xx structs supplied
184 * as part of input.
185 *
186 * Request information of CQ marks its owned by DV for all consumer index
187 * related actions.
188 *
189 * The initialization type can be combination of several types together.
190 *
191 * Return: 0 in case of success.
192 */
193 int mlx5dv_init_obj(struct mlx5dv_obj *obj, uint64_t obj_type);
194
195 enum {
196 MLX5_OPCODE_NOP = 0x00,
197 MLX5_OPCODE_SEND_INVAL = 0x01,
198 MLX5_OPCODE_RDMA_WRITE = 0x08,
199 MLX5_OPCODE_RDMA_WRITE_IMM = 0x09,
200 MLX5_OPCODE_SEND = 0x0a,
201 MLX5_OPCODE_SEND_IMM = 0x0b,
202 MLX5_OPCODE_TSO = 0x0e,
203 MLX5_OPCODE_RDMA_READ = 0x10,
204 MLX5_OPCODE_ATOMIC_CS = 0x11,
205 MLX5_OPCODE_ATOMIC_FA = 0x12,
206 MLX5_OPCODE_ATOMIC_MASKED_CS = 0x14,
207 MLX5_OPCODE_ATOMIC_MASKED_FA = 0x15,
208 MLX5_OPCODE_FMR = 0x19,
209 MLX5_OPCODE_LOCAL_INVAL = 0x1b,
210 MLX5_OPCODE_CONFIG_CMD = 0x1f,
211 MLX5_OPCODE_UMR = 0x25,
212 };
213
214 /*
215 * CQE related part
216 */
217
218 enum {
219 MLX5_INLINE_SCATTER_32 = 0x4,
220 MLX5_INLINE_SCATTER_64 = 0x8,
221 };
222
223 enum {
224 MLX5_CQE_SYNDROME_LOCAL_LENGTH_ERR = 0x01,
225 MLX5_CQE_SYNDROME_LOCAL_QP_OP_ERR = 0x02,
226 MLX5_CQE_SYNDROME_LOCAL_PROT_ERR = 0x04,
227 MLX5_CQE_SYNDROME_WR_FLUSH_ERR = 0x05,
228 MLX5_CQE_SYNDROME_MW_BIND_ERR = 0x06,
229 MLX5_CQE_SYNDROME_BAD_RESP_ERR = 0x10,
230 MLX5_CQE_SYNDROME_LOCAL_ACCESS_ERR = 0x11,
231 MLX5_CQE_SYNDROME_REMOTE_INVAL_REQ_ERR = 0x12,
232 MLX5_CQE_SYNDROME_REMOTE_ACCESS_ERR = 0x13,
233 MLX5_CQE_SYNDROME_REMOTE_OP_ERR = 0x14,
234 MLX5_CQE_SYNDROME_TRANSPORT_RETRY_EXC_ERR = 0x15,
235 MLX5_CQE_SYNDROME_RNR_RETRY_EXC_ERR = 0x16,
236 MLX5_CQE_SYNDROME_REMOTE_ABORTED_ERR = 0x22,
237 };
238
239 enum {
240 MLX5_CQE_L2_OK = 1 << 0,
241 MLX5_CQE_L3_OK = 1 << 1,
242 MLX5_CQE_L4_OK = 1 << 2,
243 };
244
245 enum {
246 MLX5_CQE_L3_HDR_TYPE_NONE = 0x0,
247 MLX5_CQE_L3_HDR_TYPE_IPV6 = 0x1,
248 MLX5_CQE_L3_HDR_TYPE_IPV4 = 0x2,
249 };
250
251 enum {
252 MLX5_CQE_OWNER_MASK = 1,
253 MLX5_CQE_REQ = 0,
254 MLX5_CQE_RESP_WR_IMM = 1,
255 MLX5_CQE_RESP_SEND = 2,
256 MLX5_CQE_RESP_SEND_IMM = 3,
257 MLX5_CQE_RESP_SEND_INV = 4,
258 MLX5_CQE_RESIZE_CQ = 5,
259 MLX5_CQE_REQ_ERR = 13,
260 MLX5_CQE_RESP_ERR = 14,
261 MLX5_CQE_INVALID = 15,
262 };
263
264 enum {
265 MLX5_CQ_DOORBELL = 0x20
266 };
267
268 enum {
269 MLX5_CQ_DB_REQ_NOT_SOL = 1 << 24,
270 MLX5_CQ_DB_REQ_NOT = 0 << 24,
271 };
272
273 struct mlx5_err_cqe {
274 uint8_t rsvd0[32];
275 uint32_t srqn;
276 uint8_t rsvd1[18];
277 uint8_t vendor_err_synd;
278 uint8_t syndrome;
279 uint32_t s_wqe_opcode_qpn;
280 uint16_t wqe_counter;
281 uint8_t signature;
282 uint8_t op_own;
283 };
284
285 struct mlx5_cqe64 {
286 uint8_t rsvd0[17];
287 uint8_t ml_path;
288 uint8_t rsvd20[4];
289 uint16_t slid;
290 uint32_t flags_rqpn;
291 uint8_t hds_ip_ext;
292 uint8_t l4_hdr_type_etc;
293 uint16_t vlan_info;
294 uint32_t srqn_uidx;
295 uint32_t imm_inval_pkey;
296 uint8_t rsvd40[4];
297 uint32_t byte_cnt;
298 __be64 timestamp;
299 uint32_t sop_drop_qpn;
300 uint16_t wqe_counter;
301 uint8_t signature;
302 uint8_t op_own;
303 };
304
305 enum mlx5dv_cqe_comp_res_format {
306 MLX5DV_CQE_RES_FORMAT_HASH = 1 << 0,
307 MLX5DV_CQE_RES_FORMAT_CSUM = 1 << 1,
308 MLX5DV_CQE_RES_FORMAT_RESERVED = 1 << 2,
309 };
310
311 static MLX5DV_ALWAYS_INLINE
mlx5dv_get_cqe_owner(struct mlx5_cqe64 * cqe)312 uint8_t mlx5dv_get_cqe_owner(struct mlx5_cqe64 *cqe)
313 {
314 return cqe->op_own & 0x1;
315 }
316
317 static MLX5DV_ALWAYS_INLINE
mlx5dv_set_cqe_owner(struct mlx5_cqe64 * cqe,uint8_t val)318 void mlx5dv_set_cqe_owner(struct mlx5_cqe64 *cqe, uint8_t val)
319 {
320 cqe->op_own = (val & 0x1) | (cqe->op_own & ~0x1);
321 }
322
323 /* Solicited event */
324 static MLX5DV_ALWAYS_INLINE
mlx5dv_get_cqe_se(struct mlx5_cqe64 * cqe)325 uint8_t mlx5dv_get_cqe_se(struct mlx5_cqe64 *cqe)
326 {
327 return (cqe->op_own >> 1) & 0x1;
328 }
329
330 static MLX5DV_ALWAYS_INLINE
mlx5dv_get_cqe_format(struct mlx5_cqe64 * cqe)331 uint8_t mlx5dv_get_cqe_format(struct mlx5_cqe64 *cqe)
332 {
333 return (cqe->op_own >> 2) & 0x3;
334 }
335
336 static MLX5DV_ALWAYS_INLINE
mlx5dv_get_cqe_opcode(struct mlx5_cqe64 * cqe)337 uint8_t mlx5dv_get_cqe_opcode(struct mlx5_cqe64 *cqe)
338 {
339 return cqe->op_own >> 4;
340 }
341
342 /*
343 * WQE related part
344 */
345 enum {
346 MLX5_INVALID_LKEY = 0x100,
347 };
348
349 enum {
350 MLX5_EXTENDED_UD_AV = 0x80000000,
351 };
352
353 enum {
354 MLX5_WQE_CTRL_CQ_UPDATE = 2 << 2,
355 MLX5_WQE_CTRL_SOLICITED = 1 << 1,
356 MLX5_WQE_CTRL_FENCE = 4 << 5,
357 MLX5_WQE_CTRL_INITIATOR_SMALL_FENCE = 1 << 5,
358 };
359
360 enum {
361 MLX5_SEND_WQE_BB = 64,
362 MLX5_SEND_WQE_SHIFT = 6,
363 };
364
365 enum {
366 MLX5_INLINE_SEG = 0x80000000,
367 };
368
369 enum {
370 MLX5_ETH_WQE_L3_CSUM = (1 << 6),
371 MLX5_ETH_WQE_L4_CSUM = (1 << 7),
372 };
373
374 struct mlx5_wqe_srq_next_seg {
375 uint8_t rsvd0[2];
376 uint16_t next_wqe_index;
377 uint8_t signature;
378 uint8_t rsvd1[11];
379 };
380
381 struct mlx5_wqe_data_seg {
382 uint32_t byte_count;
383 uint32_t lkey;
384 uint64_t addr;
385 };
386
387 struct mlx5_wqe_ctrl_seg {
388 uint32_t opmod_idx_opcode;
389 uint32_t qpn_ds;
390 uint8_t signature;
391 uint8_t rsvd[2];
392 uint8_t fm_ce_se;
393 uint32_t imm;
394 };
395
396 struct mlx5_wqe_av {
397 union {
398 struct {
399 uint32_t qkey;
400 uint32_t reserved;
401 } qkey;
402 uint64_t dc_key;
403 } key;
404 uint32_t dqp_dct;
405 uint8_t stat_rate_sl;
406 uint8_t fl_mlid;
407 uint16_t rlid;
408 uint8_t reserved0[4];
409 uint8_t rmac[6];
410 uint8_t tclass;
411 uint8_t hop_limit;
412 uint32_t grh_gid_fl;
413 uint8_t rgid[16];
414 };
415
416 struct mlx5_wqe_datagram_seg {
417 struct mlx5_wqe_av av;
418 };
419
420 struct mlx5_wqe_raddr_seg {
421 uint64_t raddr;
422 uint32_t rkey;
423 uint32_t reserved;
424 };
425
426 struct mlx5_wqe_atomic_seg {
427 uint64_t swap_add;
428 uint64_t compare;
429 };
430
431 struct mlx5_wqe_inl_data_seg {
432 uint32_t byte_count;
433 };
434
435 struct mlx5_wqe_eth_seg {
436 uint32_t rsvd0;
437 uint8_t cs_flags;
438 uint8_t rsvd1;
439 uint16_t mss;
440 uint32_t rsvd2;
441 uint16_t inline_hdr_sz;
442 uint8_t inline_hdr_start[2];
443 uint8_t inline_hdr[16];
444 };
445
446 /*
447 * Control segment - contains some control information for the current WQE.
448 *
449 * Output:
450 * seg - control segment to be filled
451 * Input:
452 * pi - WQEBB number of the first block of this WQE.
453 * This number should wrap at 0xffff, regardless of
454 * size of the WQ.
455 * opcode - Opcode of this WQE. Encodes the type of operation
456 * to be executed on the QP.
457 * opmod - Opcode modifier.
458 * qp_num - QP/SQ number this WQE is posted to.
459 * fm_ce_se - FM (fence mode), CE (completion and event mode)
460 * and SE (solicited event).
461 * ds - WQE size in octowords (16-byte units). DS accounts for all
462 * the segments in the WQE as summarized in WQE construction.
463 * signature - WQE signature.
464 * imm - Immediate data/Invalidation key/UMR mkey.
465 */
466 static MLX5DV_ALWAYS_INLINE
mlx5dv_set_ctrl_seg(struct mlx5_wqe_ctrl_seg * seg,uint16_t pi,uint8_t opcode,uint8_t opmod,uint32_t qp_num,uint8_t fm_ce_se,uint8_t ds,uint8_t signature,uint32_t imm)467 void mlx5dv_set_ctrl_seg(struct mlx5_wqe_ctrl_seg *seg, uint16_t pi,
468 uint8_t opcode, uint8_t opmod, uint32_t qp_num,
469 uint8_t fm_ce_se, uint8_t ds,
470 uint8_t signature, uint32_t imm)
471 {
472 seg->opmod_idx_opcode = htobe32(((uint32_t)opmod << 24) | ((uint32_t)pi << 8) | opcode);
473 seg->qpn_ds = htobe32((qp_num << 8) | ds);
474 seg->fm_ce_se = fm_ce_se;
475 seg->signature = signature;
476 /*
477 * The caller should prepare "imm" in advance based on WR opcode.
478 * For IBV_WR_SEND_WITH_IMM and IBV_WR_RDMA_WRITE_WITH_IMM,
479 * the "imm" should be assigned as is.
480 * For the IBV_WR_SEND_WITH_INV, it should be htobe32(imm).
481 */
482 seg->imm = imm;
483 }
484
485 /* x86 optimized version of mlx5dv_set_ctrl_seg()
486 *
487 * This is useful when doing calculations on large data sets
488 * for parallel calculations.
489 *
490 * It doesn't suit for serialized algorithms.
491 */
492 #if defined(__SSE3__)
493 static MLX5DV_ALWAYS_INLINE
mlx5dv_x86_set_ctrl_seg(struct mlx5_wqe_ctrl_seg * seg,uint16_t pi,uint8_t opcode,uint8_t opmod,uint32_t qp_num,uint8_t fm_ce_se,uint8_t ds,uint8_t signature,uint32_t imm)494 void mlx5dv_x86_set_ctrl_seg(struct mlx5_wqe_ctrl_seg *seg, uint16_t pi,
495 uint8_t opcode, uint8_t opmod, uint32_t qp_num,
496 uint8_t fm_ce_se, uint8_t ds,
497 uint8_t signature, uint32_t imm)
498 {
499 __m128i val = _mm_set_epi32(imm, qp_num, (ds << 16) | pi,
500 (signature << 24) | (opcode << 16) | (opmod << 8) | fm_ce_se);
501 __m128i mask = _mm_set_epi8(15, 14, 13, 12, /* immediate */
502 0, /* signal/fence_mode */
503 0x80, 0x80, /* reserved */
504 3, /* signature */
505 6, /* data size */
506 8, 9, 10, /* QP num */
507 2, /* opcode */
508 4, 5, /* sw_pi in BE */
509 1 /* opmod */
510 );
511 *(__m128i *) seg = _mm_shuffle_epi8(val, mask);
512 }
513 #endif /* defined(__SSE3__) */
514
515 /*
516 * Datagram Segment - contains address information required in order
517 * to form a datagram message.
518 *
519 * Output:
520 * seg - datagram segment to be filled.
521 * Input:
522 * key - Q_key/access key.
523 * dqp_dct - Destination QP number for UD and DCT for DC.
524 * ext - Address vector extension.
525 * stat_rate_sl - Maximum static rate control, SL/ethernet priority.
526 * fl_mlid - Force loopback and source LID for IB.
527 * rlid - Remote LID
528 * rmac - Remote MAC
529 * tclass - GRH tclass/IPv6 tclass/IPv4 ToS
530 * hop_limit - GRH hop limit/IPv6 hop limit/IPv4 TTL
531 * grh_gid_fi - GRH, source GID address and IPv6 flow label.
532 * rgid - Remote GID/IP address.
533 */
534 static MLX5DV_ALWAYS_INLINE
mlx5dv_set_dgram_seg(struct mlx5_wqe_datagram_seg * seg,uint64_t key,uint32_t dqp_dct,uint8_t ext,uint8_t stat_rate_sl,uint8_t fl_mlid,uint16_t rlid,uint8_t * rmac,uint8_t tclass,uint8_t hop_limit,uint32_t grh_gid_fi,uint8_t * rgid)535 void mlx5dv_set_dgram_seg(struct mlx5_wqe_datagram_seg *seg,
536 uint64_t key, uint32_t dqp_dct,
537 uint8_t ext, uint8_t stat_rate_sl,
538 uint8_t fl_mlid, uint16_t rlid,
539 uint8_t *rmac, uint8_t tclass,
540 uint8_t hop_limit, uint32_t grh_gid_fi,
541 uint8_t *rgid)
542 {
543
544 /* Always put 64 bits, in q_key, the reserved part will be 0 */
545 seg->av.key.dc_key = htobe64(key);
546 seg->av.dqp_dct = htobe32(((uint32_t)ext << 31) | dqp_dct);
547 seg->av.stat_rate_sl = stat_rate_sl;
548 seg->av.fl_mlid = fl_mlid;
549 seg->av.rlid = htobe16(rlid);
550 memcpy(seg->av.rmac, rmac, 6);
551 seg->av.tclass = tclass;
552 seg->av.hop_limit = hop_limit;
553 seg->av.grh_gid_fl = htobe32(grh_gid_fi);
554 memcpy(seg->av.rgid, rgid, 16);
555 }
556
557 /*
558 * Data Segments - contain pointers and a byte count for the scatter/gather list.
559 * They can optionally contain data, which will save a memory read access for
560 * gather Work Requests.
561 */
562 static MLX5DV_ALWAYS_INLINE
mlx5dv_set_data_seg(struct mlx5_wqe_data_seg * seg,uint32_t length,uint32_t lkey,uintptr_t address)563 void mlx5dv_set_data_seg(struct mlx5_wqe_data_seg *seg,
564 uint32_t length, uint32_t lkey,
565 uintptr_t address)
566 {
567 seg->byte_count = htobe32(length);
568 seg->lkey = htobe32(lkey);
569 seg->addr = htobe64(address);
570 }
571 /*
572 * x86 optimized version of mlx5dv_set_data_seg()
573 *
574 * This is useful when doing calculations on large data sets
575 * for parallel calculations.
576 *
577 * It doesn't suit for serialized algorithms.
578 */
579 #if defined(__SSE3__)
580 static MLX5DV_ALWAYS_INLINE
mlx5dv_x86_set_data_seg(struct mlx5_wqe_data_seg * seg,uint32_t length,uint32_t lkey,uintptr_t address)581 void mlx5dv_x86_set_data_seg(struct mlx5_wqe_data_seg *seg,
582 uint32_t length, uint32_t lkey,
583 uintptr_t address)
584 {
585 __m128i val = _mm_set_epi32((uint32_t)address, (uint32_t)(address >> 32), lkey, length);
586 __m128i mask = _mm_set_epi8(12, 13, 14, 15, /* local address low */
587 8, 9, 10, 11, /* local address high */
588 4, 5, 6, 7, /* l_key */
589 0, 1, 2, 3 /* byte count */
590 );
591 *(__m128i *) seg = _mm_shuffle_epi8(val, mask);
592 }
593 #endif /* defined(__SSE3__) */
594
595 /*
596 * Eth Segment - contains packet headers and information for stateless L2, L3, L4 offloading.
597 *
598 * Output:
599 * seg - Eth segment to be filled.
600 * Input:
601 * cs_flags - l3cs/l3cs_inner/l4cs/l4cs_inner.
602 * mss - Maximum segment size. For TSO WQEs, the number of bytes
603 * in the TCP payload to be transmitted in each packet. Must
604 * be 0 on non TSO WQEs.
605 * inline_hdr_sz - Length of the inlined packet headers.
606 * inline_hdr_start - Inlined packet header.
607 */
608 static MLX5DV_ALWAYS_INLINE
mlx5dv_set_eth_seg(struct mlx5_wqe_eth_seg * seg,uint8_t cs_flags,uint16_t mss,uint16_t inline_hdr_sz,uint8_t * inline_hdr_start)609 void mlx5dv_set_eth_seg(struct mlx5_wqe_eth_seg *seg, uint8_t cs_flags,
610 uint16_t mss, uint16_t inline_hdr_sz,
611 uint8_t *inline_hdr_start)
612 {
613 seg->cs_flags = cs_flags;
614 seg->mss = htobe16(mss);
615 seg->inline_hdr_sz = htobe16(inline_hdr_sz);
616 memcpy(seg->inline_hdr_start, inline_hdr_start, inline_hdr_sz);
617 }
618 #endif /* _MLX5DV_H_ */
619