123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- 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 */
|