forked from mirrors/linux
		
	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: Edward Cree <ecree.xilinx@gmail.com> Reviewed-by: Przemek Kitszel <przemyslaw.kitszel@intel.com> Link: https://patch.msgid.link/45f1fe61df2163c091ec394c9f52000c8b16cc3b.1719502240.git.ecree.xilinx@gmail.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
		
							parent
							
								
									eac9122f0c
								
							
						
					
					
						commit
						847a8ab186
					
				
					 3 changed files with 79 additions and 13 deletions
				
			
		|  | @ -723,6 +723,10 @@ struct ethtool_rxfh_param { | |||
|  *	RSS. | ||||
|  * @rxfh_priv_size: size of the driver private data area the core should | ||||
|  *	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_ring_params: supported ring params. | ||||
|  * @get_drvinfo: Report driver/device information. Modern drivers no | ||||
|  | @ -819,6 +823,32 @@ struct ethtool_rxfh_param { | |||
|  *	will remain unchanged. | ||||
|  *	Returns a negative error code or zero. An error code must be returned | ||||
|  *	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. | ||||
|  * @set_channels: Set number of channels.  Returns a negative error code or | ||||
|  *	zero. | ||||
|  | @ -909,6 +939,7 @@ struct ethtool_ops { | |||
| 	u32     cap_rss_ctx_supported:1; | ||||
| 	u32	cap_rss_sym_xor_supported:1; | ||||
| 	u16	rxfh_priv_size; | ||||
| 	u32	rxfh_max_context_id; | ||||
| 	u32	supported_coalesce_params; | ||||
| 	u32	supported_ring_params; | ||||
| 	void	(*get_drvinfo)(struct net_device *, struct ethtool_drvinfo *); | ||||
|  | @ -971,6 +1002,15 @@ struct ethtool_ops { | |||
| 	int	(*get_rxfh)(struct net_device *, struct ethtool_rxfh_param *); | ||||
| 	int	(*set_rxfh)(struct net_device *, struct ethtool_rxfh_param *, | ||||
| 			    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 *); | ||||
| 	int	(*set_channels)(struct net_device *, struct ethtool_channels *); | ||||
| 	int	(*get_dump_flag)(struct net_device *, struct ethtool_dump *); | ||||
|  |  | |||
|  | @ -11254,7 +11254,11 @@ static void netdev_rss_contexts_free(struct net_device *dev) | |||
| 		rxfh.rss_delete = true; | ||||
| 
 | ||||
| 		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); | ||||
| 	} | ||||
| 	xa_destroy(&dev->ethtool->rss_ctx); | ||||
|  |  | |||
|  | @ -1395,9 +1395,24 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, | |||
| 		} | ||||
| 		ctx->indir_size = dev_indir_size; | ||||
| 		ctx->key_size = dev_key_size; | ||||
| 		ctx->hfunc = rxfh.hfunc; | ||||
| 		ctx->input_xfrm = rxfh.input_xfrm; | ||||
| 		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) { | ||||
| 		ctx = xa_load(&dev->ethtool->rss_ctx, rxfh.rss_context); | ||||
| 		if (!ctx) { | ||||
|  | @ -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.input_xfrm = rxfh.input_xfrm; | ||||
| 
 | ||||
| 	ret = ops->set_rxfh(dev, &rxfh_dev, extack); | ||||
| 	if (ret) { | ||||
| 	if (rxfh.rss_context && ops->create_rxfh_context) { | ||||
| 		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 */ | ||||
| 			if (ops->create_rxfh_context) | ||||
| 				xa_erase(&dev->ethtool->rss_ctx, rxfh.rss_context); | ||||
| 			kfree(ctx); | ||||
| 		} | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -1429,12 +1457,8 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, | |||
| 			dev->priv_flags |= IFF_RXFH_CONFIGURED; | ||||
| 	} | ||||
| 	/* Update rss_ctx tracking */ | ||||
| 	if (create) { | ||||
| 		/* Ideally this should happen before calling the driver,
 | ||||
| 		 * 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 (create && !ops->create_rxfh_context) { | ||||
| 		/* driver uses old API, it chose context ID */ | ||||
| 		if (WARN_ON(xa_load(&dev->ethtool->rss_ctx, rxfh.rss_context))) { | ||||
| 			/* context ID reused, our tracking is screwed */ | ||||
| 			kfree(ctx); | ||||
|  | @ -1446,8 +1470,6 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, | |||
| 			kfree(ctx); | ||||
| 			goto out; | ||||
| 		} | ||||
| 		ctx->indir_configured = rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE; | ||||
| 		ctx->key_configured = !!rxfh.key_size; | ||||
| 	} | ||||
| 	if (rxfh_dev.rss_delete) { | ||||
| 		WARN_ON(xa_erase(&dev->ethtool->rss_ctx, rxfh.rss_context) != ctx); | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Edward Cree
						Edward Cree