Skip to content

Commit d338e12

Browse files
committed
Merge branch 'net-add-phylink-managed-eee-support'
Russell King says: ==================== net: add phylink managed EEE support Adding managed EEE support to phylink has been on the cards ever since the idea in phylib was mooted. This overly large series attempts to do so. I've included all the patches as it's important to get the driver patches out there. Patch 1 adds a definition for the clock stop capable bit in the PCS MMD status register. Patch 2 adds a phylib API to query whether the PHY allows the transmit xMII clock to be stopped while in LPI mode. This capability is for MAC drivers to save power when LPI is active, to allow them to stop their transmit clock. Patch 3 extracts a phylink internal helper for determining whether the link is up. Patch 4 adds basic phylink managed EEE support. Two new MAC APIs are added, to enable and disable LPI. The enable method is passed the LPI timer setting which it is expected to program into the hardware, and also a flag ehther the transmit clock should be stopped. I have taken the decision to make enable_tx_lpi() to return an error code, but not do much with it other than report it - the intention being that we can later use it to extend functionality if needed without reworking loads of drivers. I have also dropped the validation/limitation of the LPI timer, and left that in the driver code prior to calling phylink_ethtool_set_eee(). The remainder of the patches convert mvneta, lan743x and stmmac, and add support for mvneta. ==================== Link: https://patch.msgid.link/Z4gdtOaGsBhQCZXn@shell.armlinux.org.uk Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2 parents 6da7a0f + 4218647 commit d338e12

File tree

12 files changed

+446
-93
lines changed

12 files changed

+446
-93
lines changed

drivers/net/ethernet/marvell/mvneta.c

Lines changed: 65 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,12 @@
284284
MVNETA_TXQ_BUCKET_REFILL_PERIOD))
285285

286286
#define MVNETA_LPI_CTRL_0 0x2cc0
287+
#define MVNETA_LPI_CTRL_0_TS (0xff << 8)
287288
#define MVNETA_LPI_CTRL_1 0x2cc4
288-
#define MVNETA_LPI_REQUEST_ENABLE BIT(0)
289+
#define MVNETA_LPI_CTRL_1_REQUEST_ENABLE BIT(0)
290+
#define MVNETA_LPI_CTRL_1_REQUEST_FORCE BIT(1)
291+
#define MVNETA_LPI_CTRL_1_MANUAL_MODE BIT(2)
292+
#define MVNETA_LPI_CTRL_1_TW (0xfff << 4)
289293
#define MVNETA_LPI_CTRL_2 0x2cc8
290294
#define MVNETA_LPI_STATUS 0x2ccc
291295

@@ -541,10 +545,6 @@ struct mvneta_port {
541545
struct mvneta_bm_pool *pool_short;
542546
int bm_win_id;
543547

544-
bool eee_enabled;
545-
bool eee_active;
546-
bool tx_lpi_enabled;
547-
548548
u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)];
549549

550550
u32 indir[MVNETA_RSS_LU_TABLE_SIZE];
@@ -4213,18 +4213,6 @@ static int mvneta_mac_finish(struct phylink_config *config, unsigned int mode,
42134213
return 0;
42144214
}
42154215

4216-
static void mvneta_set_eee(struct mvneta_port *pp, bool enable)
4217-
{
4218-
u32 lpi_ctl1;
4219-
4220-
lpi_ctl1 = mvreg_read(pp, MVNETA_LPI_CTRL_1);
4221-
if (enable)
4222-
lpi_ctl1 |= MVNETA_LPI_REQUEST_ENABLE;
4223-
else
4224-
lpi_ctl1 &= ~MVNETA_LPI_REQUEST_ENABLE;
4225-
mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi_ctl1);
4226-
}
4227-
42284216
static void mvneta_mac_link_down(struct phylink_config *config,
42294217
unsigned int mode, phy_interface_t interface)
42304218
{
@@ -4240,9 +4228,6 @@ static void mvneta_mac_link_down(struct phylink_config *config,
42404228
val |= MVNETA_GMAC_FORCE_LINK_DOWN;
42414229
mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
42424230
}
4243-
4244-
pp->eee_active = false;
4245-
mvneta_set_eee(pp, false);
42464231
}
42474232

