Skip to content

Commit

Permalink
sfc: move RPS code
Browse files Browse the repository at this point in the history
Includes a couple of filtering functions and also renames a constant.

Style fixes included.

Signed-off-by: Alexandru-Mihai Maftei <amaftei@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Alex Maftei (amaftei) authored and David S. Miller committed Jan 10, 2020
1 parent 3148231 commit f7226e0
Showing 8 changed files with 273 additions and 276 deletions.
28 changes: 14 additions & 14 deletions drivers/net/ethernet/sfc/ef10.c
Original file line number Diff line number Diff line change
@@ -660,7 +660,7 @@ static int efx_ef10_probe(struct efx_nic *efx)
}
nic_data->warm_boot_count = rc;

efx->rss_context.context_id = EFX_EF10_RSS_CONTEXT_INVALID;
efx->rss_context.context_id = EFX_MCDI_RSS_CONTEXT_INVALID;

nic_data->vport_id = EVB_PORT_ID_ASSIGNED;

@@ -1440,7 +1440,7 @@ static void efx_ef10_reset_mc_allocations(struct efx_nic *efx)
nic_data->must_restore_filters = true;
nic_data->must_restore_piobufs = true;
efx_ef10_forget_old_piobufs(efx);
efx->rss_context.context_id = EFX_EF10_RSS_CONTEXT_INVALID;
efx->rss_context.context_id = EFX_MCDI_RSS_CONTEXT_INVALID;

/* Driver-created vswitches and vports must be re-created */
nic_data->must_probe_vswitching = true;
@@ -2598,7 +2598,7 @@ static int efx_ef10_alloc_rss_context(struct efx_nic *efx, bool exclusive,
EFX_EF10_MAX_SHARED_RSS_CONTEXT_SIZE);

