Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 // Copyright (c) 2020 Facebook
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; /* We don't support ksettings, so can't pretend */
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 }