summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkevans@FreeBSD.org <kevans@FreeBSD.org>2018-02-14 17:02:15 -0600
committerJoe Hershberger <joe.hershberger@ni.com>2018-03-22 15:05:27 -0500
commit66526e70381dbaad58533cfbd7bce07c668205c6 (patch)
treec37d3a1d4fd93dbe5f35d6a0f357ca127f12531e
parent2511930193a420eb8bb6cfa9c60912626f68ae67 (diff)
net: phy: Add PHY_RTL8211E_PINE64_GIGABIT_FIX for realtek phys
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>
-rw-r--r--drivers/net/phy/Kconfig10
-rw-r--r--drivers/net/phy/realtek.c34
2 files changed, 44 insertions, 0 deletions
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 25de3fb226..179e0418bc 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -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
diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c
index 6d917f86f4..d5c2a46c67 100644
--- a/drivers/net/phy/realtek.c
+++ b/drivers/net/phy/realtek.c
@@ -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
@@ -47,6 +48,13 @@
#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,