forked from Minki/linux
Merge branch 'realtek-EEE'
Heiner Kallweit says: ==================== net: phy: realtek: map vendor-specific EEE registers to standard MMD registers EEE-related registers on newer integrated PHY's have the standard layout, but are accessible not via MMD but via vendor-specific registers. Emulating the standard MMD registers allows to use the generic functions for EEE control and to significantly simplify the r8169 driver. v2: - rebase patch 2 ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
d700d26418
@ -733,6 +733,13 @@ static bool rtl_is_8168evl_up(struct rtl8169_private *tp)
|
|||||||
tp->mac_version != RTL_GIGA_MAC_VER_39;
|
tp->mac_version != RTL_GIGA_MAC_VER_39;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool rtl_supports_eee(struct rtl8169_private *tp)
|
||||||
|
{
|
||||||
|
return tp->mac_version >= RTL_GIGA_MAC_VER_34 &&
|
||||||
|
tp->mac_version != RTL_GIGA_MAC_VER_37 &&
|
||||||
|
tp->mac_version != RTL_GIGA_MAC_VER_39;
|
||||||
|
}
|
||||||
|
|
||||||
struct rtl_cond {
|
struct rtl_cond {
|
||||||
bool (*check)(struct rtl8169_private *);
|
bool (*check)(struct rtl8169_private *);
|
||||||
const char *msg;
|
const char *msg;
|
||||||
@ -1945,144 +1952,40 @@ static int rtl_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rtl_get_eee_supp(struct rtl8169_private *tp)
|
|
||||||
{
|
|
||||||
struct phy_device *phydev = tp->phydev;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
switch (tp->mac_version) {
|
|
||||||
case RTL_GIGA_MAC_VER_34:
|
|
||||||
case RTL_GIGA_MAC_VER_35:
|
|
||||||
case RTL_GIGA_MAC_VER_36:
|
|
||||||
case RTL_GIGA_MAC_VER_38:
|
|
||||||
ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE);
|
|
||||||
break;
|
|
||||||
case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
|
|
||||||
ret = phy_read_paged(phydev, 0x0a5c, 0x12);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = -EPROTONOSUPPORT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int rtl_get_eee_lpadv(struct rtl8169_private *tp)
|
|
||||||
{
|
|
||||||
struct phy_device *phydev = tp->phydev;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
switch (tp->mac_version) {
|
|
||||||
case RTL_GIGA_MAC_VER_34:
|
|
||||||
case RTL_GIGA_MAC_VER_35:
|
|
||||||
case RTL_GIGA_MAC_VER_36:
|
|
||||||
case RTL_GIGA_MAC_VER_38:
|
|
||||||
ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_LPABLE);
|
|
||||||
break;
|
|
||||||
case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
|
|
||||||
ret = phy_read_paged(phydev, 0x0a5d, 0x11);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = -EPROTONOSUPPORT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int rtl_get_eee_adv(struct rtl8169_private *tp)
|
|
||||||
{
|
|
||||||
struct phy_device *phydev = tp->phydev;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
switch (tp->mac_version) {
|
|
||||||
case RTL_GIGA_MAC_VER_34:
|
|
||||||
case RTL_GIGA_MAC_VER_35:
|
|
||||||
case RTL_GIGA_MAC_VER_36:
|
|
||||||
case RTL_GIGA_MAC_VER_38:
|
|
||||||
ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV);
|
|
||||||
break;
|
|
||||||
case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
|
|
||||||
ret = phy_read_paged(phydev, 0x0a5d, 0x10);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = -EPROTONOSUPPORT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int rtl_set_eee_adv(struct rtl8169_private *tp, int val)
|
|
||||||
{
|
|
||||||
struct phy_device *phydev = tp->phydev;
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
switch (tp->mac_version) {
|
|
||||||
case RTL_GIGA_MAC_VER_34:
|
|
||||||
case RTL_GIGA_MAC_VER_35:
|
|
||||||
case RTL_GIGA_MAC_VER_36:
|
|
||||||
case RTL_GIGA_MAC_VER_38:
|
|
||||||
ret = phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val);
|
|
||||||
break;
|
|
||||||
case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_51:
|
|
||||||
phy_write_paged(phydev, 0x0a5d, 0x10, val);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret = -EPROTONOSUPPORT;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int rtl8169_get_eee(struct net_device *dev, struct ethtool_eee *data)
|
static int rtl8169_get_eee(struct net_device *dev, struct ethtool_eee *data)
|
||||||
{
|
{
|
||||||
struct rtl8169_private *tp = netdev_priv(dev);
|
struct rtl8169_private *tp = netdev_priv(dev);
|
||||||
struct device *d = tp_to_dev(tp);
|
struct device *d = tp_to_dev(tp);
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
if (!rtl_supports_eee(tp))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
pm_runtime_get_noresume(d);
|
pm_runtime_get_noresume(d);
|
||||||
|
|
||||||
if (!pm_runtime_active(d)) {
|
if (!pm_runtime_active(d)) {
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
goto out;
|
} else {
|
||||||
|
ret = phy_ethtool_get_eee(tp->phydev, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get Supported EEE */
|
|
||||||
ret = rtl_get_eee_supp(tp);
|
|
||||||
if (ret < 0)
|
|
||||||
goto out;
|
|
||||||
data->supported = mmd_eee_cap_to_ethtool_sup_t(ret);
|
|
||||||
|
|
||||||
/* Get advertisement EEE */
|
|
||||||
ret = rtl_get_eee_adv(tp);
|
|
||||||
if (ret < 0)
|
|
||||||
goto out;
|
|
||||||
data->advertised = mmd_eee_adv_to_ethtool_adv_t(ret);
|
|
||||||
data->eee_enabled = !!data->advertised;
|
|
||||||
|
|
||||||
/* Get LP advertisement EEE */
|
|
||||||
ret = rtl_get_eee_lpadv(tp);
|
|
||||||
if (ret < 0)
|
|
||||||
goto out;
|
|
||||||
data->lp_advertised = mmd_eee_adv_to_ethtool_adv_t(ret);
|
|
||||||
data->eee_active = !!(data->advertised & data->lp_advertised);
|
|
||||||
out:
|
|
||||||
pm_runtime_put_noidle(d);
|
pm_runtime_put_noidle(d);
|
||||||
return ret < 0 ? ret : 0;
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int rtl8169_set_eee(struct net_device *dev, struct ethtool_eee *data)
|
static int rtl8169_set_eee(struct net_device *dev, struct ethtool_eee *data)
|
||||||
{
|
{
|
||||||
struct rtl8169_private *tp = netdev_priv(dev);
|
struct rtl8169_private *tp = netdev_priv(dev);
|
||||||
struct device *d = tp_to_dev(tp);
|
struct device *d = tp_to_dev(tp);
|
||||||
int old_adv, adv = 0, cap, ret;
|
int ret;
|
||||||
|
|
||||||
|
if (!rtl_supports_eee(tp))
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
|
||||||
pm_runtime_get_noresume(d);
|
pm_runtime_get_noresume(d);
|
||||||
|
|
||||||
if (!dev->phydev || !pm_runtime_active(d)) {
|
if (!pm_runtime_active(d)) {
|
||||||
ret = -EOPNOTSUPP;
|
ret = -EOPNOTSUPP;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
@ -2093,38 +1996,10 @@ static int rtl8169_set_eee(struct net_device *dev, struct ethtool_eee *data)
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get Supported EEE */
|
ret = phy_ethtool_set_eee(tp->phydev, data);
|
||||||
ret = rtl_get_eee_supp(tp);
|
|
||||||
if (ret < 0)
|
|
||||||
goto out;
|
|
||||||
cap = ret;
|
|
||||||
|
|
||||||
ret = rtl_get_eee_adv(tp);
|
|
||||||
if (ret < 0)
|
|
||||||
goto out;
|
|
||||||
old_adv = ret;
|
|
||||||
|
|
||||||
if (data->eee_enabled) {
|
|
||||||
adv = !data->advertised ? cap :
|
|
||||||
ethtool_adv_to_mmd_eee_adv_t(data->advertised) & cap;
|
|
||||||
/* Mask prohibited EEE modes */
|
|
||||||
adv &= ~dev->phydev->eee_broken_modes;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (old_adv != adv) {
|
|
||||||
ret = rtl_set_eee_adv(tp, adv);
|
|
||||||
if (ret < 0)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* Restart autonegotiation so the new modes get sent to the
|
|
||||||
* link partner.
|
|
||||||
*/
|
|
||||||
ret = phy_restart_aneg(dev->phydev);
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
pm_runtime_put_noidle(d);
|
pm_runtime_put_noidle(d);
|
||||||
return ret < 0 ? ret : 0;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct ethtool_ops rtl8169_ethtool_ops = {
|
static const struct ethtool_ops rtl8169_ethtool_ops = {
|
||||||
@ -2151,10 +2026,11 @@ static const struct ethtool_ops rtl8169_ethtool_ops = {
|
|||||||
|
|
||||||
static void rtl_enable_eee(struct rtl8169_private *tp)
|
static void rtl_enable_eee(struct rtl8169_private *tp)
|
||||||
{
|
{
|
||||||
int supported = rtl_get_eee_supp(tp);
|
struct phy_device *phydev = tp->phydev;
|
||||||
|
int supported = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE);
|
||||||
|
|
||||||
if (supported > 0)
|
if (supported > 0)
|
||||||
rtl_set_eee_adv(tp, supported);
|
phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, supported);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rtl8169_get_mac_version(struct rtl8169_private *tp)
|
static void rtl8169_get_mac_version(struct rtl8169_private *tp)
|
||||||
|
@ -266,6 +266,45 @@ static int rtl8366rb_config_init(struct phy_device *phydev)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int rtlgen_read_mmd(struct phy_device *phydev, int devnum, u16 regnum)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (devnum == MDIO_MMD_PCS && regnum == MDIO_PCS_EEE_ABLE) {
|
||||||
|
rtl821x_write_page(phydev, 0xa5c);
|
||||||
|
ret = __phy_read(phydev, 0x12);
|
||||||
|
rtl821x_write_page(phydev, 0);
|
||||||
|
} else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) {
|
||||||
|
rtl821x_write_page(phydev, 0xa5d);
|
||||||
|
ret = __phy_read(phydev, 0x10);
|
||||||
|
rtl821x_write_page(phydev, 0);
|
||||||
|
} else if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_LPABLE) {
|
||||||
|
rtl821x_write_page(phydev, 0xa5d);
|
||||||
|
ret = __phy_read(phydev, 0x11);
|
||||||
|
rtl821x_write_page(phydev, 0);
|
||||||
|
} else {
|
||||||
|
ret = -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int rtlgen_write_mmd(struct phy_device *phydev, int devnum, u16 regnum,
|
||||||
|
u16 val)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (devnum == MDIO_MMD_AN && regnum == MDIO_AN_EEE_ADV) {
|
||||||
|
rtl821x_write_page(phydev, 0xa5d);
|
||||||
|
ret = __phy_write(phydev, 0x10, val);
|
||||||
|
rtl821x_write_page(phydev, 0);
|
||||||
|
} else {
|
||||||
|
ret = -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int rtl8125_get_features(struct phy_device *phydev)
|
static int rtl8125_get_features(struct phy_device *phydev)
|
||||||
{
|
{
|
||||||
int val;
|
int val;
|
||||||
@ -422,6 +461,8 @@ static struct phy_driver realtek_drvs[] = {
|
|||||||
.resume = genphy_resume,
|
.resume = genphy_resume,
|
||||||
.read_page = rtl821x_read_page,
|
.read_page = rtl821x_read_page,
|
||||||
.write_page = rtl821x_write_page,
|
.write_page = rtl821x_write_page,
|
||||||
|
.read_mmd = rtlgen_read_mmd,
|
||||||
|
.write_mmd = rtlgen_write_mmd,
|
||||||
}, {
|
}, {
|
||||||
.name = "RTL8125 2.5Gbps internal",
|
.name = "RTL8125 2.5Gbps internal",
|
||||||
.match_phy_device = rtl8125_match_phy_device,
|
.match_phy_device = rtl8125_match_phy_device,
|
||||||
@ -432,6 +473,8 @@ static struct phy_driver realtek_drvs[] = {
|
|||||||
.resume = genphy_resume,
|
.resume = genphy_resume,
|
||||||
.read_page = rtl821x_read_page,
|
.read_page = rtl821x_read_page,
|
||||||
.write_page = rtl821x_write_page,
|
.write_page = rtl821x_write_page,
|
||||||
|
.read_mmd = rtlgen_read_mmd,
|
||||||
|
.write_mmd = rtlgen_write_mmd,
|
||||||
}, {
|
}, {
|
||||||
PHY_ID_MATCH_EXACT(0x001cc961),
|
PHY_ID_MATCH_EXACT(0x001cc961),
|
||||||
.name = "RTL8366RB Gigabit Ethernet",
|
.name = "RTL8366RB Gigabit Ethernet",
|
||||||
|
Loading…
Reference in New Issue
Block a user