Skip to content

Commit 42356d9

Browse files
ecree-solarflaredavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 84a1d9c commit 42356d9

File tree

9 files changed

+443
-150
lines changed

9 files changed

+443
-150
lines changed

drivers/net/ethernet/sfc/ef10.c

Lines changed: 181 additions & 92 deletions
Large diffs are not rendered by default.

drivers/net/ethernet/sfc/efx.c

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1353,12 +1353,13 @@ static void efx_fini_io(struct efx_nic *efx)
13531353
pci_disable_device(efx->pci_dev);
13541354
}
13551355

1356-
void efx_set_default_rx_indir_table(struct efx_nic *efx)
1356+
void efx_set_default_rx_indir_table(struct efx_nic *efx,
1357+
struct efx_rss_context *ctx)
13571358
{
13581359
size_t i;
13591360

1360-
for (i = 0; i < ARRAY_SIZE(efx->rx_indir_table); i++)
1361-
efx->rx_indir_table[i] =
1361+
for (i = 0; i < ARRAY_SIZE(ctx->rx_indir_table); i++)
1362+
ctx->rx_indir_table[i] =
13621363
ethtool_rxfh_indir_default(i, efx->rss_spread);
13631364
}
13641365

@@ -1739,9 +1740,9 @@ static int efx_probe_nic(struct efx_nic *efx)
17391740
} while (rc == -EAGAIN);
17401741

17411742
if (efx->n_channels > 1)
1742-
netdev_rss_key_fill(&efx->rx_hash_key,
1743-
sizeof(efx->rx_hash_key));
1744-
efx_set_default_rx_indir_table(efx);
1743+
netdev_rss_key_fill(efx->rss_context.rx_hash_key,
1744+
sizeof(efx->rss_context.rx_hash_key));
1745+
efx_set_default_rx_indir_table(efx, &efx->rss_context);
17451746

17461747
netif_set_real_num_tx_queues(efx->net_dev, efx->n_tx_channels);
17471748
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)
27002701
" VFs may not function\n", rc);
27012702
#endif
27022703

2704+
if (efx->type->rx_restore_rss_contexts)
2705+
efx->type->rx_restore_rss_contexts(efx);
27032706
down_read(&efx->filter_sem);
27042707
efx_restore_filters(efx);
27052708
up_read(&efx->filter_sem);
@@ -3003,6 +3006,7 @@ static int efx_init_struct(struct efx_nic *efx,
30033006
efx->type->rx_hash_offset - efx->type->rx_prefix_size;
30043007
efx->rx_packet_ts_offset =
30053008
efx->type->rx_ts_offset - efx->type->rx_prefix_size;
3009+
INIT_LIST_HEAD(&efx->rss_context.list);
30063010
spin_lock_init(&efx->stats_lock);
30073011
efx->vi_stride = EFX_DEFAULT_VI_STRIDE;
30083012
efx->num_mac_stats = MC_CMD_MAC_NSTATS;
@@ -3072,6 +3076,55 @@ void efx_update_sw_stats(struct efx_nic *efx, u64 *stats)
30723076
stats[GENERIC_STAT_rx_noskb_drops] = atomic_read(&efx->n_rx_noskb_drops);
30733077
}
30743078

3079+
/* RSS contexts. We're using linked lists and crappy O(n) algorithms, because
3080+
* (a) this is an infrequent control-plane operation and (b) n is small (max 64)
3081+
*/
3082+
struct efx_rss_context *efx_alloc_rss_context_entry(struct list_head *head)
3083+
{
3084+
struct efx_rss_context *ctx, *new;
3085+
u32 id = 1; /* Don't use zero, that refers to the master RSS context */
3086+
3087+
/* Search for first gap in the numbering */
3088+
list_for_each_entry(ctx, head, list) {
3089+
if (ctx->user_id != id)
3090+
break;
3091+
id++;
3092+
/* Check for wrap. If this happens, we have nearly 2^32
3093+
* allocated RSS contexts, which seems unlikely.
3094+
*/
3095+
if (WARN_ON_ONCE(!id))
3096+
return NULL;
3097+
}
3098+
3099+
/* Create the new entry */
3100+
new = kmalloc(sizeof(struct efx_rss_context), GFP_KERNEL);
3101+
if (!new)
3102+
return NULL;
3103+
new->context_id = EFX_EF10_RSS_CONTEXT_INVALID;
3104+
new->rx_hash_udp_4tuple = false;
3105+
3106+
/* Insert the new entry into the gap */
3107+
new->user_id = id;
3108+
list_add_tail(&new->list, &ctx->list);
3109+
return new;
3110+
}
3111+
3112+
struct efx_rss_context *efx_find_rss_context_entry(u32 id, struct list_head *head)
3113+
{
3114+
struct efx_rss_context *ctx;
3115+
3116+
list_for_each_entry(ctx, head, list)
3117+
if (ctx->user_id == id)
3118+
return ctx;
3119+
return NULL;
3120+
}
3121+
3122+
void efx_free_rss_context_entry(struct efx_rss_context *ctx)
3123+
{
3124+
list_del(&ctx->list);
3125+
kfree(ctx);
3126+
}
3127+
30753128
/**************************************************************************
30763129
*
30773130
* PCI interface

drivers/net/ethernet/sfc/efx.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ extern unsigned int efx_piobuf_size;
3434
extern bool efx_separate_tx_channels;
3535

3636
/* RX */
37-
void efx_set_default_rx_indir_table(struct efx_nic *efx);
37+
void efx_set_default_rx_indir_table(struct efx_nic *efx,
38+
struct efx_rss_context *ctx);
3839
void efx_rx_config_page_split(struct efx_nic *efx);
3940
int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
4041
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) {}
182183
#endif
183184
bool efx_filter_is_mc_recipient(const struct efx_filter_spec *spec);
184185