if (!exclusive && rss_spread == 1) {
ctx->context_id = EFX_EF10_RSS_CONTEXT_INVALID;
ctx->context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
if (context_size)
*context_size = 1;
return 0;
@@ -2685,11 +2685,11 @@ static void efx_ef10_rx_free_indir_table(struct efx_nic *efx)
{
int rc;

if (efx->rss_context.context_id != EFX_EF10_RSS_CONTEXT_INVALID) {
if (efx->rss_context.context_id != EFX_MCDI_RSS_CONTEXT_INVALID) {
rc = efx_ef10_free_rss_context(efx, efx->rss_context.context_id);
WARN_ON(rc != 0);
}
efx->rss_context.context_id = EFX_EF10_RSS_CONTEXT_INVALID;
efx->rss_context.context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
}

static int efx_ef10_rx_push_shared_rss_config(struct efx_nic *efx,
@@ -2715,7 +2715,7 @@ static int efx_ef10_rx_push_exclusive_rss_config(struct efx_nic *efx,
struct efx_ef10_nic_data *nic_data = efx->nic_data;
int rc;

if (efx->rss_context.context_id == EFX_EF10_RSS_CONTEXT_INVALID ||
if (efx->rss_context.context_id == EFX_MCDI_RSS_CONTEXT_INVALID ||
!nic_data->rx_rss_context_exclusive) {
rc = efx_ef10_alloc_rss_context(efx, true, &efx->rss_context,
NULL);
@@ -2731,7 +2731,7 @@ static int efx_ef10_rx_push_exclusive_rss_config(struct efx_nic *efx,
goto fail2;

if (efx->rss_context.context_id != old_rx_rss_context &&
old_rx_rss_context != EFX_EF10_RSS_CONTEXT_INVALID)
old_rx_rss_context != EFX_MCDI_RSS_CONTEXT_INVALID)
WARN_ON(efx_ef10_free_rss_context(efx, old_rx_rss_context) != 0);
nic_data->rx_rss_context_exclusive = true;
if (rx_indir_table != efx->rss_context.rx_indir_table)
@@ -2762,7 +2762,7 @@ static int efx_ef10_rx_push_rss_context_config(struct efx_nic *efx,

WARN_ON(!mutex_is_locked(&efx->rss_lock));

if (ctx->context_id == EFX_EF10_RSS_CONTEXT_INVALID) {
if (ctx->context_id == EFX_MCDI_RSS_CONTEXT_INVALID) {
rc = efx_ef10_alloc_rss_context(efx, true, ctx, NULL);
if (rc)
return rc;
@@ -2797,7 +2797,7 @@ static int efx_ef10_rx_pull_rss_context_config(struct efx_nic *efx,
BUILD_BUG_ON(MC_CMD_RSS_CONTEXT_GET_TABLE_IN_LEN !=
MC_CMD_RSS_CONTEXT_GET_KEY_IN_LEN);

if (ctx->context_id == EFX_EF10_RSS_CONTEXT_INVALID)
if (ctx->context_id == EFX_MCDI_RSS_CONTEXT_INVALID)
return -ENOENT;

MCDI_SET_DWORD(inbuf, RSS_CONTEXT_GET_TABLE_IN_RSS_CONTEXT_ID,
@@ -2858,7 +2858,7 @@ static void efx_ef10_rx_restore_rss_contexts(struct efx_nic *efx)

list_for_each_entry(ctx, &efx->rss_context.list, list) {
/* previous NIC RSS context is gone */
ctx->context_id = EFX_EF10_RSS_CONTEXT_INVALID;
ctx->context_id = EFX_MCDI_RSS_CONTEXT_INVALID;
/* so try to allocate a new one */
rc = efx_ef10_rx_push_rss_context_config(efx, ctx,
ctx->rx_indir_table,
@@ -2929,7 +2929,7 @@ static int efx_ef10_vf_rx_push_rss_config(struct efx_nic *efx, bool user,
{
if (user)
return -EOPNOTSUPP;
if (efx->rss_context.context_id != EFX_EF10_RSS_CONTEXT_INVALID)
if (efx->rss_context.context_id != EFX_MCDI_RSS_CONTEXT_INVALID)
return 0;
return efx_ef10_rx_push_shared_rss_config(efx, NULL);
}
@@ -3850,7 +3850,7 @@ static void efx_ef10_filter_push_prep(struct efx_nic *efx,
*/
if (WARN_ON_ONCE(!ctx))
flags &= ~EFX_FILTER_FLAG_RX_RSS;
else if (WARN_ON_ONCE(ctx->context_id == EFX_EF10_RSS_CONTEXT_INVALID))
else if (WARN_ON_ONCE(ctx->context_id == EFX_MCDI_RSS_CONTEXT_INVALID))
flags &= ~EFX_FILTER_FLAG_RX_RSS;
}

@@ -4029,7 +4029,7 @@ static s32 efx_ef10_filter_insert_locked(struct efx_nic *efx,
rc = -ENOENT;
goto out_unlock;
}
if (ctx->context_id == EFX_EF10_RSS_CONTEXT_INVALID) {
if (ctx->context_id == EFX_MCDI_RSS_CONTEXT_INVALID) {
rc = -EOPNOTSUPP;
goto out_unlock;
}
@@ -4770,7 +4770,7 @@ static void efx_ef10_filter_table_restore(struct efx_nic *efx)
invalid_filters++;
goto not_restored;
}
if (ctx->context_id == EFX_EF10_RSS_CONTEXT_INVALID) {
if (ctx->context_id == EFX_MCDI_RSS_CONTEXT_INVALID) {
netif_warn(efx, drv, efx->net_dev,
"Warning: unable to restore a filter with RSS context %u as it was not created.\n",
spec->rss_context);
200 changes: 0 additions & 200 deletions drivers/net/ethernet/sfc/efx.c
Original file line number Diff line number Diff line change
@@ -384,70 +384,6 @@ static void efx_remove_nic(struct efx_nic *efx)
efx->type->remove(efx);
}

static int efx_probe_filters(struct efx_nic *efx)
{
int rc;

init_rwsem(&efx->filter_sem);
mutex_lock(&efx->mac_lock);
down_write(&efx->filter_sem);
rc = efx->type->filter_table_probe(efx);
if (rc)
goto out_unlock;

#ifdef CONFIG_RFS_ACCEL
if (efx->type->offload_features & NETIF_F_NTUPLE) {
struct efx_channel *channel;
int i, success = 1;

efx_for_each_channel(channel, efx) {
channel->rps_flow_id =
kcalloc(efx->type->max_rx_ip_filters,
sizeof(*channel->rps_flow_id),
GFP_KERNEL);
if (!channel->rps_flow_id)
success = 0;
else
for (i = 0;
i < efx->type->max_rx_ip_filters;
++i)
channel->rps_flow_id[i] =
RPS_FLOW_ID_INVALID;
channel->rfs_expire_index = 0;
channel->rfs_filter_count = 0;
}

if (!success) {
efx_for_each_channel(channel, efx)
kfree(channel->rps_flow_id);
efx->type->filter_table_remove(efx);
rc = -ENOMEM;
goto out_unlock;
}
}
#endif
out_unlock:
up_write(&efx->filter_sem);
mutex_unlock(&efx->mac_lock);
return rc;
}

static void efx_remove_filters(struct efx_nic *efx)
{
#ifdef CONFIG_RFS_ACCEL
struct efx_channel *channel;

efx_for_each_channel(channel, efx) {
cancel_delayed_work_sync(&channel->filter_work);
kfree(channel->rps_flow_id);
}
#endif
down_write(&efx->filter_sem);
efx->type->filter_table_remove(efx);
up_write(&efx->filter_sem);
}


/**************************************************************************
*
* NIC startup/shutdown
@@ -1109,142 +1045,6 @@ void efx_update_sw_stats(struct efx_nic *efx, u64 *stats)
stats[GENERIC_STAT_rx_noskb_drops] = atomic_read(&efx->n_rx_noskb_drops);
}

bool efx_filter_spec_equal(const struct efx_filter_spec *left,
const struct efx_filter_spec *right)
{
if ((left->match_flags ^ right->match_flags) |
((left->flags ^ right->flags) &
(EFX_FILTER_FLAG_RX | EFX_FILTER_FLAG_TX)))
return false;

return memcmp(&left->outer_vid, &right->outer_vid,
sizeof(struct efx_filter_spec) -
offsetof(struct efx_filter_spec, outer_vid)) == 0;
}

u32 efx_filter_spec_hash(const struct efx_filter_spec *spec)
{
BUILD_BUG_ON(offsetof(struct efx_filter_spec, outer_vid) & 3);
return jhash2((const u32 *)&spec->outer_vid,
(sizeof(struct efx_filter_spec) -
offsetof(struct efx_filter_spec, outer_vid)) / 4,
0);
}

#ifdef CONFIG_RFS_ACCEL
bool efx_rps_check_rule(struct efx_arfs_rule *rule, unsigned int filter_idx,
bool *force)
{
if (rule->filter_id == EFX_ARFS_FILTER_ID_PENDING) {
/* ARFS is currently updating this entry, leave it */
return false;
}
if (rule->filter_id == EFX_ARFS_FILTER_ID_ERROR) {
/* ARFS tried and failed to update this, so it's probably out
* of date. Remove the filter and the ARFS rule entry.
*/
rule->filter_id = EFX_ARFS_FILTER_ID_REMOVING;
*force = true;
return true;
} else if (WARN_ON(rule->filter_id != filter_idx)) { /* can't happen */
/* ARFS has moved on, so old filter is not needed. Since we did
* not mark the rule with EFX_ARFS_FILTER_ID_REMOVING, it will
* not be removed by efx_rps_hash_del() subsequently.
*/
*force = true;
return true;
}
/* Remove it iff ARFS wants to. */
return true;
}

static
struct hlist_head *efx_rps_hash_bucket(struct efx_nic *efx,
const struct efx_filter_spec *spec)
{
u32 hash = efx_filter_spec_hash(spec);

lockdep_assert_held(&efx->rps_hash_lock);
if (!efx->rps_hash_table)
return NULL;
return &efx->rps_hash_table[hash % EFX_ARFS_HASH_TABLE_SIZE];
}

struct efx_arfs_rule *efx_rps_hash_find(struct efx_nic *efx,
const struct efx_filter_spec *spec)
{
struct efx_arfs_rule *rule;
struct hlist_head *head;
struct hlist_node *node;

head = efx_rps_hash_bucket(efx, spec);
if (!head)
return NULL;
hlist_for_each(node, head) {
rule = container_of(node, struct efx_arfs_rule, node);
if (efx_filter_spec_equal(spec, &rule->spec))
return rule;
}
return NULL;
}

struct efx_arfs_rule *efx_rps_hash_add(struct efx_nic *efx,
const struct efx_filter_spec *spec,
bool *new)
{
struct efx_arfs_rule *rule;
struct hlist_head *head;
struct hlist_node *node;

head = efx_rps_hash_bucket(efx, spec);
if (!head)
return NULL;
hlist_for_each(node, head) {
rule = container_of(node, struct efx_arfs_rule, node);
if (efx_filter_spec_equal(spec, &rule->spec)) {
*new = false;
return rule;
}
}
rule = kmalloc(sizeof(*rule), GFP_ATOMIC);
*new = true;
if (rule) {
memcpy(&rule->spec, spec, sizeof(rule->spec));
hlist_add_head(&rule->node, head);
}
return rule;
}

void efx_rps_hash_del(struct efx_nic *efx, const struct efx_filter_spec *spec)
{
struct efx_arfs_rule *rule;
struct hlist_head *head;
struct hlist_node *node;

head = efx_rps_hash_bucket(efx, spec);
if (WARN_ON(!head))
return;
hlist_for_each(node, head) {
rule = container_of(node, struct efx_arfs_rule, node);
if (efx_filter_spec_equal(spec, &rule->spec)) {
/* Someone already reused the entry. We know that if
* this check doesn't fire (i.e. filter_id == REMOVING)
* then the REMOVING mark was put there by our caller,
* because caller is holding a lock on filter table and
* only holders of that lock set REMOVING.
*/
if (rule->filter_id != EFX_ARFS_FILTER_ID_REMOVING)
return;
hlist_del(node);
kfree(rule);
return;
}
}
/* We didn't find it. */
WARN_ON(1);
}
#endif

/**************************************************************************
*
* PCI interface
24 changes: 1 addition & 23 deletions drivers/net/ethernet/sfc/efx.h
Original file line number Diff line number Diff line change
@@ -169,33 +169,11 @@ static inline void efx_filter_rfs_expire(struct work_struct *data)
static inline void efx_filter_rfs_expire(struct work_struct *data) {}
#define efx_filter_rfs_enabled() 0
#endif
bool efx_filter_is_mc_recipient(const struct efx_filter_spec *spec);

bool efx_filter_spec_equal(const struct efx_filter_spec *left,
const struct efx_filter_spec *right);
u32 efx_filter_spec_hash(const struct efx_filter_spec *spec);

#ifdef CONFIG_RFS_ACCEL
bool efx_rps_check_rule(struct efx_arfs_rule *rule, unsigned int filter_idx,
bool *force);

struct efx_arfs_rule *efx_rps_hash_find(struct efx_nic *efx,
const struct efx_filter_spec *spec);

/* @new is written to indicate if entry was newly added (true) or if an old
* entry was found and returned (false).
*/
struct efx_arfs_rule *efx_rps_hash_add(struct efx_nic *efx,
const struct efx_filter_spec *spec,
bool *new);

void efx_rps_hash_del(struct efx_nic *efx, const struct efx_filter_spec *spec);
#endif

/* RSS contexts */
static inline bool efx_rss_active(struct efx_rss_context *ctx)
{
return ctx->context_id != EFX_EF10_RSS_CONTEXT_INVALID;
return ctx->context_id != EFX_MCDI_RSS_CONTEXT_INVALID;
}

/* Ethtool support */
2 changes: 1 addition & 1 deletion drivers/net/ethernet/sfc/ethtool.c
Original file line number Diff line number Diff line change
@@ -1020,7 +1020,7 @@ static int efx_ethtool_set_rxfh_context(struct net_device *net_dev,
rc = -ENOMEM;
goto out_unlock;
}
ctx->context_id = EFX_EF10_RSS_CONTEXT_INVALID;
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));
6 changes: 3 additions & 3 deletions drivers/net/ethernet/sfc/net_driver.h
Original file line number Diff line number Diff line change
@@ -744,13 +744,13 @@ union efx_multicast_hash {
struct vfdi_status;

/* The reserved RSS context value */
#define EFX_EF10_RSS_CONTEXT_INVALID 0xffffffff
#define EFX_MCDI_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.
* %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_key: Toeplitz hash key for this RSS context
Loading

0 comments on commit f7226e0

Please sign in to comment.