mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-08-18 02:22:47 -07:00
sfc: support RSS spreading of ethtool ntuple filters
Use a linked list to associate user-facing context IDs with FW-facing context IDs (since the latter can change after an MC reset). Signed-off-by: Edward Cree <ecree@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
1 parent
84a1d9c482
commit
42356d9a13
9 files changed
+443
-150
No files matched your search
+181
-92
File diff suppressed because it is too large.
Load diff
@@ -1353,12 +1353,13 @@ static void efx_fini_io(struct efx_nic *efx)
|
||||
pci_disable_device(efx->pci_dev);
|
||||
}
|
||||
|
||||
void efx_set_default_rx_indir_table(struct efx_nic *efx)
|
||||
void efx_set_default_rx_indir_table(struct efx_nic *efx,
|
||||
struct efx_rss_context *ctx)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++)
|
||||
efx->rx_indir_table[i] =
|
||||
for (i = 0; i < ARRAY_SIZE(ctx->rx_indir_table); i++)
|
||||
ctx->rx_indir_table[i] =
|
||||
ethtool_rxfh_indir_default(i, efx->rss_spread);
|
||||
}
|
||||
|
||||
@@ -1739,9 +1740,9 @@ static int efx_probe_nic(struct efx_nic *efx)
|
||||
} while (rc == -EAGAIN);
|
||||
|
||||
if (efx->n_channels > 1)
|
||||
netdev_rss_key_fill(&efx->rx_hash_key,
|
||||
sizeof(efx->rx_hash_key));
|
||||
efx_set_default_rx_indir_table(efx);
|
||||
netdev_rss_key_fill(efx->rss_context.rx_hash_key,
|
||||
sizeof(efx->rss_context.rx_hash_key));
|
||||
efx_set_default_rx_indir_table(efx, &efx->rss_context);
|
||||
|
||||
netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels);
|
||||
netif_set_real_num_rx_queues(efx->net_dev, efx->n_rx_channels);
|
||||
@@ -2700,6 +2701,8 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
|
||||
" VFs may not function\n", rc);
|
||||
#endif
|
||||
|
||||
if (efx->type->rx_restore_rss_contexts)
|
||||
efx->type->rx_restore_rss_contexts(efx);
|
||||
down_read(&efx->filter_sem);
|
||||
efx_restore_filters(efx);
|
||||
up_read(&efx->filter_sem);
|
||||
@@ -3003,6 +3006,7 @@ static int efx_init_struct(struct efx_nic *efx,
|
||||
efx->type->rx_hash_offset - efx->type->rx_prefix_size;
|
||||
efx->rx_packet_ts_offset =
|
||||
efx->type->rx_ts_offset - efx->type->rx_prefix_size;
|
||||
INIT_LIST_HEAD(&efx->rss_context.list);
|
||||
spin_lock_init(&efx->stats_lock);
|
||||
efx->vi_stride = EFX_DEFAULT_VI_STRIDE;
|
||||
efx->num_mac_stats = MC_CMD_MAC_NSTATS;
|
||||
@@ -3072,6 +3076,55 @@ void efx_update_sw_stats(struct efx_nic *efx, u64 *stats)
|
||||
stats[GENERIC_STAT_rx_noskb_drops] = atomic_read(&efx->n_rx_noskb_drops);
|
||||
}
|
||||
|
||||
/* RSS contexts. We're using linked lists and crappy O(n) algorithms, because
|
||||
* (a) this is an infrequent control-plane operation and (b) n is small (max 64)
|
||||
*/
|
||||
struct efx_rss_context *efx_alloc_rss_context_entry(struct list_head *head)
|
||||
{
|
||||
struct efx_rss_context *ctx, *new;
|
||||
u32 id = 1; /* Don't use zero, that refers to the master RSS context */
|
||||
|
||||
/* Search for first gap in the numbering */
|
||||
list_for_each_entry(ctx, head, list) {
|
||||
if (ctx->user_id != id)
|
||||
break;
|
||||
id++;
|
||||
/* Check for wrap. If this happens, we have nearly 2^32
|
||||
* allocated RSS contexts, which seems unlikely.
|
||||
*/
|
||||
if (WARN_ON_ONCE(!id))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create the new entry */
|
||||
new = kmalloc(sizeof(struct efx_rss_context), GFP_KERNEL);
|
||||
if (!new)
|
||||
return NULL;
|
||||
new->context_id = EFX_EF10_RSS_CONTEXT_INVALID;
|
||||
new->rx_hash_udp_4tuple = false;
|
||||
|
||||
/* Insert the new entry into the gap */
|
||||
new->user_id = id;
|
||||
list_add_tail(&new->list, &ctx->list);
|
||||
return new;
|
||||
}
|
||||
|
||||
struct efx_rss_context *efx_find_rss_context_entry(u32 id, struct list_head *head)
|
||||
{
|
||||
struct efx_rss_context *ctx;
|
||||
|
||||
list_for_each_entry(ctx, head, list)
|
||||
if (ctx->user_id == id)
|
||||
return ctx;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void efx_free_rss_context_entry(struct efx_rss_context *ctx)
|
||||
{
|
||||
list_del(&ctx->list);
|
||||
kfree(ctx);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
*
|
||||
* PCI interface
|
||||
|
||||
@@ -34,7 +34,8 @@ extern unsigned int efx_piobuf_size;
|
||||
extern bool efx_separate_tx_channels;
|
||||
|
||||
/* RX */
|
||||
void efx_set_default_rx_indir_table(struct efx_nic *efx);
|
||||
void efx_set_default_rx_indir_table(struct efx_nic *efx,
|
||||
struct efx_rss_context *ctx);
|
||||
void efx_rx_config_page_split(struct efx_nic *efx);
|
||||
int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
|
||||
void efx_remove_rx_queue(struct efx_rx_queue *rx_queue);
|
||||
@@ -182,6 +183,15 @@ static inline void efx_filter_rfs_expire(struct efx_channel *channel) {}
|
||||
#endif
|
||||
bool efx_filter_is_mc_recipient(const struct efx_filter_spec *spec);
|
||||
|
||||
/* RSS contexts */
|
||||
struct efx_rss_context *efx_alloc_rss_context_entry(struct list_head *list);
|
||||
struct efx_rss_context *efx_find_rss_context_entry(u32 id, struct list_head *list);
|
||||
void efx_free_rss_context_entry(struct efx_rss_context *ctx);
|
||||
static inline bool efx_rss_active(struct efx_rss_context *ctx)
|
||||
{
|
||||
return ctx->context_id != EFX_EF10_RSS_CONTEXT_INVALID;
|
||||
}
|
||||
|
||||
/* Channels */
|
||||
int efx_channel_dummy_op_int(struct efx_channel *channel);
|
||||
void efx_channel_dummy_op_void(struct efx_channel *channel);
|
||||
|
||||
@@ -808,7 +808,8 @@ static inline void ip6_fill_mask(__be32 *mask)
|
||||
}
|
||||
|
||||
static int efx_ethtool_get_class_rule(struct efx_nic *efx,
|
||||
struct ethtool_rx_flow_spec *rule)
|
||||
struct ethtool_rx_flow_spec *rule,
|
||||
u32 *rss_context)
|
||||
{
|
||||
struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec;
|
||||
struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec;
|
||||
@@ -964,6 +965,11 @@ static int efx_ethtool_get_class_rule(struct efx_nic *efx,
|
||||
rule->m_ext.vlan_tci = htons(0xfff);
|
||||
}
|
||||
|
||||
if (spec.flags & EFX_FILTER_FLAG_RX_RSS) {
|
||||
rule->flow_type |= FLOW_RSS;
|
||||
*rss_context = spec.rss_context;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -972,6 +978,8 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev,
|
||||
struct ethtool_rxnfc *info, u32 *rule_locs)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
u32 rss_context = 0;
|
||||
s32 rc;
|
||||
|
||||
switch (info->cmd) {
|
||||
case ETHTOOL_GRXRINGS:
|
||||
@@ -979,12 +987,20 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev,
|
||||
return 0;
|
||||
|
||||
case ETHTOOL_GRXFH: {
|
||||
struct efx_rss_context *ctx = &efx->rss_context;
|
||||
|
||||
if (info->flow_type & FLOW_RSS && info->rss_context) {
|
||||
ctx = efx_find_rss_context_entry(info->rss_context,
|
||||
&efx->rss_context.list);
|
||||
if (!ctx)
|
||||
return -ENOENT;
|
||||
}
|
||||
info->data = 0;
|
||||
if (!efx->rss_active) /* No RSS */
|
||||
if (!efx_rss_active(ctx)) /* No RSS */
|
||||
return 0;
|
||||
switch (info->flow_type) {
|
||||
switch (info->flow_type & ~FLOW_RSS) {
|
||||
case UDP_V4_FLOW:
|
||||
if (efx->rx_hash_udp_4tuple)
|
||||
if (ctx->rx_hash_udp_4tuple)
|
||||
/* fall through */
|
||||
case TCP_V4_FLOW:
|
||||
info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
@@ -995,7 +1011,7 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev,
|
||||
info->data |= RXH_IP_SRC | RXH_IP_DST;
|
||||
break;
|
||||
case UDP_V6_FLOW:
|
||||
if (efx->rx_hash_udp_4tuple)
|
||||
if (ctx->rx_hash_udp_4tuple)
|
||||
/* fall through */
|
||||
case TCP_V6_FLOW:
|
||||
info->data |= RXH_L4_B_0_1 | RXH_L4_B_2_3;
|
||||
@@ -1023,10 +1039,14 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev,
|
||||
case ETHTOOL_GRXCLSRULE:
|
||||
if (efx_filter_get_rx_id_limit(efx) == 0)
|
||||
return -EOPNOTSUPP;
|
||||
return efx_ethtool_get_class_rule(efx, &info->fs);
|
||||
rc = efx_ethtool_get_class_rule(efx, &info->fs, &rss_context);
|
||||
if (rc < 0)
|
||||
return rc;
|
||||
if (info->fs.flow_type & FLOW_RSS)
|
||||
info->rss_context = rss_context;
|
||||
return 0;
|
||||
|
||||
case ETHTOOL_GRXCLSRLALL: {
|
||||
s32 rc;
|
||||
case ETHTOOL_GRXCLSRLALL:
|
||||
info->data = efx_filter_get_rx_id_limit(efx);
|
||||
if (info->data == 0)
|
||||
return -EOPNOTSUPP;
|
||||
@@ -1036,7 +1056,6 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev,
|
||||
return rc;
|
||||
info->rule_cnt = rc;
|
||||
return 0;
|
||||
}
|
||||
|
||||
default:
|
||||
return -EOPNOTSUPP;
|
||||
@@ -1054,7 +1073,8 @@ static inline bool ip6_mask_is_empty(__be32 mask[4])
|
||||
}
|
||||
|
||||
static int efx_ethtool_set_class_rule(struct efx_nic *efx,
|
||||
struct ethtool_rx_flow_spec *rule)
|
||||
struct ethtool_rx_flow_spec *rule,
|
||||
u32 rss_context)
|
||||
{
|
||||
struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec;
|
||||
struct ethtool_tcpip4_spec *ip_mask = &rule->m_u.tcp_ip4_spec;
|
||||
@@ -1066,6 +1086,7 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,
|
||||
struct ethtool_usrip6_spec *uip6_mask = &rule->m_u.usr_ip6_spec;
|
||||
struct ethhdr *mac_entry = &rule->h_u.ether_spec;
|
||||
struct ethhdr *mac_mask = &rule->m_u.ether_spec;
|
||||
enum efx_filter_flags flags = 0;
|
||||
struct efx_filter_spec spec;
|
||||
int rc;
|
||||
|
||||
@@ -1084,12 +1105,19 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,
|
||||
rule->m_ext.data[1]))
|
||||
return -EINVAL;
|
||||
|
||||
efx_filter_init_rx(&spec, EFX_FILTER_PRI_MANUAL,
|
||||
efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0,
|
||||
if (efx->rx_scatter)
|
||||
flags |= EFX_FILTER_FLAG_RX_SCATTER;
|
||||
if (rule->flow_type & FLOW_RSS)
|
||||
flags |= EFX_FILTER_FLAG_RX_RSS;
|
||||
|
||||
efx_filter_init_rx(&spec, EFX_FILTER_PRI_MANUAL, flags,
|
||||
(rule->ring_cookie == RX_CLS_FLOW_DISC) ?
|
||||
EFX_FILTER_RX_DMAQ_ID_DROP : rule->ring_cookie);
|
||||
|
||||
switch (rule->flow_type & ~FLOW_EXT) {
|
||||
if (rule->flow_type & FLOW_RSS)
|
||||
spec.rss_context = rss_context;
|
||||
|
||||
switch (rule->flow_type & ~(FLOW_EXT | FLOW_RSS)) {
|
||||
case TCP_V4_FLOW:
|
||||
case UDP_V4_FLOW:
|
||||
spec.match_flags = (EFX_FILTER_MATCH_ETHER_TYPE |
|
||||
@@ -1265,7 +1293,8 @@ static int efx_ethtool_set_rxnfc(struct net_device *net_dev,
|
||||
|
||||
switch (info->cmd) {
|
||||
case ETHTOOL_SRXCLSRLINS:
|
||||
return efx_ethtool_set_class_rule(efx, &info->fs);
|
||||
return efx_ethtool_set_class_rule(efx, &info->fs,
|
||||
info->rss_context);
|
||||
|
||||
case ETHTOOL_SRXCLSRLDEL:
|
||||
return efx_filter_remove_id_safe(efx, EFX_FILTER_PRI_MANUAL,
|
||||
@@ -1280,7 +1309,9 @@ static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
|
||||
return (efx->n_rx_channels == 1) ? 0 : ARRAY_SIZE(efx->rx_indir_table);
|
||||
if (efx->n_rx_channels == 1)
|
||||
return 0;
|
||||
return ARRAY_SIZE(efx->rss_context.rx_indir_table);
|
||||
}
|
||||
|
||||
static u32 efx_ethtool_get_rxfh_key_size(struct net_device *net_dev)
|
||||
@@ -1303,9 +1334,11 @@ static int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key,
|
||||
if (hfunc)
|
||||
*hfunc = ETH_RSS_HASH_TOP;
|
||||
if (indir)
|
||||
memcpy(indir, efx->rx_indir_table, sizeof(efx->rx_indir_table));
|
||||
memcpy(indir, efx->rss_context.rx_indir_table,
|
||||
sizeof(efx->rss_context.rx_indir_table));
|
||||
if (key)
|
||||
memcpy(key, efx->rx_hash_key, efx->type->rx_hash_key_size);
|
||||
memcpy(key, efx->rss_context.rx_hash_key,
|
||||
efx->type->rx_hash_key_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1321,13 +1354,93 @@ static int efx_ethtool_set_rxfh(struct net_device *net_dev, const u32 *indir,
|
||||
return 0;
|
||||
|
||||
if (!key)
|
||||
key = efx->rx_hash_key;
|
||||
key = efx->rss_context.rx_hash_key;
|
||||
if (!indir)
|
||||
indir = efx->rx_indir_table;
|
||||
indir = efx->rss_context.rx_indir_table;
|
||||
|
||||
return efx->type->rx_push_rss_config(efx, true, indir, key);
|
||||
}
|
||||
|
||||
static int efx_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir,
|
||||
u8 *key, u8 *hfunc, u32 rss_context)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
struct efx_rss_context *ctx;
|
||||
int rc;
|
||||
|
||||
if (!efx->type->rx_pull_rss_context_config)
|
||||
return -EOPNOTSUPP;
|
||||
ctx = efx_find_rss_context_entry(rss_context, &efx->rss_context.list);
|
||||
if (!ctx)
|
||||
return -ENOENT;
|
||||
rc = efx->type->rx_pull_rss_context_config(efx, ctx);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (hfunc)
|
||||
*hfunc = ETH_RSS_HASH_TOP;
|
||||
if (indir)
|
||||
memcpy(indir, ctx->rx_indir_table, sizeof(ctx->rx_indir_table));
|
||||
if (key)
|
||||
memcpy(key, ctx->rx_hash_key, efx->type->rx_hash_key_size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int efx_ethtool_set_rxfh_context(struct net_device *net_dev,
|
||||
const u32 *indir, const u8 *key,
|
||||
const u8 hfunc, u32 *rss_context,
|
||||
bool delete)
|
||||
{
|
||||
struct efx_nic *efx = netdev_priv(net_dev);
|
||||
struct efx_rss_context *ctx;
|
||||
bool allocated = false;
|
||||
int rc;
|
||||
|
||||
if (!efx->type->rx_push_rss_context_config)
|
||||
return -EOPNOTSUPP;
|
||||
/* Hash function is Toeplitz, cannot be changed */
|
||||
if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
|
||||
return -EOPNOTSUPP;
|
||||
if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) {
|
||||
if (delete)
|
||||
/* alloc + delete == Nothing to do */
|
||||
return -EINVAL;
|
||||
ctx = efx_alloc_rss_context_entry(&efx->rss_context.list);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
ctx->context_id = EFX_EF10_RSS_CONTEXT_INVALID;
|
||||
/* Initialise indir table and key to defaults */
|
||||
efx_set_default_rx_indir_table(efx, ctx);
|
||||
netdev_rss_key_fill(ctx->rx_hash_key, sizeof(ctx->rx_hash_key));
|
||||
allocated = true;
|
||||
} else {
|
||||
ctx = efx_find_rss_context_entry(*rss_context,
|
||||
&efx->rss_context.list);
|
||||
if (!ctx)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (delete) {
|
||||
/* delete this context */
|
||||
rc = efx->type->rx_push_rss_context_config(efx, ctx, NULL, NULL);
|
||||
if (!rc)
|
||||
efx_free_rss_context_entry(ctx);
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (!key)
|
||||
key = ctx->rx_hash_key;
|
||||
if (!indir)
|
||||
indir = ctx->rx_indir_table;
|
||||
|
||||
rc = efx->type->rx_push_rss_context_config(efx, ctx, indir, key);
|
||||
if (rc && allocated)
|
||||
efx_free_rss_context_entry(ctx);
|
||||
else
|
||||
*rss_context = ctx->user_id;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int efx_ethtool_get_ts_info(struct net_device *net_dev,
|
||||
struct ethtool_ts_info *ts_info)
|
||||
{
|
||||
@@ -1403,6 +1516,8 @@ const struct ethtool_ops efx_ethtool_ops = {
|
||||
.get_rxfh_key_size = efx_ethtool_get_rxfh_key_size,
|
||||
.get_rxfh = efx_ethtool_get_rxfh,
|
||||
.set_rxfh = efx_ethtool_set_rxfh,
|
||||
.get_rxfh_context = efx_ethtool_get_rxfh_context,
|
||||
.set_rxfh_context = efx_ethtool_set_rxfh_context,
|
||||
.get_ts_info = efx_ethtool_get_ts_info,
|
||||
.get_module_info = efx_ethtool_get_module_info,
|
||||
.get_module_eeprom = efx_ethtool_get_module_eeprom,
|
||||
|
||||
@@ -1630,12 +1630,12 @@ void efx_farch_rx_push_indir_table(struct efx_nic *efx)
|
||||
size_t i = 0;
|
||||
efx_dword_t dword;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(efx->rx_indir_table) !=
|
||||
BUILD_BUG_ON(ARRAY_SIZE(efx->rss_context.rx_indir_table) !=
|
||||
FR_BZ_RX_INDIRECTION_TBL_ROWS);
|
||||
|
||||
for (i = 0; i < FR_BZ_RX_INDIRECTION_TBL_ROWS; i++) {
|
||||
EFX_POPULATE_DWORD_1(dword, FRF_BZ_IT_QUEUE,
|
||||
efx->rx_indir_table[i]);
|
||||
efx->rss_context.rx_indir_table[i]);
|
||||
efx_writed(efx, &dword,
|
||||
FR_BZ_RX_INDIRECTION_TBL +
|
||||
FR_BZ_RX_INDIRECTION_TBL_STEP * i);
|
||||
@@ -1647,14 +1647,14 @@ void efx_farch_rx_pull_indir_table(struct efx_nic *efx)
|
||||
size_t i = 0;
|
||||
efx_dword_t dword;
|
||||
|
||||
BUILD_BUG_ON(ARRAY_SIZE(efx->rx_indir_table) !=
|
||||
BUILD_BUG_ON(ARRAY_SIZE(efx->rss_context.rx_indir_table) !=
|
||||
FR_BZ_RX_INDIRECTION_TBL_ROWS);
|
||||
|
||||
for (i = 0; i < FR_BZ_RX_INDIRECTION_TBL_ROWS; i++) {
|
||||
efx_readd(efx, &dword,
|
||||
FR_BZ_RX_INDIRECTION_TBL +
|
||||
FR_BZ_RX_INDIRECTION_TBL_STEP * i);
|
||||
efx->rx_indir_table[i] = EFX_DWORD_FIELD(dword, FRF_BZ_IT_QUEUE);
|
||||
efx->rss_context.rx_indir_table[i] = EFX_DWORD_FIELD(dword, FRF_BZ_IT_QUEUE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2032,8 +2032,7 @@ efx_farch_filter_from_gen_spec(struct efx_farch_filter_spec *spec,
|
||||
{
|
||||
bool is_full = false;
|
||||
|
||||
if ((gen_spec->flags & EFX_FILTER_FLAG_RX_RSS) &&
|
||||
gen_spec->rss_context != EFX_FILTER_RSS_CONTEXT_DEFAULT)
|
||||
if ((gen_spec->flags & EFX_FILTER_FLAG_RX_RSS) && gen_spec->rss_context)
|
||||
return -EINVAL;
|
||||
|
||||
spec->priority = gen_spec->priority;
|
||||
|
||||
@@ -125,7 +125,9 @@ enum efx_encap_type {
|
||||
* @match_flags: Match type flags, from &enum efx_filter_match_flags
|
||||
* @priority: Priority of the filter, from &enum efx_filter_priority
|
||||
* @flags: Miscellaneous flags, from &enum efx_filter_flags
|
||||
* @rss_context: RSS context to use, if %EFX_FILTER_FLAG_RX_RSS is set
|
||||
* @rss_context: RSS context to use, if %EFX_FILTER_FLAG_RX_RSS is set. This
|
||||
* is a user_id (with 0 meaning the driver/default RSS context), not an
|
||||
* MCFW context_id.
|
||||
* @dmaq_id: Source/target queue index, or %EFX_FILTER_RX_DMAQ_ID_DROP for
|
||||
* an RX drop filter
|
||||
* @outer_vid: Outer VLAN ID to match, if %EFX_FILTER_MATCH_OUTER_VID is set
|
||||
@@ -173,7 +175,6 @@ struct efx_filter_spec {
|
||||
};
|
||||
|
||||
enum {
|
||||
EFX_FILTER_RSS_CONTEXT_DEFAULT = 0xffffffff,
|
||||
EFX_FILTER_RX_DMAQ_ID_DROP = 0xfff
|
||||
};
|
||||
|
||||
@@ -185,7 +186,7 @@ static inline void efx_filter_init_rx(struct efx_filter_spec *spec,
|
||||
memset(spec, 0, sizeof(*spec));
|
||||
spec->priority = priority;
|
||||
spec->flags = EFX_FILTER_FLAG_RX | flags;
|
||||
spec->rss_context = EFX_FILTER_RSS_CONTEXT_DEFAULT;
|
||||
spec->rss_context = 0;
|
||||
spec->dmaq_id = rxq_id;
|
||||
}
|
||||
|
||||
|
||||
@@ -704,6 +704,28 @@ union efx_multicast_hash {
|
||||
|
||||
struct vfdi_status;
|
||||
|
||||
/* The reserved RSS context value */
|
||||
#define EFX_EF10_RSS_CONTEXT_INVALID 0xffffffff
|
||||
/**
|
||||
* struct efx_rss_context - A user-defined RSS context for filtering
|
||||
* @list: node of linked list on which this struct is stored
|
||||
* @context_id: the RSS_CONTEXT_ID returned by MC firmware, or
|
||||
* %EFX_EF10_RSS_CONTEXT_INVALID if this context is not present on the NIC.
|
||||
* For Siena, 0 if RSS is active, else %EFX_EF10_RSS_CONTEXT_INVALID.
|
||||
* @user_id: the rss_context ID exposed to userspace over ethtool.
|
||||
* @rx_hash_udp_4tuple: UDP 4-tuple hashing enabled
|
||||
* @rx_hash_key: Toeplitz hash key for this RSS context
|
||||
* @indir_table: Indirection table for this RSS context
|
||||
*/
|
||||
struct efx_rss_context {
|
||||
struct list_head list;
|
||||
u32 context_id;
|
||||
u32 user_id;
|
||||
bool rx_hash_udp_4tuple;
|
||||
u8 rx_hash_key[40];
|
||||
u32 rx_indir_table[128];
|
||||
};
|
||||
|
||||
/**
|
||||
* struct efx_nic - an Efx NIC
|
||||
* @name: Device name (net device name or bus id before net device registered)
|
||||
@@ -764,11 +786,9 @@ struct vfdi_status;
|
||||
* (valid only for NICs that set %EFX_RX_PKT_PREFIX_LEN; always negative)
|
||||
* @rx_packet_ts_offset: Offset of timestamp from start of packet data
|
||||
* (valid only if channel->sync_timestamps_enabled; always negative)
|
||||
* @rx_hash_key: Toeplitz hash key for RSS
|
||||
* @rx_indir_table: Indirection table for RSS
|
||||
* @rx_scatter: Scatter mode enabled for receives
|
||||
* @rss_active: RSS enabled on hardware
|
||||
* @rx_hash_udp_4tuple: UDP 4-tuple hashing enabled
|
||||
* @rss_context: Main RSS context. Its @list member is the head of the list of
|
||||
* RSS contexts created by user requests
|
||||
* @int_error_count: Number of internal errors seen recently
|
||||
* @int_error_expire: Time at which error count will be expired
|
||||
* @irq_soft_enabled: Are IRQs soft-enabled? If not, IRQ handler will
|
||||
@@ -909,11 +929,8 @@ struct efx_nic {
|
||||
int rx_packet_hash_offset;
|
||||
int rx_packet_len_offset;
|
||||
int rx_packet_ts_offset;
|
||||
u8 rx_hash_key[40];
|
||||
u32 rx_indir_table[128];
|
||||
bool rx_scatter;
|
||||
bool rss_active;
|
||||
bool rx_hash_udp_4tuple;
|
||||
struct efx_rss_context rss_context;
|
||||
|
||||
unsigned int_error_count;
|
||||
unsigned long int_error_expire;
|
||||
@@ -1099,6 +1116,10 @@ struct efx_udp_tunnel {
|
||||
* @tx_write: Write TX descriptors and doorbell
|
||||
* @rx_push_rss_config: Write RSS hash key and indirection table to the NIC
|
||||
* @rx_pull_rss_config: Read RSS hash key and indirection table back from the NIC
|
||||
* @rx_push_rss_context_config: Write RSS hash key and indirection table for
|
||||
* user RSS context to the NIC
|
||||
* @rx_pull_rss_context_config: Read RSS hash key and indirection table for user
|
||||
* RSS context back from the NIC
|
||||
* @rx_probe: Allocate resources for RX queue
|
||||
* @rx_init: Initialise RX queue on the NIC
|
||||
* @rx_remove: Free resources for RX queue
|
||||
@@ -1237,6 +1258,13 @@ struct efx_nic_type {
|
||||
int (*rx_push_rss_config)(struct efx_nic *efx, bool user,
|
||||
const u32 *rx_indir_table, const u8 *key);
|
||||
int (*rx_pull_rss_config)(struct efx_nic *efx);
|
||||
int (*rx_push_rss_context_config)(struct efx_nic *efx,
|
||||
struct efx_rss_context *ctx,
|
||||
const u32 *rx_indir_table,
|
||||
const u8 *key);
|
||||
int (*rx_pull_rss_context_config)(struct efx_nic *efx,
|
||||
struct efx_rss_context *ctx);
|
||||
void (*rx_restore_rss_contexts)(struct efx_nic *efx);
|
||||
int (*rx_probe)(struct efx_rx_queue *rx_queue);
|
||||
void (*rx_init)(struct efx_rx_queue *rx_queue);
|
||||
void (*rx_remove)(struct efx_rx_queue *rx_queue);
|
||||
|
||||
@@ -374,7 +374,6 @@ enum {
|
||||
* @piobuf_size: size of a single PIO buffer
|
||||
* @must_restore_piobufs: Flag: PIO buffers have yet to be restored after MC
|
||||
* reboot
|
||||
* @rx_rss_context: Firmware handle for our RSS context
|
||||
* @rx_rss_context_exclusive: Whether our RSS context is exclusive or shared
|
||||
* @stats: Hardware statistics
|
||||
* @workaround_35388: Flag: firmware supports workaround for bug 35388
|
||||
@@ -415,7 +414,6 @@ struct efx_ef10_nic_data {
|
||||
unsigned int piobuf_handle[EF10_TX_PIOBUF_COUNT];
|
||||
u16 piobuf_size;
|
||||
bool must_restore_piobufs;
|
||||
u32 rx_rss_context;
|
||||
bool rx_rss_context_exclusive;
|
||||
u64 stats[EF10_STAT_COUNT];
|
||||
bool workaround_35388;
|
||||
|
||||
@@ -350,11 +350,11 @@ static int siena_rx_pull_rss_config(struct efx_nic *efx)
|
||||
* siena_rx_push_rss_config, below)
|
||||
*/
|
||||
efx_reado(efx, &temp, FR_CZ_RX_RSS_IPV6_REG1);
|
||||
memcpy(efx->rx_hash_key, &temp, sizeof(temp));
|
||||
memcpy(efx->rss_context.rx_hash_key, &temp, sizeof(temp));
|
||||
efx_reado(efx, &temp, FR_CZ_RX_RSS_IPV6_REG2);
|
||||
memcpy(efx->rx_hash_key + sizeof(temp), &temp, sizeof(temp));
|
||||
memcpy(efx->rss_context.rx_hash_key + sizeof(temp), &temp, sizeof(temp));
|
||||
efx_reado(efx, &temp, FR_CZ_RX_RSS_IPV6_REG3);
|
||||
memcpy(efx->rx_hash_key + 2 * sizeof(temp), &temp,
|
||||
memcpy(efx->rss_context.rx_hash_key + 2 * sizeof(temp), &temp,
|
||||
FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8);
|
||||
efx_farch_rx_pull_indir_table(efx);
|
||||
return 0;
|
||||
@@ -367,26 +367,26 @@ static int siena_rx_push_rss_config(struct efx_nic *efx, bool user,
|
||||
|
||||
/* Set hash key for IPv4 */
|
||||
if (key)
|
||||
memcpy(efx->rx_hash_key, key, sizeof(temp));
|
||||
memcpy(&temp, efx->rx_hash_key, sizeof(temp));
|
||||
memcpy(efx->rss_context.rx_hash_key, key, sizeof(temp));
|
||||
memcpy(&temp, efx->rss_context.rx_hash_key, sizeof(temp));
|
||||
efx_writeo(efx, &temp, FR_BZ_RX_RSS_TKEY);
|
||||
|
||||
/* Enable IPv6 RSS */
|
||||
BUILD_BUG_ON(sizeof(efx->rx_hash_key) <
|
||||
BUILD_BUG_ON(sizeof(efx->rss_context.rx_hash_key) <
|
||||
2 * sizeof(temp) + FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8 ||
|
||||
FRF_CZ_RX_RSS_IPV6_TKEY_HI_LBN != 0);
|
||||
memcpy(&temp, efx->rx_hash_key, sizeof(temp));
|
||||
memcpy(&temp, efx->rss_context.rx_hash_key, sizeof(temp));
|
||||
efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG1);
|
||||
memcpy(&temp, efx->rx_hash_key + sizeof(temp), sizeof(temp));
|
||||
memcpy(&temp, efx->rss_context.rx_hash_key + sizeof(temp), sizeof(temp));
|
||||
efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG2);
|
||||
EFX_POPULATE_OWORD_2(temp, FRF_CZ_RX_RSS_IPV6_THASH_ENABLE, 1,
|
||||
FRF_CZ_RX_RSS_IPV6_IP_THASH_ENABLE, 1);
|
||||
memcpy(&temp, efx->rx_hash_key + 2 * sizeof(temp),
|
||||
memcpy(&temp, efx->rss_context.rx_hash_key + 2 * sizeof(temp),
|
||||
FRF_CZ_RX_RSS_IPV6_TKEY_HI_WIDTH / 8);
|
||||
efx_writeo(efx, &temp, FR_CZ_RX_RSS_IPV6_REG3);
|
||||
|
||||
memcpy(efx->rx_indir_table, rx_indir_table,
|
||||
sizeof(efx->rx_indir_table));
|
||||
memcpy(efx->rss_context.rx_indir_table, rx_indir_table,
|
||||
sizeof(efx->rss_context.rx_indir_table));
|
||||
efx_farch_rx_push_indir_table(efx);
|
||||
|
||||
return 0;
|
||||
@@ -432,8 +432,8 @@ static int siena_init_nic(struct efx_nic *efx)
|
||||
EFX_RX_USR_BUF_SIZE >> 5);
|
||||
efx_writeo(efx, &temp, FR_AZ_RX_CFG);
|
||||
|
||||
siena_rx_push_rss_config(efx, false, efx->rx_indir_table, NULL);
|
||||
efx->rss_active = true;
|
||||
siena_rx_push_rss_config(efx, false, efx->rss_context.rx_indir_table, NULL);
|
||||
efx->rss_context.context_id = 0; /* indicates RSS is active */
|
||||
|
||||
/* Enable event logging */
|
||||
rc = efx_mcdi_log_ctrl(efx, true, false, 0);
|
||||
|
||||
Reference in new issue
Block a user