summaryrefslogtreecommitdiff
path: root/target/linux/mvebu/patches-4.9/428-net-mvneta-add-EEE-support.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/mvebu/patches-4.9/428-net-mvneta-add-EEE-support.patch')
-rw-r--r--target/linux/mvebu/patches-4.9/428-net-mvneta-add-EEE-support.patch179
1 files changed, 179 insertions, 0 deletions
diff --git a/target/linux/mvebu/patches-4.9/428-net-mvneta-add-EEE-support.patch b/target/linux/mvebu/patches-4.9/428-net-mvneta-add-EEE-support.patch
new file mode 100644
index 0000000..a8bafd9
--- /dev/null
+++ b/target/linux/mvebu/patches-4.9/428-net-mvneta-add-EEE-support.patch
@@ -0,0 +1,179 @@
+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];
+@@ -3291,6 +3308,18 @@ static void mvneta_mac_config(struct net
+ 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);
+@@ -3304,6 +3333,9 @@ static void mvneta_mac_link_down(struct
+ 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,
+@@ -3320,6 +3352,11 @@ static void mvneta_mac_link_up(struct ne
+ }
+
+ 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 = {
+@@ -3772,6 +3809,13 @@ static void mvneta_ethtool_update_stats(
+ 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;
+@@ -3907,6 +3951,47 @@ static u16 mvneta_select_queue(struct ne
+ }
+
+
++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,
+@@ -3939,6 +4024,8 @@ const struct ethtool_ops mvneta_eth_tool
+ .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 */