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:
Ben Hutchings
2010-06-30 05:06:28 +00:00
committed by David S. Miller
parent a5b6ee291e
commit 765c9f4686
5 changed files with 105 additions and 10 deletions

View File

@@ -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,
};