stmmac: Configure Flow Control to work correctly based on rxfifo size
authorVince Bridgers <vbridger@opensource.altera.com>
Wed, 15 Apr 2015 16:17:42 +0000 (11:17 -0500)
committerDavid S. Miller <davem@davemloft.net>
Thu, 16 Apr 2015 17:58:42 +0000 (13:58 -0400)
Configure flow control correctly, and based on the receive fifo size read
as a property from the devicetree since the Synopsys stmmac fifo sizes are
configurable based on a particular chip's implementation. This patch maintains
the previous incorrect behavior unless the receive fifo size is found in the
devicetree.

Signed-off-by: Vince Bridgers <vbridger@opensource.altera.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c

index cd77289c3cfe3aad2715cd27d1d20c0ecea79674..623c6ed8764ac36237ea48f1470fac6b10702c5a 100644 (file)
@@ -150,7 +150,7 @@ struct stmmac_extra_stats {
 #define        MAC_CSR_H_FRQ_MASK      0x20
 
 #define HASH_TABLE_SIZE 64
-#define PAUSE_TIME 0x200
+#define PAUSE_TIME 0xffff
 
 /* Flow Control defines */
 #define FLOW_OFF       0
@@ -357,7 +357,8 @@ struct stmmac_dma_ops {
        void (*dump_regs) (void __iomem *ioaddr);
        /* Set tx/rx threshold in the csr6 register
         * An invalid value enables the store-and-forward mode */
-       void (*dma_mode) (void __iomem *ioaddr, int txmode, int rxmode);
+       void (*dma_mode)(void __iomem *ioaddr, int txmode, int rxmode,
+                        int rxfifosz);
        /* To track extra statistic (if supported) */
        void (*dma_diagnostic_fr) (void *data, struct stmmac_extra_stats *x,
                                   void __iomem *ioaddr);
index 59d92e811750295e6125cdfcf4f410da6aa21bba..0e8937c1184af811490bf232a05a100af06a9373 100644 (file)
@@ -106,8 +106,29 @@ static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
        return 0;
 }
 
+static u32 dwmac1000_configure_fc(u32 csr6, int rxfifosz)
+{
+       csr6 &= ~DMA_CONTROL_RFA_MASK;
+       csr6 &= ~DMA_CONTROL_RFD_MASK;
+
+       /* Leave flow control disabled if receive fifo size is less than
+        * 4K or 0. Otherwise, send XOFF when fifo is 1K less than full,
+        * and send XON when 2K less than full.
+        */
+       if (rxfifosz < 4096) {
+               csr6 &= ~DMA_CONTROL_EFC;
+               pr_debug("GMAC: disabling flow control, rxfifo too small(%d)\n",
+                        rxfifosz);
+       } else {
+               csr6 |= DMA_CONTROL_EFC;
+               csr6 |= RFA_FULL_MINUS_1K;
+               csr6 |= RFD_FULL_MINUS_2K;
+       }
+       return csr6;
+}
+
 static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode,
-                                        int rxmode)
+                                        int rxmode, int rxfifosz)
 {
        u32 csr6 = readl(ioaddr + DMA_CONTROL);
 
@@ -153,6 +174,9 @@ static void dwmac1000_dma_operation_mode(void __iomem *ioaddr, int txmode,
                        csr6 |= DMA_CONTROL_RTC_128;
        }
 
+       /* Configure flow control based on rx fifo size */
+       csr6 = dwmac1000_configure_fc(csr6, rxfifosz);
+
        writel(csr6, ioaddr + DMA_CONTROL);
 }
 
index 7d1dce9e7ffc9ddcd6769e08cba179538858f7dd..9d0971c1c2ee852fa726262e071c0d88857d738b 100644 (file)
@@ -72,7 +72,7 @@ static int dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
  * control register.
  */
 static void dwmac100_dma_operation_mode(void __iomem *ioaddr, int txmode,
-                                       int rxmode)
+                                       int rxmode, int rxfifosz)
 {
        u32 csr6 = readl(ioaddr + DMA_CONTROL);
 
index 60651738f2a94bea9e79e7fb5c90c3defc753bbd..05c146f718a36551c4fe4ada4871f2612f16571d 100644 (file)
@@ -1277,8 +1277,10 @@ static void free_dma_desc_resources(struct stmmac_priv *priv)
  */
 static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
 {
+       int rxfifosz = priv->plat->rx_fifo_size;
+
        if (priv->plat->force_thresh_dma_mode)
-               priv->hw->dma->dma_mode(priv->ioaddr, tc, tc);
+               priv->hw->dma->dma_mode(priv->ioaddr, tc, tc, rxfifosz);
        else if (priv->plat->force_sf_dma_mode || priv->plat->tx_coe) {
                /*
                 * In case of GMAC, SF mode can be enabled
@@ -1287,10 +1289,12 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
                 * 2) There is no bugged Jumbo frame support
                 *    that needs to not insert csum in the TDES.
                 */
-               priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE);
+               priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE,
+                                       rxfifosz);
                priv->xstats.threshold = SF_DMA_MODE;
        } else
-               priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE);
+               priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE,
+                                       rxfifosz);
 }
 
 /**
@@ -1442,6 +1446,7 @@ static void stmmac_tx_err(struct stmmac_priv *priv)
 static void stmmac_dma_interrupt(struct stmmac_priv *priv)
 {
        int status;
+       int rxfifosz = priv->plat->rx_fifo_size;
 
        status = priv->hw->dma->dma_interrupt(priv->ioaddr, &priv->xstats);
        if (likely((status & handle_rx)) || (status & handle_tx)) {
@@ -1456,10 +1461,11 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
                    (tc <= 256)) {
                        tc += 64;
                        if (priv->plat->force_thresh_dma_mode)
-                               priv->hw->dma->dma_mode(priv->ioaddr, tc, tc);
+                               priv->hw->dma->dma_mode(priv->ioaddr, tc, tc,
+                                                       rxfifosz);
                        else
                                priv->hw->dma->dma_mode(priv->ioaddr, tc,
-                                       SF_DMA_MODE);
+                                                       SF_DMA_MODE, rxfifosz);
                        priv->xstats.threshold = tc;
                }
        } else if (unlikely(status == tx_hard_error))