Netdev Archive on lore.kernel.org
 help / color / Atom feed
* [PATCH net] net: dsa: mv88e6xxx: do not allow inband AN for 2500base-x mode
@ 2021-01-14  2:40 Marek Behún
  2021-01-14 23:00 ` Andrew Lunn
  0 siblings, 1 reply; 4+ messages in thread
From: Marek Behún @ 2021-01-14  2:40 UTC (permalink / raw)
  To: netdev
  Cc: pavana.sharma, vivien.didelot, f.fainelli, kuba, lkp, davem,
	ashkan.boldaji, andrew, Chris Packham, olteanv,
	Russell King - ARM Linux admin, Marek Behún, Russell King

Commit a5a6858b793ff ("net: dsa: mv88e6xxx: extend phylink to Serdes
PHYs") introduced method mv88e6390_serdes_pcs_config(), which is called
(indirectly) by phylink to configure the PCS.

This method enables inband AN if requested by phylink.

It seems though that for 2500base-x mode some of these switches (at
least Amethyst) do not support inband AN on Serdes.

Moreover the above mentioned commit causes a regression when the Serdes
of the switch is connected to a Marvell 88X3310 PHY in 2500base-x mode,
because this PHY does not enable inband AN when it self-switches to
2500base-x (nor does it seem to work if manually enabling AN by writing
the register), and it seems that 88E6390 devices won't link on
2500base-x mode if AN is enabled on the switch and disabled on the peer.

Since it seems that 2500base-x mode has no definitive documentation of
what exactly it is, and that Marvell devices disable inband AN when
switching to this mode, this patch disables inband AN when configuring
for 2500base-x in the mv88e6390_serdes_pcs_config() function and prints
a warning if such mode is requested. mv88e6xxx_serdes_pcs_get_state is
edited accordingly.

We may need to refactor phylink code to not request inband AN for
2500base-x at all, but until then we need at least to fix this
regression.

Signed-off-by: Marek Behún <kabel@kernel.org>
Fixes: a5a6858b793ff ("net: dsa: mv88e6xxx: extend phylink to Serdes PHYs")
Cc: Russell King <rmk+kernel@armlinux.org.uk>
---
 drivers/net/dsa/mv88e6xxx/serdes.c | 30 ++++++++++++++++++------------
 1 file changed, 18 insertions(+), 12 deletions(-)

diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
index 3195936dc5be..b8241820679e 100644
--- a/drivers/net/dsa/mv88e6xxx/serdes.c
+++ b/drivers/net/dsa/mv88e6xxx/serdes.c
@@ -55,9 +55,20 @@ static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
 {
 	if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) {
 		state->link = !!(status & MV88E6390_SGMII_PHY_STATUS_LINK);
+
+		if (state->interface == PHY_INTERFACE_MODE_2500BASEX) {
+			if (state->link) {
+				state->speed = SPEED_2500;
+				state->duplex = DUPLEX_FULL;
+			}
+
+			return 0;
+		}
+
+		state->an_complete = 1;
 		state->duplex = status &
 				MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ?
-			                         DUPLEX_FULL : DUPLEX_HALF;
+						DUPLEX_FULL : DUPLEX_HALF;
 
 		if (status & MV88E6390_SGMII_PHY_STATUS_TX_PAUSE)
 			state->pause |= MLO_PAUSE_TX;
@@ -66,10 +77,7 @@ static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
 
 		switch (status & MV88E6390_SGMII_PHY_STATUS_SPEED_MASK) {
 		case MV88E6390_SGMII_PHY_STATUS_SPEED_1000:
-			if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
-				state->speed = SPEED_2500;
-			else
-				state->speed = SPEED_1000;
+			state->speed = SPEED_1000;
 			break;
 		case MV88E6390_SGMII_PHY_STATUS_SPEED_100:
 			state->speed = SPEED_100;
@@ -85,10 +93,7 @@ static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
 		state->link = false;
 	}
 
-	if (state->interface == PHY_INTERFACE_MODE_2500BASEX)
-		mii_lpa_mod_linkmode_x(state->lp_advertising, lpa,
-				       ETHTOOL_LINK_MODE_2500baseX_Full_BIT);
-	else if (state->interface == PHY_INTERFACE_MODE_1000BASEX)
+	if (state->interface == PHY_INTERFACE_MODE_1000BASEX)
 		mii_lpa_mod_linkmode_x(state->lp_advertising, lpa,
 				       ETHTOOL_LINK_MODE_1000baseX_Full_BIT);
 
@@ -820,9 +825,10 @@ int mv88e6390_serdes_pcs_config(struct mv88e6xxx_chip *chip, int port,
 		break;
 
 	case PHY_INTERFACE_MODE_2500BASEX:
-		adv = linkmode_adv_to_mii_adv_x(advertise,
-					ETHTOOL_LINK_MODE_2500baseX_Full_BIT);
-		break;
+		if (phylink_autoneg_inband(mode))
+			dev_warn(chip->dev,
+				 "inband AN unsupported on 2500base-x mode\n");
+		return 0;
 
 	default:
 		return 0;

base-commit: f50e2f9f791647aa4e5b19d0064f5cabf630bf6e
-- 
2.26.2


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH net] net: dsa: mv88e6xxx: do not allow inband AN for 2500base-x mode
  2021-01-14  2:40 [PATCH net] net: dsa: mv88e6xxx: do not allow inband AN for 2500base-x mode Marek Behún
@ 2021-01-14 23:00 ` Andrew Lunn
  2021-01-14 23:55   ` Marek Behún
  0 siblings, 1 reply; 4+ messages in thread
From: Andrew Lunn @ 2021-01-14 23:00 UTC (permalink / raw)
  To: Marek Behún
  Cc: netdev, pavana.sharma, vivien.didelot, f.fainelli, kuba, lkp,
	davem, ashkan.boldaji, Chris Packham, olteanv,
	Russell King - ARM Linux admin, Russell King

> diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
> index 3195936dc5be..b8241820679e 100644
> --- a/drivers/net/dsa/mv88e6xxx/serdes.c
> +++ b/drivers/net/dsa/mv88e6xxx/serdes.c
> @@ -55,9 +55,20 @@ static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
>  {
>  	if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) {
>  		state->link = !!(status & MV88E6390_SGMII_PHY_STATUS_LINK);
> +
> +		if (state->interface == PHY_INTERFACE_MODE_2500BASEX) {
> +			if (state->link) {
> +				state->speed = SPEED_2500;
> +				state->duplex = DUPLEX_FULL;
> +			}
> +
> +			return 0;
> +		}
> +
> +		state->an_complete = 1;

Should this be here? It seems like a logically different change, it is
not clear to me it is to do with PHY_INTERFACE_MODE_2500BASEX.

>  		state->duplex = status &
>  				MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ?
> -			                         DUPLEX_FULL : DUPLEX_HALF;
> +						DUPLEX_FULL : DUPLEX_HALF;

This looks like an unintended white space change.

     Andrew

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH net] net: dsa: mv88e6xxx: do not allow inband AN for 2500base-x mode
  2021-01-14 23:00 ` Andrew Lunn
