Skip to content

Commit

Permalink
Merge branch 'net-add-phylink-managed-eee-support'
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jakub Kicinski committed Jan 17, 2025
2 parents 6da7a0f + 4218647 commit d338e12
Show file tree
Hide file tree
Showing 12 changed files with 446 additions and 93 deletions.
107 changes: 65 additions & 42 deletions drivers/net/ethernet/marvell/mvneta.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,12 @@
MVNETA_TXQ_BUCKET_REFILL_PERIOD))

#define MVNETA_LPI_CTRL_0 0x2cc0
#define MVNETA_LPI_CTRL_0_TS (0xff << 8)
#define MVNETA_LPI_CTRL_1 0x2cc4
#define MVNETA_LPI_REQUEST_ENABLE BIT(0)
#define MVNETA_LPI_CTRL_1_REQUEST_ENABLE BIT(0)
#define MVNETA_LPI_CTRL_1_REQUEST_FORCE BIT(1)
#define MVNETA_LPI_CTRL_1_MANUAL_MODE BIT(2)
#define MVNETA_LPI_CTRL_1_TW (0xfff << 4)
#define MVNETA_LPI_CTRL_2 0x2cc8
#define MVNETA_LPI_STATUS 0x2ccc

Expand Down Expand Up @@ -541,10 +545,6 @@ struct mvneta_port {
struct mvneta_bm_pool *pool_short;
int bm_win_id;

bool eee_enabled;
bool eee_active;
bool tx_lpi_enabled;

u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)];

u32 indir[MVNETA_RSS_LU_TABLE_SIZE];
Expand Down Expand Up @@ -4213,18 +4213,6 @@ static int mvneta_mac_finish(struct phylink_config *config, unsigned int mode,
return 0;
}

static void mvneta_set_eee(struct mvneta_port *pp, bool enable)
{
u32 lpi_ctl1;

lpi_ctl1 = mvreg_read(pp, MVNETA_LPI_CTRL_1);
if (enable)
lpi_ctl1 |= MVNETA_LPI_REQUEST_ENABLE;
else
lpi_ctl1 &= ~MVNETA_LPI_REQUEST_ENABLE;
mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi_ctl1);
}

static void mvneta_mac_link_down(struct phylink_config *config,
unsigned int mode, phy_interface_t interface)
{
Expand All @@ -4240,9 +4228,6 @@ static void mvneta_mac_link_down(struct phylink_config *config,
val |= MVNETA_GMAC_FORCE_LINK_DOWN;
mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
}

pp->eee_active = false;
mvneta_set_eee(pp, false);
}

static void mvneta_mac_link_up(struct phylink_config *config,
Expand Down Expand Up @@ -4291,11 +4276,56 @@ static void mvneta_mac_link_up(struct phylink_config *config,
}

mvneta_port_up(pp);
}

if (phy && pp->eee_enabled) {
pp->eee_active = phy_init_eee(phy, false) >= 0;
mvneta_set_eee(pp, pp->eee_active && pp->tx_lpi_enabled);
static void mvneta_mac_disable_tx_lpi(struct phylink_config *config)
{
struct mvneta_port *pp = netdev_priv(to_net_dev(config->dev));
u32 lpi1;

lpi1 = mvreg_read(pp, MVNETA_LPI_CTRL_1);
lpi1 &= ~(MVNETA_LPI_CTRL_1_REQUEST_ENABLE |
MVNETA_LPI_CTRL_1_REQUEST_FORCE |
MVNETA_LPI_CTRL_1_MANUAL_MODE);
mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi1);
}

