Commit 847a8ab1 authored by Edward Cree's avatar Edward Cree Committed by Jakub Kicinski

net: ethtool: let the core choose RSS context IDs

Add a new API to create/modify/remove RSS contexts, that passes in the
 newly-chosen context ID (not as a pointer) rather than leaving the
 driver to choose it on create.  Also pass in the ctx, allowing drivers
 to easily use its private data area to store their hardware-specific
 state.
Keep the existing .set_rxfh API for now as a fallback, but deprecate it
 for custom contexts (rss_context != 0).
Signed-off-by: default avatarEdward Cree <ecree.xilinx@gmail.com>
Reviewed-by: default avatarPrzemek Kitszel <przemyslaw.kitszel@intel.com>
Link: https://patch.msgid.link/45f1fe61df2163c091ec394c9f52000c8b16cc3b.1719502240.git.ecree.xilinx@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent eac9122f
...@@ -723,6 +723,10 @@ struct ethtool_rxfh_param { ...@@ -723,6 +723,10 @@ struct ethtool_rxfh_param {
* RSS. * RSS.
* @rxfh_priv_size: size of the driver private data area the core should * @rxfh_priv_size: size of the driver private data area the core should
* allocate for an RSS context (in &struct ethtool_rxfh_context). * allocate for an RSS context (in &struct ethtool_rxfh_context).
* @rxfh_max_context_id: maximum (exclusive) supported RSS context ID. If this
* is zero then the core may choose any (nonzero) ID, otherwise the core
* will only use IDs strictly less than this value, as the @rss_context
* argument to @create_rxfh_context and friends.
* @supported_coalesce_params: supported types of interrupt coalescing. * @supported_coalesce_params: supported types of interrupt coalescing.
* @supported_ring_params: supported ring params. * @supported_ring_params: supported ring params.
* @get_drvinfo: Report driver/device information. Modern drivers no * @get_drvinfo: Report driver/device information. Modern drivers no
...@@ -819,6 +823,32 @@ struct ethtool_rxfh_param { ...@@ -819,6 +823,32 @@ struct ethtool_rxfh_param {
* will remain unchanged. * will remain unchanged.
* Returns a negative error code or zero. An error code must be returned * Returns a negative error code or zero. An error code must be returned
* if at least one unsupported change was requested. * if at least one unsupported change was requested.
* @create_rxfh_context: Create a new RSS context with the specified RX flow
* hash indirection table, hash key, and hash function.
* The &struct ethtool_rxfh_context for this context is passed in @ctx;
* note that the indir table, hkey and hfunc are not yet populated as
* of this call. The driver does not need to update these; the core
* will do so if this op succeeds.
* However, if @rxfh.indir is set to %NULL, the driver must update the
* indir table in @ctx with the (default or inherited) table actually in
* use; similarly, if @rxfh.key is %NULL, @rxfh.hfunc is
* %ETH_RSS_HASH_NO_CHANGE, or @rxfh.input_xfrm is %RXH_XFRM_NO_CHANGE,
* the driver should update the corresponding information in @ctx.
* If the driver provides this method, it must also provide
* @modify_rxfh_context and @remove_rxfh_context.
* Returns a negative error code or zero.
* @modify_rxfh_context: Reconfigure the specified RSS context. Allows setting
* the contents of the RX flow hash indirection table, hash key, and/or
* hash function associated with the given context.
* Parameters which are set to %NULL or zero will remain unchanged.
* The &struct ethtool_rxfh_context for this context is passed in @ctx;
* note that it will still contain the *old* settings. The driver does
* not need to update these; the core will do so if this op succeeds.
* Returns a negative error code or zero. An error code must be returned
* if at least one unsupported change was requested.
* @remove_rxfh_context: Remove the specified RSS context.
* The &struct ethtool_rxfh_context for this context is passed in @ctx.
* Returns a negative error code or zero.
* @get_channels: Get number of channels. * @get_channels: Get number of channels.
* @set_channels: Set number of channels. Returns a negative error code or * @set_channels: Set number of channels. Returns a negative error code or
* zero. * zero.
...@@ -909,6 +939,7 @@ struct ethtool_ops { ...@@ -909,6 +939,7 @@ struct ethtool_ops {
u32 cap_rss_ctx_supported:1; u32 cap_rss_ctx_supported:1;
u32 cap_rss_sym_xor_supported:1; u32 cap_rss_sym_xor_supported:1;
u16 rxfh_priv_size; u16 rxfh_priv_size;
u32 rxfh_max_context_id;
u32 supported_coalesce_params; u32 supported_coalesce_params;
u32 supported_ring_params; u32 supported_ring_params;
void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *); void (*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *);
...@@ -971,6 +1002,15 @@ struct ethtool_ops { ...@@ -971,6 +1002,15 @@ struct ethtool_ops {
int (*get_rxfh)(struct net_device *, struct ethtool_rxfh_param *); int (*get_rxfh)(struct net_device *, struct ethtool_rxfh_param *);
int (*set_rxfh)(struct net_device *, struct ethtool_rxfh_param *, int (*set_rxfh)(struct net_device *, struct ethtool_rxfh_param *,
struct netlink_ext_ack *extack); struct netlink_ext_ack *extack);
int (*create_rxfh_context)(struct net_device *,
struct ethtool_rxfh_context *ctx,
const struct ethtool_rxfh_param *rxfh);
int (*modify_rxfh_context)(struct net_device *,
struct ethtool_rxfh_context *ctx,
const struct ethtool_rxfh_param *rxfh);
int (*remove_rxfh_context)(struct net_device *,
struct ethtool_rxfh_context *ctx,
u32 rss_context);
void (*get_channels)(struct net_device *, struct ethtool_channels *); void (*get_channels)(struct net_device *, struct ethtool_channels *);
int (*set_channels)(struct net_device *, struct ethtool_channels *); int (*set_channels)(struct net_device *, struct ethtool_channels *);
int (*get_dump_flag)(struct net_device *, struct ethtool_dump *); int (*get_dump_flag)(struct net_device *, struct ethtool_dump *);
......
...@@ -11254,7 +11254,11 @@ static void netdev_rss_contexts_free(struct net_device *dev) ...@@ -11254,7 +11254,11 @@ static void netdev_rss_contexts_free(struct net_device *dev)
rxfh.rss_delete = true; rxfh.rss_delete = true;
xa_erase(&dev->ethtool->rss_ctx, context); xa_erase(&dev->ethtool->rss_ctx, context);
dev->ethtool_ops->set_rxfh(dev, &rxfh, NULL); if (dev->ethtool_ops->create_rxfh_context)
dev->ethtool_ops->remove_rxfh_context(dev, ctx,
context);
else
dev->ethtool_ops->set_rxfh(dev, &rxfh, NULL);
kfree(ctx); kfree(ctx);
} }
xa_destroy(&dev->ethtool->rss_ctx); xa_destroy(&dev->ethtool->rss_ctx);
......
...@@ -1395,9 +1395,24 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, ...@@ -1395,9 +1395,24 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
} }
ctx->indir_size = dev_indir_size; ctx->indir_size = dev_indir_size;
ctx->key_size = dev_key_size; ctx->key_size = dev_key_size;
ctx->hfunc = rxfh.hfunc;
ctx->input_xfrm = rxfh.input_xfrm;
ctx->priv_size = ops->rxfh_priv_size; ctx->priv_size = ops->rxfh_priv_size;
/* Initialise to an empty context */
ctx->hfunc = ETH_RSS_HASH_NO_CHANGE;
ctx->input_xfrm = RXH_XFRM_NO_CHANGE;
if (ops->create_rxfh_context) {
u32 limit = ops->rxfh_max_context_id ?: U32_MAX;
u32 ctx_id;
/* driver uses new API, core allocates ID */
ret = xa_alloc(&dev->ethtool->rss_ctx, &ctx_id, ctx,
XA_LIMIT(1, limit), GFP_KERNEL_ACCOUNT);
if (ret < 0) {
kfree(ctx);
goto out;
}
WARN_ON(!ctx_id); /* can't happen */
rxfh.rss_context = ctx_id;
}
} else if (rxfh.rss_context) { } else if (rxfh.rss_context) {
ctx = xa_load(&dev->ethtool->rss_ctx, rxfh.rss_context); ctx = xa_load(&dev->ethtool->rss_ctx, rxfh.rss_context);
if (!ctx) { if (!ctx) {
...@@ -1409,11 +1424,24 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, ...@@ -1409,11 +1424,24 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
rxfh_dev.rss_context = rxfh.rss_context; rxfh_dev.rss_context = rxfh.rss_context;
rxfh_dev.input_xfrm = rxfh.input_xfrm; rxfh_dev.input_xfrm = rxfh.input_xfrm;
ret = ops->set_rxfh(dev, &rxfh_dev, extack); if (rxfh.rss_context && ops->create_rxfh_context) {
if (ret) {
if (create) if (create)
ret = ops->create_rxfh_context(dev, ctx, &rxfh_dev);
else if (rxfh_dev.rss_delete)
ret = ops->remove_rxfh_context(dev, ctx,
rxfh.rss_context);
else
ret = ops->modify_rxfh_context(dev, ctx, &rxfh_dev);
} else {
ret = ops->set_rxfh(dev, &rxfh_dev, extack);
}
if (ret) {
if (create) {
/* failed to create, free our new tracking entry */ /* failed to create, free our new tracking entry */
if (ops->create_rxfh_context)
xa_erase(&dev->ethtool->rss_ctx, rxfh.rss_context);
kfree(ctx); kfree(ctx);
}
goto out; goto out;
} }
...@@ -1429,12 +1457,8 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, ...@@ -1429,12 +1457,8 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
dev->priv_flags |= IFF_RXFH_CONFIGURED; dev->priv_flags |= IFF_RXFH_CONFIGURED;
} }
/* Update rss_ctx tracking */ /* Update rss_ctx tracking */
if (create) { if (create && !ops->create_rxfh_context) {
/* Ideally this should happen before calling the driver, /* driver uses old API, it chose context ID */
* so that we can fail more cleanly; but we don't have the
* context ID until the driver picks it, so we have to
* wait until after.
*/
if (WARN_ON(xa_load(&dev->ethtool->rss_ctx, rxfh.rss_context))) { if (WARN_ON(xa_load(&dev->ethtool->rss_ctx, rxfh.rss_context))) {
/* context ID reused, our tracking is screwed */ /* context ID reused, our tracking is screwed */
kfree(ctx); kfree(ctx);
...@@ -1446,8 +1470,6 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, ...@@ -1446,8 +1470,6 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,
kfree(ctx); kfree(ctx);
goto out; goto out;
} }
ctx->indir_configured = rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE;
ctx->key_configured = !!rxfh.key_size;
} }
if (rxfh_dev.rss_delete) { if (rxfh_dev.rss_delete) {
WARN_ON(xa_erase(&dev->ethtool->rss_ctx, rxfh.rss_context) != ctx); WARN_ON(xa_erase(&dev->ethtool->rss_ctx, rxfh.rss_context) != ctx);
......
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