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