net: dsa: forward hardware timestamping ioctls to switch driver

This patch adds support to the dsa slave network device so that
switch drivers can implement the SIOC[GS]HWTSTAMP ioctls and the
ethtool timestamp-info interface.

Signed-off-by: Brandon Streiff <brandon.streiff@ni.com>
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Brandon Streiff 2018-02-14 01:07:48 +01:00 committed by David S. Miller
parent 4eb3be2937
commit 0336369d3a
2 changed files with 44 additions and 0 deletions

View File

@ -19,6 +19,7 @@
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/net_tstamp.h>
#include <net/devlink.h> #include <net/devlink.h>
#include <net/switchdev.h> #include <net/switchdev.h>
@ -367,6 +368,12 @@ struct dsa_switch_ops {
int (*set_wol)(struct dsa_switch *ds, int port, int (*set_wol)(struct dsa_switch *ds, int port,
struct ethtool_wolinfo *w); struct ethtool_wolinfo *w);
/*
* ethtool timestamp info
*/
int (*get_ts_info)(struct dsa_switch *ds, int port,
struct ethtool_ts_info *ts);
/* /*
* Suspend and resume * Suspend and resume
*/ */
@ -469,6 +476,14 @@ struct dsa_switch_ops {
int port, struct net_device *br); int port, struct net_device *br);
void (*crosschip_bridge_leave)(struct dsa_switch *ds, int sw_index, void (*crosschip_bridge_leave)(struct dsa_switch *ds, int sw_index,
int port, struct net_device *br); int port, struct net_device *br);
/*
* PTP functionality
*/
int (*port_hwtstamp_get)(struct dsa_switch *ds, int port,
struct ifreq *ifr);
int (*port_hwtstamp_set)(struct dsa_switch *ds, int port,
struct ifreq *ifr);
}; };
struct dsa_switch_driver { struct dsa_switch_driver {

View File

@ -255,6 +255,22 @@ dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{ {
struct dsa_slave_priv *p = netdev_priv(dev);
struct dsa_switch *ds = p->dp->ds;
int port = p->dp->index;
/* Pass through to switch driver if it supports timestamping */
switch (cmd) {
case SIOCGHWTSTAMP:
if (ds->ops->port_hwtstamp_get)
return ds->ops->port_hwtstamp_get(ds, port, ifr);
break;
case SIOCSHWTSTAMP:
if (ds->ops->port_hwtstamp_set)
return ds->ops->port_hwtstamp_set(ds, port, ifr);
break;
}
if (!dev->phydev) if (!dev->phydev)
return -ENODEV; return -ENODEV;
@ -918,6 +934,18 @@ static int dsa_slave_set_rxnfc(struct net_device *dev,
return ds->ops->set_rxnfc(ds, dp->index, nfc); return ds->ops->set_rxnfc(ds, dp->index, nfc);
} }
static int dsa_slave_get_ts_info(struct net_device *dev,
struct ethtool_ts_info *ts)
{
struct dsa_slave_priv *p = netdev_priv(dev);
struct dsa_switch *ds = p->dp->ds;
if (!ds->ops->get_ts_info)
return -EOPNOTSUPP;
return ds->ops->get_ts_info(ds, p->dp->index, ts);
}
static const struct ethtool_ops dsa_slave_ethtool_ops = { static const struct ethtool_ops dsa_slave_ethtool_ops = {
.get_drvinfo = dsa_slave_get_drvinfo, .get_drvinfo = dsa_slave_get_drvinfo,
.get_regs_len = dsa_slave_get_regs_len, .get_regs_len = dsa_slave_get_regs_len,
@ -938,6 +966,7 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
.set_link_ksettings = phy_ethtool_set_link_ksettings, .set_link_ksettings = phy_ethtool_set_link_ksettings,
.get_rxnfc = dsa_slave_get_rxnfc, .get_rxnfc = dsa_slave_get_rxnfc,
.set_rxnfc = dsa_slave_set_rxnfc, .set_rxnfc = dsa_slave_set_rxnfc,
.get_ts_info = dsa_slave_get_ts_info,
}; };
/* legacy way, bypassing the bridge *****************************************/ /* legacy way, bypassing the bridge *****************************************/