aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2018-02-14 14:33:38 -0500
committerDavid S. Miller <davem@davemloft.net>2018-02-14 14:33:38 -0500
commit64da58528bdbdba171cf6c6ffaf39c2ee75e3a10 (patch)
treed779fcb16a984e9c1070269050d885c2d73ce120 /net
parente0f9759f530bf789e984961dce79f525b151ecf3 (diff)
parenta2e47134e577713add97124afd812bc3f93627fb (diff)
Merge branch 'PTP-support-for-DSA-and-mv88e6xxx-driver'
Andrew Lunn says: ==================== PTP support for DSA and mv88e6xxx driver. This patchset adds support for using the PTP hardware in switches supported by the mv88e6xxx driver. The code was produces in collaboration with Brandon Streiff doing the initial implementation, and then Richard Cochran and Andrew Lunn making further changes and cleanups. The code is sufficient to use ptp4l on a single DSA interface, either as a master or a slave. Due to the use of an MDIO bus to access the switch, reading hardware timestamps is slower than what ptp4l expects. Thus it is necessary to use the option --tx_timestamp_timeout=32. Heavy use of ethtool -S, or bridge fdb show can also upset ptp4l. Patches to address this will follow. Further work is requires to support bridges using Boundary Clock or Transparent Clock mode. Since the RFC, an overflow bug has been fixed. Brandon Streiff has also Acked-by: the updates to his initial patchset. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/dsa/dsa.c36
-rw-r--r--net/dsa/slave.c59
2 files changed, 95 insertions, 0 deletions
diff --git a/net/dsa/dsa.c b/net/dsa/dsa.c
index 6a9d0f50fbee..e63c554e0623 100644
--- a/net/dsa/dsa.c
+++ b/net/dsa/dsa.c
@@ -23,6 +23,7 @@
23#include <linux/netdevice.h> 23#include <linux/netdevice.h>
24#include <linux/sysfs.h> 24#include <linux/sysfs.h>
25#include <linux/phy_fixed.h> 25#include <linux/phy_fixed.h>
26#include <linux/ptp_classify.h>
26#include <linux/gpio/consumer.h> 27#include <linux/gpio/consumer.h>
27#include <linux/etherdevice.h> 28#include <linux/etherdevice.h>
28 29
@@ -122,6 +123,38 @@ struct net_device *dsa_dev_to_net_device(struct device *dev)
122} 123}
123EXPORT_SYMBOL_GPL(dsa_dev_to_net_device); 124EXPORT_SYMBOL_GPL(dsa_dev_to_net_device);
124 125
126/* Determine if we should defer delivery of skb until we have a rx timestamp.
127 *
128 * Called from dsa_switch_rcv. For now, this will only work if tagging is
129 * enabled on the switch. Normally the MAC driver would retrieve the hardware
130 * timestamp when it reads the packet out of the hardware. However in a DSA
131 * switch, the DSA driver owning the interface to which the packet is
132 * delivered is never notified unless we do so here.
133 */
134static bool dsa_skb_defer_rx_timestamp(struct dsa_slave_priv *p,
135 struct sk_buff *skb)
136{
137 struct dsa_switch *ds = p->dp->ds;
138 unsigned int type;
139
140 if (skb_headroom(skb) < ETH_HLEN)
141 return false;
142
143 __skb_push(skb, ETH_HLEN);
144
145 type = ptp_classify_raw(skb);
146
147 __skb_pull(skb, ETH_HLEN);
148
149 if (type == PTP_CLASS_NONE)
150 return false;
151
152 if (likely(ds->ops->port_rxtstamp))
153 return ds->ops->port_rxtstamp(ds, p->dp->index, skb, type);
154
155 return false;
156}
157
125static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, 158static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
126 struct packet_type *pt, struct net_device *unused) 159 struct packet_type *pt, struct net_device *unused)
127{ 160{
@@ -157,6 +190,9 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
157 s->rx_bytes += skb->len; 190 s->rx_bytes += skb->len;
158 u64_stats_update_end(&s->syncp); 191 u64_stats_update_end(&s->syncp);
159 192
193 if (dsa_skb_defer_rx_timestamp(p, skb))
194 return 0;
195
160 netif_receive_skb(skb); 196 netif_receive_skb(skb);
161 197
162 return 0; 198 return 0;
diff --git a/net/dsa/slave.c b/net/dsa/slave.c
index f52307296de4..3376dad6dcfd 100644
--- a/net/dsa/slave.c
+++ b/net/dsa/slave.c
@@ -21,6 +21,7 @@
21#include <net/tc_act/tc_mirred.h> 21#include <net/tc_act/tc_mirred.h>
22#include <linux/if_bridge.h> 22#include <linux/if_bridge.h>
23#include <linux/netpoll.h> 23#include <linux/netpoll.h>
24#include <linux/ptp_classify.h>
24 25
25#include "dsa_priv.h" 26#include "dsa_priv.h"
26 27
@@ -255,6 +256,22 @@ dsa_slave_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
255 256
256static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) 257static int dsa_slave_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
257{ 258{
259 struct dsa_slave_priv *p = netdev_priv(dev);
260 struct dsa_switch *ds = p->dp->ds;
261 int port = p->dp->index;
262
263 /* Pass through to switch driver if it supports timestamping */
264 switch (cmd) {
265 case SIOCGHWTSTAMP:
266 if (ds->ops->port_hwtstamp_get)
267 return ds->ops->port_hwtstamp_get(ds, port, ifr);
268 break;
269 case SIOCSHWTSTAMP:
270 if (ds->ops->port_hwtstamp_set)
271 return ds->ops->port_hwtstamp_set(ds, port, ifr);
272 break;
273 }
274
258 if (!dev->phydev) 275 if (!dev->phydev)
259 return -ENODEV; 276 return -ENODEV;
260 277
@@ -385,6 +402,30 @@ static inline netdev_tx_t dsa_slave_netpoll_send_skb(struct net_device *dev,
385 return NETDEV_TX_OK; 402 return NETDEV_TX_OK;
386} 403}
387 404
405static void dsa_skb_tx_timestamp(struct dsa_slave_priv *p,
406 struct sk_buff *skb)
407{
408 struct dsa_switch *ds = p->dp->ds;
409 struct sk_buff *clone;
410 unsigned int type;
411
412 type = ptp_classify_raw(skb);
413 if (type == PTP_CLASS_NONE)
414 return;
415
416 if (!ds->ops->port_txtstamp)
417 return;
418
419 clone = skb_clone_sk(skb);
420 if (!clone)
421 return;
422
423 if (ds->ops->port_txtstamp(ds, p->dp->index, clone, type))
424 return;
425
426 kfree_skb(clone);
427}
428
388static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev) 429static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
389{ 430{
390 struct dsa_slave_priv *p = netdev_priv(dev); 431 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)
397 s->tx_bytes += skb->len; 438 s->tx_bytes += skb->len;
398 u64_stats_update_end(&s->syncp); 439 u64_stats_update_end(&s->syncp);
399 440
441 /* Identify PTP protocol packets, clone them, and pass them to the
442 * switch driver
443 */
444 dsa_skb_tx_timestamp(p, skb);
445
400 /* Transmit function may have to reallocate the original SKB, 446 /* Transmit function may have to reallocate the original SKB,
401 * in which case it must have freed it. Only free it here on error. 447 * in which case it must have freed it. Only free it here on error.
402 */ 448 */
@@ -918,6 +964,18 @@ static int dsa_slave_set_rxnfc(struct net_device *dev,
918 return ds->ops->set_rxnfc(ds, dp->index, nfc); 964 return ds->ops->set_rxnfc(ds, dp->index, nfc);
919} 965}
920 966
967static int dsa_slave_get_ts_info(struct net_device *dev,
968 struct ethtool_ts_info *ts)
969{
970 struct dsa_slave_priv *p = netdev_priv(dev);
971 struct dsa_switch *ds = p->dp->ds;
972
973 if (!ds->ops->get_ts_info)
974 return -EOPNOTSUPP;
975
976 return ds->ops->get_ts_info(ds, p->dp->index, ts);
977}
978
921static const struct ethtool_ops dsa_slave_ethtool_ops = { 979static const struct ethtool_ops dsa_slave_ethtool_ops = {
922 .get_drvinfo = dsa_slave_get_drvinfo, 980 .get_drvinfo = dsa_slave_get_drvinfo,
923 .get_regs_len = dsa_slave_get_regs_len, 981 .get_regs_len = dsa_slave_get_regs_len,
@@ -938,6 +996,7 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
938 .set_link_ksettings = phy_ethtool_set_link_ksettings, 996 .set_link_ksettings = phy_ethtool_set_link_ksettings,
939 .get_rxnfc = dsa_slave_get_rxnfc, 997 .get_rxnfc = dsa_slave_get_rxnfc,
940 .set_rxnfc = dsa_slave_set_rxnfc, 998 .set_rxnfc = dsa_slave_set_rxnfc,
999 .get_ts_info = dsa_slave_get_ts_info,
941}; 1000};
942 1001
943/* legacy way, bypassing the bridge *****************************************/ 1002/* legacy way, bypassing the bridge *****************************************/