diff mbox series

[RFC,net-next] net: phy: marvell10g: add downshift tunable support

Message ID E1m5pwy-0003uX-Pf@rmk-PC.armlinux.org.uk (mailing list archive)
State RFC
Delegated to: Netdev Maintainers
Headers show
Series [RFC,net-next] net: phy: marvell10g: add downshift tunable support | expand

Checks

Context Check Description
netdev/cover_letter success Link
netdev/fixes_present success Link
netdev/patch_count success Link
netdev/tree_selection success Clearly marked for net-next
netdev/subject_prefix success Link
netdev/cc_maintainers warning 1 maintainers not CCed: linux@armlinux.org.uk
netdev/source_inline success Was 0 now: 0
netdev/verify_signedoff success Link
netdev/module_param success Was 0 now: 0
netdev/build_32bit success Errors and warnings before: 0 this patch: 0
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/verify_fixes success Link
netdev/checkpatch fail ERROR: space required after that ',' (ctx:VxV)
netdev/build_allmodconfig_warn success Errors and warnings before: 0 this patch: 0
netdev/header_inline success Link

Commit Message

Russell King (Oracle) July 20, 2021, 1:38 p.m. UTC
Add support for the downshift tunable for the Marvell 88x3310 PHY.
Downshift is only usable with firmware 0.3.5.0 and later.

Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
---

It would be useful to have views on the "FIXME" comment in this patch
please. Thanks.

 drivers/net/phy/marvell10g.c | 87 +++++++++++++++++++++++++++++++++++-
 1 file changed, 86 insertions(+), 1 deletion(-)

Comments

Andrew Lunn July 20, 2021, 2:28 p.m. UTC | #1
> +static int mv3310_set_downshift(struct phy_device *phydev, u8 ds)
> +{
> +	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
> +	u16 val;
> +	int err;
> +
> +	/* Fails to downshift with v0.3.5.0 and earlier */
> +	if (priv->firmware_ver < MV_VERSION(0,3,5,0))
> +		return -EOPNOTSUPP;
> +
> +	if (ds == DOWNSHIFT_DEV_DISABLE)
> +		return phy_clear_bits_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1,
> +					  MV_PCS_DSC1_ENABLE);
> +
> +	/* FIXME: The default is disabled, so should we disable? */
> +	if (ds == DOWNSHIFT_DEV_DEFAULT_COUNT)
> +		ds = 2;

Interesting question.

It is a useful feature, so i would enable it by default.

Is it possible to read the actual speed via some vendor register?  The
phy-core might then give a warning, but it is 50/50 since the link
peer might perform the downshift.

   Andrew
Russell King (Oracle) July 20, 2021, 2:30 p.m. UTC | #2
On Tue, Jul 20, 2021 at 04:28:12PM +0200, Andrew Lunn wrote:
> > +static int mv3310_set_downshift(struct phy_device *phydev, u8 ds)
> > +{
> > +	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
> > +	u16 val;
> > +	int err;
> > +
> > +	/* Fails to downshift with v0.3.5.0 and earlier */
> > +	if (priv->firmware_ver < MV_VERSION(0,3,5,0))
> > +		return -EOPNOTSUPP;
> > +
> > +	if (ds == DOWNSHIFT_DEV_DISABLE)
> > +		return phy_clear_bits_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1,
> > +					  MV_PCS_DSC1_ENABLE);
> > +
> > +	/* FIXME: The default is disabled, so should we disable? */
> > +	if (ds == DOWNSHIFT_DEV_DEFAULT_COUNT)
> > +		ds = 2;
> 
> Interesting question.
> 
> It is a useful feature, so i would enable it by default.
> 
> Is it possible to read the actual speed via some vendor register?  The
> phy-core might then give a warning, but it is 50/50 since the link
> peer might perform the downshift.

We already do read the actual negotiated speed anbd other parameters
from the MV_PCS_CSSR1 register.
Marek Behún July 20, 2021, 3:04 p.m. UTC | #3
Hi Russell,

On Tue, 20 Jul 2021 14:38:20 +0100
Russell King <rmk+kernel@armlinux.org.uk> wrote:

> Add support for the downshift tunable for the Marvell 88x3310 PHY.
> Downshift is only usable with firmware 0.3.5.0 and later.

