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:
committed by
David S. Miller
parent
a5b6ee291e
commit
765c9f4686
@@ -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,
|
||||
};
|
||||
|
Reference in New Issue
Block a user