42484233
static void mvneta_mac_link_up(struct phylink_config *config,
@@ -4291,11 +4276,56 @@ static void mvneta_mac_link_up(struct phylink_config *config,
42914276
}
42924277

42934278
mvneta_port_up(pp);
4279+
}
42944280

4295-
if (phy && pp->eee_enabled) {
4296-
pp->eee_active = phy_init_eee(phy, false) >= 0;
4297-
mvneta_set_eee(pp, pp->eee_active && pp->tx_lpi_enabled);
4281+
static void mvneta_mac_disable_tx_lpi(struct phylink_config *config)
4282+
{
4283+
struct mvneta_port *pp = netdev_priv(to_net_dev(config->dev));
4284+
u32 lpi1;
4285+
4286+
lpi1 = mvreg_read(pp, MVNETA_LPI_CTRL_1);
4287+
lpi1 &= ~(MVNETA_LPI_CTRL_1_REQUEST_ENABLE |
4288+
MVNETA_LPI_CTRL_1_REQUEST_FORCE |
4289+
MVNETA_LPI_CTRL_1_MANUAL_MODE);
4290+
mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi1);
4291+
}
4292+
4293+
static int mvneta_mac_enable_tx_lpi(struct phylink_config *config, u32 timer,
4294+
bool tx_clk_stop)
4295+
{
4296+
struct mvneta_port *pp = netdev_priv(to_net_dev(config->dev));
4297+
u32 ts, tw, lpi0, lpi1, status;
4298+
4299+
status = mvreg_read(pp, MVNETA_GMAC_STATUS);
4300+
if (status & MVNETA_GMAC_SPEED_1000) {
4301+
/* At 1G speeds, the timer resolution are 1us, and
4302+
* 802.3 says tw is 16.5us. Round up to 17us.
4303+
*/
4304+
tw = 17;
4305+
ts = timer;
4306+
} else {
4307+
/* At 100M speeds, the timer resolutions are 10us, and
4308+
* 802.3 says tw is 30us.
4309+
*/
4310+
tw = 3;
4311+
ts = DIV_ROUND_UP(timer, 10);
42984312
}
4313+
4314+
if (ts > 255)
4315+
ts = 255;
4316+
4317+
/* Configure ts */
4318+
lpi0 = mvreg_read(pp, MVNETA_LPI_CTRL_0);
4319+
lpi0 = u32_replace_bits(lpi0, ts, MVNETA_LPI_CTRL_0_TS);
4320+
mvreg_write(pp, MVNETA_LPI_CTRL_0, lpi0);
4321+
4322+
/* Configure tw and enable LPI generation */
4323+
lpi1 = mvreg_read(pp, MVNETA_LPI_CTRL_1);
4324+
lpi1 = u32_replace_bits(lpi1, tw, MVNETA_LPI_CTRL_1_TW);
4325+
lpi1 |= MVNETA_LPI_CTRL_1_REQUEST_ENABLE;
4326+
mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi1);
4327+
4328+
return 0;
42994329
}
43004330