186+
/* RSS contexts */
187+
struct efx_rss_context *efx_alloc_rss_context_entry(struct list_head *list);
188+
struct efx_rss_context *efx_find_rss_context_entry(u32 id, struct list_head *list);
189+
void efx_free_rss_context_entry(struct efx_rss_context *ctx);
190+
static inline bool efx_rss_active(struct efx_rss_context *ctx)
191+
{
192+
return ctx->context_id != EFX_EF10_RSS_CONTEXT_INVALID;
193+
}
194+
185195
/* Channels */
186196
int efx_channel_dummy_op_int(struct efx_channel *channel);
187197
void efx_channel_dummy_op_void(struct efx_channel *channel);

drivers/net/ethernet/sfc/ethtool.c

Lines changed: 134 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -808,7 +808,8 @@ static inline void ip6_fill_mask(__be32 *mask)
808808
}
809809

810810
static int efx_ethtool_get_class_rule(struct efx_nic *efx,
811-
struct ethtool_rx_flow_spec *rule)
811+
struct ethtool_rx_flow_spec *rule,
812+
u32 *rss_context)
812813
{
813814
struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec;
814815
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,
964965
rule->m_ext.vlan_tci = htons(0xfff);
965966
}
966967

968+
if (spec.flags & EFX_FILTER_FLAG_RX_RSS) {
969+
rule->flow_type |= FLOW_RSS;
970+
*rss_context = spec.rss_context;
971+
}
972+
967973
return rc;
968974
}
969975