mv3310_{g,s}et_features are also used for 88E211x, but there is no such
register in the documentation for these PHYs. (Also firmware versions on
those are different, the newest is 8.3.0.0, but thats not important.)
My solution would be to rename the current methods prefix to mv211x_ and
and add new mv3310_{g,s}et_tunable methods.

Marek
Russell King (Oracle) July 20, 2021, 5:14 p.m. UTC | #4
On Tue, Jul 20, 2021 at 05:04:24PM +0200, Marek Behún wrote:
> Hi Russell,
> 
> On Tue, 20 Jul 2021 14:38:20 +0100
> Russell King <rmk+kernel@armlinux.org.uk> wrote:
> 
> > Add support for the downshift tunable for the Marvell 88x3310 PHY.
> > Downshift is only usable with firmware 0.3.5.0 and later.
> 
> mv3310_{g,s}et_features are also used for 88E211x, but there is no such
> register in the documentation for these PHYs. (Also firmware versions on
> those are different, the newest is 8.3.0.0, but thats not important.)
> My solution would be to rename the current methods prefix to mv211x_ and
> and add new mv3310_{g,s}et_tunable methods.

There's more than just the tunables themselves - there's also
config_init().

We already need to reject downshift when old firmware is running,
as that fails to work correctly. So, we can just do that for
88E211x as well, adding a flag to struct mv3310_chip to indicate
whether downshift is present. Sound sensible?
Marek Behún July 20, 2021, 5:32 p.m. UTC | #5
On Tue, 20 Jul 2021 18:14:01 +0100
"Russell King (Oracle)" <linux@armlinux.org.uk> wrote:

> On Tue, Jul 20, 2021 at 05:04:24PM +0200, Marek Behún wrote:
> > Hi Russell,
> > 
> > On Tue, 20 Jul 2021 14:38:20 +0100
> > Russell King <rmk+kernel@armlinux.org.uk> wrote:
> >   
> > > Add support for the downshift tunable for the Marvell 88x3310 PHY.
> > > Downshift is only usable with firmware 0.3.5.0 and later.  
> > 
> > mv3310_{g,s}et_features are also used for 88E211x, but there is no
> > such register in the documentation for these PHYs. (Also firmware
> > versions on those are different, the newest is 8.3.0.0, but thats
> > not important.) My solution would be to rename the current methods
> > prefix to mv211x_ and and add new mv3310_{g,s}et_tunable methods.  
> 
> There's more than just the tunables themselves - there's also
> config_init().
> 
> We already need to reject downshift when old firmware is running,
> as that fails to work correctly. So, we can just do that for
> 88E211x as well, adding a flag to struct mv3310_chip to indicate
> whether downshift is present. Sound sensible?

Hmm, maybe add the flag to struct mv3310_priv, instead of struct
mv3310_chip, since the latter is static. And fill in the flag in
mv3310_probe() function, depending on firmware version?

BTW would you agree with a patch renaming the mv3310_ prefixes to
mv10g_ for all functions that are generic to both mv3310_ and mv2110_?
I was thinking about such a thing because it has become rather
confusing.

Marek
Russell King (Oracle) July 20, 2021, 5:39 p.m. UTC | #6
On Tue, Jul 20, 2021 at 07:32:23PM +0200, Marek Behún wrote:
> On Tue, 20 Jul 2021 18:14:01 +0100
> "Russell King (Oracle)" <linux@armlinux.org.uk> wrote:
> 
> > On Tue, Jul 20, 2021 at 05:04:24PM +0200, Marek Behún wrote:
> > > Hi Russell,
> > > 
> > > On Tue, 20 Jul 2021 14:38:20 +0100
> > > Russell King <rmk+kernel@armlinux.org.uk> wrote:
> > >   
> > > > Add support for the downshift tunable for the Marvell 88x3310 PHY.
> > > > Downshift is only usable with firmware 0.3.5.0 and later.  
> > > 
> > > mv3310_{g,s}et_features are also used for 88E211x, but there is no
> > > such register in the documentation for these PHYs. (Also firmware
> > > versions on those are different, the newest is 8.3.0.0, but thats
> > > not important.) My solution would be to rename the current methods
> > > prefix to mv211x_ and and add new mv3310_{g,s}et_tunable methods.  
> > 
> > There's more than just the tunables themselves - there's also
> > config_init().
> > 
> > We already need to reject downshift when old firmware is running,
> > as that fails to work correctly. So, we can just do that for
> > 88E211x as well, adding a flag to struct mv3310_chip to indicate
> > whether downshift is present. Sound sensible?
> 
> Hmm, maybe add the flag to struct mv3310_priv, instead of struct
> mv3310_chip, since the latter is static. And fill in the flag in
> mv3310_probe() function, depending on firmware version?

