From: Stefan Chulski <stef...@marvell.com>

This patch adds RXQ flow control configurations.
Flow control disabled by default.
Minimum ring size limited to 1024 descriptors.

Signed-off-by: Stefan Chulski <stef...@marvell.com>
---
 drivers/net/ethernet/marvell/mvpp2/mvpp2.h      |  35 +++++-
 drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 116 ++++++++++++++++++++
 2 files changed, 150 insertions(+), 1 deletion(-)

diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h 
b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
index 8945fb9..0010a3e9 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
@@ -765,9 +765,36 @@
 /* MSS Flow control */
 #define MSS_FC_COM_REG                 0
 #define FLOW_CONTROL_ENABLE_BIT                BIT(0)
+#define FLOW_CONTROL_UPDATE_COMMAND_BIT        BIT(31)
 #define FC_QUANTA                      0xFFFF
 #define FC_CLK_DIVIDER                 100
-#define MSS_THRESHOLD_STOP             768
+
+#define MSS_RXQ_TRESH_BASE             0x200
+#define MSS_RXQ_TRESH_OFFS             4
+#define MSS_RXQ_TRESH_REG(q, fq)       (MSS_RXQ_TRESH_BASE + (((q) + (fq)) \
+                                       * MSS_RXQ_TRESH_OFFS))
+
+#define MSS_RXQ_TRESH_START_MASK       0xFFFF
+#define MSS_RXQ_TRESH_STOP_MASK                (0xFFFF << 
MSS_RXQ_TRESH_STOP_OFFS)
+#define MSS_RXQ_TRESH_STOP_OFFS                16
+
+#define MSS_RXQ_ASS_BASE       0x80
+#define MSS_RXQ_ASS_OFFS       4
+#define MSS_RXQ_ASS_PER_REG    4
+#define MSS_RXQ_ASS_PER_OFFS   8
+#define MSS_RXQ_ASS_PORTID_OFFS        0
+#define MSS_RXQ_ASS_PORTID_MASK        0x3
+#define MSS_RXQ_ASS_HOSTID_OFFS        2
+#define MSS_RXQ_ASS_HOSTID_MASK        0x3F
+
+#define MSS_RXQ_ASS_Q_BASE(q, fq) ((((q) + (fq)) % MSS_RXQ_ASS_PER_REG)        
 \
+                                 * MSS_RXQ_ASS_PER_OFFS)
+#define MSS_RXQ_ASS_PQ_BASE(q, fq) ((((q) + (fq)) / MSS_RXQ_ASS_PER_REG) \
+                                  * MSS_RXQ_ASS_OFFS)
+#define MSS_RXQ_ASS_REG(q, fq) (MSS_RXQ_ASS_BASE + MSS_RXQ_ASS_PQ_BASE(q, fq))
+
+#define MSS_THRESHOLD_STOP     768
+#define MSS_THRESHOLD_START    1024
 
 /* RX buffer constants */
 #define MVPP2_SKB_SHINFO_SIZE \
