stmmac: rework DMA bus setting and introduce new platform AXI structure
authorGiuseppe Cavallaro <peppe.cavallaro@st.com>
Mon, 29 Feb 2016 13:27:28 +0000 (14:27 +0100)
committerDavid S. Miller <davem@davemloft.net>
Wed, 2 Mar 2016 19:21:30 +0000 (14:21 -0500)
This patch restructures the DMA bus settings and this is done
by introducing a new platform structure used for programming
the AXI Bus Mode Register inside the DMA module.
This structure can be populated from device-tree as documented in the
binding txt file.

After initializing the DMA, the AXI register can be optionally tuned
for platform drivers based.
This patch also reworks some parameters to make coherent the DMA
configuration now that AXI register is introduced.
For example, the burst_len is managed by using the mentioned axi
support above; so the snps,burst-len parameter has been removed.
It makes sense to provide the AAL parameter from DT to Address-Aligned
Beats inside the Register0 and review the PBL settings when initialize
the engine.

For PCI glue, rebuilding the story of this setting, it
was added to align a configuration so not for fixing some
known problem. No issue raised after this patch.
It is safe to use the default burst length instead of
tuning it to the maximum value

Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com>
Signed-off-by: Alexandre TORGUE <alexandre.torgue@st.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Documentation/devicetree/bindings/net/stmmac.txt
drivers/net/ethernet/stmicro/stmmac/common.h
drivers/net/ethernet/stmicro/stmmac/dwmac1000.h
drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
drivers/net/ethernet/stmicro/stmmac/dwmac100_dma.c
drivers/net/ethernet/stmicro/stmmac/dwmac_dma.h
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
include/linux/stmmac.h

index e862a922bd3f957daca0989d1a94ae246afa48ca..6605d19601c2a6bcce217ef02a60f5afb42e0d55 100644 (file)
@@ -17,7 +17,25 @@ Required properties:
        The 1st cell is reset pre-delay in micro seconds.
        The 2nd cell is reset pulse in micro seconds.
        The 3rd cell is reset post-delay in micro seconds.
+
+Optional properties:
+- resets: Should contain a phandle to the STMMAC reset signal, if any
+- reset-names: Should contain the reset signal name "stmmaceth", if a
+       reset phandle is given
+- max-frame-size: See ethernet.txt file in the same directory
+- clocks: If present, the first clock should be the GMAC main clock and
+  the second clock should be peripheral's register interface clock. Further
+  clocks may be specified in derived bindings.
+- clock-names: One name for each entry in the clocks property, the
+  first one should be "stmmaceth" and the second one should be "pclk".
+- clk_ptp_ref: this is the PTP reference clock; in case of the PTP is
+  available this clock is used for programming the Timestamp Addend Register.
+  If not passed then the system clock will be used and this is fine on some
+  platforms.
+- tx-fifo-depth: See ethernet.txt file in the same directory
+- rx-fifo-depth: See ethernet.txt file in the same directory
 - snps,pbl             Programmable Burst Length
+- snps,aal             Address-Aligned Beats
 - snps,fixed-burst     Program the DMA to use the fixed burst mode
 - snps,mixed-burst     Program the DMA to use the mixed burst mode
 - snps,force_thresh_dma_mode   Force DMA to use the threshold mode for
@@ -29,27 +47,28 @@ Required properties:
                                supported by this device instance
 - snps,perfect-filter-entries: Number of perfect filter entries supported
                                by this device instance
