Skip to content

Commit 6d0f77a

Browse files
committed
Merge branch 'net-ethernet-rework-eee'
Oleksij Rempel says: ==================== net: ethernet: Rework EEE with Andrew's permission I'll continue mainlining this patches: ============================================================== Most MAC drivers get EEE wrong. The API to the PHY is not very obvious, which is probably why. Rework the API, pushing most of the EEE handling into phylib core, leaving the MAC drivers to just enable/disable support for EEE in there change_link call back. MAC drivers are now expect to indicate to phylib if they support EEE. This will allow future patches to configure the PHY to advertise no EEE link modes when EEE is not supported. The information could also be used to enable SmartEEE if the PHY supports it. With these changes, the uAPI configuration eee_enable becomes a global on/off. tx-lpi must also be enabled before EEE is enabled. This fits the discussion here: https://lore.kernel.org/netdev/af880ce8-a7b8-138e-1ab9-8c89e662eecf@gmail.com/T/ This patchset puts in place all the infrastructure, and converts one MAC driver to the new API. Following patchsets will convert other MAC drivers, extend support into phylink, and when all MAC drivers are converted to the new scheme, clean up some unneeded code. ==================== Link: https://lore.kernel.org/r/20240302195306.3207716-1-o.rempel@pengutronix.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 344f7a4 + 6a2495a commit 6d0f77a

File tree

6 files changed

+168
-54
lines changed

6 files changed

+168
-54
lines changed

drivers/net/ethernet/freescale/fec_main.c

