Merge branch 'ethtool-rssh-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bwh/net-next
Ben Hutchings says:
====================
Pull request: Fixes for new ethtool RSS commands
This addresses several problems I previously identified with the new
ETHTOOL_{G,S}RSSH commands:
1. Missing validation of reserved parameters
2. Vague documentation
3. Use of unnamed magic number
4. No consolidation with existing driver operations
I don't currently have access to suitable network hardware, but have
tested these changes with a dummy driver that can support various
combinations of operations and sizes, together with (a) Debian's ethtool
3.13 (b) ethtool 3.14 with the submitted patch to use ETHTOOL_{G,S}RSSH
and minor adjustment for fixes 1 and 3.
v2: Update RSS operations in vmxnet3 too
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
	
	
This commit is contained in:
		
				commit
				
					
						014b20133b
					
				
			
		
					 14 changed files with 122 additions and 131 deletions
				
			
		|  | @ -3316,7 +3316,7 @@ static u32 bnx2x_get_rxfh_indir_size(struct net_device *dev) | ||||||
| 	return T_ETH_INDIRECTION_TABLE_SIZE; | 	return T_ETH_INDIRECTION_TABLE_SIZE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int bnx2x_get_rxfh_indir(struct net_device *dev, u32 *indir) | static int bnx2x_get_rxfh(struct net_device *dev, u32 *indir, u8 *key) | ||||||
| { | { | ||||||
| 	struct bnx2x *bp = netdev_priv(dev); | 	struct bnx2x *bp = netdev_priv(dev); | ||||||
| 	u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0}; | 	u8 ind_table[T_ETH_INDIRECTION_TABLE_SIZE] = {0}; | ||||||
|  | @ -3340,14 +3340,15 @@ static int bnx2x_get_rxfh_indir(struct net_device *dev, u32 *indir) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int bnx2x_set_rxfh_indir(struct net_device *dev, const u32 *indir) | static int bnx2x_set_rxfh(struct net_device *dev, const u32 *indir, | ||||||
|  | 			  const u8 *key) | ||||||
| { | { | ||||||
| 	struct bnx2x *bp = netdev_priv(dev); | 	struct bnx2x *bp = netdev_priv(dev); | ||||||
| 	size_t i; | 	size_t i; | ||||||
| 
 | 
 | ||||||
| 	for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) { | 	for (i = 0; i < T_ETH_INDIRECTION_TABLE_SIZE; i++) { | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * The same as in bnx2x_get_rxfh_indir: we can't use a memcpy() | 		 * The same as in bnx2x_get_rxfh: we can't use a memcpy() | ||||||
| 		 * as an internal storage of an indirection table is a u8 array | 		 * as an internal storage of an indirection table is a u8 array | ||||||
| 		 * while indir->ring_index points to an array of u32. | 		 * while indir->ring_index points to an array of u32. | ||||||
| 		 * | 		 * | ||||||
|  | @ -3471,8 +3472,8 @@ static const struct ethtool_ops bnx2x_ethtool_ops = { | ||||||
| 	.get_rxnfc		= bnx2x_get_rxnfc, | 	.get_rxnfc		= bnx2x_get_rxnfc, | ||||||
| 	.set_rxnfc		= bnx2x_set_rxnfc, | 	.set_rxnfc		= bnx2x_set_rxnfc, | ||||||
| 	.get_rxfh_indir_size	= bnx2x_get_rxfh_indir_size, | 	.get_rxfh_indir_size	= bnx2x_get_rxfh_indir_size, | ||||||
| 	.get_rxfh_indir		= bnx2x_get_rxfh_indir, | 	.get_rxfh		= bnx2x_get_rxfh, | ||||||
| 	.set_rxfh_indir		= bnx2x_set_rxfh_indir, | 	.set_rxfh		= bnx2x_set_rxfh, | ||||||
| 	.get_channels		= bnx2x_get_channels, | 	.get_channels		= bnx2x_get_channels, | ||||||
| 	.set_channels		= bnx2x_set_channels, | 	.set_channels		= bnx2x_set_channels, | ||||||
| 	.get_module_info	= bnx2x_get_module_info, | 	.get_module_info	= bnx2x_get_module_info, | ||||||
|  | @ -3498,8 +3499,8 @@ static const struct ethtool_ops bnx2x_vf_ethtool_ops = { | ||||||
| 	.get_rxnfc		= bnx2x_get_rxnfc, | 	.get_rxnfc		= bnx2x_get_rxnfc, | ||||||
| 	.set_rxnfc		= bnx2x_set_rxnfc, | 	.set_rxnfc		= bnx2x_set_rxnfc, | ||||||
| 	.get_rxfh_indir_size	= bnx2x_get_rxfh_indir_size, | 	.get_rxfh_indir_size	= bnx2x_get_rxfh_indir_size, | ||||||
| 	.get_rxfh_indir		= bnx2x_get_rxfh_indir, | 	.get_rxfh		= bnx2x_get_rxfh, | ||||||
| 	.set_rxfh_indir		= bnx2x_set_rxfh_indir, | 	.set_rxfh		= bnx2x_set_rxfh, | ||||||
| 	.get_channels		= bnx2x_get_channels, | 	.get_channels		= bnx2x_get_channels, | ||||||
| 	.set_channels		= bnx2x_set_channels, | 	.set_channels		= bnx2x_set_channels, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | @ -12532,7 +12532,7 @@ static u32 tg3_get_rxfh_indir_size(struct net_device *dev) | ||||||
| 	return size; | 	return size; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int tg3_get_rxfh_indir(struct net_device *dev, u32 *indir) | static int tg3_get_rxfh(struct net_device *dev, u32 *indir, u8 *key) | ||||||
| { | { | ||||||
| 	struct tg3 *tp = netdev_priv(dev); | 	struct tg3 *tp = netdev_priv(dev); | ||||||
| 	int i; | 	int i; | ||||||
|  | @ -12543,7 +12543,7 @@ static int tg3_get_rxfh_indir(struct net_device *dev, u32 *indir) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int tg3_set_rxfh_indir(struct net_device *dev, const u32 *indir) | static int tg3_set_rxfh(struct net_device *dev, const u32 *indir, const u8 *key) | ||||||
| { | { | ||||||
| 	struct tg3 *tp = netdev_priv(dev); | 	struct tg3 *tp = netdev_priv(dev); | ||||||
| 	size_t i; | 	size_t i; | ||||||
|  | @ -14075,8 +14075,8 @@ static const struct ethtool_ops tg3_ethtool_ops = { | ||||||
| 	.get_sset_count		= tg3_get_sset_count, | 	.get_sset_count		= tg3_get_sset_count, | ||||||
| 	.get_rxnfc		= tg3_get_rxnfc, | 	.get_rxnfc		= tg3_get_rxnfc, | ||||||
| 	.get_rxfh_indir_size    = tg3_get_rxfh_indir_size, | 	.get_rxfh_indir_size    = tg3_get_rxfh_indir_size, | ||||||
| 	.get_rxfh_indir		= tg3_get_rxfh_indir, | 	.get_rxfh		= tg3_get_rxfh, | ||||||
| 	.set_rxfh_indir		= tg3_set_rxfh_indir, | 	.set_rxfh		= tg3_set_rxfh, | ||||||
| 	.get_channels		= tg3_get_channels, | 	.get_channels		= tg3_get_channels, | ||||||
| 	.set_channels		= tg3_set_channels, | 	.set_channels		= tg3_set_channels, | ||||||
| 	.get_ts_info		= tg3_get_ts_info, | 	.get_ts_info		= tg3_get_ts_info, | ||||||
|  |  | ||||||
|  | @ -2739,7 +2739,7 @@ static u32 get_rss_table_size(struct net_device *dev) | ||||||
| 	return pi->rss_size; | 	return pi->rss_size; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int get_rss_table(struct net_device *dev, u32 *p) | static int get_rss_table(struct net_device *dev, u32 *p, u8 *key) | ||||||
| { | { | ||||||
| 	const struct port_info *pi = netdev_priv(dev); | 	const struct port_info *pi = netdev_priv(dev); | ||||||
| 	unsigned int n = pi->rss_size; | 	unsigned int n = pi->rss_size; | ||||||
|  | @ -2749,7 +2749,7 @@ static int get_rss_table(struct net_device *dev, u32 *p) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int set_rss_table(struct net_device *dev, const u32 *p) | static int set_rss_table(struct net_device *dev, const u32 *p, const u8 *key) | ||||||
| { | { | ||||||
| 	unsigned int i; | 	unsigned int i; | ||||||
| 	struct port_info *pi = netdev_priv(dev); | 	struct port_info *pi = netdev_priv(dev); | ||||||
|  | @ -2851,8 +2851,8 @@ static const struct ethtool_ops cxgb_ethtool_ops = { | ||||||
| 	.set_wol           = set_wol, | 	.set_wol           = set_wol, | ||||||
| 	.get_rxnfc         = get_rxnfc, | 	.get_rxnfc         = get_rxnfc, | ||||||
| 	.get_rxfh_indir_size = get_rss_table_size, | 	.get_rxfh_indir_size = get_rss_table_size, | ||||||
| 	.get_rxfh_indir    = get_rss_table, | 	.get_rxfh	   = get_rss_table, | ||||||
| 	.set_rxfh_indir    = set_rss_table, | 	.set_rxfh	   = set_rss_table, | ||||||
| 	.flash_device      = set_flash, | 	.flash_device      = set_flash, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2065,7 +2065,7 @@ int be_cmd_reset_function(struct be_adapter *adapter) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, | int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, | ||||||
| 		      u32 rss_hash_opts, u16 table_size, u8 *rss_hkey) | 		      u32 rss_hash_opts, u16 table_size, const u8 *rss_hkey) | ||||||
| { | { | ||||||
| 	struct be_mcc_wrb *wrb; | 	struct be_mcc_wrb *wrb; | ||||||
| 	struct be_cmd_req_rss_config *req; | 	struct be_cmd_req_rss_config *req; | ||||||
|  |  | ||||||
|  | @ -2082,7 +2082,7 @@ int be_cmd_query_fw_cfg(struct be_adapter *adapter, u32 *port_num, | ||||||
| 			u32 *function_mode, u32 *function_caps, u16 *asic_rev); | 			u32 *function_mode, u32 *function_caps, u16 *asic_rev); | ||||||
| int be_cmd_reset_function(struct be_adapter *adapter); | int be_cmd_reset_function(struct be_adapter *adapter); | ||||||
| int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, | int be_cmd_rss_config(struct be_adapter *adapter, u8 *rsstable, | ||||||
| 		      u32 rss_hash_opts, u16 table_size, u8 *rss_hkey); | 		      u32 rss_hash_opts, u16 table_size, const u8 *rss_hkey); | ||||||
| int be_process_mcc(struct be_adapter *adapter); | int be_process_mcc(struct be_adapter *adapter); | ||||||
| int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num, u8 beacon, | int be_cmd_set_beacon_state(struct be_adapter *adapter, u8 port_num, u8 beacon, | ||||||
| 			    u8 status, u8 state); | 			    u8 status, u8 state); | ||||||
|  |  | ||||||
|  | @ -1117,7 +1117,8 @@ static int be_get_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int be_set_rxfh(struct net_device *netdev, u32 *indir, u8 *hkey) | static int be_set_rxfh(struct net_device *netdev, const u32 *indir, | ||||||
|  | 		       const u8 *hkey) | ||||||
| { | { | ||||||
| 	int rc = 0, i, j; | 	int rc = 0, i, j; | ||||||
| 	struct be_adapter *adapter = netdev_priv(netdev); | 	struct be_adapter *adapter = netdev_priv(netdev); | ||||||
|  |  | ||||||
|  | @ -624,13 +624,14 @@ static u32 i40evf_get_rxfh_indir_size(struct net_device *netdev) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * i40evf_get_rxfh_indir - get the rx flow hash indirection table |  * i40evf_get_rxfh - get the rx flow hash indirection table | ||||||
|  * @netdev: network interface device structure |  * @netdev: network interface device structure | ||||||
|  * @indir: indirection table |  * @indir: indirection table | ||||||
|  |  * @key: hash key (will be %NULL until get_rxfh_key_size is implemented) | ||||||
|  * |  * | ||||||
|  * Reads the indirection table directly from the hardware. Always returns 0. |  * Reads the indirection table directly from the hardware. Always returns 0. | ||||||
|  **/ |  **/ | ||||||
| static int i40evf_get_rxfh_indir(struct net_device *netdev, u32 *indir) | static int i40evf_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key) | ||||||
| { | { | ||||||
| 	struct i40evf_adapter *adapter = netdev_priv(netdev); | 	struct i40evf_adapter *adapter = netdev_priv(netdev); | ||||||
| 	struct i40e_hw *hw = &adapter->hw; | 	struct i40e_hw *hw = &adapter->hw; | ||||||
|  | @ -648,14 +649,16 @@ static int i40evf_get_rxfh_indir(struct net_device *netdev, u32 *indir) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * i40evf_set_rxfh_indir - set the rx flow hash indirection table |  * i40evf_set_rxfh - set the rx flow hash indirection table | ||||||
|  * @netdev: network interface device structure |  * @netdev: network interface device structure | ||||||
|  * @indir: indirection table |  * @indir: indirection table | ||||||
|  |  * @key: hash key (will be %NULL until get_rxfh_key_size is implemented) | ||||||
|  * |  * | ||||||
|  * Returns -EINVAL if the table specifies an inavlid queue id, otherwise |  * Returns -EINVAL if the table specifies an inavlid queue id, otherwise | ||||||
|  * returns 0 after programming the table. |  * returns 0 after programming the table. | ||||||
|  **/ |  **/ | ||||||
| static int i40evf_set_rxfh_indir(struct net_device *netdev, const u32 *indir) | static int i40evf_set_rxfh(struct net_device *netdev, const u32 *indir, | ||||||
|  | 			   const u8 *key) | ||||||
| { | { | ||||||
| 	struct i40evf_adapter *adapter = netdev_priv(netdev); | 	struct i40evf_adapter *adapter = netdev_priv(netdev); | ||||||
| 	struct i40e_hw *hw = &adapter->hw; | 	struct i40e_hw *hw = &adapter->hw; | ||||||
|  | @ -689,8 +692,8 @@ static const struct ethtool_ops i40evf_ethtool_ops = { | ||||||
| 	.get_rxnfc		= i40evf_get_rxnfc, | 	.get_rxnfc		= i40evf_get_rxnfc, | ||||||
| 	.set_rxnfc		= i40evf_set_rxnfc, | 	.set_rxnfc		= i40evf_set_rxnfc, | ||||||
| 	.get_rxfh_indir_size	= i40evf_get_rxfh_indir_size, | 	.get_rxfh_indir_size	= i40evf_get_rxfh_indir_size, | ||||||
| 	.get_rxfh_indir		= i40evf_get_rxfh_indir, | 	.get_rxfh		= i40evf_get_rxfh, | ||||||
| 	.set_rxfh_indir		= i40evf_set_rxfh_indir, | 	.set_rxfh		= i40evf_set_rxfh, | ||||||
| 	.get_channels		= i40evf_get_channels, | 	.get_channels		= i40evf_get_channels, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -2830,7 +2830,7 @@ static u32 igb_get_rxfh_indir_size(struct net_device *netdev) | ||||||
| 	return IGB_RETA_SIZE; | 	return IGB_RETA_SIZE; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int igb_get_rxfh_indir(struct net_device *netdev, u32 *indir) | static int igb_get_rxfh(struct net_device *netdev, u32 *indir, u8 *key) | ||||||
| { | { | ||||||
| 	struct igb_adapter *adapter = netdev_priv(netdev); | 	struct igb_adapter *adapter = netdev_priv(netdev); | ||||||
| 	int i; | 	int i; | ||||||
|  | @ -2876,7 +2876,8 @@ void igb_write_rss_indir_tbl(struct igb_adapter *adapter) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int igb_set_rxfh_indir(struct net_device *netdev, const u32 *indir) | static int igb_set_rxfh(struct net_device *netdev, const u32 *indir, | ||||||
|  | 			const u8 *key) | ||||||
| { | { | ||||||
| 	struct igb_adapter *adapter = netdev_priv(netdev); | 	struct igb_adapter *adapter = netdev_priv(netdev); | ||||||
| 	struct e1000_hw *hw = &adapter->hw; | 	struct e1000_hw *hw = &adapter->hw; | ||||||
|  | @ -3025,8 +3026,8 @@ static const struct ethtool_ops igb_ethtool_ops = { | ||||||
| 	.get_module_info	= igb_get_module_info, | 	.get_module_info	= igb_get_module_info, | ||||||
| 	.get_module_eeprom	= igb_get_module_eeprom, | 	.get_module_eeprom	= igb_get_module_eeprom, | ||||||
| 	.get_rxfh_indir_size	= igb_get_rxfh_indir_size, | 	.get_rxfh_indir_size	= igb_get_rxfh_indir_size, | ||||||
| 	.get_rxfh_indir		= igb_get_rxfh_indir, | 	.get_rxfh		= igb_get_rxfh, | ||||||
| 	.set_rxfh_indir		= igb_set_rxfh_indir, | 	.set_rxfh		= igb_set_rxfh, | ||||||
| 	.get_channels		= igb_get_channels, | 	.get_channels		= igb_get_channels, | ||||||
| 	.set_channels		= igb_set_channels, | 	.set_channels		= igb_set_channels, | ||||||
| 	.begin			= igb_ethtool_begin, | 	.begin			= igb_ethtool_begin, | ||||||
|  |  | ||||||
|  | @ -564,7 +564,7 @@ static u32 mlx4_en_get_rxfh_indir_size(struct net_device *dev) | ||||||
| 	return priv->rx_ring_num; | 	return priv->rx_ring_num; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int mlx4_en_get_rxfh_indir(struct net_device *dev, u32 *ring_index) | static int mlx4_en_get_rxfh(struct net_device *dev, u32 *ring_index, u8 *key) | ||||||
| { | { | ||||||
| 	struct mlx4_en_priv *priv = netdev_priv(dev); | 	struct mlx4_en_priv *priv = netdev_priv(dev); | ||||||
| 	struct mlx4_en_rss_map *rss_map = &priv->rss_map; | 	struct mlx4_en_rss_map *rss_map = &priv->rss_map; | ||||||
|  | @ -582,8 +582,8 @@ static int mlx4_en_get_rxfh_indir(struct net_device *dev, u32 *ring_index) | ||||||
| 	return err; | 	return err; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int mlx4_en_set_rxfh_indir(struct net_device *dev, | static int mlx4_en_set_rxfh(struct net_device *dev, const u32 *ring_index, | ||||||
| 		const u32 *ring_index) | 			    const u8 *key) | ||||||
| { | { | ||||||
| 	struct mlx4_en_priv *priv = netdev_priv(dev); | 	struct mlx4_en_priv *priv = netdev_priv(dev); | ||||||
| 	struct mlx4_en_dev *mdev = priv->mdev; | 	struct mlx4_en_dev *mdev = priv->mdev; | ||||||
|  | @ -1224,8 +1224,8 @@ const struct ethtool_ops mlx4_en_ethtool_ops = { | ||||||
| 	.get_rxnfc = mlx4_en_get_rxnfc, | 	.get_rxnfc = mlx4_en_get_rxnfc, | ||||||
| 	.set_rxnfc = mlx4_en_set_rxnfc, | 	.set_rxnfc = mlx4_en_set_rxnfc, | ||||||
| 	.get_rxfh_indir_size = mlx4_en_get_rxfh_indir_size, | 	.get_rxfh_indir_size = mlx4_en_get_rxfh_indir_size, | ||||||
| 	.get_rxfh_indir = mlx4_en_get_rxfh_indir, | 	.get_rxfh = mlx4_en_get_rxfh, | ||||||
| 	.set_rxfh_indir = mlx4_en_set_rxfh_indir, | 	.set_rxfh = mlx4_en_set_rxfh, | ||||||
| 	.get_channels = mlx4_en_get_channels, | 	.get_channels = mlx4_en_get_channels, | ||||||
| 	.set_channels = mlx4_en_set_channels, | 	.set_channels = mlx4_en_set_channels, | ||||||
| 	.get_ts_info = mlx4_en_get_ts_info, | 	.get_ts_info = mlx4_en_get_ts_info, | ||||||
|  |  | ||||||
|  | @ -1033,7 +1033,7 @@ static u32 efx_ethtool_get_rxfh_indir_size(struct net_device *net_dev) | ||||||
| 		0 : ARRAY_SIZE(efx->rx_indir_table)); | 		0 : ARRAY_SIZE(efx->rx_indir_table)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, u32 *indir) | static int efx_ethtool_get_rxfh(struct net_device *net_dev, u32 *indir, u8 *key) | ||||||
| { | { | ||||||
| 	struct efx_nic *efx = netdev_priv(net_dev); | 	struct efx_nic *efx = netdev_priv(net_dev); | ||||||
| 
 | 
 | ||||||
|  | @ -1041,8 +1041,8 @@ static int efx_ethtool_get_rxfh_indir(struct net_device *net_dev, u32 *indir) | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int efx_ethtool_set_rxfh_indir(struct net_device *net_dev, | static int efx_ethtool_set_rxfh(struct net_device *net_dev, | ||||||
| 				      const u32 *indir) | 				const u32 *indir, const u8 *key) | ||||||
| { | { | ||||||
| 	struct efx_nic *efx = netdev_priv(net_dev); | 	struct efx_nic *efx = netdev_priv(net_dev); | ||||||
| 
 | 
 | ||||||
|  | @ -1125,8 +1125,8 @@ const struct ethtool_ops efx_ethtool_ops = { | ||||||
| 	.get_rxnfc		= efx_ethtool_get_rxnfc, | 	.get_rxnfc		= efx_ethtool_get_rxnfc, | ||||||
| 	.set_rxnfc		= efx_ethtool_set_rxnfc, | 	.set_rxnfc		= efx_ethtool_set_rxnfc, | ||||||
| 	.get_rxfh_indir_size	= efx_ethtool_get_rxfh_indir_size, | 	.get_rxfh_indir_size	= efx_ethtool_get_rxfh_indir_size, | ||||||
| 	.get_rxfh_indir		= efx_ethtool_get_rxfh_indir, | 	.get_rxfh		= efx_ethtool_get_rxfh, | ||||||
| 	.set_rxfh_indir		= efx_ethtool_set_rxfh_indir, | 	.set_rxfh		= efx_ethtool_set_rxfh, | ||||||
| 	.get_ts_info		= efx_ethtool_get_ts_info, | 	.get_ts_info		= efx_ethtool_get_ts_info, | ||||||
| 	.get_module_info	= efx_ethtool_get_module_info, | 	.get_module_info	= efx_ethtool_get_module_info, | ||||||
| 	.get_module_eeprom	= efx_ethtool_get_module_eeprom, | 	.get_module_eeprom	= efx_ethtool_get_module_eeprom, | ||||||
|  |  | ||||||
|  | @ -579,7 +579,7 @@ vmxnet3_get_rss_indir_size(struct net_device *netdev) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| vmxnet3_get_rss_indir(struct net_device *netdev, u32 *p) | vmxnet3_get_rss(struct net_device *netdev, u32 *p, u8 *key) | ||||||
| { | { | ||||||
| 	struct vmxnet3_adapter *adapter = netdev_priv(netdev); | 	struct vmxnet3_adapter *adapter = netdev_priv(netdev); | ||||||
| 	struct UPT1_RSSConf *rssConf = adapter->rss_conf; | 	struct UPT1_RSSConf *rssConf = adapter->rss_conf; | ||||||
|  | @ -592,7 +592,7 @@ vmxnet3_get_rss_indir(struct net_device *netdev, u32 *p) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int | static int | ||||||
| vmxnet3_set_rss_indir(struct net_device *netdev, const u32 *p) | vmxnet3_set_rss(struct net_device *netdev, const u32 *p, const u8 *key) | ||||||
| { | { | ||||||
| 	unsigned int i; | 	unsigned int i; | ||||||
| 	unsigned long flags; | 	unsigned long flags; | ||||||
|  | @ -628,8 +628,8 @@ static const struct ethtool_ops vmxnet3_ethtool_ops = { | ||||||
| 	.get_rxnfc         = vmxnet3_get_rxnfc, | 	.get_rxnfc         = vmxnet3_get_rxnfc, | ||||||
| #ifdef VMXNET3_RSS | #ifdef VMXNET3_RSS | ||||||
| 	.get_rxfh_indir_size = vmxnet3_get_rss_indir_size, | 	.get_rxfh_indir_size = vmxnet3_get_rss_indir_size, | ||||||
| 	.get_rxfh_indir    = vmxnet3_get_rss_indir, | 	.get_rxfh          = vmxnet3_get_rss, | ||||||
| 	.set_rxfh_indir    = vmxnet3_set_rss_indir, | 	.set_rxfh          = vmxnet3_set_rss, | ||||||
| #endif | #endif | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -158,19 +158,16 @@ static inline u32 ethtool_rxfh_indir_default(u32 index, u32 n_rx_rings) | ||||||
|  *	Returns zero if not supported for this specific device. |  *	Returns zero if not supported for this specific device. | ||||||
|  * @get_rxfh_indir_size: Get the size of the RX flow hash indirection table. |  * @get_rxfh_indir_size: Get the size of the RX flow hash indirection table. | ||||||
|  *	Returns zero if not supported for this specific device. |  *	Returns zero if not supported for this specific device. | ||||||
|  * @get_rxfh_indir: Get the contents of the RX flow hash indirection table. |  | ||||||
|  *	Will not be called if @get_rxfh_indir_size returns zero. |  | ||||||
|  * @get_rxfh: Get the contents of the RX flow hash indirection table and hash |  * @get_rxfh: Get the contents of the RX flow hash indirection table and hash | ||||||
|  *	key. |  *	key. | ||||||
|  *	Will not be called if @get_rxfh_indir_size and @get_rxfh_key_size |  *	Will only be called if one or both of @get_rxfh_indir_size and | ||||||
|  *	returns zero. |  *	@get_rxfh_key_size are implemented and return non-zero. | ||||||
|  *	Returns a negative error code or zero. |  *	Returns a negative error code or zero. | ||||||
|  * @set_rxfh_indir: Set the contents of the RX flow hash indirection table. |  * @set_rxfh: Set the contents of the RX flow hash indirection table and/or | ||||||
|  *	Will not be called if @get_rxfh_indir_size returns zero. |  *	hash key.  In case only the indirection table or hash key is to be | ||||||
|  * @set_rxfh: Set the contents of the RX flow hash indirection table and |  *	changed, the other argument will be %NULL. | ||||||
|  *	hash key. |  *	Will only be called if one or both of @get_rxfh_indir_size and | ||||||
|  *	Will not be called if @get_rxfh_indir_size and @get_rxfh_key_size |  *	@get_rxfh_key_size are implemented and return non-zero. | ||||||
|  *	returns zero. |  | ||||||
|  *	Returns a negative error code or zero. |  *	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 | ||||||
|  | @ -244,10 +241,9 @@ struct ethtool_ops { | ||||||
| 	int	(*reset)(struct net_device *, u32 *); | 	int	(*reset)(struct net_device *, u32 *); | ||||||
| 	u32	(*get_rxfh_key_size)(struct net_device *); | 	u32	(*get_rxfh_key_size)(struct net_device *); | ||||||
| 	u32	(*get_rxfh_indir_size)(struct net_device *); | 	u32	(*get_rxfh_indir_size)(struct net_device *); | ||||||
| 	int	(*get_rxfh)(struct net_device *, u32 *, u8 *); | 	int	(*get_rxfh)(struct net_device *, u32 *indir, u8 *key); | ||||||
| 	int	(*set_rxfh)(struct net_device *, u32 *, u8 *); | 	int	(*set_rxfh)(struct net_device *, const u32 *indir, | ||||||
| 	int	(*get_rxfh_indir)(struct net_device *, u32 *); | 			    const u8 *key); | ||||||
| 	int	(*set_rxfh_indir)(struct net_device *, const u32 *); |  | ||||||
| 	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 *); | ||||||
|  |  | ||||||
|  | @ -850,21 +850,23 @@ struct ethtool_rxfh_indir { | ||||||
|  * struct ethtool_rxfh - command to get/set RX flow hash indir or/and hash key. |  * struct ethtool_rxfh - command to get/set RX flow hash indir or/and hash key. | ||||||
|  * @cmd: Specific command number - %ETHTOOL_GRSSH or %ETHTOOL_SRSSH |  * @cmd: Specific command number - %ETHTOOL_GRSSH or %ETHTOOL_SRSSH | ||||||
|  * @rss_context: RSS context identifier. |  * @rss_context: RSS context identifier. | ||||||
|  * @indir_size: On entry, the array size of the user buffer, which may be zero. |  * @indir_size: On entry, the array size of the user buffer for the | ||||||
|  *		On return from %ETHTOOL_GRSSH, the array size of the hardware |  *	indirection table, which may be zero, or (for %ETHTOOL_SRSSH), | ||||||
|  *		indirection table. |  *	%ETH_RXFH_INDIR_NO_CHANGE.  On return from %ETHTOOL_GRSSH, | ||||||
|  * @key_size:	On entry, the array size of the user buffer in bytes, |  *	the array size of the hardware indirection table. | ||||||
|  *		which may be zero. |  * @key_size: On entry, the array size of the user buffer for the hash key, | ||||||
|  *		On return from %ETHTOOL_GRSSH, the size of the RSS hash key. |  *	which may be zero.  On return from %ETHTOOL_GRSSH, the size of the | ||||||
|  |  *	hardware hash key. | ||||||
|  * @rsvd:	Reserved for future extensions. |  * @rsvd:	Reserved for future extensions. | ||||||
|  * @rss_config: RX ring/queue index for each hash value i.e., indirection table |  * @rss_config: RX ring/queue index for each hash value i.e., indirection table | ||||||
|  *		of size @indir_size followed by hash key of size @key_size. |  *	of @indir_size __u32 elements, followed by hash key of @key_size | ||||||
|  |  *	bytes. | ||||||
|  * |  * | ||||||
|  * For %ETHTOOL_GRSSH, a @indir_size and key_size of zero means that only the |  * For %ETHTOOL_GRSSH, a @indir_size and key_size of zero means that only the | ||||||
|  * size should be returned.  For %ETHTOOL_SRSSH, a @indir_size of 0xDEADBEEF |  * size should be returned.  For %ETHTOOL_SRSSH, an @indir_size of | ||||||
|  * means that indir table setting is not requested and a @indir_size of zero |  * %ETH_RXFH_INDIR_NO_CHANGE means that indir table setting is not requested | ||||||
|  * means the indir table should be reset to default values.  This last feature |  * and a @indir_size of zero means the indir table should be reset to default | ||||||
|  * is not supported by the original implementations. |  * values. | ||||||
|  */ |  */ | ||||||
| struct ethtool_rxfh { | struct ethtool_rxfh { | ||||||
| 	__u32   cmd; | 	__u32   cmd; | ||||||
|  | @ -874,6 +876,7 @@ struct ethtool_rxfh { | ||||||
| 	__u32	rsvd[2]; | 	__u32	rsvd[2]; | ||||||
| 	__u32   rss_config[0]; | 	__u32   rss_config[0]; | ||||||
| }; | }; | ||||||
|  | #define ETH_RXFH_INDIR_NO_CHANGE	0xffffffff | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * struct ethtool_rx_ntuple_flow_spec - specification for RX flow filter |  * struct ethtool_rx_ntuple_flow_spec - specification for RX flow filter | ||||||
|  |  | ||||||
|  | @ -561,19 +561,17 @@ static int ethtool_copy_validate_indir(u32 *indir, void __user *useraddr, | ||||||
| 					struct ethtool_rxnfc *rx_rings, | 					struct ethtool_rxnfc *rx_rings, | ||||||
| 					u32 size) | 					u32 size) | ||||||
| { | { | ||||||
| 	int ret = 0, i; | 	int i; | ||||||
| 
 | 
 | ||||||
| 	if (copy_from_user(indir, useraddr, size * sizeof(indir[0]))) | 	if (copy_from_user(indir, useraddr, size * sizeof(indir[0]))) | ||||||
| 		ret = -EFAULT; | 		return -EFAULT; | ||||||
| 
 | 
 | ||||||
| 	/* Validate ring indices */ | 	/* Validate ring indices */ | ||||||
| 	for (i = 0; i < size; i++) { | 	for (i = 0; i < size; i++) | ||||||
| 		if (indir[i] >= rx_rings->data) { | 		if (indir[i] >= rx_rings->data) | ||||||
| 			ret = -EINVAL; | 			return -EINVAL; | ||||||
| 			break; | 
 | ||||||
| 		} | 	return 0; | ||||||
| 	} |  | ||||||
| 	return ret; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, | static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, | ||||||
|  | @ -584,7 +582,7 @@ static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, | ||||||
| 	int ret; | 	int ret; | ||||||
| 
 | 
 | ||||||
| 	if (!dev->ethtool_ops->get_rxfh_indir_size || | 	if (!dev->ethtool_ops->get_rxfh_indir_size || | ||||||
| 	    !dev->ethtool_ops->get_rxfh_indir) | 	    !dev->ethtool_ops->get_rxfh) | ||||||
| 		return -EOPNOTSUPP; | 		return -EOPNOTSUPP; | ||||||
| 	dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev); | 	dev_size = dev->ethtool_ops->get_rxfh_indir_size(dev); | ||||||
| 	if (dev_size == 0) | 	if (dev_size == 0) | ||||||
|  | @ -610,7 +608,7 @@ static noinline_for_stack int ethtool_get_rxfh_indir(struct net_device *dev, | ||||||
| 	if (!indir) | 	if (!indir) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
| 	ret = dev->ethtool_ops->get_rxfh_indir(dev, indir); | 	ret = dev->ethtool_ops->get_rxfh(dev, indir, NULL); | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
|  | @ -634,7 +632,7 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev, | ||||||
| 	int ret; | 	int ret; | ||||||
| 	u32 ringidx_offset = offsetof(struct ethtool_rxfh_indir, ring_index[0]); | 	u32 ringidx_offset = offsetof(struct ethtool_rxfh_indir, ring_index[0]); | ||||||
| 
 | 
 | ||||||
| 	if (!ops->get_rxfh_indir_size || !ops->set_rxfh_indir || | 	if (!ops->get_rxfh_indir_size || !ops->set_rxfh || | ||||||
| 	    !ops->get_rxnfc) | 	    !ops->get_rxnfc) | ||||||
| 		return -EOPNOTSUPP; | 		return -EOPNOTSUPP; | ||||||
| 
 | 
 | ||||||
|  | @ -671,7 +669,7 @@ static noinline_for_stack int ethtool_set_rxfh_indir(struct net_device *dev, | ||||||
| 			goto out; | 			goto out; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	ret = ops->set_rxfh_indir(dev, indir); | 	ret = ops->set_rxfh(dev, indir, NULL); | ||||||
| 
 | 
 | ||||||
| out: | out: | ||||||
| 	kfree(indir); | 	kfree(indir); | ||||||
|  | @ -683,11 +681,11 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev, | ||||||
| { | { | ||||||
| 	int ret; | 	int ret; | ||||||
| 	const struct ethtool_ops *ops = dev->ethtool_ops; | 	const struct ethtool_ops *ops = dev->ethtool_ops; | ||||||
| 	u32 user_indir_size = 0, user_key_size = 0; | 	u32 user_indir_size, user_key_size; | ||||||
| 	u32 dev_indir_size = 0, dev_key_size = 0; | 	u32 dev_indir_size = 0, dev_key_size = 0; | ||||||
|  | 	struct ethtool_rxfh rxfh; | ||||||
| 	u32 total_size; | 	u32 total_size; | ||||||
| 	u32 indir_offset, indir_bytes; | 	u32 indir_bytes; | ||||||
| 	u32 key_offset; |  | ||||||
| 	u32 *indir = NULL; | 	u32 *indir = NULL; | ||||||
| 	u8 *hkey = NULL; | 	u8 *hkey = NULL; | ||||||
| 	u8 *rss_config; | 	u8 *rss_config; | ||||||
|  | @ -699,33 +697,24 @@ static noinline_for_stack int ethtool_get_rxfh(struct net_device *dev, | ||||||
| 
 | 
 | ||||||
| 	if (ops->get_rxfh_indir_size) | 	if (ops->get_rxfh_indir_size) | ||||||
| 		dev_indir_size = ops->get_rxfh_indir_size(dev); | 		dev_indir_size = ops->get_rxfh_indir_size(dev); | ||||||
| 
 |  | ||||||
| 	indir_offset = offsetof(struct ethtool_rxfh, indir_size); |  | ||||||
| 
 |  | ||||||
| 	if (copy_from_user(&user_indir_size, |  | ||||||
| 			   useraddr + indir_offset, |  | ||||||
| 			   sizeof(user_indir_size))) |  | ||||||
| 		return -EFAULT; |  | ||||||
| 
 |  | ||||||
| 	if (copy_to_user(useraddr + indir_offset, |  | ||||||
| 			 &dev_indir_size, sizeof(dev_indir_size))) |  | ||||||
| 		return -EFAULT; |  | ||||||
| 
 |  | ||||||
| 	if (ops->get_rxfh_key_size) | 	if (ops->get_rxfh_key_size) | ||||||
| 		dev_key_size = ops->get_rxfh_key_size(dev); | 		dev_key_size = ops->get_rxfh_key_size(dev); | ||||||
| 
 | 
 | ||||||
| 	if ((dev_key_size + dev_indir_size) == 0) | 	if ((dev_key_size + dev_indir_size) == 0) | ||||||
| 		return -EOPNOTSUPP; | 		return -EOPNOTSUPP; | ||||||
| 
 | 
 | ||||||
| 	key_offset = offsetof(struct ethtool_rxfh, key_size); | 	if (copy_from_user(&rxfh, useraddr, sizeof(rxfh))) | ||||||
| 
 |  | ||||||
| 	if (copy_from_user(&user_key_size, |  | ||||||
| 			   useraddr + key_offset, |  | ||||||
| 			   sizeof(user_key_size))) |  | ||||||
| 		return -EFAULT; | 		return -EFAULT; | ||||||
|  | 	user_indir_size = rxfh.indir_size; | ||||||
|  | 	user_key_size = rxfh.key_size; | ||||||
| 
 | 
 | ||||||
| 	if (copy_to_user(useraddr + key_offset, | 	/* Check that reserved fields are 0 for now */ | ||||||
| 			 &dev_key_size, sizeof(dev_key_size))) | 	if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1]) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	rxfh.indir_size = dev_indir_size; | ||||||
|  | 	rxfh.key_size = dev_key_size; | ||||||
|  | 	if (copy_to_user(useraddr, &rxfh, sizeof(rxfh))) | ||||||
| 		return -EFAULT; | 		return -EFAULT; | ||||||
| 
 | 
 | ||||||
| 	/* If the user buffer size is 0, this is just a query for the
 | 	/* If the user buffer size is 0, this is just a query for the
 | ||||||
|  | @ -770,12 +759,11 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, | ||||||
| 	int ret; | 	int ret; | ||||||
| 	const struct ethtool_ops *ops = dev->ethtool_ops; | 	const struct ethtool_ops *ops = dev->ethtool_ops; | ||||||
| 	struct ethtool_rxnfc rx_rings; | 	struct ethtool_rxnfc rx_rings; | ||||||
| 	u32 user_indir_size = 0, dev_indir_size = 0, i; | 	struct ethtool_rxfh rxfh; | ||||||
| 	u32 user_key_size = 0, dev_key_size = 0; | 	u32 dev_indir_size = 0, dev_key_size = 0, i; | ||||||
| 	u32 *indir = NULL, indir_bytes = 0; | 	u32 *indir = NULL, indir_bytes = 0; | ||||||
| 	u8 *hkey = NULL; | 	u8 *hkey = NULL; | ||||||
| 	u8 *rss_config; | 	u8 *rss_config; | ||||||
| 	u32 indir_offset, key_offset; |  | ||||||
| 	u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]); | 	u32 rss_cfg_offset = offsetof(struct ethtool_rxfh, rss_config[0]); | ||||||
| 
 | 
 | ||||||
| 	if (!(ops->get_rxfh_indir_size || ops->get_rxfh_key_size) || | 	if (!(ops->get_rxfh_indir_size || ops->get_rxfh_key_size) || | ||||||
|  | @ -784,36 +772,33 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, | ||||||
| 
 | 
 | ||||||
| 	if (ops->get_rxfh_indir_size) | 	if (ops->get_rxfh_indir_size) | ||||||
| 		dev_indir_size = ops->get_rxfh_indir_size(dev); | 		dev_indir_size = ops->get_rxfh_indir_size(dev); | ||||||
| 
 |  | ||||||
| 	indir_offset = offsetof(struct ethtool_rxfh, indir_size); |  | ||||||
| 	if (copy_from_user(&user_indir_size, |  | ||||||
| 			   useraddr + indir_offset, |  | ||||||
| 			   sizeof(user_indir_size))) |  | ||||||
| 		return -EFAULT; |  | ||||||
| 
 |  | ||||||
| 	if (ops->get_rxfh_key_size) | 	if (ops->get_rxfh_key_size) | ||||||
| 		dev_key_size = dev->ethtool_ops->get_rxfh_key_size(dev); | 		dev_key_size = dev->ethtool_ops->get_rxfh_key_size(dev); | ||||||
| 
 |  | ||||||
| 	if ((dev_key_size + dev_indir_size) == 0) | 	if ((dev_key_size + dev_indir_size) == 0) | ||||||
| 		return -EOPNOTSUPP; | 		return -EOPNOTSUPP; | ||||||
| 
 | 
 | ||||||
| 	key_offset = offsetof(struct ethtool_rxfh, key_size); | 	if (copy_from_user(&rxfh, useraddr, sizeof(rxfh))) | ||||||
| 	if (copy_from_user(&user_key_size, |  | ||||||
| 			   useraddr + key_offset, |  | ||||||
| 			   sizeof(user_key_size))) |  | ||||||
| 		return -EFAULT; | 		return -EFAULT; | ||||||
| 
 | 
 | ||||||
| 	/* If either indir or hash key is valid, proceed further.
 | 	/* Check that reserved fields are 0 for now */ | ||||||
| 	 */ | 	if (rxfh.rss_context || rxfh.rsvd[0] || rxfh.rsvd[1]) | ||||||
| 	if ((user_indir_size && ((user_indir_size != 0xDEADBEEF) && |  | ||||||
| 				 user_indir_size != dev_indir_size)) || |  | ||||||
| 	    (user_key_size && (user_key_size != dev_key_size))) |  | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
| 	if (user_indir_size != 0xDEADBEEF) | 	/* If either indir or hash key is valid, proceed further.
 | ||||||
|  | 	 * It is not valid to request that both be unchanged. | ||||||
|  | 	 */ | ||||||
|  | 	if ((rxfh.indir_size && | ||||||
|  | 	     rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE && | ||||||
|  | 	     rxfh.indir_size != dev_indir_size) || | ||||||
|  | 	    (rxfh.key_size && (rxfh.key_size != dev_key_size)) || | ||||||
|  | 	    (rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE && | ||||||
|  | 	     rxfh.key_size == 0)) | ||||||
|  | 		return -EINVAL; | ||||||
|  | 
 | ||||||
|  | 	if (rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) | ||||||
| 		indir_bytes = dev_indir_size * sizeof(indir[0]); | 		indir_bytes = dev_indir_size * sizeof(indir[0]); | ||||||
| 
 | 
 | ||||||
| 	rss_config = kzalloc(indir_bytes + user_key_size, GFP_USER); | 	rss_config = kzalloc(indir_bytes + rxfh.key_size, GFP_USER); | ||||||
| 	if (!rss_config) | 	if (!rss_config) | ||||||
| 		return -ENOMEM; | 		return -ENOMEM; | ||||||
| 
 | 
 | ||||||
|  | @ -822,28 +807,29 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev, | ||||||
| 	if (ret) | 	if (ret) | ||||||
| 		goto out; | 		goto out; | ||||||
| 
 | 
 | ||||||
| 	/* user_indir_size == 0 means reset the indir table to default.
 | 	/* rxfh.indir_size == 0 means reset the indir table to default.
 | ||||||
| 	 * user_indir_size == 0xDEADBEEF means indir setting is not requested. | 	 * rxfh.indir_size == ETH_RXFH_INDIR_NO_CHANGE means leave it unchanged. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (user_indir_size && user_indir_size != 0xDEADBEEF) { | 	if (rxfh.indir_size && | ||||||
|  | 	    rxfh.indir_size != ETH_RXFH_INDIR_NO_CHANGE) { | ||||||
| 		indir = (u32 *)rss_config; | 		indir = (u32 *)rss_config; | ||||||
| 		ret = ethtool_copy_validate_indir(indir, | 		ret = ethtool_copy_validate_indir(indir, | ||||||
| 						  useraddr + rss_cfg_offset, | 						  useraddr + rss_cfg_offset, | ||||||
| 						  &rx_rings, | 						  &rx_rings, | ||||||
| 						  user_indir_size); | 						  rxfh.indir_size); | ||||||
| 		if (ret) | 		if (ret) | ||||||
| 			goto out; | 			goto out; | ||||||
| 	} else if (user_indir_size == 0) { | 	} else if (rxfh.indir_size == 0) { | ||||||
| 		indir = (u32 *)rss_config; | 		indir = (u32 *)rss_config; | ||||||
| 		for (i = 0; i < dev_indir_size; i++) | 		for (i = 0; i < dev_indir_size; i++) | ||||||
| 			indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data); | 			indir[i] = ethtool_rxfh_indir_default(i, rx_rings.data); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (user_key_size) { | 	if (rxfh.key_size) { | ||||||
| 		hkey = rss_config + indir_bytes; | 		hkey = rss_config + indir_bytes; | ||||||
| 		if (copy_from_user(hkey, | 		if (copy_from_user(hkey, | ||||||
| 				   useraddr + rss_cfg_offset + indir_bytes, | 				   useraddr + rss_cfg_offset + indir_bytes, | ||||||
| 				   user_key_size)) { | 				   rxfh.key_size)) { | ||||||
| 			ret = -EFAULT; | 			ret = -EFAULT; | ||||||
| 			goto out; | 			goto out; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 David S. Miller
				David S. Miller