From: Jun Yang <[email protected]>

Read the pool-channel-range property from the device tree, validate that
it has two items, and store the pool channel start and count. Warn if
the configured start differs from the default. Replace the hardcoded
pool channel range check in qman_shutdown_fq() with these DTS-derived
values, via dpaa_get_qm_channel_pool() and the new
dpaa_get_qm_channel_pool_num().

Drop the old affinity check for pool-channel FQs. It compared the FQ's
channel against the portal's dedicated channel (p->config->channel),
which never equals a pool channel, so it could never pass. Any portal
can subscribe to any pool channel through SDQCR, so just program SDQCR
for the FQ's channel and restore it afterwards.

Reject an FQ scheduled on another portal's dedicated channel with
-EBUSY instead of trying to drain it. QM_SDQCR_CHANNELS_DEDICATED only
dequeues the calling portal's own channel, so the FQRN would never
arrive and the drain loop would spin forever. Push-mode Rx queues are
such FQs. A channel in the DCP portal range is rejected the same way.

Bound the FQRN wait by QMAN_FQRN_WAIT_MAX iterations rather than
looping until the notification arrives, so a queue that never retires
cannot hang the caller.

Signed-off-by: Gagandeep Singh <[email protected]>
Signed-off-by: Jun Yang <[email protected]>
Signed-off-by: Hemant Agrawal <[email protected]>
---
 drivers/bus/dpaa/base/qbman/qman.c        | 96 ++++++++++++++---------
 drivers/bus/dpaa/base/qbman/qman_driver.c | 29 ++++++-
 drivers/bus/dpaa/dpaa_bus_base_symbols.c  |  1 +
 drivers/bus/dpaa/include/fsl_qman.h       | 11 ++-
 4 files changed, 95 insertions(+), 42 deletions(-)

diff --git a/drivers/bus/dpaa/base/qbman/qman.c 
b/drivers/bus/dpaa/base/qbman/qman.c
index 81b1e6365b..3cc3c6e635 100644
--- a/drivers/bus/dpaa/base/qbman/qman.c
+++ b/drivers/bus/dpaa/base/qbman/qman.c
@@ -2791,8 +2791,9 @@ qman_shutdown_fq(struct qman_fq *fq)
        struct qm_mc_result *mcr;
        int orl_empty, drain = 0, ret = 0;
        u32 res, fqid = fq->fqid;
+       u32 loop;
        u8 state;
-       u32 channel, wq;
+       u16 channel;
 
        DPAA_BUS_DEBUG("In shutdown for queue = %x", fqid);
        if (!p)
@@ -2806,9 +2807,10 @@ qman_shutdown_fq(struct qman_fq *fq)
                ret = -ETIMEDOUT;
                goto out;
        }
+
        state = mcr->queryfq_np.state & QM_MCR_NP_STATE_MASK;
        if (state == QM_MCR_NP_STATE_OOS) {
-               DPAA_BUS_ERR("Already in OOS");
+               DPAA_BUS_DEBUG("fqid(0x%x) Already in OOS", fqid);
                goto out; /* Already OOS, no need to do anymore checks */
        }
 
@@ -2824,7 +2826,6 @@ qman_shutdown_fq(struct qman_fq *fq)
 
        /* Need to store these since the MCR gets reused */
        channel = qm_fqd_get_chan(&mcr->queryfq.fqd);
-       wq = qm_fqd_get_wq(&mcr->queryfq.fqd);
 
        switch (state) {
        case QM_MCR_NP_STATE_TEN_SCHED:
@@ -2843,10 +2844,9 @@ qman_shutdown_fq(struct qman_fq *fq)
                }
                res = mcr->result; /* Make a copy as we reuse MCR below */
 
