From: Jun Yang <[email protected]>

Each DQRR entry consumed by the software portal costs a write to the
cache-invalidate DCAP register. The DCAP register also supports a vector
mode where a bitmap of DQRR indices is consumed with a single write, so
accumulate the indices and flush the vector once half the ring is
pending. A smaller threshold gives little benefit, and a threshold close
to the ring size starves WRIOP of DQRR space.

Because entries are now released in batches, a caller that stops polling
a portal must flush the pending vector explicitly. Pass a NULL dequeue
result to qbman_swp_dqrr_consume() to do that when the eventdev dequeue
finds the portal dry, when the net PMD finishes draining a portal, and
when a portal is released back to the bus.

Signed-off-by: Jun Yang <[email protected]>
---
 drivers/bus/fslmc/portal/dpaa2_hw_dpio.c      |  4 ++
 .../fslmc/qbman/include/fsl_qbman_portal.h    |  5 +-
 drivers/bus/fslmc/qbman/qbman_portal.c        | 63 +++++++++++++++++--
 drivers/bus/fslmc/qbman/qbman_portal.h        | 11 +++-
 drivers/event/dpaa2/dpaa2_eventdev.c          |  4 ++
 drivers/net/dpaa2/dpaa2_ethdev.c              |  2 +
 6 files changed, 81 insertions(+), 8 deletions(-)

