ethtool: Define and apply a default policy for RX flow hash indirection
authorBen Hutchings <bhutchings@solarflare.com>
Thu, 15 Dec 2011 13:56:49 +0000 (13:56 +0000)
committerDavid S. Miller <davem@davemloft.net>
Fri, 16 Dec 2011 18:53:18 +0000 (13:53 -0500)
All drivers that support modification of the RX flow hash indirection
table initialise it in the same way: RX rings are assigned to table
entries in rotation.  Make that default policy explicit by having them
call a ethtool_rxfh_indir_default() function.

In the ethtool core, add support for a zero size value for
ETHTOOL_SRXFHINDIR, which resets the table to this default.

Partly-suggested-by: Matt Carlson <mcarlson@broadcom.com>
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Acked-by: Shreyas N Bhatewara <sbhatewara@vmware.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
drivers/net/ethernet/sfc/efx.c
drivers/net/vmxnet3/vmxnet3_drv.c
include/linux/ethtool.h
net/core/ethtool.c

index 64f5cf5c68d1dc4744718e1a369fe36ee522e92a..2b731b253598e9f94da434cdd322cfd197b0cb74 100644 (file)
@@ -1545,7 +1545,8 @@ static inline int bnx2x_init_rss_pf(struct bnx2x *bp)
        if (bp->multi_mode != ETH_RSS_MODE_DISABLED) {
                for (i = 0; i < sizeof(ind_table); i++)
                        ind_table[i] =
-                               bp->fp->cl_id + (i % num_eth_queues);
+                               bp->fp->cl_id +
+                               ethtool_rxfh_indir_default(i, num_eth_queues);
        }
 
        /*
index 8ffd55bdef3d168b566d0b72987696d2105d068c..fccbe490c7f094f3aa047680e7facf583cf2aff8 100644 (file)
@@ -3449,7 +3449,7 @@ static int __devinit init_rss(struct adapter *adap)
                if (!pi->rss)
                        return -ENOMEM;
                for (j = 0; j < pi->rss_size; j++)
-                       pi->rss[j] = j % pi->nqsets;
+                       pi->rss[j] = ethtool_rxfh_indir_default(j, pi->nqsets);
        }
        return 0;
 }
index 14e134d3b4d716704855fb23efa03d0375a8a80f..44a82c6c60a71a48247947e7d0b88333e8b14647 100644 (file)
@@ -1336,7 +1336,8 @@ static int efx_probe_nic(struct efx_nic *efx)
        if (efx->n_channels > 1)
                get_random_bytes(&efx->rx_hash_key, sizeof(efx->rx_hash_key));
        for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++)
-               efx->rx_indir_table[i] = i % efx->n_rx_channels;
+               efx->rx_indir_table[i] =
+                       ethtool_rxfh_indir_default(i, efx->n_rx_channels);
 
        efx_set_channels(efx);
        netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels);
index 1c2ae11a9e3562052e02c2ff278de057f4c69113..de7fc345148a889a772c9b208dd56137519fe7e1 100644 (file)
@@ -2167,7 +2167,8 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
                rssConf->indTableSize = VMXNET3_RSS_IND_TABLE_SIZE;
                get_random_bytes(&rssConf->hashKey[0], rssConf->hashKeySize);
                for (i = 0; i < rssConf->indTableSize; i++)
-                       rssConf->indTable[i] = i % adapter->num_rx_queues;
+                       rssConf->indTable[i] = ethtool_rxfh_indir_default(
+                               i, adapter->num_rx_queues);
 
                devRead->rssConfDesc.confVer = 1;
                devRead->rssConfDesc.confLen = sizeof(*rssConf);
index 3b9f09d55b5c4d3fda14b9d3accf2d2a0f507c29..b38bf69310eeac115e6982d7aca255b7dd1bb155 100644 (file)
@@ -543,10 +543,15 @@ struct compat_ethtool_rxnfc {
 /**
  * struct ethtool_rxfh_indir - command to get or set RX flow hash indirection
  * @cmd: Specific command number - %ETHTOOL_GRXFHINDIR or %ETHTOOL_SRXFHINDIR
- * @size: On entry, the array size of the user buffer, which may be zero
- *     for %ETHTOOL_GRXFHINDIR.  On return from %ETHTOOL_GRXFHINDIR, the
- *     array size of the hardware indirection table.
+ * @size: On entry, the array size of the user buffer, which may be zero.
+ *     On return from %ETHTOOL_GRXFHINDIR, the array size of the hardware
+ *     indirection table.
  * @ring_index: RX ring/queue index for each hash value
+ *
+ * For %ETHTOOL_GRXFHINDIR, a @size of zero means that only the size
+ * should be returned.  For %ETHTOOL_SRXFHINDIR, a @size of zero means
+ * the table should be reset to default values.  This last feature
+ * is not supported by the original implementations.
  */
 struct ethtool_rxfh_indir {
        __u32   cmd;
@@ -749,6 +754,18 @@ struct net_device;
 /* Some generic methods drivers may use in their ethtool_ops */
 u32 ethtool_op_get_link(struct net_device *dev);
 
+/**
+ * ethtool_rxfh_indir_default - get default value for RX flow hash indirection
+ * @index: Index in RX flow hash indirection table
+ * @n_rx_rings: Number of RX rings to use
+ *
+ * This function provides the default policy for RX flow hash indirection.
+ */
+static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings)
+{
+       return index % n_rx_rings;
+}
+
 /**
  * struct ethtool_ops - optional netdev operations
  * @get_settings: Get various device settings including Ethernet link
index 69f71b86b0351d5b66b5f65348f17b8257042420..597732c989ca9deddcbe0788237514ceb2db9eb0 100644 (file)
@@ -581,31 +581,38 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
                           sizeof(user_size)))
                return -EFAULT;
 
-       if (user_size != dev_size)
+       if (user_size != 0 && user_size != dev_size)
                return -EINVAL;
 
        indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER);
        if (!indir)
                return -ENOMEM;
 
-       if (copy_from_user(indir,
-                          useraddr +
-                          offsetof(struct ethtool_rxfh_indir, ring_index[0]),
-                          dev_size * sizeof(indir[0]))) {
-               ret = -EFAULT;
-               goto out;
-       }
-
-       /* Validate ring indices */
        rx_rings.cmd = ETHTOOL_GRXRINGS;
        ret = dev->ethtool_ops->get_rxnfc(dev, &rx_rings, NULL);
        if (ret)
                goto out;
-       for (i = 0; i < dev_size; i++) {
-               if (indir[i] >= rx_rings.data) {
-                       ret = -EINVAL;
+
+       if (user_size == 0) {
+               for (i = 0; i < dev_size; i++)
+                       indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data);
+       } else {
+               if (copy_from_user(indir,
+                                 useraddr +
+                                 offsetof(struct ethtool_rxfh_indir,
+                                          ring_index[0]),
+                                 dev_size * sizeof(indir[0]))) {
+                       ret = -EFAULT;
                        goto out;
                }
+
+               /* Validate ring indices */
+               for (i = 0; i < dev_size; i++) {
+                       if (indir[i] >= rx_rings.data) {
+                               ret = -EINVAL;
+                               goto out;
+                       }
+               }
        }
 
        ret = dev->ethtool_ops->set_rxfh_indir(dev, indir);