aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
Diffstat (limited to 'net/core')
-rw-r--r--net/core/ethtool.c61
1 files changed, 61 insertions, 0 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 69a3edc182f9..c1a71bb738da 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -178,6 +178,64 @@ static void ethtool_get_features_compat(struct net_device *dev,
178 if (dev->ethtool_ops->get_rx_csum) 178 if (dev->ethtool_ops->get_rx_csum)
179 if (dev->ethtool_ops->get_rx_csum(dev)) 179 if (dev->ethtool_ops->get_rx_csum(dev))
180 features[0].active |= NETIF_F_RXCSUM; 180 features[0].active |= NETIF_F_RXCSUM;
181
182 /* mark legacy-changeable features */
183 if (dev->ethtool_ops->set_sg)
184 features[0].available |= NETIF_F_SG;
185 if (dev->ethtool_ops->set_tx_csum)
186 features[0].available |= NETIF_F_ALL_CSUM;
187 if (dev->ethtool_ops->set_tso)
188 features[0].available |= NETIF_F_ALL_TSO;
189 if (dev->ethtool_ops->set_rx_csum)
190 features[0].available |= NETIF_F_RXCSUM;
191 if (dev->ethtool_ops->set_flags)
192 features[0].available |= flags_dup_features;
193}
194
195static int ethtool_set_feature_compat(struct net_device *dev,
196 int (*legacy_set)(struct net_device *, u32),
197 struct ethtool_set_features_block *features, u32 mask)
198{
199 u32 do_set;
200
201 if (!legacy_set)
202 return 0;
203
204 if (!(features[0].valid & mask))
205 return 0;
206
207 features[0].valid &= ~mask;
208
209 do_set = !!(features[0].requested & mask);
210
211 if (legacy_set(dev, do_set) < 0)
212 netdev_info(dev,
213 "Legacy feature change (%s) failed for 0x%08x\n",
214 do_set ? "set" : "clear", mask);
215
216 return 1;
217}
218
219static int ethtool_set_features_compat(struct net_device *dev,
220 struct ethtool_set_features_block *features)
221{
222 int compat;
223
224 if (!dev->ethtool_ops)
225 return 0;
226
227 compat = ethtool_set_feature_compat(dev, dev->ethtool_ops->set_sg,
228 features, NETIF_F_SG);
229 compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_tx_csum,
230 features, NETIF_F_ALL_CSUM);
231 compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_tso,
232 features, NETIF_F_ALL_TSO);
233 compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_rx_csum,
234 features, NETIF_F_RXCSUM);
235 compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_flags,
236 features, flags_dup_features);
237
238 return compat;
181} 239}
182 240
183static int ethtool_get_features(struct net_device *dev, void __user *useraddr) 241static 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 if (features[0].valid & ~NETIF_F_ETHTOOL_BITS) 292 if (features[0].valid & ~NETIF_F_ETHTOOL_BITS)
235 return -EINVAL; 293 return -EINVAL;
236 294
295 if (ethtool_set_features_compat(dev, features))
296 ret |= ETHTOOL_F_COMPAT;
297
237 if (features[0].valid & ~dev->hw_features) { 298 if (features[0].valid & ~dev->hw_features) {
238 features[0].valid &= dev->hw_features; 299 features[0].valid &= dev->hw_features;
239 ret |= ETHTOOL_F_UNSUPPORTED; 300 ret |= ETHTOOL_F_UNSUPPORTED;