diff options
Diffstat (limited to 'target/linux/mvebu/patches-4.4/143-net-mvneta-add-EEE-support.patch')
-rw-r--r-- | target/linux/mvebu/patches-4.4/143-net-mvneta-add-EEE-support.patch | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/target/linux/mvebu/patches-4.4/143-net-mvneta-add-EEE-support.patch b/target/linux/mvebu/patches-4.4/143-net-mvneta-add-EEE-support.patch new file mode 100644 index 0000000000..b9043561d0 --- /dev/null +++ b/target/linux/mvebu/patches-4.4/143-net-mvneta-add-EEE-support.patch @@ -0,0 +1,182 @@ +From b7dacf514e41d6efff0ccc170f660cc6dc2aeae2 Mon Sep 17 00:00:00 2001 +From: Russell King <rmk+kernel@arm.linux.org.uk> +Date: Tue, 29 Sep 2015 15:17:39 +0100 +Subject: [PATCH 731/744] 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> +--- + drivers/net/ethernet/marvell/mvneta.c | 87 +++++++++++++++++++++++++++++++++++ + 1 file changed, 87 insertions(+) + +--- 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 { +@@ -413,6 +426,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]; +@@ -3276,6 +3293,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); +@@ -3289,6 +3318,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, +@@ -3305,6 +3337,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 = { +@@ -3744,6 +3781,13 @@ static void mvneta_ethtool_update_stats( + val64 = (u64)high << 32 | low; + pp->ethtool_stats[i] += val64; + break; ++ case T_SW: ++ switch (s->offset) { ++ case ETHTOOL_STAT_EEE_WAKEUP: ++ val = phylink_get_eee_err(pp->phylink); ++ break; ++ } ++ break; + } + } + } +@@ -3867,6 +3911,47 @@ static int mvneta_ethtool_get_rxfh(struc + return 0; + } + ++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, +@@ -3898,6 +3983,8 @@ const struct ethtool_ops mvneta_eth_tool + .get_rxnfc = mvneta_ethtool_get_rxnfc, + .get_rxfh = mvneta_ethtool_get_rxfh, + .set_rxfh = mvneta_ethtool_set_rxfh, ++ .get_eee = mvneta_ethtool_get_eee, ++ .set_eee = mvneta_ethtool_set_eee, + }; + + /* Initialize hw */ |