1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (c) 2020 Facebook
4 #include <linux/debugfs.h>
5 #include <linux/ethtool.h>
6 #include <linux/random.h>
11 nsim_get_pause_stats(struct net_device
*dev
,
12 struct ethtool_pause_stats
*pause_stats
)
14 struct netdevsim
*ns
= netdev_priv(dev
);
16 if (ns
->ethtool
.pauseparam
.report_stats_rx
)
17 pause_stats
->rx_pause_frames
= 1;
18 if (ns
->ethtool
.pauseparam
.report_stats_tx
)
19 pause_stats
->tx_pause_frames
= 2;
23 nsim_get_pauseparam(struct net_device
*dev
, struct ethtool_pauseparam
*pause
)
25 struct netdevsim
*ns
= netdev_priv(dev
);
27 pause
->autoneg
= 0; /* We don't support ksettings, so can't pretend */
28 pause
->rx_pause
= ns
->ethtool
.pauseparam
.rx
;
29 pause
->tx_pause
= ns
->ethtool
.pauseparam
.tx
;
33 nsim_set_pauseparam(struct net_device
*dev
, struct ethtool_pauseparam
*pause
)
35 struct netdevsim
*ns
= netdev_priv(dev
);
40 ns
->ethtool
.pauseparam
.rx
= pause
->rx_pause
;
41 ns
->ethtool
.pauseparam
.tx
= pause
->tx_pause
;
45 static int nsim_get_coalesce(struct net_device
*dev
,
46 struct ethtool_coalesce
*coal
,
47 struct kernel_ethtool_coalesce
*kernel_coal
,
48 struct netlink_ext_ack
*extack
)
50 struct netdevsim
*ns
= netdev_priv(dev
);
52 memcpy(coal
, &ns
->ethtool
.coalesce
, sizeof(ns
->ethtool
.coalesce
));
56 static int nsim_set_coalesce(struct net_device
*dev
,
57 struct ethtool_coalesce
*coal
,
58 struct kernel_ethtool_coalesce
*kernel_coal
,
59 struct netlink_ext_ack
*extack
)
61 struct netdevsim
*ns
= netdev_priv(dev
);
63 memcpy(&ns
->ethtool
.coalesce
, coal
, sizeof(ns
->ethtool
.coalesce
));
67 static void nsim_get_ringparam(struct net_device
*dev
,
68 struct ethtool_ringparam
*ring
,
69 struct kernel_ethtool_ringparam
*kernel_ring
,
70 struct netlink_ext_ack
*extack
)
72 struct netdevsim
*ns
= netdev_priv(dev
);
74 memcpy(ring
, &ns
->ethtool
.ring
, sizeof(ns
->ethtool
.ring
));
77 static int nsim_set_ringparam(struct net_device
*dev
,
78 struct ethtool_ringparam
*ring
,
79 struct kernel_ethtool_ringparam
*kernel_ring
,
80 struct netlink_ext_ack
*extack
)
82 struct netdevsim
*ns
= netdev_priv(dev
);
84 ns
->ethtool
.ring
.rx_pending
= ring
->rx_pending
;
85 ns
->ethtool
.ring
.rx_jumbo_pending
= ring
->rx_jumbo_pending
;
86 ns
->ethtool
.ring
.rx_mini_pending
= ring
->rx_mini_pending
;
87 ns
->ethtool
.ring
.tx_pending
= ring
->tx_pending
;
92 nsim_get_channels(struct net_device
*dev
, struct ethtool_channels
*ch
)
94 struct netdevsim
*ns
= netdev_priv(dev
);
96 ch
->max_combined
= ns
->nsim_bus_dev
->num_queues
;
97 ch
->combined_count
= ns
->ethtool
.channels
;
101 nsim_set_channels(struct net_device
*dev
, struct ethtool_channels
*ch
)
103 struct netdevsim
*ns
= netdev_priv(dev
);
106 mutex_lock(&dev
->lock
);
107 err
= netif_set_real_num_queues(dev
, ch
->combined_count
,
109 mutex_unlock(&dev
->lock
);
113 ns
->ethtool
.channels
= ch
->combined_count
;
118 nsim_get_fecparam(struct net_device
*dev
, struct ethtool_fecparam
*fecparam
)
120 struct netdevsim
*ns
= netdev_priv(dev
);
122 if (ns
->ethtool
.get_err
)
123 return -ns
->ethtool
.get_err
;
124 memcpy(fecparam
, &ns
->ethtool
.fec
, sizeof(ns
->ethtool
.fec
));
129 nsim_set_fecparam(struct net_device
*dev
, struct ethtool_fecparam
*fecparam
)
131 struct netdevsim
*ns
= netdev_priv(dev
);
134 if (ns
->ethtool
.set_err
)
135 return -ns
->ethtool
.set_err
;
136 memcpy(&ns
->ethtool
.fec
, fecparam
, sizeof(ns
->ethtool
.fec
));
138 if (fec
== ETHTOOL_FEC_AUTO
)
139 fec
|= ETHTOOL_FEC_OFF
;
140 fec
|= ETHTOOL_FEC_NONE
;
141 ns
->ethtool
.fec
.active_fec
= 1 << (fls(fec
) - 1);
146 nsim_get_fec_stats(struct net_device
*dev
, struct ethtool_fec_stats
*fec_stats
)
148 fec_stats
->corrected_blocks
.total
= 123;
149 fec_stats
->uncorrectable_blocks
.total
= 4;
152 static int nsim_get_ts_info(struct net_device
*dev
,
153 struct kernel_ethtool_ts_info
*info
)
155 struct netdevsim
*ns
= netdev_priv(dev
);
157 info
->phc_index
= mock_phc_index(ns
->phc
);
162 static const struct ethtool_ops nsim_ethtool_ops
= {
163 .supported_coalesce_params
= ETHTOOL_COALESCE_ALL_PARAMS
,
164 .get_pause_stats
= nsim_get_pause_stats
,
165 .get_pauseparam
= nsim_get_pauseparam
,
166 .set_pauseparam
= nsim_set_pauseparam
,
167 .set_coalesce
= nsim_set_coalesce
,
168 .get_coalesce
= nsim_get_coalesce
,
169 .get_ringparam
= nsim_get_ringparam
,
170 .set_ringparam
= nsim_set_ringparam
,
171 .get_channels
= nsim_get_channels
,
172 .set_channels
= nsim_set_channels
,
173 .get_fecparam
= nsim_get_fecparam
,
174 .set_fecparam
= nsim_set_fecparam
,
175 .get_fec_stats
= nsim_get_fec_stats
,
176 .get_ts_info
= nsim_get_ts_info
,
179 static void nsim_ethtool_ring_init(struct netdevsim
*ns
)
181 ns
->ethtool
.ring
.rx_max_pending
= 4096;
182 ns
->ethtool
.ring
.rx_jumbo_max_pending
= 4096;
183 ns
->ethtool
.ring
.rx_mini_max_pending
= 4096;
184 ns
->ethtool
.ring
.tx_max_pending
= 4096;
187 void nsim_ethtool_init(struct netdevsim
*ns
)
189 struct dentry
*ethtool
, *dir
;
191 ns
->netdev
->ethtool_ops
= &nsim_ethtool_ops
;
193 nsim_ethtool_ring_init(ns
);
195 ns
->ethtool
.pauseparam
.report_stats_rx
= true;
196 ns
->ethtool
.pauseparam
.report_stats_tx
= true;
198 ns
->ethtool
.fec
.fec
= ETHTOOL_FEC_NONE
;
199 ns
->ethtool
.fec
.active_fec
= ETHTOOL_FEC_NONE
;
201 ns
->ethtool
.channels
= ns
->nsim_bus_dev
->num_queues
;
203 ethtool
= debugfs_create_dir("ethtool", ns
->nsim_dev_port
->ddir
);
205 debugfs_create_u32("get_err", 0600, ethtool
, &ns
->ethtool
.get_err
);
206 debugfs_create_u32("set_err", 0600, ethtool
, &ns
->ethtool
.set_err
);
208 dir
= debugfs_create_dir("pause", ethtool
);
209 debugfs_create_bool("report_stats_rx", 0600, dir
,
210 &ns
->ethtool
.pauseparam
.report_stats_rx
);
211 debugfs_create_bool("report_stats_tx", 0600, dir
,
212 &ns
->ethtool
.pauseparam
.report_stats_tx
);
214 dir
= debugfs_create_dir("ring", ethtool
);
215 debugfs_create_u32("rx_max_pending", 0600, dir
,
216 &ns
->ethtool
.ring
.rx_max_pending
);
217 debugfs_create_u32("rx_jumbo_max_pending", 0600, dir
,
218 &ns
->ethtool
.ring
.rx_jumbo_max_pending
);
219 debugfs_create_u32("rx_mini_max_pending", 0600, dir
,
220 &ns
->ethtool
.ring
.rx_mini_max_pending
);
221 debugfs_create_u32("tx_max_pending", 0600, dir
,
222 &ns
->ethtool
.ring
.tx_max_pending
);