aboutsummaryrefslogtreecommitdiffstats
path: root/net/core/ethtool.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2011-04-06 15:27:34 -0400
committerDavid S. Miller <davem@davemloft.net>2011-04-06 15:27:34 -0400
commit4c844d97d269a7ec4a6ba7d530aa876ac64dfb76 (patch)
tree67198ffbe0d8652f9a26548a7435f7514912a8cc /net/core/ethtool.c
parent66ee33bfda6237b009b6fb0e48690e31800ff334 (diff)
parentc5e129ac2fc72c119b85db79a629de66332f136d (diff)
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/bwh/sfc-next-2.6
Diffstat (limited to 'net/core/ethtool.c')
-rw-r--r--net/core/ethtool.c55
1 files changed, 53 insertions, 2 deletions
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 719670ae199c..1b7fa984de7d 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)