xref: /openbmc/linux/net/core/timestamping.c (revision a44e4f3a)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * PTP 1588 clock support - support for timestamping in PHY devices
4  *
5  * Copyright (C) 2010 OMICRON electronics GmbH
6  */
7 #include <linux/errqueue.h>
8 #include <linux/phy.h>
9 #include <linux/ptp_classify.h>
10 #include <linux/skbuff.h>
11 #include <linux/export.h>
12 
13 static unsigned int classify(const struct sk_buff *skb)
14 {
15 	if (likely(skb->dev && skb->dev->phydev &&
16 		   skb->dev->phydev->drv))
17 		return ptp_classify_raw(skb);
18 	else
19 		return PTP_CLASS_NONE;
20 }
21 
22 void skb_clone_tx_timestamp(struct sk_buff *skb)
23 {
24 	struct phy_device *phydev;
25 	struct sk_buff *clone;
26 	unsigned int type;
27 
28 	if (!skb->sk)
29 		return;
30 
31 	type = classify(skb);
32 	if (type == PTP_CLASS_NONE)
33 		return;
34 
35 	phydev = skb->dev->phydev;
36 	if (likely(phydev->drv->txtstamp)) {
37 		clone = skb_clone_sk(skb);
38 		if (!clone)
39 			return;
40 		phydev->drv->txtstamp(phydev, clone, type);
41 	}
42 }
43 EXPORT_SYMBOL_GPL(skb_clone_tx_timestamp);
44 
45 bool skb_defer_rx_timestamp(struct sk_buff *skb)
46 {
47 	struct phy_device *phydev;
48 	unsigned int type;
49 
50 	if (!skb->dev || !skb->dev->phydev || !skb->dev->phydev->drv)
51 		return false;
52 
53 	if (skb_headroom(skb) < ETH_HLEN)
54 		return false;
55 
56 	__skb_push(skb, ETH_HLEN);
57 
58 	type = ptp_classify_raw(skb);
59 
60 	__skb_pull(skb, ETH_HLEN);
61 
62 	if (type == PTP_CLASS_NONE)
63 		return false;
64 
65 	phydev = skb->dev->phydev;
66 	if (likely(phydev->drv->rxtstamp))
67 		return phydev->drv->rxtstamp(phydev, skb, type);
68 
69 	return false;
70 }
71 EXPORT_SYMBOL_GPL(skb_defer_rx_timestamp);
72