diff options
Diffstat (limited to 'net/dsa/slave.c')
| -rw-r--r-- | net/dsa/slave.c | 61 | 
1 files changed, 60 insertions, 1 deletions
diff --git a/net/dsa/slave.c b/net/dsa/slave.c index f52307296de4..18561af7a8f1 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -21,6 +21,7 @@  #include <net/tc_act/tc_mirred.h>  #include <linux/if_bridge.h>  #include <linux/netpoll.h> +#include <linux/ptp_classify.h>  #include "dsa_priv.h" @@ -255,6 +256,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)  { +	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)  		return -ENODEV; @@ -385,6 +402,30 @@ static inline netdev_tx_t dsa_slave_netpoll_send_skb(struct net_device *dev,  	return NETDEV_TX_OK;  } +static void dsa_skb_tx_timestamp(struct dsa_slave_priv *p, +				 struct sk_buff *skb) +{ +	struct dsa_switch *ds = p->dp->ds; +	struct sk_buff *clone; +	unsigned int type; + +	type = ptp_classify_raw(skb); +	if (type == PTP_CLASS_NONE) +		return; + +	if (!ds->ops->port_txtstamp) +		return; + +	clone = skb_clone_sk(skb); +	if (!clone) +		return; + +	if (ds->ops->port_txtstamp(ds, p->dp->index, clone, type)) +		return; + +	kfree_skb(clone); +} +  static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)  {  	struct dsa_slave_priv *p = netdev_priv(dev); @@ -397,6 +438,11 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)  	s->tx_bytes += skb->len;  	u64_stats_update_end(&s->syncp); +	/* Identify PTP protocol packets, clone them, and pass them to the +	 * switch driver +	 */ +	dsa_skb_tx_timestamp(p, skb); +  	/* Transmit function may have to reallocate the original SKB,  	 * in which case it must have freed it. Only free it here on error.  	 */ @@ -559,7 +605,7 @@ static int dsa_slave_get_sset_count(struct net_device *dev, int sset)  		count = 4;  		if (ds->ops->get_sset_count) -			count += ds->ops->get_sset_count(ds); +			count += ds->ops->get_sset_count(ds, dp->index);  		return count;  	} @@ -918,6 +964,18 @@ static int dsa_slave_set_rxnfc(struct net_device *dev,  	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 = {  	.get_drvinfo		= dsa_slave_get_drvinfo,  	.get_regs_len		= dsa_slave_get_regs_len, @@ -938,6 +996,7 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {  	.set_link_ksettings	= phy_ethtool_set_link_ksettings,  	.get_rxnfc		= dsa_slave_get_rxnfc,  	.set_rxnfc		= dsa_slave_set_rxnfc, +	.get_ts_info		= dsa_slave_get_ts_info,  };  /* legacy way, bypassing the bridge *****************************************/  | 
