aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-02-25 22:07:00 -0500
committerDavid S. Miller <davem@davemloft.net>2016-02-25 22:07:00 -0500
commit8d3f2806f8fbd9b222b3504580b5eaa9ba2964b8 (patch)
tree045aa107208927f1b67a74b3e817b11870a08da1 /net
parenta87cb3e48ee86d29868d3f59cfb9ce1a8fa63314 (diff)
parent3d8f7cc78d0eb07641fdcfb3961e8794778a6678 (diff)
Merge branch 'ethtool-ksettings'
David Decotigny says: ==================== new ETHTOOL_GLINKSETTINGS/SLINKSETTINGS API History: v9 - add 'link' in macro, struct and function names - rename ethtool_link_ksettings::parent -> ::base - remove un-needed mlx4 en_dbg_enabled() companion patch - note: bitmap u32[] API patches were merged separately by Kan Liang v8 - bitmap u32 API returns number of bits copied, unit tests updated v7 - module_exit in test_bitmap v6 - fix copy_from_user in user/kernel handshake v5 note: please see v4 bullets for a question regarding bitmap.c - minor fix to make allyesconfig/allmodconfig v4 - removed typedef for link mode bitmaps - moved bitmap<->u32[] conversion routines to bitmap.c . This is the naive implementation. I have an endian-aware version that uses memcpy/memset as much as possible, but I find it harder to follow (see http://paste.ubuntu.com/13863722/). Please let me know if I should use it instead. - fixes suggested by Ben Hutchings v3 - rebased v2 on top of latest net-next, minor checkpatch/printf %*pb updates v2 - keep return 0 in get_settings when successful, instead of propagating positive result from driver's get_settings callback. v1 - original submission The main goal of this series is to support ethtool link mode masks larger than 32 bits. It implements a new ioctl pair (ETHTOOL_GLINKSETTINGS/SLINKSETTINGS), its associated callbacks (get/set_link_ksettings) and a new struct ethtool_link_settings, which should eventually replace legacy ethtool_cmd. Internally, the kernel uses fixed length link mode masks defined at compilation time in ethtool.h (for now: 31 bits), that can be increased by changing __ETHTOOL_LINK_MODE_LAST in ethtool.h (absolute max is 4064 bits, checked at compile time), and the user/kernel interface allows this length to be arbitrary within 1..4064. This should allow some flexibility without using too much heap/stack space, at the cost of a small kernel/user handshake for the user to determine the sizes of those bitmaps. Along the way, I chose to drop in the new structure the 3 ethtool_cmd fields marked "deprecated" (transceiver/maxrxpkt/maxtxpkt). They are still available for old drivers via the (old) ETHTOOL_GSET/SSET API, but are not available to drivers that switch to new API. Of those 3 fields, ethtool_cmd::transceiver seems to be still actively used by several drivers, maybe we should not consider this field deprecated? The 2 other fields are basically not used. This transition requires some care in the way old and new ethtool talk to the kernel. More technical details provided in the description for main patch. In particular details about backward compatibility properties. Some open questions: - the kernel/interface multiplexes the "tell me the bitmap length" handshake and the "give me the settings" inside the new ETHTOOL_GLINKSETTINGS cmd. I was thinking of making this into 2 separate cmds: 1 cmd ETHTOOL_GKERNELPROPERTIES which would be kernel-wide rather than device-specific, would return properties like "length of the link mode bitmaps", and possibly others. And ETHTOOL_GLINKSETTINGS would expect the proper bitmaps - the link mode bitmaps are piggybacked at tail of the new struct ethtool_link_settings. Since its user-visible definition does not assume specific bitmap width, I am using a 0-length array as the publicly visible placeholder. But then, the kernel needs to specialize it (struct ethtool_link_ksettings) to specify its current link mode masks. This means that kernel code is "littered" with "ksettings->base.field" to access "field" inside ethtool_settings: + I could use ethtool_link_settings everywhere (instead of a new ethtool_ksettings) and an container_of accessor (or a plain cast) to retrieve the link mode masks? + or: we could decide to make the link mode masks statically bounded again, ie. make their width public, but larger than current 32, and unchangeable forever. This would make everything straightforward, but we might hit limits later, or have an unneeded memory/stack usage for unused bits. any preference? - I foresee bugs where people use the legacy/deprecated SUPPORTED_x macros instead of the new ETHTOOL_LINK_MODE_x_BIT enums in the new get/set_link_ksettings callbacks. Not sure how to prevent problems with this. The only driver which was converted for now is mlx4. I am not considering fcoe as fully converted, but I updated it a minima to be able to remove __ethtool_get_settings, now known as __ethtool_get_link_ksettings. Tested with legacy and "future" ethtool on 64b x86 kernel and 32+64b ethtool, and on a 32b x86 kernel + 32b ethtool. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/8021q/vlan_dev.c8
-rw-r--r--net/bridge/br_if.c6
-rw-r--r--net/core/ethtool.c446
-rw-r--r--net/core/net-sysfs.c15
-rw-r--r--net/packet/af_packet.c11
5 files changed, 456 insertions, 30 deletions
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 055f0e989e90..e416a4038a12 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -621,12 +621,12 @@ static netdev_features_t vlan_dev_fix_features(struct net_device *dev,
621 return features; 621 return features;
622} 622}
623 623
624static int vlan_ethtool_get_settings(struct net_device *dev, 624static int vlan_ethtool_get_link_ksettings(struct net_device *dev,
625 struct ethtool_cmd *cmd) 625 struct ethtool_link_ksettings *cmd)
626{ 626{
627 const struct vlan_dev_priv *vlan = vlan_dev_priv(dev); 627 const struct vlan_dev_priv *vlan = vlan_dev_priv(dev);
628 628
629 return __ethtool_get_settings(vlan->real_dev, cmd); 629 return __ethtool_get_link_ksettings(vlan->real_dev, cmd);
630} 630}
631 631
632static void vlan_ethtool_get_drvinfo(struct net_device *dev, 632static void vlan_ethtool_get_drvinfo(struct net_device *dev,
@@ -741,7 +741,7 @@ static int vlan_dev_get_iflink(const struct net_device *dev)
741} 741}
742 742
743static const struct ethtool_ops vlan_ethtool_ops = { 743static const struct ethtool_ops vlan_ethtool_ops = {
744 .get_settings = vlan_ethtool_get_settings, 744 .get_link_ksettings = vlan_ethtool_get_link_ksettings,
745 .get_drvinfo = vlan_ethtool_get_drvinfo, 745 .get_drvinfo = vlan_ethtool_get_drvinfo,
746 .get_link = ethtool_op_get_link, 746 .get_link = ethtool_op_get_link,
747 .get_ts_info = vlan_ethtool_get_ts_info, 747 .get_ts_info = vlan_ethtool_get_ts_info,
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index c367b3e1b5ac..b37a1cc97d98 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -36,10 +36,10 @@
36 */ 36 */
37static int port_cost(struct net_device *dev) 37static int port_cost(struct net_device *dev)
38{ 38{
39 struct ethtool_cmd ecmd; 39 struct ethtool_link_ksettings ecmd;
40 40
41 if (!__ethtool_get_settings(dev, &ecmd)) { 41 if (!__ethtool_get_link_ksettings(dev, &ecmd)) {
42 switch (ethtool_cmd_speed(&ecmd)) { 42 switch (ecmd.base.speed) {
43 case SPEED_10000: 43 case SPEED_10000:
44 return 2; 44 return 2;
45 case SPEED_1000: 45 case SPEED_1000:
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 2406101002b1..2966cd0d7c93 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -387,43 +387,461 @@ static int __ethtool_set_flags(struct net_device *dev, u32 data)
387 return 0; 387 return 0;
388} 388}
389 389
390int __ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) 390static void convert_legacy_u32_to_link_mode(unsigned long *dst, u32 legacy_u32)
391{ 391{
392 bitmap_zero(dst, __ETHTOOL_LINK_MODE_MASK_NBITS);
393 dst[0] = legacy_u32;
394}
395
396/* return false if src had higher bits set. lower bits always updated. */
397static bool convert_link_mode_to_legacy_u32(u32 *legacy_u32,
398 const unsigned long *src)
399{
400 bool retval = true;
401
402 /* TODO: following test will soon always be true */
403 if (__ETHTOOL_LINK_MODE_MASK_NBITS > 32) {
404 __ETHTOOL_DECLARE_LINK_MODE_MASK(ext);
405
406 bitmap_zero(ext, __ETHTOOL_LINK_MODE_MASK_NBITS);
407 bitmap_fill(ext, 32);
408 bitmap_complement(ext, ext, __ETHTOOL_LINK_MODE_MASK_NBITS);
409 if (bitmap_intersects(ext, src,
410 __ETHTOOL_LINK_MODE_MASK_NBITS)) {
411 /* src mask goes beyond bit 31 */
412 retval = false;
413 }
414 }
415 *legacy_u32 = src[0];
416 return retval;
417}
418
419/* return false if legacy contained non-0 deprecated fields
420 * transceiver/maxtxpkt/maxrxpkt. rest of ksettings always updated
421 */
422static bool
423convert_legacy_settings_to_link_ksettings(
424 struct ethtool_link_ksettings *link_ksettings,
425 const struct ethtool_cmd *legacy_settings)
426{
427 bool retval = true;
428
429 memset(link_ksettings, 0, sizeof(*link_ksettings));
430
431 /* This is used to tell users that driver is still using these
432 * deprecated legacy fields, and they should not use
433 * %ETHTOOL_GLINKSETTINGS/%ETHTOOL_SLINKSETTINGS
434 */
435 if (legacy_settings->transceiver ||
436 legacy_settings->maxtxpkt ||
437 legacy_settings->maxrxpkt)
438 retval = false;
439
440 convert_legacy_u32_to_link_mode(
441 link_ksettings->link_modes.supported,
442 legacy_settings->supported);
443 convert_legacy_u32_to_link_mode(
444 link_ksettings->link_modes.advertising,
445 legacy_settings->advertising);
446 convert_legacy_u32_to_link_mode(
447 link_ksettings->link_modes.lp_advertising,
448 legacy_settings->lp_advertising);
449 link_ksettings->base.speed
450 = ethtool_cmd_speed(legacy_settings);
451 link_ksettings->base.duplex
452 = legacy_settings->duplex;
453 link_ksettings->base.port
454 = legacy_settings->port;
455 link_ksettings->base.phy_address
456 = legacy_settings->phy_address;
457 link_ksettings->base.autoneg
458 = legacy_settings->autoneg;
459 link_ksettings->base.mdio_support
460 = legacy_settings->mdio_support;
461 link_ksettings->base.eth_tp_mdix
462 = legacy_settings->eth_tp_mdix;
463 link_ksettings->base.eth_tp_mdix_ctrl
464 = legacy_settings->eth_tp_mdix_ctrl;
465 return retval;
466}
467
468/* return false if ksettings link modes had higher bits
469 * set. legacy_settings always updated (best effort)
470 */
471static bool
472convert_link_ksettings_to_legacy_settings(
473 struct ethtool_cmd *legacy_settings,
474 const struct ethtool_link_ksettings *link_ksettings)
475{
476 bool retval = true;
477
478 memset(legacy_settings, 0, sizeof(*legacy_settings));
479 /* this also clears the deprecated fields in legacy structure:
480 * __u8 transceiver;
481 * __u32 maxtxpkt;
482 * __u32 maxrxpkt;
483 */
484
485 retval &= convert_link_mode_to_legacy_u32(
486 &legacy_settings->supported,
487 link_ksettings->link_modes.supported);
488 retval &= convert_link_mode_to_legacy_u32(
489 &legacy_settings->advertising,
490 link_ksettings->link_modes.advertising);
491 retval &= convert_link_mode_to_legacy_u32(
492 &legacy_settings->lp_advertising,
493 link_ksettings->link_modes.lp_advertising);
494 ethtool_cmd_speed_set(legacy_settings, link_ksettings->base.speed);
495 legacy_settings->duplex
496 = link_ksettings->base.duplex;
497 legacy_settings->port
498 = link_ksettings->base.port;
499 legacy_settings->phy_address
500 = link_ksettings->base.phy_address;
501 legacy_settings->autoneg
502 = link_ksettings->base.autoneg;
503 legacy_settings->mdio_support
504 = link_ksettings->base.mdio_support;
505 legacy_settings->eth_tp_mdix
506 = link_ksettings->base.eth_tp_mdix;
507 legacy_settings->eth_tp_mdix_ctrl
508 = link_ksettings->base.eth_tp_mdix_ctrl;
509 return retval;
510}
511
512/* number of 32-bit words to store the user's link mode bitmaps */
513#define __ETHTOOL_LINK_MODE_MASK_NU32 \
514 DIV_ROUND_UP(__ETHTOOL_LINK_MODE_MASK_NBITS, 32)
515
516/* layout of the struct passed from/to userland */
517struct ethtool_link_usettings {
518 struct ethtool_link_settings base;
519 struct {
520 __u32 supported[__ETHTOOL_LINK_MODE_MASK_NU32];
521 __u32 advertising[__ETHTOOL_LINK_MODE_MASK_NU32];
522 __u32 lp_advertising[__ETHTOOL_LINK_MODE_MASK_NU32];
523 } link_modes;
524};
525
526/* Internal kernel helper to query a device ethtool_link_settings.
527 *
528 * Backward compatibility note: for compatibility with legacy drivers
529 * that implement only the ethtool_cmd API, this has to work with both
530 * drivers implementing get_link_ksettings API and drivers
531 * implementing get_settings API. When drivers implement get_settings
532 * and report ethtool_cmd deprecated fields
533 * (transceiver/maxrxpkt/maxtxpkt), these fields are silently ignored
534 * because the resulting struct ethtool_link_settings does not report them.
535 */
536int __ethtool_get_link_ksettings(struct net_device *dev,
537 struct ethtool_link_ksettings *link_ksettings)
538{
539 int err;
540 struct ethtool_cmd cmd;
541
392 ASSERT_RTNL(); 542 ASSERT_RTNL();
393 543
544 if (dev->ethtool_ops->get_link_ksettings) {
545 memset(link_ksettings, 0, sizeof(*link_ksettings));
546 return dev->ethtool_ops->get_link_ksettings(dev,
547 link_ksettings);
548 }
549
550 /* driver doesn't support %ethtool_link_ksettings API. revert to
551 * legacy %ethtool_cmd API, unless it's not supported either.
552 * TODO: remove when ethtool_ops::get_settings disappears internally
553 */
394 if (!dev->ethtool_ops->get_settings) 554 if (!dev->ethtool_ops->get_settings)
395 return -EOPNOTSUPP; 555 return -EOPNOTSUPP;
396 556
397 memset(cmd, 0, sizeof(struct ethtool_cmd)); 557 memset(&cmd, 0, sizeof(cmd));
398 cmd->cmd = ETHTOOL_GSET; 558 cmd.cmd = ETHTOOL_GSET;
399 return dev->ethtool_ops->get_settings(dev, cmd); 559 err = dev->ethtool_ops->get_settings(dev, &cmd);
560 if (err < 0)
561 return err;
562
563 /* we ignore deprecated fields transceiver/maxrxpkt/maxtxpkt
564 */
565 convert_legacy_settings_to_link_ksettings(link_ksettings, &cmd);
566 return err;
567}
568EXPORT_SYMBOL(__ethtool_get_link_ksettings);
569
570/* convert ethtool_link_usettings in user space to a kernel internal
571 * ethtool_link_ksettings. return 0 on success, errno on error.
572 */
573static int load_link_ksettings_from_user(struct ethtool_link_ksettings *to,
574 const void __user *from)
575{
576 struct ethtool_link_usettings link_usettings;
577
578 if (copy_from_user(&link_usettings, from, sizeof(link_usettings)))
579 return -EFAULT;
580
581 memcpy(&to->base, &link_usettings.base, sizeof(to->base));
582 bitmap_from_u32array(to->link_modes.supported,
583 __ETHTOOL_LINK_MODE_MASK_NBITS,
584 link_usettings.link_modes.supported,
585 __ETHTOOL_LINK_MODE_MASK_NU32);
586 bitmap_from_u32array(to->link_modes.advertising,
587 __ETHTOOL_LINK_MODE_MASK_NBITS,
588 link_usettings.link_modes.advertising,
589 __ETHTOOL_LINK_MODE_MASK_NU32);
590 bitmap_from_u32array(to->link_modes.lp_advertising,
591 __ETHTOOL_LINK_MODE_MASK_NBITS,
592 link_usettings.link_modes.lp_advertising,
593 __ETHTOOL_LINK_MODE_MASK_NU32);
594
595 return 0;
400} 596}
401EXPORT_SYMBOL(__ethtool_get_settings);
402 597
403static int ethtool_get_settings(struct net_device *dev, void __user *useraddr) 598/* convert a kernel internal ethtool_link_ksettings to
599 * ethtool_link_usettings in user space. return 0 on success, errno on
600 * error.
601 */
602static int
603store_link_ksettings_for_user(void __user *to,
604 const struct ethtool_link_ksettings *from)
605{
606 struct ethtool_link_usettings link_usettings;
607
608 memcpy(&link_usettings.base, &from->base, sizeof(link_usettings));
609 bitmap_to_u32array(link_usettings.link_modes.supported,
610 __ETHTOOL_LINK_MODE_MASK_NU32,
611 from->link_modes.supported,
612 __ETHTOOL_LINK_MODE_MASK_NBITS);
613 bitmap_to_u32array(link_usettings.link_modes.advertising,
614 __ETHTOOL_LINK_MODE_MASK_NU32,
615 from->link_modes.advertising,
616 __ETHTOOL_LINK_MODE_MASK_NBITS);
617 bitmap_to_u32array(link_usettings.link_modes.lp_advertising,
618 __ETHTOOL_LINK_MODE_MASK_NU32,
619 from->link_modes.lp_advertising,
620 __ETHTOOL_LINK_MODE_MASK_NBITS);
621
622 if (copy_to_user(to, &link_usettings, sizeof(link_usettings)))
623 return -EFAULT;
624
625 return 0;
626}
627
628/* Query device for its ethtool_link_settings.
629 *
630 * Backward compatibility note: this function must fail when driver
631 * does not implement ethtool::get_link_ksettings, even if legacy
632 * ethtool_ops::get_settings is implemented. This tells new versions
633 * of ethtool that they should use the legacy API %ETHTOOL_GSET for
634 * this driver, so that they can correctly access the ethtool_cmd
635 * deprecated fields (transceiver/maxrxpkt/maxtxpkt), until no driver
636 * implements ethtool_ops::get_settings anymore.
637 */
638static int ethtool_get_link_ksettings(struct net_device *dev,
639 void __user *useraddr)
404{ 640{
405 int err; 641 int err = 0;
406 struct ethtool_cmd cmd; 642 struct ethtool_link_ksettings link_ksettings;
643
644 ASSERT_RTNL();
645
646 if (!dev->ethtool_ops->get_link_ksettings)
647 return -EOPNOTSUPP;
648
649 /* handle bitmap nbits handshake */
650 if (copy_from_user(&link_ksettings.base, useraddr,
651 sizeof(link_ksettings.base)))
652 return -EFAULT;
653
654 if (__ETHTOOL_LINK_MODE_MASK_NU32
655 != link_ksettings.base.link_mode_masks_nwords) {
656 /* wrong link mode nbits requested */
657 memset(&link_ksettings, 0, sizeof(link_ksettings));
658 /* keep cmd field reset to 0 */
659 /* send back number of words required as negative val */
660 compiletime_assert(__ETHTOOL_LINK_MODE_MASK_NU32 <= S8_MAX,
661 "need too many bits for link modes!");
662 link_ksettings.base.link_mode_masks_nwords
663 = -((s8)__ETHTOOL_LINK_MODE_MASK_NU32);
664
665 /* copy the base fields back to user, not the link
666 * mode bitmaps
667 */
668 if (copy_to_user(useraddr, &link_ksettings.base,
669 sizeof(link_ksettings.base)))
670 return -EFAULT;
671
672 return 0;
673 }
674
675 /* handshake successful: user/kernel agree on
676 * link_mode_masks_nwords
677 */
407 678
408 err = __ethtool_get_settings(dev, &cmd); 679 memset(&link_ksettings, 0, sizeof(link_ksettings));
680 err = dev->ethtool_ops->get_link_ksettings(dev, &link_ksettings);
409 if (err < 0) 681 if (err < 0)
410 return err; 682 return err;
411 683
684 /* make sure we tell the right values to user */
685 link_ksettings.base.cmd = ETHTOOL_GLINKSETTINGS;
686 link_ksettings.base.link_mode_masks_nwords
687 = __ETHTOOL_LINK_MODE_MASK_NU32;
688
689 return store_link_ksettings_for_user(useraddr, &link_ksettings);
690}
691
692/* Update device ethtool_link_settings.
693 *
694 * Backward compatibility note: this function must fail when driver
695 * does not implement ethtool::set_link_ksettings, even if legacy
696 * ethtool_ops::set_settings is implemented. This tells new versions
697 * of ethtool that they should use the legacy API %ETHTOOL_SSET for
698 * this driver, so that they can correctly update the ethtool_cmd
699 * deprecated fields (transceiver/maxrxpkt/maxtxpkt), until no driver
700 * implements ethtool_ops::get_settings anymore.
701 */
702static int ethtool_set_link_ksettings(struct net_device *dev,
703 void __user *useraddr)
704{
705 int err;
706 struct ethtool_link_ksettings link_ksettings;
707
708 ASSERT_RTNL();
709
710 if (!dev->ethtool_ops->set_link_ksettings)
711 return -EOPNOTSUPP;
712
713 /* make sure nbits field has expected value */
714 if (copy_from_user(&link_ksettings.base, useraddr,
715 sizeof(link_ksettings.base)))
716 return -EFAULT;
717
718 if (__ETHTOOL_LINK_MODE_MASK_NU32
719 != link_ksettings.base.link_mode_masks_nwords)
720 return -EINVAL;
721
722 /* copy the whole structure, now that we know it has expected
723 * format
724 */
725 err = load_link_ksettings_from_user(&link_ksettings, useraddr);
726 if (err)
727 return err;
728
729 /* re-check nwords field, just in case */
730 if (__ETHTOOL_LINK_MODE_MASK_NU32
731 != link_ksettings.base.link_mode_masks_nwords)
732 return -EINVAL;
733
734 return dev->ethtool_ops->set_link_ksettings(dev, &link_ksettings);
735}
736
737static void
738warn_incomplete_ethtool_legacy_settings_conversion(const char *details)
739{
740 char name[sizeof(current->comm)];
741
742 pr_info_once("warning: `%s' uses legacy ethtool link settings API, %s\n",
743 get_task_comm(name, current), details);
744}
745
746/* Query device for its ethtool_cmd settings.
747 *
748 * Backward compatibility note: for compatibility with legacy ethtool,
749 * this has to work with both drivers implementing get_link_ksettings
750 * API and drivers implementing get_settings API. When drivers
751 * implement get_link_ksettings and report higher link mode bits, a
752 * kernel warning is logged once (with name of 1st driver/device) to
753 * recommend user to upgrade ethtool, but the command is successful
754 * (only the lower link mode bits reported back to user).
755 */
756static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
757{
758 struct ethtool_cmd cmd;
759
760 ASSERT_RTNL();
761
762 if (dev->ethtool_ops->get_link_ksettings) {
763 /* First, use link_ksettings API if it is supported */
764 int err;
765 struct ethtool_link_ksettings link_ksettings;
766
767 memset(&link_ksettings, 0, sizeof(link_ksettings));
768 err = dev->ethtool_ops->get_link_ksettings(dev,
769 &link_ksettings);
770 if (err < 0)
771 return err;
772 if (!convert_link_ksettings_to_legacy_settings(&cmd,
773 &link_ksettings))
774 warn_incomplete_ethtool_legacy_settings_conversion(
775 "link modes are only partially reported");
776
777 /* send a sensible cmd tag back to user */
778 cmd.cmd = ETHTOOL_GSET;
779 } else {
780 /* driver doesn't support %ethtool_link_ksettings
781 * API. revert to legacy %ethtool_cmd API, unless it's
782 * not supported either.
783 */
784 int err;
785
786 if (!dev->ethtool_ops->get_settings)
787 return -EOPNOTSUPP;
788
789 memset(&cmd, 0, sizeof(cmd));
790 cmd.cmd = ETHTOOL_GSET;
791 err = dev->ethtool_ops->get_settings(dev, &cmd);
792 if (err < 0)
793 return err;
794 }
795
412 if (copy_to_user(useraddr, &cmd, sizeof(cmd))) 796 if (copy_to_user(useraddr, &cmd, sizeof(cmd)))
413 return -EFAULT; 797 return -EFAULT;
798
414 return 0; 799 return 0;
415} 800}
416 801
802/* Update device link settings with given ethtool_cmd.
803 *
804 * Backward compatibility note: for compatibility with legacy ethtool,
805 * this has to work with both drivers implementing set_link_ksettings
806 * API and drivers implementing set_settings API. When drivers
807 * implement set_link_ksettings and user's request updates deprecated
808 * ethtool_cmd fields (transceiver/maxrxpkt/maxtxpkt), a kernel
809 * warning is logged once (with name of 1st driver/device) to
810 * recommend user to upgrade ethtool, and the request is rejected.
811 */
417static int ethtool_set_settings(struct net_device *dev, void __user *useraddr) 812static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
418{ 813{
419 struct ethtool_cmd cmd; 814 struct ethtool_cmd cmd;
420 815
421 if (!dev->ethtool_ops->set_settings) 816 ASSERT_RTNL();
422 return -EOPNOTSUPP;
423 817
424 if (copy_from_user(&cmd, useraddr, sizeof(cmd))) 818 if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
425 return -EFAULT; 819 return -EFAULT;
426 820
821 /* first, try new %ethtool_link_ksettings API. */
822 if (dev->ethtool_ops->set_link_ksettings) {
823 struct ethtool_link_ksettings link_ksettings;
824
825 if (!convert_legacy_settings_to_link_ksettings(&link_ksettings,
826 &cmd))
827 return -EINVAL;
828
829 link_ksettings.base.cmd = ETHTOOL_SLINKSETTINGS;
830 link_ksettings.base.link_mode_masks_nwords
831 = __ETHTOOL_LINK_MODE_MASK_NU32;
832 return dev->ethtool_ops->set_link_ksettings(dev,
833 &link_ksettings);
834 }
835
836 /* legacy %ethtool_cmd API */
837
838 /* TODO: return -EOPNOTSUPP when ethtool_ops::get_settings
839 * disappears internally
840 */
841
842 if (!dev->ethtool_ops->set_settings)
843 return -EOPNOTSUPP;
844
427 return dev->ethtool_ops->set_settings(dev, &cmd); 845 return dev->ethtool_ops->set_settings(dev, &cmd);
428} 846}
429 847
@@ -2252,6 +2670,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
2252 case ETHTOOL_PERQUEUE: 2670 case ETHTOOL_PERQUEUE:
2253 rc = ethtool_set_per_queue(dev, useraddr); 2671 rc = ethtool_set_per_queue(dev, useraddr);
2254 break; 2672 break;
2673 case ETHTOOL_GLINKSETTINGS:
2674 rc = ethtool_get_link_ksettings(dev, useraddr);
2675 break;
2676 case ETHTOOL_SLINKSETTINGS:
2677 rc = ethtool_set_link_ksettings(dev, useraddr);
2678 break;
2255 default: 2679 default:
2256 rc = -EOPNOTSUPP; 2680 rc = -EOPNOTSUPP;
2257 } 2681 }
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index 4ae17c3166fc..2b3f76fe65f4 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -198,9 +198,10 @@ static ssize_t speed_show(struct device *dev,
198 return restart_syscall(); 198 return restart_syscall();
199 199
200 if (netif_running(netdev)) { 200 if (netif_running(netdev)) {
201 struct ethtool_cmd cmd; 201 struct ethtool_link_ksettings cmd;
202 if (!__ethtool_get_settings(netdev, &cmd)) 202
203 ret = sprintf(buf, fmt_dec, ethtool_cmd_speed(&cmd)); 203 if (!__ethtool_get_link_ksettings(netdev, &cmd))
204 ret = sprintf(buf, fmt_dec, cmd.base.speed);
204 } 205 }
205 rtnl_unlock(); 206 rtnl_unlock();
206 return ret; 207 return ret;
@@ -217,10 +218,12 @@ static ssize_t duplex_show(struct device *dev,
217 return restart_syscall(); 218 return restart_syscall();
218 219
219 if (netif_running(netdev)) { 220 if (netif_running(netdev)) {
220 struct ethtool_cmd cmd; 221 struct ethtool_link_ksettings cmd;
221 if (!__ethtool_get_settings(netdev, &cmd)) { 222
223 if (!__ethtool_get_link_ksettings(netdev, &cmd)) {
222 const char *duplex; 224 const char *duplex;
223 switch (cmd.duplex) { 225
226 switch (cmd.base.duplex) {
224 case DUPLEX_HALF: 227 case DUPLEX_HALF:
225 duplex = "half"; 228 duplex = "half";
226 break; 229 break;
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index b7e7851ddc5d..d41b1074cb2d 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -557,9 +557,8 @@ static int prb_calc_retire_blk_tmo(struct packet_sock *po,
557{ 557{
558 struct net_device *dev; 558 struct net_device *dev;
559 unsigned int mbits = 0, msec = 0, div = 0, tmo = 0; 559 unsigned int mbits = 0, msec = 0, div = 0, tmo = 0;
560 struct ethtool_cmd ecmd; 560 struct ethtool_link_ksettings ecmd;
561 int err; 561 int err;
562 u32 speed;
563 562
564 rtnl_lock(); 563 rtnl_lock();
565 dev = __dev_get_by_index(sock_net(&po->sk), po->ifindex); 564 dev = __dev_get_by_index(sock_net(&po->sk), po->ifindex);
@@ -567,19 +566,19 @@ static int prb_calc_retire_blk_tmo(struct packet_sock *po,
567 rtnl_unlock(); 566 rtnl_unlock();
568 return DEFAULT_PRB_RETIRE_TOV; 567 return DEFAULT_PRB_RETIRE_TOV;
569 } 568 }
570 err = __ethtool_get_settings(dev, &ecmd); 569 err = __ethtool_get_link_ksettings(dev, &ecmd);
571 speed = ethtool_cmd_speed(&ecmd);
572 rtnl_unlock(); 570 rtnl_unlock();
573 if (!err) { 571 if (!err) {
574 /* 572 /*
575 * If the link speed is so slow you don't really 573 * If the link speed is so slow you don't really
576 * need to worry about perf anyways 574 * need to worry about perf anyways
577 */ 575 */
578 if (speed < SPEED_1000 || speed == SPEED_UNKNOWN) { 576 if (ecmd.base.speed < SPEED_1000 ||
577 ecmd.base.speed == SPEED_UNKNOWN) {
579 return DEFAULT_PRB_RETIRE_TOV; 578 return DEFAULT_PRB_RETIRE_TOV;
580 } else { 579 } else {
581 msec = 1; 580 msec = 1;
582 div = speed / 1000; 581 div = ecmd.base.speed / 1000;
583 } 582 }
584 } 583 }
585 584