File Index
Files and directories
Sign in
FILE

ethtool.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/netdevsim/ethtool.c C
  1// SPDX-License-Identifier: GPL-2.0
  2// Copyright (c) 2020 Facebook
  3
  4#include <linux/debugfs.h>
  5#include <linux/random.h>
  6#include <net/netdev_queues.h>
  7
  8#include "netdevsim.h"
  9
 10static void
 11nsim_get_pause_stats(struct net_device *dev,
 12		     struct ethtool_pause_stats *pause_stats)
 13{
 14	struct netdevsim *ns = netdev_priv(dev);
 15
 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;
 20}
 21
 22static void
 23nsim_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause)
 24{
 25	struct netdevsim *ns = netdev_priv(dev);
 26
 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;
 30}
 31
 32static int
 33nsim_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause)
 34{
 35	struct netdevsim *ns = netdev_priv(dev);
 36
 37	if (pause->autoneg)
 38		return -EINVAL;
 39
 40	ns->ethtool.pauseparam.rx = pause->rx_pause;
 41	ns->ethtool.pauseparam.tx = pause->tx_pause;
 42	return 0;
 43}
 44
 45static 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)
 49{
 50	struct netdevsim *ns = netdev_priv(dev);
 51
 52	memcpy(coal, &ns->ethtool.coalesce, sizeof(ns->ethtool.coalesce));
 53	return 0;
 54}
 55
 56static 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)
 60{
 61	struct netdevsim *ns = netdev_priv(dev);
 62
 63	memcpy(&ns->ethtool.coalesce, coal, sizeof(ns->ethtool.coalesce));
 64	return 0;
 65}
 66
 67static 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)
 71{
 72	struct netdevsim *ns = netdev_priv(dev);
 73
 74	memcpy(ring, &ns->ethtool.ring, sizeof(ns->ethtool.ring));
 75	kernel_ring->hds_thresh_max = NSIM_HDS_THRESHOLD_MAX;
 76
 77	if (dev->cfg->hds_config == ETHTOOL_TCP_DATA_SPLIT_UNKNOWN)
 78		kernel_ring->tcp_data_split = ETHTOOL_TCP_DATA_SPLIT_ENABLED;
 79}
 80
 81static int nsim_set_ringparam(struct net_device *dev,
 82			      struct ethtool_ringparam *ring,
 83			      struct kernel_ethtool_ringparam *kernel_ring,
 84			      struct netlink_ext_ack *extack)
 85{
 86	struct netdevsim *ns = netdev_priv(dev);
 87
 88	ns->ethtool.ring.rx_pending = ring->rx_pending;
 89	ns->ethtool.ring.rx_jumbo_pending = ring->rx_jumbo_pending;
 90	ns->ethtool.ring.rx_mini_pending = ring->rx_mini_pending;
 91	ns->ethtool.ring.tx_pending = ring->tx_pending;
 92	return 0;
 93}
 94
 95static void
 96nsim_get_channels(struct net_device *dev, struct ethtool_channels *ch)
 97{
 98	struct netdevsim *ns = netdev_priv(dev);
 99
100	ch->max_combined = ns->nsim_bus_dev->num_queues;
101	ch->combined_count = ns->ethtool.channels;
102}
103
104static void
105nsim_wake_queues(struct net_device *dev)
106{
107	struct netdevsim *ns = netdev_priv(dev);
108	struct netdevsim *peer;
109
110	synchronize_net();
111	netif_tx_wake_all_queues(dev);
112
113	rcu_read_lock();
114	peer = rcu_dereference(ns->peer);
115	if (peer)
116		netif_tx_wake_all_queues(peer->netdev);
117	rcu_read_unlock();
118}
119
120static int
121nsim_set_channels(struct net_device *dev, struct ethtool_channels *ch)
122{
123	struct netdevsim *ns = netdev_priv(dev);
124	int err;
125
126	err = netif_set_real_num_queues(dev, ch->combined_count,
127					ch->combined_count);
128	if (err)
129		return err;
130
131	ns->ethtool.channels = ch->combined_count;
132
133	/* Only wake up queues if devices are linked */
134	if (rcu_access_pointer(ns->peer))
135		nsim_wake_queues(dev);
136
137	return 0;
138}
139
140static int
141nsim_get_fecparam(struct net_device *dev, struct ethtool_fecparam *fecparam)
142{
143	struct netdevsim *ns = netdev_priv(dev);
144
145	if (ns->ethtool.get_err)
146		return -ns->ethtool.get_err;
147	memcpy(fecparam, &ns->ethtool.fec, sizeof(ns->ethtool.fec));
148	return 0;
149}
150
151static int
152nsim_set_fecparam(struct net_device *dev, struct ethtool_fecparam *fecparam)
153{
154	struct netdevsim *ns = netdev_priv(dev);
155	u32 fec;
156
157	if (ns->ethtool.set_err)
158		return -ns->ethtool.set_err;
159	memcpy(&ns->ethtool.fec, fecparam, sizeof(ns->ethtool.fec));
160	fec = fecparam->fec;
161	if (fec == ETHTOOL_FEC_AUTO)
162		fec |= ETHTOOL_FEC_OFF;
163	fec |= ETHTOOL_FEC_NONE;
164	ns->ethtool.fec.active_fec = 1 << (fls(fec) - 1);
165	return 0;
166}
167
168static const struct ethtool_fec_hist_range netdevsim_fec_ranges[] = {
169	{ 0, 0},
170	{ 1, 3},
171	{ 4, 7},
172	{ 0, 0}
173};
174
175static void
176nsim_get_fec_stats(struct net_device *dev, struct ethtool_fec_stats *fec_stats,
177		   struct ethtool_fec_hist *hist)
178{
179	struct ethtool_fec_hist_value *values = hist->values;
180
181	hist->ranges = netdevsim_fec_ranges;
182
183	fec_stats->corrected_blocks.total = 123;
184	fec_stats->uncorrectable_blocks.total = 4;
185
186	values[0].per_lane[0] = 125;
187	values[0].per_lane[1] = 120;
188	values[0].per_lane[2] = 100;
189	values[0].per_lane[3] = 100;
190	values[1].sum = 12;
191	values[2].sum = 2;
192	values[2].per_lane[0] = 2;
193	values[2].per_lane[1] = 0;
194	values[2].per_lane[2] = 0;
195	values[2].per_lane[3] = 0;
196}
197
198static int nsim_get_ts_info(struct net_device *dev,
199			    struct kernel_ethtool_ts_info *info)
200{
201	struct netdevsim *ns = netdev_priv(dev);
202
203	info->phc_index = mock_phc_index(ns->phc);
204
205	return 0;
206}
207
208static const struct ethtool_ops nsim_ethtool_ops = {
209	.supported_coalesce_params	= ETHTOOL_COALESCE_ALL_PARAMS,
210	.supported_ring_params		= ETHTOOL_RING_USE_TCP_DATA_SPLIT |
211					  ETHTOOL_RING_USE_HDS_THRS,
212	.get_pause_stats	        = nsim_get_pause_stats,
213	.get_pauseparam		        = nsim_get_pauseparam,
214	.set_pauseparam		        = nsim_set_pauseparam,
215	.set_coalesce			= nsim_set_coalesce,
216	.get_coalesce			= nsim_get_coalesce,
217	.get_ringparam			= nsim_get_ringparam,
218	.set_ringparam			= nsim_set_ringparam,
219	.get_channels			= nsim_get_channels,
220	.set_channels			= nsim_set_channels,
221	.get_fecparam			= nsim_get_fecparam,
222	.set_fecparam			= nsim_set_fecparam,
223	.get_fec_stats			= nsim_get_fec_stats,
224	.get_ts_info			= nsim_get_ts_info,
225};
226
227static void nsim_ethtool_ring_init(struct netdevsim *ns)
228{
229	ns->ethtool.ring.rx_pending = 512;
230	ns->ethtool.ring.rx_max_pending = 4096;
231	ns->ethtool.ring.rx_jumbo_max_pending = 4096;
232	ns->ethtool.ring.rx_mini_max_pending = 4096;
233	ns->ethtool.ring.tx_pending = 512;
234	ns->ethtool.ring.tx_max_pending = 4096;
235}
236
237void nsim_ethtool_init(struct netdevsim *ns)
238{
239	struct dentry *ethtool, *dir;
240
241	ns->netdev->ethtool_ops = &nsim_ethtool_ops;
242
243	nsim_ethtool_ring_init(ns);
244
245	ns->ethtool.pauseparam.report_stats_rx = true;
246	ns->ethtool.pauseparam.report_stats_tx = true;
247
248	ns->ethtool.fec.fec = ETHTOOL_FEC_NONE;
249	ns->ethtool.fec.active_fec = ETHTOOL_FEC_NONE;
250
251	ns->ethtool.channels = ns->nsim_bus_dev->num_queues;
252
253	ethtool = debugfs_create_dir("ethtool", ns->nsim_dev_port->ddir);
254
255	debugfs_create_u32("get_err", 0600, ethtool, &ns->ethtool.get_err);
256	debugfs_create_u32("set_err", 0600, ethtool, &ns->ethtool.set_err);
257
258	dir = debugfs_create_dir("pause", ethtool);
259	debugfs_create_bool("report_stats_rx", 0600, dir,
260			    &ns->ethtool.pauseparam.report_stats_rx);
261	debugfs_create_bool("report_stats_tx", 0600, dir,
262			    &ns->ethtool.pauseparam.report_stats_tx);
263
264	dir = debugfs_create_dir("ring", ethtool);
265	debugfs_create_u32("rx_max_pending", 0600, dir,
266			   &ns->ethtool.ring.rx_max_pending);
267	debugfs_create_u32("rx_jumbo_max_pending", 0600, dir,
268			   &ns->ethtool.ring.rx_jumbo_max_pending);
269	debugfs_create_u32("rx_mini_max_pending", 0600, dir,
270			   &ns->ethtool.ring.rx_mini_max_pending);
271	debugfs_create_u32("tx_max_pending", 0600, dir,
272			   &ns->ethtool.ring.tx_max_pending);
273}
~/ Read-only file preview.