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;
        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);
                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;
        }