blob: 7234dbfb73fcc524a34677a52d142f2729e0cdc0 [file] [log] [blame]
Rakesh Nair9bcf2602017-01-06 16:02:16 +05301/*
2 * Copyright (c) 2015 - 2017, The Linux Foundation. All rights reserved.
3 *
4 * Permission to use, copy, modify, and/or distribute this software for
5 * any purpose with or without fee is hereby granted, provided that the
6 * above copyright notice and this permission notice appear in all copies.
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
13 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
14 */
15
16#include <linux/ethtool.h>
17#include <linux/netdevice.h>
18#include <linux/string.h>
19#include "edma.h"
20
21struct edma_ethtool_stats {
22 uint8_t stat_string[ETH_GSTRING_LEN];
23 uint32_t stat_offset;
24};
25
26#define EDMA_STAT(m) offsetof(struct edma_ethtool_statistics, m)
27#define DRVINFO_LEN 32
28
29/* Array of strings describing statistics */
30static const struct edma_ethtool_stats edma_gstrings_stats[] = {
31 {"tx_q0_pkt", EDMA_STAT(tx_q0_pkt)},
32 {"tx_q1_pkt", EDMA_STAT(tx_q1_pkt)},
33 {"tx_q2_pkt", EDMA_STAT(tx_q2_pkt)},
34 {"tx_q3_pkt", EDMA_STAT(tx_q3_pkt)},
35 {"tx_q4_pkt", EDMA_STAT(tx_q4_pkt)},
36 {"tx_q5_pkt", EDMA_STAT(tx_q5_pkt)},
37 {"tx_q6_pkt", EDMA_STAT(tx_q6_pkt)},
38 {"tx_q7_pkt", EDMA_STAT(tx_q7_pkt)},
39 {"tx_q8_pkt", EDMA_STAT(tx_q8_pkt)},
40 {"tx_q9_pkt", EDMA_STAT(tx_q9_pkt)},
41 {"tx_q10_pkt", EDMA_STAT(tx_q10_pkt)},
42 {"tx_q11_pkt", EDMA_STAT(tx_q11_pkt)},
43 {"tx_q12_pkt", EDMA_STAT(tx_q12_pkt)},
44 {"tx_q13_pkt", EDMA_STAT(tx_q13_pkt)},
45 {"tx_q14_pkt", EDMA_STAT(tx_q14_pkt)},
46 {"tx_q15_pkt", EDMA_STAT(tx_q15_pkt)},
47 {"tx_q0_byte", EDMA_STAT(tx_q0_byte)},
48 {"tx_q1_byte", EDMA_STAT(tx_q1_byte)},
49 {"tx_q2_byte", EDMA_STAT(tx_q2_byte)},
50 {"tx_q3_byte", EDMA_STAT(tx_q3_byte)},
51 {"tx_q4_byte", EDMA_STAT(tx_q4_byte)},
52 {"tx_q5_byte", EDMA_STAT(tx_q5_byte)},
53 {"tx_q6_byte", EDMA_STAT(tx_q6_byte)},
54 {"tx_q7_byte", EDMA_STAT(tx_q7_byte)},
55 {"tx_q8_byte", EDMA_STAT(tx_q8_byte)},
56 {"tx_q9_byte", EDMA_STAT(tx_q9_byte)},
57 {"tx_q10_byte", EDMA_STAT(tx_q10_byte)},
58 {"tx_q11_byte", EDMA_STAT(tx_q11_byte)},
59 {"tx_q12_byte", EDMA_STAT(tx_q12_byte)},
60 {"tx_q13_byte", EDMA_STAT(tx_q13_byte)},
61 {"tx_q14_byte", EDMA_STAT(tx_q14_byte)},
62 {"tx_q15_byte", EDMA_STAT(tx_q15_byte)},
63 {"rx_q0_pkt", EDMA_STAT(rx_q0_pkt)},
64 {"rx_q1_pkt", EDMA_STAT(rx_q1_pkt)},
65 {"rx_q2_pkt", EDMA_STAT(rx_q2_pkt)},
66 {"rx_q3_pkt", EDMA_STAT(rx_q3_pkt)},
67 {"rx_q4_pkt", EDMA_STAT(rx_q4_pkt)},
68 {"rx_q5_pkt", EDMA_STAT(rx_q5_pkt)},
69 {"rx_q6_pkt", EDMA_STAT(rx_q6_pkt)},
70 {"rx_q7_pkt", EDMA_STAT(rx_q7_pkt)},
71 {"rx_q0_byte", EDMA_STAT(rx_q0_byte)},
72 {"rx_q1_byte", EDMA_STAT(rx_q1_byte)},
73 {"rx_q2_byte", EDMA_STAT(rx_q2_byte)},
74 {"rx_q3_byte", EDMA_STAT(rx_q3_byte)},
75 {"rx_q4_byte", EDMA_STAT(rx_q4_byte)},
76 {"rx_q5_byte", EDMA_STAT(rx_q5_byte)},
77 {"rx_q6_byte", EDMA_STAT(rx_q6_byte)},
78 {"rx_q7_byte", EDMA_STAT(rx_q7_byte)},
79 {"tx_desc_error", EDMA_STAT(tx_desc_error)},
80};
81
82#define EDMA_STATS_LEN ARRAY_SIZE(edma_gstrings_stats)
83
84/* edma_get_strset_count()
85 * Get strset count
86 */
87static int edma_get_strset_count(struct net_device *netdev,
88 int sset)
89{
90 switch (sset) {
91 case ETH_SS_STATS:
92 return EDMA_STATS_LEN;
93 default:
94 netdev_dbg(netdev, "%s: Invalid string set", __func__);
95 return -EOPNOTSUPP;
96 }
97}
98
99
100/* edma_get_strings()
101 * get stats string
102 */
103static void edma_get_strings(struct net_device *netdev, uint32_t stringset,
104 uint8_t *data)
105{
106 uint8_t *p = data;
107 uint32_t i;
108
109 switch (stringset) {
110 case ETH_SS_STATS:
111 for (i = 0; i < EDMA_STATS_LEN; i++) {
112 memcpy(p, edma_gstrings_stats[i].stat_string,
113 min((size_t)ETH_GSTRING_LEN,
114 strlen(edma_gstrings_stats[i].stat_string)
115 + 1));
116 p += ETH_GSTRING_LEN;
117 }
118 break;
119 }
120}
121
122/* edma_get_ethtool_stats()
123 * Get ethtool statistics
124 */
125static void edma_get_ethtool_stats(struct net_device *netdev,
126 struct ethtool_stats *stats, uint64_t *data)
127{
128 struct edma_adapter *adapter = netdev_priv(netdev);
129 struct edma_common_info *edma_cinfo = adapter->edma_cinfo;
130 int i;
131 uint8_t *p = NULL;
132
133 edma_read_append_stats(edma_cinfo);
134
135 for (i = 0; i < EDMA_STATS_LEN; i++) {
136 p = (uint8_t *)&(edma_cinfo->edma_ethstats) +
137 edma_gstrings_stats[i].stat_offset;
Bhaskar Valabojue429bab2017-03-15 09:01:23 +0530138 data[i] = *(uint64_t *)p;
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530139 }
140}
141
142/* edma_get_drvinfo()
143 * get edma driver info
144 */
145static void edma_get_drvinfo(struct net_device *dev,
146 struct ethtool_drvinfo *info)
147{
148 strlcpy(info->driver, "ess_edma", DRVINFO_LEN);
149 strlcpy(info->bus_info, "axi", ETHTOOL_BUSINFO_LEN);
150}
151
152/* edma_nway_reset()
153 * Reset the phy, if available.
154 */
155static int edma_nway_reset(struct net_device *netdev)
156{
157 return -EINVAL;
158}
159
160/* edma_get_wol()
161 * get wake on lan info
162 */
163static void edma_get_wol(struct net_device *netdev,
164 struct ethtool_wolinfo *wol)
165{
166 wol->supported = 0;
167 wol->wolopts = 0;
168}
169
170/* edma_get_msglevel()
171 * get message level.
172 */
173static uint32_t edma_get_msglevel(struct net_device *netdev)
174{
175 return 0;
176}
177
178/* edma_get_settings()
179 * Get edma settings
180 */
181static int edma_get_settings(struct net_device *netdev,
182 struct ethtool_cmd *ecmd)
183{
184 struct edma_adapter *adapter = netdev_priv(netdev);
185
Rakesh Naired29f6b2017-04-04 15:48:08 +0530186 mutex_lock(&adapter->poll_mutex);
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530187 if (!(adapter->poll_required)) {
188 /* If the speed/duplex for this GMAC is forced and we
189 * are not polling for link state changes, return the
190 * values as specified by platform. This will be true
191 * for GMACs connected to switch, and interfaces that
192 * do not use a PHY.
193 */
194 if (adapter->forced_speed != SPEED_UNKNOWN) {
195 /* set speed and duplex */
196 ethtool_cmd_speed_set(ecmd, SPEED_1000);
197 ecmd->duplex = DUPLEX_FULL;
198
199 /* Populate capabilities advertised by self */
200 ecmd->advertising = 0;
201 ecmd->autoneg = 0;
202 ecmd->port = PORT_TP;
203 ecmd->transceiver = XCVR_EXTERNAL;
204 } else {
205 /* non link polled and non
206 * forced speed/duplex interface
207 */
Rakesh Naired29f6b2017-04-04 15:48:08 +0530208 mutex_unlock(&adapter->poll_mutex);
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530209 return -EIO;
210 }
211 } else {
212 struct phy_device *phydev = NULL;
213 uint16_t phyreg;
214
215 if ((adapter->forced_speed != SPEED_UNKNOWN)
Rakesh Naired29f6b2017-04-04 15:48:08 +0530216 && !(adapter->poll_required)) {
217 mutex_unlock(&adapter->poll_mutex);
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530218 return -EPERM;
Rakesh Naired29f6b2017-04-04 15:48:08 +0530219 }
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530220
221 phydev = adapter->phydev;
222
223 ecmd->advertising = phydev->advertising;
224 ecmd->autoneg = phydev->autoneg;
225
226 if (adapter->link_state == __EDMA_LINKDOWN) {
227 ecmd->speed = SPEED_UNKNOWN;
228 ecmd->duplex = DUPLEX_UNKNOWN;
229 } else {
230 ecmd->speed = phydev->speed;
231 ecmd->duplex = phydev->duplex;
232 }
233
234 ecmd->phy_address = adapter->phy_mdio_addr;
235
236 phyreg = (uint16_t)phy_read(adapter->phydev, MII_LPA);
237 if (phyreg & LPA_10HALF)
238 ecmd->lp_advertising |= ADVERTISED_10baseT_Half;
239
240 if (phyreg & LPA_10FULL)
241 ecmd->lp_advertising |= ADVERTISED_10baseT_Full;
242
243 if (phyreg & LPA_100HALF)
244 ecmd->lp_advertising |= ADVERTISED_100baseT_Half;
245
246 if (phyreg & LPA_100FULL)
247 ecmd->lp_advertising |= ADVERTISED_100baseT_Full;
248
249 phyreg = (uint16_t)phy_read(adapter->phydev, MII_STAT1000);
250 if (phyreg & LPA_1000HALF)
251 ecmd->lp_advertising |= ADVERTISED_1000baseT_Half;
252
253 if (phyreg & LPA_1000FULL)
254 ecmd->lp_advertising |= ADVERTISED_1000baseT_Full;
255 }
Rakesh Naired29f6b2017-04-04 15:48:08 +0530256 mutex_unlock(&adapter->poll_mutex);
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530257
258 return 0;
259}
260
261/* edma_set_settings()
262 * Set EDMA settings
263 */
264static int edma_set_settings(struct net_device *netdev,
265 struct ethtool_cmd *ecmd)
266{
267 struct edma_adapter *adapter = netdev_priv(netdev);
268 struct phy_device *phydev = NULL;
269
Rakesh Naired29f6b2017-04-04 15:48:08 +0530270 mutex_lock(&adapter->poll_mutex);
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530271 if ((adapter->forced_speed != SPEED_UNKNOWN) &&
Rakesh Naired29f6b2017-04-04 15:48:08 +0530272 !adapter->poll_required) {
273 mutex_unlock(&adapter->poll_mutex);
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530274 return -EPERM;
Rakesh Naired29f6b2017-04-04 15:48:08 +0530275 }
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530276
277 phydev = adapter->phydev;
278 phydev->advertising = ecmd->advertising;
279 phydev->autoneg = ecmd->autoneg;
280 phydev->speed = ethtool_cmd_speed(ecmd);
281 phydev->duplex = ecmd->duplex;
282
283 genphy_config_aneg(phydev);
Rakesh Naired29f6b2017-04-04 15:48:08 +0530284 mutex_unlock(&adapter->poll_mutex);
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530285
286 return 0;
287}
288
289/* edma_get_coalesce
290 * get interrupt mitigation
291 */
292static int edma_get_coalesce(struct net_device *netdev,
293 struct ethtool_coalesce *ec)
294{
295 u32 reg_val;
296
297 edma_get_tx_rx_coalesce(&reg_val);
298
299 /* We read the Interrupt Moderation Timer(IMT) register value,
300 * use lower 16 bit for rx and higher 16 bit for Tx. We do a
301 * left shift by 1, because IMT resolution timer is 2usecs.
302 * Hence the value given by the register is multiplied by 2 to
303 * get the actual time in usecs.
304 */
305 ec->tx_coalesce_usecs = (((reg_val >> 16) & 0xffff) << 1);
306 ec->rx_coalesce_usecs = ((reg_val & 0xffff) << 1);
307
308 return 0;
309}
310
311/* edma_set_coalesce
312 * set interrupt mitigation
313 */
314static int edma_set_coalesce(struct net_device *netdev,
315 struct ethtool_coalesce *ec)
316{
317 if (ec->tx_coalesce_usecs)
318 edma_change_tx_coalesce(ec->tx_coalesce_usecs);
319 if (ec->rx_coalesce_usecs)
320 edma_change_rx_coalesce(ec->rx_coalesce_usecs);
321
322 return 0;
323}
324
325/* edma_set_priv_flags()
326 * Set EDMA private flags
327 */
328static int edma_set_priv_flags(struct net_device *netdev, u32 flags)
329{
330 return 0;
331}
332
333/* edma_get_priv_flags()
334 * get edma driver flags
335 */
336static u32 edma_get_priv_flags(struct net_device *netdev)
337{
338 return 0;
339}
340
341/* edma_get_ringparam()
342 * get ring size
343 */
344static void edma_get_ringparam(struct net_device *netdev,
345 struct ethtool_ringparam *ring)
346{
347 struct edma_adapter *adapter = netdev_priv(netdev);
348 struct edma_common_info *edma_cinfo = adapter->edma_cinfo;
349
350 ring->tx_max_pending = edma_cinfo->tx_ring_count;
351 ring->rx_max_pending = edma_cinfo->rx_ring_count;
352}
353
354/* Ethtool operations
355 */
356static const struct ethtool_ops edma_ethtool_ops = {
357 .get_drvinfo = &edma_get_drvinfo,
358 .get_link = &ethtool_op_get_link,
359 .get_msglevel = &edma_get_msglevel,
360 .nway_reset = &edma_nway_reset,
361 .get_wol = &edma_get_wol,
362 .get_settings = &edma_get_settings,
363 .set_settings = &edma_set_settings,
364 .get_strings = &edma_get_strings,
365 .get_sset_count = &edma_get_strset_count,
366 .get_ethtool_stats = &edma_get_ethtool_stats,
367 .get_coalesce = &edma_get_coalesce,
368 .set_coalesce = &edma_set_coalesce,
369 .get_priv_flags = edma_get_priv_flags,
370 .set_priv_flags = edma_set_priv_flags,
371 .get_ringparam = edma_get_ringparam,
372};
373
374/* edma_set_ethtool_ops
375 * Set ethtool operations
376 */
377void edma_set_ethtool_ops(struct net_device *netdev)
378{
379 netdev->ethtool_ops = &edma_ethtool_ops;
380}