-/*-
- * BSD LICENSE
- *
- * Copyright 2017 6WIND S.A.
- * Copyright 2017 Mellanox
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * * Neither the name of 6WIND S.A. nor the names of its
- * contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2017 6WIND S.A.
+ * Copyright 2017 Mellanox Technologies, Ltd
*/
/**
* giving a total of up to 256 entries.
*/
[0x00] = RTE_PTYPE_L2_ETHER,
- [0x01] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN,
+ [0x01] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
+ RTE_PTYPE_L4_NONFRAG,
[0x02] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
RTE_PTYPE_L4_FRAG,
[0x03] = RTE_PTYPE_L2_ETHER | RTE_PTYPE_L3_IPV4_EXT_UNKNOWN |
};
/**
- * Stamp a WQE so it won't be reused by the HW.
+ * Stamp TXBB burst so it won't be reused by the HW.
*
* Routine is used when freeing WQE used by the chip or when failing
* building an WQ entry has failed leaving partial information on the queue.
*
* @param sq
* Pointer to the SQ structure.
- * @param[in, out] wqe
- * Pointer of WQE address to stamp. This value is modified on return to
- * store the address of the next WQE.
+ * @param start
+ * Pointer to the first TXBB to stamp.
+ * @param end
+ * Pointer to the followed end TXBB to stamp.
*
* @return
- * WQE size.
+ * Stamping burst size in byte units.
*/
static uint32_t
-mlx4_txq_stamp_freed_wqe(struct mlx4_sq *sq, volatile uint32_t **wqe)
+mlx4_txq_stamp_freed_wqe(struct mlx4_sq *sq, volatile uint32_t *start,
+ volatile uint32_t *end)
{
uint32_t stamp = sq->stamp;
- volatile uint32_t *next_txbb = *wqe;
- /* Extract the size from the control segment of the WQE. */
- 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;
+ int32_t size = (intptr_t)end - (intptr_t)start;
- /* Optimize the common case when there is no wrap-around. */
- if ((uintptr_t)next_txbb + size < (uintptr_t)sq->eob) {
- /* Stamp the freed descriptor. */
- do {
- *next_txbb = stamp;
- next_txbb += MLX4_SQ_STAMP_DWORDS;
- size_cd -= MLX4_TXBB_SIZE;
- } while (size_cd);
- } else {
- /* Stamp the freed descriptor. */
+ assert(start != end);
+ /* Hold SQ ring wrap around. */
+ if (size < 0) {
+ size = (int32_t)sq->size + size;
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);
+ *start = stamp;
+ start += MLX4_SQ_STAMP_DWORDS;
+ } while (start != (volatile uint32_t *)sq->eob);
+ start = (volatile uint32_t *)sq->buf;
+ /* Flip invalid stamping ownership. */
+ stamp ^= RTE_BE32(0x1 << MLX4_SQ_OWNER_BIT);
+ sq->stamp = stamp;
+ if (start == end)
+ return size;
}
- *wqe = next_txbb;
- return size;
+ do {
+ *start = stamp;
+ start += MLX4_SQ_STAMP_DWORDS;
+ } while (start != end);
+ return (uint32_t)size;
}
/**
*
* @param txq
* Pointer to Tx queue structure.
+ * @param elts_m
+ * Tx elements number mask.
+ * @param sq
+ * Pointer to the SQ structure.
*/
static void
-mlx4_txq_complete(struct txq *txq, const unsigned int elts_n,
- struct mlx4_sq *sq)
+mlx4_txq_complete(struct txq *txq, const unsigned int elts_m,
+ struct mlx4_sq *sq)
{
unsigned int elts_tail = txq->elts_tail;
struct mlx4_cq *cq = &txq->mcq;
volatile struct mlx4_cqe *cqe;
+ uint32_t completed;
uint32_t cons_index = cq->cons_index;
- 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;
+ volatile uint32_t *first_txbb;
+
/*
* Traverse over all CQ entries reported and handle each WQ entry
* reported by them.
break;
}
#endif /* NDEBUG */
- /* 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. */
- first_wqe = next_wqe;
- sq->remain_size +=
- mlx4_txq_stamp_freed_wqe(sq, &next_wqe);
- pkts++;
- } while (first_wqe != last_wqe);
cons_index++;
} while (1);
- if (unlikely(pkts == 0))
+ completed = (cons_index - cq->cons_index) * txq->elts_comp_cd_init;
+ if (unlikely(!completed))
return;
+ /* First stamping address is the end of the last one. */
+ first_txbb = (&(*txq->elts)[elts_tail & elts_m])->eocb;
+ elts_tail += completed;
+ /* The new tail element holds the end address. */
+ sq->remain_size += mlx4_txq_stamp_freed_wqe(sq, first_txbb,
+ (&(*txq->elts)[elts_tail & elts_m])->eocb);
/* Update CQ consumer index. */
cq->cons_index = cons_index;
*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;
}
struct txq *txq = (struct txq *)dpdk_txq;
unsigned int elts_head = txq->elts_head;
const unsigned int elts_n = txq->elts_n;
+ const unsigned int elts_m = elts_n - 1;
unsigned int bytes_sent = 0;
unsigned int i;
- unsigned int max;
+ unsigned int max = elts_head - txq->elts_tail;
struct mlx4_sq *sq = &txq->msq;
volatile struct mlx4_wqe_ctrl_seg *ctrl;
struct txq_elt *elt;
assert(txq->elts_comp_cd != 0);
- if (likely(txq->elts_comp != 0))
- mlx4_txq_complete(txq, elts_n, sq);
- max = (elts_n - (elts_head - txq->elts_tail));
- if (max > elts_n)
- max -= elts_n;
+ if (likely(max >= txq->elts_comp_cd_init))
+ mlx4_txq_complete(txq, elts_m, sq);
+ max = elts_n - max;
assert(max >= 1);
assert(max <= elts_n);
/* Always leave one free entry in the ring. */
--max;
if (max > pkts_n)
max = pkts_n;
- elt = &(*txq->elts)[elts_head];
- /* Each element saves its appropriate work queue. */
+ elt = &(*txq->elts)[elts_head & elts_m];
+ /* First Tx burst element saves the next WQE control segment. */
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_next = &(*txq->elts)[++elts_head & elts_m];
uint32_t owner_opcode = sq->owner_opcode;
volatile struct mlx4_wqe_data_seg *dseg =
(volatile struct mlx4_wqe_data_seg *)(ctrl + 1);
* that no ICRC should be calculated.
*/
if (--txq->elts_comp_cd == 0) {
+ /* Save the completion burst end address. */
+ elt_next->eocb = (volatile uint32_t *)ctrl_next;
txq->elts_comp_cd = txq->elts_comp_cd_init;
srcrb.flags = RTE_BE32(MLX4_WQE_CTRL_SOLICIT |
MLX4_WQE_CTRL_CQ_UPDATE);
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))
return 0;
+ /* Save WQE address of the next Tx burst element. */
+ elt->wqe = ctrl;
/* Increment send statistics counters. */
txq->stats.opackets += i;
txq->stats.obytes += bytes_sent;
rte_wmb();
/* Ring QP doorbell. */
rte_write32(txq->msq.doorbell_qpn, txq->msq.db);
- txq->elts_head = elts_head;
- txq->elts_comp += i;
+ txq->elts_head += i;
return i;
}