aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ethtool.h30
-rw-r--r--net/core/ethtool.c55
2 files changed, 82 insertions, 3 deletions
diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h
index ead7dcb1bf1e..c04d1316d221 100644
--- a/include/linux/ethtool.h
+++ b/include/linux/ethtool.h
@@ -663,6 +663,22 @@ struct ethtool_rx_ntuple_list {
663 unsigned int count; 663 unsigned int count;
664}; 664};
665 665
666/**
667 * enum ethtool_phys_id_state - indicator state for physical identification
668 * @ETHTOOL_ID_INACTIVE: Physical ID indicator should be deactivated
669 * @ETHTOOL_ID_ACTIVE: Physical ID indicator should be activated
670 * @ETHTOOL_ID_ON: LED should be turned on (used iff %ETHTOOL_ID_ACTIVE
671 * is not supported)
672 * @ETHTOOL_ID_OFF: LED should be turned off (used iff %ETHTOOL_ID_ACTIVE
673 * is not supported)
674 */
675enum ethtool_phys_id_state {
676 ETHTOOL_ID_INACTIVE,
677 ETHTOOL_ID_ACTIVE,
678 ETHTOOL_ID_ON,
679 ETHTOOL_ID_OFF
680};
681
666struct net_device; 682struct net_device;
667 683
668/* Some generic methods drivers may use in their ethtool_ops */ 684/* Some generic methods drivers may use in their ethtool_ops */
@@ -741,7 +757,18 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported);
741 * segmentation offload on or off. Returns a negative error code or zero. 757 * segmentation offload on or off. Returns a negative error code or zero.
742 * @self_test: Run specified self-tests 758 * @self_test: Run specified self-tests
743 * @get_strings: Return a set of strings that describe the requested objects 759 * @get_strings: Return a set of strings that describe the requested objects
744 * @phys_id: Identify the physical device, e.g. by flashing an LED 760 * @set_phys_id: Identify the physical devices, e.g. by flashing an LED
761 * attached to it. The implementation may update the indicator
762 * asynchronously or synchronously, but in either case it must return
763 * quickly. It is initially called with the argument %ETHTOOL_ID_ACTIVE,
764 * and must either activate asynchronous updates or return -%EINVAL.
765 * If it returns -%EINVAL then it will be called again at intervals with
766 * argument %ETHTOOL_ID_ON or %ETHTOOL_ID_OFF and should set the state of
767 * the indicator accordingly. Finally, it is called with the argument
768 * %ETHTOOL_ID_INACTIVE and must deactivate the indicator. Returns a
769 * negative error code or zero.
770 * @phys_id: Deprecated in favour of @set_phys_id.
771 * Identify the physical device, e.g. by flashing an LED
745 * attached to it until interrupted by a signal or the given time 772 * attached to it until interrupted by a signal or the given time
746 * (in seconds) elapses. If the given time is zero, use a default 773 * (in seconds) elapses. If the given time is zero, use a default
747 * time limit. Returns a negative error code or zero. Being 774 * time limit. Returns a negative error code or zero. Being
@@ -830,6 +857,7 @@ struct ethtool_ops {
830 int (*set_tso)(struct net_device *, u32); 857 int (*set_tso)(struct net_device *, u32);
831 void (*self_test)(struct net_device *, struct ethtool_test *, u64 *); 858 void (*self_test)(struct net_device *, struct ethtool_test *, u64 *);
832 void (*get_strings)(struct net_device *, u32 stringset, u8 *); 859 void (*get_strings)(struct net_device *, u32 stringset, u8 *);
860 int (*set_phys_id)(struct net_device *, enum ethtool_phys_id_state);
833 int (*phys_id)(struct net_device *, u32); 861 int (*phys_id)(struct net_device *, u32);
834 void (*get_ethtool_stats)(struct net_device *, 862 void (*get_ethtool_stats)(struct net_device *,
835 struct ethtool_stats *, u64 *); 863 struct ethtool_stats *, u64 *);
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 74ead9eca126..1c95f0fb8b3a 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -21,6 +21,8 @@
21#include <linux/uaccess.h> 21#include <linux/uaccess.h>
22#include <linux/vmalloc.h> 22#include <linux/vmalloc.h>
23#include <linux/slab.h> 23#include <linux/slab.h>
24#include <linux/rtnetlink.h>
25#include <linux/sched.h>
24 26
25/* 27/*
26 * Some useful ethtool_ops methods that're device independent. 28 * Some useful ethtool_ops methods that're device independent.
@@ -1618,14 +1620,63 @@ out:
1618static int ethtool_phys_id(struct net_device *dev, void __user *useraddr) 1620static int ethtool_phys_id(struct net_device *dev, void __user *useraddr)
1619{ 1621{
1620 struct ethtool_value id; 1622 struct ethtool_value id;
1623 static bool busy;
1624 int rc;
1621 1625
1622 if (!dev->ethtool_ops->phys_id) 1626 if (!dev->ethtool_ops->set_phys_id && !dev->ethtool_ops->phys_id)
1623 return -EOPNOTSUPP; 1627 return -EOPNOTSUPP;
1624 1628
1629 if (busy)
1630 return -EBUSY;
1631
1625 if (copy_from_user(&id, useraddr, sizeof(id))) 1632 if (copy_from_user(&id, useraddr, sizeof(id)))
1626 return -EFAULT; 1633 return -EFAULT;
1627 1634
1628 return dev->ethtool_ops->phys_id(dev, id.data); 1635 if (!dev->ethtool_ops->set_phys_id)
1636 /* Do it the old way */
1637 return dev->ethtool_ops->phys_id(dev, id.data);
1638
1639 rc = dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_ACTIVE);
1640 if (rc && rc != -EINVAL)
1641 return rc;
1642
1643 /* Drop the RTNL lock while waiting, but prevent reentry or
1644 * removal of the device.
1645 */
1646 busy = true;
1647 dev_hold(dev);
1648 rtnl_unlock();
1649
1650 if (rc == 0) {
1651 /* Driver will handle this itself */
1652 schedule_timeout_interruptible(
1653 id.data ? id.data : MAX_SCHEDULE_TIMEOUT);
1654 } else {
1655 /* Driver expects to be called periodically */
1656 do {
1657 rtnl_lock();
1658 rc = dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_ON);
1659 rtnl_unlock();
1660 if (rc)
1661 break;
1662 schedule_timeout_interruptible(HZ / 2);
1663
1664 rtnl_lock();
1665 rc = dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_OFF);
1666 rtnl_unlock();
1667 if (rc)
1668 break;
1669 schedule_timeout_interruptible(HZ / 2);
1670 } while (!signal_pending(current) &&
1671 (id.data == 0 || --id.data != 0));
1672 }
1673
1674 rtnl_lock();
1675 dev_put(dev);
1676 busy = false;
1677
1678 (void)dev->ethtool_ops->set_phys_id(dev, ETHTOOL_ID_INACTIVE);
1679 return rc;
1629} 1680}
1630 1681
1631static int ethtool_get_stats(struct net_device *dev, void __user *useraddr) 1682static int ethtool_get_stats(struct net_device *dev, void __user *useraddr)