Skip to content

Instantly share code, notes, and snippets.

@changtimwu
Last active March 1, 2019 23:20
Show Gist options
  • Save changtimwu/82414e52b110a638b2ac to your computer and use it in GitHub Desktop.
Save changtimwu/82414e52b110a638b2ac to your computer and use it in GitHub Desktop.
description of the eth1 DMA initialization fail problem
  • code clip of the error message. drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
   /* DMA initialization and SW reset */
    ret = stmmac_init_dma_engine(priv);
    if (ret < 0) {                                                                                  
        pr_err("%s: DMA initialization failed\n", __func__);
        goto open_error;
    }
  • backtrace 1
static int stmmac_init_dma_engine(struct stmmac_priv *priv)
{
    int pbl = DEFAULT_DMA_PBL, fixed_burst = 0, burst_len = 0;
    int mixed_burst = 0;

    /* Some DMA parameters can be passed from the platform;
     * in case of these are not passed we keep a default
     * (good for all the chips) and init the DMA! */
    if (priv->plat->dma_cfg) {
        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;
    }

    return priv->hw->dma->init(priv->ioaddr, pbl, fixed_burst, mixed_burst,
                   burst_len, priv->dma_tx_phy,
                   priv->dma_rx_phy);
}
  • backtrace 2, drivers/net/ethernet/stmicro/stmmac/dwmac1000_dma.c
static int dwmac1000_dma_init(void __iomem *ioaddr, int pbl, int fb,
                              int mb, int burst_len, u32 dma_tx, u32 dma_rx)
{
        u32 value = readl(ioaddr + DMA_BUS_MODE);
        int limit;

        /* DMA SW reset */
        value |= DMA_BUS_MODE_SFT_RESET;
        writel(value, ioaddr + DMA_BUS_MODE);
        limit = 10;
        while (limit--) {
                if (!(readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET))
                        break;
                mdelay(10);
        }
        if (limit < 0)
                return -EBUSY;

The problem is that readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET) is always busy. We try to increase limit to 1000 but problem still remains.

@danielkucera
Copy link

this is my workaround:

diff --git a/kernel/arch/sh/boards/mach-hdk7108/setup.c b/kernel/arch/sh/boards/mach-hdk7108/setup.c
index a6eb23f..4ca23a7 100644
--- a/kernel/arch/sh/boards/mach-hdk7108/setup.c
+++ b/kernel/arch/sh/boards/mach-hdk7108/setup.c
@@ -173,7 +173,7 @@ static int hdk7108_phy_reset(void *bus)
                gpio_set_value(HDK7108_PIO_POWER_ON_ETHERNET, 0);
                udelay(10000); /* 10 miliseconds is enough for everyone ;-) */
                gpio_set_value(HDK7108_PIO_POWER_ON_ETHERNET, 1);
-               done = 1;
+               //done = 1;
        }
 
        return 1;
diff --git a/kernel/drivers/net/stmmac/stmmac_main.c b/kernel/drivers/net/stmmac/stmmac_main.c
index 9da578c..ce64b18 100644
--- a/kernel/drivers/net/stmmac/stmmac_main.c
+++ b/kernel/drivers/net/stmmac/stmmac_main.c
@@ -1030,6 +1030,12 @@ static int _stmmac_open(struct net_device *dev, bool resuming)
        priv->dma_buf_sz = STMMAC_ALIGN(buf_sz);
        init_dma_desc_rings(dev);
 
+       /* HW reset because SW reset sometimes fails */
+        if (priv->plat->mdio_bus_data->phy_reset) {
+                pr_debug("stmmac_mdio_reset: calling phy_reset\n");
+                priv->plat->mdio_bus_data->phy_reset(priv->plat->bsp_priv);
+       }
+
        /* DMA initialization and SW reset */
        ret = priv->hw->dma->init(priv->ioaddr, priv->plat->pbl,
                                  priv->dma_tx_phy, priv->dma_rx_phy);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment