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

Merge branch 'phy-25g'

Maxime Chevallier says:

====================
net: phy: Add 2.5G/5GBASET PHYs support

The 802.3bz standard defines 2 modes based on the NBASET alliance work
that allow to use 2.5Gbps and 5Gbps speeds on Cat 5e, 6 and 7 cables.

This series adds the necessary infrastructure to handle these modes with
C45 PHYs. This series was originally part of a bigger one, that has
seen 2 iterations [1] [2] that added support for these modes on Marvell
Alaska PHYs.

Following some discussions with Heiner and Andrew [3], we decided to
split-out the generic parts so that we can work together on the
following steps to get these mode fully working with Aquantia and
Marvell PHYS.

The first 3 patches are reworking some of the internal network phy
infrastructure to handle the new modes in a more generic way.

The 4th patch adds all the C45 register definition and accesses that
follows the 802.3bz standard to support 2.5GBASET and 5GBASET.

[1] : https://lore.kernel.org/netdev/20190118152352.26417-1-maxime.chevallier@bootlin.com/
[2] : https://lore.kernel.org/netdev/20190207094939.27369-1-maxime.chevallier@bootlin.com/
[3] : https://lore.kernel.org/netdev/81c340ea-54b0-1abf-94af-b8dc4ee83e3a@gmail.com/


====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d2d37444 7fd8afa8
Loading
Loading
Loading
Loading
+8 −70
Original line number Diff line number Diff line
@@ -233,8 +233,7 @@ static int mv3310_resume(struct phy_device *phydev)

static int mv3310_config_init(struct phy_device *phydev)
{
	__ETHTOOL_DECLARE_LINK_MODE_MASK(supported) = { 0, };
	int val;
	int ret, val;

	/* Check that the PHY interface type is compatible */
	if (phydev->interface != PHY_INTERFACE_MODE_SGMII &&
@@ -243,8 +242,8 @@ static int mv3310_config_init(struct phy_device *phydev)
	    phydev->interface != PHY_INTERFACE_MODE_10GKR)
		return -ENODEV;

	__set_bit(ETHTOOL_LINK_MODE_Pause_BIT, supported);
	__set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, supported);
	__set_bit(ETHTOOL_LINK_MODE_Pause_BIT, phydev->supported);
	__set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, phydev->supported);

	if (phydev->c45_ids.devices_in_package & MDIO_DEVS_AN) {
		val = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_STAT1);
@@ -252,74 +251,13 @@ static int mv3310_config_init(struct phy_device *phydev)
			return val;

		if (val & MDIO_AN_STAT1_ABLE)
			__set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, supported);
	}

	val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_STAT2);
	if (val < 0)
		return val;

	/* Ethtool does not support the WAN mode bits */
	if (val & (MDIO_PMA_STAT2_10GBSR | MDIO_PMA_STAT2_10GBLR |
		   MDIO_PMA_STAT2_10GBER | MDIO_PMA_STAT2_10GBLX4 |
		   MDIO_PMA_STAT2_10GBSW | MDIO_PMA_STAT2_10GBLW |
		   MDIO_PMA_STAT2_10GBEW))
		__set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported);
	if (val & MDIO_PMA_STAT2_10GBSR)
		__set_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT, supported);
	if (val & MDIO_PMA_STAT2_10GBLR)
		__set_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT, supported);
	if (val & MDIO_PMA_STAT2_10GBER)
		__set_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT, supported);

	if (val & MDIO_PMA_STAT2_EXTABLE) {
		val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE);
		if (val < 0)
			return val;

		if (val & (MDIO_PMA_EXTABLE_10GBT | MDIO_PMA_EXTABLE_1000BT |
			   MDIO_PMA_EXTABLE_100BTX | MDIO_PMA_EXTABLE_10BT))
			__set_bit(ETHTOOL_LINK_MODE_TP_BIT, supported);
		if (val & MDIO_PMA_EXTABLE_10GBLRM)
			__set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, supported);
		if (val & (MDIO_PMA_EXTABLE_10GBKX4 | MDIO_PMA_EXTABLE_10GBKR |
			   MDIO_PMA_EXTABLE_1000BKX))
			__set_bit(ETHTOOL_LINK_MODE_Backplane_BIT, supported);
		if (val & MDIO_PMA_EXTABLE_10GBLRM)
			__set_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
				  supported);
		if (val & MDIO_PMA_EXTABLE_10GBT)
			__set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
				  supported);
		if (val & MDIO_PMA_EXTABLE_10GBKX4)
			__set_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
				  supported);
		if (val & MDIO_PMA_EXTABLE_10GBKR)
			__set_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
				  supported);
		if (val & MDIO_PMA_EXTABLE_1000BT)
			__set_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
				  supported);
		if (val & MDIO_PMA_EXTABLE_1000BKX)
			__set_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
				  supported);
		if (val & MDIO_PMA_EXTABLE_100BTX) {
			__set_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
				  supported);
			__set_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
				  supported);
		}
		if (val & MDIO_PMA_EXTABLE_10BT) {
			__set_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
				  supported);
			__set_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
				  supported);
		}
			__set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT,
				  phydev->supported);
	}

	linkmode_copy(phydev->supported, supported);
	linkmode_and(phydev->advertising, phydev->advertising,
		     phydev->supported);
	ret = genphy_c45_pma_read_abilities(phydev);
	if (ret)
		return ret;

	return 0;
}
+111 −0
Original line number Diff line number Diff line
@@ -47,6 +47,16 @@ int genphy_c45_pma_setup_forced(struct phy_device *phydev)
		/* Assume 1000base-T */
		ctrl2 |= MDIO_PMA_CTRL2_1000BT;
		break;
	case SPEED_2500:
		ctrl1 |= MDIO_CTRL1_SPEED2_5G;
		/* Assume 2.5Gbase-T */
		ctrl2 |= MDIO_PMA_CTRL2_2_5GBT;
		break;
	case SPEED_5000:
		ctrl1 |= MDIO_CTRL1_SPEED5G;
		/* Assume 5Gbase-T */
		ctrl2 |= MDIO_PMA_CTRL2_5GBT;
		break;
	case SPEED_10000:
		ctrl1 |= MDIO_CTRL1_SPEED10G;
		/* Assume 10Gbase-T */
