Commit f74d1995 authored by Edward Cree's avatar Edward Cree Committed by David S. Miller

sfc: support setting RSS hash key through ethtool API

Signed-off-by: default avatarEdward Cree <ecree@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 96fe11f2
...@@ -1325,7 +1325,7 @@ static int efx_ef10_init_nic(struct efx_nic *efx) ...@@ -1325,7 +1325,7 @@ static int efx_ef10_init_nic(struct efx_nic *efx)
} }
/* don't fail init if RSS setup doesn't work */ /* don't fail init if RSS setup doesn't work */
rc = efx->type->rx_push_rss_config(efx, false, efx->rx_indir_table); rc = efx->type->rx_push_rss_config(efx, false, efx->rx_indir_table, NULL);
efx->rss_active = (rc == 0); efx->rss_active = (rc == 0);
return 0; return 0;
...@@ -2535,7 +2535,7 @@ static void efx_ef10_free_rss_context(struct efx_nic *efx, u32 context) ...@@ -2535,7 +2535,7 @@ static void efx_ef10_free_rss_context(struct efx_nic *efx, u32 context)
} }
static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context, static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context,
const u32 *rx_indir_table) const u32 *rx_indir_table, const u8 *key)
{ {
MCDI_DECLARE_BUF(tablebuf, MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN); MCDI_DECLARE_BUF(tablebuf, MC_CMD_RSS_CONTEXT_SET_TABLE_IN_LEN);
MCDI_DECLARE_BUF(keybuf, MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN); MCDI_DECLARE_BUF(keybuf, MC_CMD_RSS_CONTEXT_SET_KEY_IN_LEN);
...@@ -2546,6 +2546,11 @@ static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context, ...@@ -2546,6 +2546,11 @@ static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context,
BUILD_BUG_ON(ARRAY_SIZE(efx->rx_indir_table) != BUILD_BUG_ON(ARRAY_SIZE(efx->rx_indir_table) !=
MC_CMD_RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE_LEN); MC_CMD_RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE_LEN);
/* This iterates over the length of efx->rx_indir_table, but copies
* bytes from rx_indir_table. That's because the latter is a pointer
* rather than an array, but should have the same length.
* The efx->rx_hash_key loop below is similar.
*/
for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); ++i) for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); ++i)
MCDI_PTR(tablebuf, MCDI_PTR(tablebuf,
RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE)[i] = RSS_CONTEXT_SET_TABLE_IN_INDIRECTION_TABLE)[i] =
...@@ -2561,8 +2566,7 @@ static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context, ...@@ -2561,8 +2566,7 @@ static int efx_ef10_populate_rss_table(struct efx_nic *efx, u32 context,
BUILD_BUG_ON(ARRAY_SIZE(efx->rx_hash_key) != BUILD_BUG_ON(ARRAY_SIZE(efx->rx_hash_key) !=
MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN); MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN);
for (i = 0; i < ARRAY_SIZE(efx->rx_hash_key); ++i) for (i = 0; i < ARRAY_SIZE(efx->rx_hash_key); ++i)
MCDI_PTR(keybuf, RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY)[i] = MCDI_PTR(keybuf, RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY)[i] = key[i];
efx->rx_hash_key[i];
return efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_SET_KEY, keybuf, return efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_SET_KEY, keybuf,
sizeof(keybuf), NULL, 0, NULL); sizeof(keybuf), NULL, 0, NULL);
...@@ -2595,7 +2599,8 @@ static int efx_ef10_rx_push_shared_rss_config(struct efx_nic *efx, ...@@ -2595,7 +2599,8 @@ static int efx_ef10_rx_push_shared_rss_config(struct efx_nic *efx,
} }
static int efx_ef10_rx_push_exclusive_rss_config(struct efx_nic *efx, static int efx_ef10_rx_push_exclusive_rss_config(struct efx_nic *efx,
const u32 *rx_indir_table) const u32 *rx_indir_table,
const u8 *key)
{ {
struct efx_ef10_nic_data *nic_data = efx->nic_data; struct efx_ef10_nic_data *nic_data = efx->nic_data;
int rc; int rc;
...@@ -2614,7 +2619,7 @@ static int efx_ef10_rx_push_exclusive_rss_config(struct efx_nic *efx, ...@@ -2614,7 +2619,7 @@ static int efx_ef10_rx_push_exclusive_rss_config(struct efx_nic *efx,
} }
rc = efx_ef10_populate_rss_table(efx, new_rx_rss_context, rc = efx_ef10_populate_rss_table(efx, new_rx_rss_context,
rx_indir_table); rx_indir_table, key);
if (rc != 0) if (rc != 0)
goto fail2; goto fail2;
...@@ -2625,6 +2630,9 @@ static int efx_ef10_rx_push_exclusive_rss_config(struct efx_nic *efx, ...@@ -2625,6 +2630,9 @@ static int efx_ef10_rx_push_exclusive_rss_config(struct efx_nic *efx,
if (rx_indir_table != efx->rx_indir_table) if (rx_indir_table != efx->rx_indir_table)
memcpy(efx->rx_indir_table, rx_indir_table, memcpy(efx->rx_indir_table, rx_indir_table,
sizeof(efx->rx_indir_table)); sizeof(efx->rx_indir_table));
if (key != efx->rx_hash_key)
memcpy(efx->rx_hash_key, key, efx->type->rx_hash_key_size);
return 0; return 0;
fail2: fail2:
...@@ -2636,14 +2644,18 @@ static int efx_ef10_rx_push_exclusive_rss_config(struct efx_nic *efx, ...@@ -2636,14 +2644,18 @@ static int efx_ef10_rx_push_exclusive_rss_config(struct efx_nic *efx,
} }
static int efx_ef10_pf_rx_push_rss_config(struct efx_nic *efx, bool user, static int efx_ef10_pf_rx_push_rss_config(struct efx_nic *efx, bool user,
const u32 *rx_indir_table) const u32 *rx_indir_table,
const u8 *key)
{ {
int rc; int rc;
if (efx->rss_spread == 1) if (efx->rss_spread == 1)
return 0; return 0;
rc = efx_ef10_rx_push_exclusive_rss_config(efx, rx_indir_table); if (!key)
key = efx->rx_hash_key;
rc = efx_ef10_rx_push_exclusive_rss_config(efx, rx_indir_table, key);
if (rc == -ENOBUFS && !user) { if (rc == -ENOBUFS && !user) {
unsigned context_size; unsigned context_size;
...@@ -2681,6 +2693,8 @@ static int efx_ef10_pf_rx_push_rss_config(struct efx_nic *efx, bool user, ...@@ -2681,6 +2693,8 @@ static int efx_ef10_pf_rx_push_rss_config(struct efx_nic *efx, bool user,
static int efx_ef10_vf_rx_push_rss_config(struct efx_nic *efx, bool user, static int efx_ef10_vf_rx_push_rss_config(struct efx_nic *efx, bool user,
const u32 *rx_indir_table const u32 *rx_indir_table
__attribute__ ((unused)),
const u8 *key
__attribute__ ((unused))) __attribute__ ((unused)))
{ {
struct efx_ef10_nic_data *nic_data = efx->nic_data; struct efx_ef10_nic_data *nic_data = efx->nic_data;
...@@ -5686,6 +5700,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = { ...@@ -5686,6 +5700,7 @@ const struct efx_nic_type efx_hunt_a0_vf_nic_type = {
.max_rx_ip_filters = HUNT_FILTER_TBL_ROWS, .max_rx_ip_filters = HUNT_FILTER_TBL_ROWS,
.hwtstamp_filters = 1 << HWTSTAMP_FILTER_NONE | .hwtstamp_filters = 1 << HWTSTAMP_FILTER_NONE |
1 << HWTSTAMP_FILTER_ALL, 1 << HWTSTAMP_FILTER_ALL,
.rx_hash_key_size = 40,
}; };
const struct efx_nic_type efx_hunt_a0_nic_type = { const struct efx_nic_type efx_hunt_a0_nic_type = {
...@@ -5812,4 +5827,5 @@ const struct efx_nic_type efx_hunt_a0_nic_type = { ...@@ -5812,4 +5827,5 @@ const struct efx_nic_type efx_hunt_a0_nic_type = {
.max_rx_ip_filters = HUNT_FILTER_TBL_ROWS, .max_rx_ip_filters = HUNT_FILTER_TBL_ROWS,
.hwtstamp_filters = 1 << HWTSTAMP_FILTER_NONE | .hwtstamp_filters = 1 << HWTSTAMP_FILTER_NONE |
1 << HWTSTAMP_FILTER_ALL, 1 << HWTSTAMP_FILTER_ALL,
.rx_hash_key_size = 40,
}; };
...@@ -1278,6 +1278,13 @@ static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev) ...@@ -1278,6 +1278,13 @@ static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev)
return (efx->n_rx_channels == 1) ? 0 : ARRAY_SIZE(efx->rx_indir_table); return (efx->n_rx_channels == 1) ? 0 : ARRAY_SIZE(efx->rx_indir_table);
} }
static u32 efx_ethtool_get_rxfh_key_size(struct net_device *net_dev)
{
struct efx_nic *efx = netdev_priv(net_dev);
return efx->type->rx_hash_key_size;
}
static int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key, static int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key,
u8 *hfunc) u8 *hfunc)
{ {
...@@ -1287,6 +1294,8 @@ static int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key, ...@@ -1287,6 +1294,8 @@ static int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key,
*hfunc = ETH_RSS_HASH_TOP; *hfunc = ETH_RSS_HASH_TOP;
if (indir) if (indir)
memcpy(indir, efx->rx_indir_table, sizeof(efx->rx_indir_table)); memcpy(indir, efx->rx_indir_table, sizeof(efx->rx_indir_table));
if (key)
memcpy(key, efx->rx_hash_key, efx->type->rx_hash_key_size);
return 0; return 0;
} }
...@@ -1295,14 +1304,18 @@ static int efx_ethtool_set_rxfh(struct net_device *net_dev, const u32 *indir, ...@@ -1295,14 +1304,18 @@ static int efx_ethtool_set_rxfh(struct net_device *net_dev, const u32 *indir,
{ {
struct efx_nic *efx = netdev_priv(net_dev); struct efx_nic *efx = netdev_priv(net_dev);
/* We do not allow change in unsupported parameters */ /* Hash function is Toeplitz, cannot be changed */
if (key || if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
(hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP))
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (!indir) if (!indir && !key)
return 0; return 0;
return efx->type->rx_push_rss_config(efx, true, indir); if (!key)
key = efx->rx_hash_key;
if (!indir)
indir = efx->rx_indir_table;
return efx->type->rx_push_rss_config(efx, true, indir, key);
} }
static int efx_ethtool_get_ts_info(struct net_device *net_dev, static int efx_ethtool_get_ts_info(struct net_device *net_dev,
...@@ -1377,6 +1390,7 @@ const struct ethtool_ops efx_ethtool_ops = { ...@@ -1377,6 +1390,7 @@ const struct ethtool_ops efx_ethtool_ops = {
.get_rxnfc = efx_ethtool_get_rxnfc, .get_rxnfc = efx_ethtool_get_rxnfc,
.set_rxnfc = efx_ethtool_set_rxnfc, .set_rxnfc = efx_ethtool_set_rxnfc,
.get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size,
.get_rxfh_key_size = efx_ethtool_get_rxfh_key_size,
.get_rxfh = efx_ethtool_get_rxfh, .get_rxfh = efx_ethtool_get_rxfh,
.set_rxfh = efx_ethtool_set_rxfh, .set_rxfh = efx_ethtool_set_rxfh,
.get_ts_info = efx_ethtool_get_ts_info, .get_ts_info = efx_ethtool_get_ts_info,
......
...@@ -1311,7 +1311,7 @@ struct efx_nic_type { ...@@ -1311,7 +1311,7 @@ struct efx_nic_type {
unsigned int (*tx_limit_len)(struct efx_tx_queue *tx_queue, unsigned int (*tx_limit_len)(struct efx_tx_queue *tx_queue,
dma_addr_t dma_addr, unsigned int len); dma_addr_t dma_addr, unsigned int len);
int (*rx_push_rss_config)(struct efx_nic *efx, bool user, int (*rx_push_rss_config)(struct efx_nic *efx, bool user,
const u32 *rx_indir_table); const u32 *rx_indir_table, const u8 *key);
int (*rx_probe)(struct efx_rx_queue *rx_queue); int (*rx_probe)(struct efx_rx_queue *rx_queue);
void (*rx_init)(struct efx_rx_queue *rx_queue); void (*rx_init)(struct efx_rx_queue *rx_queue);
void (*rx_remove)(struct efx_rx_queue *rx_queue); void (*rx_remove)(struct efx_rx_queue *rx_queue);
...@@ -1410,6 +1410,7 @@ struct efx_nic_type { ...@@ -1410,6 +1410,7 @@ struct efx_nic_type {
int mcdi_max_ver; int mcdi_max_ver;
unsigned int max_rx_ip_filters; unsigned int max_rx_ip_filters;
u32 hwtstamp_filters; u32 hwtstamp_filters;
unsigned int rx_hash_key_size;
}; };
/************************************************************************** /**************************************************************************
......
...@@ -333,11 +333,13 @@ static int siena_probe_nic(struct efx_nic *efx) ...@@ -333,11 +333,13 @@ static int siena_probe_nic(struct efx_nic *efx)
} }
static int siena_rx_push_rss_config(struct efx_nic *efx, bool user, static int siena_rx_push_rss_config(struct efx_nic *efx, bool user,
const u32 *rx_indir_table) const u32 *rx_indir_table, const u8 *key)
{ {
efx_oword_t temp; efx_oword_t temp;
/* Set hash key for IPv4 */ /* Set hash key for IPv4 */
if (key)
memcpy(efx->rx_hash_key, key, sizeof(temp));
memcpy(&temp, efx->rx_hash_key, sizeof(temp)); memcpy(&temp, efx->rx_hash_key, sizeof(temp));
efx_writeo(efx, &temp, FR_BZ_RX_RSS_TKEY); efx_writeo(efx, &temp, FR_BZ_RX_RSS_TKEY);
...@@ -402,7 +404,7 @@ static int siena_init_nic(struct efx_nic *efx) ...@@ -402,7 +404,7 @@ static int siena_init_nic(struct efx_nic *efx)
EFX_RX_USR_BUF_SIZE >> 5); EFX_RX_USR_BUF_SIZE >> 5);
efx_writeo(efx, &temp, FR_AZ_RX_CFG); efx_writeo(efx, &temp, FR_AZ_RX_CFG);
siena_rx_push_rss_config(efx, false, efx->rx_indir_table); siena_rx_push_rss_config(efx, false, efx->rx_indir_table, NULL);
efx->rss_active = true; efx->rss_active = true;
/* Enable event logging */ /* Enable event logging */
...@@ -1054,4 +1056,5 @@ const struct efx_nic_type siena_a0_nic_type = { ...@@ -1054,4 +1056,5 @@ const struct efx_nic_type siena_a0_nic_type = {
.hwtstamp_filters = (1 << HWTSTAMP_FILTER_NONE | .hwtstamp_filters = (1 << HWTSTAMP_FILTER_NONE |
1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT | 1 << HWTSTAMP_FILTER_PTP_V1_L4_EVENT |
1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT), 1 << HWTSTAMP_FILTER_PTP_V2_L4_EVENT),
.rx_hash_key_size = 16,
}; };
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