Skip to content

Commit

Permalink
Merge branch 'address-eee-regressions-on-ksz-switches-since-v6-9-v6-14'
Browse files Browse the repository at this point in the history
Oleksij Rempel says:

====================
address EEE regressions on KSZ switches since v6.9 (v6.14+)

This patch series addresses a regression in Energy Efficient Ethernet
(EEE) handling for KSZ switches with integrated PHYs, introduced in
kernel v6.9 by commit fe0d4fd ("net: phy: Keep track of EEE
configuration").

The first patch updates the DSA driver to allow phylink to properly
manage PHY EEE configuration. Since integrated PHYs handle LPI
internally and ports without integrated PHYs do not document MAC-level
LPI support, dummy MAC LPI callbacks are provided.

The second patch removes outdated EEE workarounds from the micrel PHY
driver, as they are no longer needed with correct phylink handling.

This series addresses the regression for mainline and kernels starting
from v6.14. It is not easily possible to fully fix older kernels due
to missing infrastructure changes.

Tested on KSZ9893 hardware.
====================

Link: https://patch.msgid.link/20250504081434.424489-1-o.rempel@pengutronix.de
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
  • Loading branch information
Paolo Abeni committed May 13, 2025
2 parents 498625a + 8c619eb commit 6eeceb3
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 36 deletions.
135 changes: 107 additions & 28 deletions drivers/net/dsa/microchip/ksz_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -265,16 +265,70 @@ static void ksz_phylink_mac_link_down(struct phylink_config *config,
unsigned int mode,
phy_interface_t interface);

/**
* ksz_phylink_mac_disable_tx_lpi() - Callback to signal LPI support (Dummy)
* @config: phylink config structure
*
* This function is a dummy handler. See ksz_phylink_mac_enable_tx_lpi() for
* a detailed explanation of EEE/LPI handling in KSZ switches.
*/
static void ksz_phylink_mac_disable_tx_lpi(struct phylink_config *config)
{
}

/**
* ksz_phylink_mac_enable_tx_lpi() - Callback to signal LPI support (Dummy)
* @config: phylink config structure
* @timer: timer value before entering LPI (unused)
* @tx_clock_stop: whether to stop the TX clock in LPI mode (unused)
*
* This function signals to phylink that the driver architecture supports
* LPI management, enabling phylink to control EEE advertisement during
* negotiation according to IEEE Std 802.3 (Clause 78).
*
* Hardware Management of EEE/LPI State:
* For KSZ switch ports with integrated PHYs (e.g., KSZ9893R ports 1-2),
* observation and testing suggest that the actual EEE / Low Power Idle (LPI)
* state transitions are managed autonomously by the hardware based on
* the auto-negotiation results. (Note: While the datasheet describes EEE
* operation based on negotiation, it doesn't explicitly detail the internal
* MAC/PHY interaction, so autonomous hardware management of the MAC state
* for LPI is inferred from observed behavior).
* This hardware control, consistent with the switch's ability to operate
* autonomously via strapping, means MAC-level software intervention is not
* required or exposed for managing the LPI state once EEE is negotiated.
* (Ref: KSZ9893R Data Sheet DS00002420D, primarily Section 4.7.5 explaining
* EEE, also Sections 4.1.7 on Auto-Negotiation and 3.2.1 on Configuration
* Straps).
*
* Additionally, ports configured as MAC interfaces (e.g., KSZ9893R port 3)
* lack documented MAC-level LPI control.
*
* Therefore, this callback performs no action and serves primarily to inform
* phylink of LPI awareness and to document the inferred hardware behavior.
*
* Returns: 0 (Always success)
*/
static int ksz_phylink_mac_enable_tx_lpi(struct phylink_config *config,
u32 timer, bool tx_clock_stop)
{
return 0;
}

static const struct phylink_mac_ops ksz88x3_phylink_mac_ops = {
.mac_config = ksz88x3_phylink_mac_config,
.mac_link_down = ksz_phylink_mac_link_down,
.mac_link_up = ksz8_phylink_mac_link_up,
.mac_disable_tx_lpi = ksz_phylink_mac_disable_tx_lpi,
.mac_enable_tx_lpi = ksz_phylink_mac_enable_tx_lpi,
};

static const struct phylink_mac_ops ksz8_phylink_mac_ops = {
.mac_config = ksz_phylink_mac_config,
.mac_link_down = ksz_phylink_mac_link_down,
.mac_link_up = ksz8_phylink_mac_link_up,
.mac_disable_tx_lpi = ksz_phylink_mac_disable_tx_lpi,
.mac_enable_tx_lpi = ksz_phylink_mac_enable_tx_lpi,
};

static const struct ksz_dev_ops ksz88xx_dev_ops = {
Expand Down Expand Up @@ -358,6 +412,8 @@ static const struct phylink_mac_ops ksz9477_phylink_mac_ops = {
.mac_config = ksz_phylink_mac_config,
.mac_link_down = ksz_phylink_mac_link_down,
.mac_link_up = ksz9477_phylink_mac_link_up,
.mac_disable_tx_lpi = ksz_phylink_mac_disable_tx_lpi,
.mac_enable_tx_lpi = ksz_phylink_mac_enable_tx_lpi,
};

static const struct ksz_dev_ops ksz9477_dev_ops = {
Expand Down Expand Up @@ -401,6 +457,8 @@ static const struct phylink_mac_ops lan937x_phylink_mac_ops = {
.mac_config = ksz_phylink_mac_config,
.mac_link_down = ksz_phylink_mac_link_down,
.mac_link_up = ksz9477_phylink_mac_link_up,
.mac_disable_tx_lpi = ksz_phylink_mac_disable_tx_lpi,
.mac_enable_tx_lpi = ksz_phylink_mac_enable_tx_lpi,
};

static const struct ksz_dev_ops lan937x_dev_ops = {
Expand Down Expand Up @@ -2016,6 +2074,18 @@ static void ksz_phylink_get_caps(struct dsa_switch *ds, int port,

if (dev->dev_ops->get_caps)
dev->dev_ops->get_caps(dev, port, config);

if (ds->ops->support_eee && ds->ops->support_eee(ds, port)) {
memcpy(config->lpi_interfaces, config->supported_interfaces,
sizeof(config->lpi_interfaces));

config->lpi_capabilities = MAC_100FD;
if (dev->info->gbit_capable[port])
config->lpi_capabilities |= MAC_1000FD;

/* EEE is fully operational */
config->eee_enabled_default = true;
}
}

void ksz_r_mib_stats64(struct ksz_device *dev, int port)
Expand Down Expand Up @@ -3008,31 +3078,6 @@ static u32 ksz_get_phy_flags(struct dsa_switch *ds, int port)
if (!port)
return MICREL_KSZ8_P1_ERRATA;
break;
case KSZ8567_CHIP_ID:
/* KSZ8567R Errata DS80000752C Module 4 */
case KSZ8765_CHIP_ID:
case KSZ8794_CHIP_ID:
case KSZ8795_CHIP_ID:
/* KSZ879x/KSZ877x/KSZ876x Errata DS80000687C Module 2 */
case KSZ9477_CHIP_ID:
/* KSZ9477S Errata DS80000754A Module 4 */
case KSZ9567_CHIP_ID:
/* KSZ9567S Errata DS80000756A Module 4 */
case KSZ9896_CHIP_ID:
/* KSZ9896C Errata DS80000757A Module 3 */
case KSZ9897_CHIP_ID:
case LAN9646_CHIP_ID:
/* KSZ9897R Errata DS80000758C Module 4 */
/* Energy Efficient Ethernet (EEE) feature select must be manually disabled
* The EEE feature is enabled by default, but it is not fully
* operational. It must be manually disabled through register
* controls. If not disabled, the PHY ports can auto-negotiate
* to enable EEE, and this feature can cause link drops when
* linked to another device supporting EEE.
*
* The same item appears in the errata for all switches above.
*/
return MICREL_NO_EEE;
}

return 0;
Expand Down Expand Up @@ -3466,6 +3511,20 @@ static int ksz_max_mtu(struct dsa_switch *ds, int port)
return -EOPNOTSUPP;
}

/**
* ksz_support_eee - Determine Energy Efficient Ethernet (EEE) support for a
* port
* @ds: Pointer to the DSA switch structure
* @port: Port number to check
*
* This function also documents devices where EEE was initially advertised but
* later withdrawn due to reliability issues, as described in official errata
* documents. These devices are explicitly listed to record known limitations,
* even if there is no technical necessity for runtime checks.
*
* Returns: true if the internal PHY on the given port supports fully
* operational EEE, false otherwise.
*/
static bool ksz_support_eee(struct dsa_switch *ds, int port)
{
struct ksz_device *dev = ds->priv;
Expand All @@ -3475,15 +3534,35 @@ static bool ksz_support_eee(struct dsa_switch *ds, int port)

switch (dev->chip_id) {
case KSZ8563_CHIP_ID:
case KSZ9563_CHIP_ID:
case KSZ9893_CHIP_ID:
return true;
case KSZ8567_CHIP_ID:
/* KSZ8567R Errata DS80000752C Module 4 */
case KSZ8765_CHIP_ID:
case KSZ8794_CHIP_ID:
case KSZ8795_CHIP_ID:
/* KSZ879x/KSZ877x/KSZ876x Errata DS80000687C Module 2 */
case KSZ9477_CHIP_ID:
case KSZ9563_CHIP_ID:
/* KSZ9477S Errata DS80000754A Module 4 */
case KSZ9567_CHIP_ID:
case KSZ9893_CHIP_ID:
/* KSZ9567S Errata DS80000756A Module 4 */
case KSZ9896_CHIP_ID:
/* KSZ9896C Errata DS80000757A Module 3 */
case KSZ9897_CHIP_ID:
case LAN9646_CHIP_ID:
return true;
/* KSZ9897R Errata DS80000758C Module 4 */
/* Energy Efficient Ethernet (EEE) feature select must be
* manually disabled
* The EEE feature is enabled by default, but it is not fully
* operational. It must be manually disabled through register
* controls. If not disabled, the PHY ports can auto-negotiate
* to enable EEE, and this feature can cause link drops when
* linked to another device supporting EEE.
*
* The same item appears in the errata for all switches above.
*/
break;
}

return false;
Expand Down
7 changes: 0 additions & 7 deletions drivers/net/phy/micrel.c
Original file line number Diff line number Diff line change
Expand Up @@ -2027,12 +2027,6 @@ static int ksz9477_config_init(struct phy_device *phydev)
return err;
}

/* According to KSZ9477 Errata DS80000754C (Module 4) all EEE modes
* in this switch shall be regarded as broken.
*/
if (phydev->dev_flags & MICREL_NO_EEE)
phy_disable_eee(phydev);

return kszphy_config_init(phydev);
}

Expand Down Expand Up @@ -5705,7 +5699,6 @@ static struct phy_driver ksphy_driver[] = {
.handle_interrupt = kszphy_handle_interrupt,
.suspend = genphy_suspend,
.resume = ksz9477_resume,
.get_features = ksz9477_get_features,
} };

module_phy_driver(ksphy_driver);
Expand Down
1 change: 0 additions & 1 deletion include/linux/micrel_phy.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@
#define MICREL_PHY_50MHZ_CLK BIT(0)
#define MICREL_PHY_FXEN BIT(1)
#define MICREL_KSZ8_P1_ERRATA BIT(2)
#define MICREL_NO_EEE BIT(3)

#define MICREL_KSZ9021_EXTREG_CTRL 0xB
#define MICREL_KSZ9021_EXTREG_DATA_WRITE 0xC
Expand Down

0 comments on commit 6eeceb3

Please sign in to comment.