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 |  *      Probably there are other device-specific constraints on some features | ||||||
|  *      in the set. When %ETHTOOL_F_UNSUPPORTED is set, .valid is considered |  *      in the set. When %ETHTOOL_F_UNSUPPORTED is set, .valid is considered | ||||||
|  *      here as though ignored bits were cleared. |  *      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 |  * 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 |  * bits in the arrays - always multiple of 32) and %ETHTOOL_GSTRINGS commands | ||||||
|  | @ -600,10 +603,12 @@ struct ethtool_sfeatures { | ||||||
| enum ethtool_sfeatures_retval_bits { | enum ethtool_sfeatures_retval_bits { | ||||||
| 	ETHTOOL_F_UNSUPPORTED__BIT, | 	ETHTOOL_F_UNSUPPORTED__BIT, | ||||||
| 	ETHTOOL_F_WISH__BIT, | 	ETHTOOL_F_WISH__BIT, | ||||||
|  | 	ETHTOOL_F_COMPAT__BIT, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #define ETHTOOL_F_UNSUPPORTED   (1 << ETHTOOL_F_UNSUPPORTED__BIT) | #define ETHTOOL_F_UNSUPPORTED   (1 << ETHTOOL_F_UNSUPPORTED__BIT) | ||||||
| #define ETHTOOL_F_WISH          (1 << ETHTOOL_F_WISH__BIT) | #define ETHTOOL_F_WISH          (1 << ETHTOOL_F_WISH__BIT) | ||||||
|  | #define ETHTOOL_F_COMPAT        (1 << ETHTOOL_F_COMPAT__BIT) | ||||||
| 
 | 
 | ||||||
| #ifdef __KERNEL__ | #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) | ||||||
| 		if (dev->ethtool_ops->get_rx_csum(dev)) | 		if (dev->ethtool_ops->get_rx_csum(dev)) | ||||||
| 			features[0].active |= NETIF_F_RXCSUM; | 			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) | 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) | 	if (features[0].valid & ~NETIF_F_ETHTOOL_BITS) | ||||||
| 		return -EINVAL; | 		return -EINVAL; | ||||||
| 
 | 
 | ||||||
|  | 	if (ethtool_set_features_compat(dev, features)) | ||||||
|  | 		ret |= ETHTOOL_F_COMPAT; | ||||||
|  | 
 | ||||||
| 	if (features[0].valid & ~dev->hw_features) { | 	if (features[0].valid & ~dev->hw_features) { | ||||||
| 		features[0].valid &= dev->hw_features; | 		features[0].valid &= dev->hw_features; | ||||||
| 		ret |= ETHTOOL_F_UNSUPPORTED; | 		ret |= ETHTOOL_F_UNSUPPORTED; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Michał Mirosław
				Michał Mirosław