Skip to content

Commit 90188ff

Browse files
ceggers-arridavem330
authored andcommitted
net: dsa: microchip: ptp: add packet reception timestamping
Rx Timestamping is done through 4 additional bytes in tail tag. Whenever the ptp packet is received, the 4 byte hardware time stamped value is added before 1 byte tail tag. Also, bit 7 in tail tag indicates it as PTP frame. This 4 byte value is extracted from the tail tag and reconstructed to absolute time and assigned to skb hwtstamp. If the packet received in PDelay_Resp, then partial ingress timestamp is subtracted from the correction field. Since user space tools expects to be done in hardware. Signed-off-by: Christian Eggers <ceggers@arri.de> Co-developed-by: Arun Ramadoss <arun.ramadoss@microchip.com> Signed-off-by: Arun Ramadoss <arun.ramadoss@microchip.com> Reviewed-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 2955762 commit 90188ff

File tree

5 files changed

+108
-6
lines changed

5 files changed

+108
-6
lines changed

drivers/net/dsa/microchip/ksz_common.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2991,6 +2991,7 @@ static const struct dsa_switch_ops ksz_switch_ops = {
29912991
.get_ts_info = ksz_get_ts_info,
29922992
.port_hwtstamp_get = ksz_hwtstamp_get,
29932993
.port_hwtstamp_set = ksz_hwtstamp_set,
2994+
.port_rxtstamp = ksz_port_rxtstamp,
29942995
};
29952996

29962997
struct ksz_device *ksz_switch_alloc(struct device *base, void *priv)

drivers/net/dsa/microchip/ksz_ptp.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,69 @@ int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr)
169169
return copy_to_user(ifr->ifr_data, &config, sizeof(config));
170170
}
171171

172+
static ktime_t ksz_tstamp_reconstruct(struct ksz_device *dev, ktime_t tstamp)
173+
{
174+
struct timespec64 ptp_clock_time;
175+
struct ksz_ptp_data *ptp_data;
176+
struct timespec64 diff;
177+
struct timespec64 ts;
178+
179+
ptp_data = &dev->ptp_data;
180+
ts = ktime_to_timespec64(tstamp);
181+
182+
spin_lock_bh(&ptp_data->clock_lock);
183+
ptp_clock_time = ptp_data->clock_time;
184+
spin_unlock_bh(&ptp_data->clock_lock);
185+
186+
/* calculate full time from partial time stamp */
187+
ts.tv_sec = (ptp_clock_time.tv_sec & ~3) | ts.tv_sec;
188+
189+
/* find nearest possible point in time */
190+
diff = timespec64_sub(ts, ptp_clock_time);
191+
if (diff.tv_sec > 2)
192+
ts.tv_sec -= 4;
193+
else if (diff.tv_sec < -2)
194+
ts.tv_sec += 4;
195+
196+
return timespec64_to_ktime(ts);
197+
}
198+
199+
bool ksz_port_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb,
200+
unsigned int type)
201+
{
202+
struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
203+
struct ksz_device *dev = ds->priv;
204+
struct ptp_header *ptp_hdr;
205+
u8 ptp_msg_type;
206+
ktime_t tstamp;
207+
s64 correction;
208+
209+
tstamp = KSZ_SKB_CB(skb)->tstamp;
210+
memset(hwtstamps, 0, sizeof(*hwtstamps));
211+
hwtstamps->hwtstamp = ksz_tstamp_reconstruct(dev, tstamp);
212+
213+
ptp_hdr = ptp_parse_header(skb, type);
214+
if (!ptp_hdr)
215+
goto out;
216+
217+
ptp_msg_type = ptp_get_msgtype(ptp_hdr, type);
218+
if (ptp_msg_type != PTP_MSGTYPE_PDELAY_REQ)
219+
goto out;
220+
221+
/* Only subtract the partial time stamp from the correction field. When
222+
* the hardware adds the egress time stamp to the correction field of
223+
* the PDelay_Resp message on tx, also only the partial time stamp will
224+
* be added.
225+
*/
226+
correction = (s64)get_unaligned_be64(&ptp_hdr->correction);
227+
correction -= ktime_to_ns(tstamp) << 16;
228+
229+
ptp_header_update_correction(skb, type, ptp_hdr, correction);
230+
231+
out:
232+
return false;
233+
}
234+
172235
static int _ksz_ptp_gettime(struct ksz_device *dev, struct timespec64 *ts)
173236
{
174237
u32 nanoseconds;

drivers/net/dsa/microchip/ksz_ptp.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ int ksz_get_ts_info(struct dsa_switch *ds, int port,
3030
struct ethtool_ts_info *ts);
3131
int ksz_hwtstamp_get(struct dsa_switch *ds, int port, struct ifreq *ifr);
3232
int ksz_hwtstamp_set(struct dsa_switch *ds, int port, struct ifreq *ifr);
33+
bool ksz_port_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb,
34+
unsigned int type);
3335
int ksz_ptp_irq_setup(struct dsa_switch *ds, u8 p);
3436
void ksz_ptp_irq_free(struct dsa_switch *ds, u8 p);
3537

@@ -60,6 +62,8 @@ static inline void ksz_ptp_irq_free(struct dsa_switch *ds, u8 p) {}
6062

6163
#define ksz_hwtstamp_set NULL
6264

65+
#define ksz_port_rxtstamp NULL
66+
6367
#endif /* End of CONFIG_NET_DSA_MICROCHIP_KSZ_PTP */
6468

6569
#endif

include/linux/dsa/ksz_common.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,31 @@
99

1010
#include <net/dsa.h>
1111

12+
/* All time stamps from the KSZ consist of 2 bits for seconds and 30 bits for
13+
* nanoseconds. This is NOT the same as 32 bits for nanoseconds.
14+
*/
15+
#define KSZ_TSTAMP_SEC_MASK GENMASK(31, 30)
16+
#define KSZ_TSTAMP_NSEC_MASK GENMASK(29, 0)
17+
18+
static inline ktime_t ksz_decode_tstamp(u32 tstamp)
19+
{
20+
u64 ns = FIELD_GET(KSZ_TSTAMP_SEC_MASK, tstamp) * NSEC_PER_SEC +
21+
FIELD_GET(KSZ_TSTAMP_NSEC_MASK, tstamp);
22+
23+
return ns_to_ktime(ns);
24+
}
25+
1226
struct ksz_tagger_data {
1327
void (*hwtstamp_set_state)(struct dsa_switch *ds, bool on);
1428
};
1529

30+
struct ksz_skb_cb {
31+
u32 tstamp;
32+
};
33+
34+
#define KSZ_SKB_CB(skb) \
35+
((struct ksz_skb_cb *)((skb)->cb))
36+
1637
static inline struct ksz_tagger_data *
1738
ksz_tagger_data(struct dsa_switch *ds)
1839
{

net/dsa/tag_ksz.c

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -151,10 +151,11 @@ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8795, KSZ8795_NAME);
151151
* tag0 : Prioritization (not used now)
152152
* tag1 : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x10=port5)
153153
*
154-
* For Egress (KSZ9477 -> Host), 1 byte is added before FCS.
154+
* For Egress (KSZ9477 -> Host), 1/5 bytes is added before FCS.
155155
* ---------------------------------------------------------------------------
156-
* DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|FCS(4bytes)
156+
* DA(6bytes)|SA(6bytes)|....|Data(nbytes)|ts(4bytes)|tag0(1byte)|FCS(4bytes)
157157
* ---------------------------------------------------------------------------
158+
* ts : time stamp (Present only if bit 7 of tag0 is set)
158159
* tag0 : zero-based value represents port
159160
* (eg, 0x00=port1, 0x02=port3, 0x06=port7)
160161
*/
@@ -166,6 +167,15 @@ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ8795, KSZ8795_NAME);
166167
#define KSZ9477_TAIL_TAG_OVERRIDE BIT(9)
167168
#define KSZ9477_TAIL_TAG_LOOKUP BIT(10)
168169

170+
static void ksz_rcv_timestamp(struct sk_buff *skb, u8 *tag)
171+
{
172+
u8 *tstamp_raw = tag - KSZ_PTP_TAG_LEN;
173+
ktime_t tstamp;
174+
175+
tstamp = ksz_decode_tstamp(get_unaligned_be32(tstamp_raw));
176+
KSZ_SKB_CB(skb)->tstamp = tstamp;
177+
}
178+
169179
/* Time stamp tag *needs* to be inserted if PTP is enabled in hardware.
170180
* Regardless of Whether it is a PTP frame or not.
171181
*/
@@ -216,8 +226,10 @@ static struct sk_buff *ksz9477_rcv(struct sk_buff *skb, struct net_device *dev)
216226
unsigned int len = KSZ_EGRESS_TAG_LEN;
217227

218228
/* Extra 4-bytes PTP timestamp */
219-
if (tag[0] & KSZ9477_PTP_TAG_INDICATION)
220-
len += KSZ9477_PTP_TAG_LEN;
229+
if (tag[0] & KSZ9477_PTP_TAG_INDICATION) {
230+
ksz_rcv_timestamp(skb, tag);
231+
len += KSZ_PTP_TAG_LEN;
232+
}
221233

222234
return ksz_common_rcv(skb, dev, port, len);
223235
}
@@ -284,10 +296,11 @@ MODULE_ALIAS_DSA_TAG_DRIVER(DSA_TAG_PROTO_KSZ9893, KSZ9893_NAME);
284296
* tag0 : represents tag override, lookup and valid
285297
* tag1 : each bit represents port (eg, 0x01=port1, 0x02=port2, 0x80=port8)
286298
*
287-
* For rcv, 1 byte is added before FCS.
299+
* For rcv, 1/5 bytes is added before FCS.
288300
* ---------------------------------------------------------------------------
289-
* DA(6bytes)|SA(6bytes)|....|Data(nbytes)|tag0(1byte)|FCS(4bytes)
301+
* DA(6bytes)|SA(6bytes)|....|Data(nbytes)|ts(4bytes)|tag0(1byte)|FCS(4bytes)
290302
* ---------------------------------------------------------------------------
303+
* ts : time stamp (Present only if bit 7 of tag0 is set)
291304
* tag0 : zero-based value represents port
292305
* (eg, 0x00=port1, 0x02=port3, 0x07=port8)
293306
*/

0 commit comments

Comments
 (0)