Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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: Edward Cree <ecree.xilinx@gmail.com>
Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com>
Link: https://patch.msgid.link/150274740ea8cc137fef5502541ce573d32fb319.1719502240.git.ecree.xilinx@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Edward Cree and committed by
Jakub Kicinski
a9ee8d4a 87925151

+212 -219
+1 -1
drivers/net/ethernet/sfc/ef10.c
··· 1396 1396 efx_mcdi_filter_table_reset_mc_allocations(efx); 1397 1397 nic_data->must_restore_piobufs = true; 1398 1398 efx_ef10_forget_old_piobufs(efx); 1399 - efx->rss_context.context_id = EFX_MCDI_RSS_CONTEXT_INVALID; 1399 + efx->rss_context.priv.context_id = EFX_MCDI_RSS_CONTEXT_INVALID; 1400 1400 1401 1401 /* Driver-created vswitches and vports must be re-created */ 1402 1402 nic_data->must_probe_vswitching = true;
+4
drivers/net/ethernet/sfc/ef100_ethtool.c
··· 59 59 60 60 .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, 61 61 .get_rxfh_key_size = efx_ethtool_get_rxfh_key_size, 62 + .rxfh_priv_size = sizeof(struct efx_rss_context_priv), 62 63 .get_rxfh = efx_ethtool_get_rxfh, 63 64 .set_rxfh = efx_ethtool_set_rxfh, 65 + .create_rxfh_context = efx_ethtool_create_rxfh_context, 66 + .modify_rxfh_context = efx_ethtool_modify_rxfh_context, 67 + .remove_rxfh_context = efx_ethtool_remove_rxfh_context, 64 68 65 69 .get_module_info = efx_ethtool_get_module_info, 66 70 .get_module_eeprom = efx_ethtool_get_module_eeprom,
+1 -1
drivers/net/ethernet/sfc/efx.c
··· 299 299 if (efx->n_channels > 1) 300 300 netdev_rss_key_fill(efx->rss_context.rx_hash_key, 301 301 sizeof(efx->rss_context.rx_hash_key)); 302 - efx_set_default_rx_indir_table(efx, &efx->rss_context); 302 + efx_set_default_rx_indir_table(efx, efx->rss_context.rx_indir_table); 303 303 304 304 /* Initialise the interrupt moderation settings */ 305 305 efx->irq_mod_step_us = DIV_ROUND_UP(efx->timer_quantum_ns, 1000);
+1 -1
drivers/net/ethernet/sfc/efx.h
··· 158 158 } 159 159 160 160 /* RSS contexts */ 161 - static inline bool efx_rss_active(struct efx_rss_context *ctx) 161 + static inline bool efx_rss_active(struct efx_rss_context_priv *ctx) 162 162 { 163 163 return ctx->context_id != EFX_MCDI_RSS_CONTEXT_INVALID; 164 164 }
+4 -6
drivers/net/ethernet/sfc/efx_common.c
··· 714 714 715 715 mutex_lock(&efx->mac_lock); 716 716 down_write(&efx->filter_sem); 717 - mutex_lock(&efx->rss_lock); 717 + mutex_lock(&efx->net_dev->ethtool->rss_lock); 718 718 efx->type->fini(efx); 719 719 } 720 720 ··· 777 777 778 778 if (efx->type->rx_restore_rss_contexts) 779 779 efx->type->rx_restore_rss_contexts(efx); 780 - mutex_unlock(&efx->rss_lock); 780 + mutex_unlock(&efx->net_dev->ethtool->rss_lock); 781 781 efx->type->filter_table_restore(efx); 782 782 up_write(&efx->filter_sem); 783 783 ··· 793 793 fail: 794 794 efx->port_initialized = false; 795 795 796 - mutex_unlock(&efx->rss_lock); 796 + mutex_unlock(&efx->net_dev->ethtool->rss_lock); 797 797 up_write(&efx->filter_sem); 798 798 mutex_unlock(&efx->mac_lock); 799 799 ··· 1000 1000 efx->type->rx_hash_offset - efx->type->rx_prefix_size; 1001 1001 efx->rx_packet_ts_offset = 1002 1002 efx->type->rx_ts_offset - efx->type->rx_prefix_size; 1003 - INIT_LIST_HEAD(&efx->rss_context.list); 1004 - efx->rss_context.context_id = EFX_MCDI_RSS_CONTEXT_INVALID; 1005 - mutex_init(&efx->rss_lock); 1003 + efx->rss_context.priv.context_id = EFX_MCDI_RSS_CONTEXT_INVALID; 1006 1004 efx->vport_id = EVB_PORT_ID_ASSIGNED; 1007 1005 spin_lock_init(&efx->stats_lock); 1008 1006 efx->vi_stride = EFX_DEFAULT_VI_STRIDE;
+4
drivers/net/ethernet/sfc/ethtool.c
··· 268 268 .set_rxnfc = efx_ethtool_set_rxnfc, 269 269 .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, 270 270 .get_rxfh_key_size = efx_ethtool_get_rxfh_key_size, 271 + .rxfh_priv_size = sizeof(struct efx_rss_context_priv), 271 272 .get_rxfh = efx_ethtool_get_rxfh, 272 273 .set_rxfh = efx_ethtool_set_rxfh, 274 + .create_rxfh_context = efx_ethtool_create_rxfh_context, 275 + .modify_rxfh_context = efx_ethtool_modify_rxfh_context, 276 + .remove_rxfh_context = efx_ethtool_remove_rxfh_context, 273 277 .get_ts_info = efx_ethtool_get_ts_info, 274 278 .get_module_info = efx_ethtool_get_module_info, 275 279 .get_module_eeprom = efx_ethtool_get_module_eeprom,
+86 -66
drivers/net/ethernet/sfc/ethtool_common.c
··· 820 820 return 0; 821 821 822 822 case ETHTOOL_GRXFH: { 823 - struct efx_rss_context *ctx = &efx->rss_context; 823 + struct efx_rss_context_priv *ctx = &efx->rss_context.priv; 824 824 __u64 data; 825 825 826 - mutex_lock(&efx->rss_lock); 826 + mutex_lock(&net_dev->ethtool->rss_lock); 827 827 if (info->flow_type & FLOW_RSS && info->rss_context) { 828 828 ctx = efx_find_rss_context_entry(efx, info->rss_context); 829 829 if (!ctx) { ··· 864 864 out_setdata_unlock: 865 865 info->data = data; 866 866 out_unlock: 867 - mutex_unlock(&efx->rss_lock); 867 + mutex_unlock(&net_dev->ethtool->rss_lock); 868 868 return rc; 869 869 } 870 870 ··· 1167 1167 struct ethtool_rxfh_param *rxfh) 1168 1168 { 1169 1169 struct efx_nic *efx = efx_netdev_priv(net_dev); 1170 - struct efx_rss_context *ctx; 1170 + struct efx_rss_context_priv *ctx_priv; 1171 + struct efx_rss_context ctx; 1171 1172 int rc = 0; 1172 1173 1173 1174 if (!efx->type->rx_pull_rss_context_config) 1174 1175 return -EOPNOTSUPP; 1175 1176 1176 - mutex_lock(&efx->rss_lock); 1177 - ctx = efx_find_rss_context_entry(efx, rxfh->rss_context); 1178 - if (!ctx) { 1177 + mutex_lock(&net_dev->ethtool->rss_lock); 1178 + ctx_priv = efx_find_rss_context_entry(efx, rxfh->rss_context); 1179 + if (!ctx_priv) { 1179 1180 rc = -ENOENT; 1180 1181 goto out_unlock; 1181 1182 } 1182 - rc = efx->type->rx_pull_rss_context_config(efx, ctx); 1183 + ctx.priv = *ctx_priv; 1184 + rc = efx->type->rx_pull_rss_context_config(efx, &ctx); 1183 1185 if (rc) 1184 1186 goto out_unlock; 1185 1187 1186 1188 rxfh->hfunc = ETH_RSS_HASH_TOP; 1187 1189 if (rxfh->indir) 1188 - memcpy(rxfh->indir, ctx->rx_indir_table, 1189 - sizeof(ctx->rx_indir_table)); 1190 + memcpy(rxfh->indir, ctx.rx_indir_table, 1191 + sizeof(ctx.rx_indir_table)); 1190 1192 if (rxfh->key) 1191 - memcpy(rxfh->key, ctx->rx_hash_key, 1193 + memcpy(rxfh->key, ctx.rx_hash_key, 1192 1194 efx->type->rx_hash_key_size); 1193 1195 out_unlock: 1194 - mutex_unlock(&efx->rss_lock); 1196 + mutex_unlock(&net_dev->ethtool->rss_lock); 1195 1197 return rc; 1196 1198 } 1197 1199 ··· 1220 1218 return 0; 1221 1219 } 1222 1220 1223 - static int efx_ethtool_set_rxfh_context(struct net_device *net_dev, 1224 - struct ethtool_rxfh_param *rxfh, 1225 - struct netlink_ext_ack *extack) 1221 + int efx_ethtool_modify_rxfh_context(struct net_device *net_dev, 1222 + struct ethtool_rxfh_context *ctx, 1223 + const struct ethtool_rxfh_param *rxfh, 1224 + struct netlink_ext_ack *extack) 1226 1225 { 1227 1226 struct efx_nic *efx = efx_netdev_priv(net_dev); 1228 - u32 *rss_context = &rxfh->rss_context; 1229 - struct efx_rss_context *ctx; 1230 - u32 *indir = rxfh->indir; 1231 - bool allocated = false; 1232 - u8 *key = rxfh->key; 1233 - int rc; 1227 + struct efx_rss_context_priv *priv; 1228 + const u32 *indir = rxfh->indir; 1229 + const u8 *key = rxfh->key; 1234 1230 1235 - if (!efx->type->rx_push_rss_context_config) 1231 + if (!efx->type->rx_push_rss_context_config) { 1232 + NL_SET_ERR_MSG_MOD(extack, 1233 + "NIC type does not support custom contexts"); 1236 1234 return -EOPNOTSUPP; 1237 - 1238 - mutex_lock(&efx->rss_lock); 1239 - 1240 - if (*rss_context == ETH_RXFH_CONTEXT_ALLOC) { 1241 - if (rxfh->rss_delete) { 1242 - /* alloc + delete == Nothing to do */ 1243 - rc = -EINVAL; 1244 - goto out_unlock; 1245 - } 1246 - ctx = efx_alloc_rss_context_entry(efx); 1247 - if (!ctx) { 1248 - rc = -ENOMEM; 1249 - goto out_unlock; 1250 - } 1251 - ctx->context_id = EFX_MCDI_RSS_CONTEXT_INVALID; 1252 - /* Initialise indir table and key to defaults */ 1253 - efx_set_default_rx_indir_table(efx, ctx); 1254 - netdev_rss_key_fill(ctx->rx_hash_key, sizeof(ctx->rx_hash_key)); 1255 - allocated = true; 1256 - } else { 1257 - ctx = efx_find_rss_context_entry(efx, *rss_context); 1258 - if (!ctx) { 1259 - rc = -ENOENT; 1260 - goto out_unlock; 1261 - } 1235 + } 1236 + /* Hash function is Toeplitz, cannot be changed */ 1237 + if (rxfh->hfunc != ETH_RSS_HASH_NO_CHANGE && 1238 + rxfh->hfunc != ETH_RSS_HASH_TOP) { 1239 + NL_SET_ERR_MSG_MOD(extack, "Only Toeplitz hash is supported"); 1240 + return -EOPNOTSUPP; 1262 1241 } 1263 1242 1264 - if (rxfh->rss_delete) { 1265 - /* delete this context */ 1266 - rc = efx->type->rx_push_rss_context_config(efx, ctx, NULL, NULL); 1267 - if (!rc) 1268 - efx_free_rss_context_entry(ctx); 1269 - goto out_unlock; 1270 - } 1243 + priv = ethtool_rxfh_context_priv(ctx); 1271 1244 1272 1245 if (!key) 1273 - key = ctx->rx_hash_key; 1246 + key = ethtool_rxfh_context_key(ctx); 1274 1247 if (!indir) 1275 - indir = ctx->rx_indir_table; 1248 + indir = ethtool_rxfh_context_indir(ctx); 1276 1249 1277 - rc = efx->type->rx_push_rss_context_config(efx, ctx, indir, key); 1278 - if (rc && allocated) 1279 - efx_free_rss_context_entry(ctx); 1280 - else 1281 - *rss_context = ctx->user_id; 1282 - out_unlock: 1283 - mutex_unlock(&efx->rss_lock); 1284 - return rc; 1250 + return efx->type->rx_push_rss_context_config(efx, priv, indir, key, 1251 + false); 1252 + } 1253 + 1254 + int efx_ethtool_create_rxfh_context(struct net_device *net_dev, 1255 + struct ethtool_rxfh_context *ctx, 1256 + const struct ethtool_rxfh_param *rxfh, 1257 + struct netlink_ext_ack *extack) 1258 + { 1259 + struct efx_nic *efx = efx_netdev_priv(net_dev); 1260 + struct efx_rss_context_priv *priv; 1261 + 1262 + priv = ethtool_rxfh_context_priv(ctx); 1263 + 1264 + priv->context_id = EFX_MCDI_RSS_CONTEXT_INVALID; 1265 + priv->rx_hash_udp_4tuple = false; 1266 + /* Generate default indir table and/or key if not specified. 1267 + * We use ctx as a place to store these; this is fine because 1268 + * we're doing a create, so if we fail then the ctx will just 1269 + * be deleted. 1270 + */ 1271 + if (!rxfh->indir) 1272 + efx_set_default_rx_indir_table(efx, ethtool_rxfh_context_indir(ctx)); 1273 + if (!rxfh->key) 1274 + netdev_rss_key_fill(ethtool_rxfh_context_key(ctx), 1275 + ctx->key_size); 1276 + if (rxfh->hfunc == ETH_RSS_HASH_NO_CHANGE) 1277 + ctx->hfunc = ETH_RSS_HASH_TOP; 1278 + if (rxfh->input_xfrm == RXH_XFRM_NO_CHANGE) 1279 + ctx->input_xfrm = 0; 1280 + return efx_ethtool_modify_rxfh_context(net_dev, ctx, rxfh, extack); 1281 + } 1282 + 1283 + int efx_ethtool_remove_rxfh_context(struct net_device *net_dev, 1284 + struct ethtool_rxfh_context *ctx, 1285 + u32 rss_context, 1286 + struct netlink_ext_ack *extack) 1287 + { 1288 + struct efx_nic *efx = efx_netdev_priv(net_dev); 1289 + struct efx_rss_context_priv *priv; 1290 + 1291 + if (!efx->type->rx_push_rss_context_config) { 1292 + NL_SET_ERR_MSG_MOD(extack, 1293 + "NIC type does not support custom contexts"); 1294 + return -EOPNOTSUPP; 1295 + } 1296 + 1297 + priv = ethtool_rxfh_context_priv(ctx); 1298 + return efx->type->rx_push_rss_context_config(efx, priv, NULL, NULL, 1299 + true); 1285 1300 } 1286 1301 1287 1302 int efx_ethtool_set_rxfh(struct net_device *net_dev, ··· 1314 1295 rxfh->hfunc != ETH_RSS_HASH_TOP) 1315 1296 return -EOPNOTSUPP; 1316 1297 1317 - if (rxfh->rss_context) 1318 - return efx_ethtool_set_rxfh_context(net_dev, rxfh, extack); 1298 + /* Custom contexts should use new API */ 1299 + if (WARN_ON_ONCE(rxfh->rss_context)) 1300 + return -EIO; 1319 1301 1320 1302 if (!indir && !key) 1321 1303 return 0;
+12
drivers/net/ethernet/sfc/ethtool_common.h
··· 49 49 int efx_ethtool_set_rxfh(struct net_device *net_dev, 50 50 struct ethtool_rxfh_param *rxfh, 51 51 struct netlink_ext_ack *extack); 52 + int efx_ethtool_create_rxfh_context(struct net_device *net_dev, 53 + struct ethtool_rxfh_context *ctx, 54 + const struct ethtool_rxfh_param *rxfh, 55 + struct netlink_ext_ack *extack); 56 + int efx_ethtool_modify_rxfh_context(struct net_device *net_dev, 57 + struct ethtool_rxfh_context *ctx, 58 + const struct ethtool_rxfh_param *rxfh, 59 + struct netlink_ext_ack *extack); 60 + int efx_ethtool_remove_rxfh_context(struct net_device *net_dev, 61 + struct ethtool_rxfh_context *ctx, 62 + u32 rss_context, 63 + struct netlink_ext_ack *extack); 52 64 int efx_ethtool_reset(struct net_device *net_dev, u32 *flags); 53 65 int efx_ethtool_get_module_eeprom(struct net_device *net_dev, 54 66 struct ethtool_eeprom *ee,
+70 -65
drivers/net/ethernet/sfc/mcdi_filters.c
··· 194 194 static void efx_mcdi_filter_push_prep(struct efx_nic *efx, 195 195 const struct efx_filter_spec *spec, 196 196 efx_dword_t *inbuf, u64 handle, 197 - struct efx_rss_context *ctx, 197 + struct efx_rss_context_priv *ctx, 198 198 bool replacing) 199 199 { 200 200 u32 flags = spec->flags; ··· 245 245 246 246 static int efx_mcdi_filter_push(struct efx_nic *efx, 247 247 const struct efx_filter_spec *spec, u64 *handle, 248 - struct efx_rss_context *ctx, bool replacing) 248 + struct efx_rss_context_priv *ctx, bool replacing) 249 249 { 250 250 MCDI_DECLARE_BUF(inbuf, MC_CMD_FILTER_OP_EXT_IN_LEN); 251 251 MCDI_DECLARE_BUF(outbuf, MC_CMD_FILTER_OP_EXT_OUT_LEN); ··· 345 345 bool replace_equal) 346 346 { 347 347 DECLARE_BITMAP(mc_rem_map, EFX_EF10_FILTER_SEARCH_LIMIT); 348 + struct efx_rss_context_priv *ctx = NULL; 348 349 struct efx_mcdi_filter_table *table; 349 350 struct efx_filter_spec *saved_spec; 350 - struct efx_rss_context *ctx = NULL; 351 351 unsigned int match_pri, hash; 352 352 unsigned int priv_flags; 353 353 bool rss_locked = false; ··· 380 380 bitmap_zero(mc_rem_map, EFX_EF10_FILTER_SEARCH_LIMIT); 381 381 382 382 if (spec->flags & EFX_FILTER_FLAG_RX_RSS) { 383 - mutex_lock(&efx->rss_lock); 383 + mutex_lock(&efx->net_dev->ethtool->rss_lock); 384 384 rss_locked = true; 385 385 if (spec->rss_context) 386 386 ctx = efx_find_rss_context_entry(efx, spec->rss_context); 387 387 else 388 - ctx = &efx->rss_context; 388 + ctx = &efx->rss_context.priv; 389 389 if (!ctx) { 390 390 rc = -ENOENT; 391 391 goto out_unlock; ··· 548 548 549 549 out_unlock: 550 550 if (rss_locked) 551 - mutex_unlock(&efx->rss_lock); 551 + mutex_unlock(&efx->net_dev->ethtool->rss_lock); 552 552 up_write(&table->lock); 553 553 return rc; 554 554 } ··· 611 611 612 612 new_spec.priority = EFX_FILTER_PRI_AUTO; 613 613 new_spec.flags = (EFX_FILTER_FLAG_RX | 614 - (efx_rss_active(&efx->rss_context) ? 614 + (efx_rss_active(&efx->rss_context.priv) ? 615 615 EFX_FILTER_FLAG_RX_RSS : 0)); 616 616 new_spec.dmaq_id = 0; 617 617 new_spec.rss_context = 0; 618 618 rc = efx_mcdi_filter_push(efx, &new_spec, 619 619 &table->entry[filter_idx].handle, 620 - &efx->rss_context, 620 + &efx->rss_context.priv, 621 621 true); 622 622 623 623 if (rc == 0) ··· 764 764 ids = vlan->uc; 765 765 } 766 766 767 - filter_flags = efx_rss_active(&efx->rss_context) ? EFX_FILTER_FLAG_RX_RSS : 0; 767 + filter_flags = efx_rss_active(&efx->rss_context.priv) ? EFX_FILTER_FLAG_RX_RSS : 0; 768 768 769 769 /* Insert/renew filters */ 770 770 for (i = 0; i < addr_count; i++) { ··· 833 833 int rc; 834 834 u16 *id; 835 835 836 - filter_flags = efx_rss_active(&efx->rss_context) ? EFX_FILTER_FLAG_RX_RSS : 0; 836 + filter_flags = efx_rss_active(&efx->rss_context.priv) ? EFX_FILTER_FLAG_RX_RSS : 0; 837 837 838 838 efx_filter_init_rx(&spec, EFX_FILTER_PRI_AUTO, filter_flags, 0); 839 839 ··· 1375 1375 struct efx_mcdi_filter_table *table = efx->filter_state; 1376 1376 unsigned int invalid_filters = 0, failed = 0; 1377 1377 struct efx_mcdi_filter_vlan *vlan; 1378 + struct efx_rss_context_priv *ctx; 1378 1379 struct efx_filter_spec *spec; 1379 - struct efx_rss_context *ctx; 1380 1380 unsigned int filter_idx; 1381 1381 u32 mcdi_flags; 1382 1382 int match_pri; ··· 1388 1388 return; 1389 1389 1390 1390 down_write(&table->lock); 1391 - mutex_lock(&efx->rss_lock); 1391 + mutex_lock(&efx->net_dev->ethtool->rss_lock); 1392 1392 1393 1393 for (filter_idx = 0; filter_idx < EFX_MCDI_FILTER_TBL_ROWS; filter_idx++) { 1394 1394 spec = efx_mcdi_filter_entry_spec(table, filter_idx); ··· 1407 1407 if (spec->rss_context) 1408 1408 ctx = efx_find_rss_context_entry(efx, spec->rss_context); 1409 1409 else 1410 - ctx = &efx->rss_context; 1410 + ctx = &efx->rss_context.priv; 1411 1411 if (spec->flags & EFX_FILTER_FLAG_RX_RSS) { 1412 1412 if (!ctx) { 1413 1413 netif_warn(efx, drv, efx->net_dev, ··· 1444 1444 } 1445 1445 } 1446 1446 1447 - mutex_unlock(&efx->rss_lock); 1447 + mutex_unlock(&efx->net_dev->ethtool->rss_lock); 1448 1448 up_write(&table->lock); 1449 1449 1450 1450 /* ··· 1861 1861 RSS_MODE_HASH_ADDRS << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_UDP_IPV6_RSS_MODE_LBN |\ 1862 1862 RSS_MODE_HASH_ADDRS << MC_CMD_RSS_CONTEXT_GET_FLAGS_OUT_OTHER_IPV6_RSS_MODE_LBN) 1863 1863 1864 - int efx_mcdi_get_rss_context_flags(struct efx_nic *efx, u32 context, u32 *flags) 1864 + static int efx_mcdi_get_rss_context_flags(struct efx_nic *efx, u32 context, 1865 + u32 *flags) 1865 1866 { 1866 1867 /* 1867 1868 * Firmware had a bug (sfc bug 61952) where it would not actually ··· 1910 1909 * Defaults are 4-tuple for TCP and 2-tuple for UDP and other-IP, so we 1911 1910 * just need to set the UDP ports flags (for both IP versions). 1912 1911 */ 1913 - void efx_mcdi_set_rss_context_flags(struct efx_nic *efx, 1914 - struct efx_rss_context *ctx) 1912 + static void efx_mcdi_set_rss_context_flags(struct efx_nic *efx, 1913 + struct efx_rss_context_priv *ctx) 1915 1914 { 1916 1915 MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_SET_FLAGS_IN_LEN); 1917 1916 u32 flags; ··· 1932 1931 } 1933 1932 1934 1933 static int efx_mcdi_filter_alloc_rss_context(struct efx_nic *efx, bool exclusive, 1935 - struct efx_rss_context *ctx, 1934 + struct efx_rss_context_priv *ctx, 1936 1935 unsigned *context_size) 1937 1936 { 1938 1937 MCDI_DECLARE_BUF(inbuf, MC_CMD_RSS_CONTEXT_ALLOC_IN_LEN); ··· 2033 2032 { 2034 2033 int rc; 2035 2034 2036 - if (efx->rss_context.context_id != EFX_MCDI_RSS_CONTEXT_INVALID) { 2037 - rc = efx_mcdi_filter_free_rss_context(efx, efx->rss_context.context_id); 2035 + if (efx->rss_context.priv.context_id != EFX_MCDI_RSS_CONTEXT_INVALID) { 2036 + rc = efx_mcdi_filter_free_rss_context(efx, efx->rss_context.priv.context_id); 2038 2037 WARN_ON(rc != 0); 2039 2038 } 2040 - efx->rss_context.context_id = EFX_MCDI_RSS_CONTEXT_INVALID; 2039 + efx->rss_context.priv.context_id = EFX_MCDI_RSS_CONTEXT_INVALID; 2041 2040 } 2042 2041 2043 2042 static int efx_mcdi_filter_rx_push_shared_rss_config(struct efx_nic *efx, 2044 2043 unsigned *context_size) 2045 2044 { 2046 2045 struct efx_mcdi_filter_table *table = efx->filter_state; 2047 - int rc = efx_mcdi_filter_alloc_rss_context(efx, false, &efx->rss_context, 2048 - context_size); 2046 + int rc = efx_mcdi_filter_alloc_rss_context(efx, false, 2047 + &efx->rss_context.priv, 2048 + context_size); 2049 2049 2050 2050 if (rc != 0) 2051 2051 return rc; 2052 2052 2053 2053 table->rx_rss_context_exclusive = false; 2054 - efx_set_default_rx_indir_table(efx, &efx->rss_context); 2054 + efx_set_default_rx_indir_table(efx, efx->rss_context.rx_indir_table); 2055 2055 return 0; 2056 2056 } 2057 2057 ··· 2060 2058 const u32 *rx_indir_table, 2061 2059 const u8 *key) 2062 2060 { 2061 + u32 old_rx_rss_context = efx->rss_context.priv.context_id; 2063 2062 struct efx_mcdi_filter_table *table = efx->filter_state; 2064 - u32 old_rx_rss_context = efx->rss_context.context_id; 2065 2063 int rc; 2066 2064 2067 - if (efx->rss_context.context_id == EFX_MCDI_RSS_CONTEXT_INVALID || 2065 + if (efx->rss_context.priv.context_id == EFX_MCDI_RSS_CONTEXT_INVALID || 2068 2066 !table->rx_rss_context_exclusive) { 2069 - rc = efx_mcdi_filter_alloc_rss_context(efx, true, &efx->rss_context, 2070 - NULL); 2067 + rc = efx_mcdi_filter_alloc_rss_context(efx, true, 2068 + &efx->rss_context.priv, 2069 + NULL); 2071 2070 if (rc == -EOPNOTSUPP) 2072 2071 return rc; 2073 2072 else if (rc != 0) 2074 2073 goto fail1; 2075 2074 } 2076 2075 2077 - rc = efx_mcdi_filter_populate_rss_table(efx, efx->rss_context.context_id, 2078 - rx_indir_table, key); 2076 + rc = efx_mcdi_filter_populate_rss_table(efx, efx->rss_context.priv.context_id, 2077 + rx_indir_table, key); 2079 2078 if (rc != 0) 2080 2079 goto fail2; 2081 2080 2082 - if (efx->rss_context.context_id != old_rx_rss_context && 2081 + if (efx->rss_context.priv.context_id != old_rx_rss_context && 2083 2082 old_rx_rss_context != EFX_MCDI_RSS_CONTEXT_INVALID) 2084 2083 WARN_ON(efx_mcdi_filter_free_rss_context(efx, old_rx_rss_context) != 0); 2085 2084 table->rx_rss_context_exclusive = true; ··· 2094 2091 return 0; 2095 2092 2096 2093 fail2: 2097 - if (old_rx_rss_context != efx->rss_context.context_id) { 2098 - WARN_ON(efx_mcdi_filter_free_rss_context(efx, efx->rss_context.context_id) != 0); 2099 - efx->rss_context.context_id = old_rx_rss_context; 2094 + if (old_rx_rss_context != efx->rss_context.priv.context_id) { 2095 + WARN_ON(efx_mcdi_filter_free_rss_context(efx, efx->rss_context.priv.context_id) != 0); 2096 + efx->rss_context.priv.context_id = old_rx_rss_context; 2100 2097 } 2101 2098 fail1: 2102 2099 netif_err(efx, hw, efx->net_dev, "%s: failed rc=%d\n", __func__, rc); ··· 2104 2101 } 2105 2102 2106 2103 int efx_mcdi_rx_push_rss_context_config(struct efx_nic *efx, 2107 - struct efx_rss_context *ctx, 2104 + struct efx_rss_context_priv *ctx, 2108 2105 const u32 *rx_indir_table, 2109 - const u8 *key) 2106 + const u8 *key, bool delete) 2110 2107 { 2111 2108 int rc; 2112 2109 2113 - WARN_ON(!mutex_is_locked(&efx->rss_lock)); 2110 + WARN_ON(!mutex_is_locked(&efx->net_dev->ethtool->rss_lock)); 2114 2111 2115 2112 if (ctx->context_id == EFX_MCDI_RSS_CONTEXT_INVALID) { 2113 + if (delete) 2114 + /* already wasn't in HW, nothing to do */ 2115 + return 0; 2116 2116 rc = efx_mcdi_filter_alloc_rss_context(efx, true, ctx, NULL); 2117 2117 if (rc) 2118 2118 return rc; 2119 2119 } 2120 2120 2121 - if (!rx_indir_table) /* Delete this context */ 2121 + if (delete) /* Delete this context */ 2122 2122 return efx_mcdi_filter_free_rss_context(efx, ctx->context_id); 2123 2123 2124 - rc = efx_mcdi_filter_populate_rss_table(efx, ctx->context_id, 2125 - rx_indir_table, key); 2126 - if (rc) 2127 - return rc; 2128 - 2129 - memcpy(ctx->rx_indir_table, rx_indir_table, 2130 - sizeof(efx->rss_context.rx_indir_table)); 2131 - memcpy(ctx->rx_hash_key, key, efx->type->rx_hash_key_size); 2132 - 2133 - return 0; 2124 + return efx_mcdi_filter_populate_rss_table(efx, ctx->context_id, 2125 + rx_indir_table, key); 2134 2126 } 2135 2127 2136 2128 int efx_mcdi_rx_pull_rss_context_config(struct efx_nic *efx, ··· 2137 2139 size_t outlen; 2138 2140 int rc, i; 2139 2141 2140 - WARN_ON(!mutex_is_locked(&efx->rss_lock)); 2142 + WARN_ON(!mutex_is_locked(&efx->net_dev->ethtool->rss_lock)); 2141 2143 2142 2144 BUILD_BUG_ON(MC_CMD_RSS_CONTEXT_GET_TABLE_IN_LEN != 2143 2145 MC_CMD_RSS_CONTEXT_GET_KEY_IN_LEN); 2144 2146 2145 - if (ctx->context_id == EFX_MCDI_RSS_CONTEXT_INVALID) 2147 + if (ctx->priv.context_id == EFX_MCDI_RSS_CONTEXT_INVALID) 2146 2148 return -ENOENT; 2147 2149 2148 2150 MCDI_SET_DWORD(inbuf, RSS_CONTEXT_GET_TABLE_IN_RSS_CONTEXT_ID, 2149 - ctx->context_id); 2151 + ctx->priv.context_id); 2150 2152 BUILD_BUG_ON(ARRAY_SIZE(ctx->rx_indir_table) != 2151 2153 MC_CMD_RSS_CONTEXT_GET_TABLE_OUT_INDIRECTION_TABLE_LEN); 2152 2154 rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_GET_TABLE, inbuf, sizeof(inbuf), ··· 2162 2164 RSS_CONTEXT_GET_TABLE_OUT_INDIRECTION_TABLE)[i]; 2163 2165 2164 2166 MCDI_SET_DWORD(inbuf, RSS_CONTEXT_GET_KEY_IN_RSS_CONTEXT_ID, 2165 - ctx->context_id); 2167 + ctx->priv.context_id); 2166 2168 BUILD_BUG_ON(ARRAY_SIZE(ctx->rx_hash_key) != 2167 2169 MC_CMD_RSS_CONTEXT_SET_KEY_IN_TOEPLITZ_KEY_LEN); 2168 2170 rc = efx_mcdi_rpc(efx, MC_CMD_RSS_CONTEXT_GET_KEY, inbuf, sizeof(inbuf), ··· 2184 2186 { 2185 2187 int rc; 2186 2188 2187 - mutex_lock(&efx->rss_lock); 2189 + mutex_lock(&efx->net_dev->ethtool->rss_lock); 2188 2190 rc = efx_mcdi_rx_pull_rss_context_config(efx, &efx->rss_context); 2189 - mutex_unlock(&efx->rss_lock); 2191 + mutex_unlock(&efx->net_dev->ethtool->rss_lock); 2190 2192 return rc; 2191 2193 } 2192 2194 2193 2195 void efx_mcdi_rx_restore_rss_contexts(struct efx_nic *efx) 2194 2196 { 2195 2197 struct efx_mcdi_filter_table *table = efx->filter_state; 2196 - struct efx_rss_context *ctx; 2198 + struct ethtool_rxfh_context *ctx; 2199 + unsigned long context; 2197 2200 int rc; 2198 2201 2199 - WARN_ON(!mutex_is_locked(&efx->rss_lock)); 2202 + WARN_ON(!mutex_is_locked(&efx->net_dev->ethtool->rss_lock)); 2200 2203 2201 2204 if (!table->must_restore_rss_contexts) 2202 2205 return; 2203 2206 2204 - list_for_each_entry(ctx, &efx->rss_context.list, list) { 2207 + xa_for_each(&efx->net_dev->ethtool->rss_ctx, context, ctx) { 2208 + struct efx_rss_context_priv *priv; 2209 + u32 *indir; 2210 + u8 *key; 2211 + 2212 + priv = ethtool_rxfh_context_priv(ctx); 2205 2213 /* previous NIC RSS context is gone */ 2206 - ctx->context_id = EFX_MCDI_RSS_CONTEXT_INVALID; 2214 + priv->context_id = EFX_MCDI_RSS_CONTEXT_INVALID; 2207 2215 /* so try to allocate a new one */ 2208 - rc = efx_mcdi_rx_push_rss_context_config(efx, ctx, 2209 - ctx->rx_indir_table, 2210 - ctx->rx_hash_key); 2216 + indir = ethtool_rxfh_context_indir(ctx); 2217 + key = ethtool_rxfh_context_key(ctx); 2218 + rc = efx_mcdi_rx_push_rss_context_config(efx, priv, indir, key, 2219 + false); 2211 2220 if (rc) 2212 2221 netif_warn(efx, probe, efx->net_dev, 2213 - "failed to restore RSS context %u, rc=%d" 2222 + "failed to restore RSS context %lu, rc=%d" 2214 2223 "; RSS filters may fail to be applied\n", 2215 - ctx->user_id, rc); 2224 + context, rc); 2216 2225 } 2217 2226 table->must_restore_rss_contexts = false; 2218 2227 } ··· 2281 2276 { 2282 2277 if (user) 2283 2278 return -EOPNOTSUPP; 2284 - if (efx->rss_context.context_id != EFX_MCDI_RSS_CONTEXT_INVALID) 2279 + if (efx->rss_context.priv.context_id != EFX_MCDI_RSS_CONTEXT_INVALID) 2285 2280 return 0; 2286 2281 return efx_mcdi_filter_rx_push_shared_rss_config(efx, NULL); 2287 2282 } ··· 2300 2295 2301 2296 efx_mcdi_rx_free_indir_table(efx); 2302 2297 if (rss_spread > 1) { 2303 - efx_set_default_rx_indir_table(efx, &efx->rss_context); 2298 + efx_set_default_rx_indir_table(efx, efx->rss_context.rx_indir_table); 2304 2299 rc = efx->type->rx_push_rss_config(efx, false, 2305 2300 efx->rss_context.rx_indir_table, NULL); 2306 2301 }
+2 -6
drivers/net/ethernet/sfc/mcdi_filters.h
··· 145 145 146 146 void efx_mcdi_rx_free_indir_table(struct efx_nic *efx); 147 147 int efx_mcdi_rx_push_rss_context_config(struct efx_nic *efx, 148 - struct efx_rss_context *ctx, 148 + struct efx_rss_context_priv *ctx, 149 149 const u32 *rx_indir_table, 150 - const u8 *key); 150 + const u8 *key, bool delete); 151 151 int efx_mcdi_pf_rx_push_rss_config(struct efx_nic *efx, bool user, 152 152 const u32 *rx_indir_table, 153 153 const u8 *key); ··· 161 161 int efx_mcdi_rx_pull_rss_config(struct efx_nic *efx); 162 162 int efx_mcdi_rx_pull_rss_context_config(struct efx_nic *efx, 163 163 struct efx_rss_context *ctx); 164 - int efx_mcdi_get_rss_context_flags(struct efx_nic *efx, u32 context, 165 - u32 *flags); 166 - void efx_mcdi_set_rss_context_flags(struct efx_nic *efx, 167 - struct efx_rss_context *ctx); 168 164 void efx_mcdi_rx_restore_rss_contexts(struct efx_nic *efx); 169 165 170 166 static inline void efx_mcdi_update_rx_scatter(struct efx_nic *efx)
+14 -14
drivers/net/ethernet/sfc/net_driver.h
··· 737 737 /* The reserved RSS context value */ 738 738 #define EFX_MCDI_RSS_CONTEXT_INVALID 0xffffffff 739 739 /** 740 - * struct efx_rss_context - A user-defined RSS context for filtering 741 - * @list: node of linked list on which this struct is stored 740 + * struct efx_rss_context_priv - driver private data for an RSS context 742 741 * @context_id: the RSS_CONTEXT_ID returned by MC firmware, or 743 742 * %EFX_MCDI_RSS_CONTEXT_INVALID if this context is not present on the NIC. 744 - * For Siena, 0 if RSS is active, else %EFX_MCDI_RSS_CONTEXT_INVALID. 745 - * @user_id: the rss_context ID exposed to userspace over ethtool. 746 743 * @rx_hash_udp_4tuple: UDP 4-tuple hashing enabled 744 + */ 745 + struct efx_rss_context_priv { 746 + u32 context_id; 747 + bool rx_hash_udp_4tuple; 748 + }; 749 + 750 + /** 751 + * struct efx_rss_context - an RSS context 752 + * @priv: hardware-specific state 747 753 * @rx_hash_key: Toeplitz hash key for this RSS context 748 754 * @indir_table: Indirection table for this RSS context 749 755 */ 750 756 struct efx_rss_context { 751 - struct list_head list; 752 - u32 context_id; 753 - u32 user_id; 754 - bool rx_hash_udp_4tuple; 757 + struct efx_rss_context_priv priv; 755 758 u8 rx_hash_key[40]; 756 759 u32 rx_indir_table[128]; 757 760 }; ··· 886 883 * @rx_packet_ts_offset: Offset of timestamp from start of packet data 887 884 * (valid only if channel->sync_timestamps_enabled; always negative) 888 885 * @rx_scatter: Scatter mode enabled for receives 889 - * @rss_context: Main RSS context. Its @list member is the head of the list of 890 - * RSS contexts created by user requests 891 - * @rss_lock: Protects custom RSS context software state in @rss_context.list 886 + * @rss_context: Main RSS context. 892 887 * @vport_id: The function's vport ID, only relevant for PFs 893 888 * @int_error_count: Number of internal errors seen recently 894 889 * @int_error_expire: Time at which error count will be expired ··· 1053 1052 int rx_packet_ts_offset; 1054 1053 bool rx_scatter; 1055 1054 struct efx_rss_context rss_context; 1056 - struct mutex rss_lock; 1057 1055 u32 vport_id; 1058 1056 1059 1057 unsigned int_error_count; ··· 1416 1416 const u32 *rx_indir_table, const u8 *key); 1417 1417 int (*rx_pull_rss_config)(struct efx_nic *efx); 1418 1418 int (*rx_push_rss_context_config)(struct efx_nic *efx, 1419 - struct efx_rss_context *ctx, 1419 + struct efx_rss_context_priv *ctx, 1420 1420 const u32 *rx_indir_table, 1421 - const u8 *key); 1421 + const u8 *key, bool delete); 1422 1422 int (*rx_pull_rss_context_config)(struct efx_nic *efx, 1423 1423 struct efx_rss_context *ctx); 1424 1424 void (*rx_restore_rss_contexts)(struct efx_nic *efx);
+10 -54
drivers/net/ethernet/sfc/rx_common.c
··· 557 557 napi_gro_frags(napi); 558 558 } 559 559 560 - /* RSS contexts. We're using linked lists and crappy O(n) algorithms, because 561 - * (a) this is an infrequent control-plane operation and (b) n is small (max 64) 562 - */ 563 - struct efx_rss_context *efx_alloc_rss_context_entry(struct efx_nic *efx) 560 + struct efx_rss_context_priv *efx_find_rss_context_entry(struct efx_nic *efx, 561 + u32 id) 564 562 { 565 - struct list_head *head = &efx->rss_context.list; 566 - struct efx_rss_context *ctx, *new; 567 - u32 id = 1; /* Don't use zero, that refers to the master RSS context */ 563 + struct ethtool_rxfh_context *ctx; 568 564 569 - WARN_ON(!mutex_is_locked(&efx->rss_lock)); 565 + WARN_ON(!mutex_is_locked(&efx->net_dev->ethtool->rss_lock)); 570 566 571 - /* Search for first gap in the numbering */ 572 - list_for_each_entry(ctx, head, list) { 573 - if (ctx->user_id != id) 574 - break; 575 - id++; 576 - /* Check for wrap. If this happens, we have nearly 2^32 577 - * allocated RSS contexts, which seems unlikely. 578 - */ 579 - if (WARN_ON_ONCE(!id)) 580 - return NULL; 581 - } 582 - 583 - /* Create the new entry */ 584 - new = kmalloc(sizeof(*new), GFP_KERNEL); 585 - if (!new) 567 + ctx = xa_load(&efx->net_dev->ethtool->rss_ctx, id); 568 + if (!ctx) 586 569 return NULL; 587 - new->context_id = EFX_MCDI_RSS_CONTEXT_INVALID; 588 - new->rx_hash_udp_4tuple = false; 589 - 590 - /* Insert the new entry into the gap */ 591 - new->user_id = id; 592 - list_add_tail(&new->list, &ctx->list); 593 - return new; 570 + return ethtool_rxfh_context_priv(ctx); 594 571 } 595 572 596 - struct efx_rss_context *efx_find_rss_context_entry(struct efx_nic *efx, u32 id) 597 - { 598 - struct list_head *head = &efx->rss_context.list; 599 - struct efx_rss_context *ctx; 600 - 601 - WARN_ON(!mutex_is_locked(&efx->rss_lock)); 602 - 603 - list_for_each_entry(ctx, head, list) 604 - if (ctx->user_id == id) 605 - return ctx; 606 - return NULL; 607 - } 608 - 609 - void efx_free_rss_context_entry(struct efx_rss_context *ctx) 610 - { 611 - list_del(&ctx->list); 612 - kfree(ctx); 613 - } 614 - 615 - void efx_set_default_rx_indir_table(struct efx_nic *efx, 616 - struct efx_rss_context *ctx) 573 + void efx_set_default_rx_indir_table(struct efx_nic *efx, u32 *indir) 617 574 { 618 575 size_t i; 619 576 620 - for (i = 0; i < ARRAY_SIZE(ctx->rx_indir_table); i++) 621 - ctx->rx_indir_table[i] = 622 - ethtool_rxfh_indir_default(i, efx->rss_spread); 577 + for (i = 0; i < ARRAY_SIZE(efx->rss_context.rx_indir_table); i++) 578 + indir[i] = ethtool_rxfh_indir_default(i, efx->rss_spread); 623 579 } 624 580 625 581 /**
+3 -5
drivers/net/ethernet/sfc/rx_common.h
··· 84 84 efx_rx_packet_gro(struct efx_channel *channel, struct efx_rx_buffer *rx_buf, 85 85 unsigned int n_frags, u8 *eh, __wsum csum); 86 86 87 - struct efx_rss_context *efx_alloc_rss_context_entry(struct efx_nic *efx); 88 - struct efx_rss_context *efx_find_rss_context_entry(struct efx_nic *efx, u32 id); 89 - void efx_free_rss_context_entry(struct efx_rss_context *ctx); 90 - void efx_set_default_rx_indir_table(struct efx_nic *efx, 91 - struct efx_rss_context *ctx); 87 + struct efx_rss_context_priv *efx_find_rss_context_entry(struct efx_nic *efx, 88 + u32 id); 89 + void efx_set_default_rx_indir_table(struct efx_nic *efx, u32 *indir); 92 90 93 91 bool efx_filter_is_mc_recipient(const struct efx_filter_spec *spec); 94 92 bool efx_filter_spec_equal(const struct efx_filter_spec *left,