43014331
static const struct phylink_mac_ops mvneta_phylink_ops = {
@@ -4305,6 +4335,8 @@ static const struct phylink_mac_ops mvneta_phylink_ops = {
43054335
.mac_finish = mvneta_mac_finish,
43064336
.mac_link_down = mvneta_mac_link_down,
43074337
.mac_link_up = mvneta_mac_link_up,
4338+
.mac_disable_tx_lpi = mvneta_mac_disable_tx_lpi,
4339+
.mac_enable_tx_lpi = mvneta_mac_enable_tx_lpi,
43084340
};
43094341

43104342
static int mvneta_mdio_probe(struct mvneta_port *pp)
@@ -5109,14 +5141,6 @@ static int mvneta_ethtool_get_eee(struct net_device *dev,
51095141
struct ethtool_keee *eee)
51105142
{
51115143
struct mvneta_port *pp = netdev_priv(dev);
5112-
u32 lpi_ctl0;
5113-
5114-
lpi_ctl0 = mvreg_read(pp, MVNETA_LPI_CTRL_0);
5115-
5116-
eee->eee_enabled = pp->eee_enabled;
5117-
eee->eee_active = pp->eee_active;
5118-
eee->tx_lpi_enabled = pp->tx_lpi_enabled;
5119-
eee->tx_lpi_timer = (lpi_ctl0) >> 8; // * scale;
51205144

51215145
return phylink_ethtool_get_eee(pp->phylink, eee);
51225146
}
@@ -5125,24 +5149,13 @@ static int mvneta_ethtool_set_eee(struct net_device *dev,
51255149
struct ethtool_keee *eee)
51265150
{
51275151
struct mvneta_port *pp = netdev_priv(dev);
5128-
u32 lpi_ctl0;
51295152

51305153
/* The Armada 37x documents do not give limits for this other than
51315154
* it being an 8-bit register.
51325155
*/
51335156
if (eee->tx_lpi_enabled && eee->tx_lpi_timer > 255)
51345157
return -EINVAL;
51355158

5136-
lpi_ctl0 = mvreg_read(pp, MVNETA_LPI_CTRL_0);
5137-
lpi_ctl0 &= ~(0xff << 8);
5138-
lpi_ctl0 |= eee->tx_lpi_timer << 8;
5139-
mvreg_write(pp, MVNETA_LPI_CTRL_0, lpi_ctl0);
5140-
5141-
pp->eee_enabled = eee->eee_enabled;
5142-
pp->tx_lpi_enabled = eee->tx_lpi_enabled;
5143-
5144-
mvneta_set_eee(pp, eee->tx_lpi_enabled && eee->eee_enabled);
5145-
51465159
return phylink_ethtool_set_eee(pp->phylink, eee);
51475160
}
51485161

@@ -5456,6 +5469,9 @@ static int mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
54565469
!phy_interface_mode_is_rgmii(phy_mode))
54575470
return -EINVAL;
54585471

5472+
/* Ensure LPI is disabled */
5473+
mvneta_mac_disable_tx_lpi(&pp->phylink_config);
5474+
54595475
return 0;
54605476
}
54615477

@@ -5547,6 +5563,13 @@ static int mvneta_probe(struct platform_device *pdev)
55475563
pp->phylink_config.mac_capabilities = MAC_SYM_PAUSE | MAC_10 |
55485564
MAC_100 | MAC_1000FD | MAC_2500FD;
55495565

5566+
/* Setup EEE. Choose 250us idle. Only supported in SGMII modes. */
5567+
__set_bit(PHY_INTERFACE_MODE_QSGMII, pp->phylink_config.lpi_interfaces);
5568+
__set_bit(PHY_INTERFACE_MODE_SGMII, pp->phylink_config.lpi_interfaces);
5569+
pp->phylink_config.lpi_capabilities = MAC_100FD | MAC_1000FD;
5570+
pp->phylink_config.lpi_timer_default = 250;
5571+
pp->phylink_config.eee_enabled_default = true;
5572+
55505573
phy_interface_set_rgmii(pp->phylink_config.supported_interfaces);
55515574
__set_bit(PHY_INTERFACE_MODE_QSGMII,
55525575
pp->phylink_config.supported_interfaces);

drivers/net/ethernet/marvell/mvpp2/mvpp2.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,11 @@
481481
#define MVPP22_GMAC_INT_SUM_MASK 0xa4
482482
#define MVPP22_GMAC_INT_SUM_MASK_LINK_STAT BIT(1)
483483
#define MVPP22_GMAC_INT_SUM_MASK_PTP BIT(2)
484+
#define MVPP2_GMAC_LPI_CTRL0 0xc0
485+
#define MVPP2_GMAC_LPI_CTRL0_TS_MASK GENMASK(15, 8)
486+
#define MVPP2_GMAC_LPI_CTRL1 0xc4
487+
#define MVPP2_GMAC_LPI_CTRL1_REQ_EN BIT(0)
488+
#define MVPP2_GMAC_LPI_CTRL1_TW_MASK GENMASK(15, 4)
484489

