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>
This commit is contained in:
kevans@FreeBSD.org 2018-02-14 17:02:15 -06:00 committed by Joe Hershberger
parent 2511930193
commit 66526e7038
2 changed files with 44 additions and 0 deletions

View 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

View 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
@ -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,