Lines changed: 36 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -2017,6 +2017,37 @@ static int fec_get_mac(struct net_device *ndev)
20172017
/*
20182018
* Phy section
20192019
*/
2020+
2021+
/* LPI Sleep Ts count base on tx clk (clk_ref).
2022+
* The lpi sleep cnt value = X us / (cycle_ns).
2023+
*/
2024+
static int fec_enet_us_to_tx_cycle(struct net_device *ndev, int us)
2025+
{
2026+
struct fec_enet_private *fep = netdev_priv(ndev);
2027+
2028+
return us * (fep->clk_ref_rate / 1000) / 1000;
2029+
}
2030+
2031+
static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable)
2032+
{
2033+
struct fec_enet_private *fep = netdev_priv(ndev);
2034+
struct ethtool_keee *p = &fep->eee;
2035+
unsigned int sleep_cycle, wake_cycle;
2036+
2037+
if (enable) {
2038+
sleep_cycle = fec_enet_us_to_tx_cycle(ndev, p->tx_lpi_timer);
2039+
wake_cycle = sleep_cycle;
2040+
} else {
2041+
sleep_cycle = 0;
2042+
wake_cycle = 0;
2043+
}
2044+
2045+
writel(sleep_cycle, fep->hwp + FEC_LPI_SLEEP);
2046+
writel(wake_cycle, fep->hwp + FEC_LPI_WAKE);
2047+
2048+
return 0;
2049+
}
2050+
20202051
static void fec_enet_adjust_link(struct net_device *ndev)
20212052
{
20222053
struct fec_enet_private *fep = netdev_priv(ndev);
@@ -2056,6 +2087,8 @@ static void fec_enet_adjust_link(struct net_device *ndev)
20562087
netif_tx_unlock_bh(ndev);
20572088
napi_enable(&fep->napi);
20582089
}
2090+
if (fep->quirks & FEC_QUIRK_HAS_EEE)
2091+
fec_enet_eee_mode_set(ndev, phy_dev->enable_tx_lpi);
20592092
} else {
20602093
if (fep->link) {
20612094
netif_stop_queue(ndev);
@@ -2415,6 +2448,9 @@ static int fec_enet_mii_probe(struct net_device *ndev)
24152448
else
24162449
phy_set_max_speed(phy_dev, 100);
24172450

2451+
if (fep->quirks & FEC_QUIRK_HAS_EEE)
2452+
phy_support_eee(phy_dev);
2453+
24182454
fep->link = 0;
24192455
fep->full_duplex = 0;
24202456

@@ -3121,43 +3157,6 @@ static int fec_enet_set_coalesce(struct net_device *ndev,
31213157
return 0;
31223158
}
31233159

3124-
/* LPI Sleep Ts count base on tx clk (clk_ref).
3125-
* The lpi sleep cnt value = X us / (cycle_ns).
3126-
*/
3127-
static int fec_enet_us_to_tx_cycle(struct net_device *ndev, int us)
3128-
{
3129-
struct fec_enet_private *fep = netdev_priv(ndev);
3130-
3131-
return us * (fep->clk_ref_rate / 1000) / 1000;
3132-
}
3133-
3134-
static int fec_enet_eee_mode_set(struct net_device *ndev, bool enable)
3135-
{
3136-
struct fec_enet_private *fep = netdev_priv(ndev);
3137-
struct ethtool_keee *p = &fep->eee;
3138-
unsigned int sleep_cycle, wake_cycle;
3139-
int ret = 0;
3140-
3141-
if (enable) {
3142-
ret = phy_init_eee(ndev->phydev, false);
3143-
if (ret)
3144-
return ret;
3145-
3146-
sleep_cycle = fec_enet_us_to_tx_cycle(ndev, p->tx_lpi_timer);
3147-
wake_cycle = sleep_cycle;
3148-
} else {
3149-
sleep_cycle = 0;
3150-
wake_cycle = 0;
3151-
}
3152-
3153-
p->tx_lpi_enabled = enable;
3154-
3155-
writel(sleep_cycle, fep->hwp + FEC_LPI_SLEEP);
3156-
writel(wake_cycle, fep->hwp + FEC_LPI_WAKE);
3157-
3158-
return 0;
3159-
}
3160-
31613160
static int
31623161
fec_enet_get_eee(struct net_device *ndev, struct ethtool_keee *edata)
31633162
{
@@ -3171,7 +3170,6 @@ fec_enet_get_eee(struct net_device *ndev, struct ethtool_keee *edata)
31713170
return -ENETDOWN;
31723171

31733172
edata->tx_lpi_timer = p->tx_lpi_timer;
3174-
edata->tx_lpi_enabled = p->tx_lpi_enabled;
31753173

31763174
return phy_ethtool_get_eee(ndev->phydev, edata);
31773175
}
@@ -3181,7 +3179,6 @@ fec_enet_set_eee(struct net_device *ndev, struct ethtool_keee *edata)
31813179
{
31823180
struct fec_enet_private *fep = netdev_priv(ndev);
31833181
struct ethtool_keee *p = &fep->eee;
3184-
int ret = 0;
31853182

31863183
if (!(fep->quirks & FEC_QUIRK_HAS_EEE))
31873184
return -EOPNOTSUPP;
@@ -3191,15 +3188,6 @@ fec_enet_set_eee(struct net_device *ndev, struct ethtool_keee *edata)
31913188

31923189
p->tx_lpi_timer = edata->tx_lpi_timer;
31933190

3194-
if (!edata->eee_enabled || !edata->tx_lpi_enabled ||
3195-
!edata->tx_lpi_timer)
3196-
ret = fec_enet_eee_mode_set(ndev, false);
3197-
else
3198-
ret = fec_enet_eee_mode_set(ndev, true);
3199-
3200-
if (ret)
3201-
return ret;
3202-
32033191
return phy_ethtool_set_eee(ndev->phydev, edata);
32043192
}
32053193

drivers/net/phy/phy-c45.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1550,6 +1550,8 @@ EXPORT_SYMBOL(genphy_c45_ethtool_get_eee);
15501550
* advertised, but the previously advertised link modes are
15511551
* retained. This allows EEE to be enabled/disabled in a
15521552
* non-destructive way.
1553+
* Returns either error code, 0 if there was no change, or positive
1554+
* value if there was a change which triggered auto-neg.
15531555
*/
15541556
int genphy_c45_ethtool_set_eee(struct phy_device *phydev,
15551557
struct ethtool_keee *data)
@@ -1576,8 +1578,16 @@ int genphy_c45_ethtool_set_eee(struct phy_device *phydev,
15761578
phydev->eee_enabled = data->eee_enabled;
15771579

15781580
ret = genphy_c45_an_config_eee_aneg(phydev);
1579-
if (ret > 0)
1580-
return phy_restart_aneg(phydev);
1581+
if (ret > 0) {
1582+
ret = phy_restart_aneg(phydev);
1583+
if (ret < 0)
1584+
return ret;
1585+
1586+
/* explicitly return 1, otherwise (ret > 0) value will be
1587+
* overwritten by phy_restart_aneg().
1588+
*/
1589+
return 1;
1590+
}
15811591

15821592
return ret;
15831593
}

drivers/net/phy/phy.c

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -983,9 +983,17 @@ static int phy_check_link_status(struct phy_device *phydev)
983983
if (phydev->link && phydev->state != PHY_RUNNING) {
984984
phy_check_downshift(phydev);
985985
phydev->state = PHY_RUNNING;
986+
err = genphy_c45_eee_is_active(phydev,
987+
NULL, NULL, NULL);
988+
if (err < 0)
989+
phydev->enable_tx_lpi = false;
990+
else
991+
phydev->enable_tx_lpi = (err & phydev->eee_cfg.tx_lpi_enabled);
992+
986993
phy_link_up(phydev);
987994
} else if (!phydev->link && phydev->state != PHY_NOLINK) {
988995
phydev->state = PHY_NOLINK;
996+
phydev->enable_tx_lpi = false;
989997
phy_link_down(phydev);
990998
}
991999

@@ -1633,8 +1641,8 @@ EXPORT_SYMBOL(phy_get_eee_err);
16331641
* @phydev: target phy_device struct
16341642
* @data: ethtool_keee data
16351643
*
1636-
* Description: it reportes the Supported/Advertisement/LP Advertisement
1637-
* capabilities.
1644+
* Description: reports the Supported/Advertisement/LP Advertisement
1645+
* capabilities, etc.
16381646
*/
16391647
int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_keee *data)
16401648
{
@@ -1645,12 +1653,43 @@ int phy_ethtool_get_eee(struct phy_device *phydev, struct ethtool_keee *data)
16451653

16461654
mutex_lock(&phydev->lock);
16471655
ret = genphy_c45_ethtool_get_eee(phydev, data);
1656+
eeecfg_to_eee(data, &phydev->eee_cfg);
16481657
mutex_unlock(&phydev->lock);
16491658

16501659
return ret;
16511660
}
16521661
EXPORT_SYMBOL(phy_ethtool_get_eee);
16531662

1663+
/**
1664+
* phy_ethtool_set_eee_noneg - Adjusts MAC LPI configuration without PHY
1665+
* renegotiation
1666+
* @phydev: pointer to the target PHY device structure
1667+
* @data: pointer to the ethtool_keee structure containing the new EEE settings
1668+
*
1669+
* This function updates the Energy Efficient Ethernet (EEE) configuration
1670+
* for cases where only the MAC's Low Power Idle (LPI) configuration changes,
1671+
* without triggering PHY renegotiation. It ensures that the MAC is properly
1672+
* informed of the new LPI settings by cycling the link down and up, which
1673+
* is necessary for the MAC to adopt the new configuration. This adjustment
1674+
* is done only if there is a change in the tx_lpi_enabled or tx_lpi_timer
1675+
* configuration.
1676+
*/
1677+
static void phy_ethtool_set_eee_noneg(struct phy_device *phydev,
1678+
struct ethtool_keee *data)
1679+
{
1680+
if (phydev->eee_cfg.tx_lpi_enabled != data->tx_lpi_enabled ||
1681+
phydev->eee_cfg.tx_lpi_timer != data->tx_lpi_timer) {
1682+
eee_to_eeecfg(&phydev->eee_cfg, data);
1683+
phydev->enable_tx_lpi = eeecfg_mac_can_tx_lpi(&phydev->eee_cfg);
1684+
if (phydev->link) {
1685+
phydev->link = false;
1686+
phy_link_down(phydev);
1687+
phydev->link = true;
1688+
phy_link_up(phydev);
1689+
}
1690+
}
1691+
}
1692+
16541693
/**
16551694
* phy_ethtool_set_eee - set EEE supported and status
16561695
* @phydev: target phy_device struct
@@ -1667,9 +1706,14 @@ int phy_ethtool_set_eee(struct phy_device *phydev, struct ethtool_keee *data)
16671706

16681707
mutex_lock(&phydev->lock);
16691708
ret = genphy_c45_ethtool_set_eee(phydev, data);
1709+
if (ret >= 0) {
1710+
if (ret == 0)
1711+
phy_ethtool_set_eee_noneg(phydev, data);
1712+
eee_to_eeecfg(&phydev->eee_cfg, data);
1713+
}
16701714
mutex_unlock(&phydev->lock);
16711715

1672-
return ret;
1716+
return ret < 0 ? ret : 0;
16731717
}
16741718
EXPORT_SYMBOL(phy_ethtool_set_eee);
16751719

drivers/net/phy/phy_device.c

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2910,6 +2910,34 @@ void phy_advertise_eee_all(struct phy_device *phydev)
29102910
}
29112911
EXPORT_SYMBOL_GPL(phy_advertise_eee_all);
29122912

2913+
/**
2914+
* phy_support_eee - Set initial EEE policy configuration
2915+
* @phydev: Target phy_device struct
2916+
*
2917+
* This function configures the initial policy for Energy Efficient Ethernet
2918+
* (EEE) on the specified PHY device, influencing that EEE capabilities are
2919+
* advertised before the link is established. It should be called during PHY
2920+
* registration by the MAC driver and/or the PHY driver (for SmartEEE PHYs)
2921+
* if MAC supports LPI or PHY is capable to compensate missing LPI functionality
2922+
* of the MAC.
2923+
*
2924+
* The function sets default EEE policy parameters, including preparing the PHY
2925+
* to advertise EEE capabilities based on hardware support.
2926+
*
2927+
* It also sets the expected configuration for Low Power Idle (LPI) in the MAC
2928+
* driver. If the PHY framework determines that both local and remote
2929+
* advertisements support EEE, and the negotiated link mode is compatible with
2930+
* EEE, it will set enable_tx_lpi = true. The MAC driver is expected to act on
2931+
* this setting by enabling the LPI timer if enable_tx_lpi is set.
2932+
*/
2933+
void phy_support_eee(struct phy_device *phydev)
2934+
{
2935+
linkmode_copy(phydev->advertising_eee, phydev->supported_eee);
2936+
phydev->eee_cfg.tx_lpi_enabled = true;
2937+
phydev->eee_cfg.eee_enabled = true;
2938+
}
2939+
EXPORT_SYMBOL(phy_support_eee);
2940+
29132941
/**
29142942
* phy_support_sym_pause - Enable support of symmetrical pause
29152943
* @phydev: target phy_device struct

include/linux/phy.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include <linux/refcount.h>
3131

3232
#include <linux/atomic.h>
33+
#include <net/eee.h>
3334

3435
#define PHY_DEFAULT_FEATURES (SUPPORTED_Autoneg | \
3536
SUPPORTED_TP | \
@@ -594,6 +595,8 @@ struct macsec_ops;
594595
* @supported_eee: supported PHY EEE linkmodes
595596
* @advertising_eee: Currently advertised EEE linkmodes
596597
* @eee_enabled: Flag indicating whether the EEE feature is enabled
598+
* @enable_tx_lpi: When True, MAC should transmit LPI to PHY
599+
* @eee_cfg: User configuration of EEE
597600
* @lp_advertising: Current link partner advertised linkmodes
598601
* @host_interfaces: PHY interface modes supported by host
599602
* @eee_broken_modes: Energy efficient ethernet modes which should be prohibited
@@ -703,7 +706,7 @@ struct phy_device {
703706
__ETHTOOL_DECLARE_LINK_MODE_MASK(lp_advertising);
704707
/* used with phy_speed_down */
705708
__ETHTOOL_DECLARE_LINK_MODE_MASK(adv_old);
706-
/* used for eee validation */
709+
/* used for eee validation and configuration*/
707710
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported_eee);
708711
__ETHTOOL_DECLARE_LINK_MODE_MASK(advertising_eee);
709712
bool eee_enabled;
@@ -713,6 +716,8 @@ struct phy_device {
713716

714717
/* Energy efficient ethernet modes which should be prohibited */
715718
u32 eee_broken_modes;
719+
bool enable_tx_lpi;
720+
struct eee_config eee_cfg;
716721

717722
#ifdef CONFIG_LED_TRIGGER_PHY
718723
struct phy_led_trigger *phy_led_triggers;
@@ -1968,6 +1973,7 @@ void phy_advertise_supported(struct phy_device *phydev);
19681973
void phy_advertise_eee_all(struct phy_device *phydev);
19691974
void phy_support_sym_pause(struct phy_device *phydev);
19701975
void phy_support_asym_pause(struct phy_device *phydev);
1976+
void phy_support_eee(struct phy_device *phydev);
19711977
void phy_set_sym_pause(struct phy_device *phydev, bool rx, bool tx,
19721978
bool autoneg);
19731979
void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx);

