aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/ethtool.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/core/ethtool.c')
-rw-r--r--net/core/ethtool.c556
1 files changed, 101 insertions, 455 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index f44481707124..31b0b7f5383e 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -36,235 +36,44 @@ u32 ethtool_op_get_link(struct net_device *dev)
36} 36}
37EXPORT_SYMBOL(ethtool_op_get_link); 37EXPORT_SYMBOL(ethtool_op_get_link);
38 38
39u32 ethtool_op_get_tx_csum(struct net_device *dev)
40{
41 return (dev->features & NETIF_F_ALL_CSUM) != 0;
42}
43EXPORT_SYMBOL(ethtool_op_get_tx_csum);
44
45int ethtool_op_set_tx_csum(struct net_device *dev, u32 data)
46{
47 if (data)
48 dev->features |= NETIF_F_IP_CSUM;
49 else
50 dev->features &= ~NETIF_F_IP_CSUM;
51
52 return 0;
53}
54EXPORT_SYMBOL(ethtool_op_set_tx_csum);
55
56int ethtool_op_set_tx_hw_csum(struct net_device *dev, u32 data)
57{
58 if (data)
59 dev->features |= NETIF_F_HW_CSUM;
60 else
61 dev->features &= ~NETIF_F_HW_CSUM;
62
63 return 0;
64}
65EXPORT_SYMBOL(ethtool_op_set_tx_hw_csum);
66
67int ethtool_op_set_tx_ipv6_csum(struct net_device *dev, u32 data)
68{
69 if (data)
70 dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
71 else
72 dev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
73
74 return 0;
75}
76EXPORT_SYMBOL(ethtool_op_set_tx_ipv6_csum);
77
78u32 ethtool_op_get_sg(struct net_device *dev)
79{
80 return (dev->features & NETIF_F_SG) != 0;
81}
82EXPORT_SYMBOL(ethtool_op_get_sg);
83
84int ethtool_op_set_sg(struct net_device *dev, u32 data)
85{
86 if (data)
87 dev->features |= NETIF_F_SG;
88 else
89 dev->features &= ~NETIF_F_SG;
90
91 return 0;
92}
93EXPORT_SYMBOL(ethtool_op_set_sg);
94
95u32 ethtool_op_get_tso(struct net_device *dev)
96{
97 return (dev->features & NETIF_F_TSO) != 0;
98}
99EXPORT_SYMBOL(ethtool_op_get_tso);
100
101int ethtool_op_set_tso(struct net_device *dev, u32 data)
102{
103 if (data)
104 dev->features |= NETIF_F_TSO;
105 else
106 dev->features &= ~NETIF_F_TSO;
107
108 return 0;
109}
110EXPORT_SYMBOL(ethtool_op_set_tso);
111
112u32 ethtool_op_get_ufo(struct net_device *dev)
113{
114 return (dev->features & NETIF_F_UFO) != 0;
115}
116EXPORT_SYMBOL(ethtool_op_get_ufo);
117
118int ethtool_op_set_ufo(struct net_device *dev, u32 data)
119{
120 if (data)
121 dev->features |= NETIF_F_UFO;
122 else
123 dev->features &= ~NETIF_F_UFO;
124 return 0;
125}
126EXPORT_SYMBOL(ethtool_op_set_ufo);
127
128/* the following list of flags are the same as their associated
129 * NETIF_F_xxx values in include/linux/netdevice.h
130 */
131static const u32 flags_dup_features =
132 (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | ETH_FLAG_NTUPLE |
133 ETH_FLAG_RXHASH);
134
135u32 ethtool_op_get_flags(struct net_device *dev)
136{
137 /* in the future, this function will probably contain additional
138 * handling for flags which are not so easily handled
139 * by a simple masking operation
140 */
141
142 return dev->features & flags_dup_features;
143}
144EXPORT_SYMBOL(ethtool_op_get_flags);
145
146/* Check if device can enable (or disable) particular feature coded in "data"
147 * argument. Flags "supported" describe features that can be toggled by device.
148 * If feature can not be toggled, it state (enabled or disabled) must match
149 * hardcoded device features state, otherwise flags are marked as invalid.
150 */
151bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported)
152{
153 u32 features = dev->features & flags_dup_features;
154 /* "data" can contain only flags_dup_features bits,
155 * see __ethtool_set_flags */
156
157 return (features & ~supported) != (data & ~supported);
158}
159EXPORT_SYMBOL(ethtool_invalid_flags);
160
161int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported)
162{
163 if (ethtool_invalid_flags(dev, data, supported))
164 return -EINVAL;
165
166 dev->features = ((dev->features & ~flags_dup_features) |
167 (data & flags_dup_features));
168 return 0;
169}
170EXPORT_SYMBOL(ethtool_op_set_flags);
171
172/* Handlers for each ethtool command */ 39/* Handlers for each ethtool command */
173 40
174#define ETHTOOL_DEV_FEATURE_WORDS 1 41#define ETHTOOL_DEV_FEATURE_WORDS ((NETDEV_FEATURE_COUNT + 31) / 32)
175 42
176static void ethtool_get_features_compat(struct net_device *dev, 43static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN] = {
177 struct ethtool_get_features_block *features) 44 [NETIF_F_SG_BIT] = "tx-scatter-gather",
178{ 45 [NETIF_F_IP_CSUM_BIT] = "tx-checksum-ipv4",
179 if (!dev->ethtool_ops) 46 [NETIF_F_HW_CSUM_BIT] = "tx-checksum-ip-generic",
180 return; 47 [NETIF_F_IPV6_CSUM_BIT] = "tx-checksum-ipv6",
181 48 [NETIF_F_HIGHDMA_BIT] = "highdma",
182 /* getting RX checksum */ 49 [NETIF_F_FRAGLIST_BIT] = "tx-scatter-gather-fraglist",
183 if (dev->ethtool_ops->get_rx_csum) 50 [NETIF_F_HW_VLAN_TX_BIT] = "tx-vlan-hw-insert",
184 if (dev->ethtool_ops->get_rx_csum(dev)) 51
185 features[0].active |= NETIF_F_RXCSUM; 52 [NETIF_F_HW_VLAN_RX_BIT] = "rx-vlan-hw-parse",
186 53 [NETIF_F_HW_VLAN_FILTER_BIT] = "rx-vlan-filter",
187 /* mark legacy-changeable features */ 54 [NETIF_F_VLAN_CHALLENGED_BIT] = "vlan-challenged",
188 if (dev->ethtool_ops->set_sg) 55 [NETIF_F_GSO_BIT] = "tx-generic-segmentation",
189 features[0].available |= NETIF_F_SG; 56 [NETIF_F_LLTX_BIT] = "tx-lockless",
190 if (dev->ethtool_ops->set_tx_csum) 57 [NETIF_F_NETNS_LOCAL_BIT] = "netns-local",
191 features[0].available |= NETIF_F_ALL_CSUM; 58 [NETIF_F_GRO_BIT] = "rx-gro",
192 if (dev->ethtool_ops->set_tso) 59 [NETIF_F_LRO_BIT] = "rx-lro",
193 features[0].available |= NETIF_F_ALL_TSO; 60
194 if (dev->ethtool_ops->set_rx_csum) 61 [NETIF_F_TSO_BIT] = "tx-tcp-segmentation",
195 features[0].available |= NETIF_F_RXCSUM; 62 [NETIF_F_UFO_BIT] = "tx-udp-fragmentation",
196 if (dev->ethtool_ops->set_flags) 63 [NETIF_F_GSO_ROBUST_BIT] = "tx-gso-robust",
197 features[0].available |= flags_dup_features; 64 [NETIF_F_TSO_ECN_BIT] = "tx-tcp-ecn-segmentation",
198} 65 [NETIF_F_TSO6_BIT] = "tx-tcp6-segmentation",
199 66 [NETIF_F_FSO_BIT] = "tx-fcoe-segmentation",
200static int ethtool_set_feature_compat(struct net_device *dev, 67
201 int (*legacy_set)(struct net_device *, u32), 68 [NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc",
202 struct ethtool_set_features_block *features, u32 mask) 69 [NETIF_F_SCTP_CSUM_BIT] = "tx-checksum-sctp",
203{ 70 [NETIF_F_FCOE_MTU_BIT] = "fcoe-mtu",
204 u32 do_set; 71 [NETIF_F_NTUPLE_BIT] = "rx-ntuple-filter",
205 72 [NETIF_F_RXHASH_BIT] = "rx-hashing",
206 if (!legacy_set) 73 [NETIF_F_RXCSUM_BIT] = "rx-checksum",
207 return 0; 74 [NETIF_F_NOCACHE_COPY_BIT] = "tx-nocache-copy",
208 75 [NETIF_F_LOOPBACK_BIT] = "loopback",
209 if (!(features[0].valid & mask)) 76};
210 return 0;
211
212 features[0].valid &= ~mask;
213
214 do_set = !!(features[0].requested & mask);
215
216 if (legacy_set(dev, do_set) < 0)
217 netdev_info(dev,
218 "Legacy feature change (%s) failed for 0x%08x\n",
219 do_set ? "set" : "clear", mask);
220
221 return 1;
222}
223
224static int ethtool_set_flags_compat(struct net_device *dev,
225 int (*legacy_set)(struct net_device *, u32),
226 struct ethtool_set_features_block *features, u32 mask)
227{
228 u32 value;
229
230 if (!legacy_set)
231 return 0;
232
233 if (!(features[0].valid & mask))
234 return 0;
235
236 value = dev->features & ~features[0].valid;
237 value |= features[0].requested;
238
239 features[0].valid &= ~mask;
240
241 if (legacy_set(dev, value & mask) < 0)
242 netdev_info(dev, "Legacy flags change failed\n");
243
244 return 1;
245}
246
247static int ethtool_set_features_compat(struct net_device *dev,
248 struct ethtool_set_features_block *features)
249{
250 int compat;
251
252 if (!dev->ethtool_ops)
253 return 0;
254
255 compat = ethtool_set_feature_compat(dev, dev->ethtool_ops->set_sg,
256 features, NETIF_F_SG);
257 compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_tx_csum,
258 features, NETIF_F_ALL_CSUM);
259 compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_tso,
260 features, NETIF_F_ALL_TSO);
261 compat |= ethtool_set_feature_compat(dev, dev->ethtool_ops->set_rx_csum,
262 features, NETIF_F_RXCSUM);
263 compat |= ethtool_set_flags_compat(dev, dev->ethtool_ops->set_flags,
264 features, flags_dup_features);
265
266 return compat;
267}
268 77
269static int ethtool_get_features(struct net_device *dev, void __user *useraddr) 78static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
270{ 79{
@@ -272,18 +81,21 @@ static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
272 .cmd = ETHTOOL_GFEATURES, 81 .cmd = ETHTOOL_GFEATURES,
273 .size = ETHTOOL_DEV_FEATURE_WORDS, 82 .size = ETHTOOL_DEV_FEATURE_WORDS,
274 }; 83 };
275 struct ethtool_get_features_block features[ETHTOOL_DEV_FEATURE_WORDS] = { 84 struct ethtool_get_features_block features[ETHTOOL_DEV_FEATURE_WORDS];
276 {
277 .available = dev->hw_features,
278 .requested = dev->wanted_features,
279 .active = dev->features,
280 .never_changed = NETIF_F_NEVER_CHANGE,
281 },
282 };
283 u32 __user *sizeaddr; 85 u32 __user *sizeaddr;
284 u32 copy_size; 86 u32 copy_size;
87 int i;
285 88
286 ethtool_get_features_compat(dev, features); 89 /* in case feature bits run out again */
90 BUILD_BUG_ON(ETHTOOL_DEV_FEATURE_WORDS * sizeof(u32) > sizeof(netdev_features_t));
91
92 for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) {
93 features[i].available = (u32)(dev->hw_features >> (32 * i));
94 features[i].requested = (u32)(dev->wanted_features >> (32 * i));
95 features[i].active = (u32)(dev->features >> (32 * i));
96 features[i].never_changed =
97 (u32)(NETIF_F_NEVER_CHANGE >> (32 * i));
98 }
287 99
288 sizeaddr = useraddr + offsetof(struct ethtool_gfeatures, size); 100 sizeaddr = useraddr + offsetof(struct ethtool_gfeatures, size);
289 if (get_user(copy_size, sizeaddr)) 101 if (get_user(copy_size, sizeaddr))
@@ -305,7 +117,8 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
305{ 117{
306 struct ethtool_sfeatures cmd; 118 struct ethtool_sfeatures cmd;
307 struct ethtool_set_features_block features[ETHTOOL_DEV_FEATURE_WORDS]; 119 struct ethtool_set_features_block features[ETHTOOL_DEV_FEATURE_WORDS];
308 int ret = 0; 120 netdev_features_t wanted = 0, valid = 0;
121 int i, ret = 0;
309 122
310 if (copy_from_user(&cmd, useraddr, sizeof(cmd))) 123 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
311 return -EFAULT; 124 return -EFAULT;
@@ -317,65 +130,29 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
317 if (copy_from_user(features, useraddr, sizeof(features))) 130 if (copy_from_user(features, useraddr, sizeof(features)))
318 return -EFAULT; 131 return -EFAULT;
319 132
320 if (features[0].valid & ~NETIF_F_ETHTOOL_BITS) 133 for (i = 0; i < ETHTOOL_DEV_FEATURE_WORDS; ++i) {
321 return -EINVAL; 134 valid |= (netdev_features_t)features[i].valid << (32 * i);
135 wanted |= (netdev_features_t)features[i].requested << (32 * i);
136 }
322 137
323 if (ethtool_set_features_compat(dev, features)) 138 if (valid & ~NETIF_F_ETHTOOL_BITS)
324 ret |= ETHTOOL_F_COMPAT; 139 return -EINVAL;
325 140
326 if (features[0].valid & ~dev->hw_features) { 141 if (valid & ~dev->hw_features) {
327 features[0].valid &= dev->hw_features; 142 valid &= dev->hw_features;
328 ret |= ETHTOOL_F_UNSUPPORTED; 143 ret |= ETHTOOL_F_UNSUPPORTED;
329 } 144 }
330 145
331 dev->wanted_features &= ~features[0].valid; 146 dev->wanted_features &= ~valid;
332 dev->wanted_features |= features[0].valid & features[0].requested; 147 dev->wanted_features |= wanted & valid;
333 __netdev_update_features(dev); 148 __netdev_update_features(dev);
334 149
335 if ((dev->wanted_features ^ dev->features) & features[0].valid) 150 if ((dev->wanted_features ^ dev->features) & valid)
336 ret |= ETHTOOL_F_WISH; 151 ret |= ETHTOOL_F_WISH;
337 152
338 return ret; 153 return ret;
339} 154}
340 155
341static const char netdev_features_strings[ETHTOOL_DEV_FEATURE_WORDS * 32][ETH_GSTRING_LEN] = {
342 /* NETIF_F_SG */ "tx-scatter-gather",
343 /* NETIF_F_IP_CSUM */ "tx-checksum-ipv4",
344 /* NETIF_F_NO_CSUM */ "tx-checksum-unneeded",
345 /* NETIF_F_HW_CSUM */ "tx-checksum-ip-generic",
346 /* NETIF_F_IPV6_CSUM */ "tx-checksum-ipv6",
347 /* NETIF_F_HIGHDMA */ "highdma",
348 /* NETIF_F_FRAGLIST */ "tx-scatter-gather-fraglist",
349 /* NETIF_F_HW_VLAN_TX */ "tx-vlan-hw-insert",
350
351 /* NETIF_F_HW_VLAN_RX */ "rx-vlan-hw-parse",
352 /* NETIF_F_HW_VLAN_FILTER */ "rx-vlan-filter",
353 /* NETIF_F_VLAN_CHALLENGED */ "vlan-challenged",
354 /* NETIF_F_GSO */ "tx-generic-segmentation",
355 /* NETIF_F_LLTX */ "tx-lockless",
356 /* NETIF_F_NETNS_LOCAL */ "netns-local",
357 /* NETIF_F_GRO */ "rx-gro",
358 /* NETIF_F_LRO */ "rx-lro",
359
360 /* NETIF_F_TSO */ "tx-tcp-segmentation",
361 /* NETIF_F_UFO */ "tx-udp-fragmentation",
362 /* NETIF_F_GSO_ROBUST */ "tx-gso-robust",
363 /* NETIF_F_TSO_ECN */ "tx-tcp-ecn-segmentation",
364 /* NETIF_F_TSO6 */ "tx-tcp6-segmentation",
365 /* NETIF_F_FSO */ "tx-fcoe-segmentation",
366 "",
367 "",
368
369 /* NETIF_F_FCOE_CRC */ "tx-checksum-fcoe-crc",
370 /* NETIF_F_SCTP_CSUM */ "tx-checksum-sctp",
371 /* NETIF_F_FCOE_MTU */ "fcoe-mtu",
372 /* NETIF_F_NTUPLE */ "rx-ntuple-filter",
373 /* NETIF_F_RXHASH */ "rx-hashing",
374 /* NETIF_F_RXCSUM */ "rx-checksum",
375 /* NETIF_F_NOCACHE_COPY */ "tx-nocache-copy",
376 /* NETIF_F_LOOPBACK */ "loopback",
377};
378
379static int __ethtool_get_sset_count(struct net_device *dev, int sset) 156static int __ethtool_get_sset_count(struct net_device *dev, int sset)
380{ 157{
381 const struct ethtool_ops *ops = dev->ethtool_ops; 158 const struct ethtool_ops *ops = dev->ethtool_ops;
@@ -402,7 +179,7 @@ static void __ethtool_get_strings(struct net_device *dev,
402 ops->get_strings(dev, stringset, data); 179 ops->get_strings(dev, stringset, data);
403} 180}
404 181
405static u32 ethtool_get_feature_mask(u32 eth_cmd) 182static netdev_features_t ethtool_get_feature_mask(u32 eth_cmd)
406{ 183{
407 /* feature masks of legacy discrete ethtool ops */ 184 /* feature masks of legacy discrete ethtool ops */
408 185
@@ -433,136 +210,82 @@ static u32 ethtool_get_feature_mask(u32 eth_cmd)
433 } 210 }
434} 211}
435 212
436static void *__ethtool_get_one_feature_actor(struct net_device *dev, u32 ethcmd)
437{
438 const struct ethtool_ops *ops = dev->ethtool_ops;
439
440 if (!ops)
441 return NULL;
442
443 switch (ethcmd) {
444 case ETHTOOL_GTXCSUM:
445 return ops->get_tx_csum;
446 case ETHTOOL_GRXCSUM:
447 return ops->get_rx_csum;
448 case ETHTOOL_SSG:
449 return ops->get_sg;
450 case ETHTOOL_STSO:
451 return ops->get_tso;
452 case ETHTOOL_SUFO:
453 return ops->get_ufo;
454 default:
455 return NULL;
456 }
457}
458
459static u32 __ethtool_get_rx_csum_oldbug(struct net_device *dev)
460{
461 return !!(dev->features & NETIF_F_ALL_CSUM);
462}
463
464static int ethtool_get_one_feature(struct net_device *dev, 213static int ethtool_get_one_feature(struct net_device *dev,
465 char __user *useraddr, u32 ethcmd) 214 char __user *useraddr, u32 ethcmd)
466{ 215{
467 u32 mask = ethtool_get_feature_mask(ethcmd); 216 netdev_features_t mask = ethtool_get_feature_mask(ethcmd);
468 struct ethtool_value edata = { 217 struct ethtool_value edata = {
469 .cmd = ethcmd, 218 .cmd = ethcmd,
470 .data = !!(dev->features & mask), 219 .data = !!(dev->features & mask),
471 }; 220 };
472 221
473 /* compatibility with discrete get_ ops */
474 if (!(dev->hw_features & mask)) {
475 u32 (*actor)(struct net_device *);
476
477 actor = __ethtool_get_one_feature_actor(dev, ethcmd);
478
479 /* bug compatibility with old get_rx_csum */
480 if (ethcmd == ETHTOOL_GRXCSUM && !actor)
481 actor = __ethtool_get_rx_csum_oldbug;
482
483 if (actor)
484 edata.data = actor(dev);
485 }
486
487 if (copy_to_user(useraddr, &edata, sizeof(edata))) 222 if (copy_to_user(useraddr, &edata, sizeof(edata)))
488 return -EFAULT; 223 return -EFAULT;
489 return 0; 224 return 0;
490} 225}
491 226
492static int __ethtool_set_tx_csum(struct net_device *dev, u32 data);
493static int __ethtool_set_rx_csum(struct net_device *dev, u32 data);
494static int __ethtool_set_sg(struct net_device *dev, u32 data);
495static int __ethtool_set_tso(struct net_device *dev, u32 data);
496static int __ethtool_set_ufo(struct net_device *dev, u32 data);
497
498static int ethtool_set_one_feature(struct net_device *dev, 227static int ethtool_set_one_feature(struct net_device *dev,
499 void __user *useraddr, u32 ethcmd) 228 void __user *useraddr, u32 ethcmd)
500{ 229{
501 struct ethtool_value edata; 230 struct ethtool_value edata;
502 u32 mask; 231 netdev_features_t mask;
503 232
504 if (copy_from_user(&edata, useraddr, sizeof(edata))) 233 if (copy_from_user(&edata, useraddr, sizeof(edata)))
505 return -EFAULT; 234 return -EFAULT;
506 235
507 mask = ethtool_get_feature_mask(ethcmd); 236 mask = ethtool_get_feature_mask(ethcmd);
508 mask &= dev->hw_features; 237 mask &= dev->hw_features;
509 if (mask) { 238 if (!mask)
510 if (edata.data) 239 return -EOPNOTSUPP;
511 dev->wanted_features |= mask;
512 else
513 dev->wanted_features &= ~mask;
514 240
515 __netdev_update_features(dev); 241 if (edata.data)
516 return 0; 242 dev->wanted_features |= mask;
517 } 243 else
244 dev->wanted_features &= ~mask;
518 245
519 /* Driver is not converted to ndo_fix_features or does not 246 __netdev_update_features(dev);
520 * support changing this offload. In the latter case it won't
521 * have corresponding ethtool_ops field set.
522 *
523 * Following part is to be removed after all drivers advertise
524 * their changeable features in netdev->hw_features and stop
525 * using discrete offload setting ops.
526 */
527 247
528 switch (ethcmd) { 248 return 0;
529 case ETHTOOL_STXCSUM: 249}
530 return __ethtool_set_tx_csum(dev, edata.data); 250
531 case ETHTOOL_SRXCSUM: 251#define ETH_ALL_FLAGS (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | \
532 return __ethtool_set_rx_csum(dev, edata.data); 252 ETH_FLAG_NTUPLE | ETH_FLAG_RXHASH)
533 case ETHTOOL_SSG: 253#define ETH_ALL_FEATURES (NETIF_F_LRO | NETIF_F_HW_VLAN_RX | \
534 return __ethtool_set_sg(dev, edata.data); 254 NETIF_F_HW_VLAN_TX | NETIF_F_NTUPLE | NETIF_F_RXHASH)
535 case ETHTOOL_STSO: 255
536 return __ethtool_set_tso(dev, edata.data); 256static u32 __ethtool_get_flags(struct net_device *dev)
537 case ETHTOOL_SUFO: 257{
538 return __ethtool_set_ufo(dev, edata.data); 258 u32 flags = 0;
539 default: 259
540 return -EOPNOTSUPP; 260 if (dev->features & NETIF_F_LRO) flags |= ETH_FLAG_LRO;
541 } 261 if (dev->features & NETIF_F_HW_VLAN_RX) flags |= ETH_FLAG_RXVLAN;
262 if (dev->features & NETIF_F_HW_VLAN_TX) flags |= ETH_FLAG_TXVLAN;
263 if (dev->features & NETIF_F_NTUPLE) flags |= ETH_FLAG_NTUPLE;
264 if (dev->features & NETIF_F_RXHASH) flags |= ETH_FLAG_RXHASH;
265
266 return flags;
542} 267}
543 268
544int __ethtool_set_flags(struct net_device *dev, u32 data) 269static int __ethtool_set_flags(struct net_device *dev, u32 data)
545{ 270{
546 u32 changed; 271 netdev_features_t features = 0, changed;
547 272
548 if (data & ~flags_dup_features) 273 if (data & ~ETH_ALL_FLAGS)
549 return -EINVAL; 274 return -EINVAL;
550 275
551 /* legacy set_flags() op */ 276 if (data & ETH_FLAG_LRO) features |= NETIF_F_LRO;
552 if (dev->ethtool_ops->set_flags) { 277 if (data & ETH_FLAG_RXVLAN) features |= NETIF_F_HW_VLAN_RX;
553 if (unlikely(dev->hw_features & flags_dup_features)) 278 if (data & ETH_FLAG_TXVLAN) features |= NETIF_F_HW_VLAN_TX;
554 netdev_warn(dev, 279 if (data & ETH_FLAG_NTUPLE) features |= NETIF_F_NTUPLE;
555 "driver BUG: mixed hw_features and set_flags()\n"); 280 if (data & ETH_FLAG_RXHASH) features |= NETIF_F_RXHASH;
556 return dev->ethtool_ops->set_flags(dev, data);
557 }
558 281
559 /* allow changing only bits set in hw_features */ 282 /* allow changing only bits set in hw_features */
560 changed = (data ^ dev->features) & flags_dup_features; 283 changed = (features ^ dev->features) & ETH_ALL_FEATURES;
561 if (changed & ~dev->hw_features) 284 if (changed & ~dev->hw_features)
562 return (changed & dev->hw_features) ? -EINVAL : -EOPNOTSUPP; 285 return (changed & dev->hw_features) ? -EINVAL : -EOPNOTSUPP;
563 286
564 dev->wanted_features = 287 dev->wanted_features =
565 (dev->wanted_features & ~changed) | (data & dev->hw_features); 288 (dev->wanted_features & ~changed) | (features & changed);
566 289
567 __netdev_update_features(dev); 290 __netdev_update_features(dev);
568 291
@@ -1231,81 +954,6 @@ static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr)
1231 return dev->ethtool_ops->set_pauseparam(dev, &pauseparam); 954 return dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
1232} 955}
1233 956
1234static int __ethtool_set_sg(struct net_device *dev, u32 data)
1235{
1236 int err;
1237
1238 if (!dev->ethtool_ops->set_sg)
1239 return -EOPNOTSUPP;
1240
1241 if (data && !(dev->features & NETIF_F_ALL_CSUM))
1242 return -EINVAL;
1243
1244 if (!data && dev->ethtool_ops->set_tso) {
1245 err = dev->ethtool_ops->set_tso(dev, 0);
1246 if (err)
1247 return err;
1248 }
1249
1250 if (!data && dev->ethtool_ops->set_ufo) {
1251 err = dev->ethtool_ops->set_ufo(dev, 0);
1252 if (err)
1253 return err;
1254 }
1255 return dev->ethtool_ops->set_sg(dev, data);
1256}
1257
1258static int __ethtool_set_tx_csum(struct net_device *dev, u32 data)
1259{
1260 int err;
1261
1262 if (!dev->ethtool_ops->set_tx_csum)
1263 return -EOPNOTSUPP;
1264
1265 if (!data && dev->ethtool_ops->set_sg) {
1266 err = __ethtool_set_sg(dev, 0);
1267 if (err)
1268 return err;
1269 }
1270
1271 return dev->ethtool_ops->set_tx_csum(dev, data);
1272}
1273
1274static int __ethtool_set_rx_csum(struct net_device *dev, u32 data)
1275{
1276 if (!dev->ethtool_ops->set_rx_csum)
1277 return -EOPNOTSUPP;
1278
1279 if (!data)
1280 dev->features &= ~NETIF_F_GRO;
1281
1282 return dev->ethtool_ops->set_rx_csum(dev, data);
1283}
1284
1285static int __ethtool_set_tso(struct net_device *dev, u32 data)
1286{
1287 if (!dev->ethtool_ops->set_tso)
1288 return -EOPNOTSUPP;
1289
1290 if (data && !(dev->features & NETIF_F_SG))
1291 return -EINVAL;
1292
1293 return dev->ethtool_ops->set_tso(dev, data);
1294}
1295
1296static int __ethtool_set_ufo(struct net_device *dev, u32 data)
1297{
1298 if (!dev->ethtool_ops->set_ufo)
1299 return -EOPNOTSUPP;
1300 if (data && !(dev->features & NETIF_F_SG))
1301 return -EINVAL;
1302 if (data && !((dev->features & NETIF_F_GEN_CSUM) ||
1303 (dev->features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))
1304 == (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM)))
1305 return -EINVAL;
1306 return dev->ethtool_ops->set_ufo(dev, data);
1307}
1308
1309static int ethtool_self_test(struct net_device *dev, char __user *useraddr) 957static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
1310{ 958{
1311 struct ethtool_test test; 959 struct ethtool_test test;
@@ -1771,9 +1419,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1771 break; 1419 break;
1772 case ETHTOOL_GFLAGS: 1420 case ETHTOOL_GFLAGS:
1773 rc = ethtool_get_value(dev, useraddr, ethcmd, 1421 rc = ethtool_get_value(dev, useraddr, ethcmd,
1774 (dev->ethtool_ops->get_flags ? 1422 __ethtool_get_flags);
1775 dev->ethtool_ops->get_flags :
1776 ethtool_op_get_flags));
1777 break; 1423 break;
1778 case ETHTOOL_SFLAGS: 1424 case ETHTOOL_SFLAGS:
1779 rc = ethtool_set_value(dev, useraddr, __ethtool_set_flags); 1425 rc = ethtool_set_value(dev, useraddr, __ethtool_set_flags);