static int mvneta_mac_enable_tx_lpi(struct phylink_config *config, u32 timer,
bool tx_clk_stop)
{
struct mvneta_port *pp = netdev_priv(to_net_dev(config->dev));
u32 ts, tw, lpi0, lpi1, status;

status = mvreg_read(pp, MVNETA_GMAC_STATUS);
if (status & MVNETA_GMAC_SPEED_1000) {
/* At 1G speeds, the timer resolution are 1us, and
* 802.3 says tw is 16.5us. Round up to 17us.
*/
tw = 17;
ts = timer;
} else {
/* At 100M speeds, the timer resolutions are 10us, and
* 802.3 says tw is 30us.
*/
tw = 3;
ts = DIV_ROUND_UP(timer, 10);
}

if (ts > 255)
ts = 255;

/* Configure ts */
lpi0 = mvreg_read(pp, MVNETA_LPI_CTRL_0);
lpi0 = u32_replace_bits(lpi0, ts, MVNETA_LPI_CTRL_0_TS);
mvreg_write(pp, MVNETA_LPI_CTRL_0, lpi0);

/* Configure tw and enable LPI generation */
lpi1 = mvreg_read(pp, MVNETA_LPI_CTRL_1);
lpi1 = u32_replace_bits(lpi1, tw, MVNETA_LPI_CTRL_1_TW);
lpi1 |= MVNETA_LPI_CTRL_1_REQUEST_ENABLE;
mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi1);

return 0;
}

static const struct phylink_mac_ops mvneta_phylink_ops = {
Expand All @@ -4305,6 +4335,8 @@ static const struct phylink_mac_ops mvneta_phylink_ops = {
.mac_finish = mvneta_mac_finish,
.mac_link_down = mvneta_mac_link_down,
.mac_link_up = mvneta_mac_link_up,
.mac_disable_tx_lpi = mvneta_mac_disable_tx_lpi,
.mac_enable_tx_lpi = mvneta_mac_enable_tx_lpi,
};

static int mvneta_mdio_probe(struct mvneta_port *pp)
Expand Down Expand Up @@ -5109,14 +5141,6 @@ static int mvneta_ethtool_get_eee(struct net_device *dev,
struct ethtool_keee *eee)
{
struct mvneta_port *pp = netdev_priv(dev);
u32 lpi_ctl0;

lpi_ctl0 = mvreg_read(pp, MVNETA_LPI_CTRL_0);

eee->eee_enabled = pp->eee_enabled;
eee->eee_active = pp->eee_active;
eee->tx_lpi_enabled = pp->tx_lpi_enabled;
eee->tx_lpi_timer = (lpi_ctl0) >> 8; // * scale;

return phylink_ethtool_get_eee(pp->phylink, eee);
}
Expand All @@ -5125,24 +5149,13 @@ static int mvneta_ethtool_set_eee(struct net_device *dev,
struct ethtool_keee *eee)
{
struct mvneta_port *pp = netdev_priv(dev);
u32 lpi_ctl0;

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

lpi_ctl0 = mvreg_read(pp, MVNETA_LPI_CTRL_0);
lpi_ctl0 &= ~(0xff << 8);
lpi_ctl0 |= eee->tx_lpi_timer << 8;
mvreg_write(pp, MVNETA_LPI_CTRL_0, lpi_ctl0);

pp->eee_enabled = eee->eee_enabled;
pp->tx_lpi_enabled = eee->tx_lpi_enabled;

mvneta_set_eee(pp, eee->tx_lpi_enabled && eee->eee_enabled);

return phylink_ethtool_set_eee(pp->phylink, eee);
}

Expand Down Expand Up @@ -5456,6 +5469,9 @@ static int mvneta_port_power_up(struct mvneta_port *pp, int phy_mode)
!phy_interface_mode_is_rgmii(phy_mode))
return -EINVAL;

/* Ensure LPI is disabled */
mvneta_mac_disable_tx_lpi(&pp->phylink_config);

return 0;
}

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