-
-Optional properties:
-- resets: Should contain a phandle to the STMMAC reset signal, if any
-- reset-names: Should contain the reset signal name "stmmaceth", if a
-       reset phandle is given
-- max-frame-size: See ethernet.txt file in the same directory
-- clocks: If present, the first clock should be the GMAC main clock
-  The optional second clock should be peripheral's register interface clock.
-  The third optional clock should be the ptp reference clock.
-  Further clocks may be specified in derived bindings.
-- clock-names: One name for each entry in the clocks property.
-  The first one should be "stmmaceth".
-  The optional second one should be "pclk".
-  The optional third one should be "clk_ptp_ref".
-- snps,burst_len: The AXI burst lenth value of the AXI BUS MODE register.
-- tx-fifo-depth: See ethernet.txt file in the same directory
-- rx-fifo-depth: See ethernet.txt file in the same directory
+- AXI BUS Mode parameters: below the list of all the parameters to program the
+                          AXI register inside the DMA module:
+       - snps,lpi_en: enable Low Power Interface
+       - snps,xit_frm: unlock on WoL
+       - snps,wr_osr_lmt: max write oustanding req. limit
+       - snps,rd_osr_lmt: max read oustanding req. limit
+       - snps,kbbe: do not cross 1KiB boundary.
+       - snps,axi_all: align address
+       - snps,blen: this is a vector of supported burst length.
+       - snps,fb: fixed-burst
+       - snps,mb: mixed-burst
+       - snps,rb: rebuild INCRx Burst
 - mdio: with compatible = "snps,dwmac-mdio", create and register mdio bus.
 
 Examples:
 
