[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <E1a5zkj-00076u-9Y@rmk-PC.arm.linux.org.uk>
Date: Mon, 07 Dec 2015 17:39:09 +0000
From: Russell King <rmk+kernel@....linux.org.uk>
To: Florian Fainelli <f.fainelli@...il.com>,
Thomas Petazzoni <thomas.petazzoni@...e-electrons.com>
Cc: netdev@...r.kernel.org
Subject: [PATCH RFC 23/26] 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@....linux.org.uk>
---
drivers/net/ethernet/marvell/mvneta.c | 87 +++++++++++++++++++++++++++++++++++
1 file changed, 87 insertions(+)
diff --git a/drivers/net/ethernet/marvell/mvneta.c b/drivers/net/ethernet/marvell/mvneta.c
index 165dfab134b7..3de2aa9335b2 100644
--- a/drivers/net/ethernet/marvell/mvneta.c
+++ b/drivers/net/ethernet/marvell/mvneta.c
@@ -224,6 +224,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 */
@@ -288,6 +294,11 @@
#define MVNETA_RX_BUF_SIZE(pkt_size) ((pkt_size) + NET_SKB_PAD)
+enum {
+ ETHTOOL_STAT_EEE_WAKEUP,
+ ETHTOOL_MAX_STATS,
+};
+
struct mvneta_statistic {
unsigned short offset;
unsigned short type;
@@ -296,6 +307,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", },
@@ -330,6 +342,7 @@ static const struct mvneta_statistic mvneta_statistics[] = {
{ 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 {
@@ -373,6 +386,10 @@ struct mvneta_port {
unsigned int tx_csum_limit;
struct phylink *phylink;
+ bool eee_enabled;
+ bool eee_active;
+ bool tx_lpi_enabled;
+
u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)];
};
@@ -2750,6 +2767,18 @@ static void mvneta_mac_config(struct net_device *ndev, unsigned int mode,
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);
@@ -2763,6 +2792,9 @@ static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode)
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,
@@ -2779,6 +2811,11 @@ static void mvneta_mac_link_up(struct net_device *ndev, unsigned int mode,
}
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 = {
@@ -3175,6 +3212,13 @@ static void mvneta_ethtool_update_stats(struct mvneta_port *pp)
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;
@@ -3200,6 +3244,47 @@ static int mvneta_ethtool_get_sset_count(struct net_device *dev, int sset)
return -EOPNOTSUPP;
}
+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,
@@ -3227,6 +3312,8 @@ const struct ethtool_ops mvneta_eth_tool_ops = {
.get_strings = mvneta_ethtool_get_strings,
.get_ethtool_stats = mvneta_ethtool_get_stats,
.get_sset_count = mvneta_ethtool_get_sset_count,
+ .get_eee = mvneta_ethtool_get_eee,
+ .set_eee = mvneta_ethtool_set_eee,
};
/* Initialize hw */
--
2.1.0
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists