On Tue, Nov 28, 2017 at 12:19:27PM +0000, Matan Azrad wrote: > The Tx queue send ring was managed by Tx block head,tail,count and mask > management variables which were used for managing the send queue remain > space and next places of empty or completted work queue entries.
completted => completed > > This method suffered from an actual addresses recalculation per packet, > an unnecessary Tx block based calculations and an expensive dual > management of Tx rings. > > Move send queue ring calculation to be based on actual addresses while > managing it by descriptors ring indexes. > > Add new work queue entry pointer to the descriptor element to hold the > appropriate entry in the send queue. > > Signed-off-by: Matan Azrad <ma...@mellanox.com> > --- > drivers/net/mlx4/mlx4_prm.h | 20 ++-- > drivers/net/mlx4/mlx4_rxtx.c | 241 > +++++++++++++++++++------------------------ > drivers/net/mlx4/mlx4_rxtx.h | 1 + > drivers/net/mlx4/mlx4_txq.c | 23 +++-- > 4 files changed, 126 insertions(+), 159 deletions(-) > > diff --git a/drivers/net/mlx4/mlx4_prm.h b/drivers/net/mlx4/mlx4_prm.h > index fcc7c12..2ca303a 100644 > --- a/drivers/net/mlx4/mlx4_prm.h > +++ b/drivers/net/mlx4/mlx4_prm.h > @@ -54,22 +54,18 @@ > > /* Typical TSO descriptor with 16 gather entries is 352 bytes. */ > #define MLX4_MAX_WQE_SIZE 512 > -#define MLX4_MAX_WQE_TXBBS (MLX4_MAX_WQE_SIZE / MLX4_TXBB_SIZE) > +#define MLX4_SEG_SHIFT 4 > > /* Send queue stamping/invalidating information. */ > #define MLX4_SQ_STAMP_STRIDE 64 > #define MLX4_SQ_STAMP_DWORDS (MLX4_SQ_STAMP_STRIDE / 4) > -#define MLX4_SQ_STAMP_SHIFT 31 > +#define MLX4_SQ_OWNER_BIT 31 > #define MLX4_SQ_STAMP_VAL 0x7fffffff > > /* Work queue element (WQE) flags. */ > -#define MLX4_BIT_WQE_OWN 0x80000000 > #define MLX4_WQE_CTRL_IIP_HDR_CSUM (1 << 28) > #define MLX4_WQE_CTRL_IL4_HDR_CSUM (1 << 27) > > -#define MLX4_SIZE_TO_TXBBS(size) \ > - (RTE_ALIGN((size), (MLX4_TXBB_SIZE)) >> (MLX4_TXBB_SHIFT)) > - > /* CQE checksum flags. */ > enum { > MLX4_CQE_L2_TUNNEL_IPV4 = (int)(1u << 25), > @@ -98,17 +94,15 @@ enum { > struct mlx4_sq { > volatile uint8_t *buf; /**< SQ buffer. */ > volatile uint8_t *eob; /**< End of SQ buffer */ > - uint32_t head; /**< SQ head counter in units of TXBBS. */ > - uint32_t tail; /**< SQ tail counter in units of TXBBS. */ > - uint32_t txbb_cnt; /**< Num of WQEBB in the Q (should be ^2). */ > - uint32_t txbb_cnt_mask; /**< txbbs_cnt mask (txbb_cnt is ^2). */ > - uint32_t headroom_txbbs; /**< Num of txbbs that should be kept free. */ > + uint32_t size; /**< SQ size includes headroom. */ > + int32_t remain_size; /**< Remain WQE size in SQ. */ Remain => Remaining? By "size", do you mean "room" as there could be several WQEs in there? Note before reviewing the rest of this patch, the fact it's a signed integer bothers me; it's probably a mistake. You should standardize on unsigned values everywhere. > + /**< Default owner opcode with HW valid owner bit. */ The "/**<" syntax requires the comment to come after the documented field. You should either move this line below "owner_opcode" or use "/**". > + uint32_t owner_opcode; > + uint32_t stamp; /**< Stamp value with an invalid HW owner bit. */ > volatile uint32_t *db; /**< Pointer to the doorbell. */ > uint32_t doorbell_qpn; /**< qp number to write to the doorbell. */ > }; > > -#define mlx4_get_send_wqe(sq, n) ((sq)->buf + ((n) * (MLX4_TXBB_SIZE))) > - > /* Completion queue events, numbers and masks. */ > #define MLX4_CQ_DB_GEQ_N_MASK 0x3 > #define MLX4_CQ_DOORBELL 0x20 > diff --git a/drivers/net/mlx4/mlx4_rxtx.c b/drivers/net/mlx4/mlx4_rxtx.c > index b9cb2fc..0a8ef93 100644 > --- a/drivers/net/mlx4/mlx4_rxtx.c > +++ b/drivers/net/mlx4/mlx4_rxtx.c > @@ -61,9 +61,6 @@ > #include "mlx4_rxtx.h" > #include "mlx4_utils.h" > > -#define WQE_ONE_DATA_SEG_SIZE \ > - (sizeof(struct mlx4_wqe_ctrl_seg) + sizeof(struct mlx4_wqe_data_seg)) > - > /** > * Pointer-value pair structure used in tx_post_send for saving the first > * DWORD (32 byte) of a TXBB. > @@ -268,52 +265,48 @@ struct pv { > * > * @param sq > * Pointer to the SQ structure. > - * @param index > - * Index of the freed WQE. > - * @param num_txbbs > - * Number of blocks to stamp. > - * If < 0 the routine will use the size written in the WQ entry. > - * @param owner > - * The value of the WQE owner bit to use in the stamp. > + * @param wqe > + * Pointer of WQE to stamp. Looks like it's not just a simple pointer to the WQE to stamp seeing this function also stores the address of the next WQE in the provided buffer (uint32_t **wqe). It's not documented as such. > * > * @return > - * The number of Tx basic blocs (TXBB) the WQE contained. > + * WQE size. > */ > -static int > -mlx4_txq_stamp_freed_wqe(struct mlx4_sq *sq, uint16_t index, uint8_t owner) > +static uint32_t > +mlx4_txq_stamp_freed_wqe(struct mlx4_sq *sq, volatile uint32_t **wqe) > { > - uint32_t stamp = rte_cpu_to_be_32(MLX4_SQ_STAMP_VAL | > - (!!owner << MLX4_SQ_STAMP_SHIFT)); > - volatile uint8_t *wqe = mlx4_get_send_wqe(sq, > - (index & sq->txbb_cnt_mask)); > - volatile uint32_t *ptr = (volatile uint32_t *)wqe; > - int i; > - int txbbs_size; > - int num_txbbs; > - > + uint32_t stamp = sq->stamp; > + volatile uint32_t *next_txbb = *wqe; > /* Extract the size from the control segment of the WQE. */ > - num_txbbs = MLX4_SIZE_TO_TXBBS((((volatile struct mlx4_wqe_ctrl_seg *) > - wqe)->fence_size & 0x3f) << 4); > - txbbs_size = num_txbbs * MLX4_TXBB_SIZE; > + uint32_t size = RTE_ALIGN((uint32_t) > + ((((volatile struct mlx4_wqe_ctrl_seg *) > + next_txbb)->fence_size & 0x3f) << 4), > + MLX4_TXBB_SIZE); > + uint32_t size_cd = size; > + > /* Optimize the common case when there is no wrap-around. */ > - if (wqe + txbbs_size <= sq->eob) { > + if ((uintptr_t)next_txbb + size < (uintptr_t)sq->eob) { > /* Stamp the freed descriptor. */ > - for (i = 0; i < txbbs_size; i += MLX4_SQ_STAMP_STRIDE) { > - *ptr = stamp; > - ptr += MLX4_SQ_STAMP_DWORDS; > - } > + do { > + *next_txbb = stamp; > + next_txbb += MLX4_SQ_STAMP_DWORDS; > + size_cd -= MLX4_TXBB_SIZE; > + } while (size_cd); > } else { > /* Stamp the freed descriptor. */ > - for (i = 0; i < txbbs_size; i += MLX4_SQ_STAMP_STRIDE) { > - *ptr = stamp; > - ptr += MLX4_SQ_STAMP_DWORDS; > - if ((volatile uint8_t *)ptr >= sq->eob) { > - ptr = (volatile uint32_t *)sq->buf; > - stamp ^= RTE_BE32(0x80000000); > + do { > + *next_txbb = stamp; > + next_txbb += MLX4_SQ_STAMP_DWORDS; > + if ((volatile uint8_t *)next_txbb >= sq->eob) { > + next_txbb = (volatile uint32_t *)sq->buf; > + /* Flip invalid stamping ownership. */ > + stamp ^= RTE_BE32(0x1 << MLX4_SQ_OWNER_BIT); > + sq->stamp = stamp; > } > - } > + size_cd -= MLX4_TXBB_SIZE; > + } while (size_cd); > } > - return num_txbbs; > + *wqe = next_txbb; > + return size; > } > > /** > @@ -326,24 +319,22 @@ struct pv { > * > * @param txq > * Pointer to Tx queue structure. > - * > - * @return > - * 0 on success, -1 on failure. > */ > -static int > +static void > mlx4_txq_complete(struct txq *txq, const unsigned int elts_n, > struct mlx4_sq *sq) > { > - unsigned int elts_comp = txq->elts_comp; > unsigned int elts_tail = txq->elts_tail; > - unsigned int sq_tail = sq->tail; > struct mlx4_cq *cq = &txq->mcq; > volatile struct mlx4_cqe *cqe; > uint32_t cons_index = cq->cons_index; > - uint16_t new_index; > - uint16_t nr_txbbs = 0; > - int pkts = 0; > - > + volatile uint32_t *first_wqe; > + volatile uint32_t *next_wqe = (volatile uint32_t *) > + ((&(*txq->elts)[elts_tail])->wqe); > + volatile uint32_t *last_wqe; > + uint16_t mask = (((uintptr_t)sq->eob - (uintptr_t)sq->buf) >> > + MLX4_TXBB_SHIFT) - 1; > + uint32_t pkts = 0; > /* > * Traverse over all CQ entries reported and handle each WQ entry > * reported by them. > @@ -353,11 +344,11 @@ struct pv { > if (unlikely(!!(cqe->owner_sr_opcode & MLX4_CQE_OWNER_MASK) ^ > !!(cons_index & cq->cqe_cnt))) > break; > +#ifndef NDEBUG > /* > * Make sure we read the CQE after we read the ownership bit. > */ > rte_io_rmb(); > -#ifndef NDEBUG > if (unlikely((cqe->owner_sr_opcode & MLX4_CQE_OPCODE_MASK) == > MLX4_CQE_OPCODE_ERROR)) { > volatile struct mlx4_err_cqe *cqe_err = > @@ -366,41 +357,32 @@ struct pv { > " syndrome: 0x%x\n", > (void *)txq, cqe_err->vendor_err, > cqe_err->syndrome); > + break; > } > #endif /* NDEBUG */ > - /* Get WQE index reported in the CQE. */ > - new_index = > - rte_be_to_cpu_16(cqe->wqe_index) & sq->txbb_cnt_mask; > + /* Get WQE address buy index from the CQE. */ > + last_wqe = (volatile uint32_t *)((uintptr_t)sq->buf + > + ((rte_be_to_cpu_16(cqe->wqe_index) & mask) << > + MLX4_TXBB_SHIFT)); > do { > /* Free next descriptor. */ > - sq_tail += nr_txbbs; > - nr_txbbs = > - mlx4_txq_stamp_freed_wqe(sq, > - sq_tail & sq->txbb_cnt_mask, > - !!(sq_tail & sq->txbb_cnt)); > + first_wqe = next_wqe; > + sq->remain_size += > + mlx4_txq_stamp_freed_wqe(sq, &next_wqe); > pkts++; > - } while ((sq_tail & sq->txbb_cnt_mask) != new_index); > + } while (first_wqe != last_wqe); > cons_index++; > } while (1); > if (unlikely(pkts == 0)) > - return 0; > - /* Update CQ. */ > + return; > + /* Update CQ consumer index. */ > cq->cons_index = cons_index; > - *cq->set_ci_db = rte_cpu_to_be_32(cq->cons_index & MLX4_CQ_DB_CI_MASK); > - sq->tail = sq_tail + nr_txbbs; > - /* Update the list of packets posted for transmission. */ > - elts_comp -= pkts; > - assert(elts_comp <= txq->elts_comp); > - /* > - * Assume completion status is successful as nothing can be done about > - * it anyway. > - */ > + *cq->set_ci_db = rte_cpu_to_be_32(cons_index & MLX4_CQ_DB_CI_MASK); > + txq->elts_comp -= pkts; > elts_tail += pkts; > if (elts_tail >= elts_n) > elts_tail -= elts_n; > txq->elts_tail = elts_tail; > - txq->elts_comp = elts_comp; > - return 0; > } > > /** > @@ -421,41 +403,27 @@ struct pv { > return buf->pool; > } > > -static int > +static volatile struct mlx4_wqe_ctrl_seg * > mlx4_tx_burst_segs(struct rte_mbuf *buf, struct txq *txq, > - volatile struct mlx4_wqe_ctrl_seg **pctrl) > + volatile struct mlx4_wqe_ctrl_seg *ctrl) Can you use this opportunity to document this function? > { > - int wqe_real_size; > - int nr_txbbs; > struct pv *pv = (struct pv *)txq->bounce_buf; > struct mlx4_sq *sq = &txq->msq; > - uint32_t head_idx = sq->head & sq->txbb_cnt_mask; > - volatile struct mlx4_wqe_ctrl_seg *ctrl; > - volatile struct mlx4_wqe_data_seg *dseg; > struct rte_mbuf *sbuf = buf; > uint32_t lkey; > int pv_counter = 0; > int nb_segs = buf->nb_segs; > + int32_t wqe_size; > + volatile struct mlx4_wqe_data_seg *dseg = > + (volatile struct mlx4_wqe_data_seg *)(ctrl + 1); > > - /* Calculate the needed work queue entry size for this packet. */ > - wqe_real_size = sizeof(volatile struct mlx4_wqe_ctrl_seg) + > - nb_segs * sizeof(volatile struct mlx4_wqe_data_seg); > - nr_txbbs = MLX4_SIZE_TO_TXBBS(wqe_real_size); > - /* > - * Check that there is room for this WQE in the send queue and that > - * the WQE size is legal. > - */ > - if (((sq->head - sq->tail) + nr_txbbs + > - sq->headroom_txbbs) >= sq->txbb_cnt || > - nr_txbbs > MLX4_MAX_WQE_TXBBS) { > - return -1; > - } > - /* Get the control and data entries of the WQE. */ > - ctrl = (volatile struct mlx4_wqe_ctrl_seg *) > - mlx4_get_send_wqe(sq, head_idx); > - dseg = (volatile struct mlx4_wqe_data_seg *) > - ((uintptr_t)ctrl + sizeof(struct mlx4_wqe_ctrl_seg)); > - *pctrl = ctrl; > + ctrl->fence_size = 1 + nb_segs; > + wqe_size = RTE_ALIGN((int32_t)(ctrl->fence_size << MLX4_SEG_SHIFT), > + MLX4_TXBB_SIZE); > + /* Validate WQE size and WQE space in the send queue. */ > + if (sq->remain_size < wqe_size || > + wqe_size > MLX4_MAX_WQE_SIZE) > + return NULL; > /* > * Fill the data segments with buffer information. > * First WQE TXBB head segment is always control segment, > @@ -469,7 +437,7 @@ struct pv { > if (unlikely(lkey == (uint32_t)-1)) { > DEBUG("%p: unable to get MP <-> MR association", > (void *)txq); > - return -1; > + return NULL; > } > /* Handle WQE wraparound. */ > if (dseg >= > @@ -501,7 +469,7 @@ struct pv { > if (unlikely(lkey == (uint32_t)-1)) { > DEBUG("%p: unable to get MP <-> MR association", > (void *)txq); > - return -1; > + return NULL; > } > mlx4_fill_tx_data_seg(dseg, lkey, > rte_pktmbuf_mtod(sbuf, uintptr_t), > @@ -517,7 +485,7 @@ struct pv { > if (unlikely(lkey == (uint32_t)-1)) { > DEBUG("%p: unable to get MP <-> MR association", > (void *)txq); > - return -1; > + return NULL; > } > mlx4_fill_tx_data_seg(dseg, lkey, > rte_pktmbuf_mtod(sbuf, uintptr_t), > @@ -533,7 +501,7 @@ struct pv { > if (unlikely(lkey == (uint32_t)-1)) { > DEBUG("%p: unable to get MP <-> MR association", > (void *)txq); > - return -1; > + return NULL; > } > mlx4_fill_tx_data_seg(dseg, lkey, > rte_pktmbuf_mtod(sbuf, uintptr_t), > @@ -557,9 +525,10 @@ struct pv { > for (--pv_counter; pv_counter >= 0; pv_counter--) > pv[pv_counter].dseg->byte_count = pv[pv_counter].val; > } > - /* Fill the control parameters for this packet. */ > - ctrl->fence_size = (wqe_real_size >> 4) & 0x3f; > - return nr_txbbs; > + sq->remain_size -= wqe_size; > + /* Align next WQE address to the next TXBB. */ > + return (volatile struct mlx4_wqe_ctrl_seg *) > + ((volatile uint8_t *)ctrl + wqe_size); > } > > /** > @@ -585,7 +554,8 @@ struct pv { > unsigned int i; > unsigned int max; > struct mlx4_sq *sq = &txq->msq; > - int nr_txbbs; > + volatile struct mlx4_wqe_ctrl_seg *ctrl; > + struct txq_elt *elt; > > assert(txq->elts_comp_cd != 0); > if (likely(txq->elts_comp != 0)) > @@ -599,29 +569,30 @@ struct pv { > --max; > if (max > pkts_n) > max = pkts_n; > + elt = &(*txq->elts)[elts_head]; > + /* Each element saves its appropriate work queue. */ > + ctrl = elt->wqe; > for (i = 0; (i != max); ++i) { > struct rte_mbuf *buf = pkts[i]; > unsigned int elts_head_next = > (((elts_head + 1) == elts_n) ? 0 : elts_head + 1); > struct txq_elt *elt_next = &(*txq->elts)[elts_head_next]; > - struct txq_elt *elt = &(*txq->elts)[elts_head]; > - uint32_t owner_opcode = MLX4_OPCODE_SEND; > - volatile struct mlx4_wqe_ctrl_seg *ctrl; > - volatile struct mlx4_wqe_data_seg *dseg; > + uint32_t owner_opcode = sq->owner_opcode; > + volatile struct mlx4_wqe_data_seg *dseg = > + (volatile struct mlx4_wqe_data_seg *)(ctrl + 1); > + volatile struct mlx4_wqe_ctrl_seg *ctrl_next; > union { > uint32_t flags; > uint16_t flags16[2]; > } srcrb; > - uint32_t head_idx = sq->head & sq->txbb_cnt_mask; > uint32_t lkey; > > /* Clean up old buffer. */ > if (likely(elt->buf != NULL)) { > struct rte_mbuf *tmp = elt->buf; > - Empty line following variable declarations should stay. > #ifndef NDEBUG > /* Poisoning. */ > - memset(elt, 0x66, sizeof(*elt)); > + elt->buf = (struct rte_mbuf *)0x6666666666666666; Note this address depends on pointer size, which may in turn trigger a compilation warning/error. Keep memset() on elt->buf. > #endif > /* Faster than rte_pktmbuf_free(). */ > do { > @@ -633,23 +604,11 @@ struct pv { > } > RTE_MBUF_PREFETCH_TO_FREE(elt_next->buf); > if (buf->nb_segs == 1) { > - /* > - * Check that there is room for this WQE in the send > - * queue and that the WQE size is legal > - */ > - if (((sq->head - sq->tail) + 1 + sq->headroom_txbbs) >= > - sq->txbb_cnt || 1 > MLX4_MAX_WQE_TXBBS) { > + /* Validate WQE space in the send queue. */ > + if (sq->remain_size < MLX4_TXBB_SIZE) { > elt->buf = NULL; > break; > } > - /* Get the control and data entries of the WQE. */ > - ctrl = (volatile struct mlx4_wqe_ctrl_seg *) > - mlx4_get_send_wqe(sq, head_idx); > - dseg = (volatile struct mlx4_wqe_data_seg *) > - ((uintptr_t)ctrl + > - sizeof(struct mlx4_wqe_ctrl_seg)); > - > - ctrl->fence_size = (WQE_ONE_DATA_SEG_SIZE >> 4) & 0x3f; > lkey = mlx4_txq_mp2mr(txq, mlx4_txq_mb2mp(buf)); > if (unlikely(lkey == (uint32_t)-1)) { > /* MR does not exist. */ > @@ -658,23 +617,33 @@ struct pv { > elt->buf = NULL; > break; > } > - mlx4_fill_tx_data_seg(dseg, lkey, > + mlx4_fill_tx_data_seg(dseg++, lkey, > rte_pktmbuf_mtod(buf, uintptr_t), > rte_cpu_to_be_32(buf->data_len)); > - nr_txbbs = 1; > + /* Set WQE size in 16-byte units. */ > + ctrl->fence_size = 0x2; > + sq->remain_size -= MLX4_TXBB_SIZE; > + /* Align next WQE address to the next TXBB. */ > + ctrl_next = ctrl + 0x4; > } else { > - nr_txbbs = mlx4_tx_burst_segs(buf, txq, &ctrl); > - if (nr_txbbs < 0) { > + ctrl_next = mlx4_tx_burst_segs(buf, txq, ctrl); > + if (!ctrl_next) { > elt->buf = NULL; > break; > } > } > + /* Hold SQ ring wrap around. */ > + if ((volatile uint8_t *)ctrl_next >= sq->eob) { > + ctrl_next = (volatile struct mlx4_wqe_ctrl_seg *) > + ((volatile uint8_t *)ctrl_next - sq->size); > + /* Flip HW valid ownership. */ > + sq->owner_opcode ^= 0x1 << MLX4_SQ_OWNER_BIT; > + } > /* > * For raw Ethernet, the SOLICIT flag is used to indicate > * that no ICRC should be calculated. > */ > - txq->elts_comp_cd -= nr_txbbs; > - if (unlikely(txq->elts_comp_cd <= 0)) { > + if (--txq->elts_comp_cd == 0) { > txq->elts_comp_cd = txq->elts_comp_cd_init; > srcrb.flags = RTE_BE32(MLX4_WQE_CTRL_SOLICIT | > MLX4_WQE_CTRL_CQ_UPDATE); > @@ -720,13 +689,13 @@ struct pv { > * executing as soon as we do). > */ > rte_io_wmb(); > - ctrl->owner_opcode = rte_cpu_to_be_32(owner_opcode | > - ((sq->head & sq->txbb_cnt) ? > - MLX4_BIT_WQE_OWN : 0)); > - sq->head += nr_txbbs; > + ctrl->owner_opcode = rte_cpu_to_be_32(owner_opcode); > elt->buf = buf; > bytes_sent += buf->pkt_len; > elts_head = elts_head_next; > + elt_next->wqe = ctrl_next; > + ctrl = ctrl_next; > + elt = elt_next; > } > /* Take a shortcut if nothing must be sent. */ > if (unlikely(i == 0)) > diff --git a/drivers/net/mlx4/mlx4_rxtx.h b/drivers/net/mlx4/mlx4_rxtx.h > index 8207232..c092afa 100644 > --- a/drivers/net/mlx4/mlx4_rxtx.h > +++ b/drivers/net/mlx4/mlx4_rxtx.h > @@ -105,6 +105,7 @@ struct mlx4_rss { > /** Tx element. */ > struct txq_elt { > struct rte_mbuf *buf; /**< Buffer. */ > + volatile struct mlx4_wqe_ctrl_seg *wqe; /**< SQ WQE. */ > }; > > /** Rx queue counters. */ > diff --git a/drivers/net/mlx4/mlx4_txq.c b/drivers/net/mlx4/mlx4_txq.c > index 7882a4d..4c7b62a 100644 > --- a/drivers/net/mlx4/mlx4_txq.c > +++ b/drivers/net/mlx4/mlx4_txq.c > @@ -84,6 +84,7 @@ > assert(elt->buf != NULL); > rte_pktmbuf_free(elt->buf); > elt->buf = NULL; > + elt->wqe = NULL; > if (++elts_tail == RTE_DIM(*elts)) > elts_tail = 0; > } > @@ -163,20 +164,19 @@ struct txq_mp2mr_mbuf_check_data { > struct mlx4_cq *cq = &txq->mcq; > struct mlx4dv_qp *dqp = mlxdv->qp.out; > struct mlx4dv_cq *dcq = mlxdv->cq.out; > - uint32_t sq_size = (uint32_t)dqp->rq.offset - (uint32_t)dqp->sq.offset; > > - sq->buf = (uint8_t *)dqp->buf.buf + dqp->sq.offset; > /* Total length, including headroom and spare WQEs. */ > - sq->eob = sq->buf + sq_size; > - sq->head = 0; > - sq->tail = 0; > - sq->txbb_cnt = > - (dqp->sq.wqe_cnt << dqp->sq.wqe_shift) >> MLX4_TXBB_SHIFT; > - sq->txbb_cnt_mask = sq->txbb_cnt - 1; > + sq->size = (uint32_t)dqp->rq.offset - (uint32_t)dqp->sq.offset; > + sq->buf = (uint8_t *)dqp->buf.buf + dqp->sq.offset; > + sq->eob = sq->buf + sq->size; > + uint32_t headroom_size = 2048 + (1 << dqp->sq.wqe_shift); > + /* Continuous headroom size bytes must always stay freed. */ > + sq->remain_size = sq->size - headroom_size; > + sq->owner_opcode = MLX4_OPCODE_SEND | (0 << MLX4_SQ_OWNER_BIT); > + sq->stamp = rte_cpu_to_be_32(MLX4_SQ_STAMP_VAL | > + (0 << MLX4_SQ_OWNER_BIT)); > sq->db = dqp->sdb; > sq->doorbell_qpn = dqp->doorbell_qpn; > - sq->headroom_txbbs = > - (2048 + (1 << dqp->sq.wqe_shift)) >> MLX4_TXBB_SHIFT; > cq->buf = dcq->buf.buf; > cq->cqe_cnt = dcq->cqe_cnt; > cq->set_ci_db = dcq->set_ci_db; > @@ -362,6 +362,9 @@ struct txq_mp2mr_mbuf_check_data { > goto error; > } > mlx4_txq_fill_dv_obj_info(txq, &mlxdv); > + /* Save first wqe pointer in the first element. */ > + (&(*txq->elts)[0])->wqe = > + (volatile struct mlx4_wqe_ctrl_seg *)txq->msq.buf; > /* Pre-register known mempools. */ > rte_mempool_walk(mlx4_txq_mp2mr_iter, txq); > DEBUG("%p: adding Tx queue %p to list", (void *)dev, (void *)txq); > -- > 1.8.3.1 > Otherwise this patch looks OK. -- Adrien Mazarguil 6WIND