/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright 2018-2019 NXP
+ * Copyright 2018-2020 NXP
*/
#include <stdbool.h>
{
int tx_frm_cnt = 0;
struct enetc_swbd *tx_swbd;
- int i;
+ int i, hwci;
+
+ /* we don't need barriers here, we just want a relatively current value
+ * from HW.
+ */
+ hwci = (int)(rte_read32_relaxed(tx_ring->tcisr) &
+ ENETC_TBCISR_IDX_MASK);
i = tx_ring->next_to_clean;
tx_swbd = &tx_ring->q_swbd[i];
- while ((int)(enetc_rd_reg(tx_ring->tcisr) &
- ENETC_TBCISR_IDX_MASK) != i) {
+
+ /* we're only reading the CI index once here, which means HW may update
+ * it while we're doing clean-up. We could read the register in a loop
+ * but for now I assume it's OK to leave a few Tx frames for next call.
+ * The issue with reading the register in a loop is that we're stalling
+ * here trying to catch up with HW which keeps sending traffic as long
+ * as it has traffic to send, so in effect we could be waiting here for
+ * the Tx ring to be drained by HW, instead of us doing Rx in that
+ * meantime.
+ */
+ while (i != hwci) {
rte_pktmbuf_free(tx_swbd->buffer_addr);
tx_swbd->buffer_addr = NULL;
tx_swbd++;
uint16_t nb_pkts)
{
struct enetc_swbd *tx_swbd;
- int i, start;
+ int i, start, bds_to_use;
struct enetc_tx_bd *txbd;
struct enetc_bdr *tx_ring = (struct enetc_bdr *)tx_queue;
i = tx_ring->next_to_use;
+
+ bds_to_use = enetc_bd_unused(tx_ring);
+ if (bds_to_use < nb_pkts)
+ nb_pkts = bds_to_use;
+
start = 0;
while (nb_pkts--) {
enetc_clean_tx_ring(tx_ring);