+       stmmac_axi_setup: stmmac-axi-config {
+               snps,wr_osr_lmt = <0xf>;
+               snps,rd_osr_lmt = <0xf>;
+               snps,blen = <256 128 64 32 0 0 0>;
+       };
+
        gmac0: ethernet@e0800000 {
                compatible = "st,spear600-gmac";
                reg = <0xe0800000 0x8000>;
@@ -65,6 +84,7 @@ Examples:
                tx-fifo-depth = <16384>;
                clocks = <&clock>;
                clock-names = "stmmaceth";
+               snps,axi-config = <&stmmac_axi_setup>;
                mdio0 {
                        #address-cells = <1>;
                        #size-cells = <0>;
index bac0e44d763458132e702b340a8ef263b2973ddd..586a33624dd23a5f38dc8b4e6bcdf72a2b609ac3 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <linux/etherdevice.h>
 #include <linux/netdevice.h>
+#include <linux/stmmac.h>
 #include <linux/phy.h>
 #include <linux/module.h>
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
@@ -378,7 +379,9 @@ struct stmmac_dma_ops {
        /* DMA core initialization */
        int (*reset)(void __iomem *ioaddr);
        void (*init)(void __iomem *ioaddr, int pbl, int fb, int mb,
-                    int burst_len, u32 dma_tx, u32 dma_rx, int atds);
+                    int aal, u32 dma_tx, u32 dma_rx, int atds);
+       /* Configure the AXI Bus Mode Register */
+       void (*axi)(void __iomem *ioaddr, struct stmmac_axi *axi);
        /* Dump DMA registers */
        void (*dump_regs) (void __iomem *ioaddr);
        /* Set tx/rx threshold in the csr6 register
index 9d36ae788429e7f63413415f482c4a9e375db411..b0593a4268eeab5abb38f787511196faa3590f66 100644 (file)
@@ -240,7 +240,7 @@ enum rx_tx_priority_ratio {
 #define DMA_BUS_MODE_RPBL_MASK 0x003e0000      /* Rx-Programmable Burst Len */
 #define DMA_BUS_MODE_RPBL_SHIFT        17
 #define DMA_BUS_MODE_USP       0x00800000
-#define DMA_BUS_MODE_PBL       0x01000000
+#define DMA_BUS_MODE_MAXPBL    0x01000000
 #define DMA_BUS_MODE_AAL       0x02000000
 
 /* DMA CRS Control and Status Register Mapping */
index 5f0aea56b2986cc8216fcc8c8a8b792b19ec9fd7..da32d6037e3e4baacfe2d9ef4723029873d641e7 100644 (file)
 #include "dwmac1000.h"
 #include "dwmac_dma.h"
 
+static void dwmac1000_dma_axi(void __iomem *ioaddr, struct stmmac_axi *axi)
+{
+       u32 value = readl(ioaddr + DMA_AXI_BUS_MODE);
+       int i;
+
+       pr_info("dwmac1000: Master AXI performs %s burst length\n",
+               !(value & DMA_AXI_UNDEF) ? "fixed" : "any");
+
+       if (axi->axi_lpi_en)
+               value |= DMA_AXI_EN_LPI;
+       if (axi->axi_xit_frm)
+               value |= DMA_AXI_LPI_XIT_FRM;
+
+       value |= (axi->axi_wr_osr_lmt & DMA_AXI_WR_OSR_LMT_MASK) <<
+                DMA_AXI_WR_OSR_LMT_SHIFT;
+
+       value |= (axi->axi_rd_osr_lmt & DMA_AXI_RD_OSR_LMT_MASK) <<
+                DMA_AXI_RD_OSR_LMT_SHIFT;
+
+       /* Depending on the UNDEF bit the Master AXI will perform any burst
+        * length according to the BLEN programmed (by default all BLEN are
+        * set).
+        */
+       for (i = 0; i < AXI_BLEN; i++) {
+               switch (axi->axi_blen[i]) {
+               case 256:
+                       value |= DMA_AXI_BLEN256;
+                       break;
+               case 128:
+                       value |= DMA_AXI_BLEN128;
+                       break;
+               case 64:
+                       value |= DMA_AXI_BLEN64;
+                       break;
+               case 32:
+                       value |= DMA_AXI_BLEN32;
+                       break;
+               case 16:
+                       value |= DMA_AXI_BLEN16;
+                       break;
+               case 8:
+                       value |= DMA_AXI_BLEN8;
+                       break;
+               case 4:
+                       value |= DMA_AXI_BLEN4;
+                       break;
+               }
+       }
+
+       writel(value, ioaddr + DMA_AXI_BUS_MODE);
+}
+
 static void dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
-                              int burst_len, u32 dma_tx, u32 dma_rx, int atds)
+                              int aal, u32 dma_tx, u32 dma_rx, int atds)
 {
-       u32 value;
+       u32 value = readl(ioaddr + DMA_BUS_MODE);
 
        /*
-        * Set the DMA PBL (Programmable Burst Length) mode
-        * Before stmmac core 3.50 this mode bit was 4xPBL, and
+        * Set the DMA PBL (Programmable Burst Length) mode.
+        *
+        * Note: before stmmac core 3.50 this mode bit was 4xPBL, and
         * post 3.5 mode bit acts as 8*PBL.
-        * For core rev < 3.5, when the core is set for 4xPBL mode, the
-        * DMA transfers the data in 4, 8, 16, 32, 64 & 128 beats
-        * depending on pbl value.
-        * For core rev > 3.5, when the core is set for 8xPBL mode, the
-        * DMA transfers the data in 8, 16, 32, 64, 128 & 256 beats
-        * depending on pbl value.
+        *
+        * This configuration doesn't take care about the Separate PBL
+        * so only the bits: 13-8 are programmed with the PBL passed from the
+        * platform.
         */
-       value = DMA_BUS_MODE_PBL | ((pbl << DMA_BUS_MODE_PBL_SHIFT) |
-                                   (pbl << DMA_BUS_MODE_RPBL_SHIFT));
+       value |= DMA_BUS_MODE_MAXPBL;
+       value &= ~DMA_BUS_MODE_PBL_MASK;
+       value |= (pbl << DMA_BUS_MODE_PBL_SHIFT);
 
        /* Set the Fixed burst mode */
        if (fb)
@@ -60,26 +112,10 @@ static void dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
        if (atds)
                value |= DMA_BUS_MODE_ATDS;
 
-       writel(value, ioaddr + DMA_BUS_MODE);
+       if (aal)
+               value |= DMA_BUS_MODE_AAL;
 
-       /* In case of GMAC AXI configuration, program the DMA_AXI_BUS_MODE
-        * for supported bursts.
-        *
-        * Note: This is applicable only for revision GMACv3.61a. For
-        * older version this register is reserved and shall have no
-        * effect.
-        *
-        * Note:
-        *  For Fixed Burst Mode: if we directly write 0xFF to this
-        *  register using the configurations pass from platform code,
-        *  this would ensure that all bursts supported by core are set
-        *  and those which are not supported would remain ineffective.
-        *
-        *  For Non Fixed Burst Mode: provide the maximum value of the
-        *  burst length. Any burst equal or below the provided burst
-        *  length would be allowed to perform.
-        */
-       writel(burst_len, ioaddr + DMA_AXI_BUS_MODE);
+       writel(value, ioaddr + DMA_BUS_MODE);
 
        /* Mask interrupts by writing to CSR7 */
        writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
@@ -192,6 +228,7 @@ static void dwmac1000_rx_watchdog(void __iomem *ioaddr, u32 riwt)
 const struct stmmac_dma_ops dwmac1000_dma_ops = {
        .reset = dwmac_dma_reset,
        .init = dwmac1000_dma_init,
+       .axi = dwmac1000_dma_axi,
        .dump_regs = dwmac1000_dump_dma_regs,
        .dma_mode = dwmac1000_dma_operation_mode,
        .enable_dma_transmission = dwmac_enable_dma_transmission,
index c40582a938a4ccd23b9439a31c2092a09877437d..61f54c99a7de9ebf0da2db75b6f509900346ea07 100644 (file)
@@ -33,7 +33,7 @@
 #include "dwmac_dma.h"
 
 static void dwmac100_dma_init(void __iomem *ioaddr, int pbl, int fb, int mb,
-                             int burst_len, u32 dma_tx, u32 dma_rx, int atds)
+                             int aal, u32 dma_tx, u32 dma_rx, int atds)
 {
        /* Enable Application Access by writing to DMA CSR0 */
        writel(DMA_BUS_MODE_DEFAULT | (pbl << DMA_BUS_MODE_PBL_SHIFT),
index 13ca90e23479f9c77fe6380c2b13277ae3c44ba6..726d9d9aaf83dce9c91ab307791fc594642e389f 100644 (file)
 
 /* Rx watchdog register */
 #define DMA_RX_WATCHDOG                0x00001024
-/* AXI Bus Mode */
+
+/* AXI Master Bus Mode */
 #define DMA_AXI_BUS_MODE       0x00001028
+
+#define DMA_AXI_EN_LPI         BIT(31)
+#define DMA_AXI_LPI_XIT_FRM    BIT(30)
+#define DMA_AXI_WR_OSR_LMT     GENMASK(23, 20)
+#define DMA_AXI_WR_OSR_LMT_SHIFT       20
+#define DMA_AXI_WR_OSR_LMT_MASK        0xf
+#define DMA_AXI_RD_OSR_LMT     GENMASK(19, 16)
+#define DMA_AXI_RD_OSR_LMT_SHIFT       16
+#define DMA_AXI_RD_OSR_LMT_MASK        0xf
+
+#define DMA_AXI_OSR_MAX                0xf
+#define DMA_AXI_MAX_OSR_LIMIT ((DMA_AXI_OSR_MAX << DMA_AXI_WR_OSR_LMT_SHIFT) | \
+                              (DMA_AXI_OSR_MAX << DMA_AXI_RD_OSR_LMT_SHIFT))
+#define        DMA_AXI_1KBBE           BIT(13)
+#define DMA_AXI_AAL            BIT(12)
+#define DMA_AXI_BLEN256                BIT(7)
+#define DMA_AXI_BLEN128                BIT(6)
+#define DMA_AXI_BLEN64         BIT(5)
+#define DMA_AXI_BLEN32         BIT(4)
+#define DMA_AXI_BLEN16         BIT(3)
+#define DMA_AXI_BLEN8          BIT(2)
+#define DMA_AXI_BLEN4          BIT(1)
+#define DMA_BURST_LEN_DEFAULT  (DMA_AXI_BLEN256 | DMA_AXI_BLEN128 | \
+                                DMA_AXI_BLEN64 | DMA_AXI_BLEN32 | \
+                                DMA_AXI_BLEN16 | DMA_AXI_BLEN8 | \
+                                DMA_AXI_BLEN4)
+
+#define DMA_AXI_UNDEF          BIT(0)
+
+#define DMA_AXI_BURST_LEN_MASK 0x000000FE
+
 #define DMA_CUR_TX_BUF_ADDR    0x00001050      /* Current Host Tx Buffer */
 #define DMA_CUR_RX_BUF_ADDR    0x00001054      /* Current Host Rx Buffer */
 #define DMA_HW_FEATURE         0x00001058      /* HW Feature Register */
index 13752e933e43879436e1ad23eec7156bb6e0f1b5..89c26268822e8742a51853d7f4563c16e33b33c5 100644 (file)
@@ -1635,7 +1635,7 @@ static void stmmac_check_ether_addr(struct stmmac_priv *priv)
  */
 static int stmmac_init_dma_engine(struct stmmac_priv *priv)
 {
-       int pbl = DEFAULT_DMA_PBL, fixed_burst = 0, burst_len = 0;
+       int pbl = DEFAULT_DMA_PBL, fixed_burst = 0, aal = 0;
        int mixed_burst = 0;
        int atds = 0;
        int ret = 0;
@@ -1644,7 +1644,7 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
                pbl = priv->plat->dma_cfg->pbl;
                fixed_burst = priv->plat->dma_cfg->fixed_burst;
                mixed_burst = priv->plat->dma_cfg->mixed_burst;
-               burst_len = priv->plat->dma_cfg->burst_len;
+               aal = priv->plat->dma_cfg->aal;
        }
 
        if (priv->extend_desc && (priv->mode == STMMAC_RING_MODE))
@@ -1657,8 +1657,12 @@ static int stmmac_init_dma_engine(struct stmmac_priv *priv)
        }
 
        priv->hw->dma->init(priv->ioaddr, pbl, fixed_burst, mixed_burst,
-                           burst_len, priv->dma_tx_phy,
-                           priv->dma_rx_phy, atds);
+                           aal, priv->dma_tx_phy, priv->dma_rx_phy, atds);
+
+       if ((priv->synopsys_id >= DWMAC_CORE_3_50) &&
+           (priv->plat->axi && priv->hw->dma->axi))
+               priv->hw->dma->axi(priv->ioaddr, priv->plat->axi);
+
        return ret;
 }
 
