問題描述:
兩個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模式,不然工作不穩定。