* [PATCH net-next 0/2] net: phy: microchip: add downshift support for LAN88xx
@ 2026-03-29 22:41 Nicolai Buchwitz
2026-03-29 22:41 ` [PATCH 1/2] net: phy: microchip: add downshift tunable " Nicolai Buchwitz
` (2 more replies)
0 siblings, 3 replies; 13+ messages in thread
From: Nicolai Buchwitz @ 2026-03-29 22:41 UTC (permalink / raw)
To: netdev; +Cc: Phil Elwell, Nicolai Buchwitz
Add standard ETHTOOL_PHY_DOWNSHIFT tunable support for the Microchip
LAN88xx PHY, following the same pattern used by Marvell and other PHY
drivers.
Ethernet cables with faulty or missing pairs (specifically C and D)
can successfully auto-negotiate 1000BASE-T but fail to establish a
stable link. The LAN88xx PHY supports automatic downshift to
100BASE-TX after a configurable number of failed attempts (2-5).
Patch 1 adds the get/set tunable implementation.
Patch 2 enables downshift by default with a count of 2.
Based on an earlier downstream implementation by Phil Elwell.
Tested on Raspberry Pi 3B+ (LAN7515/LAN88xx).
Nicolai Buchwitz (2):
net: phy: microchip: add downshift tunable support for LAN88xx
net: phy: microchip: enable downshift by default on LAN88xx
drivers/net/phy/microchip.c | 96 +++++++++++++++++++++++++++++++++++-
include/linux/microchipphy.h | 9 ++++
2 files changed, 104 insertions(+), 1 deletion(-)
--
2.51.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH 1/2] net: phy: microchip: add downshift tunable support for LAN88xx
2026-03-29 22:41 [PATCH net-next 0/2] net: phy: microchip: add downshift support for LAN88xx Nicolai Buchwitz
@ 2026-03-29 22:41 ` Nicolai Buchwitz
2026-03-30 13:01 ` Andrew Lunn
2026-03-30 13:02 ` Andrew Lunn
2026-03-29 22:42 ` [PATCH 2/2] net: phy: microchip: enable downshift by default on LAN88xx Nicolai Buchwitz
2026-04-01 12:38 ` [PATCH net-next v3 0/2] net: phy: microchip: add downshift support for LAN88xx Nicolai Buchwitz
2 siblings, 2 replies; 13+ messages in thread
From: Nicolai Buchwitz @ 2026-03-29 22:41 UTC (permalink / raw)
To: netdev
Cc: Phil Elwell, Nicolai Buchwitz, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, linux-kernel
Implement the standard ETHTOOL_PHY_DOWNSHIFT tunable for the LAN88xx
PHY. This allows runtime configuration of the auto-downshift feature
via ethtool:
ethtool --set-phy-tunable eth0 downshift on count 3
The LAN88xx PHY supports downshifting from 1000BASE-T to 100BASE-TX
after 2-5 failed auto-negotiation attempts. Valid count values are
2, 3, 4 and 5.
This is based on an earlier downstream implementation by Phil Elwell.
Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
---
drivers/net/phy/microchip.c | 89 ++++++++++++++++++++++++++++++++++++
include/linux/microchipphy.h | 9 ++++
2 files changed, 98 insertions(+)
diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c
index dc8634e7bcbe..a044be1ade79 100644
--- a/drivers/net/phy/microchip.c
+++ b/drivers/net/phy/microchip.c
@@ -193,6 +193,93 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev)
phydev_warn(phydev, "Failed to Set Register[0x1686]\n");
}
+static int lan88xx_get_downshift(struct phy_device *phydev, u8 *data)
+{
+ int val;
+
+ val = phy_read_paged(phydev, 1, LAN78XX_PHY_CTRL3);
+ if (val < 0)
+ return val;
+
+ if (!(val & LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT)) {
+ *data = DOWNSHIFT_DEV_DISABLE;
+ return 0;
+ }
+
+ switch (val & LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK) {
+ case LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2:
+ *data = 2;
+ break;
+ case LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3:
+ *data = 3;
+ break;
+ case LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4:
+ *data = 4;
+ break;
+ case LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5:
+ *data = 5;
+ break;
+ }
+
+ return 0;
+}
+
+static int lan88xx_set_downshift(struct phy_device *phydev, u8 cnt)
+{
+ u32 mask = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK |
+ LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT;
+ u32 val;
+
+ if (cnt == DOWNSHIFT_DEV_DISABLE)
+ return phy_modify_paged(phydev, 1, LAN78XX_PHY_CTRL3,
+ LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT, 0);
+
+ if (cnt == DOWNSHIFT_DEV_DEFAULT_COUNT)
+ cnt = 2;
+
+ switch (cnt) {
+ case 2:
+ val = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2;
+ break;
+ case 3:
+ val = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3;
+ break;
+ case 4:
+ val = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4;
+ break;
+ case 5:
+ val = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return phy_modify_paged(phydev, 1, LAN78XX_PHY_CTRL3, mask,
+ val | LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT);
+}
+
+static int lan88xx_get_tunable(struct phy_device *phydev,
+ struct ethtool_tunable *tuna, void *data)
+{
+ switch (tuna->id) {
+ case ETHTOOL_PHY_DOWNSHIFT:
+ return lan88xx_get_downshift(phydev, data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int lan88xx_set_tunable(struct phy_device *phydev,
+ struct ethtool_tunable *tuna, const void *data)
+{
+ switch (tuna->id) {
+ case ETHTOOL_PHY_DOWNSHIFT:
+ return lan88xx_set_downshift(phydev, *(const u8 *)data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static int lan88xx_probe(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
@@ -499,6 +586,8 @@ static struct phy_driver microchip_phy_driver[] = {
.set_wol = lan88xx_set_wol,
.read_page = lan88xx_read_page,
.write_page = lan88xx_write_page,
+ .get_tunable = lan88xx_get_tunable,
+ .set_tunable = lan88xx_set_tunable,
},
{
PHY_ID_MATCH_MODEL(PHY_ID_LAN937X_TX),
diff --git a/include/linux/microchipphy.h b/include/linux/microchipphy.h
index 517288da19fd..a8deae3977e9 100644
--- a/include/linux/microchipphy.h
+++ b/include/linux/microchipphy.h
@@ -61,6 +61,15 @@
/* Registers specific to the LAN7800/LAN7850 embedded phy */
#define LAN78XX_PHY_LED_MODE_SELECT (0x1D)
+/* PHY Control 3 register (page 1) */
+#define LAN78XX_PHY_CTRL3 (0x14)
+#define LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT BIT(4)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK GENMASK(3, 2)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2 (0 << 2)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3 (1 << 2)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4 (2 << 2)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5 (3 << 2)
+
/* DSP registers */
#define PHY_ARDENNES_MMD_DEV_3_PHY_CFG (0x806A)
#define PHY_ARDENNES_MMD_DEV_3_PHY_CFG_ZD_DLY_EN_ (0x2000)
--
2.51.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH 2/2] net: phy: microchip: enable downshift by default on LAN88xx
2026-03-29 22:41 [PATCH net-next 0/2] net: phy: microchip: add downshift support for LAN88xx Nicolai Buchwitz
2026-03-29 22:41 ` [PATCH 1/2] net: phy: microchip: add downshift tunable " Nicolai Buchwitz
@ 2026-03-29 22:42 ` Nicolai Buchwitz
2026-03-30 13:03 ` Andrew Lunn
2026-04-01 12:38 ` [PATCH net-next v3 0/2] net: phy: microchip: add downshift support for LAN88xx Nicolai Buchwitz
2 siblings, 1 reply; 13+ messages in thread
From: Nicolai Buchwitz @ 2026-03-29 22:42 UTC (permalink / raw)
To: netdev
Cc: Phil Elwell, Nicolai Buchwitz, Andrew Lunn, Heiner Kallweit,
Russell King, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, linux-kernel
Enable auto-downshift from 1000BASE-T to 100BASE-TX after 2 failed
auto-negotiation attempts by default. This ensures that links with
faulty or missing cable pairs (C and D) fall back to 100Mbps without
requiring userspace configuration.
Users can override or disable downshift at runtime:
ethtool --set-phy-tunable eth0 downshift off
Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
---
drivers/net/phy/microchip.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c
index a044be1ade79..3455fe713088 100644
--- a/drivers/net/phy/microchip.c
+++ b/drivers/net/phy/microchip.c
@@ -371,7 +371,7 @@ static void lan88xx_set_mdix(struct phy_device *phydev)
static int lan88xx_config_init(struct phy_device *phydev)
{
- int val;
+ int val, err;
/*Zerodetect delay enable */
val = phy_read_mmd(phydev, MDIO_MMD_PCS,
@@ -384,6 +384,11 @@ static int lan88xx_config_init(struct phy_device *phydev)
/* Config DSP registers */
lan88xx_config_TR_regs(phydev);
+ /* Enable downshift after 2 failed attempts by default */
+ err = lan88xx_set_downshift(phydev, 2);
+ if (err < 0)
+ return err;
+
return 0;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH 1/2] net: phy: microchip: add downshift tunable support for LAN88xx
2026-03-29 22:41 ` [PATCH 1/2] net: phy: microchip: add downshift tunable " Nicolai Buchwitz
@ 2026-03-30 13:01 ` Andrew Lunn
2026-03-30 14:57 ` Nicolai Buchwitz
2026-03-30 13:02 ` Andrew Lunn
1 sibling, 1 reply; 13+ messages in thread
From: Andrew Lunn @ 2026-03-30 13:01 UTC (permalink / raw)
To: Nicolai Buchwitz
Cc: netdev, Phil Elwell, Heiner Kallweit, Russell King,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
linux-kernel
> + switch (val & LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK) {
> + case LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2:
> + *data = 2;
> + break;
> + case LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3:
> + *data = 3;
> + break;
> + case LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4:
> + *data = 4;
> + break;
> + case LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5:
> + *data = 5;
> + break;
> + }
> +#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2 (0 << 2)
> +#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3 (1 << 2)
> +#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4 (2 << 2)
> +#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5 (3 << 2)
It looks like you can replace the switch statement with a FIELD_GET() + 2.
Andrew
---
pw-bot: cr
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/2] net: phy: microchip: add downshift tunable support for LAN88xx
2026-03-29 22:41 ` [PATCH 1/2] net: phy: microchip: add downshift tunable " Nicolai Buchwitz
2026-03-30 13:01 ` Andrew Lunn
@ 2026-03-30 13:02 ` Andrew Lunn
1 sibling, 0 replies; 13+ messages in thread
From: Andrew Lunn @ 2026-03-30 13:02 UTC (permalink / raw)
To: Nicolai Buchwitz
Cc: netdev, Phil Elwell, Heiner Kallweit, Russell King,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
linux-kernel
> +static int lan88xx_set_downshift(struct phy_device *phydev, u8 cnt)
> +{
> + u32 mask = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK |
> + LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT;
> + u32 val;
> +
> + if (cnt == DOWNSHIFT_DEV_DISABLE)
> + return phy_modify_paged(phydev, 1, LAN78XX_PHY_CTRL3,
> + LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT, 0);
> +
> + if (cnt == DOWNSHIFT_DEV_DEFAULT_COUNT)
> + cnt = 2;
> +
> + switch (cnt) {
> + case 2:
> + val = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2;
> + break;
> + case 3:
> + val = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3;
> + break;
> + case 4:
> + val = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4;
> + break;
> + case 5:
> + val = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5;
> + break;
> + default:
> + return -EINVAL;
And this could be a range check followed by a FIELD_PREP(cnt - 2);
Andrew
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 2/2] net: phy: microchip: enable downshift by default on LAN88xx
2026-03-29 22:42 ` [PATCH 2/2] net: phy: microchip: enable downshift by default on LAN88xx Nicolai Buchwitz
@ 2026-03-30 13:03 ` Andrew Lunn
0 siblings, 0 replies; 13+ messages in thread
From: Andrew Lunn @ 2026-03-30 13:03 UTC (permalink / raw)
To: Nicolai Buchwitz
Cc: netdev, Phil Elwell, Heiner Kallweit, Russell King,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
linux-kernel
On Mon, Mar 30, 2026 at 12:42:00AM +0200, Nicolai Buchwitz wrote:
> Enable auto-downshift from 1000BASE-T to 100BASE-TX after 2 failed
> auto-negotiation attempts by default. This ensures that links with
> faulty or missing cable pairs (C and D) fall back to 100Mbps without
> requiring userspace configuration.
>
> Users can override or disable downshift at runtime:
>
> ethtool --set-phy-tunable eth0 downshift off
>
> Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Andrew
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH 1/2] net: phy: microchip: add downshift tunable support for LAN88xx
2026-03-30 13:01 ` Andrew Lunn
@ 2026-03-30 14:57 ` Nicolai Buchwitz
0 siblings, 0 replies; 13+ messages in thread
From: Nicolai Buchwitz @ 2026-03-30 14:57 UTC (permalink / raw)
To: Andrew Lunn
Cc: netdev, Phil Elwell, Heiner Kallweit, Russell King,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
linux-kernel
On 30.3.2026 15:01, Andrew Lunn wrote:
>> + switch (val & LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK) {
>> + case LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2:
>> + *data = 2;
>> + break;
>> + case LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3:
>> + *data = 3;
>> + break;
>> + case LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4:
>> + *data = 4;
>> + break;
>> + case LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5:
>> + *data = 5;
>> + break;
>> + }
>
>> +#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_2 (0 << 2)
>> +#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_3 (1 << 2)
>> +#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_4 (2 << 2)
>> +#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_5 (3 << 2)
>
> It looks like you can replace the switch statement with a FIELD_GET() +
> 2.
>
Thanks for the review, Andrew! I will incorporate both changes and send
a v2.
Nicolai
> Andrew
>
> ---
> pw-bot: cr
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH net-next v3 0/2] net: phy: microchip: add downshift support for LAN88xx
2026-03-29 22:41 [PATCH net-next 0/2] net: phy: microchip: add downshift support for LAN88xx Nicolai Buchwitz
2026-03-29 22:41 ` [PATCH 1/2] net: phy: microchip: add downshift tunable " Nicolai Buchwitz
2026-03-29 22:42 ` [PATCH 2/2] net: phy: microchip: enable downshift by default on LAN88xx Nicolai Buchwitz
@ 2026-04-01 12:38 ` Nicolai Buchwitz
2026-04-01 12:38 ` [PATCH net-next v3 1/2] net: phy: microchip: add downshift tunable " Nicolai Buchwitz
` (3 more replies)
2 siblings, 4 replies; 13+ messages in thread
From: Nicolai Buchwitz @ 2026-04-01 12:38 UTC (permalink / raw)
To: netdev; +Cc: Phil Elwell, Russell King, Andrew Lunn, Nicolai Buchwitz
Add standard ETHTOOL_PHY_DOWNSHIFT tunable support for the Microchip
LAN88xx PHY, following the same pattern used by Marvell and other PHY
drivers.
Ethernet cables with faulty or missing pairs (specifically C and D)
can successfully auto-negotiate 1000BASE-T but fail to establish a
stable link. The LAN88xx PHY supports automatic downshift to
100BASE-TX after a configurable number of failed attempts (2-5).
Patch 1 adds the get/set tunable implementation.
Patch 2 enables downshift by default with a count of 2. The setting is
stored in the driver's private data so that user changes via ethtool are
preserved across suspend/resume cycles.
Based on an earlier downstream implementation by Phil Elwell.
Tested on Raspberry Pi 3B+ (LAN7515/LAN88xx).
Changes since v2:
- Store downshift count in priv struct and restore in config_init to
preserve user settings across suspend/resume (Russell King)
Changes since v1:
- Replace switch statements with FIELD_GET()/FIELD_PREP() (Andrew Lunn)
- Drop unused per-count register defines from microchipphy.h
Nicolai Buchwitz (2):
net: phy: microchip: add downshift tunable support for LAN88xx
net: phy: microchip: enable downshift by default on LAN88xx
drivers/net/phy/microchip.c | 79 +++++++++++++++++++++++++++++++++++-
include/linux/microchipphy.h | 5 +++
2 files changed, 83 insertions(+), 1 deletion(-)
--
2.51.0
^ permalink raw reply [flat|nested] 13+ messages in thread
* [PATCH net-next v3 1/2] net: phy: microchip: add downshift tunable support for LAN88xx
2026-04-01 12:38 ` [PATCH net-next v3 0/2] net: phy: microchip: add downshift support for LAN88xx Nicolai Buchwitz
@ 2026-04-01 12:38 ` Nicolai Buchwitz
2026-04-01 12:38 ` [PATCH net-next v3 2/2] net: phy: microchip: enable downshift by default on LAN88xx Nicolai Buchwitz
` (2 subsequent siblings)
3 siblings, 0 replies; 13+ messages in thread
From: Nicolai Buchwitz @ 2026-04-01 12:38 UTC (permalink / raw)
To: netdev
Cc: Phil Elwell, Russell King, Andrew Lunn, Nicolai Buchwitz,
Russell King (Oracle), Heiner Kallweit, David S. Miller,
Eric Dumazet, Jakub Kicinski, Paolo Abeni, linux-kernel
Implement the standard ETHTOOL_PHY_DOWNSHIFT tunable for the LAN88xx
PHY. This allows runtime configuration of the auto-downshift feature
via ethtool:
ethtool --set-phy-tunable eth0 downshift on count 3
The LAN88xx PHY supports downshifting from 1000BASE-T to 100BASE-TX
after 2-5 failed auto-negotiation attempts. Valid count values are
2, 3, 4 and 5.
This is based on an earlier downstream implementation by Phil Elwell.
Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
---
drivers/net/phy/microchip.c | 64 ++++++++++++++++++++++++++++++++++++
include/linux/microchipphy.h | 5 +++
2 files changed, 69 insertions(+)
diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c
index dc8634e7bcbe..bc293d2dd130 100644
--- a/drivers/net/phy/microchip.c
+++ b/drivers/net/phy/microchip.c
@@ -2,6 +2,7 @@
/*
* Copyright (C) 2015 Microchip Technology
*/
+#include <linux/bitfield.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/mii.h>
@@ -193,6 +194,67 @@ static void lan88xx_config_TR_regs(struct phy_device *phydev)
phydev_warn(phydev, "Failed to Set Register[0x1686]\n");
}
+static int lan88xx_get_downshift(struct phy_device *phydev, u8 *data)
+{
+ int val;
+
+ val = phy_read_paged(phydev, 1, LAN78XX_PHY_CTRL3);
+ if (val < 0)
+ return val;
+
+ if (!(val & LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT)) {
+ *data = DOWNSHIFT_DEV_DISABLE;
+ return 0;
+ }
+
+ *data = FIELD_GET(LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK, val) + 2;
+
+ return 0;
+}
+
+static int lan88xx_set_downshift(struct phy_device *phydev, u8 cnt)
+{
+ u32 mask = LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK |
+ LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT;
+
+ if (cnt == DOWNSHIFT_DEV_DISABLE)
+ return phy_modify_paged(phydev, 1, LAN78XX_PHY_CTRL3,
+ LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT, 0);
+
+ if (cnt == DOWNSHIFT_DEV_DEFAULT_COUNT)
+ cnt = 2;
+
+ if (cnt < 2 || cnt > 5)
+ return -EINVAL;
+
+ return phy_modify_paged(phydev, 1, LAN78XX_PHY_CTRL3, mask,
+ FIELD_PREP(LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK,
+ cnt - 2) |
+ LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT);
+}
+
+static int lan88xx_get_tunable(struct phy_device *phydev,
+ struct ethtool_tunable *tuna, void *data)
+{
+ switch (tuna->id) {
+ case ETHTOOL_PHY_DOWNSHIFT:
+ return lan88xx_get_downshift(phydev, data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static int lan88xx_set_tunable(struct phy_device *phydev,
+ struct ethtool_tunable *tuna, const void *data)
+{
+ switch (tuna->id) {
+ case ETHTOOL_PHY_DOWNSHIFT:
+ return lan88xx_set_downshift(phydev, *(const u8 *)data);
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static int lan88xx_probe(struct phy_device *phydev)
{
struct device *dev = &phydev->mdio.dev;
@@ -499,6 +561,8 @@ static struct phy_driver microchip_phy_driver[] = {
.set_wol = lan88xx_set_wol,
.read_page = lan88xx_read_page,
.write_page = lan88xx_write_page,
+ .get_tunable = lan88xx_get_tunable,
+ .set_tunable = lan88xx_set_tunable,
},
{
PHY_ID_MATCH_MODEL(PHY_ID_LAN937X_TX),
diff --git a/include/linux/microchipphy.h b/include/linux/microchipphy.h
index 517288da19fd..7da956c666a0 100644
--- a/include/linux/microchipphy.h
+++ b/include/linux/microchipphy.h
@@ -61,6 +61,11 @@
/* Registers specific to the LAN7800/LAN7850 embedded phy */
#define LAN78XX_PHY_LED_MODE_SELECT (0x1D)
+/* PHY Control 3 register (page 1) */
+#define LAN78XX_PHY_CTRL3 (0x14)
+#define LAN78XX_PHY_CTRL3_AUTO_DOWNSHIFT BIT(4)
+#define LAN78XX_PHY_CTRL3_DOWNSHIFT_CTRL_MASK GENMASK(3, 2)
+
/* DSP registers */
#define PHY_ARDENNES_MMD_DEV_3_PHY_CFG (0x806A)
#define PHY_ARDENNES_MMD_DEV_3_PHY_CFG_ZD_DLY_EN_ (0x2000)
--
2.51.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* [PATCH net-next v3 2/2] net: phy: microchip: enable downshift by default on LAN88xx
2026-04-01 12:38 ` [PATCH net-next v3 0/2] net: phy: microchip: add downshift support for LAN88xx Nicolai Buchwitz
2026-04-01 12:38 ` [PATCH net-next v3 1/2] net: phy: microchip: add downshift tunable " Nicolai Buchwitz
@ 2026-04-01 12:38 ` Nicolai Buchwitz
2026-04-02 1:48 ` [PATCH net-next v3 0/2] net: phy: microchip: add downshift support for LAN88xx Jakub Kicinski
2026-04-03 1:10 ` patchwork-bot+netdevbpf
3 siblings, 0 replies; 13+ messages in thread
From: Nicolai Buchwitz @ 2026-04-01 12:38 UTC (permalink / raw)
To: netdev
Cc: Phil Elwell, Russell King, Andrew Lunn, Nicolai Buchwitz,
Heiner Kallweit, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, linux-kernel
Enable auto-downshift from 1000BASE-T to 100BASE-TX after 2 failed
auto-negotiation attempts by default. This ensures that links with
faulty or missing cable pairs (C and D) fall back to 100Mbps without
requiring userspace configuration.
The downshift count is stored in the driver's private data and applied
in config_init, so user changes via ethtool are preserved across
suspend/resume cycles.
Users can override or disable downshift at runtime:
ethtool --set-phy-tunable eth0 downshift off
Signed-off-by: Nicolai Buchwitz <nb@tipi-net.de>
---
drivers/net/phy/microchip.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/drivers/net/phy/microchip.c b/drivers/net/phy/microchip.c
index bc293d2dd130..33bc633bdba0 100644
--- a/drivers/net/phy/microchip.c
+++ b/drivers/net/phy/microchip.c
@@ -26,6 +26,7 @@ struct lan88xx_priv {
int chip_id;
int chip_rev;
__u32 wolopts;
+ u8 downshift_cnt;
};
static int lan88xx_read_page(struct phy_device *phydev)
@@ -247,9 +248,15 @@ static int lan88xx_get_tunable(struct phy_device *phydev,
static int lan88xx_set_tunable(struct phy_device *phydev,
struct ethtool_tunable *tuna, const void *data)
{
+ struct lan88xx_priv *priv = phydev->priv;
+ int ret;
+
switch (tuna->id) {
case ETHTOOL_PHY_DOWNSHIFT:
- return lan88xx_set_downshift(phydev, *(const u8 *)data);
+ ret = lan88xx_set_downshift(phydev, *(const u8 *)data);
+ if (!ret)
+ priv->downshift_cnt = *(const u8 *)data;
+ return ret;
default:
return -EOPNOTSUPP;
}
@@ -267,6 +274,7 @@ static int lan88xx_probe(struct phy_device *phydev)
return -ENOMEM;
priv->wolopts = 0;
+ priv->downshift_cnt = 2;
len = of_property_read_variable_u32_array(dev->of_node,
"microchip,led-modes",
@@ -346,7 +354,8 @@ static void lan88xx_set_mdix(struct phy_device *phydev)
static int lan88xx_config_init(struct phy_device *phydev)
{
- int val;
+ struct lan88xx_priv *priv = phydev->priv;
+ int val, err;
/*Zerodetect delay enable */
val = phy_read_mmd(phydev, MDIO_MMD_PCS,
@@ -359,6 +368,10 @@ static int lan88xx_config_init(struct phy_device *phydev)
/* Config DSP registers */
lan88xx_config_TR_regs(phydev);
+ err = lan88xx_set_downshift(phydev, priv->downshift_cnt);
+ if (err < 0)
+ return err;
+
return 0;
}
--
2.51.0
^ permalink raw reply related [flat|nested] 13+ messages in thread
* Re: [PATCH net-next v3 0/2] net: phy: microchip: add downshift support for LAN88xx
2026-04-01 12:38 ` [PATCH net-next v3 0/2] net: phy: microchip: add downshift support for LAN88xx Nicolai Buchwitz
2026-04-01 12:38 ` [PATCH net-next v3 1/2] net: phy: microchip: add downshift tunable " Nicolai Buchwitz
2026-04-01 12:38 ` [PATCH net-next v3 2/2] net: phy: microchip: enable downshift by default on LAN88xx Nicolai Buchwitz
@ 2026-04-02 1:48 ` Jakub Kicinski
2026-04-02 7:11 ` Nicolai Buchwitz
2026-04-03 1:10 ` patchwork-bot+netdevbpf
3 siblings, 1 reply; 13+ messages in thread
From: Jakub Kicinski @ 2026-04-02 1:48 UTC (permalink / raw)
To: Nicolai Buchwitz; +Cc: netdev, Phil Elwell, Russell King, Andrew Lunn
On Wed, 1 Apr 2026 14:38:43 +0200 Nicolai Buchwitz wrote:
> Add standard ETHTOOL_PHY_DOWNSHIFT tunable support for the Microchip
> LAN88xx PHY, following the same pattern used by Marvell and other PHY
> drivers.
Please do not post patches in reply to a previous posting.
Add a lore link to the previous posting in the changelog.
You're submitting quite a lot of patches, it'd be great if
you could give our docs a read before sending more :/
https://www.kernel.org/doc/html/next/process/maintainer-netdev.html
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net-next v3 0/2] net: phy: microchip: add downshift support for LAN88xx
2026-04-02 1:48 ` [PATCH net-next v3 0/2] net: phy: microchip: add downshift support for LAN88xx Jakub Kicinski
@ 2026-04-02 7:11 ` Nicolai Buchwitz
0 siblings, 0 replies; 13+ messages in thread
From: Nicolai Buchwitz @ 2026-04-02 7:11 UTC (permalink / raw)
To: Jakub Kicinski; +Cc: netdev, Phil Elwell, Russell King, Andrew Lunn
On 2.4.2026 03:48, Jakub Kicinski wrote:
> On Wed, 1 Apr 2026 14:38:43 +0200 Nicolai Buchwitz wrote:
>> Add standard ETHTOOL_PHY_DOWNSHIFT tunable support for the Microchip
>> LAN88xx PHY, following the same pattern used by Marvell and other PHY
>> drivers.
>
> Please do not post patches in reply to a previous posting.
Sorry, that was accidental. Previous versions were sent as fresh
threads and I'll make sure to do so going forward.
> Add a lore link to the previous posting in the changelog.
Makes sense, I will add a lore link to the previous patches in future
changelogs.
> You're submitting quite a lot of patches, it'd be great if
> you could give our docs a read before sending more :/
> https://www.kernel.org/doc/html/next/process/maintainer-netdev.html
Will do, thanks for the pointer.
Nicolai
^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [PATCH net-next v3 0/2] net: phy: microchip: add downshift support for LAN88xx
2026-04-01 12:38 ` [PATCH net-next v3 0/2] net: phy: microchip: add downshift support for LAN88xx Nicolai Buchwitz
` (2 preceding siblings ...)
2026-04-02 1:48 ` [PATCH net-next v3 0/2] net: phy: microchip: add downshift support for LAN88xx Jakub Kicinski
@ 2026-04-03 1:10 ` patchwork-bot+netdevbpf
3 siblings, 0 replies; 13+ messages in thread
From: patchwork-bot+netdevbpf @ 2026-04-03 1:10 UTC (permalink / raw)
To: Nicolai Buchwitz; +Cc: netdev, phil, linux, andrew
Hello:
This series was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Wed, 1 Apr 2026 14:38:43 +0200 you wrote:
> Add standard ETHTOOL_PHY_DOWNSHIFT tunable support for the Microchip
> LAN88xx PHY, following the same pattern used by Marvell and other PHY
> drivers.
>
> Ethernet cables with faulty or missing pairs (specifically C and D)
> can successfully auto-negotiate 1000BASE-T but fail to establish a
> stable link. The LAN88xx PHY supports automatic downshift to
> 100BASE-TX after a configurable number of failed attempts (2-5).
>
> [...]
Here is the summary with links:
- [net-next,v3,1/2] net: phy: microchip: add downshift tunable support for LAN88xx
https://git.kernel.org/netdev/net-next/c/e417ac73d24a
- [net-next,v3,2/2] net: phy: microchip: enable downshift by default on LAN88xx
https://git.kernel.org/netdev/net-next/c/70180f72d911
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-04-03 1:10 UTC | newest]
Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-29 22:41 [PATCH net-next 0/2] net: phy: microchip: add downshift support for LAN88xx Nicolai Buchwitz
2026-03-29 22:41 ` [PATCH 1/2] net: phy: microchip: add downshift tunable " Nicolai Buchwitz
2026-03-30 13:01 ` Andrew Lunn
2026-03-30 14:57 ` Nicolai Buchwitz
2026-03-30 13:02 ` Andrew Lunn
2026-03-29 22:42 ` [PATCH 2/2] net: phy: microchip: enable downshift by default on LAN88xx Nicolai Buchwitz
2026-03-30 13:03 ` Andrew Lunn
2026-04-01 12:38 ` [PATCH net-next v3 0/2] net: phy: microchip: add downshift support for LAN88xx Nicolai Buchwitz
2026-04-01 12:38 ` [PATCH net-next v3 1/2] net: phy: microchip: add downshift tunable " Nicolai Buchwitz
2026-04-01 12:38 ` [PATCH net-next v3 2/2] net: phy: microchip: enable downshift by default on LAN88xx Nicolai Buchwitz
2026-04-02 1:48 ` [PATCH net-next v3 0/2] net: phy: microchip: add downshift support for LAN88xx Jakub Kicinski
2026-04-02 7:11 ` Nicolai Buchwitz
2026-04-03 1:10 ` patchwork-bot+netdevbpf
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox