net: ethtool: use ndo_fix_features for offload setting
authorMichał Mirosław <mirq-linux@rere.qmqm.pl>
Tue, 15 Feb 2011 16:59:17 +0000 (16:59 +0000)
committerDavid S. Miller <davem@davemloft.net>
Thu, 17 Feb 2011 22:16:34 +0000 (14:16 -0800)
Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl>
Signed-off-by: David S. Miller <davem@davemloft.net>
net/core/ethtool.c

index 9577396..6599997 100644 (file)
@@ -357,15 +357,21 @@ static void *__ethtool_get_one_feature_actor(struct net_device *dev, u32 ethcmd)
 static int ethtool_get_one_feature(struct net_device *dev,
        char __user *useraddr, u32 ethcmd)
 {
+       u32 mask = ethtool_get_feature_mask(ethcmd);
        struct ethtool_value edata = {
                .cmd = ethcmd,
-               .data = !!(dev->features & ethtool_get_feature_mask(ethcmd)),
+               .data = !!(dev->features & mask),
        };
-       u32 (*actor)(struct net_device *);
 
-       actor = __ethtool_get_one_feature_actor(dev, ethcmd);
-       if (actor)
-               edata.data = actor(dev);
+       /* compatibility with discrete get_ ops */
+       if (!(dev->hw_features & mask)) {
+               u32 (*actor)(struct net_device *);
+
+               actor = __ethtool_get_one_feature_actor(dev, ethcmd);
+
+               if (actor)
+                       edata.data = actor(dev);
+       }
 
        if (copy_to_user(useraddr, &edata, sizeof(edata)))
                return -EFAULT;
@@ -386,6 +392,27 @@ static int ethtool_set_one_feature(struct net_device *dev,
        if (copy_from_user(&edata, useraddr, sizeof(edata)))
                return -EFAULT;
 
+       mask = ethtool_get_feature_mask(ethcmd);
+       mask &= dev->hw_features;
+       if (mask) {
+               if (edata.data)
+                       dev->wanted_features |= mask;
+               else
+                       dev->wanted_features &= ~mask;
+
+               netdev_update_features(dev);
+               return 0;
+       }
+
+       /* Driver is not converted to ndo_fix_features or does not
+        * support changing this offload. In the latter case it won't
+        * have corresponding ethtool_ops field set.
+        *
+        * Following part is to be removed after all drivers advertise
+        * their changeable features in netdev->hw_features and stop
+        * using discrete offload setting ops.
+        */
+
        switch (ethcmd) {
        case ETHTOOL_STXCSUM:
                return __ethtool_set_tx_csum(dev, edata.data);
@@ -395,14 +422,6 @@ static int ethtool_set_one_feature(struct net_device *dev,
                return __ethtool_set_tso(dev, edata.data);
        case ETHTOOL_SUFO:
                return __ethtool_set_ufo(dev, edata.data);
-       case ETHTOOL_SGSO:
-       case ETHTOOL_SGRO:
-               mask = ethtool_get_feature_mask(ethcmd);
-               if (edata.data)
-                       dev->features |= mask;
-               else
-                       dev->features &= ~mask;
-               return 0;
        default:
                return -EOPNOTSUPP;
        }