I was intending to leave the firmware version check where it was and
just add a flag to say "this has downshift". The older firmwares on
3310 are basically buggy - they do downshift but only from 1G to 100M,
they fail to go to 10M.

> BTW would you agree with a patch renaming the mv3310_ prefixes to
> mv10g_ for all functions that are generic to both mv3310_ and mv2110_?
> I was thinking about such a thing because it has become rather
> confusing.

I've been thinking the same thing actually.
Marek Behún July 20, 2021, 5:50 p.m. UTC | #7
On Tue, 20 Jul 2021 18:39:41 +0100
"Russell King (Oracle)" <linux@armlinux.org.uk> wrote:

> I was intending to leave the firmware version check where it was and
> just add a flag to say "this has downshift". The older firmwares on
> 3310 are basically buggy - they do downshift but only from 1G to 100M,
> they fail to go to 10M.

So we have two options

* do the firmware version comparison at the position where the given
  feature is being configured

* do the firmware version comparison in probe method and set specific
  flags for all features

The second option is better if different PHYs have differnet system of
versioning, but this can potentially lead to many different flags.

I'll leave this decision to you.

> > BTW would you agree with a patch renaming the mv3310_ prefixes to
> > mv10g_ for all functions that are generic to both mv3310_ and
> > mv2110_?
> > I was thinking about such a thing because it has become rather
> > confusing.  
> 
> I've been thinking the same thing actually.

OK I will send a patch then once your downshift patch is applied.

Marek
diff mbox series

Patch

diff --git a/drivers/net/phy/marvell10g.c b/drivers/net/phy/marvell10g.c
index 0b7cae118ad7..0c9e7e1fab91 100644
--- a/drivers/net/phy/marvell10g.c
+++ b/drivers/net/phy/marvell10g.c
@@ -22,6 +22,7 @@ 
  * If both the fiber and copper ports are connected, the first to gain
  * link takes priority and the other port is completely locked out.
  */
+#include <linux/bitfield.h>
 #include <linux/ctype.h>
 #include <linux/delay.h>
 #include <linux/hwmon.h>
@@ -33,6 +34,8 @@ 
 #define MV_PHY_ALASKA_NBT_QUIRK_MASK	0xfffffffe
 #define MV_PHY_ALASKA_NBT_QUIRK_REV	(MARVELL_PHY_ID_88X3310 | 0xa)
 
+#define MV_VERSION(a,b,c,d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
+
 enum {
 	MV_PMA_FW_VER0		= 0xc011,
 	MV_PMA_FW_VER1		= 0xc012,
@@ -62,6 +65,15 @@  enum {
 	MV_PCS_CSCR1_MDIX_MDIX	= 0x0020,
 	MV_PCS_CSCR1_MDIX_AUTO	= 0x0060,
 
+	MV_PCS_DSC1		= 0x8003,
+	MV_PCS_DSC1_ENABLE	= BIT(9),
+	MV_PCS_DSC1_10GBT	= 0x01c0,
+	MV_PCS_DSC1_1GBR	= 0x0038,
+	MV_PCS_DSC1_100BTX	= 0x0007,
+	MV_PCS_DSC2		= 0x8004,
+	MV_PCS_DSC2_2P5G	= 0xf000,
+	MV_PCS_DSC2_5G		= 0x0f00,
+
 	MV_PCS_CSSR1		= 0x8008,
 	MV_PCS_CSSR1_SPD1_MASK	= 0xc000,
 	MV_PCS_CSSR1_SPD1_SPD2	= 0xc000,
@@ -330,6 +342,66 @@  static int mv3310_reset(struct phy_device *phydev, u32 unit)
 					 5000, 100000, true);
 }
 
