1// SPDX-License-Identifier: GPL-2.0-only
2/* Ethtool support for Altera Triple-Speed Ethernet MAC driver
3 * Copyright (C) 2008-2014 Altera Corporation. All rights reserved
4 *
5 * Contributors:
6 * Dalon Westergreen
7 * Thomas Chou
8 * Ian Abbott
9 * Yuriy Kozlov
10 * Tobias Klauser
11 * Andriy Smolskyy
12 * Roman Bulgakov
13 * Dmytro Mytarchuk
14 *
15 * Original driver contributed by SLS.
16 * Major updates contributed by GlobalLogic
17 */
18
19#include <linux/ethtool.h>
20#include <linux/kernel.h>
21#include <linux/netdevice.h>
22#include <linux/phy.h>
23
24#include "altera_tse.h"
25
26#define TSE_STATS_LEN 31
27#define TSE_NUM_REGS 128
28
29static char const stat_gstrings[][ETH_GSTRING_LEN] = {
30 "tx_packets",
31 "rx_packets",
32 "rx_crc_errors",
33 "rx_align_errors",
34 "tx_bytes",
35 "rx_bytes",
36 "tx_pause",
37 "rx_pause",
38 "rx_errors",
39 "tx_errors",
40 "rx_unicast",
41 "rx_multicast",
42 "rx_broadcast",
43 "tx_discards",
44 "tx_unicast",
45 "tx_multicast",
46 "tx_broadcast",
47 "ether_drops",
48 "rx_total_bytes",
49 "rx_total_packets",
50 "rx_undersize",
51 "rx_oversize",
52 "rx_64_bytes",
53 "rx_65_127_bytes",
54 "rx_128_255_bytes",
55 "rx_256_511_bytes",
56 "rx_512_1023_bytes",
57 "rx_1024_1518_bytes",
58 "rx_gte_1519_bytes",
59 "rx_jabbers",
60 "rx_runts",
61};
62
63static void tse_get_drvinfo(struct net_device *dev,
64 struct ethtool_drvinfo *info)
65{
66 struct altera_tse_private *priv = netdev_priv(dev);
67 u32 rev = ioread32(&priv->mac_dev->megacore_revision);
68
69 strcpy(p: info->driver, q: "altera_tse");
70 snprintf(buf: info->fw_version, ETHTOOL_FWVERS_LEN, fmt: "v%d.%d",
71 rev & 0xFFFF, (rev & 0xFFFF0000) >> 16);
72 sprintf(buf: info->bus_info, fmt: "platform");
73}
74
75/* Fill in a buffer with the strings which correspond to the
76 * stats
77 */
78static void tse_gstrings(struct net_device *dev, u32 stringset, u8 *buf)
79{
80 memcpy(buf, stat_gstrings, TSE_STATS_LEN * ETH_GSTRING_LEN);
81}
82
83static void tse_fill_stats(struct net_device *dev, struct ethtool_stats *dummy,
84 u64 *buf)
85{
86 struct altera_tse_private *priv = netdev_priv(dev);
87 u64 ext;
88
89 buf[0] = csrrd32(mac: priv->mac_dev,
90 tse_csroffs(frames_transmitted_ok));
91 buf[1] = csrrd32(mac: priv->mac_dev,
92 tse_csroffs(frames_received_ok));
93 buf[2] = csrrd32(mac: priv->mac_dev,
94 tse_csroffs(frames_check_sequence_errors));
95 buf[3] = csrrd32(mac: priv->mac_dev,
96 tse_csroffs(alignment_errors));
97
98 /* Extended aOctetsTransmittedOK counter */
99 ext = (u64) csrrd32(mac: priv->mac_dev,
100 tse_csroffs(msb_octets_transmitted_ok)) << 32;
101
102 ext |= csrrd32(mac: priv->mac_dev,
103 tse_csroffs(octets_transmitted_ok));
104 buf[4] = ext;
105
106 /* Extended aOctetsReceivedOK counter */
107 ext = (u64) csrrd32(mac: priv->mac_dev,
108 tse_csroffs(msb_octets_received_ok)) << 32;
109
110 ext |= csrrd32(mac: priv->mac_dev,
111 tse_csroffs(octets_received_ok));
112 buf[5] = ext;
113
114 buf[6] = csrrd32(mac: priv->mac_dev,
115 tse_csroffs(tx_pause_mac_ctrl_frames));
116 buf[7] = csrrd32(mac: priv->mac_dev,
117 tse_csroffs(rx_pause_mac_ctrl_frames));
118 buf[8] = csrrd32(mac: priv->mac_dev,
119 tse_csroffs(if_in_errors));
120 buf[9] = csrrd32(mac: priv->mac_dev,
121 tse_csroffs(if_out_errors));
122 buf[10] = csrrd32(mac: priv->mac_dev,
123 tse_csroffs(if_in_ucast_pkts));
124 buf[11] = csrrd32(mac: priv->mac_dev,
125 tse_csroffs(if_in_multicast_pkts));
126 buf[12] = csrrd32(mac: priv->mac_dev,
127 tse_csroffs(if_in_broadcast_pkts));
128 buf[13] = csrrd32(mac: priv->mac_dev,
129 tse_csroffs(if_out_discards));
130 buf[14] = csrrd32(mac: priv->mac_dev,
131 tse_csroffs(if_out_ucast_pkts));
132 buf[15] = csrrd32(mac: priv->mac_dev,
133 tse_csroffs(if_out_multicast_pkts));
134 buf[16] = csrrd32(mac: priv->mac_dev,
135 tse_csroffs(if_out_broadcast_pkts));
136 buf[17] = csrrd32(mac: priv->mac_dev,
137 tse_csroffs(ether_stats_drop_events));
138
139 /* Extended etherStatsOctets counter */
140 ext = (u64) csrrd32(mac: priv->mac_dev,
141 tse_csroffs(msb_ether_stats_octets)) << 32;
142 ext |= csrrd32(mac: priv->mac_dev,
143 tse_csroffs(ether_stats_octets));
144 buf[18] = ext;
145
146 buf[19] = csrrd32(mac: priv->mac_dev,
147 tse_csroffs(ether_stats_pkts));
148 buf[20] = csrrd32(mac: priv->mac_dev,
149 tse_csroffs(ether_stats_undersize_pkts));
150 buf[21] = csrrd32(mac: priv->mac_dev,
151 tse_csroffs(ether_stats_oversize_pkts));
152 buf[22] = csrrd32(mac: priv->mac_dev,
153 tse_csroffs(ether_stats_pkts_64_octets));
154 buf[23] = csrrd32(mac: priv->mac_dev,
155 tse_csroffs(ether_stats_pkts_65to127_octets));
156 buf[24] = csrrd32(mac: priv->mac_dev,
157 tse_csroffs(ether_stats_pkts_128to255_octets));
158 buf[25] = csrrd32(mac: priv->mac_dev,
159 tse_csroffs(ether_stats_pkts_256to511_octets));
160 buf[26] = csrrd32(mac: priv->mac_dev,
161 tse_csroffs(ether_stats_pkts_512to1023_octets));
162 buf[27] = csrrd32(mac: priv->mac_dev,
163 tse_csroffs(ether_stats_pkts_1024to1518_octets));
164 buf[28] = csrrd32(mac: priv->mac_dev,
165 tse_csroffs(ether_stats_pkts_1519tox_octets));
166 buf[29] = csrrd32(mac: priv->mac_dev,
167 tse_csroffs(ether_stats_jabbers));
168 buf[30] = csrrd32(mac: priv->mac_dev,
169 tse_csroffs(ether_stats_fragments));
170}
171
172static int tse_sset_count(struct net_device *dev, int sset)
173{
174 switch (sset) {
175 case ETH_SS_STATS:
176 return TSE_STATS_LEN;
177 default:
178 return -EOPNOTSUPP;
179 }
180}
181
182static u32 tse_get_msglevel(struct net_device *dev)
183{
184 struct altera_tse_private *priv = netdev_priv(dev);
185 return priv->msg_enable;
186}
187
188static void tse_set_msglevel(struct net_device *dev, uint32_t data)
189{
190 struct altera_tse_private *priv = netdev_priv(dev);
191 priv->msg_enable = data;
192}
193
194static int tse_reglen(struct net_device *dev)
195{
196 return TSE_NUM_REGS * sizeof(u32);
197}
198
199static void tse_get_regs(struct net_device *dev, struct ethtool_regs *regs,
200 void *regbuf)
201{
202 struct altera_tse_private *priv = netdev_priv(dev);
203 u32 *buf = regbuf;
204 int i;
205
206 /* Set version to a known value, so ethtool knows
207 * how to do any special formatting of this data.
208 * This version number will need to change if and
209 * when this register table is changed.
210 *
211 * version[31:0] = 1: Dump the first 128 TSE Registers
212 * Upper bits are all 0 by default
213 *
214 * Upper 16-bits will indicate feature presence for
215 * Ethtool register decoding in future version.
216 */
217
218 regs->version = 1;
219
220 for (i = 0; i < TSE_NUM_REGS; i++)
221 buf[i] = csrrd32(mac: priv->mac_dev, offs: i * 4);
222}
223
224static int tse_ethtool_set_link_ksettings(struct net_device *dev,
225 const struct ethtool_link_ksettings *cmd)
226{
227 struct altera_tse_private *priv = netdev_priv(dev);
228
229 return phylink_ethtool_ksettings_set(priv->phylink, cmd);
230}
231
232static int tse_ethtool_get_link_ksettings(struct net_device *dev,
233 struct ethtool_link_ksettings *cmd)
234{
235 struct altera_tse_private *priv = netdev_priv(dev);
236
237 return phylink_ethtool_ksettings_get(priv->phylink, cmd);
238}
239
240static const struct ethtool_ops tse_ethtool_ops = {
241 .get_drvinfo = tse_get_drvinfo,
242 .get_regs_len = tse_reglen,
243 .get_regs = tse_get_regs,
244 .get_link = ethtool_op_get_link,
245 .get_strings = tse_gstrings,
246 .get_sset_count = tse_sset_count,
247 .get_ethtool_stats = tse_fill_stats,
248 .get_msglevel = tse_get_msglevel,
249 .set_msglevel = tse_set_msglevel,
250 .get_link_ksettings = tse_ethtool_get_link_ksettings,
251 .set_link_ksettings = tse_ethtool_set_link_ksettings,
252 .get_ts_info = ethtool_op_get_ts_info,
253};
254
255void altera_tse_set_ethtool_ops(struct net_device *netdev)
256{
257 netdev->ethtool_ops = &tse_ethtool_ops;
258}
259

source code of linux/drivers/net/ethernet/altera/altera_tse_ethtool.c