xref: /openbmc/linux/drivers/net/ethernet/qualcomm/emac/emac-ethtool.c (revision 03ab8e6297acd1bc0eedaa050e2a1635c576fd11)
197fb5e8dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
279f664edSTimur Tabi /* Copyright (c) 2016, The Linux Foundation. All rights reserved.
379f664edSTimur Tabi  */
479f664edSTimur Tabi 
579f664edSTimur Tabi #include <linux/ethtool.h>
679f664edSTimur Tabi #include <linux/phy.h>
779f664edSTimur Tabi 
879f664edSTimur Tabi #include "emac.h"
979f664edSTimur Tabi 
1079f664edSTimur Tabi static const char * const emac_ethtool_stat_strings[] = {
1179f664edSTimur Tabi 	"rx_ok",
1279f664edSTimur Tabi 	"rx_bcast",
1379f664edSTimur Tabi 	"rx_mcast",
1479f664edSTimur Tabi 	"rx_pause",
1579f664edSTimur Tabi 	"rx_ctrl",
1679f664edSTimur Tabi 	"rx_fcs_err",
1779f664edSTimur Tabi 	"rx_len_err",
1879f664edSTimur Tabi 	"rx_byte_cnt",
1979f664edSTimur Tabi 	"rx_runt",
2079f664edSTimur Tabi 	"rx_frag",
2179f664edSTimur Tabi 	"rx_sz_64",
2279f664edSTimur Tabi 	"rx_sz_65_127",
2379f664edSTimur Tabi 	"rx_sz_128_255",
2479f664edSTimur Tabi 	"rx_sz_256_511",
2579f664edSTimur Tabi 	"rx_sz_512_1023",
2679f664edSTimur Tabi 	"rx_sz_1024_1518",
2779f664edSTimur Tabi 	"rx_sz_1519_max",
2879f664edSTimur Tabi 	"rx_sz_ov",
2979f664edSTimur Tabi 	"rx_rxf_ov",
3079f664edSTimur Tabi 	"rx_align_err",
3179f664edSTimur Tabi 	"rx_bcast_byte_cnt",
3279f664edSTimur Tabi 	"rx_mcast_byte_cnt",
3379f664edSTimur Tabi 	"rx_err_addr",
3479f664edSTimur Tabi 	"rx_crc_align",
3579f664edSTimur Tabi 	"rx_jabbers",
3679f664edSTimur Tabi 	"tx_ok",
3779f664edSTimur Tabi 	"tx_bcast",
3879f664edSTimur Tabi 	"tx_mcast",
3979f664edSTimur Tabi 	"tx_pause",
4079f664edSTimur Tabi 	"tx_exc_defer",
4179f664edSTimur Tabi 	"tx_ctrl",
4279f664edSTimur Tabi 	"tx_defer",
4379f664edSTimur Tabi 	"tx_byte_cnt",
4479f664edSTimur Tabi 	"tx_sz_64",
4579f664edSTimur Tabi 	"tx_sz_65_127",
4679f664edSTimur Tabi 	"tx_sz_128_255",
4779f664edSTimur Tabi 	"tx_sz_256_511",
4879f664edSTimur Tabi 	"tx_sz_512_1023",
4979f664edSTimur Tabi 	"tx_sz_1024_1518",
5079f664edSTimur Tabi 	"tx_sz_1519_max",
5179f664edSTimur Tabi 	"tx_1_col",
5279f664edSTimur Tabi 	"tx_2_col",
5379f664edSTimur Tabi 	"tx_late_col",
5479f664edSTimur Tabi 	"tx_abort_col",
5579f664edSTimur Tabi 	"tx_underrun",
5679f664edSTimur Tabi 	"tx_rd_eop",
5779f664edSTimur Tabi 	"tx_len_err",
5879f664edSTimur Tabi 	"tx_trunc",
5979f664edSTimur Tabi 	"tx_bcast_byte",
6079f664edSTimur Tabi 	"tx_mcast_byte",
6179f664edSTimur Tabi 	"tx_col",
6279f664edSTimur Tabi };
6379f664edSTimur Tabi 
6479f664edSTimur Tabi #define EMAC_STATS_LEN	ARRAY_SIZE(emac_ethtool_stat_strings)
6579f664edSTimur Tabi 
emac_get_msglevel(struct net_device * netdev)6679f664edSTimur Tabi static u32 emac_get_msglevel(struct net_device *netdev)
6779f664edSTimur Tabi {
6879f664edSTimur Tabi 	struct emac_adapter *adpt = netdev_priv(netdev);
6979f664edSTimur Tabi 
7079f664edSTimur Tabi 	return adpt->msg_enable;
7179f664edSTimur Tabi }
7279f664edSTimur Tabi 
emac_set_msglevel(struct net_device * netdev,u32 data)7379f664edSTimur Tabi static void emac_set_msglevel(struct net_device *netdev, u32 data)
7479f664edSTimur Tabi {
7579f664edSTimur Tabi 	struct emac_adapter *adpt = netdev_priv(netdev);
7679f664edSTimur Tabi 
7779f664edSTimur Tabi 	adpt->msg_enable = data;
7879f664edSTimur Tabi }
7979f664edSTimur Tabi 
emac_get_sset_count(struct net_device * netdev,int sset)8079f664edSTimur Tabi static int emac_get_sset_count(struct net_device *netdev, int sset)
8179f664edSTimur Tabi {
8279f664edSTimur Tabi 	switch (sset) {
834a7a3860STimur Tabi 	case ETH_SS_PRIV_FLAGS:
844a7a3860STimur Tabi 		return 1;
8579f664edSTimur Tabi 	case ETH_SS_STATS:
8679f664edSTimur Tabi 		return EMAC_STATS_LEN;
8779f664edSTimur Tabi 	default:
8879f664edSTimur Tabi 		return -EOPNOTSUPP;
8979f664edSTimur Tabi 	}
9079f664edSTimur Tabi }
9179f664edSTimur Tabi 
emac_get_strings(struct net_device * netdev,u32 stringset,u8 * data)9279f664edSTimur Tabi static void emac_get_strings(struct net_device *netdev, u32 stringset, u8 *data)
9379f664edSTimur Tabi {
9479f664edSTimur Tabi 	unsigned int i;
9579f664edSTimur Tabi 
9679f664edSTimur Tabi 	switch (stringset) {
974a7a3860STimur Tabi 	case ETH_SS_PRIV_FLAGS:
984a7a3860STimur Tabi 		strcpy(data, "single-pause-mode");
994a7a3860STimur Tabi 		break;
1004a7a3860STimur Tabi 
10179f664edSTimur Tabi 	case ETH_SS_STATS:
10279f664edSTimur Tabi 		for (i = 0; i < EMAC_STATS_LEN; i++) {
1030a832999SJason Wang 			strscpy(data, emac_ethtool_stat_strings[i],
10479f664edSTimur Tabi 				ETH_GSTRING_LEN);
10579f664edSTimur Tabi 			data += ETH_GSTRING_LEN;
10679f664edSTimur Tabi 		}
10779f664edSTimur Tabi 		break;
10879f664edSTimur Tabi 	}
10979f664edSTimur Tabi }
11079f664edSTimur Tabi 
emac_get_ethtool_stats(struct net_device * netdev,struct ethtool_stats * stats,u64 * data)11179f664edSTimur Tabi static void emac_get_ethtool_stats(struct net_device *netdev,
11279f664edSTimur Tabi 				   struct ethtool_stats *stats,
11379f664edSTimur Tabi 				   u64 *data)
11479f664edSTimur Tabi {
11579f664edSTimur Tabi 	struct emac_adapter *adpt = netdev_priv(netdev);
11679f664edSTimur Tabi 
11779f664edSTimur Tabi 	spin_lock(&adpt->stats.lock);
11879f664edSTimur Tabi 
11979f664edSTimur Tabi 	emac_update_hw_stats(adpt);
12079f664edSTimur Tabi 	memcpy(data, &adpt->stats, EMAC_STATS_LEN * sizeof(u64));
12179f664edSTimur Tabi 
12279f664edSTimur Tabi 	spin_unlock(&adpt->stats.lock);
12379f664edSTimur Tabi }
12479f664edSTimur Tabi 
emac_nway_reset(struct net_device * netdev)12579f664edSTimur Tabi static int emac_nway_reset(struct net_device *netdev)
12679f664edSTimur Tabi {
12779f664edSTimur Tabi 	struct phy_device *phydev = netdev->phydev;
12879f664edSTimur Tabi 
12979f664edSTimur Tabi 	if (!phydev)
13079f664edSTimur Tabi 		return -ENODEV;
13179f664edSTimur Tabi 
13279f664edSTimur Tabi 	return genphy_restart_aneg(phydev);
13379f664edSTimur Tabi }
13479f664edSTimur Tabi 
emac_get_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)13579f664edSTimur Tabi static void emac_get_ringparam(struct net_device *netdev,
136*74624944SHao Chen 			       struct ethtool_ringparam *ring,
137*74624944SHao Chen 			       struct kernel_ethtool_ringparam *kernel_ring,
138*74624944SHao Chen 			       struct netlink_ext_ack *extack)
13979f664edSTimur Tabi {
14079f664edSTimur Tabi 	struct emac_adapter *adpt = netdev_priv(netdev);
14179f664edSTimur Tabi 
14279f664edSTimur Tabi 	ring->rx_max_pending = EMAC_MAX_RX_DESCS;
14379f664edSTimur Tabi 	ring->tx_max_pending = EMAC_MAX_TX_DESCS;
14479f664edSTimur Tabi 	ring->rx_pending = adpt->rx_desc_cnt;
14579f664edSTimur Tabi 	ring->tx_pending = adpt->tx_desc_cnt;
14679f664edSTimur Tabi }
14779f664edSTimur Tabi 
emac_set_ringparam(struct net_device * netdev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)148038b9404STimur Tabi static int emac_set_ringparam(struct net_device *netdev,
149*74624944SHao Chen 			      struct ethtool_ringparam *ring,
150*74624944SHao Chen 			      struct kernel_ethtool_ringparam *kernel_ring,
151*74624944SHao Chen 			      struct netlink_ext_ack *extack)
152038b9404STimur Tabi {
153038b9404STimur Tabi 	struct emac_adapter *adpt = netdev_priv(netdev);
154038b9404STimur Tabi 
155038b9404STimur Tabi 	/* We don't have separate queues/rings for small/large frames, so
156038b9404STimur Tabi 	 * reject any attempt to specify those values separately.
157038b9404STimur Tabi 	 */
158038b9404STimur Tabi 	if (ring->rx_mini_pending || ring->rx_jumbo_pending)
159038b9404STimur Tabi 		return -EINVAL;
160038b9404STimur Tabi 
161038b9404STimur Tabi 	adpt->tx_desc_cnt =
162038b9404STimur Tabi 		clamp_val(ring->tx_pending, EMAC_MIN_TX_DESCS, EMAC_MAX_TX_DESCS);
163038b9404STimur Tabi 
164038b9404STimur Tabi 	adpt->rx_desc_cnt =
165038b9404STimur Tabi 		clamp_val(ring->rx_pending, EMAC_MIN_RX_DESCS, EMAC_MAX_RX_DESCS);
166038b9404STimur Tabi 
167038b9404STimur Tabi 	if (netif_running(netdev))
168038b9404STimur Tabi 		return emac_reinit_locked(adpt);
169038b9404STimur Tabi 
170038b9404STimur Tabi 	return 0;
171038b9404STimur Tabi }
172038b9404STimur Tabi 
emac_get_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)17379f664edSTimur Tabi static void emac_get_pauseparam(struct net_device *netdev,
17479f664edSTimur Tabi 				struct ethtool_pauseparam *pause)
17579f664edSTimur Tabi {
176b44700e9STimur Tabi 	struct emac_adapter *adpt = netdev_priv(netdev);
17779f664edSTimur Tabi 
178b44700e9STimur Tabi 	pause->autoneg = adpt->automatic ? AUTONEG_ENABLE : AUTONEG_DISABLE;
179b44700e9STimur Tabi 	pause->rx_pause = adpt->rx_flow_control ? 1 : 0;
1803c19bd6cSWu Fengguang 	pause->tx_pause = adpt->tx_flow_control ? 1 : 0;
18179f664edSTimur Tabi }
182b44700e9STimur Tabi 
emac_set_pauseparam(struct net_device * netdev,struct ethtool_pauseparam * pause)183b44700e9STimur Tabi static int emac_set_pauseparam(struct net_device *netdev,
184b44700e9STimur Tabi 			       struct ethtool_pauseparam *pause)
185b44700e9STimur Tabi {
186b44700e9STimur Tabi 	struct emac_adapter *adpt = netdev_priv(netdev);
187b44700e9STimur Tabi 
188b44700e9STimur Tabi 	adpt->automatic = pause->autoneg == AUTONEG_ENABLE;
189b44700e9STimur Tabi 	adpt->rx_flow_control = pause->rx_pause != 0;
190b44700e9STimur Tabi 	adpt->tx_flow_control = pause->tx_pause != 0;
191b44700e9STimur Tabi 
192b44700e9STimur Tabi 	if (netif_running(netdev))
193b44700e9STimur Tabi 		return emac_reinit_locked(adpt);
194b44700e9STimur Tabi 
195b44700e9STimur Tabi 	return 0;
19679f664edSTimur Tabi }
19779f664edSTimur Tabi 
198c4e7beeaSTimur Tabi /* Selected registers that might want to track during runtime. */
199c4e7beeaSTimur Tabi static const u16 emac_regs[] = {
200c4e7beeaSTimur Tabi 	EMAC_DMA_MAS_CTRL,
201c4e7beeaSTimur Tabi 	EMAC_MAC_CTRL,
202c4e7beeaSTimur Tabi 	EMAC_TXQ_CTRL_0,
203c4e7beeaSTimur Tabi 	EMAC_RXQ_CTRL_0,
204c4e7beeaSTimur Tabi 	EMAC_DMA_CTRL,
205c4e7beeaSTimur Tabi 	EMAC_INT_MASK,
206c4e7beeaSTimur Tabi 	EMAC_AXI_MAST_CTRL,
207c4e7beeaSTimur Tabi 	EMAC_CORE_HW_VERSION,
208c4e7beeaSTimur Tabi 	EMAC_MISC_CTRL,
209c4e7beeaSTimur Tabi };
210c4e7beeaSTimur Tabi 
211c4e7beeaSTimur Tabi /* Every time emac_regs[] above is changed, increase this version number. */
212c4e7beeaSTimur Tabi #define EMAC_REGS_VERSION	0
213c4e7beeaSTimur Tabi 
214c4e7beeaSTimur Tabi #define EMAC_MAX_REG_SIZE	ARRAY_SIZE(emac_regs)
215c4e7beeaSTimur Tabi 
emac_get_regs(struct net_device * netdev,struct ethtool_regs * regs,void * buff)216c4e7beeaSTimur Tabi static void emac_get_regs(struct net_device *netdev,
217c4e7beeaSTimur Tabi 			  struct ethtool_regs *regs, void *buff)
218c4e7beeaSTimur Tabi {
219c4e7beeaSTimur Tabi 	struct emac_adapter *adpt = netdev_priv(netdev);
220c4e7beeaSTimur Tabi 	u32 *val = buff;
221c4e7beeaSTimur Tabi 	unsigned int i;
222c4e7beeaSTimur Tabi 
223c4e7beeaSTimur Tabi 	regs->version = EMAC_REGS_VERSION;
224c4e7beeaSTimur Tabi 	regs->len = EMAC_MAX_REG_SIZE * sizeof(u32);
225c4e7beeaSTimur Tabi 
226c4e7beeaSTimur Tabi 	for (i = 0; i < EMAC_MAX_REG_SIZE; i++)
227c4e7beeaSTimur Tabi 		val[i] = readl(adpt->base + emac_regs[i]);
228c4e7beeaSTimur Tabi }
229c4e7beeaSTimur Tabi 
emac_get_regs_len(struct net_device * netdev)230c4e7beeaSTimur Tabi static int emac_get_regs_len(struct net_device *netdev)
231c4e7beeaSTimur Tabi {
2322194bd10SDan Carpenter 	return EMAC_MAX_REG_SIZE * sizeof(u32);
233c4e7beeaSTimur Tabi }
234c4e7beeaSTimur Tabi 
2354a7a3860STimur Tabi #define EMAC_PRIV_ENABLE_SINGLE_PAUSE	BIT(0)
2364a7a3860STimur Tabi 
emac_set_priv_flags(struct net_device * netdev,u32 flags)2374a7a3860STimur Tabi static int emac_set_priv_flags(struct net_device *netdev, u32 flags)
2384a7a3860STimur Tabi {
2394a7a3860STimur Tabi 	struct emac_adapter *adpt = netdev_priv(netdev);
2404a7a3860STimur Tabi 
2414a7a3860STimur Tabi 	adpt->single_pause_mode = !!(flags & EMAC_PRIV_ENABLE_SINGLE_PAUSE);
2424a7a3860STimur Tabi 
2434a7a3860STimur Tabi 	if (netif_running(netdev))
2444a7a3860STimur Tabi 		return emac_reinit_locked(adpt);
2454a7a3860STimur Tabi 
2464a7a3860STimur Tabi 	return 0;
2474a7a3860STimur Tabi }
2484a7a3860STimur Tabi 
emac_get_priv_flags(struct net_device * netdev)2494a7a3860STimur Tabi static u32 emac_get_priv_flags(struct net_device *netdev)
2504a7a3860STimur Tabi {
2514a7a3860STimur Tabi 	struct emac_adapter *adpt = netdev_priv(netdev);
2524a7a3860STimur Tabi 
2534a7a3860STimur Tabi 	return adpt->single_pause_mode ? EMAC_PRIV_ENABLE_SINGLE_PAUSE : 0;
2544a7a3860STimur Tabi }
2554a7a3860STimur Tabi 
25679f664edSTimur Tabi static const struct ethtool_ops emac_ethtool_ops = {
25779f664edSTimur Tabi 	.get_link_ksettings = phy_ethtool_get_link_ksettings,
25879f664edSTimur Tabi 	.set_link_ksettings = phy_ethtool_set_link_ksettings,
25979f664edSTimur Tabi 
26079f664edSTimur Tabi 	.get_msglevel    = emac_get_msglevel,
26179f664edSTimur Tabi 	.set_msglevel    = emac_set_msglevel,
26279f664edSTimur Tabi 
26379f664edSTimur Tabi 	.get_sset_count  = emac_get_sset_count,
26479f664edSTimur Tabi 	.get_strings = emac_get_strings,
26579f664edSTimur Tabi 	.get_ethtool_stats = emac_get_ethtool_stats,
26679f664edSTimur Tabi 
26779f664edSTimur Tabi 	.get_ringparam = emac_get_ringparam,
268038b9404STimur Tabi 	.set_ringparam = emac_set_ringparam,
269b44700e9STimur Tabi 
27079f664edSTimur Tabi 	.get_pauseparam = emac_get_pauseparam,
271b44700e9STimur Tabi 	.set_pauseparam = emac_set_pauseparam,
27279f664edSTimur Tabi 
27379f664edSTimur Tabi 	.nway_reset = emac_nway_reset,
27479f664edSTimur Tabi 
27579f664edSTimur Tabi 	.get_link = ethtool_op_get_link,
276c4e7beeaSTimur Tabi 
277c4e7beeaSTimur Tabi 	.get_regs_len    = emac_get_regs_len,
278c4e7beeaSTimur Tabi 	.get_regs        = emac_get_regs,
2794a7a3860STimur Tabi 
2804a7a3860STimur Tabi 	.set_priv_flags = emac_set_priv_flags,
2814a7a3860STimur Tabi 	.get_priv_flags = emac_get_priv_flags,
28279f664edSTimur Tabi };
28379f664edSTimur Tabi 
emac_set_ethtool_ops(struct net_device * netdev)28479f664edSTimur Tabi void emac_set_ethtool_ops(struct net_device *netdev)
28579f664edSTimur Tabi {
28679f664edSTimur Tabi 	netdev->ethtool_ops = &emac_ethtool_ops;
28779f664edSTimur Tabi }
288