xref: /OK3568_Linux_fs/kernel/drivers/net/ethernet/qualcomm/emac/emac-ethtool.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /* Copyright (c) 2016, The Linux Foundation. All rights reserved.
3*4882a593Smuzhiyun  */
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun #include <linux/ethtool.h>
6*4882a593Smuzhiyun #include <linux/phy.h>
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include "emac.h"
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun static const char * const emac_ethtool_stat_strings[] = {
11*4882a593Smuzhiyun 	"rx_ok",
12*4882a593Smuzhiyun 	"rx_bcast",
13*4882a593Smuzhiyun 	"rx_mcast",
14*4882a593Smuzhiyun 	"rx_pause",
15*4882a593Smuzhiyun 	"rx_ctrl",
16*4882a593Smuzhiyun 	"rx_fcs_err",
17*4882a593Smuzhiyun 	"rx_len_err",
18*4882a593Smuzhiyun 	"rx_byte_cnt",
19*4882a593Smuzhiyun 	"rx_runt",
20*4882a593Smuzhiyun 	"rx_frag",
21*4882a593Smuzhiyun 	"rx_sz_64",
22*4882a593Smuzhiyun 	"rx_sz_65_127",
23*4882a593Smuzhiyun 	"rx_sz_128_255",
24*4882a593Smuzhiyun 	"rx_sz_256_511",
25*4882a593Smuzhiyun 	"rx_sz_512_1023",
26*4882a593Smuzhiyun 	"rx_sz_1024_1518",
27*4882a593Smuzhiyun 	"rx_sz_1519_max",
28*4882a593Smuzhiyun 	"rx_sz_ov",
29*4882a593Smuzhiyun 	"rx_rxf_ov",
30*4882a593Smuzhiyun 	"rx_align_err",
31*4882a593Smuzhiyun 	"rx_bcast_byte_cnt",
32*4882a593Smuzhiyun 	"rx_mcast_byte_cnt",
33*4882a593Smuzhiyun 	"rx_err_addr",
34*4882a593Smuzhiyun 	"rx_crc_align",
35*4882a593Smuzhiyun 	"rx_jabbers",
36*4882a593Smuzhiyun 	"tx_ok",
37*4882a593Smuzhiyun 	"tx_bcast",
38*4882a593Smuzhiyun 	"tx_mcast",
39*4882a593Smuzhiyun 	"tx_pause",
40*4882a593Smuzhiyun 	"tx_exc_defer",
41*4882a593Smuzhiyun 	"tx_ctrl",
42*4882a593Smuzhiyun 	"tx_defer",
43*4882a593Smuzhiyun 	"tx_byte_cnt",
44*4882a593Smuzhiyun 	"tx_sz_64",
45*4882a593Smuzhiyun 	"tx_sz_65_127",
46*4882a593Smuzhiyun 	"tx_sz_128_255",
47*4882a593Smuzhiyun 	"tx_sz_256_511",
48*4882a593Smuzhiyun 	"tx_sz_512_1023",
49*4882a593Smuzhiyun 	"tx_sz_1024_1518",
50*4882a593Smuzhiyun 	"tx_sz_1519_max",
51*4882a593Smuzhiyun 	"tx_1_col",
52*4882a593Smuzhiyun 	"tx_2_col",
53*4882a593Smuzhiyun 	"tx_late_col",
54*4882a593Smuzhiyun 	"tx_abort_col",
55*4882a593Smuzhiyun 	"tx_underrun",
56*4882a593Smuzhiyun 	"tx_rd_eop",
57*4882a593Smuzhiyun 	"tx_len_err",
58*4882a593Smuzhiyun 	"tx_trunc",
59*4882a593Smuzhiyun 	"tx_bcast_byte",
60*4882a593Smuzhiyun 	"tx_mcast_byte",
61*4882a593Smuzhiyun 	"tx_col",
62*4882a593Smuzhiyun };
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun #define EMAC_STATS_LEN	ARRAY_SIZE(emac_ethtool_stat_strings)
65*4882a593Smuzhiyun 
emac_get_msglevel(struct net_device * netdev)66*4882a593Smuzhiyun static u32 emac_get_msglevel(struct net_device *netdev)
67*4882a593Smuzhiyun {
68*4882a593Smuzhiyun 	struct emac_adapter *adpt = netdev_priv(netdev);
69*4882a593Smuzhiyun 
70*4882a593Smuzhiyun 	return adpt->msg_enable;
71*4882a593Smuzhiyun }
72*4882a593Smuzhiyun 
emac_set_msglevel(struct net_device * netdev,u32 data)73*4882a593Smuzhiyun static void emac_set_msglevel(struct net_device *netdev, u32 data)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	struct emac_adapter *adpt = netdev_priv(netdev);
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun 	adpt->msg_enable = data;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun 
emac_get_sset_count(struct net_device * netdev,int sset)80*4882a593Smuzhiyun static int emac_get_sset_count(struct net_device *netdev, int sset)
81*4882a593Smuzhiyun {
82*4882a593Smuzhiyun 	switch (sset) {
83*4882a593Smuzhiyun 	case ETH_SS_PRIV_FLAGS:
84*4882a593Smuzhiyun 		return 1;
85*4882a593Smuzhiyun 	case ETH_SS_STATS:
86*4882a593Smuzhiyun 		return EMAC_STATS_LEN;
87*4882a593Smuzhiyun 	default:
88*4882a593Smuzhiyun 		return -EOPNOTSUPP;
89*4882a593Smuzhiyun 	}
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
emac_get_strings(struct net_device * netdev,u32 stringset,u8 * data)92*4882a593Smuzhiyun static void emac_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
93*4882a593Smuzhiyun {
94*4882a593Smuzhiyun 	unsigned int i;
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 	switch (stringset) {
97*4882a593Smuzhiyun 	case ETH_SS_PRIV_FLAGS:
98*4882a593Smuzhiyun 		strcpy(data, "single-pause-mode");
99*4882a593Smuzhiyun 		break;
100*4882a593Smuzhiyun 
101*4882a593Smuzhiyun 	case ETH_SS_STATS:
102*4882a593Smuzhiyun 		for (i = 0; i < EMAC_STATS_LEN; i++) {
103*4882a593Smuzhiyun 			strlcpy(data, emac_ethtool_stat_strings[i],
104*4882a593Smuzhiyun 				ETH_GSTRING_LEN);
105*4882a593Smuzhiyun 			data += ETH_GSTRING_LEN;
106*4882a593Smuzhiyun 		}
107*4882a593Smuzhiyun 		break;
108*4882a593Smuzhiyun 	}
109*4882a593Smuzhiyun }
110*4882a593Smuzhiyun 
emac_get_ethtool_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)111*4882a593Smuzhiyun static void emac_get_ethtool_stats(struct net_device *netdev,
112*4882a593Smuzhiyun 				   struct ethtool_stats *stats,
113*4882a593Smuzhiyun 				   u64 *data)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	struct emac_adapter *adpt = netdev_priv(netdev);
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	spin_lock(&adpt->stats.lock);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	emac_update_hw_stats(adpt);
120*4882a593Smuzhiyun 	memcpy(data, &adpt->stats, EMAC_STATS_LEN * sizeof(u64));
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	spin_unlock(&adpt->stats.lock);
123*4882a593Smuzhiyun }
124*4882a593Smuzhiyun 
emac_nway_reset(struct net_device * netdev)125*4882a593Smuzhiyun static int emac_nway_reset(struct net_device *netdev)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun 	struct phy_device *phydev = netdev->phydev;
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun 	if (!phydev)
130*4882a593Smuzhiyun 		return -ENODEV;
131*4882a593Smuzhiyun 
132*4882a593Smuzhiyun 	return genphy_restart_aneg(phydev);
133*4882a593Smuzhiyun }
134*4882a593Smuzhiyun 
emac_get_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring)135*4882a593Smuzhiyun static void emac_get_ringparam(struct net_device *netdev,
136*4882a593Smuzhiyun 			       struct ethtool_ringparam *ring)
137*4882a593Smuzhiyun {
138*4882a593Smuzhiyun 	struct emac_adapter *adpt = netdev_priv(netdev);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	ring->rx_max_pending = EMAC_MAX_RX_DESCS;
141*4882a593Smuzhiyun 	ring->tx_max_pending = EMAC_MAX_TX_DESCS;
142*4882a593Smuzhiyun 	ring->rx_pending = adpt->rx_desc_cnt;
143*4882a593Smuzhiyun 	ring->tx_pending = adpt->tx_desc_cnt;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun 
emac_set_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring)146*4882a593Smuzhiyun static int emac_set_ringparam(struct net_device *netdev,
147*4882a593Smuzhiyun 			      struct ethtool_ringparam *ring)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun 	struct emac_adapter *adpt = netdev_priv(netdev);
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun 	/* We don't have separate queues/rings for small/large frames, so
152*4882a593Smuzhiyun 	 * reject any attempt to specify those values separately.
153*4882a593Smuzhiyun 	 */
154*4882a593Smuzhiyun 	if (ring->rx_mini_pending || ring->rx_jumbo_pending)
155*4882a593Smuzhiyun 		return -EINVAL;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	adpt->tx_desc_cnt =
158*4882a593Smuzhiyun 		clamp_val(ring->tx_pending, EMAC_MIN_TX_DESCS, EMAC_MAX_TX_DESCS);
159*4882a593Smuzhiyun 
160*4882a593Smuzhiyun 	adpt->rx_desc_cnt =
161*4882a593Smuzhiyun 		clamp_val(ring->rx_pending, EMAC_MIN_RX_DESCS, EMAC_MAX_RX_DESCS);
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 	if (netif_running(netdev))
164*4882a593Smuzhiyun 		return emac_reinit_locked(adpt);
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	return 0;
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun 
emac_get_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)169*4882a593Smuzhiyun static void emac_get_pauseparam(struct net_device *netdev,
170*4882a593Smuzhiyun 				struct ethtool_pauseparam *pause)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	struct emac_adapter *adpt = netdev_priv(netdev);
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	pause->autoneg = adpt->automatic ? AUTONEG_ENABLE : AUTONEG_DISABLE;
175*4882a593Smuzhiyun 	pause->rx_pause = adpt->rx_flow_control ? 1 : 0;
176*4882a593Smuzhiyun 	pause->tx_pause = adpt->tx_flow_control ? 1 : 0;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun 
emac_set_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)179*4882a593Smuzhiyun static int emac_set_pauseparam(struct net_device *netdev,
180*4882a593Smuzhiyun 			       struct ethtool_pauseparam *pause)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	struct emac_adapter *adpt = netdev_priv(netdev);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	adpt->automatic = pause->autoneg == AUTONEG_ENABLE;
185*4882a593Smuzhiyun 	adpt->rx_flow_control = pause->rx_pause != 0;
186*4882a593Smuzhiyun 	adpt->tx_flow_control = pause->tx_pause != 0;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	if (netif_running(netdev))
189*4882a593Smuzhiyun 		return emac_reinit_locked(adpt);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	return 0;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun /* Selected registers that might want to track during runtime. */
195*4882a593Smuzhiyun static const u16 emac_regs[] = {
196*4882a593Smuzhiyun 	EMAC_DMA_MAS_CTRL,
197*4882a593Smuzhiyun 	EMAC_MAC_CTRL,
198*4882a593Smuzhiyun 	EMAC_TXQ_CTRL_0,
199*4882a593Smuzhiyun 	EMAC_RXQ_CTRL_0,
200*4882a593Smuzhiyun 	EMAC_DMA_CTRL,
201*4882a593Smuzhiyun 	EMAC_INT_MASK,
202*4882a593Smuzhiyun 	EMAC_AXI_MAST_CTRL,
203*4882a593Smuzhiyun 	EMAC_CORE_HW_VERSION,
204*4882a593Smuzhiyun 	EMAC_MISC_CTRL,
205*4882a593Smuzhiyun };
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun /* Every time emac_regs[] above is changed, increase this version number. */
208*4882a593Smuzhiyun #define EMAC_REGS_VERSION	0
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun #define EMAC_MAX_REG_SIZE	ARRAY_SIZE(emac_regs)
211*4882a593Smuzhiyun 
emac_get_regs(struct net_device * netdev,struct ethtool_regs * regs,void * buff)212*4882a593Smuzhiyun static void emac_get_regs(struct net_device *netdev,
213*4882a593Smuzhiyun 			  struct ethtool_regs *regs, void *buff)
214*4882a593Smuzhiyun {
215*4882a593Smuzhiyun 	struct emac_adapter *adpt = netdev_priv(netdev);
216*4882a593Smuzhiyun 	u32 *val = buff;
217*4882a593Smuzhiyun 	unsigned int i;
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	regs->version = EMAC_REGS_VERSION;
220*4882a593Smuzhiyun 	regs->len = EMAC_MAX_REG_SIZE * sizeof(u32);
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	for (i = 0; i < EMAC_MAX_REG_SIZE; i++)
223*4882a593Smuzhiyun 		val[i] = readl(adpt->base + emac_regs[i]);
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun 
emac_get_regs_len(struct net_device * netdev)226*4882a593Smuzhiyun static int emac_get_regs_len(struct net_device *netdev)
227*4882a593Smuzhiyun {
228*4882a593Smuzhiyun 	return EMAC_MAX_REG_SIZE * sizeof(u32);
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun 
231*4882a593Smuzhiyun #define EMAC_PRIV_ENABLE_SINGLE_PAUSE	BIT(0)
232*4882a593Smuzhiyun 
emac_set_priv_flags(struct net_device * netdev,u32 flags)233*4882a593Smuzhiyun static int emac_set_priv_flags(struct net_device *netdev, u32 flags)
234*4882a593Smuzhiyun {
235*4882a593Smuzhiyun 	struct emac_adapter *adpt = netdev_priv(netdev);
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	adpt->single_pause_mode = !!(flags & EMAC_PRIV_ENABLE_SINGLE_PAUSE);
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	if (netif_running(netdev))
240*4882a593Smuzhiyun 		return emac_reinit_locked(adpt);
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	return 0;
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun 
emac_get_priv_flags(struct net_device * netdev)245*4882a593Smuzhiyun static u32 emac_get_priv_flags(struct net_device *netdev)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun 	struct emac_adapter *adpt = netdev_priv(netdev);
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 	return adpt->single_pause_mode ? EMAC_PRIV_ENABLE_SINGLE_PAUSE : 0;
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun static const struct ethtool_ops emac_ethtool_ops = {
253*4882a593Smuzhiyun 	.get_link_ksettings = phy_ethtool_get_link_ksettings,
254*4882a593Smuzhiyun 	.set_link_ksettings = phy_ethtool_set_link_ksettings,
255*4882a593Smuzhiyun 
256*4882a593Smuzhiyun 	.get_msglevel    = emac_get_msglevel,
257*4882a593Smuzhiyun 	.set_msglevel    = emac_set_msglevel,
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun 	.get_sset_count  = emac_get_sset_count,
260*4882a593Smuzhiyun 	.get_strings = emac_get_strings,
261*4882a593Smuzhiyun 	.get_ethtool_stats = emac_get_ethtool_stats,
262*4882a593Smuzhiyun 
263*4882a593Smuzhiyun 	.get_ringparam = emac_get_ringparam,
264*4882a593Smuzhiyun 	.set_ringparam = emac_set_ringparam,
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	.get_pauseparam = emac_get_pauseparam,
267*4882a593Smuzhiyun 	.set_pauseparam = emac_set_pauseparam,
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	.nway_reset = emac_nway_reset,
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	.get_link = ethtool_op_get_link,
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun 	.get_regs_len    = emac_get_regs_len,
274*4882a593Smuzhiyun 	.get_regs        = emac_get_regs,
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	.set_priv_flags = emac_set_priv_flags,
277*4882a593Smuzhiyun 	.get_priv_flags = emac_get_priv_flags,
278*4882a593Smuzhiyun };
279*4882a593Smuzhiyun 
emac_set_ethtool_ops(struct net_device * netdev)280*4882a593Smuzhiyun void emac_set_ethtool_ops(struct net_device *netdev)
281*4882a593Smuzhiyun {
282*4882a593Smuzhiyun 	netdev->ethtool_ops = &emac_ethtool_ops;
283*4882a593Smuzhiyun }
284