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

Configure Feed

Select the types of activity you want to include in your feed.

ethtool: Add RSS indirection table resize helpers

The core locks ctx->indir_size when an RSS context is created. Some
NICs (e.g. bnxt) change their indirection table size based on the
channel count, because the hardware table is a shared resource. This
forces drivers to reject channel changes when RSS contexts exist.

Add driver helpers to resize indirection tables:

ethtool_rxfh_indir_can_resize() checks whether the default context
indirection table can be resized.

ethtool_rxfh_indir_resize() resizes the default context table in
place. Folding (shrink) requires the table to be periodic at the new
size; non-periodic tables are rejected. Unfolding (grow) replicates
the existing pattern. Sizes must be multiples of each other.

ethtool_rxfh_ctxs_can_resize() validates all non-default RSS contexts
can be resized.

ethtool_rxfh_ctxs_resize() applies the resize.

Signed-off-by: Björn Töpel <bjorn@kernel.org>
Link: https://patch.msgid.link/20260320085826.1957255-3-bjorn@kernel.org
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Björn Töpel and committed by
Jakub Kicinski
02bcb200 0475f9e7

+161
+6
include/linux/ethtool.h
··· 218 218 219 219 void ethtool_rxfh_context_lost(struct net_device *dev, u32 context_id); 220 220 void ethtool_rxfh_indir_lost(struct net_device *dev); 221 + bool ethtool_rxfh_indir_can_resize(struct net_device *dev, const u32 *tbl, 222 + u32 old_size, u32 new_size); 223 + void ethtool_rxfh_indir_resize(struct net_device *dev, u32 *tbl, 224 + u32 old_size, u32 new_size); 225 + int ethtool_rxfh_ctxs_can_resize(struct net_device *dev, u32 new_indir_size); 226 + void ethtool_rxfh_ctxs_resize(struct net_device *dev, u32 new_indir_size); 221 227 222 228 struct link_mode_info { 223 229 int speed;
+155
net/ethtool/common.c
··· 1232 1232 } 1233 1233 EXPORT_SYMBOL(ethtool_rxfh_indir_lost); 1234 1234 1235 + static bool ethtool_rxfh_is_periodic(const u32 *tbl, u32 old_size, u32 new_size) 1236 + { 1237 + u32 i; 1238 + 1239 + for (i = new_size; i < old_size; i++) 1240 + if (tbl[i] != tbl[i % new_size]) 1241 + return false; 1242 + return true; 1243 + } 1244 + 1245 + static bool ethtool_rxfh_can_resize(const u32 *tbl, u32 old_size, u32 new_size, 1246 + u32 user_size) 1247 + { 1248 + if (new_size == old_size) 1249 + return true; 1250 + 1251 + if (!user_size) 1252 + return true; 1253 + 1254 + if (new_size < old_size) { 1255 + if (new_size < user_size) 1256 + return false; 1257 + if (old_size % new_size) 1258 + return false; 1259 + if (!ethtool_rxfh_is_periodic(tbl, old_size, new_size)) 1260 + return false; 1261 + return true; 1262 + } 1263 + 1264 + if (new_size % old_size) 1265 + return false; 1266 + return true; 1267 + } 1268 + 1269 + /* Resize without validation; caller must have called can_resize first */ 1270 + static void ethtool_rxfh_resize(u32 *tbl, u32 old_size, u32 new_size) 1271 + { 1272 + u32 i; 1273 + 1274 + /* Grow: replicate existing pattern; shrink is a no-op on the data */ 1275 + for (i = old_size; i < new_size; i++) 1276 + tbl[i] = tbl[i % old_size]; 1277 + } 1278 + 1279 + /** 1280 + * ethtool_rxfh_indir_can_resize - Check if context 0 indir table can resize 1281 + * @dev: network device 1282 + * @tbl: indirection table 1283 + * @old_size: current number of entries in the table 1284 + * @new_size: desired number of entries 1285 + * 1286 + * Validate that @tbl can be resized from @old_size to @new_size without 1287 + * data loss. Uses the user_size floor from context 0. When user_size is 1288 + * zero the table is not user-configured and resize always succeeds. 1289 + * Read-only; does not modify the table. 1290 + * 1291 + * Return: true if resize is possible, false otherwise. 1292 + */ 1293 + bool ethtool_rxfh_indir_can_resize(struct net_device *dev, const u32 *tbl, 1294 + u32 old_size, u32 new_size) 1295 + { 1296 + return ethtool_rxfh_can_resize(tbl, old_size, new_size, 1297 + dev->ethtool->rss_indir_user_size); 1298 + } 1299 + EXPORT_SYMBOL(ethtool_rxfh_indir_can_resize); 1300 + 1301 + /** 1302 + * ethtool_rxfh_indir_resize - Fold or unfold context 0 indirection table 1303 + * @dev: network device 1304 + * @tbl: indirection table (must have room for max(old_size, new_size) entries) 1305 + * @old_size: current number of entries in the table 1306 + * @new_size: desired number of entries 1307 + * 1308 + * Resize the default RSS context indirection table in place. Caller 1309 + * must have validated with ethtool_rxfh_indir_can_resize() first. 1310 + */ 1311 + void ethtool_rxfh_indir_resize(struct net_device *dev, u32 *tbl, 1312 + u32 old_size, u32 new_size) 1313 + { 1314 + if (!dev->ethtool->rss_indir_user_size) 1315 + return; 1316 + 1317 + ethtool_rxfh_resize(tbl, old_size, new_size); 1318 + } 1319 + EXPORT_SYMBOL(ethtool_rxfh_indir_resize); 1320 + 1321 + /** 1322 + * ethtool_rxfh_ctxs_can_resize - Validate resize for all RSS contexts 1323 + * @dev: network device 1324 + * @new_indir_size: new indirection table size 1325 + * 1326 + * Validate that the indirection tables of all non-default RSS contexts 1327 + * can be resized to @new_indir_size. Read-only; does not modify any 1328 + * context. Intended to be paired with ethtool_rxfh_ctxs_resize(). 1329 + * 1330 + * Return: 0 if all contexts can be resized, negative errno on failure. 1331 + */ 1332 + int ethtool_rxfh_ctxs_can_resize(struct net_device *dev, u32 new_indir_size) 1333 + { 1334 + struct ethtool_rxfh_context *ctx; 1335 + unsigned long context; 1336 + int ret = 0; 1337 + 1338 + if (!dev->ethtool_ops->rxfh_indir_space || 1339 + new_indir_size > dev->ethtool_ops->rxfh_indir_space) 1340 + return -EINVAL; 1341 + 1342 + mutex_lock(&dev->ethtool->rss_lock); 1343 + xa_for_each(&dev->ethtool->rss_ctx, context, ctx) { 1344 + u32 *indir = ethtool_rxfh_context_indir(ctx); 1345 + 1346 + if (!ethtool_rxfh_can_resize(indir, ctx->indir_size, 1347 + new_indir_size, 1348 + ctx->indir_user_size)) { 1349 + ret = -EINVAL; 1350 + goto unlock; 1351 + } 1352 + } 1353 + unlock: 1354 + mutex_unlock(&dev->ethtool->rss_lock); 1355 + return ret; 1356 + } 1357 + EXPORT_SYMBOL(ethtool_rxfh_ctxs_can_resize); 1358 + 1359 + /** 1360 + * ethtool_rxfh_ctxs_resize - Resize all RSS context indirection tables 1361 + * @dev: network device 1362 + * @new_indir_size: new indirection table size 1363 + * 1364 + * Resize the indirection table of every non-default RSS context to 1365 + * @new_indir_size. Caller must have validated with 1366 + * ethtool_rxfh_ctxs_can_resize() first. An %ETHTOOL_MSG_RSS_NTF is 1367 + * sent for each resized context. 1368 + * 1369 + * Notifications are sent outside the RSS lock to avoid holding the 1370 + * mutex during notification delivery. 1371 + */ 1372 + void ethtool_rxfh_ctxs_resize(struct net_device *dev, u32 new_indir_size) 1373 + { 1374 + struct ethtool_rxfh_context *ctx; 1375 + unsigned long context; 1376 + 1377 + mutex_lock(&dev->ethtool->rss_lock); 1378 + xa_for_each(&dev->ethtool->rss_ctx, context, ctx) { 1379 + ethtool_rxfh_resize(ethtool_rxfh_context_indir(ctx), 1380 + ctx->indir_size, new_indir_size); 1381 + ctx->indir_size = new_indir_size; 1382 + } 1383 + mutex_unlock(&dev->ethtool->rss_lock); 1384 + 1385 + xa_for_each(&dev->ethtool->rss_ctx, context, ctx) 1386 + ethtool_rss_notify(dev, ETHTOOL_MSG_RSS_NTF, context); 1387 + } 1388 + EXPORT_SYMBOL(ethtool_rxfh_ctxs_resize); 1389 + 1235 1390 enum ethtool_link_medium ethtool_str_to_medium(const char *str) 1236 1391 { 1237 1392 int i;