26 #define RDMA_TX_RETRIES 5 28 #define RDMA_TXQ_DV_DSEG_SZ(txq) (RDMA_MLX5_WQE_DS * RDMA_TXQ_DV_SQ_SZ(txq)) 29 #define RDMA_TXQ_DV_DSEG2WQE(d) (((d) + RDMA_MLX5_WQE_DS - 1) / RDMA_MLX5_WQE_DS) 46 struct mlx5_cqe64 *cqes = txq->
dv_cq_cqes, *cur = cqes + (idx & cq_mask);
52 op_own = *(
volatile u8 *) &cur->op_own;
53 if (((idx >> log2_cq_sz) & MLX5_CQE_OWNER_MASK) !=
54 (op_own & MLX5_CQE_OWNER_MASK) || (op_own >> 4) == MLX5_CQE_INVALID)
59 cur = cqes + (idx & cq_mask);
65 cur = cqes + ((idx - 1) & cq_mask);
72 wqe = txq->
dv_sq_wqes + (be16toh (cur->wqe_counter) & sq_mask);
91 const u16 tail,
u32 sq_mask)
93 last->
ctrl.imm = tail;
94 last->
ctrl.fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE;
135 wqe->
eseg.inline_hdr_sz = htobe16 (sz);
158 const u32 lkey = wqe[0].
dseg.lkey;
163 while (n >= 1 && wqe_n >= 1)
165 u32 *bufs = txq->
bufs + (tail & mask);
173 if (b[0]->
flags & VLIB_BUFFER_NEXT_PRESENT)
180 #define RDMA_MLX5_WQE_DS_MAX (1 << 5) 188 sizeof (
struct mlx5_wqe_data_seg) ==
189 MLX5_SEND_WQE_BB,
"wrong size");
197 while (chained_n < dseg_max
198 && chained_b->
flags & VLIB_BUFFER_NEXT_PRESENT)
200 struct mlx5_wqe_data_seg *dseg = (
void *) txq->
dv_sq_wqes;
211 chained_b->
flags &= ~(VLIB_BUFFER_NEXT_PRESENT |
212 VLIB_BUFFER_TOTAL_LENGTH_VALID);
226 if (chained_b->
flags & VLIB_BUFFER_NEXT_PRESENT)
236 dseg_max == chained_n ?
237 RDMA_TX_ERROR_SEGMENT_SIZE_EXCEEDED :
238 RDMA_TX_ERROR_NO_FREE_SLOTS, 1);
267 if (n == n_left_from)
271 return n_left_from - n;
278 const u32 n_left_from,
u32 * bi,
292 n_wrap = n_left_from - n;
302 n_left_from, n, bi, b, wqe,
327 n_left_from, n, bi, b, wqe,
358 struct ibv_wc wc[VLIB_FRAME_SIZE];
363 n = ibv_poll_cq (txq->
ibv_cq, VLIB_FRAME_SIZE, wc);
379 tail = wc[n - 1].wr_id;
392 struct ibv_send_wr wr[VLIB_FRAME_SIZE], *w = wr;
393 struct ibv_sge sge[VLIB_FRAME_SIZE], *s = sge;
401 s[0].lkey = rd->
lkey;
406 s[1].lkey = rd->
lkey;
411 s[2].lkey = rd->
lkey;
416 s[3].lkey = rd->
lkey;
419 w[0].next = &w[0] + 1;
420 w[0].sg_list = &s[0];
422 w[0].opcode = IBV_WR_SEND;
425 w[1].next = &w[1] + 1;
426 w[1].sg_list = &s[1];
428 w[1].opcode = IBV_WR_SEND;
431 w[2].next = &w[2] + 1;
432 w[2].sg_list = &s[2];
434 w[2].opcode = IBV_WR_SEND;
437 w[3].next = &w[3] + 1;
438 w[3].sg_list = &s[3];
440 w[3].opcode = IBV_WR_SEND;
452 s[0].lkey = rd->
lkey;
455 w[0].next = &w[0] + 1;
456 w[0].sg_list = &s[0];
458 w[0].opcode = IBV_WR_SEND;
466 w[-1].wr_id = txq->
tail;
468 w[-1].send_flags = IBV_SEND_SIGNALED;
474 n_left_from - (w - wr));
475 n_left_from = w - wr;
498 u32 n_left_from,
u32 * bi,
int is_mlx5dv)
512 n_left_from = is_mlx5dv ?
518 txq->
tail += n_left_from;
542 for (i = 0; i < RDMA_TX_RETRIES && n_left_from > 0; i++)
549 n_left_from -= n_enq;
559 RDMA_TX_ERROR_NO_FREE_SLOTS, n_left_from);
static_always_inline u32 rdma_device_output_tx_try(vlib_main_t *vm, const vlib_node_runtime_t *node, const rdma_device_t *rd, rdma_txq_t *txq, u32 n_left_from, u32 *bi, int is_mlx5dv)
u32 flags
buffer flags: VLIB_BUFFER_FREE_LIST_INDEX_MASK: bits used to store free list index, VLIB_BUFFER_IS_TRACED: trace this buffer.
volatile u32 * dv_sq_dbrec
struct mlx5_cqe64 * dv_cq_cqes
struct mlx5_wqe_data_seg dseg
static uword vlib_buffer_get_current_va(vlib_buffer_t *b)
rdma_mlx5_wqe_t * dv_sq_wqes
static void vlib_buffer_free(vlib_main_t *vm, u32 *buffers, u32 n_buffers)
Free buffers Frees the entire buffer chain for each buffer.
#define CLIB_COMPILER_BARRIER()
#define CLIB_MEMORY_STORE_BARRIER()
static void vlib_error_count(vlib_main_t *vm, uword node_index, uword counter, uword increment)
static_always_inline u32 rdma_device_output_tx_ibverb(vlib_main_t *vm, const vlib_node_runtime_t *node, const rdma_device_t *rd, rdma_txq_t *txq, u32 n_left_from, u32 *bi, vlib_buffer_t **b)
#define clib_memcpy_fast(a, b, c)
static_always_inline void clib_spinlock_unlock_if_init(clib_spinlock_t *p)
#define RDMA_TXQ_DV_INVALID_ID
u16 current_length
Nbytes between current data and the end of this buffer.
struct mlx5_wqe_ctrl_seg ctrl
static_always_inline void rdma_device_output_tx_mlx5_doorbell(rdma_txq_t *txq, rdma_mlx5_wqe_t *last, const u16 tail, u32 sq_mask)
volatile u32 * dv_cq_dbrec
static heap_elt_t * last(heap_header_t *h)
static void vlib_buffer_copy_indices_to_ring(u32 *ring, u32 *src, u32 start, u32 ring_size, u32 n_buffers)
#define RDMA_TXQ_DV_DSEG2WQE(d)
#define static_always_inline
static uword pow2_mask(uword x)
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
#define VNET_DEVICE_CLASS_TX_FN(devclass)
#define RDMA_TXQ_DV_SQ_SZ(txq)
struct mlx5_wqe_eth_seg eseg
static void vlib_buffer_free_from_ring(vlib_main_t *vm, u32 *ring, u32 start, u32 ring_size, u32 n_buffers)
Free buffers from ring.
#define RDMA_MLX5_WQE_DS_MAX
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
static void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
u32 node_index
Node index.
#define RDMA_TXQ_DV_DSEG_SZ(txq)
static_always_inline void rdma_device_output_free_ibverb(vlib_main_t *vm, const vlib_node_runtime_t *node, rdma_txq_t *txq)
VNET_DEVICE_CLASS_TX_FN() rdma_device_class(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
sll srl srl sll sra u16x4 i
static_always_inline void rdma_device_output_free(vlib_main_t *vm, const vlib_node_runtime_t *node, rdma_txq_t *txq, int is_mlx5dv)
static_always_inline u32 rdma_device_output_tx_mlx5_chained(vlib_main_t *vm, const vlib_node_runtime_t *node, const rdma_device_t *rd, rdma_txq_t *txq, u32 n_left_from, u32 n, u32 *bi, vlib_buffer_t **b, rdma_mlx5_wqe_t *wqe, u16 tail)
#define RDMA_TXQ_USED_SZ(head, tail)
static_always_inline void rdma_mlx5_wqe_init(rdma_mlx5_wqe_t *wqe, const void *tmpl, vlib_buffer_t *b, const u16 tail)
#define RDMA_TXQ_BUF_SZ(txq)
vlib_main_t vlib_node_runtime_t * node
#define RDMA_TXQ_AVAIL_SZ(txq, head, tail)
static_always_inline void rdma_device_output_free_mlx5(vlib_main_t *vm, const vlib_node_runtime_t *node, rdma_txq_t *txq)
static_always_inline void clib_memset_u8(void *p, u8 val, uword count)
static uword pointer_to_uword(const void *p)
static_always_inline void vlib_buffer_copy_indices(u32 *dst, u32 *src, u32 n_indices)
static_always_inline u32 rdma_device_output_tx_mlx5(vlib_main_t *vm, const vlib_node_runtime_t *node, const rdma_device_t *rd, rdma_txq_t *txq, const u32 n_left_from, u32 *bi, vlib_buffer_t **b)
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
u32 next_buffer
Next buffer for this linked-list of buffers.
#define STATIC_ASSERT(truth,...)
VLIB buffer representation.
static void * vlib_frame_vector_args(vlib_frame_t *f)
Get pointer to frame vector data.
static_always_inline uword rdma_device_output_tx(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame, rdma_device_t *rd, int is_mlx5dv)
#define STRUCT_SIZE_OF(t, f)
#define MLX5_ETH_L2_INLINE_HEADER_SIZE
vlib_main_t vlib_node_runtime_t vlib_frame_t * frame
static_always_inline void vlib_get_buffers(vlib_main_t *vm, u32 *bi, vlib_buffer_t **b, int count)
Translate array of buffer indices into buffer pointers.
static_always_inline void clib_spinlock_lock_if_init(clib_spinlock_t *p)
static vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.