imx6: fix USB for 4.9 kernel
[oweals/openwrt.git] / target / linux / mvebu / patches-4.4 / 143-net-mvneta-add-EEE-support.patch
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
5
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
10 errors.
11
12 Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
13 ---
14  drivers/net/ethernet/marvell/mvneta.c | 87 +++++++++++++++++++++++++++++++++++
15  1 file changed, 87 insertions(+)
16
17 --- a/drivers/net/ethernet/marvell/mvneta.c
18 +++ b/drivers/net/ethernet/marvell/mvneta.c
19 @@ -243,6 +243,12 @@
20  #define MVNETA_TXQ_TOKEN_SIZE_REG(q)             (0x3e40 + ((q) << 2))
21  #define      MVNETA_TXQ_TOKEN_SIZE_MAX           0x7fffffff
22  
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
28 +
29  #define MVNETA_CAUSE_TXQ_SENT_DESC_ALL_MASK     0xff
30  
31  /* Descriptor ring Macros */
32 @@ -316,6 +322,11 @@
33  #define MVNETA_RX_GET_BM_POOL_ID(rxd) \
34         (((rxd)->status & MVNETA_RXD_BM_POOL_MASK) >> MVNETA_RXD_BM_POOL_SHIFT)
35  
36 +enum {
37 +       ETHTOOL_STAT_EEE_WAKEUP,
38 +       ETHTOOL_MAX_STATS,
39 +};
40 +
41  struct mvneta_statistic {
42         unsigned short offset;
43         unsigned short type;
44 @@ -324,6 +335,7 @@ struct mvneta_statistic {
45  
46  #define T_REG_32       32
47  #define T_REG_64       64
48 +#define T_SW           1
49  
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", },
57  };
58  
59  struct mvneta_pcpu_stats {
60 @@ -413,6 +426,10 @@ struct mvneta_port {
61         struct mvneta_bm_pool *pool_short;
62         int bm_win_id;
63  
64 +       bool eee_enabled;
65 +       bool eee_active;
66 +       bool tx_lpi_enabled;
67 +
68         u64 ethtool_stats[ARRAY_SIZE(mvneta_statistics)];
69  
70         u32 indir[MVNETA_RSS_LU_TABLE_SIZE];
71 @@ -3276,6 +3293,18 @@ static void mvneta_mac_config(struct net
72                 mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, new_an);
73  }
74  
75 +static void mvneta_set_eee(struct mvneta_port *pp, bool enable)
76 +{
77 +       u32 lpi_ctl1;
78 +
79 +       lpi_ctl1 = mvreg_read(pp, MVNETA_LPI_CTRL_1);
80 +       if (enable)
81 +               lpi_ctl1 |= MVNETA_LPI_REQUEST_ENABLE;
82 +       else
83 +               lpi_ctl1 &= ~MVNETA_LPI_REQUEST_ENABLE;
84 +       mvreg_write(pp, MVNETA_LPI_CTRL_1, lpi_ctl1);
85 +}
86 +
87  static void mvneta_mac_link_down(struct net_device *ndev, unsigned int mode)
88  {
89         struct mvneta_port *pp = netdev_priv(ndev);
90 @@ -3289,6 +3318,9 @@ static void mvneta_mac_link_down(struct
91                 val |= MVNETA_GMAC_FORCE_LINK_DOWN;
92                 mvreg_write(pp, MVNETA_GMAC_AUTONEG_CONFIG, val);
93         }
94 +
95 +       pp->eee_active = false;
96 +       mvneta_set_eee(pp, false);
97  }
98  
99  static void mvneta_mac_link_up(struct net_device *ndev, unsigned int mode,
100 @@ -3305,6 +3337,11 @@ static void mvneta_mac_link_up(struct ne
101         }
102  
103         mvneta_port_up(pp);
104 +
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);
108 +       }
109  }
110  
111  static const struct phylink_mac_ops mvneta_phylink_ops = {
112 @@ -3744,6 +3781,13 @@ static void mvneta_ethtool_update_stats(
113                         val64 = (u64)high << 32 | low;
114                         pp->ethtool_stats[i] += val64;
115                         break;
116 +               case T_SW:
117 +                       switch (s->offset) {
118 +                       case ETHTOOL_STAT_EEE_WAKEUP:
119 +                               val = phylink_get_eee_err(pp->phylink);
120 +                               break;
121 +                       }
122 +                       break;
123                 }
124         }
125  }
126 @@ -3867,6 +3911,47 @@ static int mvneta_ethtool_get_rxfh(struc
127         return 0;
128  }
129  
130 +static int mvneta_ethtool_get_eee(struct net_device *dev,
131 +                                 struct ethtool_eee *eee)
132 +{
133 +       struct mvneta_port *pp = netdev_priv(dev);
134 +       u32 lpi_ctl0;
135 +
136 +       lpi_ctl0 = mvreg_read(pp, MVNETA_LPI_CTRL_0);
137 +
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;
142 +
143 +       return phylink_ethtool_get_eee(pp->phylink, eee);
144 +}
145 +
146 +static int mvneta_ethtool_set_eee(struct net_device *dev,
147 +                                 struct ethtool_eee *eee)
148 +{
149 +       struct mvneta_port *pp = netdev_priv(dev);
150 +       u32 lpi_ctl0;
151 +
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))
156 +               return -EINVAL;
157 +
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);
162 +
163 +       pp->eee_enabled = eee->eee_enabled;
164 +       pp->tx_lpi_enabled = eee->tx_lpi_enabled;
165 +
166 +       mvneta_set_eee(pp, eee->tx_lpi_enabled && eee->eee_enabled);
167 +
168 +       return phylink_ethtool_set_eee(pp->phylink, eee);
169 +}
170 +
171  static const struct net_device_ops mvneta_netdev_ops = {
172         .ndo_open            = mvneta_open,
173         .ndo_stop            = mvneta_stop,
174 @@ -3898,6 +3983,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,
180  };
181  
182  /* Initialize hw */