1 From b7dacf514e41d6efff0ccc170f660cc6dc2aeae2 Mon Sep 17 00:00:00 2001
2 From: Russell King <rmk+kernel@arm.linux.org.uk>
3 Date: Tue, 29 Sep 2015 15:17:39 +0100
4 Subject: [PATCH 731/744] net: mvneta: add EEE support
6 Add EEE support to mvneta. This allows us to enable the low power idle
7 support at MAC level if there is a PHY attached through phylink which
8 supports LPI. The appropriate ethtool support is provided to allow the
9 feature to be controlled, including ethtool statistics for EEE wakeup
12 Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
14 drivers/net/ethernet/marvell/mvneta.c | 87 +++++++++++++++++++++++++++++++++++
15 1 file changed, 87 insertions(+)
17 --- a/drivers/net/ethernet/marvell/mvneta.c
18 +++ b/drivers/net/ethernet/marvell/mvneta.c
20 #define MVNETA_TXQ_TOKEN_SIZE_REG(q) (0x3e40 + ((q) << 2))
21 #define MVNETA_TXQ_TOKEN_SIZE_MAX 0x7fffffff
23 +#define MVNETA_LPI_CTRL_0 0x2cc0
24 +#define MVNETA_LPI_CTRL_1 0x2cc4
25 +#define MVNETA_LPI_REQUEST_ENABLE BIT(0)
26 +#define MVNETA_LPI_CTRL_2 0x2cc8
27 +#define MVNETA_LPI_STATUS 0x2ccc
29 #define MVNETA_CAUSE_TXQ_SENT_DESC_ALL_MASK 0xff
31 /* Descriptor ring Macros */
33 #define MVNETA_RX_GET_BM_POOL_ID(rxd) \
34 (((rxd)->status & MVNETA_RXD_BM_POOL_MASK) >> MVNETA_RXD_BM_POOL_SHIFT)
37 + ETHTOOL_STAT_EEE_WAKEUP,
41 struct mvneta_statistic {
42 unsigned short offset;
44 @@ -324,6 +335,7 @@ struct mvneta_statistic {
50 static const struct mvneta_statistic mvneta_statistics[] = {
51 { 0x3000, T_REG_64, "good_octets_received", },
52 @@ -358,6 +370,7 @@ static const struct mvneta_statistic mvn
53 { 0x304c, T_REG_32, "broadcast_frames_sent", },
54 { 0x3054, T_REG_32, "fc_sent", },
55 { 0x300c, T_REG_32, "internal_mac_transmit_err", },
56 + { ETHTOOL_STAT_EEE_WAKEUP, T_SW, "eee_wakeup_errors", },
59 struct mvneta_pcpu_stats {
60 @@ -413,6 +426,10 @@ struct mvneta_port {
61 struct mvneta_bm_pool *pool_short;
66 + bool tx_lpi_enabled;
68 u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)];
70 u32 indir[MVNETA_RSS_LU_TABLE_SIZE];
71 @@ -3277,6 +3294,18 @@ static void mvneta_mac_config(struct net
72 mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, new_an);
75 +static void mvneta_set_eee(struct mvneta_port *pp, bool enable)
79 + lpi_ctl1 = mvreg_read(pp, MVNETA_LPI_CTRL_1);
81 + lpi_ctl1 |= MVNETA_LPI_REQUEST_ENABLE;
83 + lpi_ctl1 &= ~MVNETA_LPI_REQUEST_ENABLE;
84 + mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi_ctl1);
87 static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode)
89 struct mvneta_port *pp = netdev_priv(ndev);
90 @@ -3290,6 +3319,9 @@ static void mvneta_mac_link_down(struct
91 val |= MVNETA_GMAC_FORCE_LINK_DOWN;
92 mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
95 + pp->eee_active = false;
96 + mvneta_set_eee(pp, false);
99 static void mvneta_mac_link_up(struct net_device *ndev, unsigned int mode,
100 @@ -3306,6 +3338,11 @@ static void mvneta_mac_link_up(struct ne
105 + if (phy && pp->eee_enabled) {
106 + pp->eee_active = phy_init_eee(phy, 0) >= 0;
107 + mvneta_set_eee(pp, pp->eee_active && pp->tx_lpi_enabled);
111 static const struct phylink_mac_ops mvneta_phylink_ops = {
112 @@ -3745,6 +3782,13 @@ static void mvneta_ethtool_update_stats(
113 val64 = (u64)high << 32 | low;
114 pp->ethtool_stats[i] += val64;
117 + switch (s->offset) {
118 + case ETHTOOL_STAT_EEE_WAKEUP:
119 + val = phylink_get_eee_err(pp->phylink);
126 @@ -3868,6 +3912,47 @@ static int mvneta_ethtool_get_rxfh(struc
130 +static int mvneta_ethtool_get_eee(struct net_device *dev,
131 + struct ethtool_eee *eee)
133 + struct mvneta_port *pp = netdev_priv(dev);
136 + lpi_ctl0 = mvreg_read(pp, MVNETA_LPI_CTRL_0);
138 + eee->eee_enabled = pp->eee_enabled;
139 + eee->eee_active = pp->eee_active;
140 + eee->tx_lpi_enabled = pp->tx_lpi_enabled;
141 + eee->tx_lpi_timer = (lpi_ctl0) >> 8; // * scale;
143 + return phylink_ethtool_get_eee(pp->phylink, eee);
146 +static int mvneta_ethtool_set_eee(struct net_device *dev,
147 + struct ethtool_eee *eee)
149 + struct mvneta_port *pp = netdev_priv(dev);
152 + /* The Armada 37x documents do not give limits for this other than
153 + * it being an 8-bit register. */
154 + if (eee->tx_lpi_enabled &&
155 + (eee->tx_lpi_timer < 0 || eee->tx_lpi_timer > 255))
158 + lpi_ctl0 = mvreg_read(pp, MVNETA_LPI_CTRL_0);
159 + lpi_ctl0 &= ~(0xff << 8);
160 + lpi_ctl0 |= eee->tx_lpi_timer << 8;
161 + mvreg_write(pp, MVNETA_LPI_CTRL_0, lpi_ctl0);
163 + pp->eee_enabled = eee->eee_enabled;
164 + pp->tx_lpi_enabled = eee->tx_lpi_enabled;
166 + mvneta_set_eee(pp, eee->tx_lpi_enabled && eee->eee_enabled);
168 + return phylink_ethtool_set_eee(pp->phylink, eee);
171 static const struct net_device_ops mvneta_netdev_ops = {
172 .ndo_open = mvneta_open,
173 .ndo_stop = mvneta_stop,
174 @@ -3899,6 +3984,8 @@ const struct ethtool_ops mvneta_eth_tool
175 .get_rxnfc = mvneta_ethtool_get_rxnfc,
176 .get_rxfh = mvneta_ethtool_get_rxfh,
177 .set_rxfh = mvneta_ethtool_set_rxfh,
178 + .get_eee = mvneta_ethtool_get_eee,
179 + .set_eee = mvneta_ethtool_set_eee,