@ 2021-01-14 23:55   ` Marek Behún
  2021-01-15 14:16     ` Andrew Lunn
  0 siblings, 1 reply; 4+ messages in thread
From: Marek Behún @ 2021-01-14 23:55 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: netdev, pavana.sharma, vivien.didelot, f.fainelli, kuba, lkp,
	davem, ashkan.boldaji, Chris Packham, olteanv,
	Russell King - ARM Linux admin, Russell King

On Fri, 15 Jan 2021 00:00:33 +0100
Andrew Lunn <andrew@lunn.ch> wrote:

> > diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
> > index 3195936dc5be..b8241820679e 100644
> > --- a/drivers/net/dsa/mv88e6xxx/serdes.c
> > +++ b/drivers/net/dsa/mv88e6xxx/serdes.c
> > @@ -55,9 +55,20 @@ static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
> >  {
> >  	if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) {
> >  		state->link = !!(status & MV88E6390_SGMII_PHY_STATUS_LINK);
> > +
> > +		if (state->interface == PHY_INTERFACE_MODE_2500BASEX) {
> > +			if (state->link) {
> > +				state->speed = SPEED_2500;
> > +				state->duplex = DUPLEX_FULL;
> > +			}
> > +
> > +			return 0;
> > +		}
> > +
> > +		state->an_complete = 1;  
> 
> Should this be here? It seems like a logically different change, it is
> not clear to me it is to do with PHY_INTERFACE_MODE_2500BASEX.

This function does not set an_complete at all, and as I understand it,
it should. But maybe this should be in different commit, and more
thought put into it. I will rethink it and send another version.

> >  		state->duplex = status &
> >  				MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ?
> > -			                         DUPLEX_FULL : DUPLEX_HALF;
> > +						DUPLEX_FULL : DUPLEX_HALF;  
> 
> This looks like an unintended white space change.

This change is intended. There were 17 space there istead of 2 tabs + 1
space. And the last space is not needed, since it does not provide any
other alignment. Should this be in separate commit?

BTW Andrew, the code in serdes.c does many read and write calls, and it
could be simplified a lot by implementing modify, setbits and clearbits
methods, like phy.h implements. Or maybe we can use phy_mmd_* methods
here instead of mv88e6390_serdes_read/write ?

I fear such change will make future backporting of new fix commits
a pain. But I still think it should be done. What do you think?

Marek

^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH net] net: dsa: mv88e6xxx: do not allow inband AN for 2500base-x mode
  2021-01-14 23:55   ` Marek Behún
@ 2021-01-15 14:16     ` Andrew Lunn
  0 siblings, 0 replies; 4+ messages in thread