485490
/* Per-port XGMAC registers. PPv2.2 and PPv2.3, only for GOP port 0,
486491
* relative to port->base.

drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5757,6 +5757,28 @@ static int mvpp2_ethtool_set_rxfh(struct net_device *dev,
57575757
return mvpp2_modify_rxfh_context(dev, NULL, rxfh, extack);
57585758
}
57595759

5760+
static int mvpp2_ethtool_get_eee(struct net_device *dev,
5761+
struct ethtool_keee *eee)
5762+
{
5763+
struct mvpp2_port *port = netdev_priv(dev);
5764+
5765+
if (!port->phylink)
5766+
return -EOPNOTSUPP;
5767+
5768+
return phylink_ethtool_get_eee(port->phylink, eee);
5769+
}
5770+
5771+
static int mvpp2_ethtool_set_eee(struct net_device *dev,
5772+
struct ethtool_keee *eee)
5773+
{
5774+
struct mvpp2_port *port = netdev_priv(dev);
5775+
5776+
if (!port->phylink)
5777+
return -EOPNOTSUPP;
5778+
5779+
return phylink_ethtool_set_eee(port->phylink, eee);
5780+
}
5781+
57605782
/* Device ops */
57615783

57625784
static const struct net_device_ops mvpp2_netdev_ops = {
@@ -5802,6 +5824,8 @@ static const struct ethtool_ops mvpp2_eth_tool_ops = {
58025824
.create_rxfh_context = mvpp2_create_rxfh_context,
58035825
.modify_rxfh_context = mvpp2_modify_rxfh_context,
58045826
.remove_rxfh_context = mvpp2_remove_rxfh_context,
5827+
.get_eee = mvpp2_ethtool_get_eee,
5828+
.set_eee = mvpp2_ethtool_set_eee,
58055829
};
58065830

58075831
/* Used for PPv2.1, or PPv2.2 with the old Device Tree binding that
@@ -6674,13 +6698,64 @@ static void mvpp2_mac_link_down(struct phylink_config *config,
66746698
mvpp2_port_disable(port);
66756699
}
66766700

6701+
static void mvpp2_mac_disable_tx_lpi(struct phylink_config *config)
6702+
{
6703+
struct mvpp2_port *port = mvpp2_phylink_to_port(config);
6704+
6705+
mvpp2_modify(port->base + MVPP2_GMAC_LPI_CTRL1,
6706+
MVPP2_GMAC_LPI_CTRL1_REQ_EN, 0);
6707+
}
6708+
6709+
static int mvpp2_mac_enable_tx_lpi(struct phylink_config *config, u32 timer,
6710+
bool tx_clk_stop)
6711+
{
6712+
struct mvpp2_port *port = mvpp2_phylink_to_port(config);
6713+
u32 ts, tw, lpi1, status;
6714+
6715+
status = readl(port->base + MVPP2_GMAC_STATUS0);
6716+
if (status & MVPP2_GMAC_STATUS0_GMII_SPEED) {
6717+
/* At 1G speeds, the timer resolution are 1us, and
6718+
* 802.3 says tw is 16.5us. Round up to 17us.
6719+
*/
6720+
tw = 17;
6721+
ts = timer;
6722+
} else {
6723+
/* At 100M speeds, the timer resolutions are 10us, and
6724+
* 802.3 says tw is 30us.
6725+
*/
6726+
tw = 3;
6727+
ts = DIV_ROUND_UP(timer, 10);
6728+
}
6729+
6730+
if (ts > 255)
6731+
ts = 255;
6732+
6733+
/* Configure ts */
6734+
mvpp2_modify(port->base + MVPP2_GMAC_LPI_CTRL0,
6735+
MVPP2_GMAC_LPI_CTRL0_TS_MASK,
6736+
FIELD_PREP(MVPP2_GMAC_LPI_CTRL0_TS_MASK, ts));
6737+
6738+
lpi1 = readl(port->base + MVPP2_GMAC_LPI_CTRL1);
6739+
6740+
/* Configure tw */
6741+
lpi1 = u32_replace_bits(lpi1, tw, MVPP2_GMAC_LPI_CTRL1_TW_MASK);
6742+
6743+
/* Enable LPI generation */
6744+
writel(lpi1 | MVPP2_GMAC_LPI_CTRL1_REQ_EN,
6745+
port->base + MVPP2_GMAC_LPI_CTRL1);
6746+
6747+
return 0;
6748+
}
6749+
66776750
static const struct phylink_mac_ops mvpp2_phylink_ops = {
66786751
.mac_select_pcs = mvpp2_select_pcs,
66796752
.mac_prepare = mvpp2_mac_prepare,
66806753
.mac_config = mvpp2_mac_config,
66816754
.mac_finish = mvpp2_mac_finish,
66826755
.mac_link_up = mvpp2_mac_link_up,
66836756
.mac_link_down = mvpp2_mac_link_down,
6757+
.mac_enable_tx_lpi = mvpp2_mac_enable_tx_lpi,
6758+
.mac_disable_tx_lpi = mvpp2_mac_disable_tx_lpi,
66846759
};
66856760

