Skip to content

Commit 79f664e

Browse files
Timur Tabidavem330
authored andcommitted
net: qcom/emac: add ethtool support
Add support for some ethtool methods: get/set link settings, get/set message level, get statistics, get link status, get ring params, get pause params, and restart autonegotiation. The code to collect the hardware statistics is moved into its own function so that it can be used by "get statistics" method. Signed-off-by: Timur Tabi <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 3a89eaa commit 79f664e

File tree

4 files changed

+221
-21
lines changed

4 files changed

+221
-21
lines changed

drivers/net/ethernet/qualcomm/emac/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@
44

55
obj-$(CONFIG_QCOM_EMAC) += qcom-emac.o
66

7-
qcom-emac-objs := emac.o emac-mac.o emac-phy.o emac-sgmii.o \
7+
qcom-emac-objs := emac.o emac-mac.o emac-phy.o emac-sgmii.o emac-ethtool.o \
88
emac-sgmii-fsm9900.o emac-sgmii-qdf2432.o \
99
emac-sgmii-qdf2400.o
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/* Copyright (c) 2016, The Linux Foundation. All rights reserved.
2+
*
3+
* This program is free software; you can redistribute it and/or modify
4+
* it under the terms of the GNU General Public License version 2 and
5+
* only version 2 as published by the Free Software Foundation.
6+
*
7+
* This program is distributed in the hope that it will be useful,
8+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
9+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10+
* GNU General Public License for more details.
11+
*/
12+
13+
#include <linux/ethtool.h>
14+
#include <linux/phy.h>
15+
16+
#include "emac.h"
17+
18+
static const char * const emac_ethtool_stat_strings[] = {
19+
"rx_ok",
20+
"rx_bcast",
21+
"rx_mcast",
22+
"rx_pause",
23+
"rx_ctrl",
24+
"rx_fcs_err",
25+
"rx_len_err",
26+
"rx_byte_cnt",
27+
"rx_runt",
28+
"rx_frag",
29+
"rx_sz_64",
30+
"rx_sz_65_127",
31+
"rx_sz_128_255",
32+
"rx_sz_256_511",
33+
"rx_sz_512_1023",
34+
"rx_sz_1024_1518",
35+
"rx_sz_1519_max",
36+
"rx_sz_ov",
37+
"rx_rxf_ov",
38+
"rx_align_err",
39+
"rx_bcast_byte_cnt",
40+
"rx_mcast_byte_cnt",
41+
"rx_err_addr",
42+
"rx_crc_align",
43+
"rx_jabbers",
44+
"tx_ok",
45+
"tx_bcast",
46+
"tx_mcast",
47+
"tx_pause",
48+
"tx_exc_defer",
49+
"tx_ctrl",
50+
"tx_defer",
51+
"tx_byte_cnt",
52+
"tx_sz_64",
53+
"tx_sz_65_127",
54+
"tx_sz_128_255",
55+
"tx_sz_256_511",
56+
"tx_sz_512_1023",
57+
"tx_sz_1024_1518",
58+
"tx_sz_1519_max",
59+
"tx_1_col",
60+
"tx_2_col",
61+
"tx_late_col",
62+
"tx_abort_col",
63+
"tx_underrun",
64+
"tx_rd_eop",
65+
"tx_len_err",
66+
"tx_trunc",
67+
"tx_bcast_byte",
68+
"tx_mcast_byte",
69+
"tx_col",
70+
};
71+
72+
#define EMAC_STATS_LEN ARRAY_SIZE(emac_ethtool_stat_strings)
73+
74+
static u32 emac_get_msglevel(struct net_device *netdev)
75+
{
76+
struct emac_adapter *adpt = netdev_priv(netdev);
77+
78+
return adpt->msg_enable;
79+
}
80+
81+
static void emac_set_msglevel(struct net_device *netdev, u32 data)
82+
{
83+
struct emac_adapter *adpt = netdev_priv(netdev);
84+
85+
adpt->msg_enable = data;
86+
}
87+
88+
static int emac_get_sset_count(struct net_device *netdev, int sset)
89+
{
90+
switch (sset) {
91+
case ETH_SS_STATS:
92+
return EMAC_STATS_LEN;
93+
default:
94+
return -EOPNOTSUPP;
95+
}
96+
}
97+
98+
static void emac_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
99+
{
100+
unsigned int i;
101+
102+
switch (stringset) {
103+
case ETH_SS_STATS:
104+
for (i = 0; i < EMAC_STATS_LEN; i++) {
105+
strlcpy(data, emac_ethtool_stat_strings[i],
106+
ETH_GSTRING_LEN);
107+
data += ETH_GSTRING_LEN;
108+
}
109+
break;
110+
}
111+
}
112+
113+
static void emac_get_ethtool_stats(struct net_device *netdev,
114+
struct ethtool_stats *stats,
115+
u64 *data)
116+
{
117+
struct emac_adapter *adpt = netdev_priv(netdev);
118+
119+
spin_lock(&adpt->stats.lock);
120+
121+
emac_update_hw_stats(adpt);
122+
memcpy(data, &adpt->stats, EMAC_STATS_LEN * sizeof(u64));
123+
124+
spin_unlock(&adpt->stats.lock);
125+
}
126+
127+
static int emac_nway_reset(struct net_device *netdev)
128+
{
129+
struct phy_device *phydev = netdev->phydev;
130+
131+
if (!phydev)
132+
return -ENODEV;
133+
134+
return genphy_restart_aneg(phydev);
135+
}
136+
137+
static void emac_get_ringparam(struct net_device *netdev,
138+
struct ethtool_ringparam *ring)
139+
{
140+
struct emac_adapter *adpt = netdev_priv(netdev);
141+
142+
ring->rx_max_pending = EMAC_MAX_RX_DESCS;
143+
ring->tx_max_pending = EMAC_MAX_TX_DESCS;
144+
ring->rx_pending = adpt->rx_desc_cnt;
145+
ring->tx_pending = adpt->tx_desc_cnt;
146+
}
147+
148+
static void emac_get_pauseparam(struct net_device *netdev,
149+
struct ethtool_pauseparam *pause)
150+
{
151+
struct phy_device *phydev = netdev->phydev;
152+
153+
if (phydev) {
154+
if (phydev->autoneg)
155+
pause->autoneg = 1;
156+
if (phydev->pause)
157+
pause->rx_pause = 1;
158+
if (phydev->pause != phydev->asym_pause)
159+
pause->tx_pause = 1;
160+
}
161+
}
162+
163+
static const struct ethtool_ops emac_ethtool_ops = {
164+
.get_link_ksettings = phy_ethtool_get_link_ksettings,
165+
.set_link_ksettings = phy_ethtool_set_link_ksettings,
166+
167+
.get_msglevel = emac_get_msglevel,
168+
.set_msglevel = emac_set_msglevel,
169+
170+
.get_sset_count = emac_get_sset_count,
171+
.get_strings = emac_get_strings,
172+
.get_ethtool_stats = emac_get_ethtool_stats,
173+
174+
.get_ringparam = emac_get_ringparam,
175+
.get_pauseparam = emac_get_pauseparam,
176+
177+
.nway_reset = emac_nway_reset,
178+
179+
.get_link = ethtool_op_get_link,
180+
};
181+
182+
void emac_set_ethtool_ops(struct net_device *netdev)
183+
{
184+
netdev->ethtool_ops = &emac_ethtool_ops;
185+
}

