net: phy: Add PHY_RTL8211E_PINE64_GIGABIT_FIX for realtek phys
authorkevans@FreeBSD.org <kevans@FreeBSD.org>
Wed, 14 Feb 2018 23:02:15 +0000 (17:02 -0600)
committerJoe Hershberger <joe.hershberger@ni.com>
Thu, 22 Mar 2018 20:05:27 +0000 (15:05 -0500)
Setting PHY_RTL8211E_PINE64_GIGABIT_FIX forces internal rx/tx delays off
on the PHY, as well as flipping some magical undocumented bits. The
magic number comes from the Pine64 engineering team, presumably as a
proxy from Realtek. This configuration fixes the throughput on some
Pine64 models. Packet loss of up to 60-70% has been observed without
this.

Signed-off-by: Kyle Evans <kevans@FreeBSD.org>
Acked-by: Joe Hershberger <joe.hershberger@ni.com>
drivers/net/phy/Kconfig
drivers/net/phy/realtek.c

index 25de3fb2266586bd2b234f81dda702fd68e95a2d..179e0418bca73f683929f1f5257e2e0ddc34bb2e 100644 (file)
@@ -139,6 +139,16 @@ config PHY_NATSEMI
 config PHY_REALTEK
        bool "Realtek Ethernet PHYs support"
 
+config RTL8211E_PINE64_GIGABIT_FIX
+       bool "Fix gigabit throughput on some Pine64+ models"
+       depends on PHY_REALTEK
+       help
+         Configure the Realtek RTL8211E found on some Pine64+ models differently to
+         fix throughput on Gigabit links, turning off all internal delays in the
+         process. The settings that this touches are not documented in the CONFREG
+         section of the RTL8211E datasheet, but come from Realtek by way of the
+         Pine64 engineering team.
+
 config RTL8211X_PHY_FORCE_MASTER
        bool "Ethernet PHY RTL8211x: force 1000BASE-T master mode"
        depends on PHY_REALTEK
index 6d917f86f44d21537ffdd228316ec7e9ee86f9dc..d5c2a46c67e2b272644419cb96cfab8209a612c7 100644 (file)
@@ -13,6 +13,7 @@
 #include <phy.h>
 
 #define PHY_RTL8211x_FORCE_MASTER BIT(1)
+#define PHY_RTL8211E_PINE64_GIGABIT_FIX BIT(2)
 
 #define PHY_AUTONEGOTIATE_TIMEOUT 5000
 
 #define MIIM_RTL8211F_PHYSTAT_SPDDONE  0x0800
 #define MIIM_RTL8211F_PHYSTAT_LINK     0x0004
 
+#define MIIM_RTL8211E_CONFREG           0x1c
+#define MIIM_RTL8211E_CONFREG_TXD              0x0002
+#define MIIM_RTL8211E_CONFREG_RXD              0x0004
+#define MIIM_RTL8211E_CONFREG_MAGIC            0xb400  /* Undocumented */
+
+#define MIIM_RTL8211E_EXT_PAGE_SELECT  0x1e
+
 #define MIIM_RTL8211F_PAGE_SELECT      0x1f
 #define MIIM_RTL8211F_TX_DELAY         0x100
 #define MIIM_RTL8211F_LCR              0x10
@@ -60,6 +68,15 @@ static int rtl8211b_probe(struct phy_device *phydev)
        return 0;
 }
 
+static int rtl8211e_probe(struct phy_device *phydev)
+{
+#ifdef CONFIG_RTL8211E_PINE64_GIGABIT_FIX
+       phydev->flags |= PHY_RTL8211E_PINE64_GIGABIT_FIX;
+#endif
+
+       return 0;
+}
+
 /* RealTek RTL8211x */
 static int rtl8211x_config(struct phy_device *phydev)
 {
@@ -81,6 +98,22 @@ static int rtl8211x_config(struct phy_device *phydev)
                reg |= MIIM_RTL8211x_CTRL1000T_MASTER;
                phy_write(phydev, MDIO_DEVAD_NONE, MII_CTRL1000, reg);
        }
+       if (phydev->flags & PHY_RTL8211E_PINE64_GIGABIT_FIX) {
+               unsigned int reg;
+
+               phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT,
+                         7);
+               phy_write(phydev, MDIO_DEVAD_NONE,
+                         MIIM_RTL8211E_EXT_PAGE_SELECT, 0xa4);
+               reg = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG);
+               /* Ensure both internal delays are turned off */
+               reg &= ~(MIIM_RTL8211E_CONFREG_TXD | MIIM_RTL8211E_CONFREG_RXD);
+               /* Flip the magic undocumented bits */
+               reg |= MIIM_RTL8211E_CONFREG_MAGIC;
+               phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211E_CONFREG, reg);
+               phy_write(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211F_PAGE_SELECT,
+                         0);
+       }
        /* read interrupt status just to clear it */
        phy_read(phydev, MDIO_DEVAD_NONE, MIIM_RTL8211x_PHY_INER);
 
@@ -279,6 +312,7 @@ static struct phy_driver RTL8211E_driver = {
        .uid = 0x1cc915,
        .mask = 0xffffff,
        .features = PHY_GBIT_FEATURES,
+       .probe = &rtl8211e_probe,
        .config = &rtl8211x_config,
        .startup = &rtl8211e_startup,
        .shutdown = &genphy_shutdown,