@@ -972,19 +978,29 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev,
972978
struct ethtool_rxnfc *info, u32 *rule_locs)
973979
{
974980
struct efx_nic *efx = netdev_priv(net_dev);
981+
u32 rss_context = 0;
982+
s32 rc;
975983

976984
switch (info->cmd) {
977985
case ETHTOOL_GRXRINGS:
978986
info->data = efx->n_rx_channels;
979987
return 0;
980988

981989
case ETHTOOL_GRXFH: {
990+
struct efx_rss_context *ctx = &efx->rss_context;
991+
992+
if (info->flow_type & FLOW_RSS && info->rss_context) {
993+
ctx = efx_find_rss_context_entry(info->rss_context,
994+
&efx->rss_context.list);
995+
if (!ctx)
996+
return -ENOENT;
997+
}
982998
info->data = 0;
983-
if (!efx->rss_active) /* No RSS */
999+
if (!efx_rss_active(ctx)) /* No RSS */
9841000
return 0;
985-
switch (info->flow_type) {
1001+
switch (info->flow_type & ~FLOW_RSS) {
9861002
case UDP_V4_FLOW:
987-
if (efx->rx_hash_udp_4tuple)
1003+
if (ctx->rx_hash_udp_4tuple)
9881004
/* fall through */
9891005
case TCP_V4_FLOW:
9901006
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,
9951011
info->data |= RXH_IP_SRC | RXH_IP_DST;
9961012
break;
9971013
case UDP_V6_FLOW:
998-
if (efx->rx_hash_udp_4tuple)
1014+
if (ctx->rx_hash_udp_4tuple)
9991015
/* fall through */
10001016
case TCP_V6_FLOW:
10011017
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,
10231039
case ETHTOOL_GRXCLSRULE:
10241040
if (efx_filter_get_rx_id_limit(efx) == 0)
10251041
return -EOPNOTSUPP;
1026-
return efx_ethtool_get_class_rule(efx, &info->fs);
1042+
rc = efx_ethtool_get_class_rule(efx, &info->fs, &rss_context);
1043+
if (rc < 0)
1044+
return rc;
1045+
if (info->fs.flow_type & FLOW_RSS)
1046+
info->rss_context = rss_context;
1047+
return 0;
10271048

1028-
case ETHTOOL_GRXCLSRLALL: {
1029-
s32 rc;
1049+
case ETHTOOL_GRXCLSRLALL:
10301050
info->data = efx_filter_get_rx_id_limit(efx);
10311051
if (info->data == 0)
10321052
return -EOPNOTSUPP;
@@ -1036,7 +1056,6 @@ efx_ethtool_get_rxnfc(struct net_device *net_dev,
10361056
return rc;
10371057
info->rule_cnt = rc;
10381058
return 0;
1039-
}
10401059

10411060
default:
10421061
return -EOPNOTSUPP;
@@ -1054,7 +1073,8 @@ static inline bool ip6_mask_is_empty(__be32 mask[4])
10541073
}
10551074

10561075
static int efx_ethtool_set_class_rule(struct efx_nic *efx,
1057-
struct ethtool_rx_flow_spec *rule)
1076+
struct ethtool_rx_flow_spec *rule,
1077+
u32 rss_context)
10581078
{
10591079
struct ethtool_tcpip4_spec *ip_entry = &rule->h_u.tcp_ip4_spec;
10601080
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,
10661086
struct ethtool_usrip6_spec *uip6_mask = &rule->m_u.usr_ip6_spec;
10671087
struct ethhdr *mac_entry = &rule->h_u.ether_spec;
10681088
struct ethhdr *mac_mask = &rule->m_u.ether_spec;
1089+
enum efx_filter_flags flags = 0;
10691090
struct efx_filter_spec spec;
10701091
int rc;
10711092

@@ -1084,12 +1105,19 @@ static int efx_ethtool_set_class_rule(struct efx_nic *efx,
10841105
rule->m_ext.data[1]))
10851106
return -EINVAL;
10861107

1087-
efx_filter_init_rx(&spec, EFX_FILTER_PRI_MANUAL,
1088-
efx->rx_scatter ? EFX_FILTER_FLAG_RX_SCATTER : 0,
1108+
if (efx->rx_scatter)
1109+
flags |= EFX_FILTER_FLAG_RX_SCATTER;
1110+
if (rule->flow_type & FLOW_RSS)
1111+
flags |= EFX_FILTER_FLAG_RX_RSS;
1112+
1113+
efx_filter_init_rx(&spec, EFX_FILTER_PRI_MANUAL, flags,
10891114
(rule->ring_cookie == RX_CLS_FLOW_DISC) ?
10901115
EFX_FILTER_RX_DMAQ_ID_DROP : rule->ring_cookie);
10911116

1092-
switch (rule->flow_type & ~FLOW_EXT) {
1117+
if (rule->flow_type & FLOW_RSS)
1118+
spec.rss_context = rss_context;
1119+
1120+
switch (rule->flow_type & ~(FLOW_EXT | FLOW_RSS)) {
10931121
case TCP_V4_FLOW:
10941122
case UDP_V4_FLOW:
10951123
spec.match_flags = (EFX_FILTER_MATCH_ETHER_TYPE |
@@ -1265,7 +1293,8 @@ static int efx_ethtool_set_rxnfc(struct net_device *net_dev,
12651293

12661294
switch (info->cmd) {
12671295
case ETHTOOL_SRXCLSRLINS:
1268-
return efx_ethtool_set_class_rule(efx, &info->fs);
1296+
return efx_ethtool_set_class_rule(efx, &info->fs,
1297+
info->rss_context);
12691298

12701299
case ETHTOOL_SRXCLSRLDEL:
12711300
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)
12801309
{
12811310
struct efx_nic *efx = netdev_priv(net_dev);
12821311

1283-
return (efx->n_rx_channels == 1) ? 0 : ARRAY_SIZE(efx->rx_indir_table);
1312+
if (efx->n_rx_channels == 1)
1313+
return 0;
1314+
return ARRAY_SIZE(efx->rss_context.rx_indir_table);
12841315
}
12851316

12861317
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,
13031334
if (hfunc)
13041335
*hfunc = ETH_RSS_HASH_TOP;
13051336
if (indir)
1306-
memcpy(indir, efx->rx_indir_table, sizeof(efx->rx_indir_table));
1337+
memcpy(indir, efx->rss_context.rx_indir_table,
1338+
sizeof(efx->rss_context.rx_indir_table));
13071339
if (key)
1308-
memcpy(key, efx->rx_hash_key, efx->type->rx_hash_key_size);
1340+
memcpy(key, efx->rss_context.rx_hash_key,
1341+
efx->type->rx_hash_key_size);
13091342
return 0;
13101343
}
13111344

@@ -1321,13 +1354,93 @@ static int efx_ethtool_set_rxfh(struct net_device *net_dev, const u32 *indir,
13211354
return 0;
13221355

13231356
if (!key)
1324-
key = efx->rx_hash_key;
1357+
key = efx->rss_context.rx_hash_key;
13251358
if (!indir)
1326-
indir = efx->rx_indir_table;
1359+
indir = efx->rss_context.rx_indir_table;
13271360

13281361
return efx->type->rx_push_rss_config(efx, true, indir, key);
13291362
}
13301363

1364+
static int efx_ethtool_get_rxfh_context(struct net_device *net_dev, u32 *indir,
1365+
u8 *key, u8 *hfunc, u32 rss_context)
1366+
{
1367+
struct efx_nic *efx = netdev_priv(net_dev);
1368+
struct efx_rss_context *ctx;
1369+
int rc;
1370+
1371+
if (!efx->type->rx_pull_rss_context_config)
1372+
return -EOPNOTSUPP;
1373+
ctx = efx_find_rss_context_entry(rss_context, &efx->rss_context.list);
1374+
if (!ctx)
1375+
return -ENOENT;
1376+
rc = efx->type->rx_pull_rss_context_config(efx, ctx);
1377+
if (rc)
1378+
return rc;
1379+
1380+
if (hfunc)
1381+
*hfunc = ETH_RSS_HASH_TOP;
1382+
if (indir)
1383+
memcpy(indir, ctx->rx_indir_table, sizeof(ctx->rx_indir_table));
1384+
if (key)
1385+
memcpy(key, ctx->rx_hash_key, efx->type->rx_hash_key_size);
1386+
return 0;
1387+
}
1388+
1389+
static int efx_ethtool_set_rxfh_context(struct net_device *net_dev,
1390+
const u32 *indir, const u8 *key,
1391+
const u8 hfunc, u32 *rss_context,
1392+
bool delete)
1393+
{
1394+
struct efx_nic *efx = netdev_priv(net_dev);
1395+
struct efx_rss_context *ctx;
1396+
bool allocated = false;
1397+
int rc;
1398+
1399+
if (!efx->type->rx_push_rss_context_config)
1400+
return -EOPNOTSUPP;
1401+
/* Hash function is Toeplitz, cannot be changed */
1402+
if (hfunc != ETH_RSS_HASH_NO_CHANGE && hfunc != ETH_RSS_HASH_TOP)
1403+
return -EOPNOTSUPP;
1404+
if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) {
1405+
if (delete)
1406+
/* alloc + delete == Nothing to do */
1407+
return -EINVAL;
1408+
ctx = efx_alloc_rss_context_entry(&efx->rss_context.list);
1409+
if (!ctx)
1410+
return -ENOMEM;
1411+
ctx->context_id = EFX_EF10_RSS_CONTEXT_INVALID;
1412+
/* Initialise indir table and key to defaults */
1413+
efx_set_default_rx_indir_table(efx, ctx);
1414+
netdev_rss_key_fill(ctx->rx_hash_key, sizeof(ctx->rx_hash_key));
1415+
allocated = true;
1416+
} else {
1417+
ctx = efx_find_rss_context_entry(*rss_context,
1418+
&efx->rss_context.list);
1419+
if (!ctx)
1420+
return -ENOENT;
1421+
}
1422+
1423+
if (delete) {
1424+
/* delete this context */
1425+
rc = efx->type->rx_push_rss_context_config(efx, ctx, NULL, NULL);
1426+
if (!rc)
1427+
efx_free_rss_context_entry(ctx);
1428+
return rc;
1429+
}
1430+
1431+
if (!key)
1432+
key = ctx->rx_hash_key;
1433+
if (!indir)
1434+
indir = ctx->rx_indir_table;
1435+
1436+
rc = efx->type->rx_push_rss_context_config(efx, ctx, indir, key);
1437+
if (rc && allocated)
1438+
efx_free_rss_context_entry(ctx);
1439+
else
1440+
*rss_context = ctx->user_id;
1441+
return rc;
1442+
}
1443+
13311444
static int efx_ethtool_get_ts_info(struct net_device *net_dev,
13321445
struct ethtool_ts_info *ts_info)
13331446
{
@@ -1403,6 +1516,8 @@ const struct ethtool_ops efx_ethtool_ops = {
14031516
.get_rxfh_key_size = efx_ethtool_get_rxfh_key_size,
14041517
.get_rxfh = efx_ethtool_get_rxfh,
14051518
.set_rxfh = efx_ethtool_set_rxfh,
1519+
.get_rxfh_context = efx_ethtool_get_rxfh_context,
1520+
.set_rxfh_context = efx_ethtool_set_rxfh_context,
14061521
.get_ts_info = efx_ethtool_get_ts_info,
14071522
.get_module_info = efx_ethtool_get_module_info,
14081523
.get_module_eeprom = efx_ethtool_get_module_eeprom,

0 commit comments

Comments
 (0)