From: Andrei Pistirica <hidden> Date: 2016-09-02 12:54:31
From: Harini Katakam <redacted>
Cadence GEM provides a 102 bit time counter with 48 bits for seconds,
30 bits for nsecs and 24 bits for sub-nsecs to control 1588 timestamping.
This patch does the following:
- Registers to ptp clock framework
- Timer initialization is done by writing time of day to the timer counter.
- ns increment register is programmed as NSEC_PER_SEC/TSU_CLK.
For a 24 bit subns precision, the subns increment equals
remainder of (NS_PER_SEC/TSU_CLK) * (2^24).
- HW time stamp capabilities are advertised via ethtool and macb ioctl is
updated accordingly.
- Timestamps are obtained from the TX/RX PTP event/PEER registers.
The timestamp obtained thus is updated in skb for upper layers to access.
- The drivers register functions with ptp to perform time and frequency
adjustment.
- Time adjustment is done by writing to the 1558_ADJUST register.
The controller will read the delta in this register and update the timer
counter register. Alternatively, for large time offset adjustments,
the driver reads the secs and nsecs counter values, adds/subtracts the
delta and updates the timer counter.
- Frequency adjustment is not directly supported by this IP.
addend is the initial value ns increment and similarly addendesub.
The ppb (parts per billion) provided is used as
ns_incr = addend +/- (ppb/rate).
Similarly the remainder of the above is used to populate subns increment.
In case the ppb requested is negative AND subns adjustment greater than
the addendsub, ns_incr is reduced by 1 and subns_incr is adjusted in
positive accordingly.
Signed-off-by: Harini Katakam <redacted>
Signed-off-by: Andrei Pistirica <redacted>
---
This patch is based on original Harini's patch, implemented in a
separate file to ease the review/maintanance and integration with
other platforms (e.g. Zynq Ultrascale+ MPSoC).
Feature was tested on SAMA5D2 platform using ptp4l v1.6 from linuxptp
project and also with ptpd2 version 2.3.1. PTP was tested over
IPv4,IPv6 and 802.3 protocols.
Hariani, please let me know if you are ok with this patch, and if you
want to be stated as author/signed-off?
In case that macb is compiled as a module, it has been renamed to
cadence-macb.ko to avoid naming confusion in Makefile.
Patch is not completely ported to the very latest version of net-next,
and it will be after review.
drivers/net/ethernet/cadence/Kconfig | 10 +-
drivers/net/ethernet/cadence/Makefile | 8 +-
drivers/net/ethernet/cadence/macb.h | 82 ++++++++++++
drivers/net/ethernet/cadence/macb_ptp.c | 224 ++++++++++++++++++++++++++++++++
4 files changed, 322 insertions(+), 2 deletions(-)
create mode 100644 drivers/net/ethernet/cadence/macb_ptp.c
From: Andrei Pistirica <hidden> Date: 2016-09-02 12:54:39
Hardware time stamp on the PTP Ethernet packets are received using the
SO_TIMESTAMPING API. Timers are obtained from the PTP event/peer
gem registers.
Signed-off-by: Andrei Pistirica <redacted>
---
Integration with SAMA5D2 only. This feature wasn't tested on any
other platform that might use cadence/gem.
Patch is not completely ported to the very latest version of net-next,
and it will be after review.
drivers/net/ethernet/cadence/macb.c | 25 +++-
drivers/net/ethernet/cadence/macb.h | 13 ++
drivers/net/ethernet/cadence/macb_ptp.c | 217 ++++++++++++++++++++++++++++++++
3 files changed, 254 insertions(+), 1 deletion(-)
Hi Andrei,
Adding Richard Cochran for PTP.
On Fri, Sep 2, 2016 at 6:23 PM, Andrei Pistirica
[off-list ref] wrote:
From: Harini Katakam <redacted>
Cadence GEM provides a 102 bit time counter with 48 bits for seconds,
30 bits for nsecs and 24 bits for sub-nsecs to control 1588 timestamping.
This patch does the following:
- Registers to ptp clock framework
- Timer initialization is done by writing time of day to the timer counter.
- ns increment register is programmed as NSEC_PER_SEC/TSU_CLK.
For a 24 bit subns precision, the subns increment equals
remainder of (NS_PER_SEC/TSU_CLK) * (2^24).
- HW time stamp capabilities are advertised via ethtool and macb ioctl is
updated accordingly.
- Timestamps are obtained from the TX/RX PTP event/PEER registers.
The timestamp obtained thus is updated in skb for upper layers to access.
- The drivers register functions with ptp to perform time and frequency
adjustment.
- Time adjustment is done by writing to the 1558_ADJUST register.
The controller will read the delta in this register and update the timer
counter register. Alternatively, for large time offset adjustments,
the driver reads the secs and nsecs counter values, adds/subtracts the
delta and updates the timer counter.
- Frequency adjustment is not directly supported by this IP.
addend is the initial value ns increment and similarly addendesub.
The ppb (parts per billion) provided is used as
ns_incr = addend +/- (ppb/rate).
Similarly the remainder of the above is used to populate subns increment.
In case the ppb requested is negative AND subns adjustment greater than
the addendsub, ns_incr is reduced by 1 and subns_incr is adjusted in
positive accordingly.
Signed-off-by: Harini Katakam <redacted>
Signed-off-by: Andrei Pistirica <redacted>
---
This patch is based on original Harini's patch, implemented in a
separate file to ease the review/maintanance and integration with
other platforms (e.g. Zynq Ultrascale+ MPSoC).
Feature was tested on SAMA5D2 platform using ptp4l v1.6 from linuxptp
project and also with ptpd2 version 2.3.1. PTP was tested over
IPv4,IPv6 and 802.3 protocols.
Hariani, please let me know if you are ok with this patch, and if you
want to be stated as author/signed-off?
Thanks for the patch. It seems ok. I'm making some changes on
top of this, especially in your second patch for picking RX timestamp,
since that is handled from indication in the BD for ZynqMP.
Regards,
Harini
Hi Andrei,
+Richard Cochran
On Fri, Sep 2, 2016 at 6:23 PM, Andrei Pistirica
[off-list ref] wrote:
Hardware time stamp on the PTP Ethernet packets are received using the
SO_TIMESTAMPING API. Timers are obtained from the PTP event/peer
gem registers.
Signed-off-by: Andrei Pistirica <redacted>
---
Integration with SAMA5D2 only. This feature wasn't tested on any
other platform that might use cadence/gem.
Patch is not completely ported to the very latest version of net-next,
and it will be after review.
<snip>
quoted hunk
@@ -853,6 +858,11 @@ static int gem_rx(struct macb *bp, int budget) GEM_BFEXT(RX_CSUM, ctrl) & GEM_RX_CSUM_CHECKED_MASK) skb->ip_summed = CHECKSUM_UNNECESSARY;+/* guard the hot-path */+#ifdef CONFIG_MACB_USE_HWSTAMP+ if (bp->hwts_rx_en)+ macb_ptp_do_rxstamp(bp, skb);+#endif
I'm just wondering if the same #ifdef can be used for timestamping
in all versions of this IP.
As you know, ZynqMP uses the timestamp from BD and older
versions of do not have an indication or extended BD support.
So, it might useful to add a dependency/check on the product family,
through config structure.
That way, both version can use their respective RX timestamp methods
based on the compatible string.
Please let me know if you have any other ideas.
Regards,
Harini
From: Richard Cochran <richardcochran@gmail.com> Date: 2016-09-06 15:49:39
I have some issues with this patch...
On Fri, Sep 02, 2016 at 02:53:36PM +0200, Andrei Pistirica wrote:
quoted hunk
- Frequency adjustment is not directly supported by this IP. addend is the initial value ns increment and similarly addendesub. The ppb (parts per billion) provided is used as ns_incr = addend +/- (ppb/rate). Similarly the remainder of the above is used to populate subns increment. In case the ppb requested is negative AND subns adjustment greater than the addendsub, ns_incr is reduced by 1 and subns_incr is adjusted in positive accordingly.
This makes no sense. If you cannot adjust the frequency, then you
must implement a timecounter/cyclecounter and do in software.
Here in the header file, you only need ptp_clock_kernel.h. You don't
need all the others here. Move them to the .c file, but only if
really needed. (timecounter.h isn't used, now is it?)
Three. You need three 64 bit divisions? There must be a better way.
If I guess correctly, the nsincr/subnsincr value is added to the
device's time on every clock. So scaling these effectively adjusts
the frequency. Here is an idea for you.
You have a 24 bit fractional field. Combine that with 8 bits of whole
nanoseconds to form one 32 tuning word. Restrict the nanoseconds to 8
bits in the setup code. (8 bits allows input clocks down to 4 MHz.)
Multiply the tuning word by the 32 ppb variable, keeping the 64 bit
result. Divide the result by 10^9 and that gives you the delta to add
to (or subtract from) the nominal tuning word.
See gianfar.c for an example.
From: Richard Cochran <richardcochran@gmail.com> Date: 2016-09-06 16:39:30
On Fri, Sep 02, 2016 at 02:53:37PM +0200, Andrei Pistirica wrote:
Hardware time stamp on the PTP Ethernet packets are received using the
SO_TIMESTAMPING API. Timers are obtained from the PTP event/peer
gem registers.
Signed-off-by: Andrei Pistirica <redacted>
---
Integration with SAMA5D2 only. This feature wasn't tested on any
other platform that might use cadence/gem.
What does that mean? I didn't see any references to SAMA5D2 anywhere
in your patch.
The driver needs to positively identify the HW that supports this
feature.
We don't add additional authors any more, because git tells us that info.
quoted hunk
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
@@ -222,3 +223,219 @@ void macb_ptp_init(struct net_device *ndev) dev_info(&bp->pdev->dev, "%s ptp clock registered.\n", GMAC_TIMER_NAME); }++/* While the GEM can timestamp PTP packets, it does not mark the RX descriptor+ * to identify them. This is entirely the wrong place to be parsing UDP+ * headers, but some minimal effort must be made.
If you must parse, then it isn't the wrong place.
quoted hunk
+ *+ * Note: Inspired from drivers/net/ethernet/ti/cpts.c+ */+static inline int macb_get_ptp_peer(struct sk_buff *skb, int ptp_class)
Leave off inline, let the compiler decide.
quoted hunk
+{+ unsigned int offset = 0;+ u8 *msgtype, *data = skb->data;++ if (ptp_class == PTP_CLASS_NONE)+ return -1;++ if (ptp_class & PTP_CLASS_VLAN)+ offset += VLAN_HLEN;++ switch (ptp_class & PTP_CLASS_PMASK) {+ case PTP_CLASS_IPV4:+ offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN;+ break;+ case PTP_CLASS_IPV6:+ offset += ETH_HLEN + IP6_HLEN + UDP_HLEN;+ break;+ case PTP_CLASS_L2:+ offset += ETH_HLEN;+ break;++ /* something went wrong! */+ default:+ return -1;+ }++ if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID)+ return -1;++ if (unlikely(ptp_class & PTP_CLASS_V1))+ msgtype = data + offset + OFF_PTP_CONTROL;+ else+ msgtype = data + offset;++ return (*msgtype) & 0x2;+}++static inline void macb_ptp_tx_hwtstamp(struct macb *bp, struct sk_buff *skb,+ int peer_ev)
So you say the HW provides no matching information? Then it is really
poor. I surely don't want to let this out into the wild. I'll get
questions on the linuxptp list, like "PTP on mainline Linux is
mysteriously broken!"
This regsiter does not exist. Looking at
Zynq-7000 AP SoC Technical Reference Manual
UG585 (v1.10) February 23, 2015
starting on page 1273 we see:
udp_csum_errors 0x000001B0 32 ro 0x00000000 UDP checksum error
timer_strobe_s 0x000001C8 32 rw 0x00000000 1588 timer sync strobe seconds
timer_strobe_ns 0x000001CC 32 mixed 0x00000000 1588 timer sync strobe nanoseconds
timer_s 0x000001D0 32 rw 0x00000000 1588 timer seconds
timer_ns 0x000001D4 32 mixed 0x00000000 1588 timer nanoseconds
timer_adjust 0x000001D8 32 mixed 0x00000000 1588 timer adjust
timer_incr 0x000001DC 32 mixed 0x00000000 1588 timer increment
There is no register at 0x1BC.
quoted
+#define GEM_TSH 0x01c0 /* 1588 Timer Seconds High */
This one doesn't exist either. What is going on here?
I cant be sure of the version of Cadence GEM used in SAMA5D2
but these registers (sub ns increments alteast) only exist in
the IP version used in Zynq Ultrascale+ MPSoC.
<snip>
quoted
+ /* get GEM internal time */+ sech = gem_readl(bp, TSH);+ secl = gem_readl(bp, TSL);
Does reading TSH latch the time? The TRM is silent about that, and
most other designs latch on reading the LSB.
No, it does not latch the time.
When doing a read + adjust + write, this will
mean there's room for some error.
Although when writing, the write to MSB and LSB registers
was made atomic. This bug fix came only in the
most recent version of the IP, am afraid.
Regards,
Harini
From: Richard Cochran <richardcochran@gmail.com> Date: 2016-09-08 07:44:50
On Thu, Sep 08, 2016 at 10:22:43AM +0530, Harini Katakam wrote:
I cant be sure of the version of Cadence GEM used in SAMA5D2
but these registers (sub ns increments alteast) only exist in
the IP version used in Zynq Ultrascale+ MPSoC.
Then you need to find a way to make sure the driver only binds to the
correct silicon.
Thanks,
Richard
From: Richard Cochran <richardcochran@gmail.com> Date: 2016-09-08 19:06:32
On Thu, Sep 08, 2016 at 10:22:43AM +0530, Harini Katakam wrote:
quoted
quoted
+ /* get GEM internal time */+ sech = gem_readl(bp, TSH);+ secl = gem_readl(bp, TSL);
Does reading TSH latch the time? The TRM is silent about that, and
most other designs latch on reading the LSB.
No, it does not latch the time.
When doing a read + adjust + write, this will
mean there's room for some error.
It also means that you will have to handle when the TSL value
overflows into TSH. That means reading TSH twice, once before and
once after reading TSL and retrying if needed.
The code as written above will produce apparent jumps backwards in
time, whenever the overflow occurs between the two read operations.
Thanks,
Richard
From: Andrei Pistirica <hidden> Date: 2016-09-09 13:52:45
On 06.09.2016 17:48, Richard Cochran wrote:
I have some issues with this patch...
On Fri, Sep 02, 2016 at 02:53:36PM +0200, Andrei Pistirica wrote:
quoted
- Frequency adjustment is not directly supported by this IP. addend is the initial value ns increment and similarly addendesub. The ppb (parts per billion) provided is used as ns_incr = addend +/- (ppb/rate). Similarly the remainder of the above is used to populate subns increment. In case the ppb requested is negative AND subns adjustment greater than the addendsub, ns_incr is reduced by 1 and subns_incr is adjusted in positive accordingly.
This makes no sense. If you cannot adjust the frequency, then you
must implement a timecounter/cyclecounter and do in software.
Here in the header file, you only need ptp_clock_kernel.h. You don't
need all the others here. Move them to the .c file, but only if
really needed. (timecounter.h isn't used, now is it?)
Ack.
Except timecounter.h, I need these headers for
ptp_clock and ptp_clock_info parameters from struct macb.
Three. You need three 64 bit divisions? There must be a better way.
If I guess correctly, the nsincr/subnsincr value is added to the
device's time on every clock. So scaling these effectively adjusts
the frequency. Here is an idea for you.
You have a 24 bit fractional field. Combine that with 8 bits of whole
nanoseconds to form one 32 tuning word. Restrict the nanoseconds to 8
bits in the setup code. (8 bits allows input clocks down to 4 MHz.)
Multiply the tuning word by the 32 ppb variable, keeping the 64 bit
result. Divide the result by 10^9 and that gives you the delta to add
to (or subtract from) the nominal tuning word.
See gianfar.c for an example.
Ack.
This code was taken with respect from Harini's first patch: https://lkml.org/lkml/2015/9/11/92.
I can add an additional patch to take care of this on top of Harini's patch.
From: Andrei Pistirica <hidden> Date: 2016-09-09 14:09:32
Hi Richard,
I will take your indications into account in next version of the patch.
Regards,
Andrei
On 06.09.2016 18:37, Richard Cochran wrote:
On Fri, Sep 02, 2016 at 02:53:37PM +0200, Andrei Pistirica wrote:
quoted
Hardware time stamp on the PTP Ethernet packets are received using the
SO_TIMESTAMPING API. Timers are obtained from the PTP event/peer
gem registers.
Signed-off-by: Andrei Pistirica <redacted>
---
Integration with SAMA5D2 only. This feature wasn't tested on any
other platform that might use cadence/gem.
What does that mean? I didn't see any references to SAMA5D2 anywhere
in your patch.
The driver needs to positively identify the HW that supports this
feature.
We don't add additional authors any more, because git tells us that info.
quoted
*
* This file is licensed under the terms of the GNU General Public
* License version 2. This program is licensed "as is" without any
@@ -222,3 +223,219 @@ void macb_ptp_init(struct net_device *ndev) dev_info(&bp->pdev->dev, "%s ptp clock registered.\n", GMAC_TIMER_NAME); }++/* While the GEM can timestamp PTP packets, it does not mark the RX descriptor+ * to identify them. This is entirely the wrong place to be parsing UDP+ * headers, but some minimal effort must be made.
If you must parse, then it isn't the wrong place.
quoted
+ *+ * Note: Inspired from drivers/net/ethernet/ti/cpts.c+ */+static inline int macb_get_ptp_peer(struct sk_buff *skb, int ptp_class)
Leave off inline, let the compiler decide.
quoted
+{+ unsigned int offset = 0;+ u8 *msgtype, *data = skb->data;++ if (ptp_class == PTP_CLASS_NONE)+ return -1;++ if (ptp_class & PTP_CLASS_VLAN)+ offset += VLAN_HLEN;++ switch (ptp_class & PTP_CLASS_PMASK) {+ case PTP_CLASS_IPV4:+ offset += ETH_HLEN + IPV4_HLEN(data + offset) + UDP_HLEN;+ break;+ case PTP_CLASS_IPV6:+ offset += ETH_HLEN + IP6_HLEN + UDP_HLEN;+ break;+ case PTP_CLASS_L2:+ offset += ETH_HLEN;+ break;++ /* something went wrong! */+ default:+ return -1;+ }++ if (skb->len + ETH_HLEN < offset + OFF_PTP_SEQUENCE_ID)+ return -1;++ if (unlikely(ptp_class & PTP_CLASS_V1))+ msgtype = data + offset + OFF_PTP_CONTROL;+ else+ msgtype = data + offset;++ return (*msgtype) & 0x2;+}++static inline void macb_ptp_tx_hwtstamp(struct macb *bp, struct sk_buff *skb,+ int peer_ev)
So you say the HW provides no matching information? Then it is really
poor. I surely don't want to let this out into the wild. I'll get
questions on the linuxptp list, like "PTP on mainline Linux is
mysteriously broken!"