/* Setup EEE. Choose 250us idle. Only supported in SGMII modes. */
__set_bit(PHY_INTERFACE_MODE_QSGMII, pp->phylink_config.lpi_interfaces);
__set_bit(PHY_INTERFACE_MODE_SGMII, pp->phylink_config.lpi_interfaces);
pp->phylink_config.lpi_capabilities = MAC_100FD | MAC_1000FD;
pp->phylink_config.lpi_timer_default = 250;
pp->phylink_config.eee_enabled_default = true;

phy_interface_set_rgmii(pp->phylink_config.supported_interfaces);
__set_bit(PHY_INTERFACE_MODE_QSGMII,
pp->phylink_config.supported_interfaces);
Expand Down
5 changes: 5 additions & 0 deletions drivers/net/ethernet/marvell/mvpp2/mvpp2.h
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,11 @@
#define MVPP22_GMAC_INT_SUM_MASK 0xa4
#define MVPP22_GMAC_INT_SUM_MASK_LINK_STAT BIT(1)
#define MVPP22_GMAC_INT_SUM_MASK_PTP BIT(2)
#define MVPP2_GMAC_LPI_CTRL0 0xc0
#define MVPP2_GMAC_LPI_CTRL0_TS_MASK GENMASK(15, 8)
#define MVPP2_GMAC_LPI_CTRL1 0xc4
#define MVPP2_GMAC_LPI_CTRL1_REQ_EN BIT(0)
#define MVPP2_GMAC_LPI_CTRL1_TW_MASK GENMASK(15, 4)

/* Per-port XGMAC registers. PPv2.2 and PPv2.3, only for GOP port 0,
* relative to port->base.
Expand Down
86 changes: 86 additions & 0 deletions drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -5757,6 +5757,28 @@ static int mvpp2_ethtool_set_rxfh(struct net_device *dev,
return mvpp2_modify_rxfh_context(dev, NULL, rxfh, extack);
}

static int mvpp2_ethtool_get_eee(struct net_device *dev,
struct ethtool_keee *eee)
{
struct mvpp2_port *port = netdev_priv(dev);

if (!port->phylink)
return -EOPNOTSUPP;

return phylink_ethtool_get_eee(port->phylink, eee);
}

static int mvpp2_ethtool_set_eee(struct net_device *dev,
struct ethtool_keee *eee)
{
struct mvpp2_port *port = netdev_priv(dev);

if (!port->phylink)
return -EOPNOTSUPP;

return phylink_ethtool_set_eee(port->phylink, eee);
}

/* Device ops */