index d71a721ea61ce8f973d26ac7353ab210e33e9542..ae4388735b7fb560649da51cf823caf4f1dbdbb6 100644 (file)
@@ -81,7 +81,7 @@ static void stmmac_default_data(struct plat_stmmacenet_data *plat)
        plat->mdio_bus_data->phy_mask = 0;
 
        plat->dma_cfg->pbl = 32;
-       plat->dma_cfg->burst_len = DMA_AXI_BLEN_256;
+       /* TODO: AXI */
 
        /* Set default value for multicast hash bins */
        plat->multicast_filter_bins = HASH_TABLE_SIZE;
@@ -115,8 +115,8 @@ static int quark_default_data(struct plat_stmmacenet_data *plat,
        plat->mdio_bus_data->phy_mask = 0;
 
        plat->dma_cfg->pbl = 16;
-       plat->dma_cfg->burst_len = DMA_AXI_BLEN_256;
        plat->dma_cfg->fixed_burst = 1;
+       /* AXI (TODO) */
 
        /* Set default value for multicast hash bins */
        plat->multicast_filter_bins = HASH_TABLE_SIZE;
index 6a52fa18cbf2e94958bdfe44c4db258ababcdd02..69ccf486d4faec2be7eacf8dfc7bd6400ac7980c 100644 (file)
@@ -95,6 +95,42 @@ static int dwmac1000_validate_ucast_entries(int ucast_entries)
        return x;
 }
 
