From 854877d2e30d5f7bb6a591186a2d26b2d69aa185 Mon Sep 17 00:00:00 2001 From: Richard Cochran Date: Tue, 3 Apr 2012 22:59:17 +0000 Subject: ethtool: Introduce a method for getting time stamping capabilities. This commit adds a new ethtool ioctl that exposes the SO_TIMESTAMPING capabilities of a network interface. In addition, user space programs can use this ioctl to discover the PTP Hardware Clock (PHC) device associated with the interface. Since software receive time stamps are handled by the stack, the generic ethtool code can answer the query correctly in case the MAC or PHY drivers lack special time stamping features. Signed-off-by: Richard Cochran Reviewed-by: Ben Hutchings Signed-off-by: David S. Miller --- net/core/ethtool.c | 48 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 777c94ce2c3c..ef951145cbe1 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include #include @@ -1652,6 +1654,40 @@ out: return ret; } +static int ethtool_get_ts_info(struct net_device *dev, void __user *useraddr) +{ + int err = 0; + struct ethtool_ts_info info; + const struct ethtool_ops *ops = dev->ethtool_ops; + struct phy_device *phydev = dev->phydev; + + memset(&info, 0, sizeof(info)); + info.cmd = ETHTOOL_GET_TS_INFO; + + if (phydev && phydev->drv && phydev->drv->ts_info) { + + err = phydev->drv->ts_info(phydev, &info); + + } else if (dev->ethtool_ops && dev->ethtool_ops->get_ts_info) { + + err = ops->get_ts_info(dev, &info); + + } else { + info.so_timestamping = + SOF_TIMESTAMPING_RX_SOFTWARE | + SOF_TIMESTAMPING_SOFTWARE; + info.phc_index = -1; + } + + if (err) + return err; + + if (copy_to_user(useraddr, &info, sizeof(info))) + err = -EFAULT; + + return err; +} + /* The main entry point in this file. Called from net/core/dev.c */ int dev_ethtool(struct net *net, struct ifreq *ifr) @@ -1669,11 +1705,13 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) return -EFAULT; if (!dev->ethtool_ops) { - /* ETHTOOL_GDRVINFO does not require any driver support. - * It is also unprivileged and does not change anything, - * so we can take a shortcut to it. */ + /* A few commands do not require any driver support, + * are unprivileged, and do not change anything, so we + * can take a shortcut to them. */ if (ethcmd == ETHTOOL_GDRVINFO) return ethtool_get_drvinfo(dev, useraddr); + else if (ethcmd == ETHTOOL_GET_TS_INFO) + return ethtool_get_ts_info(dev, useraddr); else return -EOPNOTSUPP; } @@ -1703,6 +1741,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) case ETHTOOL_GRXCLSRULE: case ETHTOOL_GRXCLSRLALL: case ETHTOOL_GFEATURES: + case ETHTOOL_GET_TS_INFO: break; default: if (!capable(CAP_NET_ADMIN)) @@ -1874,6 +1913,9 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) case ETHTOOL_GET_DUMP_DATA: rc = ethtool_get_dump_data(dev, useraddr); break; + case ETHTOOL_GET_TS_INFO: + rc = ethtool_get_ts_info(dev, useraddr); + break; default: rc = -EOPNOTSUPP; } -- cgit v1.2.3