From: Andrew Lunn @ 2021-01-15 14:16 UTC (permalink / raw)
  To: Marek Behún
  Cc: netdev, pavana.sharma, vivien.didelot, f.fainelli, kuba, lkp,
	davem, ashkan.boldaji, Chris Packham, olteanv,
	Russell King - ARM Linux admin, Russell King

On Fri, Jan 15, 2021 at 12:55:16AM +0100, Marek Behún wrote:
> On Fri, 15 Jan 2021 00:00:33 +0100
> Andrew Lunn <andrew@lunn.ch> wrote:
> 
> > > diff --git a/drivers/net/dsa/mv88e6xxx/serdes.c b/drivers/net/dsa/mv88e6xxx/serdes.c
> > > index 3195936dc5be..b8241820679e 100644
> > > --- a/drivers/net/dsa/mv88e6xxx/serdes.c
> > > +++ b/drivers/net/dsa/mv88e6xxx/serdes.c
> > > @@ -55,9 +55,20 @@ static int mv88e6xxx_serdes_pcs_get_state(struct mv88e6xxx_chip *chip,
> > >  {
> > >  	if (status & MV88E6390_SGMII_PHY_STATUS_SPD_DPL_VALID) {
> > >  		state->link = !!(status & MV88E6390_SGMII_PHY_STATUS_LINK);
> > > +
> > > +		if (state->interface == PHY_INTERFACE_MODE_2500BASEX) {
> > > +			if (state->link) {
> > > +				state->speed = SPEED_2500;
> > > +				state->duplex = DUPLEX_FULL;
> > > +			}
> > > +
> > > +			return 0;
> > > +		}
> > > +
> > > +		state->an_complete = 1;  
> > 
> > Should this be here? It seems like a logically different change, it is
> > not clear to me it is to do with PHY_INTERFACE_MODE_2500BASEX.
> 
> This function does not set an_complete at all, and as I understand it,
> it should. But maybe this should be in different commit, and more
> thought put into it. I will rethink it and send another version.

Thanks. A patch should do one thing, do it well, and have a good
commit message explaining why it is making the change. So yes, please
do put this into a patch of its own.

> 
> > >  		state->duplex = status &
> > >  				MV88E6390_SGMII_PHY_STATUS_DUPLEX_FULL ?
> > > -			                         DUPLEX_FULL : DUPLEX_HALF;
> > > +						DUPLEX_FULL : DUPLEX_HALF;  
> > 
> > This looks like an unintended white space change.
> 
> This change is intended. There were 17 space there istead of 2 tabs + 1
> space. And the last space is not needed, since it does not provide any
> other alignment. Should this be in separate commit?

Yes, white space changes should always be in a separate patch. They
distract from the actual change being made here.

> BTW Andrew, the code in serdes.c does many read and write calls, and it
> could be simplified a lot by implementing modify, setbits and clearbits
> methods, like phy.h implements. Or maybe we can use phy_mmd_* methods
> here instead of mv88e6390_serdes_read/write ?
> 
> I fear such change will make future backporting of new fix commits
> a pain. But I still think it should be done. What do you think?

As you say, it make backporting hard. Are the simplifications worth
it? And it is not limited to just SERDES code, the whole driver has
bits of code doing read/modify/write, so if you are going to make such
changes, it should be done everywhere.

	 Andrew

^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, back to index

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-01-14  2:40 [PATCH net] net: dsa: mv88e6xxx: do not allow inband AN for 2500base-x mode Marek Behún
2021-01-14 23:00 ` Andrew Lunn
2021-01-14 23:55   ` Marek Behún
2021-01-15 14:16     ` Andrew Lunn

Netdev Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/netdev/0 netdev/git/0.git
	git clone --mirror https://lore.kernel.org/netdev/1 netdev/git/1.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 netdev netdev/ https://lore.kernel.org/netdev \
		netdev@vger.kernel.org
	public-inbox-index netdev

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.kernel.vger.netdev


AGPL code for this site: git clone https://public-inbox.org/public-inbox.git