Commit a9ee8d4a authored by Edward Cree's avatar Edward Cree Committed by Jakub Kicinski

sfc: use new rxfh_context API

The core is now responsible for allocating IDs and a memory region for
 us to store our state (struct efx_rss_context_priv), so we no longer
 need efx_alloc_rss_context_entry() and friends.
Since the contexts are now maintained by the core, use the core's lock
 (net_dev->ethtool->rss_lock), rather than our own mutex (efx->rss_lock),
 to serialise access against changes; and remove the now-unused
 efx->rss_lock from struct efx_nic.
Signed-off-by: default avatarEdward Cree <ecree.xilinx@gmail.com>
Reviewed-by: default avatarPrzemek Kitszel <przemyslaw.kitszel@intel.com>
Link: https://patch.msgid.link/150274740ea8cc137fef5502541ce573d32fb319.1719502240.git.ecree.xilinx@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 87925151
...@@ -1396,7 +1396,7 @@ static void efx_ef10_table_reset_mc_allocations(struct efx_nic *efx) ...@@ -1396,7 +1396,7 @@ static void efx_ef10_table_reset_mc_allocations(struct efx_nic *efx)
efx_mcdi_filter_table_reset_mc_allocations(efx); efx_mcdi_filter_table_reset_mc_allocations(efx);
nic_data->must_restore_piobufs = true; nic_data->must_restore_piobufs = true;
efx_ef10_forget_old_piobufs(efx); efx_ef10_forget_old_piobufs(efx);
efx->rss_context.context_id = EFX_MCDI_RSS_CONTEXT_INVALID; efx->rss_context.priv.context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
/* Driver-created vswitches and vports must be re-created */ /* Driver-created vswitches and vports must be re-created */
nic_data->must_probe_vswitching = true; nic_data->must_probe_vswitching = true;
......
...@@ -59,8 +59,12 @@ const struct ethtool_ops ef100_ethtool_ops = { ...@@ -59,8 +59,12 @@ const struct ethtool_ops ef100_ethtool_ops = {
.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_key_size = efx_ethtool_get_rxfh_key_size,
.rxfh_priv_size = sizeof(struct efx_rss_context_priv),
.get_rxfh = efx_ethtool_get_rxfh, .get_rxfh = efx_ethtool_get_rxfh,
.set_rxfh = efx_ethtool_set_rxfh, .set_rxfh = efx_ethtool_set_rxfh,
.create_rxfh_context = efx_ethtool_create_rxfh_context,
.modify_rxfh_context = efx_ethtool_modify_rxfh_context,
.remove_rxfh_context = efx_ethtool_remove_rxfh_context,
.get_module_info = efx_ethtool_get_module_info, .get_module_info = efx_ethtool_get_module_info,
.get_module_eeprom = efx_ethtool_get_module_eeprom, .get_module_eeprom = efx_ethtool_get_module_eeprom,
......
...@@ -299,7 +299,7 @@ static int efx_probe_nic(struct efx_nic *efx) ...@@ -299,7 +299,7 @@ static int efx_probe_nic(struct efx_nic *efx)
if (efx->n_channels > 1) if (efx->n_channels > 1)
netdev_rss_key_fill(efx->rss_context.rx_hash_key, netdev_rss_key_fill(efx->rss_context.rx_hash_key,
sizeof(efx->rss_context.rx_hash_key)); sizeof(efx->rss_context.rx_hash_key));
efx_set_default_rx_indir_table(efx, &efx->rss_context); efx_set_default_rx_indir_table(efx, efx->rss_context.rx_indir_table);
/* Initialise the interrupt moderation settings */ /* Initialise the interrupt moderation settings */
efx->irq_mod_step_us = DIV_ROUND_UP(efx->timer_quantum_ns, 1000); efx->irq_mod_step_us = DIV_ROUND_UP(efx->timer_quantum_ns, 1000);
......
...@@ -158,7 +158,7 @@ static inline s32 efx_filter_get_rx_ids(struct efx_nic *efx, ...@@ -158,7 +158,7 @@ static inline s32 efx_filter_get_rx_ids(struct efx_nic *efx,
} }
/* RSS contexts */ /* RSS contexts */
static inline bool efx_rss_active(struct efx_rss_context *ctx) static inline bool efx_rss_active(struct efx_rss_context_priv *ctx)
{ {
return ctx->context_id != EFX_MCDI_RSS_CONTEXT_INVALID; return ctx->context_id != EFX_MCDI_RSS_CONTEXT_INVALID;
} }
......
...@@ -714,7 +714,7 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method) ...@@ -714,7 +714,7 @@ void efx_reset_down(struct efx_nic *efx, enum reset_type method)
mutex_lock(&efx->mac_lock); mutex_lock(&efx->mac_lock);
down_write(&efx->filter_sem); down_write(&efx->filter_sem);
mutex_lock(&efx->rss_lock); mutex_lock(&efx->net_dev->ethtool->rss_lock);
efx->type->fini(efx); efx->type->fini(efx);
} }
...@@ -777,7 +777,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) ...@@ -777,7 +777,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
if (efx->type->rx_restore_rss_contexts) if (efx->type->rx_restore_rss_contexts)
efx->type->rx_restore_rss_contexts(efx); efx->type->rx_restore_rss_contexts(efx);
mutex_unlock(&efx->rss_lock); mutex_unlock(&efx->net_dev->ethtool->rss_lock);
efx->type->filter_table_restore(efx); efx->type->filter_table_restore(efx);
up_write(&efx->filter_sem); up_write(&efx->filter_sem);
...@@ -793,7 +793,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok) ...@@ -793,7 +793,7 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method, bool ok)
fail: fail:
efx->port_initialized = false; efx->port_initialized = false;
mutex_unlock(&efx->rss_lock); mutex_unlock(&efx->net_dev->ethtool->rss_lock);
up_write(&efx->filter_sem); up_write(&efx->filter_sem);
mutex_unlock(&efx->mac_lock); mutex_unlock(&efx->mac_lock);
...@@ -1000,9 +1000,7 @@ int efx_init_struct(struct efx_nic *efx, struct pci_dev *pci_dev) ...@@ -1000,9 +1000,7 @@ int efx_init_struct(struct efx_nic *efx, struct pci_dev *pci_dev)
efx->type->rx_hash_offset - efx->type->rx_prefix_size; efx->type->rx_hash_offset - efx->type->rx_prefix_size;
efx->rx_packet_ts_offset = efx->rx_packet_ts_offset =
efx->type->rx_ts_offset - efx->type->rx_prefix_size; efx->type->rx_ts_offset - efx->type->rx_prefix_size;
INIT_LIST_HEAD(&efx->rss_context.list); efx->rss_context.priv.context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
efx->rss_context.context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
mutex_init(&efx->rss_lock);
efx->vport_id = EVB_PORT_ID_ASSIGNED; efx->vport_id = EVB_PORT_ID_ASSIGNED;
spin_lock_init(&efx->stats_lock); spin_lock_init(&efx->stats_lock);
efx->vi_stride = EFX_DEFAULT_VI_STRIDE; efx->vi_stride = EFX_DEFAULT_VI_STRIDE;
......
...@@ -268,8 +268,12 @@ const struct ethtool_ops efx_ethtool_ops = { ...@@ -268,8 +268,12 @@ const struct ethtool_ops efx_ethtool_ops = {
.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_key_size = efx_ethtool_get_rxfh_key_size,
.rxfh_priv_size = sizeof(struct efx_rss_context_priv),
.get_rxfh = efx_ethtool_get_rxfh, .get_rxfh = efx_ethtool_get_rxfh,
.set_rxfh = efx_ethtool_set_rxfh, .set_rxfh = efx_ethtool_set_rxfh,
.create_rxfh_context = efx_ethtool_create_rxfh_context,
.modify_rxfh_context = efx_ethtool_modify_rxfh_context,
.remove_rxfh_context = efx_ethtool_remove_rxfh_context,
.get_ts_info = efx_ethtool_get_ts_info, .get_ts_info = efx_ethtool_get_ts_info,
.get_module_info = efx_ethtool_get_module_info, .get_module_info = efx_ethtool_get_module_info,
.get_module_eeprom = efx_ethtool_get_module_eeprom, .get_module_eeprom = efx_ethtool_get_module_eeprom,
......
...@@ -820,10 +820,10 @@ int efx_ethtool_get_rxnfc(struct net_device *net_dev, ...@@ -820,10 +820,10 @@ int efx_ethtool_get_rxnfc(struct net_device *net_dev,
return 0; return 0;
case ETHTOOL_GRXFH: { case ETHTOOL_GRXFH: {
struct efx_rss_context *ctx = &efx->rss_context; struct efx_rss_context_priv *ctx = &efx->rss_context.priv;
__u64 data; __u64 data;
mutex_lock(&efx->rss_lock); mutex_lock(&net_dev->ethtool->rss_lock);
if (info->flow_type & FLOW_RSS && info->rss_context) { if (info->flow_type & FLOW_RSS && info->rss_context) {
ctx = efx_find_rss_context_entry(efx, info->rss_context); ctx = efx_find_rss_context_entry(efx, info->rss_context);
if (!ctx) { if (!ctx) {
...@@ -864,7 +864,7 @@ int efx_ethtool_get_rxnfc(struct net_device *net_dev, ...@@ -864,7 +864,7 @@ int efx_ethtool_get_rxnfc(struct net_device *net_dev,
out_setdata_unlock: out_setdata_unlock:
info->data = data; info->data = data;
out_unlock: out_unlock:
mutex_unlock(&efx->rss_lock); mutex_unlock(&net_dev->ethtool->rss_lock);
return rc; return rc;
} }
...@@ -1167,31 +1167,33 @@ static int efx_ethtool_get_rxfh_context(struct net_device *net_dev, ...@@ -1167,31 +1167,33 @@ static int efx_ethtool_get_rxfh_context(struct net_device *net_dev,
struct ethtool_rxfh_param *rxfh) struct ethtool_rxfh_param *rxfh)
{ {
struct efx_nic *efx = efx_netdev_priv(net_dev); struct efx_nic *efx = efx_netdev_priv(net_dev);
struct efx_rss_context *ctx; struct efx_rss_context_priv *ctx_priv;
struct efx_rss_context ctx;
int rc = 0; int rc = 0;
if (!efx->type->rx_pull_rss_context_config) if (!efx->type->rx_pull_rss_context_config)
return -EOPNOTSUPP; return -EOPNOTSUPP;
mutex_lock(&efx->rss_lock); mutex_lock(&net_dev->ethtool->rss_lock);
ctx = efx_find_rss_context_entry(efx, rxfh->rss_context); ctx_priv = efx_find_rss_context_entry(efx, rxfh->rss_context);
if (!ctx) { if (!ctx_priv) {
rc = -ENOENT; rc = -ENOENT;
goto out_unlock; goto out_unlock;
} }
rc = efx->type->rx_pull_rss_context_config(efx, ctx); ctx.priv = *ctx_priv;
rc = efx->type->rx_pull_rss_context_config(efx, &ctx);
if (rc) if (rc)
goto out_unlock; goto out_unlock;
rxfh->hfunc = ETH_RSS_HASH_TOP; rxfh->hfunc = ETH_RSS_HASH_TOP;
if (rxfh->indir) if (rxfh->indir)
memcpy(rxfh->indir, ctx->rx_indir_table, memcpy(rxfh->indir, ctx.rx_indir_table,
sizeof(ctx->rx_indir_table)); sizeof(ctx.rx_indir_table));
if (rxfh->key) if (rxfh->key)
memcpy(rxfh->key, ctx->rx_hash_key, memcpy(rxfh->key, ctx.rx_hash_key,
efx->type->rx_hash_key_size); efx->type->rx_hash_key_size);
out_unlock: out_unlock:
mutex_unlock(&efx->rss_lock); mutex_unlock(&net_dev->ethtool->rss_lock);
return rc; return rc;
} }
...@@ -1218,68 +1220,85 @@ int efx_ethtool_get_rxfh(struct net_device *net_dev, ...@@ -1218,68 +1220,85 @@ int efx_ethtool_get_rxfh(struct net_device *net_dev,
return 0; return 0;
} }
static int efx_ethtool_set_rxfh_context(struct net_device *net_dev, int efx_ethtool_modify_rxfh_context(struct net_device *net_dev,
struct ethtool_rxfh_param *rxfh, struct ethtool_rxfh_context *ctx,
struct netlink_ext_ack *extack) const struct ethtool_rxfh_param *rxfh,
struct netlink_ext_ack *extack)
{ {
struct efx_nic *efx = efx_netdev_priv(net_dev); struct efx_nic *efx = efx_netdev_priv(net_dev);
u32 *rss_context = &rxfh->rss_context; struct efx_rss_context_priv *priv;
struct efx_rss_context *ctx; const u32 *indir = rxfh->indir;
u32 *indir = rxfh->indir; const u8 *key = rxfh->key;
bool allocated = false;
u8 *key = rxfh->key;
int rc;
if (!efx->type->rx_push_rss_context_config) if (!efx->type->rx_push_rss_context_config) {
NL_SET_ERR_MSG_MOD(extack,
"NIC type does not support custom contexts");
return -EOPNOTSUPP; return -EOPNOTSUPP;
mutex_lock(&efx->rss_lock);
if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) {
if (rxfh->rss_delete) {
/* alloc + delete == Nothing to do */
rc = -EINVAL;
goto out_unlock;
}
ctx = efx_alloc_rss_context_entry(efx);
if (!ctx) {
rc = -ENOMEM;
goto out_unlock;
}
ctx->context_id = EFX_MCDI_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(efx, *rss_context);
if (!ctx) {
rc = -ENOENT;
goto out_unlock;
}
} }
/* Hash function is Toeplitz, cannot be changed */
if (rxfh->rss_delete) { if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE &&
/* delete this context */ rxfh->hfunc != ETH_RSS_HASH_TOP) {
rc = efx->type->rx_push_rss_context_config(efx, ctx, NULL, NULL); NL_SET_ERR_MSG_MOD(extack, "Only Toeplitz hash is supported");
if (!rc) return -EOPNOTSUPP;
efx_free_rss_context_entry(ctx);
goto out_unlock;
} }
priv = ethtool_rxfh_context_priv(ctx);
if (!key) if (!key)
key = ctx->rx_hash_key; key = ethtool_rxfh_context_key(ctx);
if (!indir) if (!indir)
indir = ctx->rx_indir_table; indir = ethtool_rxfh_context_indir(ctx);
rc = efx->type->rx_push_rss_context_config(efx, ctx, indir, key); return efx->type->rx_push_rss_context_config(efx, priv, indir, key,
if (rc && allocated) false);
efx_free_rss_context_entry(ctx); }
else
*rss_context = ctx->user_id; int efx_ethtool_create_rxfh_context(struct net_device *net_dev,
out_unlock: struct ethtool_rxfh_context *ctx,
mutex_unlock(&efx->rss_lock); const struct ethtool_rxfh_param *rxfh,
return rc; struct netlink_ext_ack *extack)
{
struct efx_nic *efx = efx_netdev_priv(net_dev);
struct efx_rss_context_priv *priv;
priv = ethtool_rxfh_context_priv(ctx);
priv->context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
priv->rx_hash_udp_4tuple = false;
/* Generate default indir table and/or key if not specified.
* We use ctx as a place to store these; this is fine because
* we're doing a create, so if we fail then the ctx will just
* be deleted.
*/
if (!rxfh->indir)
efx_set_default_rx_indir_table(efx, ethtool_rxfh_context_indir(ctx));
if (!rxfh->key)
netdev_rss_key_fill(ethtool_rxfh_context_key(ctx),
ctx->key_size);
if (rxfh->hfunc == ETH_RSS_HASH_NO_CHANGE)
ctx->hfunc = ETH_RSS_HASH_TOP;
if (rxfh->input_xfrm == RXH_XFRM_NO_CHANGE)
ctx->input_xfrm = 0;
return efx_ethtool_modify_rxfh_context(net_dev, ctx, rxfh, extack);
}
int efx_ethtool_remove_rxfh_context(struct net_device *net_dev,
struct ethtool_rxfh_context *ctx,
u32 rss_context,
struct netlink_ext_ack *extack)
{
struct efx_nic *efx = efx_netdev_priv(net_dev);
struct efx_rss_context_priv *priv;
if (!efx->type->rx_push_rss_context_config) {
NL_SET_ERR_MSG_MOD(extack,
"NIC type does not support custom contexts");
return -EOPNOTSUPP;
}
priv = ethtool_rxfh_context_priv(ctx);
return efx->type->rx_push_rss_context_config(efx, priv, NULL, NULL,
true);
} }
int efx_ethtool_set_rxfh(struct net_device *net_dev, int efx_ethtool_set_rxfh(struct net_device *net_dev,
...@@ -1295,8 +1314,9 @@ int efx_ethtool_set_rxfh(struct net_device *net_dev, ...@@ -1295,8 +1314,9 @@ int efx_ethtool_set_rxfh(struct net_device *net_dev,
rxfh->hfunc != ETH_RSS_HASH_TOP) rxfh->hfunc != ETH_RSS_HASH_TOP)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (rxfh->rss_context) /* Custom contexts should use new API */
return efx_ethtool_set_rxfh_context(net_dev, rxfh, extack); if (WARN_ON_ONCE(rxfh->rss_context))
return -EIO;
if (!indir && !key) if (!indir && !key)
return 0; return 0;
......
...@@ -49,6 +49,18 @@ int efx_ethtool_get_rxfh(struct net_device *net_dev, ...@@ -49,6 +49,18 @@ int efx_ethtool_get_rxfh(struct net_device *net_dev,
int efx_ethtool_set_rxfh(struct net_device *net_dev, int efx_ethtool_set_rxfh(struct net_device *net_dev,
struct ethtool_rxfh_param *rxfh, struct ethtool_rxfh_param *rxfh,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
int efx_ethtool_create_rxfh_context(struct net_device *net_dev,
struct ethtool_rxfh_context *ctx,
const struct ethtool_rxfh_param *rxfh,
struct netlink_ext_ack *extack);
int efx_ethtool_modify_rxfh_context(struct net_device *net_dev,
struct ethtool_rxfh_context *ctx,
const struct ethtool_rxfh_param *rxfh,
struct netlink_ext_ack *extack);
int efx_ethtool_remove_rxfh_context(struct net_device *net_dev,
struct ethtool_rxfh_context *ctx,
u32 rss_context,
struct netlink_ext_ack *extack);
int efx_ethtool_reset(struct net_device *net_dev, u32 *flags); int efx_ethtool_reset(struct net_device *net_dev, u32 *flags);
int efx_ethtool_get_module_eeprom(struct net_device *net_dev, int efx_ethtool_get_module_eeprom(struct net_device *net_dev,
struct ethtool_eeprom *ee, struct ethtool_eeprom *ee,
......
...@@ -194,7 +194,7 @@ efx_mcdi_filter_push_prep_set_match_fields(struct efx_nic *efx, ...@@ -194,7 +194,7 @@ efx_mcdi_filter_push_prep_set_match_fields(struct efx_nic *efx,
static void efx_mcdi_filter_push_prep(struct efx_nic *efx, static void efx_mcdi_filter_push_prep(struct efx_nic *efx,
const struct efx_filter_spec *spec, const struct efx_filter_spec *spec,
efx_dword_t *inbuf, u64 handle, efx_dword_t *inbuf, u64 handle,
struct efx_rss_context *ctx, struct efx_rss_context_priv *ctx,
bool replacing) bool replacing)
{ {
u32 flags = spec->flags; u32 flags = spec->flags;
...@@ -245,7 +245,7 @@ static void efx_mcdi_filter_push_prep(struct efx_nic *efx, ...@@ -245,7 +245,7 @@ static void efx_mcdi_filter_push_prep(struct efx_nic *efx,
static int efx_mcdi_filter_push(struct efx_nic *efx, static int efx_mcdi_filter_push(struct efx_nic *efx,
const struct efx_filter_spec *spec, u64 *handle, const struct efx_filter_spec *spec, u64 *handle,
struct efx_rss_context *ctx, bool replacing) struct efx_rss_context_priv *ctx, bool replacing)
{ {
MCDI_DECLARE_BUF(inbuf, MC_CMD_FILTER_OP_EXT_IN_LEN); MCDI_DECLARE_BUF(inbuf, MC_CMD_FILTER_OP_EXT_IN_LEN);
MCDI_DECLARE_BUF(outbuf, MC_CMD_FILTER_OP_EXT_OUT_LEN); MCDI_DECLARE_BUF(outbuf, MC_CMD_FILTER_OP_EXT_OUT_LEN);
...@@ -345,9 +345,9 @@ static s32 efx_mcdi_filter_insert_locked(struct efx_nic *efx, ...@@ -345,9 +345,9 @@ static s32 efx_mcdi_filter_insert_locked(struct efx_nic *efx,
bool replace_equal) bool replace_equal)
{ {
DECLARE_BITMAP(mc_rem_map, EFX_EF10_FILTER_SEARCH_LIMIT); DECLARE_BITMAP(mc_rem_map, EFX_EF10_FILTER_SEARCH_LIMIT);
struct efx_rss_context_priv *ctx = NULL;
struct efx_mcdi_filter_table *table; struct efx_mcdi_filter_table *table;
struct efx_filter_spec *saved_spec; struct efx_filter_spec *saved_spec;
struct efx_rss_context *ctx = NULL;
unsigned int match_pri, hash; unsigned int match_pri, hash;
unsigned int priv_flags; unsigned int priv_flags;
bool rss_locked = false; bool rss_locked = false;
...@@ -380,12 +380,12 @@ static s32 efx_mcdi_filter_insert_locked(struct efx_nic *efx, ...@@ -380,12 +380,12 @@ static s32 efx_mcdi_filter_insert_locked(struct efx_nic *efx,
bitmap_zero(mc_rem_map, EFX_EF10_FILTER_SEARCH_LIMIT); bitmap_zero(mc_rem_map, EFX_EF10_FILTER_SEARCH_LIMIT);
if (spec->flags & EFX_FILTER_FLAG_RX_RSS) { if (spec->flags & EFX_FILTER_FLAG_RX_RSS) {
mutex_lock(&efx->rss_lock); mutex_lock(&efx->net_dev->ethtool->rss_lock);
rss_locked = true; rss_locked = true;
if (spec->rss_context) if (spec->rss_context)
ctx = efx_find_rss_context_entry(efx, spec->rss_context); ctx = efx_find_rss_context_entry(efx, spec->rss_context);
else else
ctx = &efx->rss_context; ctx = &efx->rss_context.priv;
if (!ctx) { if (!ctx) {
rc = -ENOENT; rc = -ENOENT;
goto out_unlock; goto out_unlock;
...@@ -548,7 +548,7 @@ static s32 efx_mcdi_filter_insert_locked(struct efx_nic *efx, ...@@ -548,7 +548,7 @@ static s32 efx_mcdi_filter_insert_locked(struct efx_nic *efx,
out_unlock: out_unlock:
if (rss_locked) if (rss_locked)
mutex_unlock(&efx->rss_lock); mutex_unlock(&efx->net_dev->ethtool->rss_lock);
up_write(&table->lock); up_write(&table->lock);
return rc; return rc;
} }
...@@ -611,13 +611,13 @@ static int efx_mcdi_filter_remove_internal(struct efx_nic *efx, ...@@ -611,13 +611,13 @@ static int efx_mcdi_filter_remove_internal(struct efx_nic *efx,
new_spec.priority = EFX_FILTER_PRI_AUTO; new_spec.priority = EFX_FILTER_PRI_AUTO;
new_spec.flags = (EFX_FILTER_FLAG_RX | new_spec.flags = (EFX_FILTER_FLAG_RX |
(efx_rss_active(&efx->rss_context) ? (efx_rss_active(&efx->rss_context.priv) ?
EFX_FILTER_FLAG_RX_RSS : 0)); EFX_FILTER_FLAG_RX_RSS : 0));
new_spec.dmaq_id = 0; new_spec.dmaq_id = 0;
new_spec.rss_context = 0; new_spec.rss_context = 0;
rc = efx_mcdi_filter_push(efx, &new_spec, rc = efx_mcdi_filter_push(efx, &new_spec,
&table->entry[filter_idx].handle, &table->entry[filter_idx].handle,
&efx->rss_context, &efx->rss_context.priv,
true); true);
if (rc == 0) if (rc == 0)
...@@ -764,7 +764,7 @@ static int efx_mcdi_filter_insert_addr_list(struct efx_nic *efx, ...@@ -764,7 +764,7 @@ static int efx_mcdi_filter_insert_addr_list(struct efx_nic *efx,
ids = vlan->uc; ids = vlan->uc;
} }
filter_flags = efx_rss_active(&efx->rss_context) ? EFX_FILTER_FLAG_RX_RSS : 0; filter_flags = efx_rss_active(&efx->rss_context.priv) ? EFX_FILTER_FLAG_RX_RSS : 0;
/* Insert/renew filters */ /* Insert/renew filters */
for (i = 0; i < addr_count; i++) { for (i = 0; i < addr_count; i++) {
...@@ -833,7 +833,7 @@ static int efx_mcdi_filter_insert_def(struct efx_nic *efx, ...@@ -833,7 +833,7 @@ static int efx_mcdi_filter_insert_def(struct efx_nic *efx,
int rc; int rc;
u16 *id; u16 *id;
filter_flags = efx_rss_active(&efx->rss_context) ? EFX_FILTER_FLAG_RX_RSS : 0; filter_flags = efx_rss_active(&efx->rss_context.priv) ? EFX_FILTER_FLAG_RX_RSS : 0;
efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, filter_flags, 0); efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, filter_flags, 0);
...@@ -1375,8 +1375,8 @@ void efx_mcdi_filter_table_restore(struct efx_nic *efx) ...@@ -1375,8 +1375,8 @@ void efx_mcdi_filter_table_restore(struct efx_nic *efx)
struct efx_mcdi_filter_table *table = efx->filter_state; struct efx_mcdi_filter_table *table = efx->filter_state;
unsigned int invalid_filters = 0, failed = 0; unsigned int invalid_filters = 0, failed = 0;
struct efx_mcdi_filter_vlan *vlan; struct efx_mcdi_filter_vlan *vlan;
struct efx_rss_context_priv *ctx;
struct efx_filter_spec *spec; struct efx_filter_spec *spec;
struct efx_rss_context *ctx;
unsigned int filter_idx; unsigned int filter_idx;
u32 mcdi_flags; u32 mcdi_flags;
int match_pri; int match_pri;
...@@ -1388,7 +1388,7 @@ void efx_mcdi_filter_table_restore(struct efx_nic *efx) ...@@ -1388,7 +1388,7 @@ void efx_mcdi_filter_table_restore(struct efx_nic *efx)
return; return;
down_write(&table->lock); down_write(&table->lock);
mutex_lock(&efx->rss_lock); mutex_lock(&efx->net_dev->ethtool->rss_lock);
for (filter_idx = 0; filter_idx < EFX_MCDI_FILTER_TBL_ROWS; filter_idx++) { for (filter_idx = 0; filter_idx < EFX_MCDI_FILTER_TBL_ROWS; filter_idx++) {
spec = efx_mcdi_filter_entry_spec(table, filter_idx); spec = efx_mcdi_filter_entry_spec(table, filter_idx);
...@@ -1407,7 +1407,7 @@ void efx_mcdi_filter_table_restore(struct efx_nic *efx) ...@@ -1407,7 +1407,7 @@ void efx_mcdi_filter_table_restore(struct efx_nic *efx)
if (spec->rss_context) if (spec->rss_context)
ctx = efx_find_rss_context_entry(efx, spec->rss_context); ctx = efx_find_rss_context_entry(efx, spec->rss_context);
else else
ctx = &efx->rss_context; ctx = &efx->rss_context.priv;
if (spec->flags & EFX_FILTER_FLAG_RX_RSS) { if (spec->flags & EFX_FILTER_FLAG_RX_RSS) {
if (!ctx) { if (!ctx) {
netif_warn(efx, drv, efx->net_dev, netif_warn(efx, drv, efx->net_dev,
...@@ -1444,7 +1444,7 @@ void efx_mcdi_filter_table_restore(struct efx_nic *efx) ...@@ -1444,7 +1444,7 @@ void efx_mcdi_filter_table_restore(struct efx_nic *efx)
} }
} }
mutex_unlock(&efx->rss_lock); mutex_unlock(&efx->net_dev->ethtool->rss_lock);
up_write(&table->lock); up_write(&table->lock);
/* /*
...@@ -1861,7 +1861,8 @@ bool efx_mcdi_filter_rfs_expire_one(struct efx_nic *efx, u32 flow_id, ...@@ -1861,7 +1861,8 @@ bool efx_mcdi_filter_rfs_expire_one(struct efx_nic *efx, u32 flow_id,
RSS_MODE_HASH_ADDRS << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV6_RSS_MODE_LBN |\ RSS_MODE_HASH_ADDRS << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV6_RSS_MODE_LBN |\
RSS_MODE_HASH_ADDRS << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_OTHER_IPV6_RSS_MODE_LBN) RSS_MODE_HASH_ADDRS << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_OTHER_IPV6_RSS_MODE_LBN)
int efx_mcdi_get_rss_context_flags(struct efx_nic *efx, u32 context, u32 *flags) static int efx_mcdi_get_rss_context_flags(struct efx_nic *efx, u32 context,
u32 *flags)
{ {
/* /*
* Firmware had a bug (sfc bug 61952) where it would not actually * Firmware had a bug (sfc bug 61952) where it would not actually
...@@ -1909,8 +1910,8 @@ int efx_mcdi_get_rss_context_flags(struct efx_nic *efx, u32 context, u32 *flags) ...@@ -1909,8 +1910,8 @@ int efx_mcdi_get_rss_context_flags(struct efx_nic *efx, u32 context, u32 *flags)
* Defaults are 4-tuple for TCP and 2-tuple for UDP and other-IP, so we * Defaults are 4-tuple for TCP and 2-tuple for UDP and other-IP, so we
* just need to set the UDP ports flags (for both IP versions). * just need to set the UDP ports flags (for both IP versions).
*/ */
void efx_mcdi_set_rss_context_flags(struct efx_nic *efx, static void efx_mcdi_set_rss_context_flags(struct efx_nic *efx,
struct efx_rss_context *ctx) struct efx_rss_context_priv *ctx)
{ {
MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN); MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN);
u32 flags; u32 flags;
...@@ -1931,7 +1932,7 @@ void efx_mcdi_set_rss_context_flags(struct efx_nic *efx, ...@@ -1931,7 +1932,7 @@ void efx_mcdi_set_rss_context_flags(struct efx_nic *efx,
} }
static int efx_mcdi_filter_alloc_rss_context(struct efx_nic *efx, bool exclusive, static int efx_mcdi_filter_alloc_rss_context(struct efx_nic *efx, bool exclusive,
struct efx_rss_context *ctx, struct efx_rss_context_priv *ctx,
unsigned *context_size) unsigned *context_size)
{ {
MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN); MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN);
...@@ -2032,25 +2033,26 @@ void efx_mcdi_rx_free_indir_table(struct efx_nic *efx) ...@@ -2032,25 +2033,26 @@ void efx_mcdi_rx_free_indir_table(struct efx_nic *efx)
{ {
int rc; int rc;
if (efx->rss_context.context_id != EFX_MCDI_RSS_CONTEXT_INVALID) { if (efx->rss_context.priv.context_id != EFX_MCDI_RSS_CONTEXT_INVALID) {
rc = efx_mcdi_filter_free_rss_context(efx, efx->rss_context.context_id); rc = efx_mcdi_filter_free_rss_context(efx, efx->rss_context.priv.context_id);
WARN_ON(rc != 0); WARN_ON(rc != 0);
} }
efx->rss_context.context_id = EFX_MCDI_RSS_CONTEXT_INVALID; efx->rss_context.priv.context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
} }
static int efx_mcdi_filter_rx_push_shared_rss_config(struct efx_nic *efx, static int efx_mcdi_filter_rx_push_shared_rss_config(struct efx_nic *efx,
unsigned *context_size) unsigned *context_size)
{ {
struct efx_mcdi_filter_table *table = efx->filter_state; struct efx_mcdi_filter_table *table = efx->filter_state;
int rc = efx_mcdi_filter_alloc_rss_context(efx, false, &efx->rss_context, int rc = efx_mcdi_filter_alloc_rss_context(efx, false,
context_size); &efx->rss_context.priv,
context_size);
if (rc != 0) if (rc != 0)
return rc; return rc;
table->rx_rss_context_exclusive = false; table->rx_rss_context_exclusive = false;
efx_set_default_rx_indir_table(efx, &efx->rss_context); efx_set_default_rx_indir_table(efx, efx->rss_context.rx_indir_table);
return 0; return 0;
} }
...@@ -2058,26 +2060,27 @@ static int efx_mcdi_filter_rx_push_exclusive_rss_config(struct efx_nic *efx, ...@@ -2058,26 +2060,27 @@ static int efx_mcdi_filter_rx_push_exclusive_rss_config(struct efx_nic *efx,
const u32 *rx_indir_table, const u32 *rx_indir_table,
const u8 *key) const u8 *key)
{ {
u32 old_rx_rss_context = efx->rss_context.priv.context_id;
struct efx_mcdi_filter_table *table = efx->filter_state; struct efx_mcdi_filter_table *table = efx->filter_state;
u32 old_rx_rss_context = efx->rss_context.context_id;
int rc; int rc;
if (efx->rss_context.context_id == EFX_MCDI_RSS_CONTEXT_INVALID || if (efx->rss_context.priv.context_id == EFX_MCDI_RSS_CONTEXT_INVALID ||
!table->rx_rss_context_exclusive) { !table->rx_rss_context_exclusive) {
rc = efx_mcdi_filter_alloc_rss_context(efx, true, &efx->rss_context, rc = efx_mcdi_filter_alloc_rss_context(efx, true,
NULL); &efx->rss_context.priv,
NULL);
if (rc == -EOPNOTSUPP) if (rc == -EOPNOTSUPP)
return rc; return rc;
else if (rc != 0) else if (rc != 0)
goto fail1; goto fail1;
} }
rc = efx_mcdi_filter_populate_rss_table(efx, efx->rss_context.context_id, rc = efx_mcdi_filter_populate_rss_table(efx, efx->rss_context.priv.context_id,
rx_indir_table, key); rx_indir_table, key);
if (rc != 0) if (rc != 0)
goto fail2; goto fail2;
if (efx->rss_context.context_id != old_rx_rss_context && if (efx->rss_context.priv.context_id != old_rx_rss_context &&
old_rx_rss_context != EFX_MCDI_RSS_CONTEXT_INVALID) old_rx_rss_context != EFX_MCDI_RSS_CONTEXT_INVALID)
WARN_ON(efx_mcdi_filter_free_rss_context(efx, old_rx_rss_context) != 0); WARN_ON(efx_mcdi_filter_free_rss_context(efx, old_rx_rss_context) != 0);
table->rx_rss_context_exclusive = true; table->rx_rss_context_exclusive = true;
...@@ -2091,9 +2094,9 @@ static int efx_mcdi_filter_rx_push_exclusive_rss_config(struct efx_nic *efx, ...@@ -2091,9 +2094,9 @@ static int efx_mcdi_filter_rx_push_exclusive_rss_config(struct efx_nic *efx,
return 0; return 0;
fail2: fail2:
if (old_rx_rss_context != efx->rss_context.context_id) { if (old_rx_rss_context != efx->rss_context.priv.context_id) {
WARN_ON(efx_mcdi_filter_free_rss_context(efx, efx->rss_context.context_id) != 0); WARN_ON(efx_mcdi_filter_free_rss_context(efx, efx->rss_context.priv.context_id) != 0);
efx->rss_context.context_id = old_rx_rss_context; efx->rss_context.priv.context_id = old_rx_rss_context;
} }
fail1: fail1:
netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc);
...@@ -2101,33 +2104,28 @@ static int efx_mcdi_filter_rx_push_exclusive_rss_config(struct efx_nic *efx, ...@@ -2101,33 +2104,28 @@ static int efx_mcdi_filter_rx_push_exclusive_rss_config(struct efx_nic *efx,
} }
int efx_mcdi_rx_push_rss_context_config(struct efx_nic *efx, int efx_mcdi_rx_push_rss_context_config(struct efx_nic *efx,
struct efx_rss_context *ctx, struct efx_rss_context_priv *ctx,
const u32 *rx_indir_table, const u32 *rx_indir_table,
const u8 *key) const u8 *key, bool delete)
{ {
int rc; int rc;
WARN_ON(!mutex_is_locked(&efx->rss_lock)); WARN_ON(!mutex_is_locked(&efx->net_dev->ethtool->rss_lock));
if (ctx->context_id == EFX_MCDI_RSS_CONTEXT_INVALID) { if (ctx->context_id == EFX_MCDI_RSS_CONTEXT_INVALID) {
if (delete)
/* already wasn't in HW, nothing to do */
return 0;
rc = efx_mcdi_filter_alloc_rss_context(efx, true, ctx, NULL); rc = efx_mcdi_filter_alloc_rss_context(efx, true, ctx, NULL);
if (rc) if (rc)
return rc; return rc;
} }
if (!rx_indir_table) /* Delete this context */ if (delete) /* Delete this context */
return efx_mcdi_filter_free_rss_context(efx, ctx->context_id); return efx_mcdi_filter_free_rss_context(efx, ctx->context_id);
rc = efx_mcdi_filter_populate_rss_table(efx, ctx->context_id, return efx_mcdi_filter_populate_rss_table(efx, ctx->context_id,
rx_indir_table, key); rx_indir_table, key);
if (rc)
return rc;
memcpy(ctx->rx_indir_table, rx_indir_table,
sizeof(efx->rss_context.rx_indir_table));
memcpy(ctx->rx_hash_key, key, efx->type->rx_hash_key_size);
return 0;
} }
int efx_mcdi_rx_pull_rss_context_config(struct efx_nic *efx, int efx_mcdi_rx_pull_rss_context_config(struct efx_nic *efx,
...@@ -2139,16 +2137,16 @@ int efx_mcdi_rx_pull_rss_context_config(struct efx_nic *efx, ...@@ -2139,16 +2137,16 @@ int efx_mcdi_rx_pull_rss_context_config(struct efx_nic *efx,
size_t outlen; size_t outlen;
int rc, i; int rc, i;
WARN_ON(!mutex_is_locked(&efx->rss_lock)); WARN_ON(!mutex_is_locked(&efx->net_dev->ethtool->rss_lock));
BUILD_BUG_ON(MC_CMD_RSS_CONTEXT_GET_TABLE_IN_LEN != BUILD_BUG_ON(MC_CMD_RSS_CONTEXT_GET_TABLE_IN_LEN !=
MC_CMD_RSS_CONTEXT_GET_KEY_IN_LEN); MC_CMD_RSS_CONTEXT_GET_KEY_IN_LEN);
if (ctx->context_id == EFX_MCDI_RSS_CONTEXT_INVALID) if (ctx->priv.context_id == EFX_MCDI_RSS_CONTEXT_INVALID)
return -ENOENT; return -ENOENT;
MCDI_SET_DWORD(inbuf, RSS_CONTEXT_GET_TABLE_IN_RSS_CONTEXT_ID, MCDI_SET_DWORD(inbuf, RSS_CONTEXT_GET_TABLE_IN_RSS_CONTEXT_ID,
ctx->context_id); ctx->priv.context_id);
BUILD_BUG_ON(ARRAY_SIZE(ctx->rx_indir_table) != BUILD_BUG_ON(ARRAY_SIZE(ctx->rx_indir_table) !=
MC_CMD_RSS_CONTEXT_GET_TABLE_OUT_INDIRECTION_TABLE_LEN); MC_CMD_RSS_CONTEXT_GET_TABLE_OUT_INDIRECTION_TABLE_LEN);
rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_GET_TABLE, inbuf, sizeof(inbuf), rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_GET_TABLE, inbuf, sizeof(inbuf),
...@@ -2164,7 +2162,7 @@ int efx_mcdi_rx_pull_rss_context_config(struct efx_nic *efx, ...@@ -2164,7 +2162,7 @@ int efx_mcdi_rx_pull_rss_context_config(struct efx_nic *efx,
RSS_CONTEXT_GET_TABLE_OUT_INDIRECTION_TABLE)[i]; RSS_CONTEXT_GET_TABLE_OUT_INDIRECTION_TABLE)[i];
MCDI_SET_DWORD(inbuf, RSS_CONTEXT_GET_KEY_IN_RSS_CONTEXT_ID, MCDI_SET_DWORD(inbuf, RSS_CONTEXT_GET_KEY_IN_RSS_CONTEXT_ID,
ctx->context_id); ctx->priv.context_id);
BUILD_BUG_ON(ARRAY_SIZE(ctx->rx_hash_key) != BUILD_BUG_ON(ARRAY_SIZE(ctx->rx_hash_key) !=
MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN); MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN);
rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_GET_KEY, inbuf, sizeof(inbuf), rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_GET_KEY, inbuf, sizeof(inbuf),
...@@ -2186,35 +2184,42 @@ int efx_mcdi_rx_pull_rss_config(struct efx_nic *efx) ...@@ -2186,35 +2184,42 @@ int efx_mcdi_rx_pull_rss_config(struct efx_nic *efx)
{ {
int rc; int rc;
mutex_lock(&efx->rss_lock); mutex_lock(&efx->net_dev->ethtool->rss_lock);
rc = efx_mcdi_rx_pull_rss_context_config(efx, &efx->rss_context); rc = efx_mcdi_rx_pull_rss_context_config(efx, &efx->rss_context);
mutex_unlock(&efx->rss_lock); mutex_unlock(&efx->net_dev->ethtool->rss_lock);
return rc; return rc;
} }
void efx_mcdi_rx_restore_rss_contexts(struct efx_nic *efx) void efx_mcdi_rx_restore_rss_contexts(struct efx_nic *efx)
{ {
struct efx_mcdi_filter_table *table = efx->filter_state; struct efx_mcdi_filter_table *table = efx->filter_state;
struct efx_rss_context *ctx; struct ethtool_rxfh_context *ctx;
unsigned long context;
int rc; int rc;
WARN_ON(!mutex_is_locked(&efx->rss_lock)); WARN_ON(!mutex_is_locked(&efx->net_dev->ethtool->rss_lock));
if (!table->must_restore_rss_contexts) if (!table->must_restore_rss_contexts)
return; return;
list_for_each_entry(ctx, &efx->rss_context.list, list) { xa_for_each(&efx->net_dev->ethtool->rss_ctx, context, ctx) {
struct efx_rss_context_priv *priv;
u32 *indir;
u8 *key;
priv = ethtool_rxfh_context_priv(ctx);
/* previous NIC RSS context is gone */ /* previous NIC RSS context is gone */
ctx->context_id = EFX_MCDI_RSS_CONTEXT_INVALID; priv->context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
/* so try to allocate a new one */ /* so try to allocate a new one */
rc = efx_mcdi_rx_push_rss_context_config(efx, ctx, indir = ethtool_rxfh_context_indir(ctx);
ctx->rx_indir_table, key = ethtool_rxfh_context_key(ctx);
ctx->rx_hash_key); rc = efx_mcdi_rx_push_rss_context_config(efx, priv, indir, key,
false);
if (rc) if (rc)
netif_warn(efx, probe, efx->net_dev, netif_warn(efx, probe, efx->net_dev,
"failed to restore RSS context %u, rc=%d" "failed to restore RSS context %lu, rc=%d"
"; RSS filters may fail to be applied\n", "; RSS filters may fail to be applied\n",
ctx->user_id, rc); context, rc);
} }
table->must_restore_rss_contexts = false; table->must_restore_rss_contexts = false;
} }
...@@ -2276,7 +2281,7 @@ int efx_mcdi_vf_rx_push_rss_config(struct efx_nic *efx, bool user, ...@@ -2276,7 +2281,7 @@ int efx_mcdi_vf_rx_push_rss_config(struct efx_nic *efx, bool user,
{ {
if (user) if (user)
return -EOPNOTSUPP; return -EOPNOTSUPP;
if (efx->rss_context.context_id != EFX_MCDI_RSS_CONTEXT_INVALID) if (efx->rss_context.priv.context_id != EFX_MCDI_RSS_CONTEXT_INVALID)
return 0; return 0;
return efx_mcdi_filter_rx_push_shared_rss_config(efx, NULL); return efx_mcdi_filter_rx_push_shared_rss_config(efx, NULL);
} }
...@@ -2295,7 +2300,7 @@ int efx_mcdi_push_default_indir_table(struct efx_nic *efx, ...@@ -2295,7 +2300,7 @@ int efx_mcdi_push_default_indir_table(struct efx_nic *efx,
efx_mcdi_rx_free_indir_table(efx); efx_mcdi_rx_free_indir_table(efx);
if (rss_spread > 1) { if (rss_spread > 1) {
efx_set_default_rx_indir_table(efx, &efx->rss_context); efx_set_default_rx_indir_table(efx, efx->rss_context.rx_indir_table);
rc = efx->type->rx_push_rss_config(efx, false, rc = efx->type->rx_push_rss_config(efx, false,
efx->rss_context.rx_indir_table, NULL); efx->rss_context.rx_indir_table, NULL);
} }
......
...@@ -145,9 +145,9 @@ void efx_mcdi_filter_del_vlan(struct efx_nic *efx, u16 vid); ...@@ -145,9 +145,9 @@ void efx_mcdi_filter_del_vlan(struct efx_nic *efx, u16 vid);
void efx_mcdi_rx_free_indir_table(struct efx_nic *efx); void efx_mcdi_rx_free_indir_table(struct efx_nic *efx);
int efx_mcdi_rx_push_rss_context_config(struct efx_nic *efx, int efx_mcdi_rx_push_rss_context_config(struct efx_nic *efx,
struct efx_rss_context *ctx, struct efx_rss_context_priv *ctx,
const u32 *rx_indir_table, const u32 *rx_indir_table,
const u8 *key); const u8 *key, bool delete);
int efx_mcdi_pf_rx_push_rss_config(struct efx_nic *efx, bool user, int efx_mcdi_pf_rx_push_rss_config(struct efx_nic *efx, bool user,
const u32 *rx_indir_table, const u32 *rx_indir_table,
const u8 *key); const u8 *key);
...@@ -161,10 +161,6 @@ int efx_mcdi_push_default_indir_table(struct efx_nic *efx, ...@@ -161,10 +161,6 @@ int efx_mcdi_push_default_indir_table(struct efx_nic *efx,
int efx_mcdi_rx_pull_rss_config(struct efx_nic *efx); int efx_mcdi_rx_pull_rss_config(struct efx_nic *efx);
int efx_mcdi_rx_pull_rss_context_config(struct efx_nic *efx, int efx_mcdi_rx_pull_rss_context_config(struct efx_nic *efx,
struct efx_rss_context *ctx); struct efx_rss_context *ctx);
int efx_mcdi_get_rss_context_flags(struct efx_nic *efx, u32 context,
u32 *flags);
void efx_mcdi_set_rss_context_flags(struct efx_nic *efx,
struct efx_rss_context *ctx);
void efx_mcdi_rx_restore_rss_contexts(struct efx_nic *efx); void efx_mcdi_rx_restore_rss_contexts(struct efx_nic *efx);
static inline void efx_mcdi_update_rx_scatter(struct efx_nic *efx) static inline void efx_mcdi_update_rx_scatter(struct efx_nic *efx)
......
...@@ -737,21 +737,24 @@ struct vfdi_status; ...@@ -737,21 +737,24 @@ struct vfdi_status;
/* The reserved RSS context value */ /* The reserved RSS context value */
#define EFX_MCDI_RSS_CONTEXT_INVALID 0xffffffff #define EFX_MCDI_RSS_CONTEXT_INVALID 0xffffffff
/** /**
* struct efx_rss_context - A user-defined RSS context for filtering * struct efx_rss_context_priv - driver private data for an RSS context
* @list: node of linked list on which this struct is stored
* @context_id: the RSS_CONTEXT_ID returned by MC firmware, or * @context_id: the RSS_CONTEXT_ID returned by MC firmware, or
* %EFX_MCDI_RSS_CONTEXT_INVALID if this context is not present on the NIC. * %EFX_MCDI_RSS_CONTEXT_INVALID if this context is not present on the NIC.
* For Siena, 0 if RSS is active, else %EFX_MCDI_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_udp_4tuple: UDP 4-tuple hashing enabled
*/
struct efx_rss_context_priv {
u32 context_id;
bool rx_hash_udp_4tuple;
};
/**
* struct efx_rss_context - an RSS context
* @priv: hardware-specific state
* @rx_hash_key: Toeplitz hash key for this RSS context * @rx_hash_key: Toeplitz hash key for this RSS context
* @indir_table: Indirection table for this RSS context * @indir_table: Indirection table for this RSS context
*/ */
struct efx_rss_context { struct efx_rss_context {
struct list_head list; struct efx_rss_context_priv priv;
u32 context_id;
u32 user_id;
bool rx_hash_udp_4tuple;
u8 rx_hash_key[40]; u8 rx_hash_key[40];
u32 rx_indir_table[128]; u32 rx_indir_table[128];
}; };
...@@ -883,9 +886,7 @@ struct efx_mae; ...@@ -883,9 +886,7 @@ struct efx_mae;
* @rx_packet_ts_offset: Offset of timestamp from start of packet data * @rx_packet_ts_offset: Offset of timestamp from start of packet data
* (valid only if channel->sync_timestamps_enabled; always negative) * (valid only if channel->sync_timestamps_enabled; always negative)
* @rx_scatter: Scatter mode enabled for receives * @rx_scatter: Scatter mode enabled for receives
* @rss_context: Main RSS context. Its @list member is the head of the list of * @rss_context: Main RSS context.
* RSS contexts created by user requests
* @rss_lock: Protects custom RSS context software state in @rss_context.list
* @vport_id: The function's vport ID, only relevant for PFs * @vport_id: The function's vport ID, only relevant for PFs
* @int_error_count: Number of internal errors seen recently * @int_error_count: Number of internal errors seen recently
* @int_error_expire: Time at which error count will be expired * @int_error_expire: Time at which error count will be expired
...@@ -1052,7 +1053,6 @@ struct efx_nic { ...@@ -1052,7 +1053,6 @@ struct efx_nic {
int rx_packet_ts_offset; int rx_packet_ts_offset;
bool rx_scatter; bool rx_scatter;
struct efx_rss_context rss_context; struct efx_rss_context rss_context;
struct mutex rss_lock;
u32 vport_id; u32 vport_id;
unsigned int_error_count; unsigned int_error_count;
...@@ -1416,9 +1416,9 @@ struct efx_nic_type { ...@@ -1416,9 +1416,9 @@ struct efx_nic_type {
const u32 *rx_indir_table, const u8 *key); const u32 *rx_indir_table, const u8 *key);
int (*rx_pull_rss_config)(struct efx_nic *efx); int (*rx_pull_rss_config)(struct efx_nic *efx);
int (*rx_push_rss_context_config)(struct efx_nic *efx, int (*rx_push_rss_context_config)(struct efx_nic *efx,
struct efx_rss_context *ctx, struct efx_rss_context_priv *ctx,
const u32 *rx_indir_table, const u32 *rx_indir_table,
const u8 *key); const u8 *key, bool delete);
int (*rx_pull_rss_context_config)(struct efx_nic *efx, int (*rx_pull_rss_context_config)(struct efx_nic *efx,
struct efx_rss_context *ctx); struct efx_rss_context *ctx);
void (*rx_restore_rss_contexts)(struct efx_nic *efx); void (*rx_restore_rss_contexts)(struct efx_nic *efx);
......
...@@ -557,69 +557,25 @@ efx_rx_packet_gro(struct efx_channel *channel, struct efx_rx_buffer *rx_buf, ...@@ -557,69 +557,25 @@ efx_rx_packet_gro(struct efx_channel *channel, struct efx_rx_buffer *rx_buf,
napi_gro_frags(napi); napi_gro_frags(napi);
} }
/* RSS contexts. We're using linked lists and crappy O(n) algorithms, because struct efx_rss_context_priv *efx_find_rss_context_entry(struct efx_nic *efx,
* (a) this is an infrequent control-plane operation and (b) n is small (max 64) u32 id)
*/
struct efx_rss_context *efx_alloc_rss_context_entry(struct efx_nic *efx)
{ {
struct list_head *head = &efx->rss_context.list; struct ethtool_rxfh_context *ctx;
struct efx_rss_context *ctx, *new;
u32 id = 1; /* Don't use zero, that refers to the master RSS context */
WARN_ON(!mutex_is_locked(&efx->rss_lock));
/* Search for first gap in the numbering */ WARN_ON(!mutex_is_locked(&efx->net_dev->ethtool->rss_lock));
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 */ ctx = xa_load(&efx->net_dev->ethtool->rss_ctx, id);
new = kmalloc(sizeof(*new), GFP_KERNEL); if (!ctx)
if (!new)
return NULL; return NULL;
new->context_id = EFX_MCDI_RSS_CONTEXT_INVALID; return ethtool_rxfh_context_priv(ctx);
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(struct efx_nic *efx, u32 id)
{
struct list_head *head = &efx->rss_context.list;
struct efx_rss_context *ctx;
WARN_ON(!mutex_is_locked(&efx->rss_lock));
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);
} }
void efx_set_default_rx_indir_table(struct efx_nic *efx, void efx_set_default_rx_indir_table(struct efx_nic *efx, u32 *indir)
struct efx_rss_context *ctx)
{ {
size_t i; size_t i;
for (i = 0; i < ARRAY_SIZE(ctx->rx_indir_table); i++) for (i = 0; i < ARRAY_SIZE(efx->rss_context.rx_indir_table); i++)
ctx->rx_indir_table[i] = indir[i] = ethtool_rxfh_indir_default(i, efx->rss_spread);
ethtool_rxfh_indir_default(i, efx->rss_spread);
} }
/** /**
......
...@@ -84,11 +84,9 @@ void ...@@ -84,11 +84,9 @@ void
efx_rx_packet_gro(struct efx_channel *channel, struct efx_rx_buffer *rx_buf, efx_rx_packet_gro(struct efx_channel *channel, struct efx_rx_buffer *rx_buf,
unsigned int n_frags, u8 *eh, __wsum csum); unsigned int n_frags, u8 *eh, __wsum csum);
struct efx_rss_context *efx_alloc_rss_context_entry(struct efx_nic *efx); struct efx_rss_context_priv *efx_find_rss_context_entry(struct efx_nic *efx,
struct efx_rss_context *efx_find_rss_context_entry(struct efx_nic *efx, u32 id); u32 id);
void efx_free_rss_context_entry(struct efx_rss_context *ctx); void efx_set_default_rx_indir_table(struct efx_nic *efx, u32 *indir);
void efx_set_default_rx_indir_table(struct efx_nic *efx,
struct efx_rss_context *ctx);
bool efx_filter_is_mc_recipient(const struct efx_filter_spec *spec); bool efx_filter_is_mc_recipient(const struct efx_filter_spec *spec);
bool efx_filter_spec_equal(const struct efx_filter_spec *left, bool efx_filter_spec_equal(const struct efx_filter_spec *left,
......
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