xref: /linux-6.15/drivers/net/netdevsim/ethtool.c (revision 2bcf4772)
1ff1f7c17SJakub Kicinski // SPDX-License-Identifier: GPL-2.0
2ff1f7c17SJakub Kicinski // Copyright (c) 2020 Facebook
3ff1f7c17SJakub Kicinski 
4ff1f7c17SJakub Kicinski #include <linux/debugfs.h>
5ff1f7c17SJakub Kicinski #include <linux/random.h>
63c836451SJakub Kicinski #include <net/netdev_queues.h>
7ff1f7c17SJakub Kicinski 
8ff1f7c17SJakub Kicinski #include "netdevsim.h"
9ff1f7c17SJakub Kicinski 
10ff1f7c17SJakub Kicinski static void
nsim_get_pause_stats(struct net_device * dev,struct ethtool_pause_stats * pause_stats)11ff1f7c17SJakub Kicinski nsim_get_pause_stats(struct net_device *dev,
12ff1f7c17SJakub Kicinski 		     struct ethtool_pause_stats *pause_stats)
13ff1f7c17SJakub Kicinski {
14ff1f7c17SJakub Kicinski 	struct netdevsim *ns = netdev_priv(dev);
15ff1f7c17SJakub Kicinski 
1677f9591bSAntonio Cardace 	if (ns->ethtool.pauseparam.report_stats_rx)
17ff1f7c17SJakub Kicinski 		pause_stats->rx_pause_frames = 1;
1877f9591bSAntonio Cardace 	if (ns->ethtool.pauseparam.report_stats_tx)
19ff1f7c17SJakub Kicinski 		pause_stats->tx_pause_frames = 2;
20ff1f7c17SJakub Kicinski }
21ff1f7c17SJakub Kicinski 
22ff1f7c17SJakub Kicinski static void
nsim_get_pauseparam(struct net_device * dev,struct ethtool_pauseparam * pause)23ff1f7c17SJakub Kicinski nsim_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause)
24ff1f7c17SJakub Kicinski {
25ff1f7c17SJakub Kicinski 	struct netdevsim *ns = netdev_priv(dev);
26ff1f7c17SJakub Kicinski 
27ff1f7c17SJakub Kicinski 	pause->autoneg = 0; /* We don't support ksettings, so can't pretend */
2877f9591bSAntonio Cardace 	pause->rx_pause = ns->ethtool.pauseparam.rx;
2977f9591bSAntonio Cardace 	pause->tx_pause = ns->ethtool.pauseparam.tx;
30ff1f7c17SJakub Kicinski }
31ff1f7c17SJakub Kicinski 
32ff1f7c17SJakub Kicinski static int
nsim_set_pauseparam(struct net_device * dev,struct ethtool_pauseparam * pause)33ff1f7c17SJakub Kicinski nsim_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause)
34ff1f7c17SJakub Kicinski {
35ff1f7c17SJakub Kicinski 	struct netdevsim *ns = netdev_priv(dev);
36ff1f7c17SJakub Kicinski 
37ff1f7c17SJakub Kicinski 	if (pause->autoneg)
38ff1f7c17SJakub Kicinski 		return -EINVAL;
39ff1f7c17SJakub Kicinski 
4077f9591bSAntonio Cardace 	ns->ethtool.pauseparam.rx = pause->rx_pause;
4177f9591bSAntonio Cardace 	ns->ethtool.pauseparam.tx = pause->tx_pause;
42ff1f7c17SJakub Kicinski 	return 0;
43ff1f7c17SJakub Kicinski }
44ff1f7c17SJakub Kicinski 
nsim_get_coalesce(struct net_device * dev,struct ethtool_coalesce * coal,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)45a7fc6db0SAntonio Cardace static int nsim_get_coalesce(struct net_device *dev,
46f3ccfda1SYufeng Mo 			     struct ethtool_coalesce *coal,
47f3ccfda1SYufeng Mo 			     struct kernel_ethtool_coalesce *kernel_coal,
48f3ccfda1SYufeng Mo 			     struct netlink_ext_ack *extack)
49a7fc6db0SAntonio Cardace {
50a7fc6db0SAntonio Cardace 	struct netdevsim *ns = netdev_priv(dev);
51a7fc6db0SAntonio Cardace 
52a7fc6db0SAntonio Cardace 	memcpy(coal, &ns->ethtool.coalesce, sizeof(ns->ethtool.coalesce));
53a7fc6db0SAntonio Cardace 	return 0;
54a7fc6db0SAntonio Cardace }
55a7fc6db0SAntonio Cardace 
nsim_set_coalesce(struct net_device * dev,struct ethtool_coalesce * coal,struct kernel_ethtool_coalesce * kernel_coal,struct netlink_ext_ack * extack)56a7fc6db0SAntonio Cardace static int nsim_set_coalesce(struct net_device *dev,
57f3ccfda1SYufeng Mo 			     struct ethtool_coalesce *coal,
58f3ccfda1SYufeng Mo 			     struct kernel_ethtool_coalesce *kernel_coal,
59f3ccfda1SYufeng Mo 			     struct netlink_ext_ack *extack)
60a7fc6db0SAntonio Cardace {
61a7fc6db0SAntonio Cardace 	struct netdevsim *ns = netdev_priv(dev);
62a7fc6db0SAntonio Cardace 
63a7fc6db0SAntonio Cardace 	memcpy(&ns->ethtool.coalesce, coal, sizeof(ns->ethtool.coalesce));
64a7fc6db0SAntonio Cardace 	return 0;
65a7fc6db0SAntonio Cardace }
66a7fc6db0SAntonio Cardace 
nsim_get_ringparam(struct net_device * dev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)67a7fc6db0SAntonio Cardace static void nsim_get_ringparam(struct net_device *dev,
6874624944SHao Chen 			       struct ethtool_ringparam *ring,
6974624944SHao Chen 			       struct kernel_ethtool_ringparam *kernel_ring,
7074624944SHao Chen 			       struct netlink_ext_ack *extack)
71a7fc6db0SAntonio Cardace {
72a7fc6db0SAntonio Cardace 	struct netdevsim *ns = netdev_priv(dev);
73a7fc6db0SAntonio Cardace 
74a7fc6db0SAntonio Cardace 	memcpy(ring, &ns->ethtool.ring, sizeof(ns->ethtool.ring));
75f394d07bSTaehee Yoo 	kernel_ring->hds_thresh_max = NSIM_HDS_THRESHOLD_MAX;
76f394d07bSTaehee Yoo 
776db9d3a5SJakub Kicinski 	if (dev->cfg->hds_config == ETHTOOL_TCP_DATA_SPLIT_UNKNOWN)
78f394d07bSTaehee Yoo 		kernel_ring->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_ENABLED;
79a7fc6db0SAntonio Cardace }
80a7fc6db0SAntonio Cardace 
nsim_set_ringparam(struct net_device * dev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)81a7fc6db0SAntonio Cardace static int nsim_set_ringparam(struct net_device *dev,
8274624944SHao Chen 			      struct ethtool_ringparam *ring,
8374624944SHao Chen 			      struct kernel_ethtool_ringparam *kernel_ring,
8474624944SHao Chen 			      struct netlink_ext_ack *extack)
85a7fc6db0SAntonio Cardace {
86a7fc6db0SAntonio Cardace 	struct netdevsim *ns = netdev_priv(dev);
87a7fc6db0SAntonio Cardace 
88ee60e626SFilip Pokryvka 	ns->ethtool.ring.rx_pending = ring->rx_pending;
89ee60e626SFilip Pokryvka 	ns->ethtool.ring.rx_jumbo_pending = ring->rx_jumbo_pending;
90ee60e626SFilip Pokryvka 	ns->ethtool.ring.rx_mini_pending = ring->rx_mini_pending;
91ee60e626SFilip Pokryvka 	ns->ethtool.ring.tx_pending = ring->tx_pending;
92a7fc6db0SAntonio Cardace 	return 0;
93a7fc6db0SAntonio Cardace }
94a7fc6db0SAntonio Cardace 
952e367522SJakub Kicinski static void
nsim_get_channels(struct net_device * dev,struct ethtool_channels * ch)962e367522SJakub Kicinski nsim_get_channels(struct net_device *dev, struct ethtool_channels *ch)
972e367522SJakub Kicinski {
982e367522SJakub Kicinski 	struct netdevsim *ns = netdev_priv(dev);
992e367522SJakub Kicinski 
1002e367522SJakub Kicinski 	ch->max_combined = ns->nsim_bus_dev->num_queues;
1012e367522SJakub Kicinski 	ch->combined_count = ns->ethtool.channels;
1022e367522SJakub Kicinski }
1032e367522SJakub Kicinski 
1042e367522SJakub Kicinski static int
nsim_set_channels(struct net_device * dev,struct ethtool_channels * ch)1052e367522SJakub Kicinski nsim_set_channels(struct net_device *dev, struct ethtool_channels *ch)
1062e367522SJakub Kicinski {
1072e367522SJakub Kicinski 	struct netdevsim *ns = netdev_priv(dev);
1082e367522SJakub Kicinski 	int err;
1092e367522SJakub Kicinski 
1102e367522SJakub Kicinski 	err = netif_set_real_num_queues(dev, ch->combined_count,
1112e367522SJakub Kicinski 					ch->combined_count);
1122e367522SJakub Kicinski 	if (err)
1132e367522SJakub Kicinski 		return err;
1142e367522SJakub Kicinski 
1152e367522SJakub Kicinski 	ns->ethtool.channels = ch->combined_count;
1162e367522SJakub Kicinski 	return 0;
1172e367522SJakub Kicinski }
1182e367522SJakub Kicinski 
1190d7f76dcSJakub Kicinski static int
nsim_get_fecparam(struct net_device * dev,struct ethtool_fecparam * fecparam)1200d7f76dcSJakub Kicinski nsim_get_fecparam(struct net_device *dev, struct ethtool_fecparam *fecparam)
1210d7f76dcSJakub Kicinski {
1220d7f76dcSJakub Kicinski 	struct netdevsim *ns = netdev_priv(dev);
1230d7f76dcSJakub Kicinski 
1240d7f76dcSJakub Kicinski 	if (ns->ethtool.get_err)
1250d7f76dcSJakub Kicinski 		return -ns->ethtool.get_err;
1260d7f76dcSJakub Kicinski 	memcpy(fecparam, &ns->ethtool.fec, sizeof(ns->ethtool.fec));
1270d7f76dcSJakub Kicinski 	return 0;
1280d7f76dcSJakub Kicinski }
1290d7f76dcSJakub Kicinski 
1300d7f76dcSJakub Kicinski static int
nsim_set_fecparam(struct net_device * dev,struct ethtool_fecparam * fecparam)1310d7f76dcSJakub Kicinski nsim_set_fecparam(struct net_device *dev, struct ethtool_fecparam *fecparam)
1320d7f76dcSJakub Kicinski {
1330d7f76dcSJakub Kicinski 	struct netdevsim *ns = netdev_priv(dev);
1340d7f76dcSJakub Kicinski 	u32 fec;
1350d7f76dcSJakub Kicinski 
1360d7f76dcSJakub Kicinski 	if (ns->ethtool.set_err)
1370d7f76dcSJakub Kicinski 		return -ns->ethtool.set_err;
1380d7f76dcSJakub Kicinski 	memcpy(&ns->ethtool.fec, fecparam, sizeof(ns->ethtool.fec));
1390d7f76dcSJakub Kicinski 	fec = fecparam->fec;
1400d7f76dcSJakub Kicinski 	if (fec == ETHTOOL_FEC_AUTO)
1410d7f76dcSJakub Kicinski 		fec |= ETHTOOL_FEC_OFF;
1420d7f76dcSJakub Kicinski 	fec |= ETHTOOL_FEC_NONE;
1430d7f76dcSJakub Kicinski 	ns->ethtool.fec.active_fec = 1 << (fls(fec) - 1);
1440d7f76dcSJakub Kicinski 	return 0;
1450d7f76dcSJakub Kicinski }
1460d7f76dcSJakub Kicinski 
147f216306bSJakub Kicinski static void
nsim_get_fec_stats(struct net_device * dev,struct ethtool_fec_stats * fec_stats)148f216306bSJakub Kicinski nsim_get_fec_stats(struct net_device *dev, struct ethtool_fec_stats *fec_stats)
149f216306bSJakub Kicinski {
150f216306bSJakub Kicinski 	fec_stats->corrected_blocks.total = 123;
151f216306bSJakub Kicinski 	fec_stats->uncorrectable_blocks.total = 4;
152f216306bSJakub Kicinski }
153f216306bSJakub Kicinski 
nsim_get_ts_info(struct net_device * dev,struct kernel_ethtool_ts_info * info)154b63e78fcSVladimir Oltean static int nsim_get_ts_info(struct net_device *dev,
1552111375bSKory Maincent 			    struct kernel_ethtool_ts_info *info)
156b63e78fcSVladimir Oltean {
157b63e78fcSVladimir Oltean 	struct netdevsim *ns = netdev_priv(dev);
158b63e78fcSVladimir Oltean 
159b63e78fcSVladimir Oltean 	info->phc_index = mock_phc_index(ns->phc);
160b63e78fcSVladimir Oltean 
161b63e78fcSVladimir Oltean 	return 0;
162b63e78fcSVladimir Oltean }
163b63e78fcSVladimir Oltean 
164ff1f7c17SJakub Kicinski static const struct ethtool_ops nsim_ethtool_ops = {
165a7fc6db0SAntonio Cardace 	.supported_coalesce_params	= ETHTOOL_COALESCE_ALL_PARAMS,
166f394d07bSTaehee Yoo 	.supported_ring_params		= ETHTOOL_RING_USE_TCP_DATA_SPLIT |
167f394d07bSTaehee Yoo 					  ETHTOOL_RING_USE_HDS_THRS,
168ff1f7c17SJakub Kicinski 	.get_pause_stats	        = nsim_get_pause_stats,
169ff1f7c17SJakub Kicinski 	.get_pauseparam		        = nsim_get_pauseparam,
170ff1f7c17SJakub Kicinski 	.set_pauseparam		        = nsim_set_pauseparam,
171a7fc6db0SAntonio Cardace 	.set_coalesce			= nsim_set_coalesce,
172a7fc6db0SAntonio Cardace 	.get_coalesce			= nsim_get_coalesce,
173a7fc6db0SAntonio Cardace 	.get_ringparam			= nsim_get_ringparam,
174a7fc6db0SAntonio Cardace 	.set_ringparam			= nsim_set_ringparam,
1752e367522SJakub Kicinski 	.get_channels			= nsim_get_channels,
1762e367522SJakub Kicinski 	.set_channels			= nsim_set_channels,
1770d7f76dcSJakub Kicinski 	.get_fecparam			= nsim_get_fecparam,
1780d7f76dcSJakub Kicinski 	.set_fecparam			= nsim_set_fecparam,
179f216306bSJakub Kicinski 	.get_fec_stats			= nsim_get_fec_stats,
180b63e78fcSVladimir Oltean 	.get_ts_info			= nsim_get_ts_info,
181ff1f7c17SJakub Kicinski };
182ff1f7c17SJakub Kicinski 
nsim_ethtool_ring_init(struct netdevsim * ns)183a7fc6db0SAntonio Cardace static void nsim_ethtool_ring_init(struct netdevsim *ns)
184a7fc6db0SAntonio Cardace {
185*29b036beSJakub Kicinski 	ns->ethtool.ring.rx_pending = 512;
186a7fc6db0SAntonio Cardace 	ns->ethtool.ring.rx_max_pending = 4096;
187a7fc6db0SAntonio Cardace 	ns->ethtool.ring.rx_jumbo_max_pending = 4096;
188a7fc6db0SAntonio Cardace 	ns->ethtool.ring.rx_mini_max_pending = 4096;
189*29b036beSJakub Kicinski 	ns->ethtool.ring.tx_pending = 512;
190a7fc6db0SAntonio Cardace 	ns->ethtool.ring.tx_max_pending = 4096;
191a7fc6db0SAntonio Cardace }
192a7fc6db0SAntonio Cardace 
nsim_ethtool_init(struct netdevsim * ns)193ff1f7c17SJakub Kicinski void nsim_ethtool_init(struct netdevsim *ns)
194ff1f7c17SJakub Kicinski {
195ff1f7c17SJakub Kicinski 	struct dentry *ethtool, *dir;
196ff1f7c17SJakub Kicinski 
197ff1f7c17SJakub Kicinski 	ns->netdev->ethtool_ops = &nsim_ethtool_ops;
198ff1f7c17SJakub Kicinski 
199a7fc6db0SAntonio Cardace 	nsim_ethtool_ring_init(ns);
200a7fc6db0SAntonio Cardace 
201f216306bSJakub Kicinski 	ns->ethtool.pauseparam.report_stats_rx = true;
202f216306bSJakub Kicinski 	ns->ethtool.pauseparam.report_stats_tx = true;
203f216306bSJakub Kicinski 
2040d7f76dcSJakub Kicinski 	ns->ethtool.fec.fec = ETHTOOL_FEC_NONE;
2050d7f76dcSJakub Kicinski 	ns->ethtool.fec.active_fec = ETHTOOL_FEC_NONE;
2060d7f76dcSJakub Kicinski 
2072e367522SJakub Kicinski 	ns->ethtool.channels = ns->nsim_bus_dev->num_queues;
2082e367522SJakub Kicinski 
209090bc03bSJakub Kicinski 	ethtool = debugfs_create_dir("ethtool", ns->nsim_dev_port->ddir);
210ff1f7c17SJakub Kicinski 
2110d7f76dcSJakub Kicinski 	debugfs_create_u32("get_err", 0600, ethtool, &ns->ethtool.get_err);
2120d7f76dcSJakub Kicinski 	debugfs_create_u32("set_err", 0600, ethtool, &ns->ethtool.set_err);
2130d7f76dcSJakub Kicinski 
214ff1f7c17SJakub Kicinski 	dir = debugfs_create_dir("pause", ethtool);
215ff1f7c17SJakub Kicinski 	debugfs_create_bool("report_stats_rx", 0600, dir,
21677f9591bSAntonio Cardace 			    &ns->ethtool.pauseparam.report_stats_rx);
217ff1f7c17SJakub Kicinski 	debugfs_create_bool("report_stats_tx", 0600, dir,
21877f9591bSAntonio Cardace 			    &ns->ethtool.pauseparam.report_stats_tx);
219a7fc6db0SAntonio Cardace 
220a7fc6db0SAntonio Cardace 	dir = debugfs_create_dir("ring", ethtool);
221a7fc6db0SAntonio Cardace 	debugfs_create_u32("rx_max_pending", 0600, dir,
222a7fc6db0SAntonio Cardace 			   &ns->ethtool.ring.rx_max_pending);
223a7fc6db0SAntonio Cardace 	debugfs_create_u32("rx_jumbo_max_pending", 0600, dir,
224a7fc6db0SAntonio Cardace 			   &ns->ethtool.ring.rx_jumbo_max_pending);
225a7fc6db0SAntonio Cardace 	debugfs_create_u32("rx_mini_max_pending", 0600, dir,
226a7fc6db0SAntonio Cardace 			   &ns->ethtool.ring.rx_mini_max_pending);
227a7fc6db0SAntonio Cardace 	debugfs_create_u32("tx_max_pending", 0600, dir,
228a7fc6db0SAntonio Cardace 			   &ns->ethtool.ring.tx_max_pending);
229ff1f7c17SJakub Kicinski }
230