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:
Родитель
2c4b58dc75
Коммит
d445dff2df
|
@ -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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче