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