66866761
/* Work-around for ACPI */
@@ -6959,6 +7034,15 @@ static int mvpp2_port_probe(struct platform_device *pdev,
69597034
port->phylink_config.mac_capabilities =
69607035
MAC_2500FD | MAC_1000FD | MAC_100 | MAC_10;
69617036

7037+
__set_bit(PHY_INTERFACE_MODE_SGMII,
7038+
port->phylink_config.lpi_interfaces);
7039+
7040+
port->phylink_config.lpi_capabilities = MAC_1000FD | MAC_100FD;
7041+
7042+
/* Setup EEE. Choose 250us idle. */
7043+
port->phylink_config.lpi_timer_default = 250;
7044+
port->phylink_config.eee_enabled_default = true;
7045+
69627046
if (port->priv->global_tx_fc)
69637047
port->phylink_config.mac_capabilities |=
69647048
MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
@@ -7033,6 +7117,8 @@ static int mvpp2_port_probe(struct platform_device *pdev,
70337117
goto err_free_port_pcpu;
70347118
}
70357119
port->phylink = phylink;
7120+
7121+
mvpp2_mac_disable_tx_lpi(&port->phylink_config);
70367122
} else {
70377123
dev_warn(&pdev->dev, "Use link irqs for port#%d. FW update required\n", port->id);
70387124
port->phylink = NULL;

drivers/net/ethernet/microchip/lan743x_ethtool.c

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1055,34 +1055,13 @@ static int lan743x_ethtool_get_eee(struct net_device *netdev,
10551055
{
10561056
struct lan743x_adapter *adapter = netdev_priv(netdev);
10571057

1058-
eee->tx_lpi_timer = lan743x_csr_read(adapter,
1059-
MAC_EEE_TX_LPI_REQ_DLY_CNT);
1060-
10611058
return phylink_ethtool_get_eee(adapter->phylink, eee);
10621059
}
10631060

10641061
static int lan743x_ethtool_set_eee(struct net_device *netdev,
10651062
struct ethtool_keee *eee)
10661063
{
10671064
struct lan743x_adapter *adapter = netdev_priv(netdev);
1068-
u32 tx_lpi_timer;
1069-
1070-
tx_lpi_timer = lan743x_csr_read(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT);
1071-
if (tx_lpi_timer != eee->tx_lpi_timer) {
1072-
u32 mac_cr = lan743x_csr_read(adapter, MAC_CR);
1073-
1074-
/* Software should only change this field when Energy Efficient
1075-
* Ethernet Enable (EEEEN) is cleared.
1076-
* This function will trigger an autonegotiation restart and
1077-
* eee will be reenabled during link up if eee was negotiated.
1078-
*/
1079-
lan743x_mac_eee_enable(adapter, false);
1080-
lan743x_csr_write(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT,
1081-
eee->tx_lpi_timer);
1082-
1083-
if (mac_cr & MAC_CR_EEE_EN_)
1084-
lan743x_mac_eee_enable(adapter, true);
1085-
}
10861065

10871066
return phylink_ethtool_set_eee(adapter->phylink, eee);
10881067
}

0 commit comments

Comments
 (0)