diff --git a/drivers/bus/fslmc/portal/dpaa2_hw_dpio.c 
b/drivers/bus/fslmc/portal/dpaa2_hw_dpio.c
index 20d1bb2a66..cfd9548fb0 100644
--- a/drivers/bus/fslmc/portal/dpaa2_hw_dpio.c
+++ b/drivers/bus/fslmc/portal/dpaa2_hw_dpio.c
@@ -305,6 +305,10 @@ dpaa2_configure_stashing(struct dpaa2_dpio_dev *dpio_dev, 
int cpu_id, bool ethrx
 static void dpaa2_put_qbman_swp(struct dpaa2_dpio_dev *dpio_dev)
 {
        if (dpio_dev) {
+               /* consume indices may still be pending in the portal's DQRR
+                * consume vector; flush them before the portal is released.
+                */
+               qbman_swp_dqrr_consume(dpio_dev->sw_portal, NULL);
                /* rx-queue interrupts (net PMD) can arm a portal without the
                 * event driver; tear it down unconditionally. Safe when never
                 * armed: intr_deinit returns early if intr is not enabled.
diff --git a/drivers/bus/fslmc/qbman/include/fsl_qbman_portal.h 
b/drivers/bus/fslmc/qbman/include/fsl_qbman_portal.h
index b9e7789766..73e57bcdc1 100644
--- a/drivers/bus/fslmc/qbman/include/fsl_qbman_portal.h
+++ b/drivers/bus/fslmc/qbman/include/fsl_qbman_portal.h
@@ -451,7 +451,10 @@ void qbman_swp_prefetch_dqrr_next(struct qbman_swp *s);
  * qbman_swp_dqrr_consume() -  Consume DQRR entries previously returned from
  * qbman_swp_dqrr_next().
  * @s: the software portal object.
- * @dq: the DQRR entry to be consumed.
+ * @dq: the DQRR entry to be consumed, NULL to consume the entries accumulated
+ * so far. Entries are accumulated and consumed in batches, so a caller which
+ * stops polling the portal must call this with a NULL dq to release the
+ * entries it has already processed.
  */
 __rte_internal
 void qbman_swp_dqrr_consume(struct qbman_swp *s, const struct qbman_result 
*dq);
diff --git a/drivers/bus/fslmc/qbman/qbman_portal.c 
b/drivers/bus/fslmc/qbman/qbman_portal.c
index c93bec5dd3..c95c62baa7 100644
--- a/drivers/bus/fslmc/qbman/qbman_portal.c
+++ b/drivers/bus/fslmc/qbman/qbman_portal.c
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
- * Copyright 2018-2020,2023-2024 NXP
+ * Copyright 2018-2020,2023-2024,2026 NXP
  *
  */
 
@@ -9,13 +9,20 @@
 #include "qbman_portal.h"
 
 #include <eal_export.h>
+#include <rte_bitops.h>
 
 /* QBMan portal management command codes */
 #define QBMAN_MC_ACQUIRE       0x30
 #define QBMAN_WQCHAN_CONFIGURE 0x46
 
 /* Reverse mapping of QBMAN_CENA_SWP_DQRR() */
-#define QBMAN_IDX_FROM_DQRR(p) (((unsigned long)p & 0x1ff) >> 6)
+#define QBMAN_IDX_FROM_DQRR(p) (((unsigned long)(p) & 0x1ff) >> 6)
+
+/* DCAP consume-index-vector mode: the vector of DQRR indices to consume starts
+ * at bit 16 of DCAP and bit 8 selects vector mode over single-index mode.
+ */
+#define DQRR_DCAP_CI_VEC_OFFSET 16
+#define DQRR_DCAP_CI_VEC_SELECT 0x100
 
 /* QBMan FQ management command codes */
 #define QBMAN_FQ_SCHEDULE      0x48
@@ -284,6 +291,13 @@ struct qbman_swp *qbman_swp_init(const struct 
qbman_swp_desc *d)
                p->dqrr.dqrr_size = 8;
                p->dqrr.reset_bug = 0;
        }
+       /* Consume DQRR entries in vector mode by default and flush the vector
+        * once half the ring is pending. A smaller threshold gives little
+        * benefit; a threshold close to the ring size starves WRIOP of DQRR
+        * space and slows its enqueues down.
+        */
+       p->dqrr.ci_vec_en = true;
+       p->dqrr.ci_flush_th = p->dqrr.dqrr_size / 2;
 
        ret = qbman_swp_sys_init(&p->sys, d, p->dqrr.dqrr_size);
        if (ret) {
@@ -2225,13 +2239,47 @@ const struct qbman_result 
*qbman_swp_dqrr_next_mem_back(struct qbman_swp *s)
        return p;
 }
 
-/* Consume DQRR entries previously returned from qbman_swp_dqrr_next(). */
+/* Write the pending consume vector to DCAP if it holds at least "threshold"
+ * indices, consuming all of them with a single register access.
+ */
+static inline void
+qbman_swp_dqrr_vec_flush(struct qbman_swp *s, uint8_t threshold)
+{
+       if (s->dqrr.ci_count < threshold)
+               return;
+
+       qbman_cinh_write(&s->sys, QBMAN_CINH_SWP_DCAP,
+                        s->dqrr.ci_vector | DQRR_DCAP_CI_VEC_SELECT);
+       s->dqrr.ci_vector = 0;
+       s->dqrr.ci_count = 0;
+}
+
+/* Add a DQRR index to the pending consume vector, flushing it once the
+ * configured threshold is reached.
+ */
+static inline void
+qbman_swp_dqrr_vec_consume(struct qbman_swp *s, uint8_t idx)
+{
+       s->dqrr.ci_vector |= RTE_BIT32(idx + DQRR_DCAP_CI_VEC_OFFSET);
+       s->dqrr.ci_count++;
+       qbman_swp_dqrr_vec_flush(s, s->dqrr.ci_flush_th);
+}
+
+/* Consume DQRR entries previously returned from qbman_swp_dqrr_next().
+ * A NULL dq flushes any indices still pending in the consume vector, which
+ * the caller must do before it stops polling the portal.
+ */
 RTE_EXPORT_INTERNAL_SYMBOL(qbman_swp_dqrr_consume)
 void qbman_swp_dqrr_consume(struct qbman_swp *s,
                            const struct qbman_result *dq)
 {
-       qbman_cinh_write(&s->sys,
-                       QBMAN_CINH_SWP_DCAP, QBMAN_IDX_FROM_DQRR(dq));
+       if (unlikely(dq == NULL))
+               qbman_swp_dqrr_vec_flush(s, 1);
+       else if (s->dqrr.ci_vec_en)
+               qbman_swp_dqrr_vec_consume(s, QBMAN_IDX_FROM_DQRR(dq));
+       else
+               qbman_cinh_write(&s->sys, QBMAN_CINH_SWP_DCAP,
+                                QBMAN_IDX_FROM_DQRR(dq));
 }
 
 /* Consume DQRR entries previously returned from qbman_swp_dqrr_next(). */
@@ -2239,7 +2287,10 @@ RTE_EXPORT_INTERNAL_SYMBOL(qbman_swp_dqrr_idx_consume)
 void qbman_swp_dqrr_idx_consume(struct qbman_swp *s,
                            uint8_t dqrr_index)
 {
-       qbman_cinh_write(&s->sys, QBMAN_CINH_SWP_DCAP, dqrr_index);
+       if (s->dqrr.ci_vec_en)
+               qbman_swp_dqrr_vec_consume(s, dqrr_index);
+       else
+               qbman_cinh_write(&s->sys, QBMAN_CINH_SWP_DCAP, dqrr_index);
 }
 
 /*********************************/
diff --git a/drivers/bus/fslmc/qbman/qbman_portal.h 
b/drivers/bus/fslmc/qbman/qbman_portal.h
index 1cf7918309..db74db5fe1 100644
--- a/drivers/bus/fslmc/qbman/qbman_portal.h
+++ b/drivers/bus/fslmc/qbman/qbman_portal.h
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: BSD-3-Clause
  *
  * Copyright (C) 2014-2016 Freescale Semiconductor, Inc.
- * Copyright 2018-2020 NXP
+ * Copyright 2018-2020, 2026 NXP
  *
  */
 
@@ -93,6 +93,15 @@ struct qbman_swp {
                uint32_t valid_bit;
                uint8_t dqrr_size;
                int reset_bug;
+               /* Consume index vector: instead of writing DCAP once per
+                * consumed entry, the indices are accumulated in ci_vector
+                * and written with a single DCAP access once ci_count
+                * reaches ci_flush_th.
+                */
+               bool ci_vec_en;
+               uint8_t ci_count;
+               uint8_t ci_flush_th;
+               uint32_t ci_vector;
        } dqrr;
        struct {
                uint32_t pi;
diff --git a/drivers/event/dpaa2/dpaa2_eventdev.c 
b/drivers/event/dpaa2/dpaa2_eventdev.c
index 95d9154b11..5d32bd9fd6 100644
--- a/drivers/event/dpaa2/dpaa2_eventdev.c
+++ b/drivers/event/dpaa2/dpaa2_eventdev.c
@@ -320,6 +320,10 @@ dpaa2_eventdev_dequeue_burst(void *port, struct rte_event 
ev[],
        do {
                dq = qbman_swp_dqrr_next(swp);
                if (!dq) {
+                       /* portal is dry: consume whatever is still pending in
+                        * the DQRR consume vector before leaving it idle.
+                        */
+                       qbman_swp_dqrr_consume(swp, NULL);
                        if (!num_pkts && timeout_ticks) {
                                dpaa2_eventdev_dequeue_wait(timeout_ticks);
                                timeout_ticks = 0;
diff --git a/drivers/net/dpaa2/dpaa2_ethdev.c b/drivers/net/dpaa2/dpaa2_ethdev.c
index a33d6c5db6..34f1e00b12 100644
--- a/drivers/net/dpaa2/dpaa2_ethdev.c
+++ b/drivers/net/dpaa2/dpaa2_ethdev.c
@@ -3533,6 +3533,8 @@ dpaa2_napi_drain_portal(struct dpaa2_dpio_dev *dpio)
 
        while ((dq = qbman_swp_dqrr_next(dpio->sw_portal)))
                qbman_swp_dqrr_consume(dpio->sw_portal, dq);
+       /* flush the indices still pending in the DQRR consume vector */
+       qbman_swp_dqrr_consume(dpio->sw_portal, NULL);
        qbman_swp_interrupt_clear_status(dpio->sw_portal, 0xffffffff);
 }
 
-- 
2.43.0

Reply via email to