@@ -194,6 +204,12 @@ int genphy_c45_read_lpa(struct phy_device *phydev)
	if (val < 0)
		return val;

	if (val & MDIO_AN_10GBT_STAT_LP2_5G)
		linkmode_set_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
				 phydev->lp_advertising);
	if (val & MDIO_AN_10GBT_STAT_LP5G)
		linkmode_set_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
				 phydev->lp_advertising);
	if (val & MDIO_AN_10GBT_STAT_LP10G)
		linkmode_set_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
				 phydev->lp_advertising);
@@ -224,6 +240,12 @@ int genphy_c45_read_pma(struct phy_device *phydev)
	case MDIO_PMA_CTRL1_SPEED1000:
		phydev->speed = SPEED_1000;
		break;
	case MDIO_CTRL1_SPEED2_5G:
		phydev->speed = SPEED_2500;
		break;
	case MDIO_CTRL1_SPEED5G:
		phydev->speed = SPEED_5000;
		break;
	case MDIO_CTRL1_SPEED10G:
		phydev->speed = SPEED_10000;
		break;
@@ -271,6 +293,95 @@ int genphy_c45_read_mdix(struct phy_device *phydev)
}
EXPORT_SYMBOL_GPL(genphy_c45_read_mdix);

/**
 * genphy_c45_pma_read_abilities - read supported link modes from PMA
 * @phydev: target phy_device struct
 *
 * Read the supported link modes from the PMA Status 2 (1.8) register. If bit
 * 1.8.9 is set, the list of supported modes is build using the values in the
 * PMA Extended Abilities (1.11) register, indicating 1000BASET an 10G related
 * modes. If bit 1.11.14 is set, then the list is also extended with the modes
 * in the 2.5G/5G PMA Extended register (1.21), indicating if 2.5GBASET and
 * 5GBASET are supported.
 */