+static int mv3310_get_downshift(struct phy_device *phydev, u8 *ds)
+{
+	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+	int val;
+
+	if (priv->firmware_ver < MV_VERSION(0,3,5,0))
+		return -EOPNOTSUPP;
+
+	val = phy_read_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1);
+	if (val < 0)
+		return val;
+
+	if (val & MV_PCS_DSC1_ENABLE)
+		/* assume that all fields are the same */
+		*ds = 1 + FIELD_GET(MV_PCS_DSC1_10GBT, (u16)val);
+	else
+		*ds = DOWNSHIFT_DEV_DISABLE;
+
+	return 0;
+}
+
+static int mv3310_set_downshift(struct phy_device *phydev, u8 ds)
+{
+	struct mv3310_priv *priv = dev_get_drvdata(&phydev->mdio.dev);
+	u16 val;
+	int err;
+
+	/* Fails to downshift with v0.3.5.0 and earlier */
+	if (priv->firmware_ver < MV_VERSION(0,3,5,0))
+		return -EOPNOTSUPP;
+
+	if (ds == DOWNSHIFT_DEV_DISABLE)
+		return phy_clear_bits_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1,
+					  MV_PCS_DSC1_ENABLE);
+
+	/* FIXME: The default is disabled, so should we disable? */
+	if (ds == DOWNSHIFT_DEV_DEFAULT_COUNT)
+		ds = 2;
+
+	if (ds > 8)
+		return -E2BIG;
+
+	ds -= 1;
+	val = FIELD_PREP(MV_PCS_DSC2_2P5G, ds);
+	val |= FIELD_PREP(MV_PCS_DSC2_5G, ds);
+	err = phy_modify_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC2,
+			     MV_PCS_DSC2_2P5G | MV_PCS_DSC2_5G, val);
+	if (err < 0)
+		return err;
+
+	val = MV_PCS_DSC1_ENABLE;
+	val |= FIELD_PREP(MV_PCS_DSC1_10GBT, ds);
+	val |= FIELD_PREP(MV_PCS_DSC1_1GBR, ds);
+	val |= FIELD_PREP(MV_PCS_DSC1_100BTX, ds);
+
+	return phy_modify_mmd(phydev, MDIO_MMD_PCS, MV_PCS_DSC1,
+			      MV_PCS_DSC1_ENABLE | MV_PCS_DSC1_10GBT |
+			      MV_PCS_DSC1_1GBR | MV_PCS_DSC1_100BTX, val);
+}
+
 static int mv3310_get_edpd(struct phy_device *phydev, u16 *edpd)
 {
 	int val;
@@ -616,7 +688,16 @@  static int mv3310_config_init(struct phy_device *phydev)
 	}
 
 	/* Enable EDPD mode - saving 600mW */
-	return mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS);
+	err = mv3310_set_edpd(phydev, ETHTOOL_PHY_EDPD_DFLT_TX_MSECS);
+	if (err)
+		return err;
+
+	/* Allow downshift */
+	err = mv3310_set_downshift(phydev, DOWNSHIFT_DEV_DEFAULT_COUNT);
+	if (err && err != -EOPNOTSUPP)
+		return err;
+
+	return 0;
 }
 
 static int mv3310_get_features(struct phy_device *phydev)
@@ -886,6 +967,8 @@  static int mv3310_get_tunable(struct phy_device *phydev,
 			      struct ethtool_tunable *tuna, void *data)
 {
 	switch (tuna->id) {
+	case ETHTOOL_PHY_DOWNSHIFT:
+		return mv3310_get_downshift(phydev, data);
 	case ETHTOOL_PHY_EDPD:
 		return mv3310_get_edpd(phydev, data);
 	default:
@@ -897,6 +980,8 @@  static int mv3310_set_tunable(struct phy_device *phydev,
 			      struct ethtool_tunable *tuna, const void *data)
 {
 	switch (tuna->id) {
+	case ETHTOOL_PHY_DOWNSHIFT:
+		return mv3310_set_downshift(phydev, *(u8 *)data);
 	case ETHTOOL_PHY_EDPD:
 		return mv3310_set_edpd(phydev, *(u16 *)data);
 	default: