GNU Linux-libre 4.19.295-gnu1
[releases.git] / drivers / staging / mt7621-eth / 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-2016 John Crispin <blogic@openwrt.org>
11  *   Copyright (C) 2009-2016 Felix Fietkau <nbd@openwrt.org>
12  *   Copyright (C) 2013-2016 Michael Lee <igvtee@gmail.com>
13  */
14
15 #include "mtk_eth_soc.h"
16 #include "ethtool.h"
17
18 struct mtk_stat {
19         char name[ETH_GSTRING_LEN];
20         unsigned int idx;
21 };
22
23 #define MTK_HW_STAT(stat) { \
24         .name = #stat, \
25         .idx = offsetof(struct mtk_hw_stats, stat) / sizeof(u64) \
26 }
27
28 static const struct mtk_stat mtk_ethtool_hw_stats[] = {
29         MTK_HW_STAT(tx_bytes),
30         MTK_HW_STAT(tx_packets),
31         MTK_HW_STAT(tx_skip),
32         MTK_HW_STAT(tx_collisions),
33         MTK_HW_STAT(rx_bytes),
34         MTK_HW_STAT(rx_packets),
35         MTK_HW_STAT(rx_overflow),
36         MTK_HW_STAT(rx_fcs_errors),
37         MTK_HW_STAT(rx_short_errors),
38         MTK_HW_STAT(rx_long_errors),
39         MTK_HW_STAT(rx_checksum_errors),
40         MTK_HW_STAT(rx_flow_control_packets),
41 };
42
43 #define MTK_HW_STATS_LEN        ARRAY_SIZE(mtk_ethtool_hw_stats)
44
45 static int mtk_get_link_ksettings(struct net_device *dev,
46                                   struct ethtool_link_ksettings *cmd)
47 {
48         struct mtk_mac *mac = netdev_priv(dev);
49         int err;
50
51         if (!mac->phy_dev)
52                 return -ENODEV;
53
54         if (mac->phy_flags == MTK_PHY_FLAG_ATTACH) {
55                 err = phy_read_status(mac->phy_dev);
56                 if (err)
57                         return -ENODEV;
58         }
59
60         phy_ethtool_ksettings_get(mac->phy_dev, cmd);
61         return 0;
62 }
63
64 static int mtk_set_link_ksettings(struct net_device *dev,
65                                   const struct ethtool_link_ksettings *cmd)
66 {
67         struct mtk_mac *mac = netdev_priv(dev);
68
69         if (!mac->phy_dev)
70                 return -ENODEV;
71
72         if (cmd->base.phy_address != mac->phy_dev->mdio.addr) {
73                 if (mac->hw->phy->phy_node[cmd->base.phy_address]) {
74                         mac->phy_dev = mac->hw->phy->phy[cmd->base.phy_address];
75                         mac->phy_flags = MTK_PHY_FLAG_PORT;
76                 } else if (mac->hw->mii_bus) {
77                         mac->phy_dev = mdiobus_get_phy(mac->hw->mii_bus,
78                                                        cmd->base.phy_address);
79                         if (!mac->phy_dev)
80                                 return -ENODEV;
81                         mac->phy_flags = MTK_PHY_FLAG_ATTACH;
82                 } else {
83                         return -ENODEV;
84                 }
85         }
86
87         return phy_ethtool_ksettings_set(mac->phy_dev, cmd);
88 }
89
90 static void mtk_get_drvinfo(struct net_device *dev,
91                             struct ethtool_drvinfo *info)
92 {
93         struct mtk_mac *mac = netdev_priv(dev);
94         struct mtk_soc_data *soc = mac->hw->soc;
95
96         strlcpy(info->driver, mac->hw->dev->driver->name, sizeof(info->driver));
97         strlcpy(info->bus_info, dev_name(mac->hw->dev), sizeof(info->bus_info));
98
99         if (soc->reg_table[MTK_REG_MTK_COUNTER_BASE])
100                 info->n_stats = MTK_HW_STATS_LEN;
101 }
102
103 static u32 mtk_get_msglevel(struct net_device *dev)
104 {
105         struct mtk_mac *mac = netdev_priv(dev);
106
107         return mac->hw->msg_enable;
108 }
109
110 static void mtk_set_msglevel(struct net_device *dev, u32 value)
111 {
112         struct mtk_mac *mac = netdev_priv(dev);
113
114         mac->hw->msg_enable = value;
115 }
116
117 static int mtk_nway_reset(struct net_device *dev)
118 {
119         struct mtk_mac *mac = netdev_priv(dev);
120
121         if (!mac->phy_dev)
122                 return -EOPNOTSUPP;
123
124         return genphy_restart_aneg(mac->phy_dev);
125 }
126
127 static u32 mtk_get_link(struct net_device *dev)
128 {
129         struct mtk_mac *mac = netdev_priv(dev);
130         int err;
131
132         if (!mac->phy_dev)
133                 goto out_get_link;
134
135         if (mac->phy_flags == MTK_PHY_FLAG_ATTACH) {
136                 err = genphy_update_link(mac->phy_dev);
137                 if (err)
138                         goto out_get_link;
139         }
140
141         return mac->phy_dev->link;
142
143 out_get_link:
144         return ethtool_op_get_link(dev);
145 }
146
147 static int mtk_set_ringparam(struct net_device *dev,
148                              struct ethtool_ringparam *ring)
149 {
150         struct mtk_mac *mac = netdev_priv(dev);
151
152         if ((ring->tx_pending < 2) ||
153             (ring->rx_pending < 2) ||
154             (ring->rx_pending > mac->hw->soc->dma_ring_size) ||
155             (ring->tx_pending > mac->hw->soc->dma_ring_size))
156                 return -EINVAL;
157
158         dev->netdev_ops->ndo_stop(dev);
159
160         mac->hw->tx_ring.tx_ring_size = BIT(fls(ring->tx_pending) - 1);
161         mac->hw->rx_ring[0].rx_ring_size = BIT(fls(ring->rx_pending) - 1);
162
163         return dev->netdev_ops->ndo_open(dev);
164 }
165
166 static void mtk_get_ringparam(struct net_device *dev,
167                               struct ethtool_ringparam *ring)
168 {
169         struct mtk_mac *mac = netdev_priv(dev);
170
171         ring->rx_max_pending = mac->hw->soc->dma_ring_size;
172         ring->tx_max_pending = mac->hw->soc->dma_ring_size;
173         ring->rx_pending = mac->hw->rx_ring[0].rx_ring_size;
174         ring->tx_pending = mac->hw->tx_ring.tx_ring_size;
175 }
176
177 static void mtk_get_strings(struct net_device *dev, u32 stringset, u8 *data)
178 {
179         int i;
180
181         switch (stringset) {
182         case ETH_SS_STATS:
183                 for (i = 0; i < MTK_HW_STATS_LEN; i++) {
184                         memcpy(data, mtk_ethtool_hw_stats[i].name,
185                                ETH_GSTRING_LEN);
186                         data += ETH_GSTRING_LEN;
187                 }
188                 break;
189         }
190 }
191
192 static int mtk_get_sset_count(struct net_device *dev, int sset)
193 {
194         switch (sset) {
195         case ETH_SS_STATS:
196                 return MTK_HW_STATS_LEN;
197         default:
198                 return -EOPNOTSUPP;
199         }
200 }
201
202 static void mtk_get_ethtool_stats(struct net_device *dev,
203                                   struct ethtool_stats *stats, u64 *data)
204 {
205         struct mtk_mac *mac = netdev_priv(dev);
206         struct mtk_hw_stats *hwstats = mac->hw_stats;
207         unsigned int start;
208         int i;
209
210         if (netif_running(dev) && netif_device_present(dev)) {
211                 if (spin_trylock(&hwstats->stats_lock)) {
212                         mtk_stats_update_mac(mac);
213                         spin_unlock(&hwstats->stats_lock);
214                 }
215         }
216
217         do {
218                 start = u64_stats_fetch_begin_irq(&hwstats->syncp);
219                 for (i = 0; i < MTK_HW_STATS_LEN; i++)
220                         data[i] = ((u64 *)hwstats)[mtk_ethtool_hw_stats[i].idx];
221
222         } while (u64_stats_fetch_retry_irq(&hwstats->syncp, start));
223 }
224
225 static struct ethtool_ops mtk_ethtool_ops = {
226         .get_link_ksettings     = mtk_get_link_ksettings,
227         .set_link_ksettings     = mtk_set_link_ksettings,
228         .get_drvinfo            = mtk_get_drvinfo,
229         .get_msglevel           = mtk_get_msglevel,
230         .set_msglevel           = mtk_set_msglevel,
231         .nway_reset             = mtk_nway_reset,
232         .get_link               = mtk_get_link,
233         .set_ringparam          = mtk_set_ringparam,
234         .get_ringparam          = mtk_get_ringparam,
235 };
236
237 void mtk_set_ethtool_ops(struct net_device *netdev)
238 {
239         struct mtk_mac *mac = netdev_priv(netdev);
240         struct mtk_soc_data *soc = mac->hw->soc;
241
242         if (soc->reg_table[MTK_REG_MTK_COUNTER_BASE]) {
243                 mtk_ethtool_ops.get_strings = mtk_get_strings;
244                 mtk_ethtool_ops.get_sset_count = mtk_get_sset_count;
245                 mtk_ethtool_ops.get_ethtool_stats = mtk_get_ethtool_stats;
246         }
247
248         netdev->ethtool_ops = &mtk_ethtool_ops;
249 }