static const struct net_device_ops mvpp2_netdev_ops = {
Expand Down Expand Up @@ -5802,6 +5824,8 @@ static const struct ethtool_ops mvpp2_eth_tool_ops = {
.create_rxfh_context = mvpp2_create_rxfh_context,
.modify_rxfh_context = mvpp2_modify_rxfh_context,
.remove_rxfh_context = mvpp2_remove_rxfh_context,
.get_eee = mvpp2_ethtool_get_eee,
.set_eee = mvpp2_ethtool_set_eee,
};

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

static void mvpp2_mac_disable_tx_lpi(struct phylink_config *config)
{
struct mvpp2_port *port = mvpp2_phylink_to_port(config);

mvpp2_modify(port->base + MVPP2_GMAC_LPI_CTRL1,
MVPP2_GMAC_LPI_CTRL1_REQ_EN, 0);
}

static int mvpp2_mac_enable_tx_lpi(struct phylink_config *config, u32 timer,
bool tx_clk_stop)
{
struct mvpp2_port *port = mvpp2_phylink_to_port(config);
u32 ts, tw, lpi1, status;

status = readl(port->base + MVPP2_GMAC_STATUS0);
if (status & MVPP2_GMAC_STATUS0_GMII_SPEED) {
/* At 1G speeds, the timer resolution are 1us, and
* 802.3 says tw is 16.5us. Round up to 17us.
*/
tw = 17;
ts = timer;
} else {
/* At 100M speeds, the timer resolutions are 10us, and
* 802.3 says tw is 30us.
*/
tw = 3;
ts = DIV_ROUND_UP(timer, 10);
}

if (ts > 255)
ts = 255;

/* Configure ts */
mvpp2_modify(port->base + MVPP2_GMAC_LPI_CTRL0,
MVPP2_GMAC_LPI_CTRL0_TS_MASK,
FIELD_PREP(MVPP2_GMAC_LPI_CTRL0_TS_MASK, ts));

lpi1 = readl(port->base + MVPP2_GMAC_LPI_CTRL1);

/* Configure tw */
lpi1 = u32_replace_bits(lpi1, tw, MVPP2_GMAC_LPI_CTRL1_TW_MASK);

/* Enable LPI generation */
writel(lpi1 | MVPP2_GMAC_LPI_CTRL1_REQ_EN,
port->base + MVPP2_GMAC_LPI_CTRL1);

return 0;
}

static const struct phylink_mac_ops mvpp2_phylink_ops = {
.mac_select_pcs = mvpp2_select_pcs,
.mac_prepare = mvpp2_mac_prepare,
.mac_config = mvpp2_mac_config,
.mac_finish = mvpp2_mac_finish,
.mac_link_up = mvpp2_mac_link_up,
.mac_link_down = mvpp2_mac_link_down,
.mac_enable_tx_lpi = mvpp2_mac_enable_tx_lpi,
.mac_disable_tx_lpi = mvpp2_mac_disable_tx_lpi,
};

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

__set_bit(PHY_INTERFACE_MODE_SGMII,
port->phylink_config.lpi_interfaces);

port->phylink_config.lpi_capabilities = MAC_1000FD | MAC_100FD;

/* Setup EEE. Choose 250us idle. */
port->phylink_config.lpi_timer_default = 250;
port->phylink_config.eee_enabled_default = true;

if (port->priv->global_tx_fc)
port->phylink_config.mac_capabilities |=
MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
Expand Down Expand Up @@ -7033,6 +7117,8 @@ static int mvpp2_port_probe(struct platform_device *pdev,
goto err_free_port_pcpu;
}
port->phylink = phylink;

mvpp2_mac_disable_tx_lpi(&port->phylink_config);
} else {
dev_warn(&pdev->dev, "Use link irqs for port#%d. FW update required\n", port->id);
port->phylink = NULL;
Expand Down
21 changes: 0 additions & 21 deletions drivers/net/ethernet/microchip/lan743x_ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -1055,34 +1055,13 @@ static int lan743x_ethtool_get_eee(struct net_device *netdev,
{
struct lan743x_adapter *adapter = netdev_priv(netdev);

eee->tx_lpi_timer = lan743x_csr_read(adapter,
MAC_EEE_TX_LPI_REQ_DLY_CNT);

return phylink_ethtool_get_eee(adapter->phylink, eee);
}

static int lan743x_ethtool_set_eee(struct net_device *netdev,
struct ethtool_keee *eee)
{
struct lan743x_adapter *adapter = netdev_priv(netdev);
u32 tx_lpi_timer;

tx_lpi_timer = lan743x_csr_read(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT);
if (tx_lpi_timer != eee->tx_lpi_timer) {
u32 mac_cr = lan743x_csr_read(adapter, MAC_CR);

/* Software should only change this field when Energy Efficient
* Ethernet Enable (EEEEN) is cleared.
* This function will trigger an autonegotiation restart and
* eee will be reenabled during link up if eee was negotiated.
*/
lan743x_mac_eee_enable(adapter, false);
lan743x_csr_write(adapter, MAC_EEE_TX_LPI_REQ_DLY_CNT,
eee->tx_lpi_timer);

if (mac_cr & MAC_CR_EEE_EN_)
lan743x_mac_eee_enable(adapter, true);
}

return phylink_ethtool_set_eee(adapter->phylink, eee);
}
Expand Down
Loading

0 comments on commit d338e12

Please sign in to comment.