Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
0002 /* Copyright (c) 2021, Microsoft Corporation. */
0003 
0004 #include <linux/inetdevice.h>
0005 #include <linux/etherdevice.h>
0006 #include <linux/ethtool.h>
0007 
0008 #include "mana.h"
0009 
0010 static const struct {
0011     char name[ETH_GSTRING_LEN];
0012     u16 offset;
0013 } mana_eth_stats[] = {
0014     {"stop_queue", offsetof(struct mana_ethtool_stats, stop_queue)},
0015     {"wake_queue", offsetof(struct mana_ethtool_stats, wake_queue)},
0016 };
0017 
0018 static int mana_get_sset_count(struct net_device *ndev, int stringset)
0019 {
0020     struct mana_port_context *apc = netdev_priv(ndev);
0021     unsigned int num_queues = apc->num_queues;
0022 
0023     if (stringset != ETH_SS_STATS)
0024         return -EINVAL;
0025 
0026     return ARRAY_SIZE(mana_eth_stats) + num_queues * 8;
0027 }
0028 
0029 static void mana_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
0030 {
0031     struct mana_port_context *apc = netdev_priv(ndev);
0032     unsigned int num_queues = apc->num_queues;
0033     u8 *p = data;
0034     int i;
0035 
0036     if (stringset != ETH_SS_STATS)
0037         return;
0038 
0039     for (i = 0; i < ARRAY_SIZE(mana_eth_stats); i++) {
0040         memcpy(p, mana_eth_stats[i].name, ETH_GSTRING_LEN);
0041         p += ETH_GSTRING_LEN;
0042     }
0043 
0044     for (i = 0; i < num_queues; i++) {
0045         sprintf(p, "rx_%d_packets", i);
0046         p += ETH_GSTRING_LEN;
0047         sprintf(p, "rx_%d_bytes", i);
0048         p += ETH_GSTRING_LEN;
0049         sprintf(p, "rx_%d_xdp_drop", i);
0050         p += ETH_GSTRING_LEN;
0051         sprintf(p, "rx_%d_xdp_tx", i);
0052         p += ETH_GSTRING_LEN;
0053         sprintf(p, "rx_%d_xdp_redirect", i);
0054         p += ETH_GSTRING_LEN;
0055     }
0056 
0057     for (i = 0; i < num_queues; i++) {
0058         sprintf(p, "tx_%d_packets", i);
0059         p += ETH_GSTRING_LEN;
0060         sprintf(p, "tx_%d_bytes", i);
0061         p += ETH_GSTRING_LEN;
0062         sprintf(p, "tx_%d_xdp_xmit", i);
0063         p += ETH_GSTRING_LEN;
0064     }
0065 }
0066 
0067 static void mana_get_ethtool_stats(struct net_device *ndev,
0068                    struct ethtool_stats *e_stats, u64 *data)
0069 {
0070     struct mana_port_context *apc = netdev_priv(ndev);
0071     unsigned int num_queues = apc->num_queues;
0072     void *eth_stats = &apc->eth_stats;
0073     struct mana_stats_rx *rx_stats;
0074     struct mana_stats_tx *tx_stats;
0075     unsigned int start;
0076     u64 packets, bytes;
0077     u64 xdp_redirect;
0078     u64 xdp_xmit;
0079     u64 xdp_drop;
0080     u64 xdp_tx;
0081     int q, i = 0;
0082 
0083     if (!apc->port_is_up)
0084         return;
0085 
0086     for (q = 0; q < ARRAY_SIZE(mana_eth_stats); q++)
0087         data[i++] = *(u64 *)(eth_stats + mana_eth_stats[q].offset);
0088 
0089     for (q = 0; q < num_queues; q++) {
0090         rx_stats = &apc->rxqs[q]->stats;
0091 
0092         do {
0093             start = u64_stats_fetch_begin_irq(&rx_stats->syncp);
0094             packets = rx_stats->packets;
0095             bytes = rx_stats->bytes;
0096             xdp_drop = rx_stats->xdp_drop;
0097             xdp_tx = rx_stats->xdp_tx;
0098             xdp_redirect = rx_stats->xdp_redirect;
0099         } while (u64_stats_fetch_retry_irq(&rx_stats->syncp, start));
0100 
0101         data[i++] = packets;
0102         data[i++] = bytes;
0103         data[i++] = xdp_drop;
0104         data[i++] = xdp_tx;
0105         data[i++] = xdp_redirect;
0106     }
0107 
0108     for (q = 0; q < num_queues; q++) {
0109         tx_stats = &apc->tx_qp[q].txq.stats;
0110 
0111         do {
0112             start = u64_stats_fetch_begin_irq(&tx_stats->syncp);
0113             packets = tx_stats->packets;
0114             bytes = tx_stats->bytes;
0115             xdp_xmit = tx_stats->xdp_xmit;
0116         } while (u64_stats_fetch_retry_irq(&tx_stats->syncp, start));
0117 
0118         data[i++] = packets;
0119         data[i++] = bytes;
0120         data[i++] = xdp_xmit;
0121     }
0122 }
0123 
0124 static int mana_get_rxnfc(struct net_device *ndev, struct ethtool_rxnfc *cmd,
0125               u32 *rules)
0126 {
0127     struct mana_port_context *apc = netdev_priv(ndev);
0128 
0129     switch (cmd->cmd) {
0130     case ETHTOOL_GRXRINGS:
0131         cmd->data = apc->num_queues;
0132         return 0;
0133     }
0134 
0135     return -EOPNOTSUPP;
0136 }
0137 
0138 static u32 mana_get_rxfh_key_size(struct net_device *ndev)
0139 {
0140     return MANA_HASH_KEY_SIZE;
0141 }
0142 
0143 static u32 mana_rss_indir_size(struct net_device *ndev)
0144 {
0145     return MANA_INDIRECT_TABLE_SIZE;
0146 }
0147 
0148 static int mana_get_rxfh(struct net_device *ndev, u32 *indir, u8 *key,
0149              u8 *hfunc)
0150 {
0151     struct mana_port_context *apc = netdev_priv(ndev);
0152     int i;
0153 
0154     if (hfunc)
0155         *hfunc = ETH_RSS_HASH_TOP; /* Toeplitz */
0156 
0157     if (indir) {
0158         for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++)
0159             indir[i] = apc->indir_table[i];
0160     }
0161 
0162     if (key)
0163         memcpy(key, apc->hashkey, MANA_HASH_KEY_SIZE);
0164 
0165     return 0;
0166 }
0167 
0168 static int mana_set_rxfh(struct net_device *ndev, const u32 *indir,
0169              const u8 *key, const u8 hfunc)
0170 {
0171     struct mana_port_context *apc = netdev_priv(ndev);
0172     bool update_hash = false, update_table = false;
0173     u32 save_table[MANA_INDIRECT_TABLE_SIZE];
0174     u8 save_key[MANA_HASH_KEY_SIZE];
0175     int i, err;
0176 
0177     if (!apc->port_is_up)
0178         return -EOPNOTSUPP;
0179 
0180     if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
0181         return -EOPNOTSUPP;
0182 
0183     if (indir) {
0184         for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++)
0185             if (indir[i] >= apc->num_queues)
0186                 return -EINVAL;
0187 
0188         update_table = true;
0189         for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++) {
0190             save_table[i] = apc->indir_table[i];
0191             apc->indir_table[i] = indir[i];
0192         }
0193     }
0194 
0195     if (key) {
0196         update_hash = true;
0197         memcpy(save_key, apc->hashkey, MANA_HASH_KEY_SIZE);
0198         memcpy(apc->hashkey, key, MANA_HASH_KEY_SIZE);
0199     }
0200 
0201     err = mana_config_rss(apc, TRI_STATE_TRUE, update_hash, update_table);
0202 
0203     if (err) { /* recover to original values */
0204         if (update_table) {
0205             for (i = 0; i < MANA_INDIRECT_TABLE_SIZE; i++)
0206                 apc->indir_table[i] = save_table[i];
0207         }
0208 
0209         if (update_hash)
0210             memcpy(apc->hashkey, save_key, MANA_HASH_KEY_SIZE);
0211 
0212         mana_config_rss(apc, TRI_STATE_TRUE, update_hash, update_table);
0213     }
0214 
0215     return err;
0216 }
0217 
0218 static void mana_get_channels(struct net_device *ndev,
0219                   struct ethtool_channels *channel)
0220 {
0221     struct mana_port_context *apc = netdev_priv(ndev);
0222 
0223     channel->max_combined = apc->max_queues;
0224     channel->combined_count = apc->num_queues;
0225 }
0226 
0227 static int mana_set_channels(struct net_device *ndev,
0228                  struct ethtool_channels *channels)
0229 {
0230     struct mana_port_context *apc = netdev_priv(ndev);
0231     unsigned int new_count = channels->combined_count;
0232     unsigned int old_count = apc->num_queues;
0233     int err, err2;
0234 
0235     err = mana_detach(ndev, false);
0236     if (err) {
0237         netdev_err(ndev, "mana_detach failed: %d\n", err);
0238         return err;
0239     }
0240 
0241     apc->num_queues = new_count;
0242     err = mana_attach(ndev);
0243     if (!err)
0244         return 0;
0245 
0246     netdev_err(ndev, "mana_attach failed: %d\n", err);
0247 
0248     /* Try to roll it back to the old configuration. */
0249     apc->num_queues = old_count;
0250     err2 = mana_attach(ndev);
0251     if (err2)
0252         netdev_err(ndev, "mana re-attach failed: %d\n", err2);
0253 
0254     return err;
0255 }
0256 
0257 const struct ethtool_ops mana_ethtool_ops = {
0258     .get_ethtool_stats  = mana_get_ethtool_stats,
0259     .get_sset_count     = mana_get_sset_count,
0260     .get_strings        = mana_get_strings,
0261     .get_rxnfc      = mana_get_rxnfc,
0262     .get_rxfh_key_size  = mana_get_rxfh_key_size,
0263     .get_rxfh_indir_size    = mana_rss_indir_size,
0264     .get_rxfh       = mana_get_rxfh,
0265     .set_rxfh       = mana_set_rxfh,
0266     .get_channels       = mana_get_channels,
0267     .set_channels       = mana_set_channels,
0268 };