Skip to content

Commit 90af105

Browse files
bstreiffdavem330
authored andcommitted
net: dsa: forward timestamping callbacks to switch drivers
Forward the rx/tx timestamp machinery from the dsa infrastructure to the switch driver. On the rx side, defer delivery of skbs until we have an rx timestamp. This mimicks the behavior of skb_defer_rx_timestamp. On the tx side, identify PTP packets, clone them, and pass them to the underlying switch driver before we transmit. This mimicks the behavior of skb_tx_timestamp. Adjusted txstamp API to keep the allocation and freeing of the clone in the same central function by Richard Cochran Signed-off-by: Brandon Streiff <[email protected]> Signed-off-by: Richard Cochran <[email protected]> Signed-off-by: Andrew Lunn <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 0336369 commit 90af105

File tree

3 files changed

+71
-0
lines changed

3 files changed

+71
-0
lines changed

include/net/dsa.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ struct dsa_platform_data {
102102
};
103103

104104
struct packet_type;
105+
struct dsa_switch;
105106

106107
struct dsa_device_ops {
107108
struct sk_buff *(*xmit)(struct sk_buff *skb, struct net_device *dev);
@@ -484,6 +485,10 @@ struct dsa_switch_ops {
484485
struct ifreq *ifr);
485486
int (*port_hwtstamp_set)(struct dsa_switch *ds, int port,
486487
struct ifreq *ifr);
488+
bool (*port_txtstamp)(struct dsa_switch *ds, int port,
489+
struct sk_buff *clone, unsigned int type);
490+
bool (*port_rxtstamp)(struct dsa_switch *ds, int port,
491+
struct sk_buff *skb, unsigned int type);
487492
};
488493

489494
struct dsa_switch_driver {

net/dsa/dsa.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <linux/netdevice.h>
2424
#include <linux/sysfs.h>
2525
#include <linux/phy_fixed.h>
26+
#include <linux/ptp_classify.h>
2627
#include <linux/gpio/consumer.h>
2728
#include <linux/etherdevice.h>
2829

@@ -122,6 +123,38 @@ struct net_device *dsa_dev_to_net_device(struct device *dev)
122123
}
123124
EXPORT_SYMBOL_GPL(dsa_dev_to_net_device);
124125

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+
*/
134+
static 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+
125158
static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
126159
struct packet_type *pt, struct net_device *unused)
127160
{
@@ -157,6 +190,9 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
157190
s->rx_bytes += skb->len;
158191
u64_stats_update_end(&s->syncp);
159192

193+
if (dsa_skb_defer_rx_timestamp(p, skb))
194+
return 0;
195+
160196
netif_receive_skb(skb);
161197

162198
return 0;

net/dsa/slave.c

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <net/tc_act/tc_mirred.h>
2222
#include <linux/if_bridge.h>
2323
#include <linux/netpoll.h>
24+
#include <linux/ptp_classify.h>
2425

2526
#include "dsa_priv.h"
2627

@@ -401,6 +402,30 @@ static inline netdev_tx_t dsa_slave_netpoll_send_skb(struct net_device *dev,
401402
return NETDEV_TX_OK;
402403
}
403404

405+
static 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+
404429
static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
405430
{
406431
struct dsa_slave_priv *p = netdev_priv(dev);
@@ -413,6 +438,11 @@ static netdev_tx_t dsa_slave_xmit(struct sk_buff *skb, struct net_device *dev)
413438
s->tx_bytes += skb->len;
414439
u64_stats_update_end(&s->syncp);
415440

441+
/* Identify PTP protocol packets, clone them, and pass them to the
442+
* switch driver
443+
*/
444+
dsa_skb_tx_timestamp(p, skb);
445+
416446
/* Transmit function may have to reallocate the original SKB,
417447
* in which case it must have freed it. Only free it here on error.
418448
*/

0 commit comments

Comments
 (0)