Commit 39fc0ce5 authored by Michał Mirosław's avatar Michał Mirosław Committed by David S. Miller

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: default avatarMichał Mirosław <mirq-linux@rere.qmqm.pl>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 4e4db200
...@@ -591,6 +591,9 @@ struct ethtool_sfeatures { ...@@ -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 { ...@@ -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, ...@@ -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) ...@@ -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;
......
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