Skip to content

Commit 03abf2a

Browse files
Russell King (Oracle)kuba-moo
authored andcommitted
net: phylink: add EEE management
Add EEE management to phylink, making use of the phylib implementation. This will only be used where a MAC driver populates the methods and capabilities bitfield, otherwise we keep our old behaviour. Phylink will keep track of the EEE configuration, including the clock stop abilities at each end of the MAC to PHY link, programming the PHY appropriately and preserving the LPI configuration should the PHY go away. Phylink will call into the MAC driver when LPI needs to be enabled or disabled, with the requirement that the MAC have LPI disabled prior to the netdev being brought up (in other words, it will only call mac_disable_tx_lpi() if it has already called mac_enable_tx_lpi().) Support for phylink managed EEE is enabled by populating both tx_lpi MAC operations method pointers, and filling in both LPI interfaces and capabilities. If the methods are provided but the LPI interfaces or capabilities remain empty, this indicates to phylink that EEE is implemented by the driver but the hardware it is driving does not support EEE, and thus the ethtool set_eee() and get_eee() methods will return EOPNOTSUPP. No validation of the LPI timer value is performed by this patch. For interface modes which do not support LPI, we make no attempt to manipulate the phylib EEE advertisement, but instead refuse to activate LPI at the MAC, noting it at debug message level. We also restrict the advertisement and reported userspace support linkmode masks according to the lpi_capabilities provided to phylink by the MAC driver. Signed-off-by: Russell King (Oracle) <[email protected]> Reviewed-by: Jacob Keller <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
1 parent a17ceec commit 03abf2a

File tree

2 files changed

+178
-5
lines changed

2 files changed

+178
-5
lines changed

drivers/net/phy/phylink.c

Lines changed: 133 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ struct phylink {
6060
u8 act_link_an_mode; /* Active MLO_AN_xxx mode */
6161
u8 link_port; /* The current non-phy ethtool port */
6262
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
63+
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported_lpi);
6364

6465
/* The link configuration settings */
6566
struct phylink_link_state link_config;
@@ -81,12 +82,20 @@ struct phylink {
8182
unsigned int pcs_state;
8283

8384
bool link_failed;
85+
bool mac_supports_eee_ops;
86+
bool mac_supports_eee;
87+
bool phy_enable_tx_lpi;
88+
bool mac_enable_tx_lpi;
89+
bool mac_tx_clk_stop;
90+
u32 mac_tx_lpi_timer;
8491

8592
struct sfp_bus *sfp_bus;
8693
bool sfp_may_have_phy;
8794
DECLARE_PHY_INTERFACE_MASK(sfp_interfaces);
8895
__ETHTOOL_DECLARE_LINK_MODE_MASK(sfp_support);
8996
u8 sfp_port;
97+
98+
struct eee_config eee_cfg;
9099
};
91100

92101
#define phylink_printk(level, pl, fmt, ...) \
@@ -1584,6 +1593,39 @@ static const char *phylink_pause_to_str(int pause)
15841593
}
15851594
}
15861595