-               if (res == QM_MCR_RESULT_OK)
+               if (res == QM_MCR_RESULT_OK) {
                        drain_mr_fqrni(&p->p);
-
-               if (res == QM_MCR_RESULT_PENDING) {
+               } else if (res == QM_MCR_RESULT_PENDING) {
                        /*
                         * Need to wait for the FQRN in the message ring, which
                         * will only occur once the FQ has been drained.  In
@@ -2858,47 +2858,73 @@ qman_shutdown_fq(struct qman_fq *fq)
                        /* Flag that we need to drain FQ */
                        drain = 1;
 
-                       __maybe_unused u16 dequeue_wq = 0;
-                       if (channel >= qm_channel_pool1 &&
-                               channel < (u16)(qm_channel_pool1 + 15)) {
-                               /* Pool channel, enable the bit in the portal */
-                               dequeue_wq = (channel -
-                                               qm_channel_pool1 + 1) << 4 | wq;
-                       } else if (channel < qm_channel_pool1) {
-                               /* Dedicated channel */
-                               dequeue_wq = wq;
-                       } else {
-                               DPAA_BUS_ERR("Can't recover FQ 0x%x, ch: 0x%x",
-                                       fqid, channel);
-                               ret = -EBUSY;
-                               goto out;
-                       }
-                       /* Set the sdqcr to drain this channel */
-                       if (channel < qm_channel_pool1)
+                       const u16 pool_ch_start = dpaa_get_qm_channel_pool();
+                       const u16 pool_ch_end = pool_ch_start +
+                                       dpaa_get_qm_channel_pool_num();
+                       if (channel >= pool_ch_start && channel < pool_ch_end) {
+                               /*
+                                * Pool channel: subscribe this portal to it so
+                                * the hardware can deliver frames and the FQ
+                                * retires.  p->config->channel is the portal's
+                                * dedicated channel and never equals a pool
+                                * channel, so the old affinity check always
+                                * failed.  Any portal can subscribe to any pool
+                                * channel via SDQCR.
+                                */
                                qm_dqrr_sdqcr_set(&p->p,
                                                  QM_SDQCR_TYPE_ACTIVE |
-                                                 QM_SDQCR_CHANNELS_DEDICATED);
-                       else
+                                                 
QM_SDQCR_CHANNELS_POOL_CONV(channel));
+                       } else if (channel < pool_ch_start) {
+                               /*
+                                * Dedicated channel. 
QM_SDQCR_CHANNELS_DEDICATED
+                                * only dequeues this portal's own channel, so 
if
+                                * the FQ is scheduled on another portal's
+                                * dedicated channel the FQRN would never arrive
+                                * and the drain loop below would spin forever.
+                                * Push-mode Rx queues are exactly such FQs.
+                                */
+                               if (channel != p->config->channel) {
+                                       DPAA_BUS_ERR("FQ 0x%x on portal channel 
0x%x, not ours(0x%x)",
+                                               fqid, channel,
+                                               p->config->channel);
+                                       ret = -EBUSY;
+                                       goto out;
+                               }
                                qm_dqrr_sdqcr_set(&p->p,
                                                  QM_SDQCR_TYPE_ACTIVE |
-                                                 QM_SDQCR_CHANNELS_POOL_CONV
-                                                 (channel));
-                       do {
+                                                 QM_SDQCR_CHANNELS_DEDICATED);
+                       } else {
+                               /* Channel is in DCP portal range (e.g. FM0); 
not drainable here */
+                               DPAA_BUS_ERR("DCP portal channel 0x%x for FQ 
0x%x",
+                                       channel, fqid);
+                               ret = -EBUSY;
+                               goto out;
+                       }
+
+                       for (loop = 0; loop < QMAN_FQRN_WAIT_MAX; loop++) {
                                /* Keep draining DQRR while checking the MR*/
                                qm_dqrr_drain_nomatch(&p->p);
                                /* Process message ring too */
-                               found_fqrn = qm_mr_drain(&p->p,
-                                                       FQRN);
+                               found_fqrn = qm_mr_drain(&p->p, FQRN);
+                               if (found_fqrn)
+                                       break;
                                cpu_relax();
-                       } while (!found_fqrn);
-                       /* Restore SDQCR */
-                       qm_dqrr_sdqcr_set(&p->p,
-                                       p->sdqcr);
+                       }
+
+                       /* Restore portal SDQCR for both dedicated and pool 
channels */
+                       qm_dqrr_sdqcr_set(&p->p, p->sdqcr);
+
+                       if (!found_fqrn) {
+                               DPAA_BUS_ERR("FQ 0x%x retire did not complete",
+                                       fqid);
+                               ret = -EBUSY;
+                               goto out;
+                       }
                }
                if (res != QM_MCR_RESULT_OK &&
                    res != QM_MCR_RESULT_PENDING) {
                        DPAA_BUS_ERR("retire_fq failed: FQ 0x%x, res=0x%x",
-                                     fqid, res);
+                               fqid, res);
                        ret = -EIO;
                        goto out;
                }
diff --git a/drivers/bus/dpaa/base/qbman/qman_driver.c 
b/drivers/bus/dpaa/base/qbman/qman_driver.c
index bbe2640c52..ea85e4fd27 100644
--- a/drivers/bus/dpaa/base/qbman/qman_driver.c
+++ b/drivers/bus/dpaa/base/qbman/qman_driver.c
@@ -17,9 +17,10 @@
  * where CCSR isn't available).
  */
 u16 qman_ip_rev;
-u16 qm_channel_pool1 = QMAN_CHANNEL_POOL1;
-u16 qm_channel_caam = QMAN_CHANNEL_CAAM;
-u16 qm_channel_pme = QMAN_CHANNEL_PME;
+static u16 qm_channel_pool1 = QMAN_CHANNEL_POOL1;
+static u16 qm_channel_caam = QMAN_CHANNEL_CAAM;
+static u16 qm_channel_pme = QMAN_CHANNEL_PME;
+static u16 qm_channel_pool_num;
 
 /* Ccsr map address to access ccsrbased register */
 static void *qman_ccsr_map;
