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

Merge branch 'ethtool-add-support-for-Fast-Link-Down-as-new-PHY-tunable'



Heiner Kallweit says:

====================
ethtool: add support for Fast Link Down as new PHY tunable

This adds support for Fast Link Down as new PHY tunable.
Fast Link Down reduces the time until a link down event is reported
for 1000BaseT. According to the standard it's 750ms what is too long
for several use cases.

This is the kernel-related series, the ethtool userspace extension
I'd submit once the kernel part has been applied.

v2:
- add describing comment in patch 1
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 7b7ed885 69f42be8
Loading
Loading
Loading
Loading
+108 −0
Original line number Diff line number Diff line
@@ -29,6 +29,7 @@
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <linux/marvell_phy.h>
#include <linux/bitfield.h>
#include <linux/of.h>

#include <linux/io.h>
@@ -91,6 +92,14 @@
#define MII_88E1510_TEMP_SENSOR		0x1b
#define MII_88E1510_TEMP_SENSOR_MASK	0xff

#define MII_88E1540_COPPER_CTRL3	0x1a
#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK	GENMASK(11, 10)
#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS	0
#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS	1
#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS	2
#define MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS	3
#define MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN		BIT(9)

#define MII_88E6390_MISC_TEST		0x1b
#define MII_88E6390_MISC_TEST_SAMPLE_1S		0
#define MII_88E6390_MISC_TEST_SAMPLE_10MS	BIT(14)
@@ -1025,6 +1034,101 @@ static int m88e1145_config_init(struct phy_device *phydev)
	return 0;
}

static int m88e1540_get_fld(struct phy_device *phydev, u8 *msecs)
{
	int val;

	val = phy_read(phydev, MII_88E1540_COPPER_CTRL3);
	if (val < 0)
		return val;

	if (!(val & MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN)) {
		*msecs = ETHTOOL_PHY_FAST_LINK_DOWN_OFF;
		return 0;
	}

	val = FIELD_GET(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);

	switch (val) {
	case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS:
		*msecs = 0;
		break;
	case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS:
		*msecs = 10;
		break;
	case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS:
		*msecs = 20;
		break;
	case MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS:
		*msecs = 40;
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static int m88e1540_set_fld(struct phy_device *phydev, const u8 *msecs)
{
	struct ethtool_eee eee;
	int val, ret;

	if (*msecs == ETHTOOL_PHY_FAST_LINK_DOWN_OFF)
		return phy_clear_bits(phydev, MII_88E1540_COPPER_CTRL3,
				      MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN);

	/* According to the Marvell data sheet EEE must be disabled for
	 * Fast Link Down detection to work properly
	 */
	ret = phy_ethtool_get_eee(phydev, &eee);
	if (!ret && eee.eee_enabled) {
		phydev_warn(phydev, "Fast Link Down detection requires EEE to be disabled!\n");
		return -EBUSY;
	}

	if (*msecs <= 5)
		val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_00MS;
	else if (*msecs <= 15)
		val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_10MS;
	else if (*msecs <= 30)
		val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_20MS;
	else
		val = MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_40MS;

	val = FIELD_PREP(MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);

	ret = phy_modify(phydev, MII_88E1540_COPPER_CTRL3,
			 MII_88E1540_COPPER_CTRL3_LINK_DOWN_DELAY_MASK, val);
	if (ret)
		return ret;

	return phy_set_bits(phydev, MII_88E1540_COPPER_CTRL3,
			    MII_88E1540_COPPER_CTRL3_FAST_LINK_DOWN);
}

static int m88e1540_get_tunable(struct phy_device *phydev,
				struct ethtool_tunable *tuna, void *data)
{
	switch (tuna->id) {
	case ETHTOOL_PHY_FAST_LINK_DOWN:
		return m88e1540_get_fld(phydev, data);
	default:
		return -EOPNOTSUPP;
	}
}

static int m88e1540_set_tunable(struct phy_device *phydev,
				struct ethtool_tunable *tuna, const void *data)
{
	switch (tuna->id) {
	case ETHTOOL_PHY_FAST_LINK_DOWN:
		return m88e1540_set_fld(phydev, data);
	default:
		return -EOPNOTSUPP;
	}
}

/* The VOD can be out of specification on link up. Poke an
 * undocumented register, in an undocumented page, with a magic value
 * to fix this.
@@ -2247,6 +2351,8 @@ static struct phy_driver marvell_drivers[] = {
		.get_sset_count = marvell_get_sset_count,
		.get_strings = marvell_get_strings,
		.get_stats = marvell_get_stats,
		.get_tunable = m88e1540_get_tunable,
		.set_tunable = m88e1540_set_tunable,
	},
	{
		.phy_id = MARVELL_PHY_ID_88E1545,
@@ -2307,6 +2413,8 @@ static struct phy_driver marvell_drivers[] = {
		.get_sset_count = marvell_get_sset_count,
		.get_strings = marvell_get_strings,
		.get_stats = marvell_get_stats,
		.get_tunable = m88e1540_get_tunable,
		.set_tunable = m88e1540_set_tunable,
	},
};

+8 −0
Original line number Diff line number Diff line
@@ -252,9 +252,17 @@ struct ethtool_tunable {
#define DOWNSHIFT_DEV_DEFAULT_COUNT	0xff
#define DOWNSHIFT_DEV_DISABLE		0

/* Time in msecs after which link is reported as down
 * 0 = lowest time supported by the PHY
 * 0xff = off, link down detection according to standard
 */
#define ETHTOOL_PHY_FAST_LINK_DOWN_ON	0
#define ETHTOOL_PHY_FAST_LINK_DOWN_OFF	0xff

enum phy_tunable_id {
	ETHTOOL_PHY_ID_UNSPEC,
	ETHTOOL_PHY_DOWNSHIFT,
	ETHTOOL_PHY_FAST_LINK_DOWN,
	/*
	 * Add your fresh new phy tunable attribute above and remember to update
	 * phy_tunable_strings[] in net/core/ethtool.c
+2 −0
Original line number Diff line number Diff line
@@ -136,6 +136,7 @@ static const char
phy_tunable_strings[__ETHTOOL_PHY_TUNABLE_COUNT][ETH_GSTRING_LEN] = {
	[ETHTOOL_ID_UNSPEC]     = "Unspec",
	[ETHTOOL_PHY_DOWNSHIFT]	= "phy-downshift",
	[ETHTOOL_PHY_FAST_LINK_DOWN] = "phy-fast-link-down",
};

static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
@@ -2432,6 +2433,7 @@ static int ethtool_phy_tunable_valid(const struct ethtool_tunable *tuna)
{
	switch (tuna->id) {
	case ETHTOOL_PHY_DOWNSHIFT:
	case ETHTOOL_PHY_FAST_LINK_DOWN:
		if (tuna->len != sizeof(u8) ||
		    tuna->type_id != ETHTOOL_TUNABLE_U8)
			return -EINVAL;