1596+
static void phylink_deactivate_lpi(struct phylink *pl)
1597+
{
1598+
if (pl->mac_enable_tx_lpi) {
1599+
pl->mac_enable_tx_lpi = false;
1600+
1601+
phylink_dbg(pl, "disabling LPI\n");
1602+
1603+
pl->mac_ops->mac_disable_tx_lpi(pl->config);
1604+
}
1605+
}
1606+
1607+
static void phylink_activate_lpi(struct phylink *pl)
1608+
{
1609+
int err;
1610+
1611+
if (!test_bit(pl->cur_interface, pl->config->lpi_interfaces)) {
1612+
phylink_dbg(pl, "MAC does not support LPI with %s\n",
1613+
phy_modes(pl->cur_interface));
1614+
return;
1615+
}
1616+
1617+
phylink_dbg(pl, "LPI timer %uus, tx clock stop %u\n",
1618+
pl->mac_tx_lpi_timer, pl->mac_tx_clk_stop);
1619+
1620+
err = pl->mac_ops->mac_enable_tx_lpi(pl->config, pl->mac_tx_lpi_timer,
1621+
pl->mac_tx_clk_stop);
1622+
if (!err)
1623+
pl->mac_enable_tx_lpi = true;
1624+
else
1625+
phylink_err(pl, "%ps() failed: %pe\n",
1626+
pl->mac_ops->mac_enable_tx_lpi, ERR_PTR(err));
1627+
}
1628+
15871629
static void phylink_link_up(struct phylink *pl,
15881630
struct phylink_link_state link_state)
15891631
{
@@ -1630,6 +1672,9 @@ static void phylink_link_up(struct phylink *pl,
16301672
pl->cur_interface, speed, duplex,
16311673
!!(link_state.pause & MLO_PAUSE_TX), rx_pause);
16321674

1675+
if (pl->mac_supports_eee && pl->phy_enable_tx_lpi)
1676+
phylink_activate_lpi(pl);
1677+
16331678
if (ndev)
16341679
netif_carrier_on(ndev);
16351680

@@ -1646,6 +1691,9 @@ static void phylink_link_down(struct phylink *pl)
16461691

16471692
if (ndev)
16481693
netif_carrier_off(ndev);
1694+
1695+
phylink_deactivate_lpi(pl);
1696+
16491697
pl->mac_ops->mac_link_down(pl->config, pl->act_link_an_mode,
16501698
pl->cur_interface);
16511699
phylink_info(pl, "Link is Down\n");
@@ -1909,6 +1957,17 @@ struct phylink *phylink_create(struct phylink_config *config,
19091957
return ERR_PTR(-EINVAL);
19101958
}
19111959

1960+
pl->mac_supports_eee_ops = mac_ops->mac_disable_tx_lpi &&
1961+
mac_ops->mac_enable_tx_lpi;
1962+
pl->mac_supports_eee = pl->mac_supports_eee_ops &&
1963+
pl->config->lpi_capabilities &&
1964+
!phy_interface_empty(pl->config->lpi_interfaces);
1965+
1966+
/* Set the default EEE configuration */
1967+
pl->eee_cfg.eee_enabled = pl->config->eee_enabled_default;
1968+
pl->eee_cfg.tx_lpi_enabled = pl->eee_cfg.eee_enabled;
1969+
pl->eee_cfg.tx_lpi_timer = pl->config->lpi_timer_default;
1970+
19121971
pl->phy_state.interface = iface;
19131972
pl->link_interface = iface;
19141973
if (iface == PHY_INTERFACE_MODE_MOCA)
@@ -2013,16 +2072,22 @@ static void phylink_phy_change(struct phy_device *phydev, bool up)
20132072
pl->phy_state.link = up;
20142073
if (!up)
20152074
pl->link_failed = true;
2075+
2076+
/* Get the LPI state from phylib */
2077+
pl->phy_enable_tx_lpi = phydev->enable_tx_lpi;
2078+
pl->mac_tx_lpi_timer = phydev->eee_cfg.tx_lpi_timer;
20162079
mutex_unlock(&pl->state_mutex);
20172080

20182081
phylink_run_resolve(pl);
20192082

2020-
phylink_dbg(pl, "phy link %s %s/%s/%s/%s/%s\n", up ? "up" : "down",
2083+
phylink_dbg(pl, "phy link %s %s/%s/%s/%s/%s/%slpi\n",
2084+
up ? "up" : "down",
20212085
phy_modes(phydev->interface),
20222086
phy_speed_to_str(phydev->speed),
20232087
phy_duplex_to_str(phydev->duplex),
20242088
phy_rate_matching_to_str(phydev->rate_matching),
2025-
phylink_pause_to_str(pl->phy_state.pause));
2089+
phylink_pause_to_str(pl->phy_state.pause),
2090+
phydev->enable_tx_lpi ? "" : "no");
20262091
}
20272092