@@ -63,6 +64,11 @@ u16 dpaa_get_qm_channel_pool(void)
        return qm_channel_pool1;
 }
 
+u16 dpaa_get_qm_channel_pool_num(void)
+{
+       return qm_channel_pool_num;
+}
+
 static int fsl_qman_portal_init(uint32_t index, int is_shared)
 {
        struct qman_portal *portal;
@@ -273,7 +279,7 @@ int qman_global_init(void)
        uint64_t phys_addr;
        uint64_t regs_size;
        const u32 *clk;
-
+       u16 pool_channel;
        static int done;
 
        if (done)
@@ -334,6 +340,21 @@ int qman_global_init(void)
                return -EINVAL;
        }
 
+       if (lenp != sizeof(rte_be32_t) * 2) {
+               pr_err("pool-channel-range should have 2 items.\n");
+               return -EINVAL;
+       }
+       pool_channel = rte_be_to_cpu_32(chanid[0]);
+       qm_channel_pool_num = rte_be_to_cpu_32(chanid[1]);
+
+       if (pool_channel != qm_channel_pool1) {
+               pr_warn("Pool channel(0x%04x) configured != default(0x%04x)\n",
+                       pool_channel, qm_channel_pool1);
+       }
+       qm_channel_pool1 = pool_channel;
+       pr_debug("Pool channel starts from 0x%04x, number=%d, lenp:%zu\n",
+               qm_channel_pool1, qm_channel_pool_num, lenp);
+
        /* get ccsr base */
        dt_node = of_find_compatible_node(NULL, NULL, "fsl,qman");
        if (!dt_node) {
diff --git a/drivers/bus/dpaa/dpaa_bus_base_symbols.c 
b/drivers/bus/dpaa/dpaa_bus_base_symbols.c
index ee4d8da2ce..c2784272b2 100644
--- a/drivers/bus/dpaa/dpaa_bus_base_symbols.c
+++ b/drivers/bus/dpaa/dpaa_bus_base_symbols.c
@@ -62,6 +62,7 @@ RTE_EXPORT_INTERNAL_SYMBOL(dpaa_intr_enable)
 RTE_EXPORT_INTERNAL_SYMBOL(dpaa_intr_disable)
 RTE_EXPORT_INTERNAL_SYMBOL(dpaa_get_ioctl_version_number)
 RTE_EXPORT_INTERNAL_SYMBOL(dpaa_get_link_status)
+RTE_EXPORT_INTERNAL_SYMBOL(dpaa_get_qm_channel_pool_num)
 RTE_EXPORT_INTERNAL_SYMBOL(dpaa_update_link_status)
 RTE_EXPORT_INTERNAL_SYMBOL(dpaa_update_link_speed)
 RTE_EXPORT_INTERNAL_SYMBOL(dpaa_restart_link_autoneg)
diff --git a/drivers/bus/dpaa/include/fsl_qman.h 
b/drivers/bus/dpaa/include/fsl_qman.h
index 3ee4135982..91bc197907 100644
--- a/drivers/bus/dpaa/include/fsl_qman.h
+++ b/drivers/bus/dpaa/include/fsl_qman.h
@@ -35,9 +35,6 @@ extern "C" {
 #define QMAN_CHANNEL_POOL1_REV3 0x401
 #define QMAN_CHANNEL_CAAM_REV3 0x840
 #define QMAN_CHANNEL_PME_REV3 0x860
-extern u16 qm_channel_pool1;
-extern u16 qm_channel_caam;
-extern u16 qm_channel_pme;
 enum qm_dc_portal {
        qm_dc_portal_fman0 = 0,
        qm_dc_portal_fman1 = 1,
@@ -51,6 +48,9 @@ u16 dpaa_get_qm_channel_caam(void);
 __rte_internal
 u16 dpaa_get_qm_channel_pool(void);
 
+__rte_internal
+u16 dpaa_get_qm_channel_pool_num(void);
+
 /* Portal processing (interrupt) sources */
 #define QM_PIRQ_CCSCI  0x00200000      /* CEETM Congestion State Change */
 #define QM_PIRQ_CSCI   0x00100000      /* Congestion State Change */
@@ -1279,6 +1279,11 @@ struct qman_cgr {
 /* Maximum FQID value: frame queue IDs are 24 bits wide. */
 #define QMAN_MAX_FQID                  0x00FFFFFFu
 
+/* Polling bound while waiting for an FQ retirement notification. A retire
+ * that has not been reported by then is not going to complete on this portal.
+ */
+#define QMAN_FQRN_WAIT_MAX             10000000u
+
 /* Flags to qman_create_fq() */
 #define QMAN_FQ_FLAG_NO_ENQUEUE      0x00000001 /* can't enqueue */
 #define QMAN_FQ_FLAG_NO_MODIFY       0x00000002 /* can only enqueue */
-- 
2.25.1

Reply via email to