0001
0002
0003
0004 #include <linux/debugfs.h>
0005 #include <linux/ethtool.h>
0006 #include <linux/random.h>
0007
0008 #include "netdevsim.h"
0009
0010 static void
0011 nsim_get_pause_stats(struct net_device *dev,
0012 struct ethtool_pause_stats *pause_stats)
0013 {
0014 struct netdevsim *ns = netdev_priv(dev);
0015
0016 if (ns->ethtool.pauseparam.report_stats_rx)
0017 pause_stats->rx_pause_frames = 1;
0018 if (ns->ethtool.pauseparam.report_stats_tx)
0019 pause_stats->tx_pause_frames = 2;
0020 }
0021
0022 static void
0023 nsim_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause)
0024 {
0025 struct netdevsim *ns = netdev_priv(dev);
0026
0027 pause->autoneg = 0;
0028 pause->rx_pause = ns->ethtool.pauseparam.rx;
0029 pause->tx_pause = ns->ethtool.pauseparam.tx;
0030 }
0031
0032 static int
0033 nsim_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *pause)
0034 {
0035 struct netdevsim *ns = netdev_priv(dev);
0036
0037 if (pause->autoneg)
0038 return -EINVAL;
0039
0040 ns->ethtool.pauseparam.rx = pause->rx_pause;
0041 ns->ethtool.pauseparam.tx = pause->tx_pause;
0042 return 0;
0043 }
0044
0045 static int nsim_get_coalesce(struct net_device *dev,
0046 struct ethtool_coalesce *coal,
0047 struct kernel_ethtool_coalesce *kernel_coal,
0048 struct netlink_ext_ack *extack)
0049 {
0050 struct netdevsim *ns = netdev_priv(dev);
0051
0052 memcpy(coal, &ns->ethtool.coalesce, sizeof(ns->ethtool.coalesce));
0053 return 0;
0054 }
0055
0056 static int nsim_set_coalesce(struct net_device *dev,
0057 struct ethtool_coalesce *coal,
0058 struct kernel_ethtool_coalesce *kernel_coal,
0059 struct netlink_ext_ack *extack)
0060 {
0061 struct netdevsim *ns = netdev_priv(dev);
0062
0063 memcpy(&ns->ethtool.coalesce, coal, sizeof(ns->ethtool.coalesce));
0064 return 0;
0065 }
0066
0067 static void nsim_get_ringparam(struct net_device *dev,
0068 struct ethtool_ringparam *ring,
0069 struct kernel_ethtool_ringparam *kernel_ring,
0070 struct netlink_ext_ack *extack)
0071 {
0072 struct netdevsim *ns = netdev_priv(dev);
0073
0074 memcpy(ring, &ns->ethtool.ring, sizeof(ns->ethtool.ring));
0075 }
0076
0077 static int nsim_set_ringparam(struct net_device *dev,
0078 struct ethtool_ringparam *ring,
0079 struct kernel_ethtool_ringparam *kernel_ring,
0080 struct netlink_ext_ack *extack)
0081 {
0082 struct netdevsim *ns = netdev_priv(dev);
0083
0084 ns->ethtool.ring.rx_pending = ring->rx_pending;
0085 ns->ethtool.ring.rx_jumbo_pending = ring->rx_jumbo_pending;
0086 ns->ethtool.ring.rx_mini_pending = ring->rx_mini_pending;
0087 ns->ethtool.ring.tx_pending = ring->tx_pending;
0088 return 0;
0089 }
0090
0091 static void
0092 nsim_get_channels(struct net_device *dev, struct ethtool_channels *ch)
0093 {
0094 struct netdevsim *ns = netdev_priv(dev);
0095
0096 ch->max_combined = ns->nsim_bus_dev->num_queues;
0097 ch->combined_count = ns->ethtool.channels;
0098 }
0099
0100 static int
0101 nsim_set_channels(struct net_device *dev, struct ethtool_channels *ch)
0102 {
0103 struct netdevsim *ns = netdev_priv(dev);
0104 int err;
0105
0106 err = netif_set_real_num_queues(dev, ch->combined_count,
0107 ch->combined_count);
0108 if (err)
0109 return err;
0110
0111 ns->ethtool.channels = ch->combined_count;
0112 return 0;
0113 }
0114
0115 static int
0116 nsim_get_fecparam(struct net_device *dev, struct ethtool_fecparam *fecparam)
0117 {
0118 struct netdevsim *ns = netdev_priv(dev);
0119
0120 if (ns->ethtool.get_err)
0121 return -ns->ethtool.get_err;
0122 memcpy(fecparam, &ns->ethtool.fec, sizeof(ns->ethtool.fec));
0123 return 0;
0124 }
0125
0126 static int
0127 nsim_set_fecparam(struct net_device *dev, struct ethtool_fecparam *fecparam)
0128 {
0129 struct netdevsim *ns = netdev_priv(dev);
0130 u32 fec;
0131
0132 if (ns->ethtool.set_err)
0133 return -ns->ethtool.set_err;
0134 memcpy(&ns->ethtool.fec, fecparam, sizeof(ns->ethtool.fec));
0135 fec = fecparam->fec;
0136 if (fec == ETHTOOL_FEC_AUTO)
0137 fec |= ETHTOOL_FEC_OFF;
0138 fec |= ETHTOOL_FEC_NONE;
0139 ns->ethtool.fec.active_fec = 1 << (fls(fec) - 1);
0140 return 0;
0141 }
0142
0143 static const struct ethtool_ops nsim_ethtool_ops = {
0144 .supported_coalesce_params = ETHTOOL_COALESCE_ALL_PARAMS,
0145 .get_pause_stats = nsim_get_pause_stats,
0146 .get_pauseparam = nsim_get_pauseparam,
0147 .set_pauseparam = nsim_set_pauseparam,
0148 .set_coalesce = nsim_set_coalesce,
0149 .get_coalesce = nsim_get_coalesce,
0150 .get_ringparam = nsim_get_ringparam,
0151 .set_ringparam = nsim_set_ringparam,
0152 .get_channels = nsim_get_channels,
0153 .set_channels = nsim_set_channels,
0154 .get_fecparam = nsim_get_fecparam,
0155 .set_fecparam = nsim_set_fecparam,
0156 };
0157
0158 static void nsim_ethtool_ring_init(struct netdevsim *ns)
0159 {
0160 ns->ethtool.ring.rx_max_pending = 4096;
0161 ns->ethtool.ring.rx_jumbo_max_pending = 4096;
0162 ns->ethtool.ring.rx_mini_max_pending = 4096;
0163 ns->ethtool.ring.tx_max_pending = 4096;
0164 }
0165
0166 void nsim_ethtool_init(struct netdevsim *ns)
0167 {
0168 struct dentry *ethtool, *dir;
0169
0170 ns->netdev->ethtool_ops = &nsim_ethtool_ops;
0171
0172 nsim_ethtool_ring_init(ns);
0173
0174 ns->ethtool.fec.fec = ETHTOOL_FEC_NONE;
0175 ns->ethtool.fec.active_fec = ETHTOOL_FEC_NONE;
0176
0177 ns->ethtool.channels = ns->nsim_bus_dev->num_queues;
0178
0179 ethtool = debugfs_create_dir("ethtool", ns->nsim_dev_port->ddir);
0180
0181 debugfs_create_u32("get_err", 0600, ethtool, &ns->ethtool.get_err);
0182 debugfs_create_u32("set_err", 0600, ethtool, &ns->ethtool.set_err);
0183
0184 dir = debugfs_create_dir("pause", ethtool);
0185 debugfs_create_bool("report_stats_rx", 0600, dir,
0186 &ns->ethtool.pauseparam.report_stats_rx);
0187 debugfs_create_bool("report_stats_tx", 0600, dir,
0188 &ns->ethtool.pauseparam.report_stats_tx);
0189
0190 dir = debugfs_create_dir("ring", ethtool);
0191 debugfs_create_u32("rx_max_pending", 0600, dir,
0192 &ns->ethtool.ring.rx_max_pending);
0193 debugfs_create_u32("rx_jumbo_max_pending", 0600, dir,
0194 &ns->ethtool.ring.rx_jumbo_max_pending);
0195 debugfs_create_u32("rx_mini_max_pending", 0600, dir,
0196 &ns->ethtool.ring.rx_mini_max_pending);
0197 debugfs_create_u32("tx_max_pending", 0600, dir,
0198 &ns->ethtool.ring.tx_max_pending);
0199 }