20282093
static int phylink_validate_phy(struct phylink *pl, struct phy_device *phy,
@@ -2152,6 +2217,36 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
21522217

21532218
/* Restrict the phy advertisement according to the MAC support. */
21542219
linkmode_copy(phy->advertising, config.advertising);
2220+
2221+
/* If the MAC supports phylink managed EEE, restrict the EEE
2222+
* advertisement according to the MAC's LPI capabilities.
2223+
*/
2224+
if (pl->mac_supports_eee) {
2225+
/* If EEE is enabled, then we need to call phy_support_eee()
2226+
* to ensure that the advertising mask is appropriately set.
2227+
* This also enables EEE at the PHY.
2228+
*/
2229+
if (pl->eee_cfg.eee_enabled)
2230+
phy_support_eee(phy);
2231+
2232+
phy->eee_cfg.tx_lpi_enabled = pl->eee_cfg.tx_lpi_enabled;
2233+
phy->eee_cfg.tx_lpi_timer = pl->eee_cfg.tx_lpi_timer;
2234+
2235+
/* Convert the MAC's LPI capabilities to linkmodes */
2236+
linkmode_zero(pl->supported_lpi);
2237+
phylink_caps_to_linkmodes(pl->supported_lpi,
2238+
pl->config->lpi_capabilities);
2239+
2240+
/* Restrict the PHYs EEE support/advertisement to the modes
2241+
* that the MAC supports.
2242+
*/
2243+
linkmode_and(phy->advertising_eee, phy->advertising_eee,
2244+
pl->supported_lpi);
2245+
} else if (pl->mac_supports_eee_ops) {
2246+
/* MAC supports phylink EEE, but wants EEE always disabled. */
2247+
phy_disable_eee(phy);
2248+
}
2249+
21552250
mutex_unlock(&pl->state_mutex);
21562251
mutex_unlock(&phy->lock);
21572252

@@ -2167,7 +2262,13 @@ static int phylink_bringup_phy(struct phylink *pl, struct phy_device *phy,
21672262
if (pl->config->mac_managed_pm)
21682263
phy->mac_managed_pm = true;
21692264

2170-
return 0;
2265+
/* Allow the MAC to stop its clock if the PHY has the capability */
2266+
pl->mac_tx_clk_stop = phy_eee_tx_clock_stop_capable(phy) > 0;
2267+
2268+
/* Explicitly configure whether the PHY is allowed to stop it's
2269+
* receive clock.
2270+
*/
2271+
return phy_eee_rx_clock_stop(phy, pl->config->eee_rx_clk_stop_enable);
21712272
}
21722273

21732274
static int phylink_attach_phy(struct phylink *pl, struct phy_device *phy,
@@ -2324,6 +2425,8 @@ void phylink_disconnect_phy(struct phylink *pl)
23242425
mutex_lock(&phy->lock);
23252426
mutex_lock(&pl->state_mutex);
23262427
pl->phydev = NULL;
2428+
pl->phy_enable_tx_lpi = false;
2429+
pl->mac_tx_clk_stop = false;
23272430
mutex_unlock(&pl->state_mutex);
23282431
mutex_unlock(&phy->lock);
23292432
flush_work(&pl->resolve);
@@ -3078,8 +3181,16 @@ int phylink_ethtool_get_eee(struct phylink *pl, struct ethtool_keee *eee)
30783181

30793182
ASSERT_RTNL();
30803183

3081-
if (pl->phydev)
3184+
if (pl->mac_supports_eee_ops && !pl->mac_supports_eee)
3185+
return ret;
3186+
3187+
if (pl->phydev) {
30823188
ret = phy_ethtool_get_eee(pl->phydev, eee);
3189+
/* Restrict supported linkmode mask */
3190+
if (ret == 0 && pl->mac_supports_eee_ops)
3191+
linkmode_and(eee->supported, eee->supported,
3192+
pl->supported_lpi);
3193+
}
30833194

30843195
return ret;
30853196
}
@@ -3092,12 +3203,29 @@ EXPORT_SYMBOL_GPL(phylink_ethtool_get_eee);
30923203
*/
30933204
int phylink_ethtool_set_eee(struct phylink *pl, struct ethtool_keee *eee)
30943205
{
3206+
bool mac_eee = pl->mac_supports_eee;
30953207
int ret = -EOPNOTSUPP;
30963208

30973209
ASSERT_RTNL();
30983210

3099-
if (pl->phydev)
3211+
phylink_dbg(pl, "mac %s phylink EEE%s, adv %*pbl, LPI%s timer %uus\n",
3212+
mac_eee ? "supports" : "does not support",
3213+
eee->eee_enabled ? ", enabled" : "",
3214+
__ETHTOOL_LINK_MODE_MASK_NBITS, eee->advertised,
3215+
eee->tx_lpi_enabled ? " enabled" : "", eee->tx_lpi_timer);
3216+
3217+
if (pl->mac_supports_eee_ops && !mac_eee)
3218+
return ret;
3219+
3220+
if (pl->phydev) {
3221+
/* Restrict advertisement mask */
3222+
if (pl->mac_supports_eee_ops)
3223+
linkmode_and(eee->advertised, eee->advertised,
3224+
pl->supported_lpi);
31003225
ret = phy_ethtool_set_eee(pl->phydev, eee);
3226+
if (ret == 0)
3227+
eee_to_eeecfg(&pl->eee_cfg, eee);
3228+
}
31013229

31023230
return ret;
31033231
}

include/linux/phylink.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <linux/spinlock.h>
66
#include <linux/workqueue.h>
77

8+
#include <net/eee.h>
9+
810
struct device_node;
911
struct ethtool_cmd;
1012
struct fwnode_handle;
@@ -143,11 +145,17 @@ enum phylink_op_type {
143145
* possible and avoid stopping it during suspend events.
144146
* @default_an_inband: if true, defaults to MLO_AN_INBAND rather than
145147
* MLO_AN_PHY. A fixed-link specification will override.
148+
* @eee_rx_clk_stop_enable: if true, PHY can stop the receive clock during LPI
146149
* @get_fixed_state: callback to execute to determine the fixed link state,
147150
* if MAC link is at %MLO_AN_FIXED mode.
148151
* @supported_interfaces: bitmap describing which PHY_INTERFACE_MODE_xxx
149152
* are supported by the MAC/PCS.
153+
* @lpi_interfaces: bitmap describing which PHY interface modes can support
154+
* LPI signalling.
150155
* @mac_capabilities: MAC pause/speed/duplex capabilities.
156+
* @lpi_capabilities: MAC speeds which can support LPI signalling
157+
* @lpi_timer_default: Default EEE LPI timer setting.
158+
* @eee_enabled_default: If set, EEE will be enabled by phylink at creation time
151159
*/
152160
struct phylink_config {
153161
struct device *dev;
@@ -156,10 +164,15 @@ struct phylink_config {
156164
bool mac_managed_pm;
157165
bool mac_requires_rxc;
158166
bool default_an_inband;
167+
bool eee_rx_clk_stop_enable;
159168
void (*get_fixed_state)(struct phylink_config *config,
160169
struct phylink_link_state *state);
161170
DECLARE_PHY_INTERFACE_MASK(supported_interfaces);
171+
DECLARE_PHY_INTERFACE_MASK(lpi_interfaces);
162172
unsigned long mac_capabilities;
173+
unsigned long lpi_capabilities;
174+
u32 lpi_timer_default;
175+
bool eee_enabled_default;
163176
};
164177

165178
void phylink_limit_mac_speed(struct phylink_config *config, u32 max_speed);
@@ -173,6 +186,8 @@ void phylink_limit_mac_speed(struct phylink_config *config, u32 max_speed);
173186
* @mac_finish: finish a major reconfiguration of the interface.
174187
* @mac_link_down: take the link down.
175188
* @mac_link_up: allow the link to come up.
189+
* @mac_disable_tx_lpi: disable LPI.
190+
* @mac_enable_tx_lpi: enable and configure LPI.
176191
*
177192
* The individual methods are described more fully below.
178193
*/
@@ -193,6 +208,9 @@ struct phylink_mac_ops {
193208
struct phy_device *phy, unsigned int mode,
194209
phy_interface_t interface, int speed, int duplex,
195210
bool tx_pause, bool rx_pause);
211+
void (*mac_disable_tx_lpi)(struct phylink_config *config);
212+
int (*mac_enable_tx_lpi)(struct phylink_config *config, u32 timer,
213+
bool tx_clk_stop);
196214
};
197215

198216
#if 0 /* For kernel-doc purposes only. */
@@ -387,6 +405,33 @@ void mac_link_down(struct phylink_config *config, unsigned int mode,
387405
void mac_link_up(struct phylink_config *config, struct phy_device *phy,
388406
unsigned int mode, phy_interface_t interface,
389407
int speed, int duplex, bool tx_pause, bool rx_pause);
408+
409+
/**
410+
* mac_disable_tx_lpi() - disable LPI generation at the MAC
411+
* @config: a pointer to a &struct phylink_config.
412+
*
413+
* Disable generation of LPI at the MAC, effectively preventing the MAC
414+
* from indicating that it is idle.
415+
*/
416+
void mac_disable_tx_lpi(struct phylink_config *config);
417+
418+
/**
419+
* mac_enable_tx_lpi() - configure and enable LPI generation at the MAC
420+
* @config: a pointer to a &struct phylink_config.
421+
* @timer: LPI timeout in microseconds.
422+
* @tx_clk_stop: allow xMII transmit clock to be stopped during LPI
423+
*
424+
* Configure the LPI timeout accordingly. This will only be called when
425+
* the link is already up, to cater for situations where the hardware
426+
* needs to be programmed according to the link speed.
427+
*
428+
* Enable LPI generation at the MAC, and configure whether the xMII transmit
429+
* clock may be stopped.
430+
*
431+
* Returns: 0 on success. Please consult with rmk before returning an error.
432+
*/
433+
int mac_enable_tx_lpi(struct phylink_config *config, u32 timer,
434+
bool tx_clk_stop);
390435
#endif
391436

392437
struct phylink_pcs_ops;

0 commit comments

Comments
 (0)