Commit 278bc429 authored by Ben Hutchings's avatar Ben Hutchings Committed by David S. Miller

ethtool: Define and apply a default policy for RX flow hash indirection

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: default avatarMatt Carlson <mcarlson@broadcom.com>
Signed-off-by: default avatarBen Hutchings <bhutchings@solarflare.com>
Acked-by: default avatarShreyas N Bhatewara <sbhatewara@vmware.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7850f63f
...@@ -1545,7 +1545,8 @@ static inline int bnx2x_init_rss_pf(struct bnx2x *bp) ...@@ -1545,7 +1545,8 @@ static inline int bnx2x_init_rss_pf(struct bnx2x *bp)
if (bp->multi_mode != ETH_RSS_MODE_DISABLED) { if (bp->multi_mode != ETH_RSS_MODE_DISABLED) {
for (i = 0; i < sizeof(ind_table); i++) for (i = 0; i < sizeof(ind_table); i++)
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);
} }
/* /*
......
...@@ -3449,7 +3449,7 @@ static int __devinit init_rss(struct adapter *adap) ...@@ -3449,7 +3449,7 @@ static int __devinit init_rss(struct adapter *adap)
if (!pi->rss) if (!pi->rss)
return -ENOMEM; return -ENOMEM;
for (j = 0; j < pi->rss_size; j++) 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; return 0;
} }
......
...@@ -1336,7 +1336,8 @@ static int efx_probe_nic(struct efx_nic *efx) ...@@ -1336,7 +1336,8 @@ static int efx_probe_nic(struct efx_nic *efx)
if (efx->n_channels > 1) if (efx->n_channels > 1)
get_random_bytes(&efx->rx_hash_key, sizeof(efx->rx_hash_key)); get_random_bytes(&efx->rx_hash_key, sizeof(efx->rx_hash_key));
for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++) 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); efx_set_channels(efx);
netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels); netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels);
......
...@@ -2167,7 +2167,8 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter) ...@@ -2167,7 +2167,8 @@ vmxnet3_setup_driver_shared(struct vmxnet3_adapter *adapter)
rssConf->indTableSize = VMXNET3_RSS_IND_TABLE_SIZE; rssConf->indTableSize = VMXNET3_RSS_IND_TABLE_SIZE;
get_random_bytes(&rssConf->hashKey[0], rssConf->hashKeySize); get_random_bytes(&rssConf->hashKey[0], rssConf->hashKeySize);
for (i = 0; i < rssConf->indTableSize; i++) 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.confVer = 1;
devRead->rssConfDesc.confLen = sizeof(*rssConf); devRead->rssConfDesc.confLen = sizeof(*rssConf);
......
...@@ -543,10 +543,15 @@ struct compat_ethtool_rxnfc { ...@@ -543,10 +543,15 @@ struct compat_ethtool_rxnfc {
/** /**
* struct ethtool_rxfh_indir - command to get or set RX flow hash indirection * struct ethtool_rxfh_indir - command to get or set RX flow hash indirection
* @cmd: Specific command number - %ETHTOOL_GRXFHINDIR or %ETHTOOL_SRXFHINDIR * @cmd: Specific command number - %ETHTOOL_GRXFHINDIR or %ETHTOOL_SRXFHINDIR
* @size: On entry, the array size of the user buffer, which may be zero * @size: On entry, the array size of the user buffer, which may be zero.
* for %ETHTOOL_GRXFHINDIR. On return from %ETHTOOL_GRXFHINDIR, the * On return from %ETHTOOL_GRXFHINDIR, the array size of the hardware
* array size of the hardware indirection table. * indirection table.
* @ring_index: RX ring/queue index for each hash value * @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 { struct ethtool_rxfh_indir {
__u32 cmd; __u32 cmd;
...@@ -749,6 +754,18 @@ struct net_device; ...@@ -749,6 +754,18 @@ struct net_device;
/* Some generic methods drivers may use in their ethtool_ops */ /* Some generic methods drivers may use in their ethtool_ops */
u32 ethtool_op_get_link(struct net_device *dev); 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 * struct ethtool_ops - optional netdev operations
* @get_settings: Get various device settings including Ethernet link * @get_settings: Get various device settings including Ethernet link
......
...@@ -581,31 +581,38 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev, ...@@ -581,31 +581,38 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev,
sizeof(user_size))) sizeof(user_size)))
return -EFAULT; return -EFAULT;
if (user_size != dev_size) if (user_size != 0 && user_size != dev_size)
return -EINVAL; return -EINVAL;
indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER); indir = kcalloc(dev_size, sizeof(indir[0]), GFP_USER);
if (!indir) if (!indir)
return -ENOMEM; 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; rx_rings.cmd = ETHTOOL_GRXRINGS;
ret = dev->ethtool_ops->get_rxnfc(dev, &rx_rings, NULL); ret = dev->ethtool_ops->get_rxnfc(dev, &rx_rings, NULL);
if (ret) if (ret)
goto out; goto out;
for (i = 0; i < dev_size; i++) {
if (indir[i] >= rx_rings.data) { if (user_size == 0) {
ret = -EINVAL; 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; 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); ret = dev->ethtool_ops->set_rxfh_indir(dev, indir);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment