--- v4
+++ v2
@@ -1,85 +1,57 @@
From: Stefan Chulski <stefanc@marvell.com>
-This patch add RXQ flow control configurations.
-Patch do not enable flow control itself, flow control
-disabled by default.
+This patch add ethtool flow control configuration support.
+
+Tx flow control retrieved correctly by ethtool get function.
+FW per port ethtool configuration capability added.
+
+Patch also takes care about mtu change procedure, if PPv2 switch
+BM pools during mtu change.
Signed-off-by: Stefan Chulski <stefanc@marvell.com>
---
- drivers/net/ethernet/marvell/mvpp2/mvpp2.h | 38 ++++++-
- drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 111 ++++++++++++++++++++
- 2 files changed, 146 insertions(+), 3 deletions(-)
+ drivers/net/ethernet/marvell/mvpp2/mvpp2.h | 13 +++
+ drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c | 106 ++++++++++++++++++++
+ 2 files changed, 119 insertions(+)
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
-index e9625fb..934d535 100644
+index ba57465..feac64c 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2.h
-@@ -763,10 +763,39 @@
- ((kb) * 1024 - MVPP2_TX_FIFO_THRESHOLD_MIN)
+@@ -775,6 +775,19 @@
+ #define MSS_RXQ_TRESH_REG(q, fq) (MSS_RXQ_TRESH_BASE + (((q) + (fq)) \
+ * MSS_RXQ_TRESH_OFFS))
- /* MSS Flow control */
--#define MSS_SRAM_SIZE 0x800
--#define FC_QUANTA 0xFFFF
--#define FC_CLK_DIVIDER 100
-+#define MSS_SRAM_SIZE 0x800
-+#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_BUF_POOL_BASE 0x40
++#define MSS_BUF_POOL_OFFS 4
++#define MSS_BUF_POOL_REG(id) (MSS_BUF_POOL_BASE \
++ + (id) * MSS_BUF_POOL_OFFS)
+
-+#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_BUF_POOL_STOP_MASK 0xFFF
++#define MSS_BUF_POOL_START_MASK (0xFFF << MSS_BUF_POOL_START_OFFS)
++#define MSS_BUF_POOL_START_OFFS 12
++#define MSS_BUF_POOL_PORTS_MASK (0xF << MSS_BUF_POOL_PORTS_OFFS)
++#define MSS_BUF_POOL_PORTS_OFFS 24
++#define MSS_BUF_POOL_PORT_OFFS(id) (0x1 << \
++ ((id) + MSS_BUF_POOL_PORTS_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 \
-@@ -1191,6 +1220,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
+ #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
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
-index 4d55344..36e33d5 100644
+index 2407c52..20157b5 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
-@@ -742,6 +742,110 @@ static void *mvpp2_buf_alloc(struct mvpp2_port *port,
- return data;
+@@ -848,6 +848,59 @@ static void mvpp2_rxq_disable_fc(struct mvpp2_port *port)
+ spin_unlock_irqrestore(&port->priv->mss_spinlock, flags);
}
-+/* Routine enable flow control for RXQs condition */
-+static void mvpp2_rxq_enable_fc(struct mvpp2_port *port)
++/* Routine disable/enable flow control for BM pool condition */
++static void mvpp2_bm_pool_update_fc(struct mvpp2_port *port,
++ struct mvpp2_bm_pool *pool,
++ bool en)
+{
-+ int val, cm3_state, host_id, q;
-+ int fq = port->first_rxq;
++ int val, cm3_state;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->priv->mss_spinlock, flags);
@@ -92,82 +64,30 @@
+ 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);
++ /* Check if BM pool should be enabled/disable */
++ if (en) {
++ /* Set BM pool start and stop thresholds per port */
++ val = mvpp2_cm3_read(port->priv, MSS_BUF_POOL_REG(pool->id));
++ val |= MSS_BUF_POOL_PORT_OFFS(port->id);
++ val &= ~MSS_BUF_POOL_START_MASK;
++ val |= (MSS_THRESHOLD_START << MSS_BUF_POOL_START_OFFS);
++ val &= ~MSS_BUF_POOL_STOP_MASK;
++ val |= MSS_THRESHOLD_STOP;
++ mvpp2_cm3_write(port->priv, MSS_BUF_POOL_REG(pool->id), val);
++ } else {
++ /* Remove BM pool from the port */
++ val = mvpp2_cm3_read(port->priv, MSS_BUF_POOL_REG(pool->id));
++ val &= ~MSS_BUF_POOL_PORT_OFFS(port->id);
+
-+ 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));
++ /* Zero BM pool start and stop thresholds to disable pool
++ * flow control if pool empty (not used by any port)
++ */
++ if (!pool->buf_num) {
++ val &= ~MSS_BUF_POOL_START_MASK;
++ val &= ~MSS_BUF_POOL_STOP_MASK;
++ }
+
-+ /* 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 were 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);
++ mvpp2_cm3_write(port->priv, MSS_BUF_POOL_REG(pool->id), val);
+ }
+
+ /* Notify Firmware that Flow control config space ready for update */
@@ -182,27 +102,87 @@
/* Release buffer to BM */
static inline void mvpp2_bm_pool_put(struct mvpp2_port *port, int pool,
dma_addr_t buf_dma_addr,
-@@ -3008,6 +3112,9 @@ static void mvpp2_cleanup_rxqs(struct mvpp2_port *port)
+@@ -1178,6 +1231,16 @@ static int mvpp2_bm_update_mtu(struct net_device *dev, int mtu)
+ new_long_pool = MVPP2_BM_LONG;
- for (queue = 0; queue < port->nrxqs; queue++)
- mvpp2_rxq_deinit(port, port->rxqs[queue]);
+ if (new_long_pool != port->pool_long->id) {
++ if (port->tx_fc) {
++ if (pkt_size > MVPP2_BM_LONG_PKT_SIZE)
++ mvpp2_bm_pool_update_fc(port,
++ port->pool_short,
++ false);
++ else
++ mvpp2_bm_pool_update_fc(port, port->pool_long,
++ false);
++ }
+
-+ if (port->tx_fc)
+ /* Remove port from old short & long pool */
+ port->pool_long = mvpp2_bm_pool_use(port, port->pool_long->id,
+ port->pool_long->pkt_size);
+@@ -1195,6 +1258,25 @@ static int mvpp2_bm_update_mtu(struct net_device *dev, int mtu)
+ mvpp2_swf_bm_pool_init(port);
+
+ mvpp2_set_hw_csum(port, new_long_pool);
++
++ if (port->tx_fc) {
++ if (pkt_size > MVPP2_BM_LONG_PKT_SIZE)
++ mvpp2_bm_pool_update_fc(port, port->pool_long,
++ true);
++ else
++ mvpp2_bm_pool_update_fc(port, port->pool_short,
++ true);
++ }
++
++ /* Update L4 checksum when jumbo enable/disable on port */
++ if (new_long_pool == MVPP2_BM_JUMBO && port->id != 0) {
++ dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
++ dev->hw_features &= ~(NETIF_F_IP_CSUM |
++ NETIF_F_IPV6_CSUM);
++ } else {
++ dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
++ dev->hw_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
++ }
+ }
+
+ out_set:
+@@ -6357,6 +6439,7 @@ static void mvpp2_mac_link_up(struct phylink_config *config,
+ {
+ struct mvpp2_port *port = mvpp2_phylink_to_port(config);
+ u32 val;
++ int i;
+
+ if (mvpp2_is_xlg(interface)) {
+ if (!phylink_autoneg_inband(mode)) {
+@@ -6407,6 +6490,29 @@ static void mvpp2_mac_link_up(struct phylink_config *config,
+ val);
+ }
+
++ if (tx_pause && port->priv->global_tx_fc) {
++ port->tx_fc = true;
++ mvpp2_rxq_enable_fc(port);
++ if (port->priv->percpu_pools) {
++ for (i = 0; i < port->nrxqs; i++)
++ mvpp2_bm_pool_update_fc(port, &port->priv->bm_pools[i], true);
++ } else {
++ mvpp2_bm_pool_update_fc(port, port->pool_long, true);
++ mvpp2_bm_pool_update_fc(port, port->pool_short, true);
++ }
++
++ } else if (port->priv->global_tx_fc) {
++ port->tx_fc = false;
+ mvpp2_rxq_disable_fc(port);
- }
++ if (port->priv->percpu_pools) {
++ for (i = 0; i < port->nrxqs; i++)
++ mvpp2_bm_pool_update_fc(port, &port->priv->bm_pools[i], false);
++ } else {
++ mvpp2_bm_pool_update_fc(port, port->pool_long, false);
++ mvpp2_bm_pool_update_fc(port, port->pool_short, false);
++ }
++ }
++
+ mvpp2_port_enable(port);
- /* Init all Rx queues for port */
-@@ -3020,6 +3127,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:
+ mvpp2_egress_enable(port);
--
1.9.1