Commit d445dff2 authored by Heiner Kallweit's avatar Heiner Kallweit Committed by David S. Miller

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: default avatarHeiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2c4b58dc
...@@ -49,6 +49,8 @@ ...@@ -49,6 +49,8 @@
#define RTL_LPADV_5000FULL BIT(6) #define RTL_LPADV_5000FULL BIT(6)
#define RTL_LPADV_2500FULL BIT(5) #define RTL_LPADV_2500FULL BIT(5)
#define RTLGEN_SPEED_MASK 0x0630
#define RTL_GENERIC_PHYID 0x001cc800 #define RTL_GENERIC_PHYID 0x001cc800
MODULE_DESCRIPTION("Realtek PHY driver"); MODULE_DESCRIPTION("Realtek PHY driver");
...@@ -309,6 +311,55 @@ static int rtl8366rb_config_init(struct phy_device *phydev) ...@@ -309,6 +311,55 @@ static int rtl8366rb_config_init(struct phy_device *phydev)
return ret; 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) static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
{ {
int ret; int ret;
...@@ -429,6 +480,8 @@ static int rtl8125_config_aneg(struct phy_device *phydev) ...@@ -429,6 +480,8 @@ static int rtl8125_config_aneg(struct phy_device *phydev)
static int rtl8125_read_status(struct phy_device *phydev) static int rtl8125_read_status(struct phy_device *phydev)
{ {
int ret;
if (phydev->autoneg == AUTONEG_ENABLE) { if (phydev->autoneg == AUTONEG_ENABLE) {
int lpadv = phy_read_paged(phydev, 0xa5d, 0x13); int lpadv = phy_read_paged(phydev, 0xa5d, 0x13);
...@@ -443,7 +496,11 @@ static int rtl8125_read_status(struct phy_device *phydev) ...@@ -443,7 +496,11 @@ static int rtl8125_read_status(struct phy_device *phydev)
phydev->lp_advertising, lpadv & RTL_LPADV_2500FULL); 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) static bool rtlgen_supports_2_5gbps(struct phy_device *phydev)
...@@ -550,6 +607,7 @@ static struct phy_driver realtek_drvs[] = { ...@@ -550,6 +607,7 @@ static struct phy_driver realtek_drvs[] = {
}, { }, {
.name = "Generic FE-GE Realtek PHY", .name = "Generic FE-GE Realtek PHY",
.match_phy_device = rtlgen_match_phy_device, .match_phy_device = rtlgen_match_phy_device,
.read_status = rtlgen_read_status,
.suspend = genphy_suspend, .suspend = genphy_suspend,
.resume = genphy_resume, .resume = genphy_resume,
.read_page = rtl821x_read_page, .read_page = rtl821x_read_page,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment