Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d700d264 authored by David S. Miller's avatar David S. Miller
Browse files

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: default avatarDavid S. Miller <davem@davemloft.net>
parents 2441ba48 2e779ddb
Loading
Loading
Loading
Loading
+24 −148
Original line number Diff line number Diff line
@@ -733,6 +733,13 @@ static bool rtl_is_8168evl_up(struct rtl8169_private *tp)
	       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 {
	bool (*check)(struct rtl8169_private *);
	const char *msg;
@@ -1945,144 +1952,40 @@ static int rtl_set_coalesce(struct net_device *dev, struct ethtool_coalesce *ec)
	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)
{
	struct rtl8169_private *tp = netdev_priv(dev);
	struct device *d = tp_to_dev(tp);
	int ret;

	if (!rtl_supports_eee(tp))
		return -EOPNOTSUPP;

	pm_runtime_get_noresume(d);

	if (!pm_runtime_active(d)) {
		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);
	return ret < 0 ? ret : 0;

	return ret;
}

static int rtl8169_set_eee(struct net_device *dev, struct ethtool_eee *data)
{
	struct rtl8169_private *tp = netdev_priv(dev);
	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);

	if (!dev->phydev || !pm_runtime_active(d)) {
	if (!pm_runtime_active(d)) {
		ret = -EOPNOTSUPP;
		goto out;
	}
@@ -2093,38 +1996,10 @@ static int rtl8169_set_eee(struct net_device *dev, struct ethtool_eee *data)
		goto out;
	}

	/* Get Supported EEE */
	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);
	}

	ret = phy_ethtool_set_eee(tp->phydev, data);
out:
	pm_runtime_put_noidle(d);
	return ret < 0 ? ret : 0;
	return ret;
}

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)
{
	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)
		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)
+43 −0
Original line number Diff line number Diff line
@@ -266,6 +266,45 @@ static int rtl8366rb_config_init(struct phy_device *phydev)
	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)
{
	int val;
@@ -422,6 +461,8 @@ static struct phy_driver realtek_drvs[] = {
		.resume		= genphy_resume,
		.read_page	= rtl821x_read_page,
		.write_page	= rtl821x_write_page,
		.read_mmd	= rtlgen_read_mmd,
		.write_mmd	= rtlgen_write_mmd,
	}, {
		.name		= "RTL8125 2.5Gbps internal",
		.match_phy_device = rtl8125_match_phy_device,
@@ -432,6 +473,8 @@ static struct phy_driver realtek_drvs[] = {
		.resume		= genphy_resume,
		.read_page	= rtl821x_read_page,
		.write_page	= rtl821x_write_page,
		.read_mmd	= rtlgen_read_mmd,
		.write_mmd	= rtlgen_write_mmd,
	}, {
		PHY_ID_MATCH_EXACT(0x001cc961),
		.name		= "RTL8366RB Gigabit Ethernet",