blob: f234afdd862bc945983203e088641e70d4f5aad0 [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
Rakesh Nair1c6a18c2017-08-02 21:27:06 +053026extern struct edma_video_delay_stats edma_iad_stats_tx[EDMA_MAX_IAD_FLOW_STATS_SUPPORTED];
27extern struct edma_video_delay_stats edma_iad_stats_rx[EDMA_MAX_IAD_FLOW_STATS_SUPPORTED];
28
Rakesh Nair9bcf2602017-01-06 16:02:16 +053029#define EDMA_STAT(m) offsetof(struct edma_ethtool_statistics, m)
30#define DRVINFO_LEN 32
31
32/* Array of strings describing statistics */
33static const struct edma_ethtool_stats edma_gstrings_stats[] = {
34 {"tx_q0_pkt", EDMA_STAT(tx_q0_pkt)},
35 {"tx_q1_pkt", EDMA_STAT(tx_q1_pkt)},
36 {"tx_q2_pkt", EDMA_STAT(tx_q2_pkt)},
37 {"tx_q3_pkt", EDMA_STAT(tx_q3_pkt)},
38 {"tx_q4_pkt", EDMA_STAT(tx_q4_pkt)},
39 {"tx_q5_pkt", EDMA_STAT(tx_q5_pkt)},
40 {"tx_q6_pkt", EDMA_STAT(tx_q6_pkt)},
41 {"tx_q7_pkt", EDMA_STAT(tx_q7_pkt)},
42 {"tx_q8_pkt", EDMA_STAT(tx_q8_pkt)},
43 {"tx_q9_pkt", EDMA_STAT(tx_q9_pkt)},
44 {"tx_q10_pkt", EDMA_STAT(tx_q10_pkt)},
45 {"tx_q11_pkt", EDMA_STAT(tx_q11_pkt)},
46 {"tx_q12_pkt", EDMA_STAT(tx_q12_pkt)},
47 {"tx_q13_pkt", EDMA_STAT(tx_q13_pkt)},
48 {"tx_q14_pkt", EDMA_STAT(tx_q14_pkt)},
49 {"tx_q15_pkt", EDMA_STAT(tx_q15_pkt)},
50 {"tx_q0_byte", EDMA_STAT(tx_q0_byte)},
51 {"tx_q1_byte", EDMA_STAT(tx_q1_byte)},
52 {"tx_q2_byte", EDMA_STAT(tx_q2_byte)},
53 {"tx_q3_byte", EDMA_STAT(tx_q3_byte)},
54 {"tx_q4_byte", EDMA_STAT(tx_q4_byte)},
55 {"tx_q5_byte", EDMA_STAT(tx_q5_byte)},
56 {"tx_q6_byte", EDMA_STAT(tx_q6_byte)},
57 {"tx_q7_byte", EDMA_STAT(tx_q7_byte)},
58 {"tx_q8_byte", EDMA_STAT(tx_q8_byte)},
59 {"tx_q9_byte", EDMA_STAT(tx_q9_byte)},
60 {"tx_q10_byte", EDMA_STAT(tx_q10_byte)},
61 {"tx_q11_byte", EDMA_STAT(tx_q11_byte)},
62 {"tx_q12_byte", EDMA_STAT(tx_q12_byte)},
63 {"tx_q13_byte", EDMA_STAT(tx_q13_byte)},
64 {"tx_q14_byte", EDMA_STAT(tx_q14_byte)},
65 {"tx_q15_byte", EDMA_STAT(tx_q15_byte)},
66 {"rx_q0_pkt", EDMA_STAT(rx_q0_pkt)},
67 {"rx_q1_pkt", EDMA_STAT(rx_q1_pkt)},
68 {"rx_q2_pkt", EDMA_STAT(rx_q2_pkt)},
69 {"rx_q3_pkt", EDMA_STAT(rx_q3_pkt)},
70 {"rx_q4_pkt", EDMA_STAT(rx_q4_pkt)},
71 {"rx_q5_pkt", EDMA_STAT(rx_q5_pkt)},
72 {"rx_q6_pkt", EDMA_STAT(rx_q6_pkt)},
73 {"rx_q7_pkt", EDMA_STAT(rx_q7_pkt)},
74 {"rx_q0_byte", EDMA_STAT(rx_q0_byte)},
75 {"rx_q1_byte", EDMA_STAT(rx_q1_byte)},
76 {"rx_q2_byte", EDMA_STAT(rx_q2_byte)},
77 {"rx_q3_byte", EDMA_STAT(rx_q3_byte)},
78 {"rx_q4_byte", EDMA_STAT(rx_q4_byte)},
79 {"rx_q5_byte", EDMA_STAT(rx_q5_byte)},
80 {"rx_q6_byte", EDMA_STAT(rx_q6_byte)},
81 {"rx_q7_byte", EDMA_STAT(rx_q7_byte)},
82 {"tx_desc_error", EDMA_STAT(tx_desc_error)},
Rakesh Nair03b586c2017-04-03 18:28:58 +053083 {"rx_alloc_fail_ctr", EDMA_STAT(rx_alloc_fail_ctr)},
Rakesh Nair888af952017-06-30 18:41:58 +053084 {"rx_prec_0", EDMA_STAT(rx_prec[0])},
85 {"rx_prec_1", EDMA_STAT(rx_prec[1])},
86 {"rx_prec_2", EDMA_STAT(rx_prec[2])},
87 {"rx_prec_3", EDMA_STAT(rx_prec[3])},
88 {"rx_prec_4", EDMA_STAT(rx_prec[4])},
89 {"rx_prec_5", EDMA_STAT(rx_prec[5])},
90 {"rx_prec_6", EDMA_STAT(rx_prec[6])},
91 {"rx_prec_7", EDMA_STAT(rx_prec[7])},
92 {"rx_ac_bk", EDMA_STAT(rx_ac[EDMA_AC_BK])},
93 {"rx_ac_be", EDMA_STAT(rx_ac[EDMA_AC_BE])},
94 {"rx_ac_vi", EDMA_STAT(rx_ac[EDMA_AC_VI])},
95 {"rx_ac_vo", EDMA_STAT(rx_ac[EDMA_AC_VO])},
Rakesh Nair1c6a18c2017-08-02 21:27:06 +053096 {"rx_flow1_delta_start_ts", EDMA_STAT(rx_flow_delta_start_ts[0])},
97 {"rx_flow1_max_ifd_usec", EDMA_STAT(rx_flow_iad[0])},
98 {"rx_flow2_delta_start_ts", EDMA_STAT(rx_flow_delta_start_ts[1])},
99 {"rx_flow2_max_ifd_usec", EDMA_STAT(rx_flow_iad[1])},
100 {"rx_flow3_delta_start_ts", EDMA_STAT(rx_flow_delta_start_ts[2])},
101 {"rx_flow3_max_ifd_usec", EDMA_STAT(rx_flow_iad[2])},
102 {"rx_flow4_delta_start_ts", EDMA_STAT(rx_flow_delta_start_ts[3])},
103 {"rx_flow4_max_ifd_usec", EDMA_STAT(rx_flow_iad[3])},
104 {"rx_flow5_delta_start_ts", EDMA_STAT(rx_flow_delta_start_ts[4])},
105 {"rx_flow5_max_ifd_usec", EDMA_STAT(rx_flow_iad[4])},
106 {"rx_flow6_delta_start_ts", EDMA_STAT(rx_flow_delta_start_ts[5])},
107 {"rx_flow6_max_ifd_usec", EDMA_STAT(rx_flow_iad[5])},
108 {"rx_flow7_delta_start_ts", EDMA_STAT(rx_flow_delta_start_ts[6])},
109 {"rx_flow7_max_ifd_usec", EDMA_STAT(rx_flow_iad[6])},
110 {"rx_flow8_delta_start_ts", EDMA_STAT(rx_flow_delta_start_ts[7])},
111 {"rx_flow8_max_ifd_usec", EDMA_STAT(rx_flow_iad[7])},
Rakesh Nair888af952017-06-30 18:41:58 +0530112 {"tx_prec_0", EDMA_STAT(tx_prec[0])},
113 {"tx_prec_1", EDMA_STAT(tx_prec[1])},
114 {"tx_prec_2", EDMA_STAT(tx_prec[2])},
115 {"tx_prec_3", EDMA_STAT(tx_prec[3])},
116 {"tx_prec_4", EDMA_STAT(tx_prec[4])},
117 {"tx_prec_5", EDMA_STAT(tx_prec[5])},
118 {"tx_prec_6", EDMA_STAT(tx_prec[6])},
119 {"tx_prec_7", EDMA_STAT(tx_prec[7])},
120 {"tx_ac_bk", EDMA_STAT(tx_ac[EDMA_AC_BK])},
121 {"tx_ac_be", EDMA_STAT(tx_ac[EDMA_AC_BE])},
122 {"tx_ac_vi", EDMA_STAT(tx_ac[EDMA_AC_VI])},
123 {"tx_ac_vo", EDMA_STAT(tx_ac[EDMA_AC_VO])},
Rakesh Nair1c6a18c2017-08-02 21:27:06 +0530124 {"tx_flow1_delta_start_ts", EDMA_STAT(tx_flow_delta_start_ts[0])},
125 {"tx_flow1_max_ifd_usec", EDMA_STAT(tx_flow_iad[0])},
126 {"tx_flow2_delta_start_ts", EDMA_STAT(tx_flow_delta_start_ts[1])},
127 {"tx_flow2_max_ifd_usec", EDMA_STAT(tx_flow_iad[1])},
128 {"tx_flow3_delta_start_ts", EDMA_STAT(tx_flow_delta_start_ts[2])},
129 {"tx_flow3_max_ifd_usec", EDMA_STAT(tx_flow_iad[2])},
130 {"tx_flow4_delta_start_ts", EDMA_STAT(tx_flow_delta_start_ts[3])},
131 {"tx_flow4_max_ifd_usec", EDMA_STAT(tx_flow_iad[3])},
132 {"tx_flow5_delta_start_ts", EDMA_STAT(tx_flow_delta_start_ts[4])},
133 {"tx_flow5_max_ifd_usec", EDMA_STAT(tx_flow_iad[4])},
134 {"tx_flow6_delta_start_ts", EDMA_STAT(tx_flow_delta_start_ts[5])},
135 {"tx_flow6_max_ifd_usec", EDMA_STAT(tx_flow_iad[5])},
136 {"tx_flow7_delta_start_ts", EDMA_STAT(tx_flow_delta_start_ts[6])},
137 {"tx_flow7_max_ifd_usec", EDMA_STAT(tx_flow_iad[6])},
138 {"tx_flow8_delta_start_ts", EDMA_STAT(tx_flow_delta_start_ts[7])},
139 {"tx_flow8_max_ifd_usec", EDMA_STAT(tx_flow_iad[7])},
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530140};
141
142#define EDMA_STATS_LEN ARRAY_SIZE(edma_gstrings_stats)
143
144/* edma_get_strset_count()
145 * Get strset count
146 */
147static int edma_get_strset_count(struct net_device *netdev,
148 int sset)
149{
150 switch (sset) {
151 case ETH_SS_STATS:
152 return EDMA_STATS_LEN;
153 default:
154 netdev_dbg(netdev, "%s: Invalid string set", __func__);
155 return -EOPNOTSUPP;
156 }
157}
158
159
160/* edma_get_strings()
161 * get stats string
162 */
163static void edma_get_strings(struct net_device *netdev, uint32_t stringset,
164 uint8_t *data)
165{
166 uint8_t *p = data;
167 uint32_t i;
168
169 switch (stringset) {
170 case ETH_SS_STATS:
171 for (i = 0; i < EDMA_STATS_LEN; i++) {
172 memcpy(p, edma_gstrings_stats[i].stat_string,
173 min((size_t)ETH_GSTRING_LEN,
174 strlen(edma_gstrings_stats[i].stat_string)
175 + 1));
176 p += ETH_GSTRING_LEN;
177 }
178 break;
179 }
180}
181
182/* edma_get_ethtool_stats()
183 * Get ethtool statistics
184 */
185static void edma_get_ethtool_stats(struct net_device *netdev,
186 struct ethtool_stats *stats, uint64_t *data)
187{
188 struct edma_adapter *adapter = netdev_priv(netdev);
189 struct edma_common_info *edma_cinfo = adapter->edma_cinfo;
190 int i;
191 uint8_t *p = NULL;
192
193 edma_read_append_stats(edma_cinfo);
194
195 for (i = 0; i < EDMA_STATS_LEN; i++) {
196 p = (uint8_t *)&(edma_cinfo->edma_ethstats) +
197 edma_gstrings_stats[i].stat_offset;
Bhaskar Valabojue429bab2017-03-15 09:01:23 +0530198 data[i] = *(uint64_t *)p;
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530199 }
200}
201
202/* edma_get_drvinfo()
203 * get edma driver info
204 */
205static void edma_get_drvinfo(struct net_device *dev,
206 struct ethtool_drvinfo *info)
207{
208 strlcpy(info->driver, "ess_edma", DRVINFO_LEN);
209 strlcpy(info->bus_info, "axi", ETHTOOL_BUSINFO_LEN);
210}
211
212/* edma_nway_reset()
213 * Reset the phy, if available.
214 */
215static int edma_nway_reset(struct net_device *netdev)
216{
217 return -EINVAL;
218}
219
220/* edma_get_wol()
221 * get wake on lan info
222 */
223static void edma_get_wol(struct net_device *netdev,
224 struct ethtool_wolinfo *wol)
225{
226 wol->supported = 0;
227 wol->wolopts = 0;
228}
229
230/* edma_get_msglevel()
231 * get message level.
232 */
233static uint32_t edma_get_msglevel(struct net_device *netdev)
234{
235 return 0;
236}
237
238/* edma_get_settings()
239 * Get edma settings
240 */
241static int edma_get_settings(struct net_device *netdev,
242 struct ethtool_cmd *ecmd)
243{
244 struct edma_adapter *adapter = netdev_priv(netdev);
245
Rakesh Naired29f6b2017-04-04 15:48:08 +0530246 mutex_lock(&adapter->poll_mutex);
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530247 if (!(adapter->poll_required)) {
248 /* If the speed/duplex for this GMAC is forced and we
249 * are not polling for link state changes, return the
250 * values as specified by platform. This will be true
251 * for GMACs connected to switch, and interfaces that
252 * do not use a PHY.
253 */
254 if (adapter->forced_speed != SPEED_UNKNOWN) {
255 /* set speed and duplex */
256 ethtool_cmd_speed_set(ecmd, SPEED_1000);
257 ecmd->duplex = DUPLEX_FULL;
258
259 /* Populate capabilities advertised by self */
260 ecmd->advertising = 0;
261 ecmd->autoneg = 0;
262 ecmd->port = PORT_TP;
263 ecmd->transceiver = XCVR_EXTERNAL;
264 } else {
265 /* non link polled and non
266 * forced speed/duplex interface
267 */
Rakesh Naired29f6b2017-04-04 15:48:08 +0530268 mutex_unlock(&adapter->poll_mutex);
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530269 return -EIO;
270 }
271 } else {
272 struct phy_device *phydev = NULL;
273 uint16_t phyreg;
274
275 if ((adapter->forced_speed != SPEED_UNKNOWN)
Rakesh Naired29f6b2017-04-04 15:48:08 +0530276 && !(adapter->poll_required)) {
277 mutex_unlock(&adapter->poll_mutex);
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530278 return -EPERM;
Rakesh Naired29f6b2017-04-04 15:48:08 +0530279 }
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530280
281 phydev = adapter->phydev;
282
283 ecmd->advertising = phydev->advertising;
284 ecmd->autoneg = phydev->autoneg;
285
286 if (adapter->link_state == __EDMA_LINKDOWN) {
287 ecmd->speed = SPEED_UNKNOWN;
288 ecmd->duplex = DUPLEX_UNKNOWN;
289 } else {
290 ecmd->speed = phydev->speed;
291 ecmd->duplex = phydev->duplex;
292 }
293
294 ecmd->phy_address = adapter->phy_mdio_addr;
295
296 phyreg = (uint16_t)phy_read(adapter->phydev, MII_LPA);
297 if (phyreg & LPA_10HALF)
298 ecmd->lp_advertising |= ADVERTISED_10baseT_Half;
299
300 if (phyreg & LPA_10FULL)
301 ecmd->lp_advertising |= ADVERTISED_10baseT_Full;
302
303 if (phyreg & LPA_100HALF)
304 ecmd->lp_advertising |= ADVERTISED_100baseT_Half;
305
306 if (phyreg & LPA_100FULL)
307 ecmd->lp_advertising |= ADVERTISED_100baseT_Full;
308
309 phyreg = (uint16_t)phy_read(adapter->phydev, MII_STAT1000);
310 if (phyreg & LPA_1000HALF)
311 ecmd->lp_advertising |= ADVERTISED_1000baseT_Half;
312
313 if (phyreg & LPA_1000FULL)
314 ecmd->lp_advertising |= ADVERTISED_1000baseT_Full;
315 }
Rakesh Naired29f6b2017-04-04 15:48:08 +0530316 mutex_unlock(&adapter->poll_mutex);
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530317
318 return 0;
319}
320
321/* edma_set_settings()
322 * Set EDMA settings
323 */
324static int edma_set_settings(struct net_device *netdev,
325 struct ethtool_cmd *ecmd)
326{
327 struct edma_adapter *adapter = netdev_priv(netdev);
328 struct phy_device *phydev = NULL;
329
Rakesh Naired29f6b2017-04-04 15:48:08 +0530330 mutex_lock(&adapter->poll_mutex);
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530331 if ((adapter->forced_speed != SPEED_UNKNOWN) &&
Rakesh Naired29f6b2017-04-04 15:48:08 +0530332 !adapter->poll_required) {
333 mutex_unlock(&adapter->poll_mutex);
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530334 return -EPERM;
Rakesh Naired29f6b2017-04-04 15:48:08 +0530335 }
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530336
337 phydev = adapter->phydev;
338 phydev->advertising = ecmd->advertising;
339 phydev->autoneg = ecmd->autoneg;
340 phydev->speed = ethtool_cmd_speed(ecmd);
341 phydev->duplex = ecmd->duplex;
342
343 genphy_config_aneg(phydev);
Rakesh Naired29f6b2017-04-04 15:48:08 +0530344 mutex_unlock(&adapter->poll_mutex);
Rakesh Nair9bcf2602017-01-06 16:02:16 +0530345
346 return 0;
347}
348
349/* edma_get_coalesce
350 * get interrupt mitigation
351 */
352static int edma_get_coalesce(struct net_device *netdev,
353 struct ethtool_coalesce *ec)
354{
355 u32 reg_val;
356
357 edma_get_tx_rx_coalesce(&reg_val);
358
359 /* We read the Interrupt Moderation Timer(IMT) register value,
360 * use lower 16 bit for rx and higher 16 bit for Tx. We do a
361 * left shift by 1, because IMT resolution timer is 2usecs.
362 * Hence the value given by the register is multiplied by 2 to
363 * get the actual time in usecs.
364 */
365 ec->tx_coalesce_usecs = (((reg_val >> 16) & 0xffff) << 1);
366 ec->rx_coalesce_usecs = ((reg_val & 0xffff) << 1);
367
368 return 0;
369}
370
371/* edma_set_coalesce
372 * set interrupt mitigation
373 */
374static int edma_set_coalesce(struct net_device *netdev,
375 struct ethtool_coalesce *ec)
376{
377 if (ec->tx_coalesce_usecs)
378 edma_change_tx_coalesce(ec->tx_coalesce_usecs);
379 if (ec->rx_coalesce_usecs)
380 edma_change_rx_coalesce(ec->rx_coalesce_usecs);
381
382 return 0;
383}
384
385/* edma_set_priv_flags()
386 * Set EDMA private flags
387 */
388static int edma_set_priv_flags(struct net_device *netdev, u32 flags)
389{
390 return 0;
391}
392
393/* edma_get_priv_flags()
394 * get edma driver flags
395 */
396static u32 edma_get_priv_flags(struct net_device *netdev)
397{
398 return 0;
399}
400
401/* edma_get_ringparam()
402 * get ring size
403 */
404static void edma_get_ringparam(struct net_device *netdev,
405 struct ethtool_ringparam *ring)
406{
407 struct edma_adapter *adapter = netdev_priv(netdev);
408 struct edma_common_info *edma_cinfo = adapter->edma_cinfo;
409
410 ring->tx_max_pending = edma_cinfo->tx_ring_count;
411 ring->rx_max_pending = edma_cinfo->rx_ring_count;
412}
413
414/* Ethtool operations
415 */
416static const struct ethtool_ops edma_ethtool_ops = {
417 .get_drvinfo = &edma_get_drvinfo,
418 .get_link = &ethtool_op_get_link,
419 .get_msglevel = &edma_get_msglevel,
420 .nway_reset = &edma_nway_reset,
421 .get_wol = &edma_get_wol,
422 .get_settings = &edma_get_settings,
423 .set_settings = &edma_set_settings,
424 .get_strings = &edma_get_strings,
425 .get_sset_count = &edma_get_strset_count,
426 .get_ethtool_stats = &edma_get_ethtool_stats,
427 .get_coalesce = &edma_get_coalesce,
428 .set_coalesce = &edma_set_coalesce,
429 .get_priv_flags = edma_get_priv_flags,
430 .set_priv_flags = edma_set_priv_flags,
431 .get_ringparam = edma_get_ringparam,
432};
433
434/* edma_set_ethtool_ops
435 * Set ethtool operations
436 */
437void edma_set_ethtool_ops(struct net_device *netdev)
438{
439 netdev->ethtool_ops = &edma_ethtool_ops;
440}