net: phy: realtek: read actual speed to detect downshift

At least some integrated PHY's in RTL8168/RTL8125 chip versions support
downshift, and the actual link speed can be read from a vendor-specific
register. Info about this register was provided by Realtek.
More details about downshift configuration (e.g. number of attempts)
aren't available, therefore the downshift tunable is not implemented.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Heiner Kallweit 2020-03-18 23:07:24 +01:00 committed by David S. Miller
parent 2c4b58dc75
commit d445dff2df

View File

@ -49,6 +49,8 @@
#define RTL_LPADV_5000FULL BIT(6)
#define RTL_LPADV_2500FULL BIT(5)
#define RTLGEN_SPEED_MASK 0x0630
#define RTL_GENERIC_PHYID 0x001cc800
MODULE_DESCRIPTION("Realtek PHY driver");
@ -309,6 +311,55 @@ static int rtl8366rb_config_init(struct phy_device *phydev)
return ret;
}
/* get actual speed to cover the downshift case */
static int rtlgen_get_speed(struct phy_device *phydev)
{
int val;
if (!phydev->link)
return 0;
val = phy_read_paged(phydev, 0xa43, 0x12);
if (val < 0)
return val;
switch (val & RTLGEN_SPEED_MASK) {
case 0x0000:
phydev->speed = SPEED_10;
break;
case 0x0010:
phydev->speed = SPEED_100;
break;
case 0x0020:
phydev->speed = SPEED_1000;
break;
case 0x0200:
phydev->speed = SPEED_10000;
break;
case 0x0210:
phydev->speed = SPEED_2500;
break;
case 0x0220:
phydev->speed = SPEED_5000;
break;
default:
break;
}
return 0;
}
static int rtlgen_read_status(struct phy_device *phydev)
{
int ret;
ret = genphy_read_status(phydev);
if (ret < 0)
return ret;
return rtlgen_get_speed(phydev);
}
static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
{
int ret;
@ -429,6 +480,8 @@ static int rtl8125_config_aneg(struct phy_device *phydev)
static int rtl8125_read_status(struct phy_device *phydev)
{
int ret;
if (phydev->autoneg == AUTONEG_ENABLE) {
int lpadv = phy_read_paged(phydev, 0xa5d, 0x13);
@ -443,7 +496,11 @@ static int rtl8125_read_status(struct phy_device *phydev)
phydev->lp_advertising, lpadv & RTL_LPADV_2500FULL);
}
return genphy_read_status(phydev);
ret = genphy_read_status(phydev);
if (ret < 0)
return ret;
return rtlgen_get_speed(phydev);
}
static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
@ -550,6 +607,7 @@ static struct phy_driver realtek_drvs[] = {
}, {
.name = "Generic FE-GE Realtek PHY",
.match_phy_device = rtlgen_match_phy_device,
.read_status = rtlgen_read_status,
.suspend = genphy_suspend,
.resume = genphy_resume,
.read_page = rtl821x_read_page,