int genphy_c45_pma_read_abilities(struct phy_device *phydev)
{
	int val;

	val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_STAT2);
	if (val < 0)
		return val;

	linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseSR_Full_BIT,
			 phydev->supported,
			 val & MDIO_PMA_STAT2_10GBSR);

	linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseLR_Full_BIT,
			 phydev->supported,
			 val & MDIO_PMA_STAT2_10GBLR);

	linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseER_Full_BIT,
			 phydev->supported,
			 val & MDIO_PMA_STAT2_10GBER);

	if (val & MDIO_PMA_STAT2_EXTABLE) {
		val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_EXTABLE);
		if (val < 0)
			return val;

		linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseLRM_Full_BIT,
				 phydev->supported,
				 val & MDIO_PMA_EXTABLE_10GBLRM);
		linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
				 phydev->supported,
				 val & MDIO_PMA_EXTABLE_10GBT);
		linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
				 phydev->supported,
				 val & MDIO_PMA_EXTABLE_10GBKX4);
		linkmode_mod_bit(ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
				 phydev->supported,
				 val & MDIO_PMA_EXTABLE_10GBKR);
		linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
				 phydev->supported,
				 val & MDIO_PMA_EXTABLE_1000BT);
		linkmode_mod_bit(ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
				 phydev->supported,
				 val & MDIO_PMA_EXTABLE_1000BKX);

		linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
				 phydev->supported,
				 val & MDIO_PMA_EXTABLE_100BTX);
		linkmode_mod_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
				 phydev->supported,
				 val & MDIO_PMA_EXTABLE_100BTX);

		linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Full_BIT,
				 phydev->supported,
				 val & MDIO_PMA_EXTABLE_10BT);
		linkmode_mod_bit(ETHTOOL_LINK_MODE_10baseT_Half_BIT,
				 phydev->supported,
				 val & MDIO_PMA_EXTABLE_10BT);

		if (val & MDIO_PMA_EXTABLE_NBT) {
			val = phy_read_mmd(phydev, MDIO_MMD_PMAPMD,
					   MDIO_PMA_NG_EXTABLE);
			if (val < 0)
				return val;

			linkmode_mod_bit(ETHTOOL_LINK_MODE_2500baseT_Full_BIT,
					 phydev->supported,
					 val & MDIO_PMA_NG_EXTABLE_2_5GBT);

			linkmode_mod_bit(ETHTOOL_LINK_MODE_5000baseT_Full_BIT,
					 phydev->supported,
					 val & MDIO_PMA_NG_EXTABLE_5GBT);
		}
	}

	return 0;
}
EXPORT_SYMBOL_GPL(genphy_c45_pma_read_abilities);

/* The gen10g_* functions are the old Clause 45 stub */

int gen10g_config_aneg(struct phy_device *phydev)
+72 −0
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@
 */
#include <linux/export.h>
#include <linux/phy.h>
#include <linux/of.h>

const char *phy_speed_to_str(int speed)
{
@@ -338,6 +339,77 @@ size_t phy_speeds(unsigned int *speeds, size_t size,
	return count;
}

static int __set_phy_supported(struct phy_device *phydev, u32 max_speed)
{
	const struct phy_setting *p;
	int i;

	for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) {
		if (p->speed > max_speed)
			linkmode_clear_bit(p->bit, phydev->supported);
		else
			break;
	}

	return 0;
}

int phy_set_max_speed(struct phy_device *phydev, u32 max_speed)
{
	int err;

	err = __set_phy_supported(phydev, max_speed);
	if (err)
		return err;

	linkmode_copy(phydev->advertising, phydev->supported);

	return 0;
}
EXPORT_SYMBOL(phy_set_max_speed);

void of_set_phy_supported(struct phy_device *phydev)
{
	struct device_node *node = phydev->mdio.dev.of_node;
	u32 max_speed;

	if (!IS_ENABLED(CONFIG_OF_MDIO))
		return;

	if (!node)
		return;

	if (!of_property_read_u32(node, "max-speed", &max_speed))
		__set_phy_supported(phydev, max_speed);
}

void of_set_phy_eee_broken(struct phy_device *phydev)
{
	struct device_node *node = phydev->mdio.dev.of_node;
	u32 broken = 0;

	if (!IS_ENABLED(CONFIG_OF_MDIO))
		return;

	if (!node)
		return;

	if (of_property_read_bool(node, "eee-broken-100tx"))
		broken |= MDIO_EEE_100TX;
	if (of_property_read_bool(node, "eee-broken-1000t"))
		broken |= MDIO_EEE_1000T;
	if (of_property_read_bool(node, "eee-broken-10gt"))
		broken |= MDIO_EEE_10GT;
	if (of_property_read_bool(node, "eee-broken-1000kx"))
		broken |= MDIO_EEE_1000KX;
	if (of_property_read_bool(node, "eee-broken-10gkx4"))
		broken |= MDIO_EEE_10GKX4;
	if (of_property_read_bool(node, "eee-broken-10gkr"))
		broken |= MDIO_EEE_10GKR;

	phydev->eee_broken_modes = broken;
}

