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