From: Matan Azrad Date: Wed, 6 Dec 2017 17:57:53 +0000 (+0000) Subject: net/mlx4: merge Tx queue rings management X-Git-Tag: spdx-start~573 X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=78e81a9844f8;p=dpdk.git net/mlx4: merge Tx queue rings management 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 completed work queue entries. 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 Acked-by: Adrien Mazarguil --- diff --git a/drivers/net/mlx4/mlx4_prm.h b/drivers/net/mlx4/mlx4_prm.h index fcc7c129d1..217ea50913 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. */ + uint32_t remain_size; /**< Remaining WQE room in SQ (bytes). */ + uint32_t owner_opcode; + /**< Default owner opcode with HW valid owner bit. */ + 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 5b09949ab0..c10858774b 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,49 @@ uint32_t mlx4_ptype_table[0x100] __rte_cache_aligned = { * * @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[in, out] wqe + * Pointer of WQE address to stamp. This value is modified on return to + * store the address of the next WQE. * * @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 +320,22 @@ mlx4_txq_stamp_freed_wqe(struct mlx4_sq *sq, uint16_t index, uint8_t owner) * * @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 +345,11 @@ mlx4_txq_complete(struct txq *txq, const unsigned int elts_n, 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 +358,32 @@ mlx4_txq_complete(struct txq *txq, const unsigned int elts_n, " 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; } /** @@ -454,41 +437,40 @@ mlx4_fill_tx_data_seg(volatile struct mlx4_wqe_data_seg *dseg, dseg->byte_count = byte_count; } -static int +/** + * Write data segments of multi-segment packet. + * + * @param buf + * Pointer to the first packet mbuf. + * @param txq + * Pointer to Tx queue structure. + * @param ctrl + * Pointer to the WQE control segment. + * + * @return + * Pointer to the next WQE control segment on success, NULL otherwise. + */ +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) { - 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; + uint32_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((uint32_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, @@ -502,7 +484,7 @@ txbb_head_seg: 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 >= @@ -534,7 +516,7 @@ txbb_tail_segs: 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), @@ -550,7 +532,7 @@ txbb_tail_segs: 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), @@ -566,7 +548,7 @@ txbb_tail_segs: 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), @@ -590,9 +572,10 @@ txbb_tail_segs: 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); } /** @@ -618,7 +601,8 @@ mlx4_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 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)) @@ -632,20 +616,22 @@ mlx4_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) --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. */ @@ -654,7 +640,7 @@ mlx4_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) #ifndef NDEBUG /* Poisoning. */ - memset(elt, 0x66, sizeof(*elt)); + memset(&elt->buf, 0x66, sizeof(struct rte_mbuf *)); #endif /* Faster than rte_pktmbuf_free(). */ do { @@ -666,23 +652,11 @@ mlx4_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) } 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. */ @@ -691,23 +665,33 @@ mlx4_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) 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); @@ -753,13 +737,13 @@ mlx4_tx_burst(void *dpdk_txq, struct rte_mbuf **pkts, uint16_t pkts_n) * 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 463df2b0bf..d56e48d7a9 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 17f3b002c5..9d9bd246eb 100644 --- a/drivers/net/mlx4/mlx4_txq.c +++ b/drivers/net/mlx4/mlx4_txq.c @@ -83,6 +83,7 @@ mlx4_txq_free_elts(struct txq *txq) assert(elt->buf != NULL); rte_pktmbuf_free(elt->buf); elt->buf = NULL; + elt->wqe = NULL; if (++elts_tail == RTE_DIM(*elts)) elts_tail = 0; } @@ -162,20 +163,19 @@ mlx4_txq_fill_dv_obj_info(struct txq *txq, struct mlx4dv_obj *mlxdv) 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; @@ -361,6 +361,9 @@ mlx4_tx_queue_setup(struct rte_eth_dev *dev, uint16_t idx, uint16_t desc, 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);