@@ -1022,6 +1049,9 @@ struct mvpp2 {
 
        /* Global TX Flow Control config */
        bool global_tx_fc;
+
+       /* Spinlocks for CM3 shared memory configuration */
+       spinlock_t mss_spinlock;
 };
 
 struct mvpp2_pcpu_stats {
@@ -1184,6 +1214,9 @@ struct mvpp2_port {
        bool rx_hwtstamp;
        enum hwtstamp_tx_types tx_hwtstamp_type;
        struct mvpp2_hwtstamp_queue tx_hwtstamp_queue[2];
+
+       /* Firmware TX flow control */
+       bool tx_fc;
 };
 
 /* The mvpp2_tx_desc and mvpp2_rx_desc structures describe the
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c 
b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index 027101b..f1770e5 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -741,6 +741,110 @@ static void *mvpp2_buf_alloc(struct mvpp2_port *port,
        return data;
 }
 
+/* Routine enable flow control for RXQs condition */
+static void mvpp2_rxq_enable_fc(struct mvpp2_port *port)
+{
+       int val, cm3_state, host_id, q;
+       int fq = port->first_rxq;
+       unsigned long flags;
+
+       spin_lock_irqsave(&port->priv->mss_spinlock, flags);
+
+       /* Remove Flow control enable bit to prevent race between FW and Kernel
+        * If Flow control was enabled, it would be re-enabled.
+        */
+       val = mvpp2_cm3_read(port->priv, MSS_FC_COM_REG);
+       cm3_state = (val & FLOW_CONTROL_ENABLE_BIT);
+       val &= ~FLOW_CONTROL_ENABLE_BIT;
+       mvpp2_cm3_write(port->priv, MSS_FC_COM_REG, val);
+
+       /* Set same Flow control for all RXQs */
+       for (q = 0; q < port->nrxqs; q++) {
+               /* Set stop and start Flow control RXQ thresholds */
+               val = MSS_THRESHOLD_START;
+               val |= (MSS_THRESHOLD_STOP << MSS_RXQ_TRESH_STOP_OFFS);
+               mvpp2_cm3_write(port->priv, MSS_RXQ_TRESH_REG(q, fq), val);
+
+               val = mvpp2_cm3_read(port->priv, MSS_RXQ_ASS_REG(q, fq));
+               /* Set RXQ port ID */
+               val &= ~(MSS_RXQ_ASS_PORTID_MASK << MSS_RXQ_ASS_Q_BASE(q, fq));
+               val |= (port->id << MSS_RXQ_ASS_Q_BASE(q, fq));
+               val &= ~(MSS_RXQ_ASS_HOSTID_MASK << (MSS_RXQ_ASS_Q_BASE(q, fq)
+                       + MSS_RXQ_ASS_HOSTID_OFFS));
+
+               /* Calculate RXQ host ID:
+                * In Single queue mode: Host ID equal to Host ID used for
+                *                       shared RX interrupt
+                * In Multi queue mode: Host ID equal to number of
+                *                      RXQ ID / number of CoS queues
+                * In Single resource mode: Host ID always equal to 0
+                */
+               if (queue_mode == MVPP2_QDIST_SINGLE_MODE)
+                       host_id = port->nqvecs;
+               else if (queue_mode == MVPP2_QDIST_MULTI_MODE)
+                       host_id = q;
+               else
+                       host_id = 0;
+
+               /* Set RXQ host ID */
+               val |= (host_id << (MSS_RXQ_ASS_Q_BASE(q, fq)
+                       + MSS_RXQ_ASS_HOSTID_OFFS));
+
+               mvpp2_cm3_write(port->priv, MSS_RXQ_ASS_REG(q, fq), val);
+       }
+
+       /* Notify Firmware that Flow control config space ready for update */
+       val = mvpp2_cm3_read(port->priv, MSS_FC_COM_REG);
+       val |= FLOW_CONTROL_UPDATE_COMMAND_BIT;
+       val |= cm3_state;
+       mvpp2_cm3_write(port->priv, MSS_FC_COM_REG, val);
+
+       spin_unlock_irqrestore(&port->priv->mss_spinlock, flags);
+}
+
+/* Routine disable flow control for RXQs condition */
+static void mvpp2_rxq_disable_fc(struct mvpp2_port *port)
+{
+       int val, cm3_state, q;
+       unsigned long flags;
+       int fq = port->first_rxq;
+
+       spin_lock_irqsave(&port->priv->mss_spinlock, flags);
+
+       /* Remove Flow control enable bit to prevent race between FW and Kernel
+        * If Flow control was enabled, it would be re-enabled.
+        */
+       val = mvpp2_cm3_read(port->priv, MSS_FC_COM_REG);
+       cm3_state = (val & FLOW_CONTROL_ENABLE_BIT);
+       val &= ~FLOW_CONTROL_ENABLE_BIT;
+       mvpp2_cm3_write(port->priv, MSS_FC_COM_REG, val);
+
+       /* Disable Flow control for all RXQs */
+       for (q = 0; q < port->nrxqs; q++) {
+               /* Set threshold 0 to disable Flow control */
+               val = 0;
+               val |= (0 << MSS_RXQ_TRESH_STOP_OFFS);
+               mvpp2_cm3_write(port->priv, MSS_RXQ_TRESH_REG(q, fq), val);
+
+               val = mvpp2_cm3_read(port->priv, MSS_RXQ_ASS_REG(q, fq));
+
+               val &= ~(MSS_RXQ_ASS_PORTID_MASK << MSS_RXQ_ASS_Q_BASE(q, fq));
+
+               val &= ~(MSS_RXQ_ASS_HOSTID_MASK << (MSS_RXQ_ASS_Q_BASE(q, fq)
+                       + MSS_RXQ_ASS_HOSTID_OFFS));
+
+               mvpp2_cm3_write(port->priv, MSS_RXQ_ASS_REG(q, fq), val);
+       }
+
+       /* Notify Firmware that Flow control config space ready for update */
+       val = mvpp2_cm3_read(port->priv, MSS_FC_COM_REG);
+       val |= FLOW_CONTROL_UPDATE_COMMAND_BIT;
+       val |= cm3_state;
+       mvpp2_cm3_write(port->priv, MSS_FC_COM_REG, val);
+
+       spin_unlock_irqrestore(&port->priv->mss_spinlock, flags);
+}
+
 /* Release buffer to BM */
 static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool,
                                     dma_addr_t buf_dma_addr,
@@ -3005,6 +3109,9 @@ static void mvpp2_cleanup_rxqs(struct mvpp2_port *port)
 
        for (queue = 0; queue < port->nrxqs; queue++)
                mvpp2_rxq_deinit(port, port->rxqs[queue]);
+
+       if (port->tx_fc)
+               mvpp2_rxq_disable_fc(port);
 }
 
 /* Init all Rx queues for port */
@@ -3017,6 +3124,10 @@ static int mvpp2_setup_rxqs(struct mvpp2_port *port)
                if (err)
                        goto err_cleanup;
        }
+
+       if (port->tx_fc)
+               mvpp2_rxq_enable_fc(port);
+
        return 0;
 
 err_cleanup:
@@ -4316,6 +4427,8 @@ static int mvpp2_check_ringparam_valid(struct net_device 
*dev,
 
        if (ring->rx_pending > MVPP2_MAX_RXD_MAX)
                new_rx_pending = MVPP2_MAX_RXD_MAX;
+       else if (ring->rx_pending < MSS_THRESHOLD_START)
+               new_rx_pending = MSS_THRESHOLD_START;
        else if (!IS_ALIGNED(ring->rx_pending, 16))
                new_rx_pending = ALIGN(ring->rx_pending, 16);
 
@@ -7148,6 +7261,9 @@ static int mvpp2_probe(struct platform_device *pdev)
                        priv->hw_version = MVPP23;
        }
 
+       /* Init mss lock */
+       spin_lock_init(&priv->mss_spinlock);
+
        /* Initialize network controller */
        err = mvpp2_init(pdev, priv);
        if (err < 0) {
-- 
1.9.1

Reply via email to