drivers/net/ethernet/qualcomm/emac/emac.c

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -311,45 +311,56 @@ static int emac_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
311311
return phy_mii_ioctl(netdev->phydev, ifr, cmd);
312312
}
313313

314-
/* Provide network statistics info for the interface */
315-
static void emac_get_stats64(struct net_device *netdev,
316-
struct rtnl_link_stats64 *net_stats)
314+
/**
315+
* emac_update_hw_stats - read the EMAC stat registers
316+
*
317+
* Reads the stats registers and write the values to adpt->stats.
318+
*
319+
* adpt->stats.lock must be held while calling this function,
320+
* and while reading from adpt->stats.
321+
*/
322+
void emac_update_hw_stats(struct emac_adapter *adpt)
317323
{
318-
struct emac_adapter *adpt = netdev_priv(netdev);
319-
unsigned int addr = REG_MAC_RX_STATUS_BIN;
320324
struct emac_stats *stats = &adpt->stats;
321325
u64 *stats_itr = &adpt->stats.rx_ok;
322-
u32 val;
323-
324-
spin_lock(&stats->lock);
326+
void __iomem *base = adpt->base;
327+
unsigned int addr;
325328

329+
addr = REG_MAC_RX_STATUS_BIN;
326330
while (addr <= REG_MAC_RX_STATUS_END) {
327-
val = readl_relaxed(adpt->base + addr);
328-
*stats_itr += val;
331+
*stats_itr += readl_relaxed(base + addr);
329332
stats_itr++;
330333
addr += sizeof(u32);
331334
}
332335

333336
/* additional rx status */
334-
val = readl_relaxed(adpt->base + EMAC_RXMAC_STATC_REG23);
335-
adpt->stats.rx_crc_align += val;
336-
val = readl_relaxed(adpt->base + EMAC_RXMAC_STATC_REG24);
337-
adpt->stats.rx_jabbers += val;
337+
stats->rx_crc_align += readl_relaxed(base + EMAC_RXMAC_STATC_REG23);
338+
stats->rx_jabbers += readl_relaxed(base + EMAC_RXMAC_STATC_REG24);
338339

339340
/* update tx status */
340341
addr = REG_MAC_TX_STATUS_BIN;
341-
stats_itr = &adpt->stats.tx_ok;
342+
stats_itr = &stats->tx_ok;
342343

343344
while (addr <= REG_MAC_TX_STATUS_END) {
344-
val = readl_relaxed(adpt->base + addr);
345-
*stats_itr += val;
346-
++stats_itr;
345+
*stats_itr += readl_relaxed(base + addr);
346+
stats_itr++;
347347
addr += sizeof(u32);
348348
}
349349

350350
/* additional tx status */
351-
val = readl_relaxed(adpt->base + EMAC_TXMAC_STATC_REG25);
352-
adpt->stats.tx_col += val;
351+
stats->tx_col += readl_relaxed(base + EMAC_TXMAC_STATC_REG25);
352+
}
353+
354+
/* Provide network statistics info for the interface */
355+
static void emac_get_stats64(struct net_device *netdev,
356+
struct rtnl_link_stats64 *net_stats)
357+
{
358+
struct emac_adapter *adpt = netdev_priv(netdev);
359+
struct emac_stats *stats = &adpt->stats;
360+
361+
spin_lock(&stats->lock);
362+
363+
emac_update_hw_stats(adpt);
353364

354365
/* return parsed statistics */
355366
net_stats->rx_packets = stats->rx_ok;
@@ -618,6 +629,7 @@ static int emac_probe(struct platform_device *pdev)
618629

619630
dev_set_drvdata(&pdev->dev, netdev);
620631
SET_NETDEV_DEV(netdev, &pdev->dev);
632+
emac_set_ethtool_ops(netdev);
621633

622634
adpt = netdev_priv(netdev);
623635
adpt->netdev = netdev;

drivers/net/ethernet/qualcomm/emac/emac.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,4 +332,7 @@ int emac_reinit_locked(struct emac_adapter *adpt);
332332
void emac_reg_update32(void __iomem *addr, u32 mask, u32 val);
333333
irqreturn_t emac_isr(int irq, void *data);
334334

335+
void emac_set_ethtool_ops(struct net_device *netdev);
336+
void emac_update_hw_stats(struct emac_adapter *adpt);
337+
335338
#endif /* _EMAC_H_ */

0 commit comments

Comments
 (0)