diff mbox series

[net-next,8/8] net: phy: marvell10g: select host interface configuration

Message ID 20211117225050.18395-9-kabel@kernel.org (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series Extend `phy-mode` to string array | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers warning 2 maintainers not CCed: linux@armlinux.org.uk hkallweit1@gmail.com
netdev/build_clang success Errors and warnings before: 0 this patch: 0
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 182 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Marek Behún Nov. 17, 2021, 10:50 p.m. UTC
From: Russell King <rmk+kernel@armlinux.org.uk>

Select the host interface configuration according to the capabilities of
the host.

This allows the kernel to:
- support SFP modules with 88X33X0 or 88E21X0 inside them
- switch interface modes when the PHY is used with the mvpp2 MAC
  (e.g. on MacchiatoBIN)

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
[ rebase, updated, also added support for 88E21X0 ]
Signed-off-by: Marek Behún <kabel@kernel.org>
---
 drivers/net/phy/marvell10g.c | 120 +++++++++++++++++++++++++++++++++--
 1 file changed, 115 insertions(+), 5 deletions(-)

Comments

Russell King (Oracle) Nov. 18, 2021, 9:41 a.m. UTC | #1
On Wed, Nov 17, 2021 at 11:50:50PM +0100, Marek Behún wrote:
> +static int mv3310_select_mactype(unsigned long *interfaces)
> +{
> +	if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
> +		return MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII;
> +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> +		 test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
> +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> +		 test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI;
> +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> +		 test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI;
> +	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
> +	else if (test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH;
> +	else if (test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH;
> +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces))
> +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;

Hi,

There are differences in the MACTYPE register between the 88X3310
and 88X3340. For example, the 88X3340 has no support for XAUI.
This is documented in the data sheet, and in the definitions of
these values - note that MV_V2_3310_PORT_CTRL_MACTYPE_XAUI and
MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH are only applicable
to the 88X3310 (they don't use MV_V2_33X0_*).
Vladimir Oltean Nov. 18, 2021, 12:03 p.m. UTC | #2
Hello,

On Wed, Nov 17, 2021 at 11:50:50PM +0100, Marek Behún wrote:
> From: Russell King <rmk+kernel@armlinux.org.uk>
> 
> Select the host interface configuration according to the capabilities of
> the host.
> 
> This allows the kernel to:
> - support SFP modules with 88X33X0 or 88E21X0 inside them
> - switch interface modes when the PHY is used with the mvpp2 MAC
>   (e.g. on MacchiatoBIN)
> 
> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
> [ rebase, updated, also added support for 88E21X0 ]
> Signed-off-by: Marek Behún <kabel@kernel.org>
> ---
>  drivers/net/phy/marvell10g.c | 120 +++++++++++++++++++++++++++++++++--
>  1 file changed, 115 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
> index 0cb9b4ef09c7..94bea1bade6f 100644
> --- a/drivers/net/phy/marvell10g.c
> +++ b/drivers/net/phy/marvell10g.c
> @@ -96,6 +96,11 @@ enum {
>  	MV_PCS_PORT_INFO_NPORTS_MASK	= 0x0380,
>  	MV_PCS_PORT_INFO_NPORTS_SHIFT	= 7,
>  
> +	/* SerDes reinitialization 88E21X0 */
> +	MV_AN_21X0_SERDES_CTRL2	= 0x800f,
> +	MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS	= BIT(13),
> +	MV_AN_21X0_SERDES_CTRL2_RUN_INIT	= BIT(15),
> +
>  	/* These registers appear at 0x800X and 0xa00X - the 0xa00X control
>  	 * registers appear to set themselves to the 0x800X when AN is
>  	 * restarted, but status registers appear readable from either.
> @@ -140,6 +145,8 @@ struct mv3310_chip {
>  	bool (*has_downshift)(struct phy_device *phydev);
>  	void (*init_supported_interfaces)(unsigned long *mask);
>  	int (*get_mactype)(struct phy_device *phydev);
> +	int (*set_mactype)(struct phy_device *phydev, int mactype);
> +	int (*select_mactype)(unsigned long *interfaces);
>  	int (*init_interface)(struct phy_device *phydev, int mactype);
>  
>  #ifdef CONFIG_HWMON
> @@ -593,6 +600,49 @@ static int mv2110_get_mactype(struct phy_device *phydev)
>  	return mactype & MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK;
>  }
>  
> +static int mv2110_set_mactype(struct phy_device *phydev, int mactype)
> +{
> +	int err, val;
> +
> +	mactype &= MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK;
> +	err = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_21X0_PORT_CTRL,
> +			     MV_PMA_21X0_PORT_CTRL_SWRST |
> +			     MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK,
> +			     MV_PMA_21X0_PORT_CTRL_SWRST | mactype);
> +	if (err)
> +		return err;
> +
> +	err = phy_set_bits_mmd(phydev, MDIO_MMD_AN, MV_AN_21X0_SERDES_CTRL2,
> +			       MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS |
> +			       MV_AN_21X0_SERDES_CTRL2_RUN_INIT);
> +	if (err)
> +		return err;
> +
> +	err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_AN,
> +					MV_AN_21X0_SERDES_CTRL2, val,
> +					!(val &
> +					  MV_AN_21X0_SERDES_CTRL2_RUN_INIT),
> +					5000, 100000, true);
> +	if (err)
> +		return err;
> +
> +	return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, MV_AN_21X0_SERDES_CTRL2,
> +				  MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS);
> +}
> +
> +static int mv2110_select_mactype(unsigned long *interfaces)
> +{
> +	if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
> +		return MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII;
> +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> +		 !test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> +		return MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER;
> +	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> +		return MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
> +	else
> +		return -1;
> +}
> +
>  static int mv3310_get_mactype(struct phy_device *phydev)
>  {
>  	int mactype;
> @@ -604,6 +654,46 @@ static int mv3310_get_mactype(struct phy_device *phydev)
>  	return mactype & MV_V2_33X0_PORT_CTRL_MACTYPE_MASK;
>  }
>  
> +static int mv3310_set_mactype(struct phy_device *phydev, int mactype)
> +{
> +	int ret;
> +
> +	mactype &= MV_V2_33X0_PORT_CTRL_MACTYPE_MASK;
> +	ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
> +				     MV_V2_33X0_PORT_CTRL_MACTYPE_MASK,
> +				     mactype);
> +	if (ret <= 0)
> +		return ret;
> +
> +	return phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
> +				MV_V2_33X0_PORT_CTRL_SWRST);
> +}
> +
> +static int mv3310_select_mactype(unsigned long *interfaces)
> +{
> +	if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
> +		return MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII;
> +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> +		 test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
> +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> +		 test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI;
> +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> +		 test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI;
> +	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
> +	else if (test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH;
> +	else if (test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH;
> +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces))
> +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
> +	else
> +		return -1;
> +}
> +

I would like to understand this heuristic better. Both its purpose and
its implementation.

It says:
(a) If the intersection between interface modes supported by the MAC and
    the PHY contains USXGMII, then use USXGMII as a MACTYPE
(b) Otherwise, if the intersection contains both 10GBaseR and SGMII, then
    use 10GBaseR as MACTYPE
(...)
(c) Otherwise, if the intersection contains just 10GBaseR (no SGMII), then
    use 10GBaseR with rate matching as MACTYPE
(...)
(d) Otherwise, if the intersection contains just SGMII (no 10GBaseR), then
    use 10GBaseR as MACTYPE (no rate matching).

First of all, what is MACTYPE exactly? And what is the purpose of
changing it? What would happen if this configuration remained fixed, as
it were?

I see there is no MACTYPE definition for SGMII. Why is that? How does
the PHY choose to use SGMII?

Why is item (d) correct - use 10GBaseR as MACTYPE if the intersection
only supports SGMII?

A breakdown per link speed might be helpful in understanding the
configurations being performed here.

>  static int mv2110_init_interface(struct phy_device *phydev, int mactype)
>  {
>  	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
> @@ -674,10 +764,16 @@ static int mv3310_config_init(struct phy_device *phydev)
>  {
>  	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
>  	const struct mv3310_chip *chip = to_mv3310_chip(phydev);
> +	DECLARE_PHY_INTERFACE_MASK(interfaces);
>  	int err, mactype;
>  
> -	/* Check that the PHY interface type is compatible */
> -	if (!test_bit(phydev->interface, priv->supported_interfaces))
> +	/* In case host didn't provide supported interfaces */
> +	__set_bit(phydev->interface, phydev->host_interfaces);

Shouldn't phylib populate phydev->host_interfaces with
phydev->interface, rather than requiring PHY drivers to do it?

> +
> +	/* Check that there is at least one compatible PHY interface type */
> +	phy_interface_and(interfaces, phydev->host_interfaces,
> +			  priv->supported_interfaces);
> +	if (phy_interface_empty(interfaces))
>  		return -ENODEV;
>  
>  	phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
> @@ -687,9 +783,15 @@ static int mv3310_config_init(struct phy_device *phydev)
>  	if (err)
>  		return err;
>  
> -	mactype = chip->get_mactype(phydev);
> -	if (mactype < 0)
> -		return mactype;
> +	mactype = chip->select_mactype(interfaces);
> +	if (mactype < 0) {
> +		mactype = chip->get_mactype(phydev);
> +	} else {
> +		phydev_info(phydev, "Changing MACTYPE to %i\n", mactype);
> +		err = chip->set_mactype(phydev, mactype);
> +		if (err)
> +			return err;
> +	}
>  
>  	err = chip->init_interface(phydev, mactype);
>  	if (err) {
> @@ -1049,6 +1151,8 @@ static const struct mv3310_chip mv3310_type = {
>  	.has_downshift = mv3310_has_downshift,
>  	.init_supported_interfaces = mv3310_init_supported_interfaces,
>  	.get_mactype = mv3310_get_mactype,
> +	.set_mactype = mv3310_set_mactype,
> +	.select_mactype = mv3310_select_mactype,
>  	.init_interface = mv3310_init_interface,
>  
>  #ifdef CONFIG_HWMON
> @@ -1060,6 +1164,8 @@ static const struct mv3310_chip mv3340_type = {
>  	.has_downshift = mv3310_has_downshift,
>  	.init_supported_interfaces = mv3340_init_supported_interfaces,
>  	.get_mactype = mv3310_get_mactype,
> +	.set_mactype = mv3310_set_mactype,
> +	.select_mactype = mv3310_select_mactype,
>  	.init_interface = mv3340_init_interface,
>  
>  #ifdef CONFIG_HWMON
> @@ -1070,6 +1176,8 @@ static const struct mv3310_chip mv3340_type = {
>  static const struct mv3310_chip mv2110_type = {
>  	.init_supported_interfaces = mv2110_init_supported_interfaces,
>  	.get_mactype = mv2110_get_mactype,
> +	.set_mactype = mv2110_set_mactype,
> +	.select_mactype = mv2110_select_mactype,
>  	.init_interface = mv2110_init_interface,
>  
>  #ifdef CONFIG_HWMON
> @@ -1080,6 +1188,8 @@ static const struct mv3310_chip mv2110_type = {
>  static const struct mv3310_chip mv2111_type = {
>  	.init_supported_interfaces = mv2111_init_supported_interfaces,
>  	.get_mactype = mv2110_get_mactype,
> +	.set_mactype = mv2110_set_mactype,
> +	.select_mactype = mv2110_select_mactype,
>  	.init_interface = mv2110_init_interface,
>  
>  #ifdef CONFIG_HWMON
> -- 
> 2.32.0
>
Russell King (Oracle) Nov. 18, 2021, 1:22 p.m. UTC | #3
On Thu, Nov 18, 2021 at 02:03:34PM +0200, Vladimir Oltean wrote:
> On Wed, Nov 17, 2021 at 11:50:50PM +0100, Marek Behún wrote:
> > +static int mv3310_select_mactype(unsigned long *interfaces)
> > +{
> > +	if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII;
> > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > +		 test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
> > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > +		 test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI;
> > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > +		 test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> > +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI;
> > +	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
> > +	else if (test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH;
> > +	else if (test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> > +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH;
> > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
> > +	else
> > +		return -1;
> > +}
> > +
> 
> I would like to understand this heuristic better. Both its purpose and
> its implementation.
> 
> It says:
> (a) If the intersection between interface modes supported by the MAC and
>     the PHY contains USXGMII, then use USXGMII as a MACTYPE
> (b) Otherwise, if the intersection contains both 10GBaseR and SGMII, then
>     use 10GBaseR as MACTYPE
> (...)
> (c) Otherwise, if the intersection contains just 10GBaseR (no SGMII), then
>     use 10GBaseR with rate matching as MACTYPE
> (...)
> (d) Otherwise, if the intersection contains just SGMII (no 10GBaseR), then
>     use 10GBaseR as MACTYPE (no rate matching).

What is likely confusing you is a misinterpretation of the constant.
MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER actually means the PHY will
choose between 10GBASE-R, 5GBASE-R, 2500BASE-X, and SGMII depending
on the speed negotiated by the media. In this setting, the PHY
dictates which interface mode will be used.

I could have named "MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER" as
"MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_5GBASER_2500BASEX_SGMII_AUTONEG_ON".
Similar with "MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN", which
would be
"MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_5GBASER_2500BASEX_SGMII_AUTONEG_OFF".
And "MV_V2_3310_PORT_CTRL_MACTYPE_XAUI" would be
"MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_5GBASER_2500BASEX_SGMII_AUTONEG_ON".

Clearly using such long identifiers would have been rediculous,
especially the second one at 74 characters.

> First of all, what is MACTYPE exactly? And what is the purpose of
> changing it? What would happen if this configuration remained fixed, as
> it were?

The PHY defines the MAC interface mode depending on the MACTYPE
setting selected and the results of the media side negotiation.

I think the above answers your remaining questions.
Marek Behún Nov. 18, 2021, 1:46 p.m. UTC | #4
On Thu, 18 Nov 2021 09:41:27 +0000
"Russell King (Oracle)" <linux@armlinux.org.uk> wrote:

> On Wed, Nov 17, 2021 at 11:50:50PM +0100, Marek Behún wrote:
> > +static int mv3310_select_mactype(unsigned long *interfaces)
> > +{
> > +	if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII;
> > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > +		 test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
> > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > +		 test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI;
> > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > +		 test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> > +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI;
> > +	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
> > +	else if (test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH;
> > +	else if (test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> > +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH;
> > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;  
> 
> Hi,
> 
> There are differences in the MACTYPE register between the 88X3310
> and 88X3340. For example, the 88X3340 has no support for XAUI.
> This is documented in the data sheet, and in the definitions of
> these values - note that MV_V2_3310_PORT_CTRL_MACTYPE_XAUI and
> MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH are only applicable
> to the 88X3310 (they don't use MV_V2_33X0_*).

Yes, but 88X3340 does not support XAUI, only RXAUI, it is defined in
supported_interfaces. So PHY_INTERFACE_MODE_XAUI will never be set in
interfaces, and thus this function can be used for both 88X3310 and
88X3340.

Marek
Marek Behún Nov. 18, 2021, 1:56 p.m. UTC | #5
On Thu, 18 Nov 2021 14:03:34 +0200
Vladimir Oltean <olteanv@gmail.com> wrote:

> Hello,
> 
> > +static int mv3310_select_mactype(unsigned long *interfaces)
> > +{
> > +	if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII;
> > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > +		 test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
> > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > +		 test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI;
> > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > +		 test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> > +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI;
> > +	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
> > +	else if (test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH;
> > +	else if (test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> > +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH;
> > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces))
> > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
> > +	else
> > +		return -1;
> > +}
> > +  
> 
> I would like to understand this heuristic better. Both its purpose and
> its implementation.
> 
> It says:
> (a) If the intersection between interface modes supported by the MAC and
>     the PHY contains USXGMII, then use USXGMII as a MACTYPE
> (b) Otherwise, if the intersection contains both 10GBaseR and SGMII, then
>     use 10GBaseR as MACTYPE
> (...)
> (c) Otherwise, if the intersection contains just 10GBaseR (no SGMII), then
>     use 10GBaseR with rate matching as MACTYPE
> (...)
> (d) Otherwise, if the intersection contains just SGMII (no 10GBaseR), then
>     use 10GBaseR as MACTYPE (no rate matching).
> 
> First of all, what is MACTYPE exactly? And what is the purpose of
> changing it? What would happen if this configuration remained fixed, as
> it were?
> 
> I see there is no MACTYPE definition for SGMII. Why is that? How does
> the PHY choose to use SGMII?
> 
> Why is item (d) correct - use 10GBaseR as MACTYPE if the intersection
> only supports SGMII?
> 
> A breakdown per link speed might be helpful in understanding the
> configurations being performed here.

Russell already explained this. I will put a better explanation into
the commit message in v2.

> >  static int mv2110_init_interface(struct phy_device *phydev, int mactype)
> >  {
> >  	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
> > @@ -674,10 +764,16 @@ static int mv3310_config_init(struct phy_device *phydev)
> >  {
> >  	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
> >  	const struct mv3310_chip *chip = to_mv3310_chip(phydev);
> > +	DECLARE_PHY_INTERFACE_MASK(interfaces);
> >  	int err, mactype;
> >  
> > -	/* Check that the PHY interface type is compatible */
> > -	if (!test_bit(phydev->interface, priv->supported_interfaces))
> > +	/* In case host didn't provide supported interfaces */
> > +	__set_bit(phydev->interface, phydev->host_interfaces);  
> 
> Shouldn't phylib populate phydev->host_interfaces with
> phydev->interface, rather than requiring PHY drivers to do it?

I will look into this.

Marek
Vladimir Oltean Nov. 18, 2021, 2:20 p.m. UTC | #6
On Thu, Nov 18, 2021 at 01:22:18PM +0000, Russell King (Oracle) wrote:
> On Thu, Nov 18, 2021 at 02:03:34PM +0200, Vladimir Oltean wrote:
> > On Wed, Nov 17, 2021 at 11:50:50PM +0100, Marek Behún wrote:
> > > +static int mv3310_select_mactype(unsigned long *interfaces)
> > > +{
> > > +	if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
> > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII;
> > > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > > +		 test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
> > > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > > +		 test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI;
> > > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > > +		 test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> > > +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI;
> > > +	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
> > > +	else if (test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH;
> > > +	else if (test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> > > +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH;
> > > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces))
> > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
> > > +	else
> > > +		return -1;
> > > +}
> > > +
> > 
> > I would like to understand this heuristic better. Both its purpose and
> > its implementation.
> > 
> > It says:
> > (a) If the intersection between interface modes supported by the MAC and
> >     the PHY contains USXGMII, then use USXGMII as a MACTYPE
> > (b) Otherwise, if the intersection contains both 10GBaseR and SGMII, then
> >     use 10GBaseR as MACTYPE
> > (...)
> > (c) Otherwise, if the intersection contains just 10GBaseR (no SGMII), then
> >     use 10GBaseR with rate matching as MACTYPE
> > (...)
> > (d) Otherwise, if the intersection contains just SGMII (no 10GBaseR), then
> >     use 10GBaseR as MACTYPE (no rate matching).
> 
> What is likely confusing you is a misinterpretation of the constant.
> MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER actually means the PHY will
> choose between 10GBASE-R, 5GBASE-R, 2500BASE-X, and SGMII depending
> on the speed negotiated by the media. In this setting, the PHY
> dictates which interface mode will be used.
> 
> I could have named "MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER" as
> "MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_5GBASER_2500BASEX_SGMII_AUTONEG_ON".
> Similar with "MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN", which
> would be
> "MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_5GBASER_2500BASEX_SGMII_AUTONEG_OFF".
> And "MV_V2_3310_PORT_CTRL_MACTYPE_XAUI" would be
> "MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_5GBASER_2500BASEX_SGMII_AUTONEG_ON".
> 
> Clearly using such long identifiers would have been rediculous,
> especially the second one at 74 characters.

True, but at least there could be a comment above each definition.
There's no size limit to that.

> > First of all, what is MACTYPE exactly? And what is the purpose of
> > changing it? What would happen if this configuration remained fixed, as
> > it were?
> 
> The PHY defines the MAC interface mode depending on the MACTYPE
> setting selected and the results of the media side negotiation.
> 
> I think the above answers your remaining questions.

Ok, so going back to case (d). You said that the full name would be
MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_5GBASER_2500BASEX_SGMII_AUTONEG_ON.
This means that when the only interface mode supported by the host would
be SGMII, the PHY's MACTYPE is still configured to use 2500basex,
5gbaser, 10gbaser for the higher link speeds. Clearly this won't work.
But on the other hand, the phylink validate method will remove
2500baseT, 5000baseT, 1000baseT from the advertising mask of the PHY, so
the system will never end up operating at those speeds, so it should be fine.



The reason why I'm looking at these patches is to see whether they would
bring something useful to Aquantia PHYs. These come with firmware on a
flash that is customized by Aquantia themselves based on the specifications
of a single board. These PHYs have an ability which is very similar to
what I'm seeing here, which is to select, for each negotiated link speed
on the media side, the SERDES protocol to use on the system side. This
is pre-programmed by the firmware, but could be fixed up by the
operating system if done carefully.

The way Layerscape boards use Aquantia PHYs is to always select the
"rate matching" option and keep the SERDES protocol fixed, just
configure the mini MAC inside the PHY to emit PAUSE frames towards the
system to keep the data rate under control. We would be using these PHYs
with the generic C45 driver, which would be mostly enough except for
lack of PHY interrupts, because the firmware already configures
everything.

But on the other hand it gets a bit tiring, especially for PHYs on riser
cards, to have to change firmware in order to test a different SERDES
protocol, so we were experimenting with some changes in the PHY driver
that would basically keep the firmware image fixed, and just fix up the
configuration it made, and do things like "use 2500base-x for the
2500base-T speed, and sgmii for 1000base-T/100base-TX". The ability for
a PHY to work on a board where its firmware image wasn't specifically
designed for it comes in handy sometimes.

I was reluctant to submit any changes to the Aquantia PHY driver because
we don't really have any guarantees that we wouldn't break any system
that uses it. I do know that there are users who do expect SERDES
protocol changes currently, because I do see that aqr107_read_status()
checks for a possibly modified phydev->interface. But without the
ability of knowing what SERDES protocols does the system-side support,
it is pretty difficult to modify the SERDES protocol used for a certain
link speed without breaking something.

I see that this patch set basically introduces the phydev->host_interfaces
bitmap which is an attempt to find the answer to that question. But when
will we know enough about phydev->host_interfaces in order to safely
make decisions in the PHY driver based on it? phylink sets it, phylib does not.
And many Aquantia systems use the generic PHY driver, as mentioned.
Additionally, there are old device trees at play here, which only define
the initial SERDES protocol. Would we be changing the behavior for those,
in that we would be configuring the PHY to keep the SERDES protocol
fixed whereas it would have dynamically changed before?

Another question is what to do if there are multiple ways of
establishing a system-side link. For example 1000 Mbps can be achieved
either through SGMII, or USXGMII with symbol replication, or 2500base-x
with flow control, or 10GBaseR with flow control. And I want to test
them all. What would I need to do to change the SERDES protocol from one
value to the other? Changing the phy-mode array in the device tree would
be one option, but that may not always be possible.
Russell King (Oracle) Nov. 18, 2021, 2:25 p.m. UTC | #7
On Thu, Nov 18, 2021 at 02:46:28PM +0100, Marek Behún wrote:
> On Thu, 18 Nov 2021 09:41:27 +0000
> "Russell King (Oracle)" <linux@armlinux.org.uk> wrote:
> 
> > On Wed, Nov 17, 2021 at 11:50:50PM +0100, Marek Behún wrote:
> > > +static int mv3310_select_mactype(unsigned long *interfaces)
> > > +{
> > > +	if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
> > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII;
> > > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > > +		 test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
> > > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > > +		 test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI;
> > > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > > +		 test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> > > +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI;
> > > +	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
> > > +	else if (test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH;
> > > +	else if (test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> > > +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH;
> > > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces))
> > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;  
> > 
> > Hi,
> > 
> > There are differences in the MACTYPE register between the 88X3310
> > and 88X3340. For example, the 88X3340 has no support for XAUI.
> > This is documented in the data sheet, and in the definitions of
> > these values - note that MV_V2_3310_PORT_CTRL_MACTYPE_XAUI and
> > MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH are only applicable
> > to the 88X3310 (they don't use MV_V2_33X0_*).
> 
> Yes, but 88X3340 does not support XAUI, only RXAUI, it is defined in
> supported_interfaces. So PHY_INTERFACE_MODE_XAUI will never be set in
> interfaces, and thus this function can be used for both 88X3310 and
> 88X3340.

Okay, that's fine then. The only setting we will omit from this for
the 88X3340 then is MV_V2_3340_PORT_CTRL_MACTYPE_RXAUI_NO_SGMII_AN.
Russell King (Oracle) Nov. 18, 2021, 2:47 p.m. UTC | #8
On Thu, Nov 18, 2021 at 04:20:39PM +0200, Vladimir Oltean wrote:
> On Thu, Nov 18, 2021 at 01:22:18PM +0000, Russell King (Oracle) wrote:
> > On Thu, Nov 18, 2021 at 02:03:34PM +0200, Vladimir Oltean wrote:
> > > On Wed, Nov 17, 2021 at 11:50:50PM +0100, Marek Behún wrote:
> > > > +static int mv3310_select_mactype(unsigned long *interfaces)
> > > > +{
> > > > +	if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
> > > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII;
> > > > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > > > +		 test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> > > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
> > > > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > > > +		 test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> > > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI;
> > > > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > > > +		 test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> > > > +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI;
> > > > +	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> > > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
> > > > +	else if (test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> > > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH;
> > > > +	else if (test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> > > > +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH;
> > > > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces))
> > > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
> > > > +	else
> > > > +		return -1;
> > > > +}
> > > > +
> > > 
> > > I would like to understand this heuristic better. Both its purpose and
> > > its implementation.
> > > 
> > > It says:
> > > (a) If the intersection between interface modes supported by the MAC and
> > >     the PHY contains USXGMII, then use USXGMII as a MACTYPE
> > > (b) Otherwise, if the intersection contains both 10GBaseR and SGMII, then
> > >     use 10GBaseR as MACTYPE
> > > (...)
> > > (c) Otherwise, if the intersection contains just 10GBaseR (no SGMII), then
> > >     use 10GBaseR with rate matching as MACTYPE
> > > (...)
> > > (d) Otherwise, if the intersection contains just SGMII (no 10GBaseR), then
> > >     use 10GBaseR as MACTYPE (no rate matching).
> > 
> > What is likely confusing you is a misinterpretation of the constant.
> > MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER actually means the PHY will
> > choose between 10GBASE-R, 5GBASE-R, 2500BASE-X, and SGMII depending
> > on the speed negotiated by the media. In this setting, the PHY
> > dictates which interface mode will be used.
> > 
> > I could have named "MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER" as
> > "MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_5GBASER_2500BASEX_SGMII_AUTONEG_ON".
> > Similar with "MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN", which
> > would be
> > "MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_5GBASER_2500BASEX_SGMII_AUTONEG_OFF".
> > And "MV_V2_3310_PORT_CTRL_MACTYPE_XAUI" would be
> > "MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_5GBASER_2500BASEX_SGMII_AUTONEG_ON".
> > 
> > Clearly using such long identifiers would have been rediculous,
> > especially the second one at 74 characters.
> 
> True, but at least there could be a comment above each definition.
> There's no size limit to that.
> 
> > > First of all, what is MACTYPE exactly? And what is the purpose of
> > > changing it? What would happen if this configuration remained fixed, as
> > > it were?
> > 
> > The PHY defines the MAC interface mode depending on the MACTYPE
> > setting selected and the results of the media side negotiation.
> > 
> > I think the above answers your remaining questions.
> 
> Ok, so going back to case (d). You said that the full name would be
> MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_5GBASER_2500BASEX_SGMII_AUTONEG_ON.
> This means that when the only interface mode supported by the host would
> be SGMII, the PHY's MACTYPE is still configured to use 2500basex,
> 5gbaser, 10gbaser for the higher link speeds. Clearly this won't work.
> But on the other hand, the phylink validate method will remove
> 2500baseT, 5000baseT, 1000baseT from the advertising mask of the PHY, so
> the system will never end up operating at those speeds, so it should be fine.

I think you mean 10000baseT rather than 1000baseT. With that correction,
you are then correct - with the media restricted to 1G or slower speeds,
and the phy in MACTYPE mode 4 (aka 10GBASE-R as the fastest interface
mode) it will permanently be talking SGMII to the host.

> The reason why I'm looking at these patches is to see whether they would
> bring something useful to Aquantia PHYs. These come with firmware on a
> flash that is customized by Aquantia themselves based on the specifications
> of a single board. These PHYs have an ability which is very similar to
> what I'm seeing here, which is to select, for each negotiated link speed
> on the media side, the SERDES protocol to use on the system side. This
> is pre-programmed by the firmware, but could be fixed up by the
> operating system if done carefully.
> 
> The way Layerscape boards use Aquantia PHYs is to always select the
> "rate matching" option and keep the SERDES protocol fixed, just
> configure the mini MAC inside the PHY to emit PAUSE frames towards the
> system to keep the data rate under control. We would be using these PHYs
> with the generic C45 driver, which would be mostly enough except for
> lack of PHY interrupts, because the firmware already configures
> everything.
> 
> But on the other hand it gets a bit tiring, especially for PHYs on riser
> cards, to have to change firmware in order to test a different SERDES
> protocol, so we were experimenting with some changes in the PHY driver
> that would basically keep the firmware image fixed, and just fix up the
> configuration it made, and do things like "use 2500base-x for the
> 2500base-T speed, and sgmii for 1000base-T/100base-TX". The ability for
> a PHY to work on a board where its firmware image wasn't specifically
> designed for it comes in handy sometimes.

You're going to get into problems with this on Layerscape, because
reconfiguring the Serdes etc is something I've tried to highlight
as being necessary to NXP since SolidRun started using LX2160A. I
think there's some slow progress towards that, but it's so slow that
I've basically given up caring about it on the Honeycomb/Clearfog CX
boards now.

All the SFP cages on my Honeycomb have been configured for the most
useful mode to me - 1000BASE-X/SGMII, and I've given up caring about
USXGMII/10GBASE-R on those ports.

> I see that this patch set basically introduces the phydev->host_interfaces
> bitmap which is an attempt to find the answer to that question. But when
> will we know enough about phydev->host_interfaces in order to safely
> make decisions in the PHY driver based on it? phylink sets it, phylib
> does not.

It won't be something phylib could set because phylib doesn't know
the capabilities of its user - it's information that would need to be
provided to phylib.

> And many Aquantia systems use the generic PHY driver, as mentioned.
> Additionally, there are old device trees at play here, which only define
> the initial SERDES protocol. Would we be changing the behavior for those,
> in that we would be configuring the PHY to keep the SERDES protocol
> fixed whereas it would have dynamically changed before?

We have the same situation on Macchiatobin. The 88X3310 there defaults
to MACTYPE mode 4, and we've supported this for years with DT describing
the interface as 10GBASE-R - because we haven't actually cared very much
what DT says up to this point for the 88X3310. As I said in my previous
reply, the 88X3310 effectively dictates what the PHY interface mode will
be, and that is communicated back through phylib to whoever is using
phylib.

> Another question is what to do if there are multiple ways of
> establishing a system-side link. For example 1000 Mbps can be achieved
> either through SGMII, or USXGMII with symbol replication, or 2500base-x
> with flow control, or 10GBaseR with flow control. And I want to test
> them all. What would I need to do to change the SERDES protocol from one
> value to the other? Changing the phy-mode array in the device tree would
> be one option, but that may not always be possible.

First point to make here is that rate adaption at the PHY is really
not well supported in Linux, and there is no way to know via phylib if
a PHY is capable or not of rate adaption.

Today, if you have a 10GBASE-R link between a PHY doing rate adaption
and the "MAC", then what you will get from phylib is:

	phydev->interface = PHY_INTERFACE_MODE_10GBASER;
	phydev->speed = SPEED_1000;	// result of media negotiation
	phydev->duplex = DUPLEX_FULL;	// result of media negotiation
	phydev->pause = ...;		// result of media negotiation
	phydev->asym_pause = ...;	// result of media negotiation

which will, for the majority of implementations, result in the MAC being
forced to a 1G speed, possibly with or without pause enabled.

Due to this, if phylink is being used, the parameters given to
mac_link_up/pcs_link_up will be the result of the media negotiation, not
what is required on the actual link.

You mention "10GBaseR with flow control" but there is another
possibility that exists in real hardware out there. "10GBaseR without
flow control" and in that case, the MAC needs to pace its transmission
for the media speed (which is a good reason why mac_link_up should be
given the result of the media negotiation so it can do transmission
pacing.)

I have a follow-up to the response I gave to Sean Anderson on rate-
adapting PHYs that I need to finish and send, and it would be better
to have any discussion on this topic after I've sent that reply and
follow-up to that reply.
Vladimir Oltean Nov. 18, 2021, 3:09 p.m. UTC | #9
On Thu, Nov 18, 2021 at 02:47:44PM +0000, Russell King (Oracle) wrote:
> On Thu, Nov 18, 2021 at 04:20:39PM +0200, Vladimir Oltean wrote:
> > On Thu, Nov 18, 2021 at 01:22:18PM +0000, Russell King (Oracle) wrote:
> > > On Thu, Nov 18, 2021 at 02:03:34PM +0200, Vladimir Oltean wrote:
> > > > On Wed, Nov 17, 2021 at 11:50:50PM +0100, Marek Behún wrote:
> > > > > +static int mv3310_select_mactype(unsigned long *interfaces)
> > > > > +{
> > > > > +	if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
> > > > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII;
> > > > > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > > > > +		 test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> > > > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
> > > > > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > > > > +		 test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> > > > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI;
> > > > > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
> > > > > +		 test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> > > > > +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI;
> > > > > +	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
> > > > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
> > > > > +	else if (test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
> > > > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH;
> > > > > +	else if (test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
> > > > > +		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH;
> > > > > +	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces))
> > > > > +		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
> > > > > +	else
> > > > > +		return -1;
> > > > > +}
> > > > > +
> > > > 
> > > > I would like to understand this heuristic better. Both its purpose and
> > > > its implementation.
> > > > 
> > > > It says:
> > > > (a) If the intersection between interface modes supported by the MAC and
> > > >     the PHY contains USXGMII, then use USXGMII as a MACTYPE
> > > > (b) Otherwise, if the intersection contains both 10GBaseR and SGMII, then
> > > >     use 10GBaseR as MACTYPE
> > > > (...)
> > > > (c) Otherwise, if the intersection contains just 10GBaseR (no SGMII), then
> > > >     use 10GBaseR with rate matching as MACTYPE
> > > > (...)
> > > > (d) Otherwise, if the intersection contains just SGMII (no 10GBaseR), then
> > > >     use 10GBaseR as MACTYPE (no rate matching).
> > > 
> > > What is likely confusing you is a misinterpretation of the constant.
> > > MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER actually means the PHY will
> > > choose between 10GBASE-R, 5GBASE-R, 2500BASE-X, and SGMII depending
> > > on the speed negotiated by the media. In this setting, the PHY
> > > dictates which interface mode will be used.
> > > 
> > > I could have named "MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER" as
> > > "MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_5GBASER_2500BASEX_SGMII_AUTONEG_ON".
> > > Similar with "MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_NO_SGMII_AN", which
> > > would be
> > > "MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_5GBASER_2500BASEX_SGMII_AUTONEG_OFF".
> > > And "MV_V2_3310_PORT_CTRL_MACTYPE_XAUI" would be
> > > "MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_5GBASER_2500BASEX_SGMII_AUTONEG_ON".
> > > 
> > > Clearly using such long identifiers would have been rediculous,
> > > especially the second one at 74 characters.
> > 
> > True, but at least there could be a comment above each definition.
> > There's no size limit to that.
> > 
> > > > First of all, what is MACTYPE exactly? And what is the purpose of
> > > > changing it? What would happen if this configuration remained fixed, as
> > > > it were?
> > > 
> > > The PHY defines the MAC interface mode depending on the MACTYPE
> > > setting selected and the results of the media side negotiation.
> > > 
> > > I think the above answers your remaining questions.
> > 
> > Ok, so going back to case (d). You said that the full name would be
> > MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_5GBASER_2500BASEX_SGMII_AUTONEG_ON.
> > This means that when the only interface mode supported by the host would
> > be SGMII, the PHY's MACTYPE is still configured to use 2500basex,
> > 5gbaser, 10gbaser for the higher link speeds. Clearly this won't work.
> > But on the other hand, the phylink validate method will remove
> > 2500baseT, 5000baseT, 1000baseT from the advertising mask of the PHY, so
> > the system will never end up operating at those speeds, so it should be fine.
> 
> I think you mean 10000baseT rather than 1000baseT. With that correction,
> you are then correct - with the media restricted to 1G or slower speeds,
> and the phy in MACTYPE mode 4 (aka 10GBASE-R as the fastest interface
> mode) it will permanently be talking SGMII to the host.

Yes, I missed a zero.

> > The reason why I'm looking at these patches is to see whether they would
> > bring something useful to Aquantia PHYs. These come with firmware on a
> > flash that is customized by Aquantia themselves based on the specifications
> > of a single board. These PHYs have an ability which is very similar to
> > what I'm seeing here, which is to select, for each negotiated link speed
> > on the media side, the SERDES protocol to use on the system side. This
> > is pre-programmed by the firmware, but could be fixed up by the
> > operating system if done carefully.
> > 
> > The way Layerscape boards use Aquantia PHYs is to always select the
> > "rate matching" option and keep the SERDES protocol fixed, just
> > configure the mini MAC inside the PHY to emit PAUSE frames towards the
> > system to keep the data rate under control. We would be using these PHYs
> > with the generic C45 driver, which would be mostly enough except for
> > lack of PHY interrupts, because the firmware already configures
> > everything.
> > 
> > But on the other hand it gets a bit tiring, especially for PHYs on riser
> > cards, to have to change firmware in order to test a different SERDES
> > protocol, so we were experimenting with some changes in the PHY driver
> > that would basically keep the firmware image fixed, and just fix up the
> > configuration it made, and do things like "use 2500base-x for the
> > 2500base-T speed, and sgmii for 1000base-T/100base-TX". The ability for
> > a PHY to work on a board where its firmware image wasn't specifically
> > designed for it comes in handy sometimes.
> 
> You're going to get into problems with this on Layerscape, because
> reconfiguring the Serdes etc is something I've tried to highlight
> as being necessary to NXP since SolidRun started using LX2160A. I
> think there's some slow progress towards that, but it's so slow that
> I've basically given up caring about it on the Honeycomb/Clearfog CX
> boards now.
> 
> All the SFP cages on my Honeycomb have been configured for the most
> useful mode to me - 1000BASE-X/SGMII, and I've given up caring about
> USXGMII/10GBASE-R on those ports.

Speaking of that, do you know of any SFP modules that would use USXGMII?
It doesn't appear to be listed in the spec sheet when looking for that.

> > I see that this patch set basically introduces the phydev->host_interfaces
> > bitmap which is an attempt to find the answer to that question. But when
> > will we know enough about phydev->host_interfaces in order to safely
> > make decisions in the PHY driver based on it? phylink sets it, phylib
> > does not.
> 
> It won't be something phylib could set because phylib doesn't know
> the capabilities of its user - it's information that would need to be
> provided to phylib.

So you're saying it would be in phylib's best interest to not set it at
all, not even to a single bit corresponding to phydev->interface. So PHY
drivers could work out this way whether they should operate in backwards
compatibility mode or they could change MACTYPE at will.

> > And many Aquantia systems use the generic PHY driver, as mentioned.
> > Additionally, there are old device trees at play here, which only define
> > the initial SERDES protocol. Would we be changing the behavior for those,
> > in that we would be configuring the PHY to keep the SERDES protocol
> > fixed whereas it would have dynamically changed before?
> 
> We have the same situation on Macchiatobin. The 88X3310 there defaults
> to MACTYPE mode 4, and we've supported this for years with DT describing
> the interface as 10GBASE-R - because we haven't actually cared very much
> what DT says up to this point for the 88X3310. As I said in my previous
> reply, the 88X3310 effectively dictates what the PHY interface mode will
> be, and that is communicated back through phylib to whoever is using
> phylib.

So what is the full backwards compatibility strategy with old DT blobs?
Is it in this patch set? I didn't notice it.

> > Another question is what to do if there are multiple ways of
> > establishing a system-side link. For example 1000 Mbps can be achieved
> > either through SGMII, or USXGMII with symbol replication, or 2500base-x
> > with flow control, or 10GBaseR with flow control. And I want to test
> > them all. What would I need to do to change the SERDES protocol from one
> > value to the other? Changing the phy-mode array in the device tree would
> > be one option, but that may not always be possible.
> 
> First point to make here is that rate adaption at the PHY is really
> not well supported in Linux, and there is no way to know via phylib if
> a PHY is capable or not of rate adaption.
> 
> Today, if you have a 10GBASE-R link between a PHY doing rate adaption
> and the "MAC", then what you will get from phylib is:
> 
> 	phydev->interface = PHY_INTERFACE_MODE_10GBASER;
> 	phydev->speed = SPEED_1000;	// result of media negotiation
> 	phydev->duplex = DUPLEX_FULL;	// result of media negotiation
> 	phydev->pause = ...;		// result of media negotiation
> 	phydev->asym_pause = ...;	// result of media negotiation
> 
> which will, for the majority of implementations, result in the MAC being
> forced to a 1G speed, possibly with or without pause enabled.
> 
> Due to this, if phylink is being used, the parameters given to
> mac_link_up/pcs_link_up will be the result of the media negotiation, not
> what is required on the actual link.
> 
> You mention "10GBaseR with flow control" but there is another
> possibility that exists in real hardware out there. "10GBaseR without
> flow control" and in that case, the MAC needs to pace its transmission
> for the media speed (which is a good reason why mac_link_up should be
> given the result of the media negotiation so it can do transmission
> pacing.)
> 
> I have a follow-up to the response I gave to Sean Anderson on rate-
> adapting PHYs that I need to finish and send, and it would be better
> to have any discussion on this topic after I've sent that reply and
> follow-up to that reply.

Ok, how would the MAC pace itself to send at a lower data rate, if the
SERDES protocol is 10G and the PHY doesn't send it PAUSE frames back?
At least Layerscape systems can't do this AFAIK.

I can watch for updates on this on the other thread.
Marek Behún Nov. 18, 2021, 3:20 p.m. UTC | #10
On Thu, 18 Nov 2021 17:09:51 +0200
Vladimir Oltean <olteanv@gmail.com> wrote:

> Speaking of that, do you know of any SFP modules that would use USXGMII?
> It doesn't appear to be listed in the spec sheet when looking for that.

RollBall 10G SFP modules, which this series prepares support for,
contain 88X3310 PHY and thus can work in USXGMII. By defualt they use
MACTYPE=6 (10gbase-r with rate matching), but when this series and
the series that adds support for RollBall SFPs are merged, then the SFP
module will work in USXGMII if USXGMII is supported by the host MAC.

Marek
Russell King (Oracle) Nov. 18, 2021, 3:59 p.m. UTC | #11
On Thu, Nov 18, 2021 at 05:09:51PM +0200, Vladimir Oltean wrote:
> On Thu, Nov 18, 2021 at 02:47:44PM +0000, Russell King (Oracle) wrote:
> > You're going to get into problems with this on Layerscape, because
> > reconfiguring the Serdes etc is something I've tried to highlight
> > as being necessary to NXP since SolidRun started using LX2160A. I
> > think there's some slow progress towards that, but it's so slow that
> > I've basically given up caring about it on the Honeycomb/Clearfog CX
> > boards now.
> > 
> > All the SFP cages on my Honeycomb have been configured for the most
> > useful mode to me - 1000BASE-X/SGMII, and I've given up caring about
> > USXGMII/10GBASE-R on those ports.
> 
> Speaking of that, do you know of any SFP modules that would use USXGMII?
> It doesn't appear to be listed in the spec sheet when looking for that.

I only know of one possibility, which is the DM7052 which uses a
Broadcom BCM84881 PHY. I believe the PHY is capable of USXGMII (there's
various references to it on the 'net) to some extent. By that, I mean
it probably does not provide the 16-bit configuration word in USXGMII
mode - just like it doesn't provide it in SGMII mode.

On the DM7052 module, the PHY is not in USXGMII mode, it will switch
interface modes according to the media speed just like the Marvell
88X3310 does. So, it's vital to use the PHY specific driver for this
PHY, and not the generic driver.

Since the datasheet for the PHY is unavailable, it is not known how to
switch it to USXGMII mode, so it may not be possible to do so except
by modifying the pin strapping on the PHY. It may be possible to do it
through vendor registers.

> > > I see that this patch set basically introduces the phydev->host_interfaces
> > > bitmap which is an attempt to find the answer to that question. But when
> > > will we know enough about phydev->host_interfaces in order to safely
> > > make decisions in the PHY driver based on it? phylink sets it, phylib
> > > does not.
> > 
> > It won't be something phylib could set because phylib doesn't know
> > the capabilities of its user - it's information that would need to be
> > provided to phylib.
> 
> So you're saying it would be in phylib's best interest to not set it at
> all, not even to a single bit corresponding to phydev->interface. So PHY
> drivers could work out this way whether they should operate in backwards
> compatibility mode or they could change MACTYPE at will.

That's what I'm thinking - if we end up with a single bit set in the
host interface, does that mean "the host only supports a single
interface type" or does it mean "DT only specified one interface type
and we need to operate in backwards compatibility mode".

If we provide an empty host_interfaces bitmap, then we can easily
detect that it's not set and fallback to compatibility mode - in the
case of 88x3310, that would basically mean not attempting to set
MACTYPE.

> > > And many Aquantia systems use the generic PHY driver, as mentioned.
> > > Additionally, there are old device trees at play here, which only define
> > > the initial SERDES protocol. Would we be changing the behavior for those,
> > > in that we would be configuring the PHY to keep the SERDES protocol
> > > fixed whereas it would have dynamically changed before?
> > 
> > We have the same situation on Macchiatobin. The 88X3310 there defaults
> > to MACTYPE mode 4, and we've supported this for years with DT describing
> > the interface as 10GBASE-R - because we haven't actually cared very much
> > what DT says up to this point for the 88X3310. As I said in my previous
> > reply, the 88X3310 effectively dictates what the PHY interface mode will
> > be, and that is communicated back through phylib to whoever is using
> > phylib.
> 
> So what is the full backwards compatibility strategy with old DT blobs?
> Is it in this patch set? I didn't notice it.

Marek has attempted to create a backwards compatibility in phylink for
this. See phylink_update_phy_modes().

> > > Another question is what to do if there are multiple ways of
> > > establishing a system-side link. For example 1000 Mbps can be achieved
> > > either through SGMII, or USXGMII with symbol replication, or 2500base-x
> > > with flow control, or 10GBaseR with flow control. And I want to test
> > > them all. What would I need to do to change the SERDES protocol from one
> > > value to the other? Changing the phy-mode array in the device tree would
> > > be one option, but that may not always be possible.
> > 
> > First point to make here is that rate adaption at the PHY is really
> > not well supported in Linux, and there is no way to know via phylib if
> > a PHY is capable or not of rate adaption.
> > 
> > Today, if you have a 10GBASE-R link between a PHY doing rate adaption
> > and the "MAC", then what you will get from phylib is:
> > 
> > 	phydev->interface = PHY_INTERFACE_MODE_10GBASER;
> > 	phydev->speed = SPEED_1000;	// result of media negotiation
> > 	phydev->duplex = DUPLEX_FULL;	// result of media negotiation
> > 	phydev->pause = ...;		// result of media negotiation
> > 	phydev->asym_pause = ...;	// result of media negotiation
> > 
> > which will, for the majority of implementations, result in the MAC being
> > forced to a 1G speed, possibly with or without pause enabled.
> > 
> > Due to this, if phylink is being used, the parameters given to
> > mac_link_up/pcs_link_up will be the result of the media negotiation, not
> > what is required on the actual link.
> > 
> > You mention "10GBaseR with flow control" but there is another
> > possibility that exists in real hardware out there. "10GBaseR without
> > flow control" and in that case, the MAC needs to pace its transmission
> > for the media speed (which is a good reason why mac_link_up should be
> > given the result of the media negotiation so it can do transmission
> > pacing.)
> > 
> > I have a follow-up to the response I gave to Sean Anderson on rate-
> > adapting PHYs that I need to finish and send, and it would be better
> > to have any discussion on this topic after I've sent that reply and
> > follow-up to that reply.
> 
> Ok, how would the MAC pace itself to send at a lower data rate, if the
> SERDES protocol is 10G and the PHY doesn't send it PAUSE frames back?
> At least Layerscape systems can't do this AFAIK.

I'm afraid that is an exercise for the reader/MAC driver author since
it's dependent on the hardware.

One would hope that no one would create a system where the PHY needs to
use rate adaption and requires the MAC to pace itself, but the MAC has
no way to achieve that. If such a hardware combination exists, I don't
see how it could work reliably.

However, bear in mind that the 88X3310 on Macchiatobin boards is the
one without MACSEC, so if it is configured to only operate at 10GBASE-R
with rate adaption, then it will not be generating pause frames and it
will expect the MAC to pace. This is about the only platform I have
which I could experiment with a PHY performing rate adaption. However,
I'm not currently sure how useful that would be - it would be nothing
more than an experimentation exercise, and would require MAC pacing
to be implemented in the mvpp2 driver.
diff mbox series

Patch

diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index 0cb9b4ef09c7..94bea1bade6f 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -96,6 +96,11 @@  enum {
 	MV_PCS_PORT_INFO_NPORTS_MASK	= 0x0380,
 	MV_PCS_PORT_INFO_NPORTS_SHIFT	= 7,
 
+	/* SerDes reinitialization 88E21X0 */
+	MV_AN_21X0_SERDES_CTRL2	= 0x800f,
+	MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS	= BIT(13),
+	MV_AN_21X0_SERDES_CTRL2_RUN_INIT	= BIT(15),
+
 	/* These registers appear at 0x800X and 0xa00X - the 0xa00X control
 	 * registers appear to set themselves to the 0x800X when AN is
 	 * restarted, but status registers appear readable from either.
@@ -140,6 +145,8 @@  struct mv3310_chip {
 	bool (*has_downshift)(struct phy_device *phydev);
 	void (*init_supported_interfaces)(unsigned long *mask);
 	int (*get_mactype)(struct phy_device *phydev);
+	int (*set_mactype)(struct phy_device *phydev, int mactype);
+	int (*select_mactype)(unsigned long *interfaces);
 	int (*init_interface)(struct phy_device *phydev, int mactype);
 
 #ifdef CONFIG_HWMON
@@ -593,6 +600,49 @@  static int mv2110_get_mactype(struct phy_device *phydev)
 	return mactype & MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK;
 }
 
+static int mv2110_set_mactype(struct phy_device *phydev, int mactype)
+{
+	int err, val;
+
+	mactype &= MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK;
+	err = phy_modify_mmd(phydev, MDIO_MMD_PMAPMD, MV_PMA_21X0_PORT_CTRL,
+			     MV_PMA_21X0_PORT_CTRL_SWRST |
+			     MV_PMA_21X0_PORT_CTRL_MACTYPE_MASK,
+			     MV_PMA_21X0_PORT_CTRL_SWRST | mactype);
+	if (err)
+		return err;
+
+	err = phy_set_bits_mmd(phydev, MDIO_MMD_AN, MV_AN_21X0_SERDES_CTRL2,
+			       MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS |
+			       MV_AN_21X0_SERDES_CTRL2_RUN_INIT);
+	if (err)
+		return err;
+
+	err = phy_read_mmd_poll_timeout(phydev, MDIO_MMD_AN,
+					MV_AN_21X0_SERDES_CTRL2, val,
+					!(val &
+					  MV_AN_21X0_SERDES_CTRL2_RUN_INIT),
+					5000, 100000, true);
+	if (err)
+		return err;
+
+	return phy_clear_bits_mmd(phydev, MDIO_MMD_AN, MV_AN_21X0_SERDES_CTRL2,
+				  MV_AN_21X0_SERDES_CTRL2_AUTO_INIT_DIS);
+}
+
+static int mv2110_select_mactype(unsigned long *interfaces)
+{
+	if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
+		return MV_PMA_21X0_PORT_CTRL_MACTYPE_USXGMII;
+	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
+		 !test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
+		return MV_PMA_21X0_PORT_CTRL_MACTYPE_5GBASER;
+	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
+		return MV_PMA_21X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
+	else
+		return -1;
+}
+
 static int mv3310_get_mactype(struct phy_device *phydev)
 {
 	int mactype;
@@ -604,6 +654,46 @@  static int mv3310_get_mactype(struct phy_device *phydev)
 	return mactype & MV_V2_33X0_PORT_CTRL_MACTYPE_MASK;
 }
 
+static int mv3310_set_mactype(struct phy_device *phydev, int mactype)
+{
+	int ret;
+
+	mactype &= MV_V2_33X0_PORT_CTRL_MACTYPE_MASK;
+	ret = phy_modify_mmd_changed(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
+				     MV_V2_33X0_PORT_CTRL_MACTYPE_MASK,
+				     mactype);
+	if (ret <= 0)
+		return ret;
+
+	return phy_set_bits_mmd(phydev, MDIO_MMD_VEND2, MV_V2_PORT_CTRL,
+				MV_V2_33X0_PORT_CTRL_SWRST);
+}
+
+static int mv3310_select_mactype(unsigned long *interfaces)
+{
+	if (test_bit(PHY_INTERFACE_MODE_USXGMII, interfaces))
+		return MV_V2_33X0_PORT_CTRL_MACTYPE_USXGMII;
+	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
+		 test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
+		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
+	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
+		 test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
+		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI;
+	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces) &&
+		 test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
+		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI;
+	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, interfaces))
+		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER_RATE_MATCH;
+	else if (test_bit(PHY_INTERFACE_MODE_RXAUI, interfaces))
+		return MV_V2_33X0_PORT_CTRL_MACTYPE_RXAUI_RATE_MATCH;
+	else if (test_bit(PHY_INTERFACE_MODE_XAUI, interfaces))
+		return MV_V2_3310_PORT_CTRL_MACTYPE_XAUI_RATE_MATCH;
+	else if (test_bit(PHY_INTERFACE_MODE_SGMII, interfaces))
+		return MV_V2_33X0_PORT_CTRL_MACTYPE_10GBASER;
+	else
+		return -1;
+}
+
 static int mv2110_init_interface(struct phy_device *phydev, int mactype)
 {
 	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
@@ -674,10 +764,16 @@  static int mv3310_config_init(struct phy_device *phydev)
 {
 	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
 	const struct mv3310_chip *chip = to_mv3310_chip(phydev);
+	DECLARE_PHY_INTERFACE_MASK(interfaces);
 	int err, mactype;
 
-	/* Check that the PHY interface type is compatible */
-	if (!test_bit(phydev->interface, priv->supported_interfaces))
+	/* In case host didn't provide supported interfaces */
+	__set_bit(phydev->interface, phydev->host_interfaces);
+
+	/* Check that there is at least one compatible PHY interface type */
+	phy_interface_and(interfaces, phydev->host_interfaces,
+			  priv->supported_interfaces);
+	if (phy_interface_empty(interfaces))
 		return -ENODEV;
 
 	phydev->mdix_ctrl = ETH_TP_MDI_AUTO;
@@ -687,9 +783,15 @@  static int mv3310_config_init(struct phy_device *phydev)
 	if (err)
 		return err;
 
-	mactype = chip->get_mactype(phydev);
-	if (mactype < 0)
-		return mactype;
+	mactype = chip->select_mactype(interfaces);
+	if (mactype < 0) {
+		mactype = chip->get_mactype(phydev);
+	} else {
+		phydev_info(phydev, "Changing MACTYPE to %i\n", mactype);
+		err = chip->set_mactype(phydev, mactype);
+		if (err)
+			return err;
+	}
 
 	err = chip->init_interface(phydev, mactype);
 	if (err) {
@@ -1049,6 +1151,8 @@  static const struct mv3310_chip mv3310_type = {
 	.has_downshift = mv3310_has_downshift,
 	.init_supported_interfaces = mv3310_init_supported_interfaces,
 	.get_mactype = mv3310_get_mactype,
+	.set_mactype = mv3310_set_mactype,
+	.select_mactype = mv3310_select_mactype,
 	.init_interface = mv3310_init_interface,
 
 #ifdef CONFIG_HWMON
@@ -1060,6 +1164,8 @@  static const struct mv3310_chip mv3340_type = {
 	.has_downshift = mv3310_has_downshift,
 	.init_supported_interfaces = mv3340_init_supported_interfaces,
 	.get_mactype = mv3310_get_mactype,
+	.set_mactype = mv3310_set_mactype,
+	.select_mactype = mv3310_select_mactype,
 	.init_interface = mv3340_init_interface,
 
 #ifdef CONFIG_HWMON
@@ -1070,6 +1176,8 @@  static const struct mv3310_chip mv3340_type = {
 static const struct mv3310_chip mv2110_type = {
 	.init_supported_interfaces = mv2110_init_supported_interfaces,
 	.get_mactype = mv2110_get_mactype,
+	.set_mactype = mv2110_set_mactype,
+	.select_mactype = mv2110_select_mactype,
 	.init_interface = mv2110_init_interface,
 
 #ifdef CONFIG_HWMON
@@ -1080,6 +1188,8 @@  static const struct mv3310_chip mv2110_type = {
 static const struct mv3310_chip mv2111_type = {
 	.init_supported_interfaces = mv2111_init_supported_interfaces,
 	.get_mactype = mv2110_get_mactype,
+	.set_mactype = mv2110_set_mactype,
+	.select_mactype = mv2110_select_mactype,
 	.init_interface = mv2110_init_interface,
 
 #ifdef CONFIG_HWMON