/**
 * phy_resolve_aneg_linkmode - resolve the advertisements into phy settings
 * @phydev: The phy_device struct
+0 −81
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@
#include <linux/mdio.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/of.h>

MODULE_DESCRIPTION("PHY library");
MODULE_AUTHOR("Andy Fleming");
@@ -1949,44 +1948,6 @@ int genphy_loopback(struct phy_device *phydev, bool enable)
}
EXPORT_SYMBOL(genphy_loopback);

static int __set_phy_supported(struct phy_device *phydev, u32 max_speed)
{
	switch (max_speed) {
	case SPEED_10:
		linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Half_BIT,
				   phydev->supported);
		linkmode_clear_bit(ETHTOOL_LINK_MODE_100baseT_Full_BIT,
				   phydev->supported);
		/* fall through */
	case SPEED_100:
		linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
				   phydev->supported);
		linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
				   phydev->supported);
		break;
	case SPEED_1000:
		break;
	default:
		return -ENOTSUPP;
	}

	return 0;
}

int phy_set_max_speed(struct phy_device *phydev, u32 max_speed)
{
	int err;

	err = __set_phy_supported(phydev, max_speed);
	if (err)
		return err;

	linkmode_copy(phydev->advertising, phydev->supported);

	return 0;
}
EXPORT_SYMBOL(phy_set_max_speed);

/**
 * phy_remove_link_mode - Remove a supported link mode
 * @phydev: phy_device structure to remove link mode from
@@ -2117,48 +2078,6 @@ bool phy_validate_pause(struct phy_device *phydev,
}
EXPORT_SYMBOL(phy_validate_pause);

static void of_set_phy_supported(struct phy_device *phydev)
{
	struct device_node *node = phydev->mdio.dev.of_node;
	u32 max_speed;

	if (!IS_ENABLED(CONFIG_OF_MDIO))
		return;

	if (!node)
		return;

	if (!of_property_read_u32(node, "max-speed", &max_speed))
		__set_phy_supported(phydev, max_speed);
}

static void of_set_phy_eee_broken(struct phy_device *phydev)
{
	struct device_node *node = phydev->mdio.dev.of_node;
	u32 broken = 0;

	if (!IS_ENABLED(CONFIG_OF_MDIO))
		return;

	if (!node)
		return;

	if (of_property_read_bool(node, "eee-broken-100tx"))
		broken |= MDIO_EEE_100TX;
	if (of_property_read_bool(node, "eee-broken-1000t"))
		broken |= MDIO_EEE_1000T;
	if (of_property_read_bool(node, "eee-broken-10gt"))
		broken |= MDIO_EEE_10GT;
	if (of_property_read_bool(node, "eee-broken-1000kx"))
		broken |= MDIO_EEE_1000KX;
	if (of_property_read_bool(node, "eee-broken-10gkx4"))
		broken |= MDIO_EEE_10GKX4;
	if (of_property_read_bool(node, "eee-broken-10gkr"))
		broken |= MDIO_EEE_10GKR;

	phydev->eee_broken_modes = broken;
}

static bool phy_drv_supports_irq(struct phy_driver *phydrv)
{
	return phydrv->config_intr && phydrv->ack_interrupt;
+3 −0
Original line number Diff line number Diff line
@@ -673,6 +673,8 @@ phy_lookup_setting(int speed, int duplex, const unsigned long *mask,
		   bool exact);
size_t phy_speeds(unsigned int *speeds, size_t size,
		  unsigned long *mask);
void of_set_phy_supported(struct phy_device *phydev);
void of_set_phy_eee_broken(struct phy_device *phydev);

static inline bool __phy_is_started(struct phy_device *phydev)
{
@@ -1114,6 +1116,7 @@ int genphy_c45_read_pma(struct phy_device *phydev);
int genphy_c45_pma_setup_forced(struct phy_device *phydev);
int genphy_c45_an_disable_aneg(struct phy_device *phydev);
int genphy_c45_read_mdix(struct phy_device *phydev);
int genphy_c45_pma_read_abilities(struct phy_device *phydev);

/* The gen10g_* functions are the old Clause 45 stub */
int gen10g_config_aneg(struct phy_device *phydev);
Loading