aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/ethtool.c
diff options
context:
space:
mode:
authorMichał Mirosław <mirq-linux@rere.qmqm.pl>2011-11-15 10:29:55 -0500
committerDavid S. Miller <davem@davemloft.net>2011-11-16 17:43:08 -0500
commitbc5787c6125cc2c868eaace46c46ce6e83dcfcb6 (patch)
tree831619892302478a2ceb27d9edbffc871cf9ad26 /net/core/ethtool.c
parent33a5ba144e3e7ffc1cd4a1d205e99c16078885bf (diff)
net: remove legacy ethtool ops
As all drivers are converted, we may now remove discrete offload setting callback handling. Signed-off-by: Michał Mirosław <mirq-linux@rere.qmqm.pl> Acked-by: Ben Hutchings <bhutchings@solarflare.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/ethtool.c')
-rw-r--r--net/core/ethtool.c418
1 files changed, 22 insertions, 396 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index f44481707124..db8a77bb557b 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -36,236 +36,10 @@ 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 1
175 42
176static void ethtool_get_features_compat(struct net_device *dev,
177 struct ethtool_get_features_block *features)
178{
179 if (!dev->ethtool_ops)
180 return;
181
182 /* getting RX checksum */
183 if (dev->ethtool_ops->get_rx_csum)
184 if (dev->ethtool_ops->get_rx_csum(dev))
185 features[0].active |= NETIF_F_RXCSUM;
186
187 /* mark legacy-changeable features */
188 if (dev->ethtool_ops->set_sg)
189 features[0].available |= NETIF_F_SG;
190 if (dev->ethtool_ops->set_tx_csum)
191 features[0].available |= NETIF_F_ALL_CSUM;
192 if (dev->ethtool_ops->set_tso)
193 features[0].available |= NETIF_F_ALL_TSO;
194 if (dev->ethtool_ops->set_rx_csum)
195 features[0].available |= NETIF_F_RXCSUM;
196 if (dev->ethtool_ops->set_flags)
197 features[0].available |= flags_dup_features;
198}
199
200static int ethtool_set_feature_compat(struct net_device *dev,
201 int (*legacy_set)(struct net_device *, u32),
202 struct ethtool_set_features_block *features, u32 mask)
203{
204 u32 do_set;
205
206 if (!legacy_set)
207 return 0;
208
209 if (!(features[0].valid & mask))
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
269static int ethtool_get_features(struct net_device *dev, void __user *useraddr) 43static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
270{ 44{
271 struct ethtool_gfeatures cmd = { 45 struct ethtool_gfeatures cmd = {
@@ -283,8 +57,6 @@ static int ethtool_get_features(struct net_device *dev, void __user *useraddr)
283 u32 __user *sizeaddr; 57 u32 __user *sizeaddr;
284 u32 copy_size; 58 u32 copy_size;
285 59
286 ethtool_get_features_compat(dev, features);
287
288 sizeaddr = useraddr + offsetof(struct ethtool_gfeatures, size); 60 sizeaddr = useraddr + offsetof(struct ethtool_gfeatures, size);
289 if (get_user(copy_size, sizeaddr)) 61 if (get_user(copy_size, sizeaddr))
290 return -EFAULT; 62 return -EFAULT;
@@ -320,9 +92,6 @@ static int ethtool_set_features(struct net_device *dev, void __user *useraddr)
320 if (features[0].valid & ~NETIF_F_ETHTOOL_BITS) 92 if (features[0].valid & ~NETIF_F_ETHTOOL_BITS)
321 return -EINVAL; 93 return -EINVAL;
322 94
323 if (ethtool_set_features_compat(dev, features))
324 ret |= ETHTOOL_F_COMPAT;
325
326 if (features[0].valid & ~dev->hw_features) { 95 if (features[0].valid & ~dev->hw_features) {
327 features[0].valid &= dev->hw_features; 96 features[0].valid &= dev->hw_features;
328 ret |= ETHTOOL_F_UNSUPPORTED; 97 ret |= ETHTOOL_F_UNSUPPORTED;
@@ -433,34 +202,6 @@ static u32 ethtool_get_feature_mask(u32 eth_cmd)
433 } 202 }
434} 203}
435 204
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, 205static int ethtool_get_one_feature(struct net_device *dev,
465 char __user *useraddr, u32 ethcmd) 206 char __user *useraddr, u32 ethcmd)
466{ 207{
@@ -470,31 +211,11 @@ static int ethtool_get_one_feature(struct net_device *dev,
470 .data = !!(dev->features & mask), 211 .data = !!(dev->features & mask),
471 }; 212 };
472 213
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))) 214 if (copy_to_user(useraddr, &edata, sizeof(edata)))
488 return -EFAULT; 215 return -EFAULT;
489 return 0; 216 return 0;
490} 217}
491 218
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, 219static int ethtool_set_one_feature(struct net_device *dev,
499 void __user *useraddr, u32 ethcmd) 220 void __user *useraddr, u32 ethcmd)
500{ 221{
@@ -506,56 +227,38 @@ static int ethtool_set_one_feature(struct net_device *dev,
506 227
507 mask = ethtool_get_feature_mask(ethcmd); 228 mask = ethtool_get_feature_mask(ethcmd);
508 mask &= dev->hw_features; 229 mask &= dev->hw_features;
509 if (mask) { 230 if (!mask)
510 if (edata.data) 231 return -EOPNOTSUPP;
511 dev->wanted_features |= mask;
512 else
513 dev->wanted_features &= ~mask;
514 232
515 __netdev_update_features(dev); 233 if (edata.data)
516 return 0; 234 dev->wanted_features |= mask;
517 } 235 else
236 dev->wanted_features &= ~mask;
518 237
519 /* Driver is not converted to ndo_fix_features or does not 238 __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 239
528 switch (ethcmd) { 240 return 0;
529 case ETHTOOL_STXCSUM: 241}
530 return __ethtool_set_tx_csum(dev, edata.data); 242
531 case ETHTOOL_SRXCSUM: 243/* the following list of flags are the same as their associated
532 return __ethtool_set_rx_csum(dev, edata.data); 244 * NETIF_F_xxx values in include/linux/netdevice.h
533 case ETHTOOL_SSG: 245 */
534 return __ethtool_set_sg(dev, edata.data); 246static const u32 flags_dup_features =
535 case ETHTOOL_STSO: 247 (ETH_FLAG_LRO | ETH_FLAG_RXVLAN | ETH_FLAG_TXVLAN | ETH_FLAG_NTUPLE |
536 return __ethtool_set_tso(dev, edata.data); 248 ETH_FLAG_RXHASH);
537 case ETHTOOL_SUFO: 249
538 return __ethtool_set_ufo(dev, edata.data); 250static u32 __ethtool_get_flags(struct net_device *dev)
539 default: 251{
540 return -EOPNOTSUPP; 252 return dev->features & flags_dup_features;
541 }
542} 253}
543 254
544int __ethtool_set_flags(struct net_device *dev, u32 data) 255static int __ethtool_set_flags(struct net_device *dev, u32 data)
545{ 256{
546 u32 changed; 257 u32 changed;
547 258
548 if (data & ~flags_dup_features) 259 if (data & ~flags_dup_features)
549 return -EINVAL; 260 return -EINVAL;
550 261
551 /* legacy set_flags() op */
552 if (dev->ethtool_ops->set_flags) {
553 if (unlikely(dev->hw_features & flags_dup_features))
554 netdev_warn(dev,
555 "driver BUG: mixed hw_features and set_flags()\n");
556 return dev->ethtool_ops->set_flags(dev, data);
557 }
558
559 /* allow changing only bits set in hw_features */ 262 /* allow changing only bits set in hw_features */
560 changed = (data ^ dev->features) & flags_dup_features; 263 changed = (data ^ dev->features) & flags_dup_features;
561 if (changed & ~dev->hw_features) 264 if (changed & ~dev->hw_features)
@@ -1231,81 +934,6 @@ static int ethtool_set_pauseparam(struct net_device *dev, void __user *useraddr)
1231 return dev->ethtool_ops->set_pauseparam(dev, &pauseparam); 934 return dev->ethtool_ops->set_pauseparam(dev, &pauseparam);
1232} 935}
1233 936
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) 937static int ethtool_self_test(struct net_device *dev, char __user *useraddr)
1310{ 938{
1311 struct ethtool_test test; 939 struct ethtool_test test;
@@ -1771,9 +1399,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
1771 break; 1399 break;
1772 case ETHTOOL_GFLAGS: 1400 case ETHTOOL_GFLAGS:
1773 rc = ethtool_get_value(dev, useraddr, ethcmd, 1401 rc = ethtool_get_value(dev, useraddr, ethcmd,
1774 (dev->ethtool_ops->get_flags ? 1402 __ethtool_get_flags);
1775 dev->ethtool_ops->get_flags :
1776 ethtool_op_get_flags));
1777 break; 1403 break;
1778 case ETHTOOL_SFLAGS: 1404 case ETHTOOL_SFLAGS:
1779 rc = ethtool_set_value(dev, useraddr, __ethtool_set_flags); 1405 rc = ethtool_set_value(dev, useraddr, __ethtool_set_flags);