Ambarella 平台KSZ9031網卡芯片協商失敗


問題描述:

  兩個ambarella peanut板子的網口之間用網線直連,會發現不能自動協商成功(網口燈不亮),但是ambarella peanut板子的網口和其他X86 Linux機器網口直連可以協商成功(網口燈亮)。

  對於想使用peanut板子網口作LAN口,給其他peanut 板子DHCP分配IP地址會失敗。

問題分析

  1. 查看ambarella peanut平台驅動 kernel/linux-4.4/drivers/net/ethernet/ambarella/ambarella_eth.c  對網卡芯片 KSZ9031 做了哪些 MDIO 讀寫,關於MDIO定義看此篇博客:MDC/MDIO接口定義

static int ambhw_mdio_write(struct mii_bus *bus,
        int mii_id, int regnum, u16 value)
{
        int ret_val = 0;
        struct ambeth_info *lp;
        int val;
        int cnt = 0;

        lp = (struct ambeth_info *)bus->priv;

        printk("MII Write: reg[0x%.2x], val[0x%.4x].\n",
                        regnum, value); //添加的打印MDIO寫了哪些寄存器,寫了哪些值
        if (netif_msg_hw(lp))
                dev_info(&lp->ndev->dev,
                        "MII Write: id[0x%02x], add[0x%02x], val[0x%04x].\n",
                        mii_id, regnum, value);

        for (cnt = AMBETH_MII_RETRY_CNT; cnt > 0; cnt--) {
                val = readl_relaxed(lp->regbase + ETH_MAC_GMII_ADDR_OFFSET);
                if (!(val & ETH_MAC_GMII_ADDR_GB))
                        break;
                udelay(10);
        }
        if ((cnt <= 0) && netif_msg_hw(lp)) {
                dev_err(&lp->ndev->dev, "MII Error: Prewrite tmo!\n");
                ret_val = -EIO;
                goto ambhw_mdio_write_exit;
        }

        val = value;
        writel_relaxed(val, lp->regbase + ETH_MAC_GMII_DATA_OFFSET); //把要寫到網卡芯片寄存器的值寫到ambarella SoC芯片的 lp->regbase+ETH_MAC_GMII_DATA_OFFSET 寄存器里
        val = ETH_MAC_GMII_ADDR_PA(mii_id) | ETH_MAC_GMII_ADDR_GR(regnum);
        val |= ETH_MAC_GMII_ADDR_CR_250_300MHZ | ETH_MAC_GMII_ADDR_GW |
                ETH_MAC_GMII_ADDR_GB;
        writel_relaxed(val, lp->regbase + ETH_MAC_GMII_ADDR_OFFSET); //給lp->regbase+ETH_MAC_GMII_ADDR_OFFSET寫入一些flag(包括要寫入的網卡芯片寄存器的地址)觸發 lp->regbase+ETH_MAC_GMII_DATA_OFFSET 里的值寫入到網卡芯片相關寄存器里

        for (cnt = AMBETH_MII_RETRY_CNT; cnt > 0; cnt--) {
                val = readl_relaxed(lp->regbase + ETH_MAC_GMII_ADDR_OFFSET);
                if (!(val & ETH_MAC_GMII_ADDR_GB))
                        break;
                udelay(10);
        }
        if ((cnt <= 0) && netif_msg_hw(lp)) {
                dev_err(&lp->ndev->dev, "MII Error: Postwrite tmo!\n");
                ret_val = -EIO;
                goto ambhw_mdio_write_exit;
        }

ambhw_mdio_write_exit:
        return ret_val;
}

修改后發現打印信息如下:

MII Write: reg[0x00], val[0x8000].
MII Write: reg[0x0d], val[0x0002].
MII Write: reg[0x0e], val[0x0008].
MII Write: reg[0x0d], val[0x4002].
MII Write: reg[0x0d], val[0x0002].
MII Write: reg[0x0e], val[0x0008].
MII Write: reg[0x0d], val[0x4002].
MII Write: reg[0x0e], val[0x3df6].
MII Write: reg[0x0d], val[0x0002].
MII Write: reg[0x0e], val[0x0004].
MII Write: reg[0x0d], val[0x4002].
MII Write: reg[0x0d], val[0x0002].
MII Write: reg[0x0e], val[0x0004].
MII Write: reg[0x0d], val[0x4002].
MII Write: reg[0x0e], val[0x0027].
MII Write: reg[0x0d], val[0x0002].
MII Write: reg[0x0e], val[0x0005].
MII Write: reg[0x0d], val[0x4002].
MII Write: reg[0x0e], val[0x2222].
MII Write: reg[0x0d], val[0x0000].
MII Write: reg[0x0e], val[0x0004].
MII Write: reg[0x0d], val[0x4000].
MII Write: reg[0x0e], val[0x0006].
MII Write: reg[0x0d], val[0x0000].
MII Write: reg[0x0e], val[0x0003].
MII Write: reg[0x0d], val[0x4000].
MII Write: reg[0x0e], val[0x1a80].
MII Write: reg[0x00], val[0x1340].
MII Write: reg[0x00], val[0x1140].
MII Write: reg[0x09], val[0x0300].
MII Write: reg[0x09], val[0x1300].

  對照KSZ9031 datasheet比較下來,導致問題的可疑之處定位在 MII Write: reg[0x09], val[0x1300] 上面。

   本來09H的第12位網卡默認值為0的,但被設置為1了,從哪個位置設置的呢?

  2. 為了找到在哪個地方把09H的第12位設置為1的,我找到了kernel source code里的 kernel/linux-4.4/drivers/net/phy/micrel.c ,這個驅動是microchip系列網卡芯片相關寄存器配置的地方,找到如下函數:

static int ksz9031_config_aneg(struct phy_device *phydev)
{
        u32 val;

        genphy_config_aneg(phydev);

        /* Set auto Master/Slave resolution process */
        val = phy_read(phydev, MII_CTRL1000);
        val |= 0x1000; // MII_CTRL1000宏的值就是0x9,需要把此行注釋掉
        val &= ~(0x0800);
        phy_write(phydev, MII_CTRL1000, val);

        return 0;
}

原來是在這里設置的 Enable master-slave manual configuration ,Microchip提供到kernel里的網卡驅動讓ambarella修改了,注釋掉  val |= 0x1000; 這一行,重新編譯進內核或者編譯成模塊,問題解決。

拓展

  這個問題的根本原因就是兩個peanut板子都設置成了 使能手動主從控制,導致用網線直連兩個網卡不能自動協商,其中有一個peanut板子 Disable master-slave manual configuration 都不會有這個問題, peanut板子與其他X86主板的連接也沒有這個問題;

  在問題發生后,給其中一個peanut板子的網口接到交換機上,正常識別后再拔掉網線會導致網卡 MDIO 配置的復位(9H寄存器的第12位恢復默認值0),這時候再用網線直連兩個peanut板子,是可以正常協商成功的。

  雖然這個問題解決了,但還是不知道ambarella原廠為啥做這樣的修改,在其他ambarella SoC平台里用的Realtek網卡芯片ambarella沒有做類似的修改,是為了修復什么bug? 在咨詢過microchip FAE后,得到的回復是千兆自動協商有時會遇到兼容性問題,例如某些千兆設備的連接,發現要在slave模式,或者必須工作在master模式,不然工作不穩定。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM