net: Implement SFEATURES compatibility for not updated drivers
Use discrete setting ops for not updated drivers. This will not make them conform to full G/SFEATURES semantics, though. Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
		
					parent
					
						
							
								4e4db20054
							
						
					
				
			
			
				commit
				
					
						39fc0ce571
					
				
			
		
					 2 changed files with 66 additions and 0 deletions
				
			
		|  | @ -591,6 +591,9 @@ struct ethtool_sfeatures { | |||
|  *      Probably there are other device-specific constraints on some features | ||||
|  *      in the set. When %ETHTOOL_F_UNSUPPORTED is set, .valid is considered | ||||
|  *      here as though ignored bits were cleared. | ||||
|  *   %ETHTOOL_F_COMPAT - some or all changes requested were made by calling | ||||
|  *      compatibility functions. Requested offload state cannot be properly | ||||
|  *      managed by kernel. | ||||
|  * | ||||
|  * Meaning of bits in the masks are obtained by %ETHTOOL_GSSET_INFO (number of | ||||
|  * bits in the arrays - always multiple of 32) and %ETHTOOL_GSTRINGS commands | ||||
|  | @ -600,10 +603,12 @@ struct ethtool_sfeatures { | |||
| enum ethtool_sfeatures_retval_bits { | ||||
| 	ETHTOOL_F_UNSUPPORTED__BIT, | ||||
| 	ETHTOOL_F_WISH__BIT, | ||||
| 	ETHTOOL_F_COMPAT__BIT, | ||||
| }; | ||||
| 
 | ||||
| #define ETHTOOL_F_UNSUPPORTED   (1 << ETHTOOL_F_UNSUPPORTED__BIT) | ||||
| #define ETHTOOL_F_WISH          (1 << ETHTOOL_F_WISH__BIT) | ||||
| #define ETHTOOL_F_COMPAT        (1 << ETHTOOL_F_COMPAT__BIT) | ||||
| 
 | ||||
| #ifdef __KERNEL__ | ||||
| 
 | ||||
|  |  | |||
|  | @ -178,6 +178,64 @@ static void ethtool_get_features_compat(struct net_device *dev, | |||
| 	if (dev->ethtool_ops->get_rx_csum) | ||||
| 		if (dev->ethtool_ops->get_rx_csum(dev)) | ||||
| 			features[0].active |= NETIF_F_RXCSUM; | ||||
| 
 | ||||
| 	/* mark legacy-changeable features */ | ||||
| 	if (dev->ethtool_ops->set_sg) | ||||
| 		features[0].available |= NETIF_F_SG; | ||||
| 	if (dev->ethtool_ops->set_tx_csum) | ||||
| 		features[0].available |= NETIF_F_ALL_CSUM; | ||||
| 	if (dev->ethtool_ops->set_tso) | ||||
| 		features[0].available |= NETIF_F_ALL_TSO; | ||||
| 	if (dev->ethtool_ops->set_rx_csum) | ||||
| 		features[0].available |= NETIF_F_RXCSUM; | ||||
| 	if (dev->ethtool_ops->set_flags) | ||||
| 		features[0].available |= flags_dup_features; | ||||
| } | ||||
| 
 | ||||
| static int ethtool_set_feature_compat(struct net_device *dev, | ||||
| 	int (*legacy_set)(struct net_device *, u32), | ||||
| 	struct ethtool_set_features_block *features, u32 mask) | ||||
| { | ||||
| 	u32 do_set; | ||||
| 
 | ||||
| 	if (!legacy_set) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	if (!(features[0].valid & mask)) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	features[0].valid &= ~mask; | ||||
| 
 | ||||
| 	do_set = !!(features[0].requested & mask); | ||||
| 
 | ||||
| 	if (legacy_set(dev, do_set) < 0) | ||||
| 		netdev_info(dev, | ||||
| 			"Legacy feature change (%s) failed for 0x%08x\n", | ||||
| 			do_set ? "set" : "clear", mask); | ||||
| 
 | ||||
| 	return 1; | ||||
| } | ||||
| 
 | ||||
| static int ethtool_set_features_compat(struct net_device *dev, | ||||
| 	struct ethtool_set_features_block *features) | ||||
| { | ||||
| 	int compat; | ||||
| 
 | ||||
| 	if (!dev->ethtool_ops) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	compat  = ethtool_set_feature_compat(dev, dev->ethtool_ops->set_sg, | ||||
| 		features, NETIF_F_SG); | ||||
| 	compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_tx_csum, | ||||
| 		features, NETIF_F_ALL_CSUM); | ||||
| 	compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_tso, | ||||
| 		features, NETIF_F_ALL_TSO); | ||||
| 	compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_rx_csum, | ||||
| 		features, NETIF_F_RXCSUM); | ||||
| 	compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_flags, | ||||
| 		features, flags_dup_features); | ||||
| 
 | ||||
| 	return compat; | ||||
| } | ||||
| 
 | ||||
| static int ethtool_get_features(struct net_device *dev, void __user *useraddr) | ||||
|  | @ -234,6 +292,9 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr) | |||
| 	if (features[0].valid & ~NETIF_F_ETHTOOL_BITS) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	if (ethtool_set_features_compat(dev, features)) | ||||
| 		ret |= ETHTOOL_F_COMPAT; | ||||
| 
 | ||||
| 	if (features[0].valid & ~dev->hw_features) { | ||||
| 		features[0].valid &= dev->hw_features; | ||||
| 		ret |= ETHTOOL_F_UNSUPPORTED; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Michał Mirosław
				Michał Mirosław