include/net/eee.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
#ifndef _EEE_H
3+
#define _EEE_H
4+
5+
#include <linux/types.h>
6+
7+
struct eee_config {
8+
u32 tx_lpi_timer;
9+
bool tx_lpi_enabled;
10+
bool eee_enabled;
11+
};
12+
13+
static inline bool eeecfg_mac_can_tx_lpi(const struct eee_config *eeecfg)
14+
{
15+
/* eee_enabled is the master on/off */
16+
if (!eeecfg->eee_enabled || !eeecfg->tx_lpi_enabled)
17+
return false;
18+
19+
return true;
20+
}
21+
22+
static inline void eeecfg_to_eee(struct ethtool_keee *eee,
23+
const struct eee_config *eeecfg)
24+
{
25+
eee->tx_lpi_timer = eeecfg->tx_lpi_timer;
26+
eee->tx_lpi_enabled = eeecfg->tx_lpi_enabled;
27+
eee->eee_enabled = eeecfg->eee_enabled;
28+
}
29+
30+
static inline void eee_to_eeecfg(struct eee_config *eeecfg,
31+
const struct ethtool_keee *eee)
32+
{
33+
eeecfg->tx_lpi_timer = eee->tx_lpi_timer;
34+
eeecfg->tx_lpi_enabled = eee->tx_lpi_enabled;
35+
eeecfg->eee_enabled = eee->eee_enabled;
36+
}
37+
38+
#endif

0 commit comments

Comments
 (0)