xref: /openbmc/linux/drivers/net/netdevsim/ethtool.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
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/ethtool.h>
6ff1f7c17SJakub Kicinski #include <linux/random.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));
75a7fc6db0SAntonio Cardace }
76a7fc6db0SAntonio Cardace 
nsim_set_ringparam(struct net_device * dev,struct ethtool_ringparam * ring,struct kernel_ethtool_ringparam * kernel_ring,struct netlink_ext_ack * extack)77a7fc6db0SAntonio Cardace static int nsim_set_ringparam(struct net_device *dev,
7874624944SHao Chen 			      struct ethtool_ringparam *ring,
7974624944SHao Chen 			      struct kernel_ethtool_ringparam *kernel_ring,
8074624944SHao Chen 			      struct netlink_ext_ack *extack)
81a7fc6db0SAntonio Cardace {
82a7fc6db0SAntonio Cardace 	struct netdevsim *ns = netdev_priv(dev);
83a7fc6db0SAntonio Cardace 
84ee60e626SFilip Pokryvka 	ns->ethtool.ring.rx_pending = ring->rx_pending;
85ee60e626SFilip Pokryvka 	ns->ethtool.ring.rx_jumbo_pending = ring->rx_jumbo_pending;
86ee60e626SFilip Pokryvka 	ns->ethtool.ring.rx_mini_pending = ring->rx_mini_pending;
87ee60e626SFilip Pokryvka 	ns->ethtool.ring.tx_pending = ring->tx_pending;
88a7fc6db0SAntonio Cardace 	return 0;
89a7fc6db0SAntonio Cardace }
90a7fc6db0SAntonio Cardace 
912e367522SJakub Kicinski static void
nsim_get_channels(struct net_device * dev,struct ethtool_channels * ch)922e367522SJakub Kicinski nsim_get_channels(struct net_device *dev, struct ethtool_channels *ch)
932e367522SJakub Kicinski {
942e367522SJakub Kicinski 	struct netdevsim *ns = netdev_priv(dev);
952e367522SJakub Kicinski 
962e367522SJakub Kicinski 	ch->max_combined = ns->nsim_bus_dev->num_queues;
972e367522SJakub Kicinski 	ch->combined_count = ns->ethtool.channels;
982e367522SJakub Kicinski }
992e367522SJakub Kicinski 
1002e367522SJakub Kicinski static int
nsim_set_channels(struct net_device * dev,struct ethtool_channels * ch)1012e367522SJakub Kicinski nsim_set_channels(struct net_device *dev, struct ethtool_channels *ch)
1022e367522SJakub Kicinski {
1032e367522SJakub Kicinski 	struct netdevsim *ns = netdev_priv(dev);
1042e367522SJakub Kicinski 	int err;
1052e367522SJakub Kicinski 
1062e367522SJakub Kicinski 	err = netif_set_real_num_queues(dev, ch->combined_count,
1072e367522SJakub Kicinski 					ch->combined_count);
1082e367522SJakub Kicinski 	if (err)
1092e367522SJakub Kicinski 		return err;
1102e367522SJakub Kicinski 
1112e367522SJakub Kicinski 	ns->ethtool.channels = ch->combined_count;
1122e367522SJakub Kicinski 	return 0;
1132e367522SJakub Kicinski }
1142e367522SJakub Kicinski 
1150d7f76dcSJakub Kicinski static int
nsim_get_fecparam(struct net_device * dev,struct ethtool_fecparam * fecparam)1160d7f76dcSJakub Kicinski nsim_get_fecparam(struct net_device *dev, struct ethtool_fecparam *fecparam)
1170d7f76dcSJakub Kicinski {
1180d7f76dcSJakub Kicinski 	struct netdevsim *ns = netdev_priv(dev);
1190d7f76dcSJakub Kicinski 
1200d7f76dcSJakub Kicinski 	if (ns->ethtool.get_err)
1210d7f76dcSJakub Kicinski 		return -ns->ethtool.get_err;
1220d7f76dcSJakub Kicinski 	memcpy(fecparam, &ns->ethtool.fec, sizeof(ns->ethtool.fec));
1230d7f76dcSJakub Kicinski 	return 0;
1240d7f76dcSJakub Kicinski }
1250d7f76dcSJakub Kicinski 
1260d7f76dcSJakub Kicinski static int
nsim_set_fecparam(struct net_device * dev,struct ethtool_fecparam * fecparam)1270d7f76dcSJakub Kicinski nsim_set_fecparam(struct net_device *dev, struct ethtool_fecparam *fecparam)
1280d7f76dcSJakub Kicinski {
1290d7f76dcSJakub Kicinski 	struct netdevsim *ns = netdev_priv(dev);
1300d7f76dcSJakub Kicinski 	u32 fec;
1310d7f76dcSJakub Kicinski 
1320d7f76dcSJakub Kicinski 	if (ns->ethtool.set_err)
1330d7f76dcSJakub Kicinski 		return -ns->ethtool.set_err;
1340d7f76dcSJakub Kicinski 	memcpy(&ns->ethtool.fec, fecparam, sizeof(ns->ethtool.fec));
1350d7f76dcSJakub Kicinski 	fec = fecparam->fec;
1360d7f76dcSJakub Kicinski 	if (fec == ETHTOOL_FEC_AUTO)
1370d7f76dcSJakub Kicinski 		fec |= ETHTOOL_FEC_OFF;
1380d7f76dcSJakub Kicinski 	fec |= ETHTOOL_FEC_NONE;
1390d7f76dcSJakub Kicinski 	ns->ethtool.fec.active_fec = 1 << (fls(fec) - 1);
1400d7f76dcSJakub Kicinski 	return 0;
1410d7f76dcSJakub Kicinski }
1420d7f76dcSJakub Kicinski 
nsim_get_ts_info(struct net_device * dev,struct ethtool_ts_info * info)143*b63e78fcSVladimir Oltean static int nsim_get_ts_info(struct net_device *dev,
144*b63e78fcSVladimir Oltean 			    struct ethtool_ts_info *info)
145*b63e78fcSVladimir Oltean {
146*b63e78fcSVladimir Oltean 	struct netdevsim *ns = netdev_priv(dev);
147*b63e78fcSVladimir Oltean 
148*b63e78fcSVladimir Oltean 	info->phc_index = mock_phc_index(ns->phc);
149*b63e78fcSVladimir Oltean 
150*b63e78fcSVladimir Oltean 	return 0;
151*b63e78fcSVladimir Oltean }
152*b63e78fcSVladimir Oltean 
153ff1f7c17SJakub Kicinski static const struct ethtool_ops nsim_ethtool_ops = {
154a7fc6db0SAntonio Cardace 	.supported_coalesce_params	= ETHTOOL_COALESCE_ALL_PARAMS,
155ff1f7c17SJakub Kicinski 	.get_pause_stats	        = nsim_get_pause_stats,
156ff1f7c17SJakub Kicinski 	.get_pauseparam		        = nsim_get_pauseparam,
157ff1f7c17SJakub Kicinski 	.set_pauseparam		        = nsim_set_pauseparam,
158a7fc6db0SAntonio Cardace 	.set_coalesce			= nsim_set_coalesce,
159a7fc6db0SAntonio Cardace 	.get_coalesce			= nsim_get_coalesce,
160a7fc6db0SAntonio Cardace 	.get_ringparam			= nsim_get_ringparam,
161a7fc6db0SAntonio Cardace 	.set_ringparam			= nsim_set_ringparam,
1622e367522SJakub Kicinski 	.get_channels			= nsim_get_channels,
1632e367522SJakub Kicinski 	.set_channels			= nsim_set_channels,
1640d7f76dcSJakub Kicinski 	.get_fecparam			= nsim_get_fecparam,
1650d7f76dcSJakub Kicinski 	.set_fecparam			= nsim_set_fecparam,
166*b63e78fcSVladimir Oltean 	.get_ts_info			= nsim_get_ts_info,
167ff1f7c17SJakub Kicinski };
168ff1f7c17SJakub Kicinski 
nsim_ethtool_ring_init(struct netdevsim * ns)169a7fc6db0SAntonio Cardace static void nsim_ethtool_ring_init(struct netdevsim *ns)
170a7fc6db0SAntonio Cardace {
171a7fc6db0SAntonio Cardace 	ns->ethtool.ring.rx_max_pending = 4096;
172a7fc6db0SAntonio Cardace 	ns->ethtool.ring.rx_jumbo_max_pending = 4096;
173a7fc6db0SAntonio Cardace 	ns->ethtool.ring.rx_mini_max_pending = 4096;
174a7fc6db0SAntonio Cardace 	ns->ethtool.ring.tx_max_pending = 4096;
175a7fc6db0SAntonio Cardace }
176a7fc6db0SAntonio Cardace 
nsim_ethtool_init(struct netdevsim * ns)177ff1f7c17SJakub Kicinski void nsim_ethtool_init(struct netdevsim *ns)
178ff1f7c17SJakub Kicinski {
179ff1f7c17SJakub Kicinski 	struct dentry *ethtool, *dir;
180ff1f7c17SJakub Kicinski 
181ff1f7c17SJakub Kicinski 	ns->netdev->ethtool_ops = &nsim_ethtool_ops;
182ff1f7c17SJakub Kicinski 
183a7fc6db0SAntonio Cardace 	nsim_ethtool_ring_init(ns);
184a7fc6db0SAntonio Cardace 
1850d7f76dcSJakub Kicinski 	ns->ethtool.fec.fec = ETHTOOL_FEC_NONE;
1860d7f76dcSJakub Kicinski 	ns->ethtool.fec.active_fec = ETHTOOL_FEC_NONE;
1870d7f76dcSJakub Kicinski 
1882e367522SJakub Kicinski 	ns->ethtool.channels = ns->nsim_bus_dev->num_queues;
1892e367522SJakub Kicinski 
190090bc03bSJakub Kicinski 	ethtool = debugfs_create_dir("ethtool", ns->nsim_dev_port->ddir);
191ff1f7c17SJakub Kicinski 
1920d7f76dcSJakub Kicinski 	debugfs_create_u32("get_err", 0600, ethtool, &ns->ethtool.get_err);
1930d7f76dcSJakub Kicinski 	debugfs_create_u32("set_err", 0600, ethtool, &ns->ethtool.set_err);
1940d7f76dcSJakub Kicinski 
195ff1f7c17SJakub Kicinski 	dir = debugfs_create_dir("pause", ethtool);
196ff1f7c17SJakub Kicinski 	debugfs_create_bool("report_stats_rx", 0600, dir,
19777f9591bSAntonio Cardace 			    &ns->ethtool.pauseparam.report_stats_rx);
198ff1f7c17SJakub Kicinski 	debugfs_create_bool("report_stats_tx", 0600, dir,
19977f9591bSAntonio Cardace 			    &ns->ethtool.pauseparam.report_stats_tx);
200a7fc6db0SAntonio Cardace 
201a7fc6db0SAntonio Cardace 	dir = debugfs_create_dir("ring", ethtool);
202a7fc6db0SAntonio Cardace 	debugfs_create_u32("rx_max_pending", 0600, dir,
203a7fc6db0SAntonio Cardace 			   &ns->ethtool.ring.rx_max_pending);
204a7fc6db0SAntonio Cardace 	debugfs_create_u32("rx_jumbo_max_pending", 0600, dir,
205a7fc6db0SAntonio Cardace 			   &ns->ethtool.ring.rx_jumbo_max_pending);
206a7fc6db0SAntonio Cardace 	debugfs_create_u32("rx_mini_max_pending", 0600, dir,
207a7fc6db0SAntonio Cardace 			   &ns->ethtool.ring.rx_mini_max_pending);
208a7fc6db0SAntonio Cardace 	debugfs_create_u32("tx_max_pending", 0600, dir,
209a7fc6db0SAntonio Cardace 			   &ns->ethtool.ring.tx_max_pending);
210ff1f7c17SJakub Kicinski }
211