2017-02-06 10:46:48 +00:00
|
|
|
From: Russell King <rmk+kernel@arm.linux.org.uk>
|
|
|
|
Date: Tue, 29 Sep 2015 15:17:39 +0100
|
|
|
|
Subject: [PATCH] net: mvneta: add EEE support
|
|
|
|
|
|
|
|
Add EEE support to mvneta. This allows us to enable the low power idle
|
|
|
|
support at MAC level if there is a PHY attached through phylink which
|
|
|
|
supports LPI. The appropriate ethtool support is provided to allow the
|
|
|
|
feature to be controlled, including ethtool statistics for EEE wakeup
|
|
|
|
errors.
|
|
|
|
|
|
|
|
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
|
|
|
|
---
|
|
|
|
|
|
|
|
--- a/drivers/net/ethernet/marvell/mvneta.c
|
|
|
|
+++ b/drivers/net/ethernet/marvell/mvneta.c
|
|
|
|
@@ -243,6 +243,12 @@
|
|
|
|
#define MVNETA_TXQ_TOKEN_SIZE_REG(q) (0x3e40 + ((q) << 2))
|
|
|
|
#define MVNETA_TXQ_TOKEN_SIZE_MAX 0x7fffffff
|
|
|
|
|
|
|
|
+#define MVNETA_LPI_CTRL_0 0x2cc0
|
|
|
|
+#define MVNETA_LPI_CTRL_1 0x2cc4
|
|
|
|
+#define MVNETA_LPI_REQUEST_ENABLE BIT(0)
|
|
|
|
+#define MVNETA_LPI_CTRL_2 0x2cc8
|
|
|
|
+#define MVNETA_LPI_STATUS 0x2ccc
|
|
|
|
+
|
|
|
|
#define MVNETA_CAUSE_TXQ_SENT_DESC_ALL_MASK 0xff
|
|
|
|
|
|
|
|
/* Descriptor ring Macros */
|
|
|
|
@@ -316,6 +322,11 @@
|
|
|
|
#define MVNETA_RX_GET_BM_POOL_ID(rxd) \
|
|
|
|
(((rxd)->status & MVNETA_RXD_BM_POOL_MASK) >> MVNETA_RXD_BM_POOL_SHIFT)
|
|
|
|
|
|
|
|
+enum {
|
|
|
|
+ ETHTOOL_STAT_EEE_WAKEUP,
|
|
|
|
+ ETHTOOL_MAX_STATS,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
struct mvneta_statistic {
|
|
|
|
unsigned short offset;
|
|
|
|
unsigned short type;
|
|
|
|
@@ -324,6 +335,7 @@ struct mvneta_statistic {
|
|
|
|
|
|
|
|
#define T_REG_32 32
|
|
|
|
#define T_REG_64 64
|
|
|
|
+#define T_SW 1
|
|
|
|
|
|
|
|
static const struct mvneta_statistic mvneta_statistics[] = {
|
|
|
|
{ 0x3000, T_REG_64, "good_octets_received", },
|
|
|
|
@@ -358,6 +370,7 @@ static const struct mvneta_statistic mvn
|
|
|
|
{ 0x304c, T_REG_32, "broadcast_frames_sent", },
|
|
|
|
{ 0x3054, T_REG_32, "fc_sent", },
|
|
|
|
{ 0x300c, T_REG_32, "internal_mac_transmit_err", },
|
|
|
|
+ { ETHTOOL_STAT_EEE_WAKEUP, T_SW, "eee_wakeup_errors", },
|
|
|
|
};
|
|
|
|
|
|
|
|
struct mvneta_pcpu_stats {
|
|
|
|
@@ -416,6 +429,10 @@ 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];
|
2017-09-28 07:08:59 +00:00
|
|
|
@@ -3289,6 +3306,18 @@ static void mvneta_mac_config(struct net
|
2017-02-06 10:46:48 +00:00
|
|
|
mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, new_an);
|
|
|
|
}
|
|
|
|
|
|
|
|
+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 net_device *ndev, unsigned int mode)
|
|
|
|
{
|
|
|
|
struct mvneta_port *pp = netdev_priv(ndev);
|
2017-09-28 07:08:59 +00:00
|
|
|
@@ -3302,6 +3331,9 @@ static void mvneta_mac_link_down(struct
|
2017-02-06 10:46:48 +00:00
|
|
|
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 net_device *ndev, unsigned int mode,
|
2017-09-28 07:08:59 +00:00
|
|
|
@@ -3318,6 +3350,11 @@ static void mvneta_mac_link_up(struct ne
|
2017-02-06 10:46:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mvneta_port_up(pp);
|
|
|
|
+
|
|
|
|
+ if (phy && pp->eee_enabled) {
|
|
|
|
+ pp->eee_active = phy_init_eee(phy, 0) >= 0;
|
|
|
|
+ mvneta_set_eee(pp, pp->eee_active && pp->tx_lpi_enabled);
|
|
|
|
+ }
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct phylink_mac_ops mvneta_phylink_ops = {
|
2017-09-28 07:08:59 +00:00
|
|
|
@@ -3770,6 +3807,13 @@ static void mvneta_ethtool_update_stats(
|
2017-02-06 10:46:48 +00:00
|
|
|
high = readl_relaxed(base + s->offset + 4);
|
|
|
|
val = (u64)high << 32 | low;
|
|
|
|
break;
|
|
|
|
+ case T_SW:
|
|
|
|
+ switch (s->offset) {
|
|
|
|
+ case ETHTOOL_STAT_EEE_WAKEUP:
|
|
|
|
+ val = phylink_get_eee_err(pp->phylink);
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pp->ethtool_stats[i] += val;
|
2017-09-28 07:08:59 +00:00
|
|
|
@@ -3905,6 +3949,47 @@ static u16 mvneta_select_queue(struct ne
|
2017-02-06 10:46:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
+static int mvneta_ethtool_get_eee(struct net_device *dev,
|
|
|
|
+ struct ethtool_eee *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);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int mvneta_ethtool_set_eee(struct net_device *dev,
|
|
|
|
+ struct ethtool_eee *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 < 0 || 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);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
static const struct net_device_ops mvneta_netdev_ops = {
|
|
|
|
.ndo_open = mvneta_open,
|
|
|
|
.ndo_stop = mvneta_stop,
|
2017-09-28 07:08:59 +00:00
|
|
|
@@ -3937,6 +4022,8 @@ const struct ethtool_ops mvneta_eth_tool
|
2017-02-06 10:46:48 +00:00
|
|
|
.set_rxfh = mvneta_ethtool_set_rxfh,
|
|
|
|
.get_link_ksettings = mvneta_ethtool_get_link_ksettings,
|
|
|
|
.set_link_ksettings = mvneta_ethtool_set_link_ksettings,
|
|
|
|
+ .get_eee = mvneta_ethtool_get_eee,
|
|
|
|
+ .set_eee = mvneta_ethtool_set_eee,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Initialize hw */
|