+/**
+ * stmmac_axi_setup - parse DT parameters for programming the AXI register
+ * @pdev: platform device
+ * @priv: driver private struct.
+ * Description:
+ * if required, from device-tree the AXI internal register can be tuned
+ * by using platform parameters.
+ */
+static struct stmmac_axi *stmmac_axi_setup(struct platform_device *pdev)
+{
+       struct device_node *np;
+       struct stmmac_axi *axi;
+
+       np = of_parse_phandle(pdev->dev.of_node, "snps,axi-config", 0);
+       if (!np)
+               return NULL;
+
+       axi = kzalloc(sizeof(axi), GFP_KERNEL);
+       if (!axi)
+               return ERR_PTR(-ENOMEM);
+
+       axi->axi_lpi_en = of_property_read_bool(np, "snps,lpi_en");
+       axi->axi_xit_frm = of_property_read_bool(np, "snps,xit_frm");
+       axi->axi_kbbe = of_property_read_bool(np, "snps,axi_kbbe");
+       axi->axi_axi_all = of_property_read_bool(np, "snps,axi_all");
+       axi->axi_fb = of_property_read_bool(np, "snps,axi_fb");
+       axi->axi_mb = of_property_read_bool(np, "snps,axi_mb");
+       axi->axi_rb =  of_property_read_bool(np, "snps,axi_rb");
+
+       of_property_read_u32(np, "snps,wr_osr_lmt", &axi->axi_wr_osr_lmt);
+       of_property_read_u32(np, "snps,rd_osr_lmt", &axi->axi_rd_osr_lmt);
+       of_property_read_u32_array(np, "snps,blen", axi->axi_blen, AXI_BLEN);
+
+       return axi;
+}
+
 /**
  * stmmac_probe_config_dt - parse device-tree driver parameters
  * @pdev: platform_device structure
@@ -216,13 +252,11 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
                }
                plat->dma_cfg = dma_cfg;
                of_property_read_u32(np, "snps,pbl", &dma_cfg->pbl);
+               dma_cfg->aal = of_property_read_bool(np, "snps,aal");
                dma_cfg->fixed_burst =
                        of_property_read_bool(np, "snps,fixed-burst");
                dma_cfg->mixed_burst =
                        of_property_read_bool(np, "snps,mixed-burst");
-               of_property_read_u32(np, "snps,burst_len", &dma_cfg->burst_len);
-               if (dma_cfg->burst_len < 0 || dma_cfg->burst_len > 256)
-                       dma_cfg->burst_len = 0;
        }
        plat->force_thresh_dma_mode = of_property_read_bool(np, "snps,force_thresh_dma_mode");
        if (plat->force_thresh_dma_mode) {
@@ -230,6 +264,8 @@ stmmac_probe_config_dt(struct platform_device *pdev, const char **mac)
                pr_warn("force_sf_dma_mode is ignored if force_thresh_dma_mode is set.");
        }
 
+       plat->axi = stmmac_axi_setup(pdev);
+
        return plat;
 }
 #else
index eead8ab93c0a36e402741ee767d3c3bc70128964..6e53fa8942a470cb74b9baa2dc2b7d228c23876c 100644 (file)
@@ -90,7 +90,21 @@ struct stmmac_dma_cfg {
        int pbl;
        int fixed_burst;
        int mixed_burst;
-       int burst_len;
+       bool aal;
+};
+
+#define AXI_BLEN       7
+struct stmmac_axi {
+       bool axi_lpi_en;
+       bool axi_xit_frm;
+       u32 axi_wr_osr_lmt;
+       u32 axi_rd_osr_lmt;
+       bool axi_kbbe;
+       bool axi_axi_all;
+       u32 axi_blen[AXI_BLEN];
+       bool axi_fb;
+       bool axi_mb;
+       bool axi_rb;
 };
 
 struct plat_stmmacenet_data {
@@ -122,5 +136,6 @@ struct plat_stmmacenet_data {
        int (*init)(struct platform_device *pdev, void *priv);
        void (*exit)(struct platform_device *pdev, void *priv);
        void *bsp_priv;
+       struct stmmac_axi *axi;
 };
 #endif