sfc: Add support for RX flow hash control
Allow ethtool to query the number of RX rings, the fields used in RX flow hashing and the hash indirection table. Allow ethtool to update the RX flow hash indirection table. Signed-off-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
a5b6ee291e
commit
765c9f4686
5 changed files with 105 additions and 10 deletions
|
@ -868,6 +868,93 @@ extern int efx_ethtool_reset(struct net_device *net_dev, u32 *flags)
|
|||
return efx_reset(efx, method);
|
||||
}
|
||||
|
||||
static int
|
||||
efx_ethtool_get_rxnfc(struct net_device *net_dev,
|
||||
struct ethtool_rxnfc *info, void *rules __always_unused)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
|
||||
switch (info->cmd) {
|
||||
case ETHTOOL_GRXRINGS:
|
||||
info->data = efx->n_rx_channels;
|
||||
return 0;
|
||||
|
||||
case ETHTOOL_GRXFH: {
|
||||
unsigned min_revision = 0;
|
||||
|
||||
info->data = 0;
|
||||
switch (info->flow_type) {
|
||||
case TCP_V4_FLOW:
|
||||
info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
/* fall through */
|
||||
case UDP_V4_FLOW:
|
||||
case SCTP_V4_FLOW:
|
||||
case AH_ESP_V4_FLOW:
|
||||
case IPV4_FLOW:
|
||||
info->data |= RXH_IP_SRC | RXH_IP_DST;
|
||||
min_revision = EFX_REV_FALCON_B0;
|
||||
break;
|
||||
case TCP_V6_FLOW:
|
||||
info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
/* fall through */
|
||||
case UDP_V6_FLOW:
|
||||
case SCTP_V6_FLOW:
|
||||
case AH_ESP_V6_FLOW:
|
||||
case IPV6_FLOW:
|
||||
info->data |= RXH_IP_SRC | RXH_IP_DST;
|
||||
min_revision = EFX_REV_SIENA_A0;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (efx_nic_rev(efx) < min_revision)
|
||||
info->data = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
}
|
||||
|
||||
static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev,
|
||||
struct ethtool_rxfh_indir *indir)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
size_t copy_size =
|
||||
min_t(size_t, indir->size, ARRAY_SIZE(efx->rx_indir_table));
|
||||
|
||||
if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
indir->size = ARRAY_SIZE(efx->rx_indir_table);
|
||||
memcpy(indir->ring_index, efx->rx_indir_table,
|
||||
copy_size * sizeof(indir->ring_index[0]));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev,
|
||||
const struct ethtool_rxfh_indir *indir)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
size_t i;
|
||||
|
||||
if (efx_nic_rev(efx) < EFX_REV_FALCON_B0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* Validate size and indices */
|
||||
if (indir->size != ARRAY_SIZE(efx->rx_indir_table))
|
||||
return -EINVAL;
|
||||
for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++)
|
||||
if (indir->ring_index[i] >= efx->n_rx_channels)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(efx->rx_indir_table, indir->ring_index,
|
||||
sizeof(efx->rx_indir_table));
|
||||
efx_nic_push_rx_indir_table(efx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct ethtool_ops efx_ethtool_ops = {
|
||||
.get_settings = efx_ethtool_get_settings,
|
||||
.set_settings = efx_ethtool_set_settings,
|
||||
|
@ -905,4 +992,7 @@ const struct ethtool_ops efx_ethtool_ops = {
|
|||
.get_wol = efx_ethtool_get_wol,
|
||||
.set_wol = efx_ethtool_set_wol,
|
||||
.reset = efx_ethtool_reset,
|
||||
.get_rxnfc = efx_ethtool_get_rxnfc,
|
||||
.get_rxfh_indir = efx_ethtool_get_rxfh_indir,
|
||||
.set_rxfh_indir = efx_ethtool_set_rxfh_indir,
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue