Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: ptp: add helper for one-step P2P clocks

For P2P delay measurement, the ingress time stamp of the PDelay_Req is
required for the correction field of the PDelay_Resp. The application
echoes back the correction field of the PDelay_Req when sending the
PDelay_Resp.

Some hardware (like the ZHAW InES PTP time stamping IP core) subtracts
the ingress timestamp autonomously from the correction field, so that
the hardware only needs to add the egress timestamp on tx. Other
hardware (like the Microchip KSZ9563) reports the ingress time stamp via
an interrupt and requires that the software provides this time stamp via
tail-tag on tx.

In order to avoid introducing a further application interface for this,
the driver can simply emulate the behavior of the InES device and
subtract the ingress time stamp in software from the correction field.

On egress, the correction field can either be kept as it is (and the
time stamp field in the tail-tag is set to zero) or move the value from
the correction field back to the tail-tag.

Changing the correction field requires updating the UDP checksum (if UDP
is used as transport).

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>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Christian Eggers and committed by
David S. Miller
2955762b cc13ab18

+73
+73
include/linux/ptp_classify.h
··· 10 10 #ifndef _PTP_CLASSIFY_H_ 11 11 #define _PTP_CLASSIFY_H_ 12 12 13 + #include <asm/unaligned.h> 13 14 #include <linux/ip.h> 15 + #include <linux/ktime.h> 14 16 #include <linux/skbuff.h> 17 + #include <linux/udp.h> 18 + #include <net/checksum.h> 15 19 16 20 #define PTP_CLASS_NONE 0x00 /* not a PTP event message */ 17 21 #define PTP_CLASS_V1 0x01 /* protocol version 1 */ ··· 134 130 } 135 131 136 132 /** 133 + * ptp_check_diff8 - Computes new checksum (when altering a 64-bit field) 134 + * @old: old field value 135 + * @new: new field value 136 + * @oldsum: previous checksum 137 + * 138 + * This function can be used to calculate a new checksum when only a single 139 + * field is changed. Similar as ip_vs_check_diff*() in ip_vs.h. 140 + * 141 + * Return: Updated checksum 142 + */ 143 + static inline __wsum ptp_check_diff8(__be64 old, __be64 new, __wsum oldsum) 144 + { 145 + __be64 diff[2] = { ~old, new }; 146 + 147 + return csum_partial(diff, sizeof(diff), oldsum); 148 + } 149 + 150 + /** 151 + * ptp_header_update_correction - Update PTP header's correction field 152 + * @skb: packet buffer 153 + * @type: type of the packet (see ptp_classify_raw()) 154 + * @hdr: ptp header 155 + * @correction: new correction value 156 + * 157 + * This updates the correction field of a PTP header and updates the UDP 158 + * checksum (if UDP is used as transport). It is needed for hardware capable of 159 + * one-step P2P that does not already modify the correction field of Pdelay_Req 160 + * event messages on ingress. 161 + */ 162 + static inline 163 + void ptp_header_update_correction(struct sk_buff *skb, unsigned int type, 164 + struct ptp_header *hdr, s64 correction) 165 + { 166 + __be64 correction_old; 167 + struct udphdr *uhdr; 168 + 169 + /* previous correction value is required for checksum update. */ 170 + memcpy(&correction_old, &hdr->correction, sizeof(correction_old)); 171 + 172 + /* write new correction value */ 173 + put_unaligned_be64((u64)correction, &hdr->correction); 174 + 175 + switch (type & PTP_CLASS_PMASK) { 176 + case PTP_CLASS_IPV4: 177 + case PTP_CLASS_IPV6: 178 + /* locate udp header */ 179 + uhdr = (struct udphdr *)((char *)hdr - sizeof(struct udphdr)); 180 + break; 181 + default: 182 + return; 183 + } 184 + 185 + /* update checksum */ 186 + uhdr->check = csum_fold(ptp_check_diff8(correction_old, 187 + hdr->correction, 188 + ~csum_unfold(uhdr->check))); 189 + if (!uhdr->check) 190 + uhdr->check = CSUM_MANGLED_0; 191 + 192 + skb->ip_summed = CHECKSUM_NONE; 193 + } 194 + 195 + /** 137 196 * ptp_msg_is_sync - Evaluates whether the given skb is a PTP Sync message 138 197 * @skb: packet buffer 139 198 * @type: type of the packet (see ptp_classify_raw()) ··· 232 165 static inline bool ptp_msg_is_sync(struct sk_buff *skb, unsigned int type) 233 166 { 234 167 return false; 168 + } 169 + 170 + static inline 171 + void ptp_header_update_correction(struct sk_buff *skb, unsigned int type, 172 + struct ptp_header *hdr, s64 correction) 173 + { 235 174 } 236 175 #endif 237 176 #endif /* _PTP_CLASSIFY_H_ */