ramips: add v4.9 support
[librecmc/librecmc.git] / target / linux / ramips / files-4.9 / drivers / net / ethernet / mtk / ethtool.c
1 /*   This program is free software; you can redistribute it and/or modify
2  *   it under the terms of the GNU General Public License as published by
3  *   the Free Software Foundation; version 2 of the License
4  *
5  *   This program is distributed in the hope that it will be useful,
6  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
7  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
8  *   GNU General Public License for more details.
9  *
10  *   Copyright (C) 2009-2015 John Crispin <blogic@openwrt.org>
11  *   Copyright (C) 2009-2015 Felix Fietkau <nbd@nbd.name>
12  *   Copyright (C) 2013-2015 Michael Lee <igvtee@gmail.com>
13  */
14
15 #include "mtk_eth_soc.h"
16
17 static const char fe_gdma_str[][ETH_GSTRING_LEN] = {
18 #define _FE(x...)       # x,
19 FE_STAT_REG_DECLARE
20 #undef _FE
21 };
22
23 static int fe_get_settings(struct net_device *dev,
24                            struct ethtool_cmd *cmd)
25 {
26         struct fe_priv *priv = netdev_priv(dev);
27         int err;
28
29         if (!priv->phy_dev)
30                 goto out_gset;
31
32         if (priv->phy_flags == FE_PHY_FLAG_ATTACH) {
33                 err = phy_read_status(priv->phy_dev);
34                 if (err)
35                         goto out_gset;
36         }
37
38         return phy_ethtool_gset(priv->phy_dev, cmd);
39
40 out_gset:
41         return -ENODEV;
42 }
43
44 static int fe_set_settings(struct net_device *dev,
45                            struct ethtool_cmd *cmd)
46 {
47         struct fe_priv *priv = netdev_priv(dev);
48
49         if (!priv->phy_dev)
50                 goto out_sset;
51
52         if (cmd->phy_address != priv->phy_dev->mdio.addr) {
53                 if (priv->phy->phy_node[cmd->phy_address]) {
54                         priv->phy_dev = priv->phy->phy[cmd->phy_address];
55                         priv->phy_flags = FE_PHY_FLAG_PORT;
56                 } else if (priv->mii_bus && mdiobus_get_phy(priv->mii_bus, cmd->phy_address)) {
57                         priv->phy_dev = mdiobus_get_phy(priv->mii_bus, cmd->phy_address);
58                         priv->phy_flags = FE_PHY_FLAG_ATTACH;
59                 } else {
60                         goto out_sset;
61                 }
62         }
63
64         return phy_ethtool_sset(priv->phy_dev, cmd);
65
66 out_sset:
67         return -ENODEV;
68 }
69
70 static void fe_get_drvinfo(struct net_device *dev,
71                            struct ethtool_drvinfo *info)
72 {
73         struct fe_priv *priv = netdev_priv(dev);
74         struct fe_soc_data *soc = priv->soc;
75
76         strlcpy(info->driver, priv->device->driver->name, sizeof(info->driver));
77         strlcpy(info->version, MTK_FE_DRV_VERSION, sizeof(info->version));
78         strlcpy(info->bus_info, dev_name(priv->device), sizeof(info->bus_info));
79
80         if (soc->reg_table[FE_REG_FE_COUNTER_BASE])
81                 info->n_stats = ARRAY_SIZE(fe_gdma_str);
82 }
83
84 static u32 fe_get_msglevel(struct net_device *dev)
85 {
86         struct fe_priv *priv = netdev_priv(dev);
87
88         return priv->msg_enable;
89 }
90
91 static void fe_set_msglevel(struct net_device *dev, u32 value)
92 {
93         struct fe_priv *priv = netdev_priv(dev);
94
95         priv->msg_enable = value;
96 }
97
98 static int fe_nway_reset(struct net_device *dev)
99 {
100         struct fe_priv *priv = netdev_priv(dev);
101
102         if (!priv->phy_dev)
103                 goto out_nway_reset;
104
105         return genphy_restart_aneg(priv->phy_dev);
106
107 out_nway_reset:
108         return -EOPNOTSUPP;
109 }
110
111 static u32 fe_get_link(struct net_device *dev)
112 {
113         struct fe_priv *priv = netdev_priv(dev);
114         int err;
115
116         if (!priv->phy_dev)
117                 goto out_get_link;
118
119         if (priv->phy_flags == FE_PHY_FLAG_ATTACH) {
120                 err = genphy_update_link(priv->phy_dev);
121                 if (err)
122                         goto out_get_link;
123         }
124
125         return priv->phy_dev->link;
126
127 out_get_link:
128         return ethtool_op_get_link(dev);
129 }
130
131 static int fe_set_ringparam(struct net_device *dev,
132                             struct ethtool_ringparam *ring)
133 {
134         struct fe_priv *priv = netdev_priv(dev);
135
136         if ((ring->tx_pending < 2) ||
137             (ring->rx_pending < 2) ||
138             (ring->rx_pending > MAX_DMA_DESC) ||
139             (ring->tx_pending > MAX_DMA_DESC))
140                 return -EINVAL;
141
142         dev->netdev_ops->ndo_stop(dev);
143
144         priv->tx_ring.tx_ring_size = BIT(fls(ring->tx_pending) - 1);
145         priv->rx_ring.rx_ring_size = BIT(fls(ring->rx_pending) - 1);
146
147         dev->netdev_ops->ndo_open(dev);
148
149         return 0;
150 }
151
152 static void fe_get_ringparam(struct net_device *dev,
153                              struct ethtool_ringparam *ring)
154 {
155         struct fe_priv *priv = netdev_priv(dev);
156
157         ring->rx_max_pending = MAX_DMA_DESC;
158         ring->tx_max_pending = MAX_DMA_DESC;
159         ring->rx_pending = priv->rx_ring.rx_ring_size;
160         ring->tx_pending = priv->tx_ring.tx_ring_size;
161 }
162
163 static void fe_get_strings(struct net_device *dev, u32 stringset, u8 *data)
164 {
165         switch (stringset) {
166         case ETH_SS_STATS:
167                 memcpy(data, *fe_gdma_str, sizeof(fe_gdma_str));
168                 break;
169         }
170 }
171
172 static int fe_get_sset_count(struct net_device *dev, int sset)
173 {
174         switch (sset) {
175         case ETH_SS_STATS:
176                 return ARRAY_SIZE(fe_gdma_str);
177         default:
178                 return -EOPNOTSUPP;
179         }
180 }
181
182 static void fe_get_ethtool_stats(struct net_device *dev,
183                                  struct ethtool_stats *stats, u64 *data)
184 {
185         struct fe_priv *priv = netdev_priv(dev);
186         struct fe_hw_stats *hwstats = priv->hw_stats;
187         u64 *data_src, *data_dst;
188         unsigned int start;
189         int i;
190
191         if (netif_running(dev) && netif_device_present(dev)) {
192                 if (spin_trylock(&hwstats->stats_lock)) {
193                         fe_stats_update(priv);
194                         spin_unlock(&hwstats->stats_lock);
195                 }
196         }
197
198         do {
199                 data_src = &hwstats->tx_bytes;
200                 data_dst = data;
201                 start = u64_stats_fetch_begin_irq(&hwstats->syncp);
202
203                 for (i = 0; i < ARRAY_SIZE(fe_gdma_str); i++)
204                         *data_dst++ = *data_src++;
205
206         } while (u64_stats_fetch_retry_irq(&hwstats->syncp, start));
207 }
208
209 static struct ethtool_ops fe_ethtool_ops = {
210         .get_settings           = fe_get_settings,
211         .set_settings           = fe_set_settings,
212         .get_drvinfo            = fe_get_drvinfo,
213         .get_msglevel           = fe_get_msglevel,
214         .set_msglevel           = fe_set_msglevel,
215         .nway_reset             = fe_nway_reset,
216         .get_link               = fe_get_link,
217         .set_ringparam          = fe_set_ringparam,
218         .get_ringparam          = fe_get_ringparam,
219 };
220
221 void fe_set_ethtool_ops(struct net_device *netdev)
222 {
223         struct fe_priv *priv = netdev_priv(netdev);
224         struct fe_soc_data *soc = priv->soc;
225
226         if (soc->reg_table[FE_REG_FE_COUNTER_BASE]) {
227                 fe_ethtool_ops.get_strings = fe_get_strings;
228                 fe_ethtool_ops.get_sset_count = fe_get_sset_count;
229                 fe_ethtool_ops.get_ethtool_stats = fe_get_ethtool_stats;
230         }
231
232         netdev->ethtool_ops = &fe_ethtool_ops;
233 }