linux/drivers/net/dsa/sja1105/sja1105_ptp.c

971 lines
26 KiB
C
Raw Permalink Normal View History

net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2019, Vladimir Oltean <olteanv@gmail.com>
*/
net: dsa: sja1105: Implement the .gettimex64 system call for PTP Through the PTP_SYS_OFFSET_EXTENDED ioctl, it is possible for userspace applications (i.e. phc2sys) to compensate for the delays incurred while reading the PHC's time. The task itself of taking the software timestamp is delegated to the SPI subsystem, through the newly introduced API in struct spi_transfer. The goal is to cross-timestamp I/O operations on the switch's PTP clock with values in the local system clock (CLOCK_REALTIME). For that we need to understand a bit of the hardware internals. The 'read PTP time' message is a 12 byte structure, first 4 bytes of which represent the SPI header, and the last 8 bytes represent the 64-bit PTP time. The switch itself starts processing the command immediately after receiving the last bit of the address, i.e. at the middle of byte 3 (last byte of header). The PTP time is shadowed to a buffer register in the switch, and retrieved atomically during the subsequent SPI frames. A similar thing goes on for the 'write PTP time' message, although in that case the switch waits until the 64-bit PTP time becomes fully available before taking any action. So the byte that needs to be software-timestamped is byte 11 (last) of the transfer. The patch creates a common (and local) sja1105_xfer implementation for the SPI I/O, and offers 3 front-ends: - sja1105_xfer_u32 and sja1105_xfer_u64: these are capable of optionally requesting a PTP timestamp - sja1105_xfer_buf: this is for large transfers (e.g. the static config buffer) and other misc data, and there is no point in giving timestamping capabilities to this. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-11-09 13:32:22 +02:00
#include <linux/spi/spi.h>
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
#include "sja1105.h"
/* The adjfine API clamps ppb between [-32,768,000, 32,768,000], and
* therefore scaled_ppm between [-2,147,483,648, 2,147,483,647].
* Set the maximum supported ppb to a round value smaller than the maximum.
*
* Percentually speaking, this is a +/- 0.032x adjustment of the
* free-running counter (0.968x to 1.032x).
*/
#define SJA1105_MAX_ADJ_PPB 32000000
#define SJA1105_SIZE_PTP_CMD 4
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
/* PTPSYNCTS has no interrupt or update mechanism, because the intended
* hardware use case is for the timestamp to be collected synchronously,
* immediately after the CAS_MASTER SJA1105 switch has performed a CASSYNC
* one-shot toggle (no return to level) on the PTP_CLK pin. When used as a
* generic extts source, the PTPSYNCTS register needs polling and a comparison
* with the old value. The polling interval is configured as the Nyquist rate
* of a signal with 50% duty cycle and 1Hz frequency, which is sadly all that
* this hardware can do (but may be enough for some setups). Anything of higher
* frequency than 1 Hz will be lost, since there is no timestamp FIFO.
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
*/
net: dsa: sja1105: poll for extts events from a timer The current poll interval is enough to ensure that rising and falling edge events are not lost for a 1 PPS signal with 50% duty cycle. But when we deliver the events to user space, it will try to infer if they were corresponding to a rising or to a falling edge (the kernel driver doesn't know that either). User space will try to make that inference based on the time at which the PPS master had emitted the pulse (i.e. if it's a .0 time, it's rising edge, if it's .5 time, it's falling edge). But there is no in-kernel API for retrieving the precise timestamp corresponding to a PPS master (aka perout) pulse. So user space has to guess even that. It will read the PTP time on the PPS master right after we've delivered the extts event, and declare that the PPS master time was just the closest integer second, based on 2 thresholds (lower than .25, or higher than .75, and ignore anything else). Except that, if we poll for extts events (and our hardware doesn't really help us, by not providing an interrupt), then there is a risk that the poll period (and therefore the time at which the event is delivered) might confuse user space. Because we are always scheduling the next extts poll at SJA1105_EXTTS_INTERVAL "from now" (that's the only thing that the schedule_delayed_work() API gives us), it means that the start time of the next delayed workqueue will always be shifted to the right a little bit (shifted with the SPI access duration of this workqueue run). In turn, because user space sees extts events that are non-periodic compared to the PPS master's time, this means that it might start making wrong guesses about rising/falling edge. To understand the effect, here is the output of ts2phc currently. Notice the 'src' timestamps of the 'SKIP extts' events, and how they have a large wander. They keep increasing until the upper limit for the ignore threshold (.75 seconds), after which the application starts ignoring the _other_ edge. ts2phc[26.624]: /dev/ptp3 SKIP extts index 0 at 21.449898912 src 21.657784518 ts2phc[27.133]: adding tstamp 21.949894240 to clock /dev/ptp3 ts2phc[27.133]: adding tstamp 22.000000000 to clock /dev/ptp1 ts2phc[27.133]: /dev/ptp3 offset 640 s2 freq +5112 ts2phc[27.636]: /dev/ptp3 SKIP extts index 0 at 22.449889360 src 22.669398022 ts2phc[28.140]: adding tstamp 22.949884376 to clock /dev/ptp3 ts2phc[28.140]: adding tstamp 23.000000000 to clock /dev/ptp1 ts2phc[28.140]: /dev/ptp3 offset 96 s2 freq +4760 ts2phc[28.644]: /dev/ptp3 SKIP extts index 0 at 23.449879504 src 23.677420422 ts2phc[29.153]: adding tstamp 23.949874704 to clock /dev/ptp3 ts2phc[29.153]: adding tstamp 24.000000000 to clock /dev/ptp1 ts2phc[29.153]: /dev/ptp3 offset -264 s2 freq +4429 ts2phc[29.656]: /dev/ptp3 SKIP extts index 0 at 24.449870008 src 24.689407238 ts2phc[30.160]: adding tstamp 24.949865376 to clock /dev/ptp3 ts2phc[30.160]: adding tstamp 25.000000000 to clock /dev/ptp1 ts2phc[30.160]: /dev/ptp3 offset -280 s2 freq +4334 ts2phc[30.664]: /dev/ptp3 SKIP extts index 0 at 25.449860760 src 25.697449926 ts2phc[31.168]: adding tstamp 25.949856176 to clock /dev/ptp3 ts2phc[31.168]: adding tstamp 26.000000000 to clock /dev/ptp1 ts2phc[31.168]: /dev/ptp3 offset -176 s2 freq +4354 ts2phc[31.672]: /dev/ptp3 SKIP extts index 0 at 26.449851584 src 26.705433606 ts2phc[32.180]: adding tstamp 26.949846992 to clock /dev/ptp3 ts2phc[32.180]: adding tstamp 27.000000000 to clock /dev/ptp1 ts2phc[32.180]: /dev/ptp3 offset -80 s2 freq +4397 ts2phc[32.684]: /dev/ptp3 SKIP extts index 0 at 27.449842384 src 27.717415110 ts2phc[33.192]: adding tstamp 27.949837768 to clock /dev/ptp3 ts2phc[33.192]: adding tstamp 28.000000000 to clock /dev/ptp1 ts2phc[33.192]: /dev/ptp3 offset 0 s2 freq +4453 ts2phc[33.696]: /dev/ptp3 SKIP extts index 0 at 28.449833128 src 28.729412902 ts2phc[34.200]: adding tstamp 28.949828472 to clock /dev/ptp3 ts2phc[34.200]: adding tstamp 29.000000000 to clock /dev/ptp1 ts2phc[34.200]: /dev/ptp3 offset 8 s2 freq +4461 ts2phc[34.704]: /dev/ptp3 SKIP extts index 0 at 29.449823816 src 29.737416038 ts2phc[35.208]: adding tstamp 29.949819152 to clock /dev/ptp3 ts2phc[35.208]: adding tstamp 30.000000000 to clock /dev/ptp1 ts2phc[35.208]: /dev/ptp3 offset -8 s2 freq +4447 ts2phc[35.712]: /dev/ptp3 SKIP extts index 0 at 30.449814496 src 30.745554982 ts2phc[36.216]: adding tstamp 30.949809840 to clock /dev/ptp3 ts2phc[36.216]: adding tstamp 31.000000000 to clock /dev/ptp1 ts2phc[36.216]: /dev/ptp3 offset -8 s2 freq +4445 ts2phc[36.468]: /dev/ptp3 SKIP extts index 0 at 31.449805184 src 31.501109446 ts2phc[36.972]: adding tstamp 31.949800536 to clock /dev/ptp3 ts2phc[36.972]: adding tstamp 32.000000000 to clock /dev/ptp1 ts2phc[36.972]: /dev/ptp3 offset -8 s2 freq +4442 ts2phc[37.480]: /dev/ptp3 SKIP extts index 0 at 32.449795896 src 32.513320070 ts2phc[37.984]: adding tstamp 32.949791248 to clock /dev/ptp3 ts2phc[37.984]: adding tstamp 33.000000000 to clock /dev/ptp1 ts2phc[37.984]: /dev/ptp3 offset 0 s2 freq +4448 Fix that by taking the following measures: - Schedule the poll from a timer. Because we are really scheduling the timer periodically, the extts events delivered to user space are periodic too, and don't suffer from the "shift-to-the-right" effect. - Increase the poll period to 6 times a second. This imposes a smaller upper bound to the shift that can occur to the delivery time of extts events, and makes user space (ts2phc) to always interpret correctly which events should be skipped and which shouldn't. - Move the SPI readout itself to the main PTP kernel thread, instead of the generic workqueue. This is because the timer runs in atomic context, but is also better than before, because if needed, we can chrt & taskset this kernel thread, to ensure it gets enough priority under load. After this patch, one can notice that the wander is greatly reduced, and that the latencies of one extts poll are not propagated to the next. The 'src' timestamp that is skipped is never larger than .65 seconds (which means .15 seconds larger than the time at which the real event occurred at, and .10 seconds smaller than the .75 upper threshold for ignoring the falling edge): ts2phc[40.076]: adding tstamp 34.949261296 to clock /dev/ptp3 ts2phc[40.076]: adding tstamp 35.000000000 to clock /dev/ptp1 ts2phc[40.076]: /dev/ptp3 offset 48 s2 freq +4631 ts2phc[40.568]: /dev/ptp3 SKIP extts index 0 at 35.449256496 src 35.595791078 ts2phc[41.064]: adding tstamp 35.949251744 to clock /dev/ptp3 ts2phc[41.064]: adding tstamp 36.000000000 to clock /dev/ptp1 ts2phc[41.064]: /dev/ptp3 offset -224 s2 freq +4374 ts2phc[41.552]: /dev/ptp3 SKIP extts index 0 at 36.449247088 src 36.579825574 ts2phc[42.044]: adding tstamp 36.949242456 to clock /dev/ptp3 ts2phc[42.044]: adding tstamp 37.000000000 to clock /dev/ptp1 ts2phc[42.044]: /dev/ptp3 offset -240 s2 freq +4290 ts2phc[42.536]: /dev/ptp3 SKIP extts index 0 at 37.449237848 src 37.563828774 ts2phc[43.028]: adding tstamp 37.949233264 to clock /dev/ptp3 ts2phc[43.028]: adding tstamp 38.000000000 to clock /dev/ptp1 ts2phc[43.028]: /dev/ptp3 offset -144 s2 freq +4314 ts2phc[43.520]: /dev/ptp3 SKIP extts index 0 at 38.449228656 src 38.547823238 ts2phc[44.012]: adding tstamp 38.949224048 to clock /dev/ptp3 ts2phc[44.012]: adding tstamp 39.000000000 to clock /dev/ptp1 ts2phc[44.012]: /dev/ptp3 offset -80 s2 freq +4335 ts2phc[44.508]: /dev/ptp3 SKIP extts index 0 at 39.449219432 src 39.535846118 ts2phc[44.996]: adding tstamp 39.949214816 to clock /dev/ptp3 ts2phc[44.996]: adding tstamp 40.000000000 to clock /dev/ptp1 ts2phc[44.996]: /dev/ptp3 offset -32 s2 freq +4359 ts2phc[45.488]: /dev/ptp3 SKIP extts index 0 at 40.449210192 src 40.515824678 ts2phc[45.980]: adding tstamp 40.949205568 to clock /dev/ptp3 ts2phc[45.980]: adding tstamp 41.000000000 to clock /dev/ptp1 ts2phc[45.980]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[46.636]: /dev/ptp3 SKIP extts index 0 at 41.449200928 src 41.664176902 ts2phc[47.132]: adding tstamp 41.949196288 to clock /dev/ptp3 ts2phc[47.132]: adding tstamp 42.000000000 to clock /dev/ptp1 ts2phc[47.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[47.620]: /dev/ptp3 SKIP extts index 0 at 42.449191656 src 42.648117190 ts2phc[48.112]: adding tstamp 42.949187016 to clock /dev/ptp3 ts2phc[48.112]: adding tstamp 43.000000000 to clock /dev/ptp1 ts2phc[48.112]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[48.604]: /dev/ptp3 SKIP extts index 0 at 43.449182384 src 43.632112582 ts2phc[49.100]: adding tstamp 43.949177736 to clock /dev/ptp3 ts2phc[49.100]: adding tstamp 44.000000000 to clock /dev/ptp1 ts2phc[49.100]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[49.588]: /dev/ptp3 SKIP extts index 0 at 44.449173096 src 44.616136774 ts2phc[50.080]: adding tstamp 44.949168464 to clock /dev/ptp3 ts2phc[50.080]: adding tstamp 45.000000000 to clock /dev/ptp1 ts2phc[50.080]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[50.572]: /dev/ptp3 SKIP extts index 0 at 45.449163816 src 45.600134662 ts2phc[51.064]: adding tstamp 45.949159160 to clock /dev/ptp3 ts2phc[51.064]: adding tstamp 46.000000000 to clock /dev/ptp1 ts2phc[51.064]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[51.556]: /dev/ptp3 SKIP extts index 0 at 46.449154528 src 46.584588550 ts2phc[52.048]: adding tstamp 46.949149896 to clock /dev/ptp3 ts2phc[52.048]: adding tstamp 47.000000000 to clock /dev/ptp1 ts2phc[52.048]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[52.540]: /dev/ptp3 SKIP extts index 0 at 47.449145256 src 47.568132198 ts2phc[53.032]: adding tstamp 47.949140616 to clock /dev/ptp3 ts2phc[53.032]: adding tstamp 48.000000000 to clock /dev/ptp1 ts2phc[53.032]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[53.524]: /dev/ptp3 SKIP extts index 0 at 48.449135968 src 48.552121446 ts2phc[54.016]: adding tstamp 48.949131320 to clock /dev/ptp3 ts2phc[54.016]: adding tstamp 49.000000000 to clock /dev/ptp1 ts2phc[54.016]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[54.512]: /dev/ptp3 SKIP extts index 0 at 49.449126680 src 49.540147014 ts2phc[55.000]: adding tstamp 49.949122040 to clock /dev/ptp3 ts2phc[55.000]: adding tstamp 50.000000000 to clock /dev/ptp1 ts2phc[55.000]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[55.492]: /dev/ptp3 SKIP extts index 0 at 50.449117400 src 50.520119078 ts2phc[55.988]: adding tstamp 50.949112768 to clock /dev/ptp3 ts2phc[55.988]: adding tstamp 51.000000000 to clock /dev/ptp1 ts2phc[55.988]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[56.476]: /dev/ptp3 SKIP extts index 0 at 51.449108120 src 51.504175910 ts2phc[57.132]: adding tstamp 51.949103480 to clock /dev/ptp3 ts2phc[57.132]: adding tstamp 52.000000000 to clock /dev/ptp1 ts2phc[57.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[57.624]: /dev/ptp3 SKIP extts index 0 at 52.449098840 src 52.651833574 ts2phc[58.116]: adding tstamp 52.949094200 to clock /dev/ptp3 ts2phc[58.116]: adding tstamp 53.000000000 to clock /dev/ptp1 ts2phc[58.116]: /dev/ptp3 offset 8 s2 freq +4392 ts2phc[58.612]: /dev/ptp3 SKIP extts index 0 at 53.449089560 src 53.639826918 ts2phc[59.100]: adding tstamp 53.949084920 to clock /dev/ptp3 ts2phc[59.100]: adding tstamp 54.000000000 to clock /dev/ptp1 ts2phc[59.100]: /dev/ptp3 offset 8 s2 freq +4394 ts2phc[59.592]: /dev/ptp3 SKIP extts index 0 at 54.449080272 src 54.619842278 ts2phc[60.084]: adding tstamp 54.949075624 to clock /dev/ptp3 ts2phc[60.084]: adding tstamp 55.000000000 to clock /dev/ptp1 ts2phc[60.084]: /dev/ptp3 offset 8 s2 freq +4397 ts2phc[60.576]: /dev/ptp3 SKIP extts index 0 at 55.449070968 src 55.603885542 ts2phc[61.068]: adding tstamp 55.949066312 to clock /dev/ptp3 ts2phc[61.068]: adding tstamp 56.000000000 to clock /dev/ptp1 ts2phc[61.068]: /dev/ptp3 offset 0 s2 freq +4391 ts2phc[61.560]: /dev/ptp3 SKIP extts index 0 at 56.449061680 src 56.587885798 ts2phc[62.052]: adding tstamp 56.949057032 to clock /dev/ptp3 ts2phc[62.052]: adding tstamp 57.000000000 to clock /dev/ptp1 ts2phc[62.052]: /dev/ptp3 offset -8 s2 freq +4383 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-03 20:51:58 +03:00
#define SJA1105_EXTTS_INTERVAL (HZ / 6)
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
/* This range is actually +/- SJA1105_MAX_ADJ_PPB
* divided by 1000 (ppb -> ppm) and with a 16-bit
* "fractional" part (actually fixed point).
* |
* v
* Convert scaled_ppm from the +/- ((10^6) << 16) range
* into the +/- (1 << 31) range.
*
* This forgoes a "ppb" numeric representation (up to NSEC_PER_SEC)
* and defines the scaling factor between scaled_ppm and the actual
* frequency adjustments of the PHC.
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
*
* ptpclkrate = scaled_ppm * 2^31 / (10^6 * 2^16)
* simplifies to
* ptpclkrate = scaled_ppm * 2^9 / 5^6
*/
#define SJA1105_CC_MULT_NUM (1 << 9)
#define SJA1105_CC_MULT_DEM 15625
#define SJA1105_CC_MULT 0x80000000
enum sja1105_ptp_clk_mode {
PTP_ADD_MODE = 1,
PTP_SET_MODE = 0,
};
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
net: dsa: sja1105: poll for extts events from a timer The current poll interval is enough to ensure that rising and falling edge events are not lost for a 1 PPS signal with 50% duty cycle. But when we deliver the events to user space, it will try to infer if they were corresponding to a rising or to a falling edge (the kernel driver doesn't know that either). User space will try to make that inference based on the time at which the PPS master had emitted the pulse (i.e. if it's a .0 time, it's rising edge, if it's .5 time, it's falling edge). But there is no in-kernel API for retrieving the precise timestamp corresponding to a PPS master (aka perout) pulse. So user space has to guess even that. It will read the PTP time on the PPS master right after we've delivered the extts event, and declare that the PPS master time was just the closest integer second, based on 2 thresholds (lower than .25, or higher than .75, and ignore anything else). Except that, if we poll for extts events (and our hardware doesn't really help us, by not providing an interrupt), then there is a risk that the poll period (and therefore the time at which the event is delivered) might confuse user space. Because we are always scheduling the next extts poll at SJA1105_EXTTS_INTERVAL "from now" (that's the only thing that the schedule_delayed_work() API gives us), it means that the start time of the next delayed workqueue will always be shifted to the right a little bit (shifted with the SPI access duration of this workqueue run). In turn, because user space sees extts events that are non-periodic compared to the PPS master's time, this means that it might start making wrong guesses about rising/falling edge. To understand the effect, here is the output of ts2phc currently. Notice the 'src' timestamps of the 'SKIP extts' events, and how they have a large wander. They keep increasing until the upper limit for the ignore threshold (.75 seconds), after which the application starts ignoring the _other_ edge. ts2phc[26.624]: /dev/ptp3 SKIP extts index 0 at 21.449898912 src 21.657784518 ts2phc[27.133]: adding tstamp 21.949894240 to clock /dev/ptp3 ts2phc[27.133]: adding tstamp 22.000000000 to clock /dev/ptp1 ts2phc[27.133]: /dev/ptp3 offset 640 s2 freq +5112 ts2phc[27.636]: /dev/ptp3 SKIP extts index 0 at 22.449889360 src 22.669398022 ts2phc[28.140]: adding tstamp 22.949884376 to clock /dev/ptp3 ts2phc[28.140]: adding tstamp 23.000000000 to clock /dev/ptp1 ts2phc[28.140]: /dev/ptp3 offset 96 s2 freq +4760 ts2phc[28.644]: /dev/ptp3 SKIP extts index 0 at 23.449879504 src 23.677420422 ts2phc[29.153]: adding tstamp 23.949874704 to clock /dev/ptp3 ts2phc[29.153]: adding tstamp 24.000000000 to clock /dev/ptp1 ts2phc[29.153]: /dev/ptp3 offset -264 s2 freq +4429 ts2phc[29.656]: /dev/ptp3 SKIP extts index 0 at 24.449870008 src 24.689407238 ts2phc[30.160]: adding tstamp 24.949865376 to clock /dev/ptp3 ts2phc[30.160]: adding tstamp 25.000000000 to clock /dev/ptp1 ts2phc[30.160]: /dev/ptp3 offset -280 s2 freq +4334 ts2phc[30.664]: /dev/ptp3 SKIP extts index 0 at 25.449860760 src 25.697449926 ts2phc[31.168]: adding tstamp 25.949856176 to clock /dev/ptp3 ts2phc[31.168]: adding tstamp 26.000000000 to clock /dev/ptp1 ts2phc[31.168]: /dev/ptp3 offset -176 s2 freq +4354 ts2phc[31.672]: /dev/ptp3 SKIP extts index 0 at 26.449851584 src 26.705433606 ts2phc[32.180]: adding tstamp 26.949846992 to clock /dev/ptp3 ts2phc[32.180]: adding tstamp 27.000000000 to clock /dev/ptp1 ts2phc[32.180]: /dev/ptp3 offset -80 s2 freq +4397 ts2phc[32.684]: /dev/ptp3 SKIP extts index 0 at 27.449842384 src 27.717415110 ts2phc[33.192]: adding tstamp 27.949837768 to clock /dev/ptp3 ts2phc[33.192]: adding tstamp 28.000000000 to clock /dev/ptp1 ts2phc[33.192]: /dev/ptp3 offset 0 s2 freq +4453 ts2phc[33.696]: /dev/ptp3 SKIP extts index 0 at 28.449833128 src 28.729412902 ts2phc[34.200]: adding tstamp 28.949828472 to clock /dev/ptp3 ts2phc[34.200]: adding tstamp 29.000000000 to clock /dev/ptp1 ts2phc[34.200]: /dev/ptp3 offset 8 s2 freq +4461 ts2phc[34.704]: /dev/ptp3 SKIP extts index 0 at 29.449823816 src 29.737416038 ts2phc[35.208]: adding tstamp 29.949819152 to clock /dev/ptp3 ts2phc[35.208]: adding tstamp 30.000000000 to clock /dev/ptp1 ts2phc[35.208]: /dev/ptp3 offset -8 s2 freq +4447 ts2phc[35.712]: /dev/ptp3 SKIP extts index 0 at 30.449814496 src 30.745554982 ts2phc[36.216]: adding tstamp 30.949809840 to clock /dev/ptp3 ts2phc[36.216]: adding tstamp 31.000000000 to clock /dev/ptp1 ts2phc[36.216]: /dev/ptp3 offset -8 s2 freq +4445 ts2phc[36.468]: /dev/ptp3 SKIP extts index 0 at 31.449805184 src 31.501109446 ts2phc[36.972]: adding tstamp 31.949800536 to clock /dev/ptp3 ts2phc[36.972]: adding tstamp 32.000000000 to clock /dev/ptp1 ts2phc[36.972]: /dev/ptp3 offset -8 s2 freq +4442 ts2phc[37.480]: /dev/ptp3 SKIP extts index 0 at 32.449795896 src 32.513320070 ts2phc[37.984]: adding tstamp 32.949791248 to clock /dev/ptp3 ts2phc[37.984]: adding tstamp 33.000000000 to clock /dev/ptp1 ts2phc[37.984]: /dev/ptp3 offset 0 s2 freq +4448 Fix that by taking the following measures: - Schedule the poll from a timer. Because we are really scheduling the timer periodically, the extts events delivered to user space are periodic too, and don't suffer from the "shift-to-the-right" effect. - Increase the poll period to 6 times a second. This imposes a smaller upper bound to the shift that can occur to the delivery time of extts events, and makes user space (ts2phc) to always interpret correctly which events should be skipped and which shouldn't. - Move the SPI readout itself to the main PTP kernel thread, instead of the generic workqueue. This is because the timer runs in atomic context, but is also better than before, because if needed, we can chrt & taskset this kernel thread, to ensure it gets enough priority under load. After this patch, one can notice that the wander is greatly reduced, and that the latencies of one extts poll are not propagated to the next. The 'src' timestamp that is skipped is never larger than .65 seconds (which means .15 seconds larger than the time at which the real event occurred at, and .10 seconds smaller than the .75 upper threshold for ignoring the falling edge): ts2phc[40.076]: adding tstamp 34.949261296 to clock /dev/ptp3 ts2phc[40.076]: adding tstamp 35.000000000 to clock /dev/ptp1 ts2phc[40.076]: /dev/ptp3 offset 48 s2 freq +4631 ts2phc[40.568]: /dev/ptp3 SKIP extts index 0 at 35.449256496 src 35.595791078 ts2phc[41.064]: adding tstamp 35.949251744 to clock /dev/ptp3 ts2phc[41.064]: adding tstamp 36.000000000 to clock /dev/ptp1 ts2phc[41.064]: /dev/ptp3 offset -224 s2 freq +4374 ts2phc[41.552]: /dev/ptp3 SKIP extts index 0 at 36.449247088 src 36.579825574 ts2phc[42.044]: adding tstamp 36.949242456 to clock /dev/ptp3 ts2phc[42.044]: adding tstamp 37.000000000 to clock /dev/ptp1 ts2phc[42.044]: /dev/ptp3 offset -240 s2 freq +4290 ts2phc[42.536]: /dev/ptp3 SKIP extts index 0 at 37.449237848 src 37.563828774 ts2phc[43.028]: adding tstamp 37.949233264 to clock /dev/ptp3 ts2phc[43.028]: adding tstamp 38.000000000 to clock /dev/ptp1 ts2phc[43.028]: /dev/ptp3 offset -144 s2 freq +4314 ts2phc[43.520]: /dev/ptp3 SKIP extts index 0 at 38.449228656 src 38.547823238 ts2phc[44.012]: adding tstamp 38.949224048 to clock /dev/ptp3 ts2phc[44.012]: adding tstamp 39.000000000 to clock /dev/ptp1 ts2phc[44.012]: /dev/ptp3 offset -80 s2 freq +4335 ts2phc[44.508]: /dev/ptp3 SKIP extts index 0 at 39.449219432 src 39.535846118 ts2phc[44.996]: adding tstamp 39.949214816 to clock /dev/ptp3 ts2phc[44.996]: adding tstamp 40.000000000 to clock /dev/ptp1 ts2phc[44.996]: /dev/ptp3 offset -32 s2 freq +4359 ts2phc[45.488]: /dev/ptp3 SKIP extts index 0 at 40.449210192 src 40.515824678 ts2phc[45.980]: adding tstamp 40.949205568 to clock /dev/ptp3 ts2phc[45.980]: adding tstamp 41.000000000 to clock /dev/ptp1 ts2phc[45.980]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[46.636]: /dev/ptp3 SKIP extts index 0 at 41.449200928 src 41.664176902 ts2phc[47.132]: adding tstamp 41.949196288 to clock /dev/ptp3 ts2phc[47.132]: adding tstamp 42.000000000 to clock /dev/ptp1 ts2phc[47.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[47.620]: /dev/ptp3 SKIP extts index 0 at 42.449191656 src 42.648117190 ts2phc[48.112]: adding tstamp 42.949187016 to clock /dev/ptp3 ts2phc[48.112]: adding tstamp 43.000000000 to clock /dev/ptp1 ts2phc[48.112]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[48.604]: /dev/ptp3 SKIP extts index 0 at 43.449182384 src 43.632112582 ts2phc[49.100]: adding tstamp 43.949177736 to clock /dev/ptp3 ts2phc[49.100]: adding tstamp 44.000000000 to clock /dev/ptp1 ts2phc[49.100]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[49.588]: /dev/ptp3 SKIP extts index 0 at 44.449173096 src 44.616136774 ts2phc[50.080]: adding tstamp 44.949168464 to clock /dev/ptp3 ts2phc[50.080]: adding tstamp 45.000000000 to clock /dev/ptp1 ts2phc[50.080]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[50.572]: /dev/ptp3 SKIP extts index 0 at 45.449163816 src 45.600134662 ts2phc[51.064]: adding tstamp 45.949159160 to clock /dev/ptp3 ts2phc[51.064]: adding tstamp 46.000000000 to clock /dev/ptp1 ts2phc[51.064]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[51.556]: /dev/ptp3 SKIP extts index 0 at 46.449154528 src 46.584588550 ts2phc[52.048]: adding tstamp 46.949149896 to clock /dev/ptp3 ts2phc[52.048]: adding tstamp 47.000000000 to clock /dev/ptp1 ts2phc[52.048]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[52.540]: /dev/ptp3 SKIP extts index 0 at 47.449145256 src 47.568132198 ts2phc[53.032]: adding tstamp 47.949140616 to clock /dev/ptp3 ts2phc[53.032]: adding tstamp 48.000000000 to clock /dev/ptp1 ts2phc[53.032]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[53.524]: /dev/ptp3 SKIP extts index 0 at 48.449135968 src 48.552121446 ts2phc[54.016]: adding tstamp 48.949131320 to clock /dev/ptp3 ts2phc[54.016]: adding tstamp 49.000000000 to clock /dev/ptp1 ts2phc[54.016]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[54.512]: /dev/ptp3 SKIP extts index 0 at 49.449126680 src 49.540147014 ts2phc[55.000]: adding tstamp 49.949122040 to clock /dev/ptp3 ts2phc[55.000]: adding tstamp 50.000000000 to clock /dev/ptp1 ts2phc[55.000]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[55.492]: /dev/ptp3 SKIP extts index 0 at 50.449117400 src 50.520119078 ts2phc[55.988]: adding tstamp 50.949112768 to clock /dev/ptp3 ts2phc[55.988]: adding tstamp 51.000000000 to clock /dev/ptp1 ts2phc[55.988]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[56.476]: /dev/ptp3 SKIP extts index 0 at 51.449108120 src 51.504175910 ts2phc[57.132]: adding tstamp 51.949103480 to clock /dev/ptp3 ts2phc[57.132]: adding tstamp 52.000000000 to clock /dev/ptp1 ts2phc[57.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[57.624]: /dev/ptp3 SKIP extts index 0 at 52.449098840 src 52.651833574 ts2phc[58.116]: adding tstamp 52.949094200 to clock /dev/ptp3 ts2phc[58.116]: adding tstamp 53.000000000 to clock /dev/ptp1 ts2phc[58.116]: /dev/ptp3 offset 8 s2 freq +4392 ts2phc[58.612]: /dev/ptp3 SKIP extts index 0 at 53.449089560 src 53.639826918 ts2phc[59.100]: adding tstamp 53.949084920 to clock /dev/ptp3 ts2phc[59.100]: adding tstamp 54.000000000 to clock /dev/ptp1 ts2phc[59.100]: /dev/ptp3 offset 8 s2 freq +4394 ts2phc[59.592]: /dev/ptp3 SKIP extts index 0 at 54.449080272 src 54.619842278 ts2phc[60.084]: adding tstamp 54.949075624 to clock /dev/ptp3 ts2phc[60.084]: adding tstamp 55.000000000 to clock /dev/ptp1 ts2phc[60.084]: /dev/ptp3 offset 8 s2 freq +4397 ts2phc[60.576]: /dev/ptp3 SKIP extts index 0 at 55.449070968 src 55.603885542 ts2phc[61.068]: adding tstamp 55.949066312 to clock /dev/ptp3 ts2phc[61.068]: adding tstamp 56.000000000 to clock /dev/ptp1 ts2phc[61.068]: /dev/ptp3 offset 0 s2 freq +4391 ts2phc[61.560]: /dev/ptp3 SKIP extts index 0 at 56.449061680 src 56.587885798 ts2phc[62.052]: adding tstamp 56.949057032 to clock /dev/ptp3 ts2phc[62.052]: adding tstamp 57.000000000 to clock /dev/ptp1 ts2phc[62.052]: /dev/ptp3 offset -8 s2 freq +4383 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-03 20:51:58 +03:00
#define extts_to_data(t) \
container_of((t), struct sja1105_ptp_data, extts_timer)
#define ptp_caps_to_data(d) \
container_of((d), struct sja1105_ptp_data, caps)
#define ptp_data_to_sja1105(d) \
container_of((d), struct sja1105_private, ptp_data)
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
net: dsa: convert to ndo_hwtstamp_get() and ndo_hwtstamp_set() New timestamping API was introduced in commit 66f7223039c0 ("net: add NDOs for configuring hardware timestamping") from kernel v6.6. It is time to convert DSA to the new API, so that the ndo_eth_ioctl() path can be removed completely. Move the ds->ops->port_hwtstamp_get() and ds->ops->port_hwtstamp_set() calls from dsa_user_ioctl() to dsa_user_hwtstamp_get() and dsa_user_hwtstamp_set(). Due to the fact that the underlying ifreq type changes to kernel_hwtstamp_config, the drivers and the Ocelot switchdev front-end, all hooked up directly or indirectly, must also be converted all at once. The conversion also updates the comment from dsa_port_supports_hwtstamp(), which is no longer true because kernel_hwtstamp_config is kernel memory and does not need copy_to_user(). I've deliberated whether it is necessary to also update "err != -EOPNOTSUPP" to a more general "!err", but all drivers now either return 0 or -EOPNOTSUPP. The existing logic from the ocelot_ioctl() function, to avoid configuring timestamping if the PHY supports the operation, is obsoleted by more advanced core logic in dev_set_hwtstamp_phylib(). This is only a partial preparation for proper PHY timestamping support. None of these switch driver currently sets up PTP traps for PHY timestamping, so setting dev->see_all_hwtstamp_requests is not yet necessary and the conversion is relatively trivial. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com> # felix, sja1105, mv88e6xxx Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev> Link: https://patch.msgid.link/20250508095236.887789-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2025-05-08 12:52:36 +03:00
int sja1105_hwtstamp_set(struct dsa_switch *ds, int port,
struct kernel_hwtstamp_config *config,
struct netlink_ext_ack *extack)
{
struct sja1105_private *priv = ds->priv;
unsigned long hwts_tx_en, hwts_rx_en;
hwts_tx_en = priv->hwts_tx_en;
hwts_rx_en = priv->hwts_rx_en;
net: dsa: convert to ndo_hwtstamp_get() and ndo_hwtstamp_set() New timestamping API was introduced in commit 66f7223039c0 ("net: add NDOs for configuring hardware timestamping") from kernel v6.6. It is time to convert DSA to the new API, so that the ndo_eth_ioctl() path can be removed completely. Move the ds->ops->port_hwtstamp_get() and ds->ops->port_hwtstamp_set() calls from dsa_user_ioctl() to dsa_user_hwtstamp_get() and dsa_user_hwtstamp_set(). Due to the fact that the underlying ifreq type changes to kernel_hwtstamp_config, the drivers and the Ocelot switchdev front-end, all hooked up directly or indirectly, must also be converted all at once. The conversion also updates the comment from dsa_port_supports_hwtstamp(), which is no longer true because kernel_hwtstamp_config is kernel memory and does not need copy_to_user(). I've deliberated whether it is necessary to also update "err != -EOPNOTSUPP" to a more general "!err", but all drivers now either return 0 or -EOPNOTSUPP. The existing logic from the ocelot_ioctl() function, to avoid configuring timestamping if the PHY supports the operation, is obsoleted by more advanced core logic in dev_set_hwtstamp_phylib(). This is only a partial preparation for proper PHY timestamping support. None of these switch driver currently sets up PTP traps for PHY timestamping, so setting dev->see_all_hwtstamp_requests is not yet necessary and the conversion is relatively trivial. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com> # felix, sja1105, mv88e6xxx Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev> Link: https://patch.msgid.link/20250508095236.887789-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2025-05-08 12:52:36 +03:00
switch (config->tx_type) {
case HWTSTAMP_TX_OFF:
hwts_tx_en &= ~BIT(port);
break;
case HWTSTAMP_TX_ON:
hwts_tx_en |= BIT(port);
break;
default:
return -ERANGE;
}
net: dsa: convert to ndo_hwtstamp_get() and ndo_hwtstamp_set() New timestamping API was introduced in commit 66f7223039c0 ("net: add NDOs for configuring hardware timestamping") from kernel v6.6. It is time to convert DSA to the new API, so that the ndo_eth_ioctl() path can be removed completely. Move the ds->ops->port_hwtstamp_get() and ds->ops->port_hwtstamp_set() calls from dsa_user_ioctl() to dsa_user_hwtstamp_get() and dsa_user_hwtstamp_set(). Due to the fact that the underlying ifreq type changes to kernel_hwtstamp_config, the drivers and the Ocelot switchdev front-end, all hooked up directly or indirectly, must also be converted all at once. The conversion also updates the comment from dsa_port_supports_hwtstamp(), which is no longer true because kernel_hwtstamp_config is kernel memory and does not need copy_to_user(). I've deliberated whether it is necessary to also update "err != -EOPNOTSUPP" to a more general "!err", but all drivers now either return 0 or -EOPNOTSUPP. The existing logic from the ocelot_ioctl() function, to avoid configuring timestamping if the PHY supports the operation, is obsoleted by more advanced core logic in dev_set_hwtstamp_phylib(). This is only a partial preparation for proper PHY timestamping support. None of these switch driver currently sets up PTP traps for PHY timestamping, so setting dev->see_all_hwtstamp_requests is not yet necessary and the conversion is relatively trivial. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com> # felix, sja1105, mv88e6xxx Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev> Link: https://patch.msgid.link/20250508095236.887789-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2025-05-08 12:52:36 +03:00
switch (config->rx_filter) {
case HWTSTAMP_FILTER_NONE:
hwts_rx_en &= ~BIT(port);
break;
case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
hwts_rx_en |= BIT(port);
break;
default:
return -ERANGE;
}
priv->hwts_tx_en = hwts_tx_en;
priv->hwts_rx_en = hwts_rx_en;
return 0;
}
net: dsa: convert to ndo_hwtstamp_get() and ndo_hwtstamp_set() New timestamping API was introduced in commit 66f7223039c0 ("net: add NDOs for configuring hardware timestamping") from kernel v6.6. It is time to convert DSA to the new API, so that the ndo_eth_ioctl() path can be removed completely. Move the ds->ops->port_hwtstamp_get() and ds->ops->port_hwtstamp_set() calls from dsa_user_ioctl() to dsa_user_hwtstamp_get() and dsa_user_hwtstamp_set(). Due to the fact that the underlying ifreq type changes to kernel_hwtstamp_config, the drivers and the Ocelot switchdev front-end, all hooked up directly or indirectly, must also be converted all at once. The conversion also updates the comment from dsa_port_supports_hwtstamp(), which is no longer true because kernel_hwtstamp_config is kernel memory and does not need copy_to_user(). I've deliberated whether it is necessary to also update "err != -EOPNOTSUPP" to a more general "!err", but all drivers now either return 0 or -EOPNOTSUPP. The existing logic from the ocelot_ioctl() function, to avoid configuring timestamping if the PHY supports the operation, is obsoleted by more advanced core logic in dev_set_hwtstamp_phylib(). This is only a partial preparation for proper PHY timestamping support. None of these switch driver currently sets up PTP traps for PHY timestamping, so setting dev->see_all_hwtstamp_requests is not yet necessary and the conversion is relatively trivial. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com> # felix, sja1105, mv88e6xxx Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev> Link: https://patch.msgid.link/20250508095236.887789-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2025-05-08 12:52:36 +03:00
int sja1105_hwtstamp_get(struct dsa_switch *ds, int port,
struct kernel_hwtstamp_config *config)
{
struct sja1105_private *priv = ds->priv;
net: dsa: convert to ndo_hwtstamp_get() and ndo_hwtstamp_set() New timestamping API was introduced in commit 66f7223039c0 ("net: add NDOs for configuring hardware timestamping") from kernel v6.6. It is time to convert DSA to the new API, so that the ndo_eth_ioctl() path can be removed completely. Move the ds->ops->port_hwtstamp_get() and ds->ops->port_hwtstamp_set() calls from dsa_user_ioctl() to dsa_user_hwtstamp_get() and dsa_user_hwtstamp_set(). Due to the fact that the underlying ifreq type changes to kernel_hwtstamp_config, the drivers and the Ocelot switchdev front-end, all hooked up directly or indirectly, must also be converted all at once. The conversion also updates the comment from dsa_port_supports_hwtstamp(), which is no longer true because kernel_hwtstamp_config is kernel memory and does not need copy_to_user(). I've deliberated whether it is necessary to also update "err != -EOPNOTSUPP" to a more general "!err", but all drivers now either return 0 or -EOPNOTSUPP. The existing logic from the ocelot_ioctl() function, to avoid configuring timestamping if the PHY supports the operation, is obsoleted by more advanced core logic in dev_set_hwtstamp_phylib(). This is only a partial preparation for proper PHY timestamping support. None of these switch driver currently sets up PTP traps for PHY timestamping, so setting dev->see_all_hwtstamp_requests is not yet necessary and the conversion is relatively trivial. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com> # felix, sja1105, mv88e6xxx Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev> Link: https://patch.msgid.link/20250508095236.887789-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2025-05-08 12:52:36 +03:00
config->flags = 0;
if (priv->hwts_tx_en & BIT(port))
net: dsa: convert to ndo_hwtstamp_get() and ndo_hwtstamp_set() New timestamping API was introduced in commit 66f7223039c0 ("net: add NDOs for configuring hardware timestamping") from kernel v6.6. It is time to convert DSA to the new API, so that the ndo_eth_ioctl() path can be removed completely. Move the ds->ops->port_hwtstamp_get() and ds->ops->port_hwtstamp_set() calls from dsa_user_ioctl() to dsa_user_hwtstamp_get() and dsa_user_hwtstamp_set(). Due to the fact that the underlying ifreq type changes to kernel_hwtstamp_config, the drivers and the Ocelot switchdev front-end, all hooked up directly or indirectly, must also be converted all at once. The conversion also updates the comment from dsa_port_supports_hwtstamp(), which is no longer true because kernel_hwtstamp_config is kernel memory and does not need copy_to_user(). I've deliberated whether it is necessary to also update "err != -EOPNOTSUPP" to a more general "!err", but all drivers now either return 0 or -EOPNOTSUPP. The existing logic from the ocelot_ioctl() function, to avoid configuring timestamping if the PHY supports the operation, is obsoleted by more advanced core logic in dev_set_hwtstamp_phylib(). This is only a partial preparation for proper PHY timestamping support. None of these switch driver currently sets up PTP traps for PHY timestamping, so setting dev->see_all_hwtstamp_requests is not yet necessary and the conversion is relatively trivial. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com> # felix, sja1105, mv88e6xxx Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev> Link: https://patch.msgid.link/20250508095236.887789-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2025-05-08 12:52:36 +03:00
config->tx_type = HWTSTAMP_TX_ON;
else
net: dsa: convert to ndo_hwtstamp_get() and ndo_hwtstamp_set() New timestamping API was introduced in commit 66f7223039c0 ("net: add NDOs for configuring hardware timestamping") from kernel v6.6. It is time to convert DSA to the new API, so that the ndo_eth_ioctl() path can be removed completely. Move the ds->ops->port_hwtstamp_get() and ds->ops->port_hwtstamp_set() calls from dsa_user_ioctl() to dsa_user_hwtstamp_get() and dsa_user_hwtstamp_set(). Due to the fact that the underlying ifreq type changes to kernel_hwtstamp_config, the drivers and the Ocelot switchdev front-end, all hooked up directly or indirectly, must also be converted all at once. The conversion also updates the comment from dsa_port_supports_hwtstamp(), which is no longer true because kernel_hwtstamp_config is kernel memory and does not need copy_to_user(). I've deliberated whether it is necessary to also update "err != -EOPNOTSUPP" to a more general "!err", but all drivers now either return 0 or -EOPNOTSUPP. The existing logic from the ocelot_ioctl() function, to avoid configuring timestamping if the PHY supports the operation, is obsoleted by more advanced core logic in dev_set_hwtstamp_phylib(). This is only a partial preparation for proper PHY timestamping support. None of these switch driver currently sets up PTP traps for PHY timestamping, so setting dev->see_all_hwtstamp_requests is not yet necessary and the conversion is relatively trivial. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com> # felix, sja1105, mv88e6xxx Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev> Link: https://patch.msgid.link/20250508095236.887789-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2025-05-08 12:52:36 +03:00
config->tx_type = HWTSTAMP_TX_OFF;
net: dsa: sja1105: always enable the send_meta options incl_srcpt has the limitation, mentioned in commit b4638af8885a ("net: dsa: sja1105: always enable the INCL_SRCPT option"), that frames with a MAC DA of 01:80:c2:xx:yy:zz will be received as 01:80:c2:00:00:zz unless PTP RX timestamping is enabled. The incl_srcpt option was initially unconditionally enabled, then that changed with commit 42824463d38d ("net: dsa: sja1105: Limit use of incl_srcpt to bridge+vlan mode"), then again with b4638af8885a ("net: dsa: sja1105: always enable the INCL_SRCPT option"). Bottom line is that it now needs to be always enabled, otherwise the driver does not have a reliable source of information regarding source_port and switch_id for link-local traffic (tag_8021q VLANs may be imprecise since now they identify an entire bridging domain when ports are not standalone). If we accept that PTP RX timestamping (and therefore, meta frame generation) is always enabled in hardware, then that limitation could be avoided and packets with any MAC DA can be properly received, because meta frames do contain the original bytes from the MAC DA of their associated link-local packet. This change enables meta frame generation unconditionally, which also has the nice side effects of simplifying the switch control path (a switch reset is no longer required on hwtstamping settings change) and the tagger data path (it no longer needs to be informed whether to expect meta frames or not - it always does). Fixes: 227d07a07ef1 ("net: dsa: sja1105: Add support for traffic through standalone ports") Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Reviewed-by: Simon Horman <simon.horman@corigine.com> Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2023-07-04 01:05:45 +03:00
if (priv->hwts_rx_en & BIT(port))
net: dsa: convert to ndo_hwtstamp_get() and ndo_hwtstamp_set() New timestamping API was introduced in commit 66f7223039c0 ("net: add NDOs for configuring hardware timestamping") from kernel v6.6. It is time to convert DSA to the new API, so that the ndo_eth_ioctl() path can be removed completely. Move the ds->ops->port_hwtstamp_get() and ds->ops->port_hwtstamp_set() calls from dsa_user_ioctl() to dsa_user_hwtstamp_get() and dsa_user_hwtstamp_set(). Due to the fact that the underlying ifreq type changes to kernel_hwtstamp_config, the drivers and the Ocelot switchdev front-end, all hooked up directly or indirectly, must also be converted all at once. The conversion also updates the comment from dsa_port_supports_hwtstamp(), which is no longer true because kernel_hwtstamp_config is kernel memory and does not need copy_to_user(). I've deliberated whether it is necessary to also update "err != -EOPNOTSUPP" to a more general "!err", but all drivers now either return 0 or -EOPNOTSUPP. The existing logic from the ocelot_ioctl() function, to avoid configuring timestamping if the PHY supports the operation, is obsoleted by more advanced core logic in dev_set_hwtstamp_phylib(). This is only a partial preparation for proper PHY timestamping support. None of these switch driver currently sets up PTP traps for PHY timestamping, so setting dev->see_all_hwtstamp_requests is not yet necessary and the conversion is relatively trivial. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com> # felix, sja1105, mv88e6xxx Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev> Link: https://patch.msgid.link/20250508095236.887789-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2025-05-08 12:52:36 +03:00
config->rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
else
net: dsa: convert to ndo_hwtstamp_get() and ndo_hwtstamp_set() New timestamping API was introduced in commit 66f7223039c0 ("net: add NDOs for configuring hardware timestamping") from kernel v6.6. It is time to convert DSA to the new API, so that the ndo_eth_ioctl() path can be removed completely. Move the ds->ops->port_hwtstamp_get() and ds->ops->port_hwtstamp_set() calls from dsa_user_ioctl() to dsa_user_hwtstamp_get() and dsa_user_hwtstamp_set(). Due to the fact that the underlying ifreq type changes to kernel_hwtstamp_config, the drivers and the Ocelot switchdev front-end, all hooked up directly or indirectly, must also be converted all at once. The conversion also updates the comment from dsa_port_supports_hwtstamp(), which is no longer true because kernel_hwtstamp_config is kernel memory and does not need copy_to_user(). I've deliberated whether it is necessary to also update "err != -EOPNOTSUPP" to a more general "!err", but all drivers now either return 0 or -EOPNOTSUPP. The existing logic from the ocelot_ioctl() function, to avoid configuring timestamping if the PHY supports the operation, is obsoleted by more advanced core logic in dev_set_hwtstamp_phylib(). This is only a partial preparation for proper PHY timestamping support. None of these switch driver currently sets up PTP traps for PHY timestamping, so setting dev->see_all_hwtstamp_requests is not yet necessary and the conversion is relatively trivial. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com> # felix, sja1105, mv88e6xxx Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev> Link: https://patch.msgid.link/20250508095236.887789-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2025-05-08 12:52:36 +03:00
config->rx_filter = HWTSTAMP_FILTER_NONE;
net: dsa: convert to ndo_hwtstamp_get() and ndo_hwtstamp_set() New timestamping API was introduced in commit 66f7223039c0 ("net: add NDOs for configuring hardware timestamping") from kernel v6.6. It is time to convert DSA to the new API, so that the ndo_eth_ioctl() path can be removed completely. Move the ds->ops->port_hwtstamp_get() and ds->ops->port_hwtstamp_set() calls from dsa_user_ioctl() to dsa_user_hwtstamp_get() and dsa_user_hwtstamp_set(). Due to the fact that the underlying ifreq type changes to kernel_hwtstamp_config, the drivers and the Ocelot switchdev front-end, all hooked up directly or indirectly, must also be converted all at once. The conversion also updates the comment from dsa_port_supports_hwtstamp(), which is no longer true because kernel_hwtstamp_config is kernel memory and does not need copy_to_user(). I've deliberated whether it is necessary to also update "err != -EOPNOTSUPP" to a more general "!err", but all drivers now either return 0 or -EOPNOTSUPP. The existing logic from the ocelot_ioctl() function, to avoid configuring timestamping if the PHY supports the operation, is obsoleted by more advanced core logic in dev_set_hwtstamp_phylib(). This is only a partial preparation for proper PHY timestamping support. None of these switch driver currently sets up PTP traps for PHY timestamping, so setting dev->see_all_hwtstamp_requests is not yet necessary and the conversion is relatively trivial. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Tested-by: Vladimir Oltean <vladimir.oltean@nxp.com> # felix, sja1105, mv88e6xxx Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev> Link: https://patch.msgid.link/20250508095236.887789-1-vladimir.oltean@nxp.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2025-05-08 12:52:36 +03:00
return 0;
}
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
int sja1105_get_ts_info(struct dsa_switch *ds, int port,
struct kernel_ethtool_ts_info *info)
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
{
struct sja1105_private *priv = ds->priv;
struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
/* Called during cleanup */
if (!ptp_data->clock)
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
return -ENODEV;
info->so_timestamping = SOF_TIMESTAMPING_TX_HARDWARE |
SOF_TIMESTAMPING_RX_HARDWARE |
SOF_TIMESTAMPING_RAW_HARDWARE;
info->tx_types = (1 << HWTSTAMP_TX_OFF) |
(1 << HWTSTAMP_TX_ON);
info->rx_filters = (1 << HWTSTAMP_FILTER_NONE) |
(1 << HWTSTAMP_FILTER_PTP_V2_L2_EVENT);
info->phc_index = ptp_clock_index(ptp_data->clock);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
return 0;
}
void sja1105et_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd,
enum packing_op op)
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
{
const int size = SJA1105_SIZE_PTP_CMD;
/* No need to keep this as part of the structure */
u64 valid = 1;
sja1105_packing(buf, &valid, 31, 31, size, op);
net: dsa: sja1105: Implement state machine for TAS with PTP clock source Tested using the following bash script and the tc from iproute2-next: #!/bin/bash set -e -u -o pipefail NSEC_PER_SEC="1000000000" gatemask() { local tc_list="$1" local mask=0 for tc in ${tc_list}; do mask=$((${mask} | (1 << ${tc}))) done printf "%02x" ${mask} } if ! systemctl is-active --quiet ptp4l; then echo "Please start the ptp4l service" exit fi now=$(phc_ctl /dev/ptp1 get | gawk '/clock time is/ { print $5; }') # Phase-align the base time to the start of the next second. sec=$(echo "${now}" | gawk -F. '{ print $1; }') base_time="$(((${sec} + 1) * ${NSEC_PER_SEC}))" tc qdisc add dev swp5 parent root handle 100 taprio \ num_tc 8 \ map 0 1 2 3 5 6 7 \ queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \ base-time ${base_time} \ sched-entry S $(gatemask 7) 100000 \ sched-entry S $(gatemask "0 1 2 3 4 5 6") 400000 \ clockid CLOCK_TAI flags 2 The "state machine" is a workqueue invoked after each manipulation command on the PTP clock (reset, adjust time, set time, adjust frequency) which checks over the state of the time-aware scheduler. So it is not monitored periodically, only in reaction to a PTP command typically triggered from a userspace daemon (linuxptp). Otherwise there is no reason for things to go wrong. Now that the timecounter/cyclecounter has been replaced with hardware operations on the PTP clock, the TAS Kconfig now depends upon PTP and the standalone clocksource operating mode has been removed. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-11-12 02:11:54 +02:00
sja1105_packing(buf, &cmd->ptpstrtsch, 30, 30, size, op);
sja1105_packing(buf, &cmd->ptpstopsch, 29, 29, size, op);
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
sja1105_packing(buf, &cmd->startptpcp, 28, 28, size, op);
sja1105_packing(buf, &cmd->stopptpcp, 27, 27, size, op);
sja1105_packing(buf, &cmd->resptp, 2, 2, size, op);
sja1105_packing(buf, &cmd->corrclk4ts, 1, 1, size, op);
sja1105_packing(buf, &cmd->ptpclkadd, 0, 0, size, op);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
}
void sja1105pqrs_ptp_cmd_packing(u8 *buf, struct sja1105_ptp_cmd *cmd,
enum packing_op op)
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
{
const int size = SJA1105_SIZE_PTP_CMD;
/* No need to keep this as part of the structure */
u64 valid = 1;
sja1105_packing(buf, &valid, 31, 31, size, op);
net: dsa: sja1105: Implement state machine for TAS with PTP clock source Tested using the following bash script and the tc from iproute2-next: #!/bin/bash set -e -u -o pipefail NSEC_PER_SEC="1000000000" gatemask() { local tc_list="$1" local mask=0 for tc in ${tc_list}; do mask=$((${mask} | (1 << ${tc}))) done printf "%02x" ${mask} } if ! systemctl is-active --quiet ptp4l; then echo "Please start the ptp4l service" exit fi now=$(phc_ctl /dev/ptp1 get | gawk '/clock time is/ { print $5; }') # Phase-align the base time to the start of the next second. sec=$(echo "${now}" | gawk -F. '{ print $1; }') base_time="$(((${sec} + 1) * ${NSEC_PER_SEC}))" tc qdisc add dev swp5 parent root handle 100 taprio \ num_tc 8 \ map 0 1 2 3 5 6 7 \ queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \ base-time ${base_time} \ sched-entry S $(gatemask 7) 100000 \ sched-entry S $(gatemask "0 1 2 3 4 5 6") 400000 \ clockid CLOCK_TAI flags 2 The "state machine" is a workqueue invoked after each manipulation command on the PTP clock (reset, adjust time, set time, adjust frequency) which checks over the state of the time-aware scheduler. So it is not monitored periodically, only in reaction to a PTP command typically triggered from a userspace daemon (linuxptp). Otherwise there is no reason for things to go wrong. Now that the timecounter/cyclecounter has been replaced with hardware operations on the PTP clock, the TAS Kconfig now depends upon PTP and the standalone clocksource operating mode has been removed. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-11-12 02:11:54 +02:00
sja1105_packing(buf, &cmd->ptpstrtsch, 30, 30, size, op);
sja1105_packing(buf, &cmd->ptpstopsch, 29, 29, size, op);
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
sja1105_packing(buf, &cmd->startptpcp, 28, 28, size, op);
sja1105_packing(buf, &cmd->stopptpcp, 27, 27, size, op);
sja1105_packing(buf, &cmd->resptp, 3, 3, size, op);
sja1105_packing(buf, &cmd->corrclk4ts, 2, 2, size, op);
sja1105_packing(buf, &cmd->ptpclkadd, 0, 0, size, op);
}
net: dsa: sja1105: Implement state machine for TAS with PTP clock source Tested using the following bash script and the tc from iproute2-next: #!/bin/bash set -e -u -o pipefail NSEC_PER_SEC="1000000000" gatemask() { local tc_list="$1" local mask=0 for tc in ${tc_list}; do mask=$((${mask} | (1 << ${tc}))) done printf "%02x" ${mask} } if ! systemctl is-active --quiet ptp4l; then echo "Please start the ptp4l service" exit fi now=$(phc_ctl /dev/ptp1 get | gawk '/clock time is/ { print $5; }') # Phase-align the base time to the start of the next second. sec=$(echo "${now}" | gawk -F. '{ print $1; }') base_time="$(((${sec} + 1) * ${NSEC_PER_SEC}))" tc qdisc add dev swp5 parent root handle 100 taprio \ num_tc 8 \ map 0 1 2 3 5 6 7 \ queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \ base-time ${base_time} \ sched-entry S $(gatemask 7) 100000 \ sched-entry S $(gatemask "0 1 2 3 4 5 6") 400000 \ clockid CLOCK_TAI flags 2 The "state machine" is a workqueue invoked after each manipulation command on the PTP clock (reset, adjust time, set time, adjust frequency) which checks over the state of the time-aware scheduler. So it is not monitored periodically, only in reaction to a PTP command typically triggered from a userspace daemon (linuxptp). Otherwise there is no reason for things to go wrong. Now that the timecounter/cyclecounter has been replaced with hardware operations on the PTP clock, the TAS Kconfig now depends upon PTP and the standalone clocksource operating mode has been removed. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-11-12 02:11:54 +02:00
int sja1105_ptp_commit(struct dsa_switch *ds, struct sja1105_ptp_cmd *cmd,
sja1105_spi_rw_mode_t rw)
{
net: dsa: sja1105: Implement state machine for TAS with PTP clock source Tested using the following bash script and the tc from iproute2-next: #!/bin/bash set -e -u -o pipefail NSEC_PER_SEC="1000000000" gatemask() { local tc_list="$1" local mask=0 for tc in ${tc_list}; do mask=$((${mask} | (1 << ${tc}))) done printf "%02x" ${mask} } if ! systemctl is-active --quiet ptp4l; then echo "Please start the ptp4l service" exit fi now=$(phc_ctl /dev/ptp1 get | gawk '/clock time is/ { print $5; }') # Phase-align the base time to the start of the next second. sec=$(echo "${now}" | gawk -F. '{ print $1; }') base_time="$(((${sec} + 1) * ${NSEC_PER_SEC}))" tc qdisc add dev swp5 parent root handle 100 taprio \ num_tc 8 \ map 0 1 2 3 5 6 7 \ queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \ base-time ${base_time} \ sched-entry S $(gatemask 7) 100000 \ sched-entry S $(gatemask "0 1 2 3 4 5 6") 400000 \ clockid CLOCK_TAI flags 2 The "state machine" is a workqueue invoked after each manipulation command on the PTP clock (reset, adjust time, set time, adjust frequency) which checks over the state of the time-aware scheduler. So it is not monitored periodically, only in reaction to a PTP command typically triggered from a userspace daemon (linuxptp). Otherwise there is no reason for things to go wrong. Now that the timecounter/cyclecounter has been replaced with hardware operations on the PTP clock, the TAS Kconfig now depends upon PTP and the standalone clocksource operating mode has been removed. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-11-12 02:11:54 +02:00
const struct sja1105_private *priv = ds->priv;
const struct sja1105_regs *regs = priv->info->regs;
u8 buf[SJA1105_SIZE_PTP_CMD] = {0};
int rc;
if (rw == SPI_WRITE)
priv->info->ptp_cmd_packing(buf, cmd, PACK);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
rc = sja1105_xfer_buf(priv, rw, regs->ptp_control, buf,
SJA1105_SIZE_PTP_CMD);
if (rw == SPI_READ)
priv->info->ptp_cmd_packing(buf, cmd, UNPACK);
return rc;
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
}
/* The switch returns partial timestamps (24 bits for SJA1105 E/T, which wrap
* around in 0.135 seconds, and 32 bits for P/Q/R/S, wrapping around in 34.35
* seconds).
*
* This receives the RX or TX MAC timestamps, provided by hardware as
* the lower bits of the cycle counter, sampled at the time the timestamp was
* collected.
*
* To reconstruct into a full 64-bit-wide timestamp, the cycle counter is
* read and the high-order bits are filled in.
*
* Must be called within one wraparound period of the partial timestamp since
* it was generated by the MAC.
*/
static u64 sja1105_tstamp_reconstruct(struct dsa_switch *ds, u64 now,
u64 ts_partial)
{
struct sja1105_private *priv = ds->priv;
u64 partial_tstamp_mask = CYCLECOUNTER_MASK(priv->info->ptp_ts_bits);
u64 ts_reconstructed;
ts_reconstructed = (now & ~partial_tstamp_mask) | ts_partial;
/* Check lower bits of current cycle counter against the timestamp.
* If the current cycle counter is lower than the partial timestamp,
* then wraparound surely occurred and must be accounted for.
*/
if ((now & partial_tstamp_mask) <= ts_partial)
ts_reconstructed -= (partial_tstamp_mask + 1);
return ts_reconstructed;
}
/* Reads the SPI interface for an egress timestamp generated by the switch
* for frames sent using management routes.
*
* SJA1105 E/T layout of the 4-byte SPI payload:
*
* 31 23 15 7 0
* | | | | |
* +-----+-----+-----+ ^
* ^ |
* | |
* 24-bit timestamp Update bit
*
*
* SJA1105 P/Q/R/S layout of the 8-byte SPI payload:
*
* 31 23 15 7 0 63 55 47 39 32
* | | | | | | | | | |
* ^ +-----+-----+-----+-----+
* | ^
* | |
* Update bit 32-bit timestamp
*
* Notice that the update bit is in the same place.
* To have common code for E/T and P/Q/R/S for reading the timestamp,
* we need to juggle with the offset and the bit indices.
*/
static int sja1105_ptpegr_ts_poll(struct dsa_switch *ds, int port, u64 *ts)
{
struct sja1105_private *priv = ds->priv;
const struct sja1105_regs *regs = priv->info->regs;
int tstamp_bit_start, tstamp_bit_end;
int timeout = 10;
u8 packed_buf[8];
u64 update;
int rc;
do {
rc = sja1105_xfer_buf(priv, SPI_READ, regs->ptpegr_ts[port],
packed_buf, priv->info->ptpegr_ts_bytes);
if (rc < 0)
return rc;
sja1105_unpack(packed_buf, &update, 0, 0,
priv->info->ptpegr_ts_bytes);
if (update)
break;
usleep_range(10, 50);
} while (--timeout);
if (!timeout)
return -ETIMEDOUT;
/* Point the end bit to the second 32-bit word on P/Q/R/S,
* no-op on E/T.
*/
tstamp_bit_end = (priv->info->ptpegr_ts_bytes - 4) * 8;
/* Shift the 24-bit timestamp on E/T to be collected from 31:8.
* No-op on P/Q/R/S.
*/
tstamp_bit_end += 32 - priv->info->ptp_ts_bits;
tstamp_bit_start = tstamp_bit_end + priv->info->ptp_ts_bits - 1;
*ts = 0;
sja1105_unpack(packed_buf, ts, tstamp_bit_start, tstamp_bit_end,
priv->info->ptpegr_ts_bytes);
return 0;
}
/* Caller must hold ptp_data->lock */
net: dsa: sja1105: Implement the .gettimex64 system call for PTP Through the PTP_SYS_OFFSET_EXTENDED ioctl, it is possible for userspace applications (i.e. phc2sys) to compensate for the delays incurred while reading the PHC's time. The task itself of taking the software timestamp is delegated to the SPI subsystem, through the newly introduced API in struct spi_transfer. The goal is to cross-timestamp I/O operations on the switch's PTP clock with values in the local system clock (CLOCK_REALTIME). For that we need to understand a bit of the hardware internals. The 'read PTP time' message is a 12 byte structure, first 4 bytes of which represent the SPI header, and the last 8 bytes represent the 64-bit PTP time. The switch itself starts processing the command immediately after receiving the last bit of the address, i.e. at the middle of byte 3 (last byte of header). The PTP time is shadowed to a buffer register in the switch, and retrieved atomically during the subsequent SPI frames. A similar thing goes on for the 'write PTP time' message, although in that case the switch waits until the 64-bit PTP time becomes fully available before taking any action. So the byte that needs to be software-timestamped is byte 11 (last) of the transfer. The patch creates a common (and local) sja1105_xfer implementation for the SPI I/O, and offers 3 front-ends: - sja1105_xfer_u32 and sja1105_xfer_u64: these are capable of optionally requesting a PTP timestamp - sja1105_xfer_buf: this is for large transfers (e.g. the static config buffer) and other misc data, and there is no point in giving timestamping capabilities to this. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-11-09 13:32:22 +02:00
static int sja1105_ptpclkval_read(struct sja1105_private *priv, u64 *ticks,
struct ptp_system_timestamp *ptp_sts)
{
const struct sja1105_regs *regs = priv->info->regs;
net: dsa: sja1105: Implement the .gettimex64 system call for PTP Through the PTP_SYS_OFFSET_EXTENDED ioctl, it is possible for userspace applications (i.e. phc2sys) to compensate for the delays incurred while reading the PHC's time. The task itself of taking the software timestamp is delegated to the SPI subsystem, through the newly introduced API in struct spi_transfer. The goal is to cross-timestamp I/O operations on the switch's PTP clock with values in the local system clock (CLOCK_REALTIME). For that we need to understand a bit of the hardware internals. The 'read PTP time' message is a 12 byte structure, first 4 bytes of which represent the SPI header, and the last 8 bytes represent the 64-bit PTP time. The switch itself starts processing the command immediately after receiving the last bit of the address, i.e. at the middle of byte 3 (last byte of header). The PTP time is shadowed to a buffer register in the switch, and retrieved atomically during the subsequent SPI frames. A similar thing goes on for the 'write PTP time' message, although in that case the switch waits until the 64-bit PTP time becomes fully available before taking any action. So the byte that needs to be software-timestamped is byte 11 (last) of the transfer. The patch creates a common (and local) sja1105_xfer implementation for the SPI I/O, and offers 3 front-ends: - sja1105_xfer_u32 and sja1105_xfer_u64: these are capable of optionally requesting a PTP timestamp - sja1105_xfer_buf: this is for large transfers (e.g. the static config buffer) and other misc data, and there is no point in giving timestamping capabilities to this. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-11-09 13:32:22 +02:00
return sja1105_xfer_u64(priv, SPI_READ, regs->ptpclkval, ticks,
ptp_sts);
}
/* Caller must hold ptp_data->lock */
static int sja1105_ptpclkval_write(struct sja1105_private *priv, u64 ticks,
struct ptp_system_timestamp *ptp_sts)
{
const struct sja1105_regs *regs = priv->info->regs;
net: dsa: sja1105: Implement the .gettimex64 system call for PTP Through the PTP_SYS_OFFSET_EXTENDED ioctl, it is possible for userspace applications (i.e. phc2sys) to compensate for the delays incurred while reading the PHC's time. The task itself of taking the software timestamp is delegated to the SPI subsystem, through the newly introduced API in struct spi_transfer. The goal is to cross-timestamp I/O operations on the switch's PTP clock with values in the local system clock (CLOCK_REALTIME). For that we need to understand a bit of the hardware internals. The 'read PTP time' message is a 12 byte structure, first 4 bytes of which represent the SPI header, and the last 8 bytes represent the 64-bit PTP time. The switch itself starts processing the command immediately after receiving the last bit of the address, i.e. at the middle of byte 3 (last byte of header). The PTP time is shadowed to a buffer register in the switch, and retrieved atomically during the subsequent SPI frames. A similar thing goes on for the 'write PTP time' message, although in that case the switch waits until the 64-bit PTP time becomes fully available before taking any action. So the byte that needs to be software-timestamped is byte 11 (last) of the transfer. The patch creates a common (and local) sja1105_xfer implementation for the SPI I/O, and offers 3 front-ends: - sja1105_xfer_u32 and sja1105_xfer_u64: these are capable of optionally requesting a PTP timestamp - sja1105_xfer_buf: this is for large transfers (e.g. the static config buffer) and other misc data, and there is no point in giving timestamping capabilities to this. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-11-09 13:32:22 +02:00
return sja1105_xfer_u64(priv, SPI_WRITE, regs->ptpclkval, &ticks,
ptp_sts);
}
net: dsa: sja1105: poll for extts events from a timer The current poll interval is enough to ensure that rising and falling edge events are not lost for a 1 PPS signal with 50% duty cycle. But when we deliver the events to user space, it will try to infer if they were corresponding to a rising or to a falling edge (the kernel driver doesn't know that either). User space will try to make that inference based on the time at which the PPS master had emitted the pulse (i.e. if it's a .0 time, it's rising edge, if it's .5 time, it's falling edge). But there is no in-kernel API for retrieving the precise timestamp corresponding to a PPS master (aka perout) pulse. So user space has to guess even that. It will read the PTP time on the PPS master right after we've delivered the extts event, and declare that the PPS master time was just the closest integer second, based on 2 thresholds (lower than .25, or higher than .75, and ignore anything else). Except that, if we poll for extts events (and our hardware doesn't really help us, by not providing an interrupt), then there is a risk that the poll period (and therefore the time at which the event is delivered) might confuse user space. Because we are always scheduling the next extts poll at SJA1105_EXTTS_INTERVAL "from now" (that's the only thing that the schedule_delayed_work() API gives us), it means that the start time of the next delayed workqueue will always be shifted to the right a little bit (shifted with the SPI access duration of this workqueue run). In turn, because user space sees extts events that are non-periodic compared to the PPS master's time, this means that it might start making wrong guesses about rising/falling edge. To understand the effect, here is the output of ts2phc currently. Notice the 'src' timestamps of the 'SKIP extts' events, and how they have a large wander. They keep increasing until the upper limit for the ignore threshold (.75 seconds), after which the application starts ignoring the _other_ edge. ts2phc[26.624]: /dev/ptp3 SKIP extts index 0 at 21.449898912 src 21.657784518 ts2phc[27.133]: adding tstamp 21.949894240 to clock /dev/ptp3 ts2phc[27.133]: adding tstamp 22.000000000 to clock /dev/ptp1 ts2phc[27.133]: /dev/ptp3 offset 640 s2 freq +5112 ts2phc[27.636]: /dev/ptp3 SKIP extts index 0 at 22.449889360 src 22.669398022 ts2phc[28.140]: adding tstamp 22.949884376 to clock /dev/ptp3 ts2phc[28.140]: adding tstamp 23.000000000 to clock /dev/ptp1 ts2phc[28.140]: /dev/ptp3 offset 96 s2 freq +4760 ts2phc[28.644]: /dev/ptp3 SKIP extts index 0 at 23.449879504 src 23.677420422 ts2phc[29.153]: adding tstamp 23.949874704 to clock /dev/ptp3 ts2phc[29.153]: adding tstamp 24.000000000 to clock /dev/ptp1 ts2phc[29.153]: /dev/ptp3 offset -264 s2 freq +4429 ts2phc[29.656]: /dev/ptp3 SKIP extts index 0 at 24.449870008 src 24.689407238 ts2phc[30.160]: adding tstamp 24.949865376 to clock /dev/ptp3 ts2phc[30.160]: adding tstamp 25.000000000 to clock /dev/ptp1 ts2phc[30.160]: /dev/ptp3 offset -280 s2 freq +4334 ts2phc[30.664]: /dev/ptp3 SKIP extts index 0 at 25.449860760 src 25.697449926 ts2phc[31.168]: adding tstamp 25.949856176 to clock /dev/ptp3 ts2phc[31.168]: adding tstamp 26.000000000 to clock /dev/ptp1 ts2phc[31.168]: /dev/ptp3 offset -176 s2 freq +4354 ts2phc[31.672]: /dev/ptp3 SKIP extts index 0 at 26.449851584 src 26.705433606 ts2phc[32.180]: adding tstamp 26.949846992 to clock /dev/ptp3 ts2phc[32.180]: adding tstamp 27.000000000 to clock /dev/ptp1 ts2phc[32.180]: /dev/ptp3 offset -80 s2 freq +4397 ts2phc[32.684]: /dev/ptp3 SKIP extts index 0 at 27.449842384 src 27.717415110 ts2phc[33.192]: adding tstamp 27.949837768 to clock /dev/ptp3 ts2phc[33.192]: adding tstamp 28.000000000 to clock /dev/ptp1 ts2phc[33.192]: /dev/ptp3 offset 0 s2 freq +4453 ts2phc[33.696]: /dev/ptp3 SKIP extts index 0 at 28.449833128 src 28.729412902 ts2phc[34.200]: adding tstamp 28.949828472 to clock /dev/ptp3 ts2phc[34.200]: adding tstamp 29.000000000 to clock /dev/ptp1 ts2phc[34.200]: /dev/ptp3 offset 8 s2 freq +4461 ts2phc[34.704]: /dev/ptp3 SKIP extts index 0 at 29.449823816 src 29.737416038 ts2phc[35.208]: adding tstamp 29.949819152 to clock /dev/ptp3 ts2phc[35.208]: adding tstamp 30.000000000 to clock /dev/ptp1 ts2phc[35.208]: /dev/ptp3 offset -8 s2 freq +4447 ts2phc[35.712]: /dev/ptp3 SKIP extts index 0 at 30.449814496 src 30.745554982 ts2phc[36.216]: adding tstamp 30.949809840 to clock /dev/ptp3 ts2phc[36.216]: adding tstamp 31.000000000 to clock /dev/ptp1 ts2phc[36.216]: /dev/ptp3 offset -8 s2 freq +4445 ts2phc[36.468]: /dev/ptp3 SKIP extts index 0 at 31.449805184 src 31.501109446 ts2phc[36.972]: adding tstamp 31.949800536 to clock /dev/ptp3 ts2phc[36.972]: adding tstamp 32.000000000 to clock /dev/ptp1 ts2phc[36.972]: /dev/ptp3 offset -8 s2 freq +4442 ts2phc[37.480]: /dev/ptp3 SKIP extts index 0 at 32.449795896 src 32.513320070 ts2phc[37.984]: adding tstamp 32.949791248 to clock /dev/ptp3 ts2phc[37.984]: adding tstamp 33.000000000 to clock /dev/ptp1 ts2phc[37.984]: /dev/ptp3 offset 0 s2 freq +4448 Fix that by taking the following measures: - Schedule the poll from a timer. Because we are really scheduling the timer periodically, the extts events delivered to user space are periodic too, and don't suffer from the "shift-to-the-right" effect. - Increase the poll period to 6 times a second. This imposes a smaller upper bound to the shift that can occur to the delivery time of extts events, and makes user space (ts2phc) to always interpret correctly which events should be skipped and which shouldn't. - Move the SPI readout itself to the main PTP kernel thread, instead of the generic workqueue. This is because the timer runs in atomic context, but is also better than before, because if needed, we can chrt & taskset this kernel thread, to ensure it gets enough priority under load. After this patch, one can notice that the wander is greatly reduced, and that the latencies of one extts poll are not propagated to the next. The 'src' timestamp that is skipped is never larger than .65 seconds (which means .15 seconds larger than the time at which the real event occurred at, and .10 seconds smaller than the .75 upper threshold for ignoring the falling edge): ts2phc[40.076]: adding tstamp 34.949261296 to clock /dev/ptp3 ts2phc[40.076]: adding tstamp 35.000000000 to clock /dev/ptp1 ts2phc[40.076]: /dev/ptp3 offset 48 s2 freq +4631 ts2phc[40.568]: /dev/ptp3 SKIP extts index 0 at 35.449256496 src 35.595791078 ts2phc[41.064]: adding tstamp 35.949251744 to clock /dev/ptp3 ts2phc[41.064]: adding tstamp 36.000000000 to clock /dev/ptp1 ts2phc[41.064]: /dev/ptp3 offset -224 s2 freq +4374 ts2phc[41.552]: /dev/ptp3 SKIP extts index 0 at 36.449247088 src 36.579825574 ts2phc[42.044]: adding tstamp 36.949242456 to clock /dev/ptp3 ts2phc[42.044]: adding tstamp 37.000000000 to clock /dev/ptp1 ts2phc[42.044]: /dev/ptp3 offset -240 s2 freq +4290 ts2phc[42.536]: /dev/ptp3 SKIP extts index 0 at 37.449237848 src 37.563828774 ts2phc[43.028]: adding tstamp 37.949233264 to clock /dev/ptp3 ts2phc[43.028]: adding tstamp 38.000000000 to clock /dev/ptp1 ts2phc[43.028]: /dev/ptp3 offset -144 s2 freq +4314 ts2phc[43.520]: /dev/ptp3 SKIP extts index 0 at 38.449228656 src 38.547823238 ts2phc[44.012]: adding tstamp 38.949224048 to clock /dev/ptp3 ts2phc[44.012]: adding tstamp 39.000000000 to clock /dev/ptp1 ts2phc[44.012]: /dev/ptp3 offset -80 s2 freq +4335 ts2phc[44.508]: /dev/ptp3 SKIP extts index 0 at 39.449219432 src 39.535846118 ts2phc[44.996]: adding tstamp 39.949214816 to clock /dev/ptp3 ts2phc[44.996]: adding tstamp 40.000000000 to clock /dev/ptp1 ts2phc[44.996]: /dev/ptp3 offset -32 s2 freq +4359 ts2phc[45.488]: /dev/ptp3 SKIP extts index 0 at 40.449210192 src 40.515824678 ts2phc[45.980]: adding tstamp 40.949205568 to clock /dev/ptp3 ts2phc[45.980]: adding tstamp 41.000000000 to clock /dev/ptp1 ts2phc[45.980]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[46.636]: /dev/ptp3 SKIP extts index 0 at 41.449200928 src 41.664176902 ts2phc[47.132]: adding tstamp 41.949196288 to clock /dev/ptp3 ts2phc[47.132]: adding tstamp 42.000000000 to clock /dev/ptp1 ts2phc[47.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[47.620]: /dev/ptp3 SKIP extts index 0 at 42.449191656 src 42.648117190 ts2phc[48.112]: adding tstamp 42.949187016 to clock /dev/ptp3 ts2phc[48.112]: adding tstamp 43.000000000 to clock /dev/ptp1 ts2phc[48.112]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[48.604]: /dev/ptp3 SKIP extts index 0 at 43.449182384 src 43.632112582 ts2phc[49.100]: adding tstamp 43.949177736 to clock /dev/ptp3 ts2phc[49.100]: adding tstamp 44.000000000 to clock /dev/ptp1 ts2phc[49.100]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[49.588]: /dev/ptp3 SKIP extts index 0 at 44.449173096 src 44.616136774 ts2phc[50.080]: adding tstamp 44.949168464 to clock /dev/ptp3 ts2phc[50.080]: adding tstamp 45.000000000 to clock /dev/ptp1 ts2phc[50.080]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[50.572]: /dev/ptp3 SKIP extts index 0 at 45.449163816 src 45.600134662 ts2phc[51.064]: adding tstamp 45.949159160 to clock /dev/ptp3 ts2phc[51.064]: adding tstamp 46.000000000 to clock /dev/ptp1 ts2phc[51.064]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[51.556]: /dev/ptp3 SKIP extts index 0 at 46.449154528 src 46.584588550 ts2phc[52.048]: adding tstamp 46.949149896 to clock /dev/ptp3 ts2phc[52.048]: adding tstamp 47.000000000 to clock /dev/ptp1 ts2phc[52.048]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[52.540]: /dev/ptp3 SKIP extts index 0 at 47.449145256 src 47.568132198 ts2phc[53.032]: adding tstamp 47.949140616 to clock /dev/ptp3 ts2phc[53.032]: adding tstamp 48.000000000 to clock /dev/ptp1 ts2phc[53.032]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[53.524]: /dev/ptp3 SKIP extts index 0 at 48.449135968 src 48.552121446 ts2phc[54.016]: adding tstamp 48.949131320 to clock /dev/ptp3 ts2phc[54.016]: adding tstamp 49.000000000 to clock /dev/ptp1 ts2phc[54.016]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[54.512]: /dev/ptp3 SKIP extts index 0 at 49.449126680 src 49.540147014 ts2phc[55.000]: adding tstamp 49.949122040 to clock /dev/ptp3 ts2phc[55.000]: adding tstamp 50.000000000 to clock /dev/ptp1 ts2phc[55.000]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[55.492]: /dev/ptp3 SKIP extts index 0 at 50.449117400 src 50.520119078 ts2phc[55.988]: adding tstamp 50.949112768 to clock /dev/ptp3 ts2phc[55.988]: adding tstamp 51.000000000 to clock /dev/ptp1 ts2phc[55.988]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[56.476]: /dev/ptp3 SKIP extts index 0 at 51.449108120 src 51.504175910 ts2phc[57.132]: adding tstamp 51.949103480 to clock /dev/ptp3 ts2phc[57.132]: adding tstamp 52.000000000 to clock /dev/ptp1 ts2phc[57.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[57.624]: /dev/ptp3 SKIP extts index 0 at 52.449098840 src 52.651833574 ts2phc[58.116]: adding tstamp 52.949094200 to clock /dev/ptp3 ts2phc[58.116]: adding tstamp 53.000000000 to clock /dev/ptp1 ts2phc[58.116]: /dev/ptp3 offset 8 s2 freq +4392 ts2phc[58.612]: /dev/ptp3 SKIP extts index 0 at 53.449089560 src 53.639826918 ts2phc[59.100]: adding tstamp 53.949084920 to clock /dev/ptp3 ts2phc[59.100]: adding tstamp 54.000000000 to clock /dev/ptp1 ts2phc[59.100]: /dev/ptp3 offset 8 s2 freq +4394 ts2phc[59.592]: /dev/ptp3 SKIP extts index 0 at 54.449080272 src 54.619842278 ts2phc[60.084]: adding tstamp 54.949075624 to clock /dev/ptp3 ts2phc[60.084]: adding tstamp 55.000000000 to clock /dev/ptp1 ts2phc[60.084]: /dev/ptp3 offset 8 s2 freq +4397 ts2phc[60.576]: /dev/ptp3 SKIP extts index 0 at 55.449070968 src 55.603885542 ts2phc[61.068]: adding tstamp 55.949066312 to clock /dev/ptp3 ts2phc[61.068]: adding tstamp 56.000000000 to clock /dev/ptp1 ts2phc[61.068]: /dev/ptp3 offset 0 s2 freq +4391 ts2phc[61.560]: /dev/ptp3 SKIP extts index 0 at 56.449061680 src 56.587885798 ts2phc[62.052]: adding tstamp 56.949057032 to clock /dev/ptp3 ts2phc[62.052]: adding tstamp 57.000000000 to clock /dev/ptp1 ts2phc[62.052]: /dev/ptp3 offset -8 s2 freq +4383 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-03 20:51:58 +03:00
static void sja1105_extts_poll(struct sja1105_private *priv)
{
struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
const struct sja1105_regs *regs = priv->info->regs;
struct ptp_clock_event event;
u64 ptpsyncts = 0;
int rc;
rc = sja1105_xfer_u64(priv, SPI_READ, regs->ptpsyncts, &ptpsyncts,
NULL);
if (rc < 0)
dev_err_ratelimited(priv->ds->dev,
"Failed to read PTPSYNCTS: %d\n", rc);
if (ptpsyncts && ptp_data->ptpsyncts != ptpsyncts) {
event.index = 0;
event.type = PTP_CLOCK_EXTTS;
event.timestamp = ns_to_ktime(sja1105_ticks_to_ns(ptpsyncts));
ptp_clock_event(ptp_data->clock, &event);
ptp_data->ptpsyncts = ptpsyncts;
}
}
static long sja1105_rxtstamp_work(struct ptp_clock_info *ptp)
{
struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp);
struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data);
struct dsa_switch *ds = priv->ds;
struct sk_buff *skb;
mutex_lock(&ptp_data->lock);
while ((skb = skb_dequeue(&ptp_data->skb_rxtstamp_queue)) != NULL) {
struct skb_shared_hwtstamps *shwt = skb_hwtstamps(skb);
u64 ticks, ts;
int rc;
net: dsa: sja1105: Implement the .gettimex64 system call for PTP Through the PTP_SYS_OFFSET_EXTENDED ioctl, it is possible for userspace applications (i.e. phc2sys) to compensate for the delays incurred while reading the PHC's time. The task itself of taking the software timestamp is delegated to the SPI subsystem, through the newly introduced API in struct spi_transfer. The goal is to cross-timestamp I/O operations on the switch's PTP clock with values in the local system clock (CLOCK_REALTIME). For that we need to understand a bit of the hardware internals. The 'read PTP time' message is a 12 byte structure, first 4 bytes of which represent the SPI header, and the last 8 bytes represent the 64-bit PTP time. The switch itself starts processing the command immediately after receiving the last bit of the address, i.e. at the middle of byte 3 (last byte of header). The PTP time is shadowed to a buffer register in the switch, and retrieved atomically during the subsequent SPI frames. A similar thing goes on for the 'write PTP time' message, although in that case the switch waits until the 64-bit PTP time becomes fully available before taking any action. So the byte that needs to be software-timestamped is byte 11 (last) of the transfer. The patch creates a common (and local) sja1105_xfer implementation for the SPI I/O, and offers 3 front-ends: - sja1105_xfer_u32 and sja1105_xfer_u64: these are capable of optionally requesting a PTP timestamp - sja1105_xfer_buf: this is for large transfers (e.g. the static config buffer) and other misc data, and there is no point in giving timestamping capabilities to this. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-11-09 13:32:22 +02:00
rc = sja1105_ptpclkval_read(priv, &ticks, NULL);
if (rc < 0) {
dev_err(ds->dev, "Failed to read PTP clock: %d\n", rc);
kfree_skb(skb);
continue;
}
*shwt = (struct skb_shared_hwtstamps) {0};
ts = SJA1105_SKB_CB(skb)->tstamp;
ts = sja1105_tstamp_reconstruct(ds, ticks, ts);
shwt->hwtstamp = ns_to_ktime(sja1105_ticks_to_ns(ts));
netif_rx(skb);
}
net: dsa: sja1105: poll for extts events from a timer The current poll interval is enough to ensure that rising and falling edge events are not lost for a 1 PPS signal with 50% duty cycle. But when we deliver the events to user space, it will try to infer if they were corresponding to a rising or to a falling edge (the kernel driver doesn't know that either). User space will try to make that inference based on the time at which the PPS master had emitted the pulse (i.e. if it's a .0 time, it's rising edge, if it's .5 time, it's falling edge). But there is no in-kernel API for retrieving the precise timestamp corresponding to a PPS master (aka perout) pulse. So user space has to guess even that. It will read the PTP time on the PPS master right after we've delivered the extts event, and declare that the PPS master time was just the closest integer second, based on 2 thresholds (lower than .25, or higher than .75, and ignore anything else). Except that, if we poll for extts events (and our hardware doesn't really help us, by not providing an interrupt), then there is a risk that the poll period (and therefore the time at which the event is delivered) might confuse user space. Because we are always scheduling the next extts poll at SJA1105_EXTTS_INTERVAL "from now" (that's the only thing that the schedule_delayed_work() API gives us), it means that the start time of the next delayed workqueue will always be shifted to the right a little bit (shifted with the SPI access duration of this workqueue run). In turn, because user space sees extts events that are non-periodic compared to the PPS master's time, this means that it might start making wrong guesses about rising/falling edge. To understand the effect, here is the output of ts2phc currently. Notice the 'src' timestamps of the 'SKIP extts' events, and how they have a large wander. They keep increasing until the upper limit for the ignore threshold (.75 seconds), after which the application starts ignoring the _other_ edge. ts2phc[26.624]: /dev/ptp3 SKIP extts index 0 at 21.449898912 src 21.657784518 ts2phc[27.133]: adding tstamp 21.949894240 to clock /dev/ptp3 ts2phc[27.133]: adding tstamp 22.000000000 to clock /dev/ptp1 ts2phc[27.133]: /dev/ptp3 offset 640 s2 freq +5112 ts2phc[27.636]: /dev/ptp3 SKIP extts index 0 at 22.449889360 src 22.669398022 ts2phc[28.140]: adding tstamp 22.949884376 to clock /dev/ptp3 ts2phc[28.140]: adding tstamp 23.000000000 to clock /dev/ptp1 ts2phc[28.140]: /dev/ptp3 offset 96 s2 freq +4760 ts2phc[28.644]: /dev/ptp3 SKIP extts index 0 at 23.449879504 src 23.677420422 ts2phc[29.153]: adding tstamp 23.949874704 to clock /dev/ptp3 ts2phc[29.153]: adding tstamp 24.000000000 to clock /dev/ptp1 ts2phc[29.153]: /dev/ptp3 offset -264 s2 freq +4429 ts2phc[29.656]: /dev/ptp3 SKIP extts index 0 at 24.449870008 src 24.689407238 ts2phc[30.160]: adding tstamp 24.949865376 to clock /dev/ptp3 ts2phc[30.160]: adding tstamp 25.000000000 to clock /dev/ptp1 ts2phc[30.160]: /dev/ptp3 offset -280 s2 freq +4334 ts2phc[30.664]: /dev/ptp3 SKIP extts index 0 at 25.449860760 src 25.697449926 ts2phc[31.168]: adding tstamp 25.949856176 to clock /dev/ptp3 ts2phc[31.168]: adding tstamp 26.000000000 to clock /dev/ptp1 ts2phc[31.168]: /dev/ptp3 offset -176 s2 freq +4354 ts2phc[31.672]: /dev/ptp3 SKIP extts index 0 at 26.449851584 src 26.705433606 ts2phc[32.180]: adding tstamp 26.949846992 to clock /dev/ptp3 ts2phc[32.180]: adding tstamp 27.000000000 to clock /dev/ptp1 ts2phc[32.180]: /dev/ptp3 offset -80 s2 freq +4397 ts2phc[32.684]: /dev/ptp3 SKIP extts index 0 at 27.449842384 src 27.717415110 ts2phc[33.192]: adding tstamp 27.949837768 to clock /dev/ptp3 ts2phc[33.192]: adding tstamp 28.000000000 to clock /dev/ptp1 ts2phc[33.192]: /dev/ptp3 offset 0 s2 freq +4453 ts2phc[33.696]: /dev/ptp3 SKIP extts index 0 at 28.449833128 src 28.729412902 ts2phc[34.200]: adding tstamp 28.949828472 to clock /dev/ptp3 ts2phc[34.200]: adding tstamp 29.000000000 to clock /dev/ptp1 ts2phc[34.200]: /dev/ptp3 offset 8 s2 freq +4461 ts2phc[34.704]: /dev/ptp3 SKIP extts index 0 at 29.449823816 src 29.737416038 ts2phc[35.208]: adding tstamp 29.949819152 to clock /dev/ptp3 ts2phc[35.208]: adding tstamp 30.000000000 to clock /dev/ptp1 ts2phc[35.208]: /dev/ptp3 offset -8 s2 freq +4447 ts2phc[35.712]: /dev/ptp3 SKIP extts index 0 at 30.449814496 src 30.745554982 ts2phc[36.216]: adding tstamp 30.949809840 to clock /dev/ptp3 ts2phc[36.216]: adding tstamp 31.000000000 to clock /dev/ptp1 ts2phc[36.216]: /dev/ptp3 offset -8 s2 freq +4445 ts2phc[36.468]: /dev/ptp3 SKIP extts index 0 at 31.449805184 src 31.501109446 ts2phc[36.972]: adding tstamp 31.949800536 to clock /dev/ptp3 ts2phc[36.972]: adding tstamp 32.000000000 to clock /dev/ptp1 ts2phc[36.972]: /dev/ptp3 offset -8 s2 freq +4442 ts2phc[37.480]: /dev/ptp3 SKIP extts index 0 at 32.449795896 src 32.513320070 ts2phc[37.984]: adding tstamp 32.949791248 to clock /dev/ptp3 ts2phc[37.984]: adding tstamp 33.000000000 to clock /dev/ptp1 ts2phc[37.984]: /dev/ptp3 offset 0 s2 freq +4448 Fix that by taking the following measures: - Schedule the poll from a timer. Because we are really scheduling the timer periodically, the extts events delivered to user space are periodic too, and don't suffer from the "shift-to-the-right" effect. - Increase the poll period to 6 times a second. This imposes a smaller upper bound to the shift that can occur to the delivery time of extts events, and makes user space (ts2phc) to always interpret correctly which events should be skipped and which shouldn't. - Move the SPI readout itself to the main PTP kernel thread, instead of the generic workqueue. This is because the timer runs in atomic context, but is also better than before, because if needed, we can chrt & taskset this kernel thread, to ensure it gets enough priority under load. After this patch, one can notice that the wander is greatly reduced, and that the latencies of one extts poll are not propagated to the next. The 'src' timestamp that is skipped is never larger than .65 seconds (which means .15 seconds larger than the time at which the real event occurred at, and .10 seconds smaller than the .75 upper threshold for ignoring the falling edge): ts2phc[40.076]: adding tstamp 34.949261296 to clock /dev/ptp3 ts2phc[40.076]: adding tstamp 35.000000000 to clock /dev/ptp1 ts2phc[40.076]: /dev/ptp3 offset 48 s2 freq +4631 ts2phc[40.568]: /dev/ptp3 SKIP extts index 0 at 35.449256496 src 35.595791078 ts2phc[41.064]: adding tstamp 35.949251744 to clock /dev/ptp3 ts2phc[41.064]: adding tstamp 36.000000000 to clock /dev/ptp1 ts2phc[41.064]: /dev/ptp3 offset -224 s2 freq +4374 ts2phc[41.552]: /dev/ptp3 SKIP extts index 0 at 36.449247088 src 36.579825574 ts2phc[42.044]: adding tstamp 36.949242456 to clock /dev/ptp3 ts2phc[42.044]: adding tstamp 37.000000000 to clock /dev/ptp1 ts2phc[42.044]: /dev/ptp3 offset -240 s2 freq +4290 ts2phc[42.536]: /dev/ptp3 SKIP extts index 0 at 37.449237848 src 37.563828774 ts2phc[43.028]: adding tstamp 37.949233264 to clock /dev/ptp3 ts2phc[43.028]: adding tstamp 38.000000000 to clock /dev/ptp1 ts2phc[43.028]: /dev/ptp3 offset -144 s2 freq +4314 ts2phc[43.520]: /dev/ptp3 SKIP extts index 0 at 38.449228656 src 38.547823238 ts2phc[44.012]: adding tstamp 38.949224048 to clock /dev/ptp3 ts2phc[44.012]: adding tstamp 39.000000000 to clock /dev/ptp1 ts2phc[44.012]: /dev/ptp3 offset -80 s2 freq +4335 ts2phc[44.508]: /dev/ptp3 SKIP extts index 0 at 39.449219432 src 39.535846118 ts2phc[44.996]: adding tstamp 39.949214816 to clock /dev/ptp3 ts2phc[44.996]: adding tstamp 40.000000000 to clock /dev/ptp1 ts2phc[44.996]: /dev/ptp3 offset -32 s2 freq +4359 ts2phc[45.488]: /dev/ptp3 SKIP extts index 0 at 40.449210192 src 40.515824678 ts2phc[45.980]: adding tstamp 40.949205568 to clock /dev/ptp3 ts2phc[45.980]: adding tstamp 41.000000000 to clock /dev/ptp1 ts2phc[45.980]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[46.636]: /dev/ptp3 SKIP extts index 0 at 41.449200928 src 41.664176902 ts2phc[47.132]: adding tstamp 41.949196288 to clock /dev/ptp3 ts2phc[47.132]: adding tstamp 42.000000000 to clock /dev/ptp1 ts2phc[47.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[47.620]: /dev/ptp3 SKIP extts index 0 at 42.449191656 src 42.648117190 ts2phc[48.112]: adding tstamp 42.949187016 to clock /dev/ptp3 ts2phc[48.112]: adding tstamp 43.000000000 to clock /dev/ptp1 ts2phc[48.112]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[48.604]: /dev/ptp3 SKIP extts index 0 at 43.449182384 src 43.632112582 ts2phc[49.100]: adding tstamp 43.949177736 to clock /dev/ptp3 ts2phc[49.100]: adding tstamp 44.000000000 to clock /dev/ptp1 ts2phc[49.100]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[49.588]: /dev/ptp3 SKIP extts index 0 at 44.449173096 src 44.616136774 ts2phc[50.080]: adding tstamp 44.949168464 to clock /dev/ptp3 ts2phc[50.080]: adding tstamp 45.000000000 to clock /dev/ptp1 ts2phc[50.080]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[50.572]: /dev/ptp3 SKIP extts index 0 at 45.449163816 src 45.600134662 ts2phc[51.064]: adding tstamp 45.949159160 to clock /dev/ptp3 ts2phc[51.064]: adding tstamp 46.000000000 to clock /dev/ptp1 ts2phc[51.064]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[51.556]: /dev/ptp3 SKIP extts index 0 at 46.449154528 src 46.584588550 ts2phc[52.048]: adding tstamp 46.949149896 to clock /dev/ptp3 ts2phc[52.048]: adding tstamp 47.000000000 to clock /dev/ptp1 ts2phc[52.048]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[52.540]: /dev/ptp3 SKIP extts index 0 at 47.449145256 src 47.568132198 ts2phc[53.032]: adding tstamp 47.949140616 to clock /dev/ptp3 ts2phc[53.032]: adding tstamp 48.000000000 to clock /dev/ptp1 ts2phc[53.032]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[53.524]: /dev/ptp3 SKIP extts index 0 at 48.449135968 src 48.552121446 ts2phc[54.016]: adding tstamp 48.949131320 to clock /dev/ptp3 ts2phc[54.016]: adding tstamp 49.000000000 to clock /dev/ptp1 ts2phc[54.016]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[54.512]: /dev/ptp3 SKIP extts index 0 at 49.449126680 src 49.540147014 ts2phc[55.000]: adding tstamp 49.949122040 to clock /dev/ptp3 ts2phc[55.000]: adding tstamp 50.000000000 to clock /dev/ptp1 ts2phc[55.000]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[55.492]: /dev/ptp3 SKIP extts index 0 at 50.449117400 src 50.520119078 ts2phc[55.988]: adding tstamp 50.949112768 to clock /dev/ptp3 ts2phc[55.988]: adding tstamp 51.000000000 to clock /dev/ptp1 ts2phc[55.988]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[56.476]: /dev/ptp3 SKIP extts index 0 at 51.449108120 src 51.504175910 ts2phc[57.132]: adding tstamp 51.949103480 to clock /dev/ptp3 ts2phc[57.132]: adding tstamp 52.000000000 to clock /dev/ptp1 ts2phc[57.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[57.624]: /dev/ptp3 SKIP extts index 0 at 52.449098840 src 52.651833574 ts2phc[58.116]: adding tstamp 52.949094200 to clock /dev/ptp3 ts2phc[58.116]: adding tstamp 53.000000000 to clock /dev/ptp1 ts2phc[58.116]: /dev/ptp3 offset 8 s2 freq +4392 ts2phc[58.612]: /dev/ptp3 SKIP extts index 0 at 53.449089560 src 53.639826918 ts2phc[59.100]: adding tstamp 53.949084920 to clock /dev/ptp3 ts2phc[59.100]: adding tstamp 54.000000000 to clock /dev/ptp1 ts2phc[59.100]: /dev/ptp3 offset 8 s2 freq +4394 ts2phc[59.592]: /dev/ptp3 SKIP extts index 0 at 54.449080272 src 54.619842278 ts2phc[60.084]: adding tstamp 54.949075624 to clock /dev/ptp3 ts2phc[60.084]: adding tstamp 55.000000000 to clock /dev/ptp1 ts2phc[60.084]: /dev/ptp3 offset 8 s2 freq +4397 ts2phc[60.576]: /dev/ptp3 SKIP extts index 0 at 55.449070968 src 55.603885542 ts2phc[61.068]: adding tstamp 55.949066312 to clock /dev/ptp3 ts2phc[61.068]: adding tstamp 56.000000000 to clock /dev/ptp1 ts2phc[61.068]: /dev/ptp3 offset 0 s2 freq +4391 ts2phc[61.560]: /dev/ptp3 SKIP extts index 0 at 56.449061680 src 56.587885798 ts2phc[62.052]: adding tstamp 56.949057032 to clock /dev/ptp3 ts2phc[62.052]: adding tstamp 57.000000000 to clock /dev/ptp1 ts2phc[62.052]: /dev/ptp3 offset -8 s2 freq +4383 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-03 20:51:58 +03:00
if (ptp_data->extts_enabled)
sja1105_extts_poll(priv);
mutex_unlock(&ptp_data->lock);
/* Don't restart */
return -1;
}
bool sja1105_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb)
{
struct sja1105_private *priv = ds->priv;
struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
net: dsa: sja1105: always enable the send_meta options incl_srcpt has the limitation, mentioned in commit b4638af8885a ("net: dsa: sja1105: always enable the INCL_SRCPT option"), that frames with a MAC DA of 01:80:c2:xx:yy:zz will be received as 01:80:c2:00:00:zz unless PTP RX timestamping is enabled. The incl_srcpt option was initially unconditionally enabled, then that changed with commit 42824463d38d ("net: dsa: sja1105: Limit use of incl_srcpt to bridge+vlan mode"), then again with b4638af8885a ("net: dsa: sja1105: always enable the INCL_SRCPT option"). Bottom line is that it now needs to be always enabled, otherwise the driver does not have a reliable source of information regarding source_port and switch_id for link-local traffic (tag_8021q VLANs may be imprecise since now they identify an entire bridging domain when ports are not standalone). If we accept that PTP RX timestamping (and therefore, meta frame generation) is always enabled in hardware, then that limitation could be avoided and packets with any MAC DA can be properly received, because meta frames do contain the original bytes from the MAC DA of their associated link-local packet. This change enables meta frame generation unconditionally, which also has the nice side effects of simplifying the switch control path (a switch reset is no longer required on hwtstamping settings change) and the tagger data path (it no longer needs to be informed whether to expect meta frames or not - it always does). Fixes: 227d07a07ef1 ("net: dsa: sja1105: Add support for traffic through standalone ports") Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Reviewed-by: Simon Horman <simon.horman@corigine.com> Reviewed-by: Florian Fainelli <florian.fainelli@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2023-07-04 01:05:45 +03:00
if (!(priv->hwts_rx_en & BIT(port)))
return false;
/* We need to read the full PTP clock to reconstruct the Rx
* timestamp. For that we need a sleepable context.
*/
skb_queue_tail(&ptp_data->skb_rxtstamp_queue, skb);
ptp_schedule_worker(ptp_data->clock, 0);
return true;
}
bool sja1110_rxtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb)
{
struct skb_shared_hwtstamps *shwt = skb_hwtstamps(skb);
u64 ts = SJA1105_SKB_CB(skb)->tstamp;
*shwt = (struct skb_shared_hwtstamps) {0};
shwt->hwtstamp = ns_to_ktime(sja1105_ticks_to_ns(ts));
/* Don't defer */
return false;
}
/* Called from dsa_skb_defer_rx_timestamp */
bool sja1105_port_rxtstamp(struct dsa_switch *ds, int port,
struct sk_buff *skb, unsigned int type)
{
struct sja1105_private *priv = ds->priv;
return priv->info->rxtstamp(ds, port, skb);
}
void sja1110_process_meta_tstamp(struct dsa_switch *ds, int port, u8 ts_id,
enum sja1110_meta_tstamp dir, u64 tstamp)
{
struct sja1105_private *priv = ds->priv;
struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
struct sk_buff *skb, *skb_tmp, *skb_match = NULL;
struct skb_shared_hwtstamps shwt = {0};
/* We don't care about RX timestamps on the CPU port */
if (dir == SJA1110_META_TSTAMP_RX)
return;
spin_lock(&ptp_data->skb_txtstamp_queue.lock);
skb_queue_walk_safe(&ptp_data->skb_txtstamp_queue, skb, skb_tmp) {
if (SJA1105_SKB_CB(skb)->ts_id != ts_id)
continue;
__skb_unlink(skb, &ptp_data->skb_txtstamp_queue);
skb_match = skb;
break;
}
spin_unlock(&ptp_data->skb_txtstamp_queue.lock);
if (WARN_ON(!skb_match))
return;
shwt.hwtstamp = ns_to_ktime(sja1105_ticks_to_ns(tstamp));
skb_complete_tx_timestamp(skb_match, &shwt);
}
net: dsa: sja1105: implement TX timestamping for SJA1110 The TX timestamping procedure for SJA1105 is a bit unconventional because the transmit procedure itself is unconventional. Control packets (and therefore PTP as well) are transmitted to a specific port in SJA1105 using "management routes" which must be written over SPI to the switch. These are one-shot rules that match by destination MAC address on traffic coming from the CPU port, and select the precise destination port for that packet. So to transmit a packet from NET_TX softirq context, we actually need to defer to a process context so that we can perform that SPI write before we send the packet. The DSA master dev_queue_xmit() runs in process context, and we poll until the switch confirms it took the TX timestamp, then we annotate the skb clone with that TX timestamp. This is why the sja1105 driver does not need an skb queue for TX timestamping. But the SJA1110 is a bit (not much!) more conventional, and you can request 2-step TX timestamping through the DSA header, as well as give the switch a cookie (timestamp ID) which it will give back to you when it has the timestamp. So now we do need a queue for keeping the skb clones until their TX timestamps become available. The interesting part is that the metadata frames from SJA1105 haven't disappeared completely. On SJA1105 they were used as follow-ups which contained RX timestamps, but on SJA1110 they are actually TX completion packets, which contain a variable (up to 32) array of timestamps. Why an array? Because: - not only is the TX timestamp on the egress port being communicated, but also the RX timestamp on the CPU port. Nice, but we don't care about that, so we ignore it. - because a packet could be multicast to multiple egress ports, each port takes its own timestamp, and the TX completion packet contains the individual timestamps on each port. This is unconventional because switches typically have a timestamping FIFO and raise an interrupt, but this one doesn't. So the tagger needs to detect and parse meta frames, and call into the main switch driver, which pairs the timestamps with the skbs in the TX timestamping queue which are waiting for one. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2021-06-11 22:01:31 +03:00
/* In addition to cloning the skb which is done by the common
* sja1105_port_txtstamp, we need to generate a timestamp ID and save the
* packet to the TX timestamping queue.
*/
void sja1110_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb)
{
struct sk_buff *clone = SJA1105_SKB_CB(skb)->clone;
struct sja1105_private *priv = ds->priv;
struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
net: dsa: sja1105: implement TX timestamping for SJA1110 The TX timestamping procedure for SJA1105 is a bit unconventional because the transmit procedure itself is unconventional. Control packets (and therefore PTP as well) are transmitted to a specific port in SJA1105 using "management routes" which must be written over SPI to the switch. These are one-shot rules that match by destination MAC address on traffic coming from the CPU port, and select the precise destination port for that packet. So to transmit a packet from NET_TX softirq context, we actually need to defer to a process context so that we can perform that SPI write before we send the packet. The DSA master dev_queue_xmit() runs in process context, and we poll until the switch confirms it took the TX timestamp, then we annotate the skb clone with that TX timestamp. This is why the sja1105 driver does not need an skb queue for TX timestamping. But the SJA1110 is a bit (not much!) more conventional, and you can request 2-step TX timestamping through the DSA header, as well as give the switch a cookie (timestamp ID) which it will give back to you when it has the timestamp. So now we do need a queue for keeping the skb clones until their TX timestamps become available. The interesting part is that the metadata frames from SJA1105 haven't disappeared completely. On SJA1105 they were used as follow-ups which contained RX timestamps, but on SJA1110 they are actually TX completion packets, which contain a variable (up to 32) array of timestamps. Why an array? Because: - not only is the TX timestamp on the egress port being communicated, but also the RX timestamp on the CPU port. Nice, but we don't care about that, so we ignore it. - because a packet could be multicast to multiple egress ports, each port takes its own timestamp, and the TX completion packet contains the individual timestamps on each port. This is unconventional because switches typically have a timestamping FIFO and raise an interrupt, but this one doesn't. So the tagger needs to detect and parse meta frames, and call into the main switch driver, which pairs the timestamps with the skbs in the TX timestamping queue which are waiting for one. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2021-06-11 22:01:31 +03:00
u8 ts_id;
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
spin_lock(&priv->ts_id_lock);
net: dsa: sja1105: implement TX timestamping for SJA1110 The TX timestamping procedure for SJA1105 is a bit unconventional because the transmit procedure itself is unconventional. Control packets (and therefore PTP as well) are transmitted to a specific port in SJA1105 using "management routes" which must be written over SPI to the switch. These are one-shot rules that match by destination MAC address on traffic coming from the CPU port, and select the precise destination port for that packet. So to transmit a packet from NET_TX softirq context, we actually need to defer to a process context so that we can perform that SPI write before we send the packet. The DSA master dev_queue_xmit() runs in process context, and we poll until the switch confirms it took the TX timestamp, then we annotate the skb clone with that TX timestamp. This is why the sja1105 driver does not need an skb queue for TX timestamping. But the SJA1110 is a bit (not much!) more conventional, and you can request 2-step TX timestamping through the DSA header, as well as give the switch a cookie (timestamp ID) which it will give back to you when it has the timestamp. So now we do need a queue for keeping the skb clones until their TX timestamps become available. The interesting part is that the metadata frames from SJA1105 haven't disappeared completely. On SJA1105 they were used as follow-ups which contained RX timestamps, but on SJA1110 they are actually TX completion packets, which contain a variable (up to 32) array of timestamps. Why an array? Because: - not only is the TX timestamp on the egress port being communicated, but also the RX timestamp on the CPU port. Nice, but we don't care about that, so we ignore it. - because a packet could be multicast to multiple egress ports, each port takes its own timestamp, and the TX completion packet contains the individual timestamps on each port. This is unconventional because switches typically have a timestamping FIFO and raise an interrupt, but this one doesn't. So the tagger needs to detect and parse meta frames, and call into the main switch driver, which pairs the timestamps with the skbs in the TX timestamping queue which are waiting for one. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2021-06-11 22:01:31 +03:00
ts_id = priv->ts_id;
net: dsa: sja1105: implement TX timestamping for SJA1110 The TX timestamping procedure for SJA1105 is a bit unconventional because the transmit procedure itself is unconventional. Control packets (and therefore PTP as well) are transmitted to a specific port in SJA1105 using "management routes" which must be written over SPI to the switch. These are one-shot rules that match by destination MAC address on traffic coming from the CPU port, and select the precise destination port for that packet. So to transmit a packet from NET_TX softirq context, we actually need to defer to a process context so that we can perform that SPI write before we send the packet. The DSA master dev_queue_xmit() runs in process context, and we poll until the switch confirms it took the TX timestamp, then we annotate the skb clone with that TX timestamp. This is why the sja1105 driver does not need an skb queue for TX timestamping. But the SJA1110 is a bit (not much!) more conventional, and you can request 2-step TX timestamping through the DSA header, as well as give the switch a cookie (timestamp ID) which it will give back to you when it has the timestamp. So now we do need a queue for keeping the skb clones until their TX timestamps become available. The interesting part is that the metadata frames from SJA1105 haven't disappeared completely. On SJA1105 they were used as follow-ups which contained RX timestamps, but on SJA1110 they are actually TX completion packets, which contain a variable (up to 32) array of timestamps. Why an array? Because: - not only is the TX timestamp on the egress port being communicated, but also the RX timestamp on the CPU port. Nice, but we don't care about that, so we ignore it. - because a packet could be multicast to multiple egress ports, each port takes its own timestamp, and the TX completion packet contains the individual timestamps on each port. This is unconventional because switches typically have a timestamping FIFO and raise an interrupt, but this one doesn't. So the tagger needs to detect and parse meta frames, and call into the main switch driver, which pairs the timestamps with the skbs in the TX timestamping queue which are waiting for one. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2021-06-11 22:01:31 +03:00
/* Deal automatically with 8-bit wraparound */
priv->ts_id++;
net: dsa: sja1105: implement TX timestamping for SJA1110 The TX timestamping procedure for SJA1105 is a bit unconventional because the transmit procedure itself is unconventional. Control packets (and therefore PTP as well) are transmitted to a specific port in SJA1105 using "management routes" which must be written over SPI to the switch. These are one-shot rules that match by destination MAC address on traffic coming from the CPU port, and select the precise destination port for that packet. So to transmit a packet from NET_TX softirq context, we actually need to defer to a process context so that we can perform that SPI write before we send the packet. The DSA master dev_queue_xmit() runs in process context, and we poll until the switch confirms it took the TX timestamp, then we annotate the skb clone with that TX timestamp. This is why the sja1105 driver does not need an skb queue for TX timestamping. But the SJA1110 is a bit (not much!) more conventional, and you can request 2-step TX timestamping through the DSA header, as well as give the switch a cookie (timestamp ID) which it will give back to you when it has the timestamp. So now we do need a queue for keeping the skb clones until their TX timestamps become available. The interesting part is that the metadata frames from SJA1105 haven't disappeared completely. On SJA1105 they were used as follow-ups which contained RX timestamps, but on SJA1110 they are actually TX completion packets, which contain a variable (up to 32) array of timestamps. Why an array? Because: - not only is the TX timestamp on the egress port being communicated, but also the RX timestamp on the CPU port. Nice, but we don't care about that, so we ignore it. - because a packet could be multicast to multiple egress ports, each port takes its own timestamp, and the TX completion packet contains the individual timestamps on each port. This is unconventional because switches typically have a timestamping FIFO and raise an interrupt, but this one doesn't. So the tagger needs to detect and parse meta frames, and call into the main switch driver, which pairs the timestamps with the skbs in the TX timestamping queue which are waiting for one. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2021-06-11 22:01:31 +03:00
SJA1105_SKB_CB(clone)->ts_id = ts_id;
spin_unlock(&priv->ts_id_lock);
net: dsa: sja1105: implement TX timestamping for SJA1110 The TX timestamping procedure for SJA1105 is a bit unconventional because the transmit procedure itself is unconventional. Control packets (and therefore PTP as well) are transmitted to a specific port in SJA1105 using "management routes" which must be written over SPI to the switch. These are one-shot rules that match by destination MAC address on traffic coming from the CPU port, and select the precise destination port for that packet. So to transmit a packet from NET_TX softirq context, we actually need to defer to a process context so that we can perform that SPI write before we send the packet. The DSA master dev_queue_xmit() runs in process context, and we poll until the switch confirms it took the TX timestamp, then we annotate the skb clone with that TX timestamp. This is why the sja1105 driver does not need an skb queue for TX timestamping. But the SJA1110 is a bit (not much!) more conventional, and you can request 2-step TX timestamping through the DSA header, as well as give the switch a cookie (timestamp ID) which it will give back to you when it has the timestamp. So now we do need a queue for keeping the skb clones until their TX timestamps become available. The interesting part is that the metadata frames from SJA1105 haven't disappeared completely. On SJA1105 they were used as follow-ups which contained RX timestamps, but on SJA1110 they are actually TX completion packets, which contain a variable (up to 32) array of timestamps. Why an array? Because: - not only is the TX timestamp on the egress port being communicated, but also the RX timestamp on the CPU port. Nice, but we don't care about that, so we ignore it. - because a packet could be multicast to multiple egress ports, each port takes its own timestamp, and the TX completion packet contains the individual timestamps on each port. This is unconventional because switches typically have a timestamping FIFO and raise an interrupt, but this one doesn't. So the tagger needs to detect and parse meta frames, and call into the main switch driver, which pairs the timestamps with the skbs in the TX timestamping queue which are waiting for one. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2021-06-11 22:01:31 +03:00
skb_queue_tail(&ptp_data->skb_txtstamp_queue, clone);
net: dsa: sja1105: implement TX timestamping for SJA1110 The TX timestamping procedure for SJA1105 is a bit unconventional because the transmit procedure itself is unconventional. Control packets (and therefore PTP as well) are transmitted to a specific port in SJA1105 using "management routes" which must be written over SPI to the switch. These are one-shot rules that match by destination MAC address on traffic coming from the CPU port, and select the precise destination port for that packet. So to transmit a packet from NET_TX softirq context, we actually need to defer to a process context so that we can perform that SPI write before we send the packet. The DSA master dev_queue_xmit() runs in process context, and we poll until the switch confirms it took the TX timestamp, then we annotate the skb clone with that TX timestamp. This is why the sja1105 driver does not need an skb queue for TX timestamping. But the SJA1110 is a bit (not much!) more conventional, and you can request 2-step TX timestamping through the DSA header, as well as give the switch a cookie (timestamp ID) which it will give back to you when it has the timestamp. So now we do need a queue for keeping the skb clones until their TX timestamps become available. The interesting part is that the metadata frames from SJA1105 haven't disappeared completely. On SJA1105 they were used as follow-ups which contained RX timestamps, but on SJA1110 they are actually TX completion packets, which contain a variable (up to 32) array of timestamps. Why an array? Because: - not only is the TX timestamp on the egress port being communicated, but also the RX timestamp on the CPU port. Nice, but we don't care about that, so we ignore it. - because a packet could be multicast to multiple egress ports, each port takes its own timestamp, and the TX completion packet contains the individual timestamps on each port. This is unconventional because switches typically have a timestamping FIFO and raise an interrupt, but this one doesn't. So the tagger needs to detect and parse meta frames, and call into the main switch driver, which pairs the timestamps with the skbs in the TX timestamping queue which are waiting for one. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2021-06-11 22:01:31 +03:00
}
/* Called from dsa_skb_tx_timestamp. This callback is just to clone
* the skb and have it available in SJA1105_SKB_CB in the .port_deferred_xmit
* callback, where we will timestamp it synchronously.
*/
void sja1105_port_txtstamp(struct dsa_switch *ds, int port, struct sk_buff *skb)
{
struct sja1105_private *priv = ds->priv;
struct sk_buff *clone;
if (!(priv->hwts_tx_en & BIT(port)))
return;
clone = skb_clone_sk(skb);
if (!clone)
return;
SJA1105_SKB_CB(skb)->clone = clone;
net: dsa: sja1105: implement TX timestamping for SJA1110 The TX timestamping procedure for SJA1105 is a bit unconventional because the transmit procedure itself is unconventional. Control packets (and therefore PTP as well) are transmitted to a specific port in SJA1105 using "management routes" which must be written over SPI to the switch. These are one-shot rules that match by destination MAC address on traffic coming from the CPU port, and select the precise destination port for that packet. So to transmit a packet from NET_TX softirq context, we actually need to defer to a process context so that we can perform that SPI write before we send the packet. The DSA master dev_queue_xmit() runs in process context, and we poll until the switch confirms it took the TX timestamp, then we annotate the skb clone with that TX timestamp. This is why the sja1105 driver does not need an skb queue for TX timestamping. But the SJA1110 is a bit (not much!) more conventional, and you can request 2-step TX timestamping through the DSA header, as well as give the switch a cookie (timestamp ID) which it will give back to you when it has the timestamp. So now we do need a queue for keeping the skb clones until their TX timestamps become available. The interesting part is that the metadata frames from SJA1105 haven't disappeared completely. On SJA1105 they were used as follow-ups which contained RX timestamps, but on SJA1110 they are actually TX completion packets, which contain a variable (up to 32) array of timestamps. Why an array? Because: - not only is the TX timestamp on the egress port being communicated, but also the RX timestamp on the CPU port. Nice, but we don't care about that, so we ignore it. - because a packet could be multicast to multiple egress ports, each port takes its own timestamp, and the TX completion packet contains the individual timestamps on each port. This is unconventional because switches typically have a timestamping FIFO and raise an interrupt, but this one doesn't. So the tagger needs to detect and parse meta frames, and call into the main switch driver, which pairs the timestamps with the skbs in the TX timestamping queue which are waiting for one. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2021-06-11 22:01:31 +03:00
if (priv->info->txtstamp)
priv->info->txtstamp(ds, port, skb);
}
static int sja1105_ptp_reset(struct dsa_switch *ds)
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
{
struct sja1105_private *priv = ds->priv;
struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
net: dsa: sja1105: Change the PTP command access pattern The PTP command register contains enable bits for: - Putting the 64-bit PTPCLKVAL register in add/subtract or write mode - Taking timestamps off of the corrected vs free-running clock - Starting/stopping the TTEthernet scheduling - Starting/stopping PPS output - Resetting the switch When a command needs to be issued (e.g. "change the PTPCLKVAL from write mode to add/subtract mode"), one cannot simply write to the command register setting the PTPCLKADD bit to 1, because that would zeroize the other settings. One also cannot do a read-modify-write (that would be too easy for this hardware) because not all bits of the command register are readable over SPI. So this leaves us with the only option of keeping the value of the PTP command register in the driver, and operating on that. Actually there are 2 types of PTP operations now: - Operations that modify the cached PTP command. These operate on ptp_data->cmd as a pointer. - Operations that apply all previously cached PTP settings, but don't otherwise cache what they did themselves. The sja1105_ptp_reset function is such an example. It copies the ptp_data->cmd on stack before modifying and writing it to SPI. This practically means that struct sja1105_ptp_cmd is no longer an implementation detail, since it needs to be stored in full into struct sja1105_ptp_data, and hence in struct sja1105_private. So the (*ptp_cmd) function prototype can change and take struct sja1105_ptp_cmd as second argument now. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-10-12 02:18:16 +03:00
struct sja1105_ptp_cmd cmd = ptp_data->cmd;
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
int rc;
mutex_lock(&ptp_data->lock);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
cmd.resptp = 1;
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
dev_dbg(ds->dev, "Resetting PTP clock\n");
net: dsa: sja1105: Implement state machine for TAS with PTP clock source Tested using the following bash script and the tc from iproute2-next: #!/bin/bash set -e -u -o pipefail NSEC_PER_SEC="1000000000" gatemask() { local tc_list="$1" local mask=0 for tc in ${tc_list}; do mask=$((${mask} | (1 << ${tc}))) done printf "%02x" ${mask} } if ! systemctl is-active --quiet ptp4l; then echo "Please start the ptp4l service" exit fi now=$(phc_ctl /dev/ptp1 get | gawk '/clock time is/ { print $5; }') # Phase-align the base time to the start of the next second. sec=$(echo "${now}" | gawk -F. '{ print $1; }') base_time="$(((${sec} + 1) * ${NSEC_PER_SEC}))" tc qdisc add dev swp5 parent root handle 100 taprio \ num_tc 8 \ map 0 1 2 3 5 6 7 \ queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \ base-time ${base_time} \ sched-entry S $(gatemask 7) 100000 \ sched-entry S $(gatemask "0 1 2 3 4 5 6") 400000 \ clockid CLOCK_TAI flags 2 The "state machine" is a workqueue invoked after each manipulation command on the PTP clock (reset, adjust time, set time, adjust frequency) which checks over the state of the time-aware scheduler. So it is not monitored periodically, only in reaction to a PTP command typically triggered from a userspace daemon (linuxptp). Otherwise there is no reason for things to go wrong. Now that the timecounter/cyclecounter has been replaced with hardware operations on the PTP clock, the TAS Kconfig now depends upon PTP and the standalone clocksource operating mode has been removed. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-11-12 02:11:54 +02:00
rc = sja1105_ptp_commit(ds, &cmd, SPI_WRITE);
sja1105_tas_clockstep(priv->ds);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
mutex_unlock(&ptp_data->lock);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
return rc;
}
/* Caller must hold ptp_data->lock */
int __sja1105_ptp_gettimex(struct dsa_switch *ds, u64 *ns,
struct ptp_system_timestamp *ptp_sts)
{
struct sja1105_private *priv = ds->priv;
u64 ticks;
int rc;
rc = sja1105_ptpclkval_read(priv, &ticks, ptp_sts);
if (rc < 0) {
dev_err(ds->dev, "Failed to read PTP clock: %d\n", rc);
return rc;
}
*ns = sja1105_ticks_to_ns(ticks);
return 0;
}
net: dsa: sja1105: Implement the .gettimex64 system call for PTP Through the PTP_SYS_OFFSET_EXTENDED ioctl, it is possible for userspace applications (i.e. phc2sys) to compensate for the delays incurred while reading the PHC's time. The task itself of taking the software timestamp is delegated to the SPI subsystem, through the newly introduced API in struct spi_transfer. The goal is to cross-timestamp I/O operations on the switch's PTP clock with values in the local system clock (CLOCK_REALTIME). For that we need to understand a bit of the hardware internals. The 'read PTP time' message is a 12 byte structure, first 4 bytes of which represent the SPI header, and the last 8 bytes represent the 64-bit PTP time. The switch itself starts processing the command immediately after receiving the last bit of the address, i.e. at the middle of byte 3 (last byte of header). The PTP time is shadowed to a buffer register in the switch, and retrieved atomically during the subsequent SPI frames. A similar thing goes on for the 'write PTP time' message, although in that case the switch waits until the 64-bit PTP time becomes fully available before taking any action. So the byte that needs to be software-timestamped is byte 11 (last) of the transfer. The patch creates a common (and local) sja1105_xfer implementation for the SPI I/O, and offers 3 front-ends: - sja1105_xfer_u32 and sja1105_xfer_u64: these are capable of optionally requesting a PTP timestamp - sja1105_xfer_buf: this is for large transfers (e.g. the static config buffer) and other misc data, and there is no point in giving timestamping capabilities to this. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-11-09 13:32:22 +02:00
static int sja1105_ptp_gettimex(struct ptp_clock_info *ptp,
struct timespec64 *ts,
struct ptp_system_timestamp *ptp_sts)
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
{
struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp);
struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data);
u64 now = 0;
int rc;
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
mutex_lock(&ptp_data->lock);
rc = __sja1105_ptp_gettimex(priv->ds, &now, ptp_sts);
*ts = ns_to_timespec64(now);
mutex_unlock(&ptp_data->lock);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
return rc;
}
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
/* Caller must hold ptp_data->lock */
static int sja1105_ptp_mode_set(struct sja1105_private *priv,
enum sja1105_ptp_clk_mode mode)
{
struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
if (ptp_data->cmd.ptpclkadd == mode)
return 0;
ptp_data->cmd.ptpclkadd = mode;
net: dsa: sja1105: Implement state machine for TAS with PTP clock source Tested using the following bash script and the tc from iproute2-next: #!/bin/bash set -e -u -o pipefail NSEC_PER_SEC="1000000000" gatemask() { local tc_list="$1" local mask=0 for tc in ${tc_list}; do mask=$((${mask} | (1 << ${tc}))) done printf "%02x" ${mask} } if ! systemctl is-active --quiet ptp4l; then echo "Please start the ptp4l service" exit fi now=$(phc_ctl /dev/ptp1 get | gawk '/clock time is/ { print $5; }') # Phase-align the base time to the start of the next second. sec=$(echo "${now}" | gawk -F. '{ print $1; }') base_time="$(((${sec} + 1) * ${NSEC_PER_SEC}))" tc qdisc add dev swp5 parent root handle 100 taprio \ num_tc 8 \ map 0 1 2 3 5 6 7 \ queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \ base-time ${base_time} \ sched-entry S $(gatemask 7) 100000 \ sched-entry S $(gatemask "0 1 2 3 4 5 6") 400000 \ clockid CLOCK_TAI flags 2 The "state machine" is a workqueue invoked after each manipulation command on the PTP clock (reset, adjust time, set time, adjust frequency) which checks over the state of the time-aware scheduler. So it is not monitored periodically, only in reaction to a PTP command typically triggered from a userspace daemon (linuxptp). Otherwise there is no reason for things to go wrong. Now that the timecounter/cyclecounter has been replaced with hardware operations on the PTP clock, the TAS Kconfig now depends upon PTP and the standalone clocksource operating mode has been removed. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-11-12 02:11:54 +02:00
return sja1105_ptp_commit(priv->ds, &ptp_data->cmd, SPI_WRITE);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
}
/* Write to PTPCLKVAL while PTPCLKADD is 0 */
int __sja1105_ptp_settime(struct dsa_switch *ds, u64 ns,
struct ptp_system_timestamp *ptp_sts)
{
struct sja1105_private *priv = ds->priv;
u64 ticks = ns_to_sja1105_ticks(ns);
int rc;
rc = sja1105_ptp_mode_set(priv, PTP_SET_MODE);
if (rc < 0) {
dev_err(priv->ds->dev, "Failed to put PTPCLK in set mode\n");
return rc;
}
net: dsa: sja1105: Implement state machine for TAS with PTP clock source Tested using the following bash script and the tc from iproute2-next: #!/bin/bash set -e -u -o pipefail NSEC_PER_SEC="1000000000" gatemask() { local tc_list="$1" local mask=0 for tc in ${tc_list}; do mask=$((${mask} | (1 << ${tc}))) done printf "%02x" ${mask} } if ! systemctl is-active --quiet ptp4l; then echo "Please start the ptp4l service" exit fi now=$(phc_ctl /dev/ptp1 get | gawk '/clock time is/ { print $5; }') # Phase-align the base time to the start of the next second. sec=$(echo "${now}" | gawk -F. '{ print $1; }') base_time="$(((${sec} + 1) * ${NSEC_PER_SEC}))" tc qdisc add dev swp5 parent root handle 100 taprio \ num_tc 8 \ map 0 1 2 3 5 6 7 \ queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \ base-time ${base_time} \ sched-entry S $(gatemask 7) 100000 \ sched-entry S $(gatemask "0 1 2 3 4 5 6") 400000 \ clockid CLOCK_TAI flags 2 The "state machine" is a workqueue invoked after each manipulation command on the PTP clock (reset, adjust time, set time, adjust frequency) which checks over the state of the time-aware scheduler. So it is not monitored periodically, only in reaction to a PTP command typically triggered from a userspace daemon (linuxptp). Otherwise there is no reason for things to go wrong. Now that the timecounter/cyclecounter has been replaced with hardware operations on the PTP clock, the TAS Kconfig now depends upon PTP and the standalone clocksource operating mode has been removed. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-11-12 02:11:54 +02:00
rc = sja1105_ptpclkval_write(priv, ticks, ptp_sts);
sja1105_tas_clockstep(priv->ds);
return rc;
}
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
static int sja1105_ptp_settime(struct ptp_clock_info *ptp,
const struct timespec64 *ts)
{
struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp);
struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data);
u64 ns = timespec64_to_ns(ts);
int rc;
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
mutex_lock(&ptp_data->lock);
rc = __sja1105_ptp_settime(priv->ds, ns, NULL);
mutex_unlock(&ptp_data->lock);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
return rc;
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
}
static int sja1105_ptp_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
{
struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp);
struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data);
const struct sja1105_regs *regs = priv->info->regs;
u32 clkrate32;
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
s64 clkrate;
int rc;
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
clkrate = (s64)scaled_ppm * SJA1105_CC_MULT_NUM;
clkrate = div_s64(clkrate, SJA1105_CC_MULT_DEM);
/* Take a +/- value and re-center it around 2^31. */
clkrate = SJA1105_CC_MULT + clkrate;
WARN_ON(abs(clkrate) >= GENMASK_ULL(31, 0));
clkrate32 = clkrate;
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
mutex_lock(&ptp_data->lock);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
net: dsa: sja1105: Implement the .gettimex64 system call for PTP Through the PTP_SYS_OFFSET_EXTENDED ioctl, it is possible for userspace applications (i.e. phc2sys) to compensate for the delays incurred while reading the PHC's time. The task itself of taking the software timestamp is delegated to the SPI subsystem, through the newly introduced API in struct spi_transfer. The goal is to cross-timestamp I/O operations on the switch's PTP clock with values in the local system clock (CLOCK_REALTIME). For that we need to understand a bit of the hardware internals. The 'read PTP time' message is a 12 byte structure, first 4 bytes of which represent the SPI header, and the last 8 bytes represent the 64-bit PTP time. The switch itself starts processing the command immediately after receiving the last bit of the address, i.e. at the middle of byte 3 (last byte of header). The PTP time is shadowed to a buffer register in the switch, and retrieved atomically during the subsequent SPI frames. A similar thing goes on for the 'write PTP time' message, although in that case the switch waits until the 64-bit PTP time becomes fully available before taking any action. So the byte that needs to be software-timestamped is byte 11 (last) of the transfer. The patch creates a common (and local) sja1105_xfer implementation for the SPI I/O, and offers 3 front-ends: - sja1105_xfer_u32 and sja1105_xfer_u64: these are capable of optionally requesting a PTP timestamp - sja1105_xfer_buf: this is for large transfers (e.g. the static config buffer) and other misc data, and there is no point in giving timestamping capabilities to this. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-11-09 13:32:22 +02:00
rc = sja1105_xfer_u32(priv, SPI_WRITE, regs->ptpclkrate, &clkrate32,
NULL);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
net: dsa: sja1105: Implement state machine for TAS with PTP clock source Tested using the following bash script and the tc from iproute2-next: #!/bin/bash set -e -u -o pipefail NSEC_PER_SEC="1000000000" gatemask() { local tc_list="$1" local mask=0 for tc in ${tc_list}; do mask=$((${mask} | (1 << ${tc}))) done printf "%02x" ${mask} } if ! systemctl is-active --quiet ptp4l; then echo "Please start the ptp4l service" exit fi now=$(phc_ctl /dev/ptp1 get | gawk '/clock time is/ { print $5; }') # Phase-align the base time to the start of the next second. sec=$(echo "${now}" | gawk -F. '{ print $1; }') base_time="$(((${sec} + 1) * ${NSEC_PER_SEC}))" tc qdisc add dev swp5 parent root handle 100 taprio \ num_tc 8 \ map 0 1 2 3 5 6 7 \ queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \ base-time ${base_time} \ sched-entry S $(gatemask 7) 100000 \ sched-entry S $(gatemask "0 1 2 3 4 5 6") 400000 \ clockid CLOCK_TAI flags 2 The "state machine" is a workqueue invoked after each manipulation command on the PTP clock (reset, adjust time, set time, adjust frequency) which checks over the state of the time-aware scheduler. So it is not monitored periodically, only in reaction to a PTP command typically triggered from a userspace daemon (linuxptp). Otherwise there is no reason for things to go wrong. Now that the timecounter/cyclecounter has been replaced with hardware operations on the PTP clock, the TAS Kconfig now depends upon PTP and the standalone clocksource operating mode has been removed. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-11-12 02:11:54 +02:00
sja1105_tas_adjfreq(priv->ds);
mutex_unlock(&ptp_data->lock);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
return rc;
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
}
/* Write to PTPCLKVAL while PTPCLKADD is 1 */
int __sja1105_ptp_adjtime(struct dsa_switch *ds, s64 delta)
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
{
struct sja1105_private *priv = ds->priv;
s64 ticks = ns_to_sja1105_ticks(delta);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
int rc;
rc = sja1105_ptp_mode_set(priv, PTP_ADD_MODE);
if (rc < 0) {
dev_err(priv->ds->dev, "Failed to put PTPCLK in add mode\n");
return rc;
}
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
net: dsa: sja1105: Implement state machine for TAS with PTP clock source Tested using the following bash script and the tc from iproute2-next: #!/bin/bash set -e -u -o pipefail NSEC_PER_SEC="1000000000" gatemask() { local tc_list="$1" local mask=0 for tc in ${tc_list}; do mask=$((${mask} | (1 << ${tc}))) done printf "%02x" ${mask} } if ! systemctl is-active --quiet ptp4l; then echo "Please start the ptp4l service" exit fi now=$(phc_ctl /dev/ptp1 get | gawk '/clock time is/ { print $5; }') # Phase-align the base time to the start of the next second. sec=$(echo "${now}" | gawk -F. '{ print $1; }') base_time="$(((${sec} + 1) * ${NSEC_PER_SEC}))" tc qdisc add dev swp5 parent root handle 100 taprio \ num_tc 8 \ map 0 1 2 3 5 6 7 \ queues 1@0 1@1 1@2 1@3 1@4 1@5 1@6 1@7 \ base-time ${base_time} \ sched-entry S $(gatemask 7) 100000 \ sched-entry S $(gatemask "0 1 2 3 4 5 6") 400000 \ clockid CLOCK_TAI flags 2 The "state machine" is a workqueue invoked after each manipulation command on the PTP clock (reset, adjust time, set time, adjust frequency) which checks over the state of the time-aware scheduler. So it is not monitored periodically, only in reaction to a PTP command typically triggered from a userspace daemon (linuxptp). Otherwise there is no reason for things to go wrong. Now that the timecounter/cyclecounter has been replaced with hardware operations on the PTP clock, the TAS Kconfig now depends upon PTP and the standalone clocksource operating mode has been removed. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-11-12 02:11:54 +02:00
rc = sja1105_ptpclkval_write(priv, ticks, NULL);
sja1105_tas_clockstep(priv->ds);
return rc;
}
static int sja1105_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp);
struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data);
int rc;
mutex_lock(&ptp_data->lock);
rc = __sja1105_ptp_adjtime(priv->ds, delta);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
mutex_unlock(&ptp_data->lock);
return rc;
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
}
net: dsa: sja1105: poll for extts events from a timer The current poll interval is enough to ensure that rising and falling edge events are not lost for a 1 PPS signal with 50% duty cycle. But when we deliver the events to user space, it will try to infer if they were corresponding to a rising or to a falling edge (the kernel driver doesn't know that either). User space will try to make that inference based on the time at which the PPS master had emitted the pulse (i.e. if it's a .0 time, it's rising edge, if it's .5 time, it's falling edge). But there is no in-kernel API for retrieving the precise timestamp corresponding to a PPS master (aka perout) pulse. So user space has to guess even that. It will read the PTP time on the PPS master right after we've delivered the extts event, and declare that the PPS master time was just the closest integer second, based on 2 thresholds (lower than .25, or higher than .75, and ignore anything else). Except that, if we poll for extts events (and our hardware doesn't really help us, by not providing an interrupt), then there is a risk that the poll period (and therefore the time at which the event is delivered) might confuse user space. Because we are always scheduling the next extts poll at SJA1105_EXTTS_INTERVAL "from now" (that's the only thing that the schedule_delayed_work() API gives us), it means that the start time of the next delayed workqueue will always be shifted to the right a little bit (shifted with the SPI access duration of this workqueue run). In turn, because user space sees extts events that are non-periodic compared to the PPS master's time, this means that it might start making wrong guesses about rising/falling edge. To understand the effect, here is the output of ts2phc currently. Notice the 'src' timestamps of the 'SKIP extts' events, and how they have a large wander. They keep increasing until the upper limit for the ignore threshold (.75 seconds), after which the application starts ignoring the _other_ edge. ts2phc[26.624]: /dev/ptp3 SKIP extts index 0 at 21.449898912 src 21.657784518 ts2phc[27.133]: adding tstamp 21.949894240 to clock /dev/ptp3 ts2phc[27.133]: adding tstamp 22.000000000 to clock /dev/ptp1 ts2phc[27.133]: /dev/ptp3 offset 640 s2 freq +5112 ts2phc[27.636]: /dev/ptp3 SKIP extts index 0 at 22.449889360 src 22.669398022 ts2phc[28.140]: adding tstamp 22.949884376 to clock /dev/ptp3 ts2phc[28.140]: adding tstamp 23.000000000 to clock /dev/ptp1 ts2phc[28.140]: /dev/ptp3 offset 96 s2 freq +4760 ts2phc[28.644]: /dev/ptp3 SKIP extts index 0 at 23.449879504 src 23.677420422 ts2phc[29.153]: adding tstamp 23.949874704 to clock /dev/ptp3 ts2phc[29.153]: adding tstamp 24.000000000 to clock /dev/ptp1 ts2phc[29.153]: /dev/ptp3 offset -264 s2 freq +4429 ts2phc[29.656]: /dev/ptp3 SKIP extts index 0 at 24.449870008 src 24.689407238 ts2phc[30.160]: adding tstamp 24.949865376 to clock /dev/ptp3 ts2phc[30.160]: adding tstamp 25.000000000 to clock /dev/ptp1 ts2phc[30.160]: /dev/ptp3 offset -280 s2 freq +4334 ts2phc[30.664]: /dev/ptp3 SKIP extts index 0 at 25.449860760 src 25.697449926 ts2phc[31.168]: adding tstamp 25.949856176 to clock /dev/ptp3 ts2phc[31.168]: adding tstamp 26.000000000 to clock /dev/ptp1 ts2phc[31.168]: /dev/ptp3 offset -176 s2 freq +4354 ts2phc[31.672]: /dev/ptp3 SKIP extts index 0 at 26.449851584 src 26.705433606 ts2phc[32.180]: adding tstamp 26.949846992 to clock /dev/ptp3 ts2phc[32.180]: adding tstamp 27.000000000 to clock /dev/ptp1 ts2phc[32.180]: /dev/ptp3 offset -80 s2 freq +4397 ts2phc[32.684]: /dev/ptp3 SKIP extts index 0 at 27.449842384 src 27.717415110 ts2phc[33.192]: adding tstamp 27.949837768 to clock /dev/ptp3 ts2phc[33.192]: adding tstamp 28.000000000 to clock /dev/ptp1 ts2phc[33.192]: /dev/ptp3 offset 0 s2 freq +4453 ts2phc[33.696]: /dev/ptp3 SKIP extts index 0 at 28.449833128 src 28.729412902 ts2phc[34.200]: adding tstamp 28.949828472 to clock /dev/ptp3 ts2phc[34.200]: adding tstamp 29.000000000 to clock /dev/ptp1 ts2phc[34.200]: /dev/ptp3 offset 8 s2 freq +4461 ts2phc[34.704]: /dev/ptp3 SKIP extts index 0 at 29.449823816 src 29.737416038 ts2phc[35.208]: adding tstamp 29.949819152 to clock /dev/ptp3 ts2phc[35.208]: adding tstamp 30.000000000 to clock /dev/ptp1 ts2phc[35.208]: /dev/ptp3 offset -8 s2 freq +4447 ts2phc[35.712]: /dev/ptp3 SKIP extts index 0 at 30.449814496 src 30.745554982 ts2phc[36.216]: adding tstamp 30.949809840 to clock /dev/ptp3 ts2phc[36.216]: adding tstamp 31.000000000 to clock /dev/ptp1 ts2phc[36.216]: /dev/ptp3 offset -8 s2 freq +4445 ts2phc[36.468]: /dev/ptp3 SKIP extts index 0 at 31.449805184 src 31.501109446 ts2phc[36.972]: adding tstamp 31.949800536 to clock /dev/ptp3 ts2phc[36.972]: adding tstamp 32.000000000 to clock /dev/ptp1 ts2phc[36.972]: /dev/ptp3 offset -8 s2 freq +4442 ts2phc[37.480]: /dev/ptp3 SKIP extts index 0 at 32.449795896 src 32.513320070 ts2phc[37.984]: adding tstamp 32.949791248 to clock /dev/ptp3 ts2phc[37.984]: adding tstamp 33.000000000 to clock /dev/ptp1 ts2phc[37.984]: /dev/ptp3 offset 0 s2 freq +4448 Fix that by taking the following measures: - Schedule the poll from a timer. Because we are really scheduling the timer periodically, the extts events delivered to user space are periodic too, and don't suffer from the "shift-to-the-right" effect. - Increase the poll period to 6 times a second. This imposes a smaller upper bound to the shift that can occur to the delivery time of extts events, and makes user space (ts2phc) to always interpret correctly which events should be skipped and which shouldn't. - Move the SPI readout itself to the main PTP kernel thread, instead of the generic workqueue. This is because the timer runs in atomic context, but is also better than before, because if needed, we can chrt & taskset this kernel thread, to ensure it gets enough priority under load. After this patch, one can notice that the wander is greatly reduced, and that the latencies of one extts poll are not propagated to the next. The 'src' timestamp that is skipped is never larger than .65 seconds (which means .15 seconds larger than the time at which the real event occurred at, and .10 seconds smaller than the .75 upper threshold for ignoring the falling edge): ts2phc[40.076]: adding tstamp 34.949261296 to clock /dev/ptp3 ts2phc[40.076]: adding tstamp 35.000000000 to clock /dev/ptp1 ts2phc[40.076]: /dev/ptp3 offset 48 s2 freq +4631 ts2phc[40.568]: /dev/ptp3 SKIP extts index 0 at 35.449256496 src 35.595791078 ts2phc[41.064]: adding tstamp 35.949251744 to clock /dev/ptp3 ts2phc[41.064]: adding tstamp 36.000000000 to clock /dev/ptp1 ts2phc[41.064]: /dev/ptp3 offset -224 s2 freq +4374 ts2phc[41.552]: /dev/ptp3 SKIP extts index 0 at 36.449247088 src 36.579825574 ts2phc[42.044]: adding tstamp 36.949242456 to clock /dev/ptp3 ts2phc[42.044]: adding tstamp 37.000000000 to clock /dev/ptp1 ts2phc[42.044]: /dev/ptp3 offset -240 s2 freq +4290 ts2phc[42.536]: /dev/ptp3 SKIP extts index 0 at 37.449237848 src 37.563828774 ts2phc[43.028]: adding tstamp 37.949233264 to clock /dev/ptp3 ts2phc[43.028]: adding tstamp 38.000000000 to clock /dev/ptp1 ts2phc[43.028]: /dev/ptp3 offset -144 s2 freq +4314 ts2phc[43.520]: /dev/ptp3 SKIP extts index 0 at 38.449228656 src 38.547823238 ts2phc[44.012]: adding tstamp 38.949224048 to clock /dev/ptp3 ts2phc[44.012]: adding tstamp 39.000000000 to clock /dev/ptp1 ts2phc[44.012]: /dev/ptp3 offset -80 s2 freq +4335 ts2phc[44.508]: /dev/ptp3 SKIP extts index 0 at 39.449219432 src 39.535846118 ts2phc[44.996]: adding tstamp 39.949214816 to clock /dev/ptp3 ts2phc[44.996]: adding tstamp 40.000000000 to clock /dev/ptp1 ts2phc[44.996]: /dev/ptp3 offset -32 s2 freq +4359 ts2phc[45.488]: /dev/ptp3 SKIP extts index 0 at 40.449210192 src 40.515824678 ts2phc[45.980]: adding tstamp 40.949205568 to clock /dev/ptp3 ts2phc[45.980]: adding tstamp 41.000000000 to clock /dev/ptp1 ts2phc[45.980]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[46.636]: /dev/ptp3 SKIP extts index 0 at 41.449200928 src 41.664176902 ts2phc[47.132]: adding tstamp 41.949196288 to clock /dev/ptp3 ts2phc[47.132]: adding tstamp 42.000000000 to clock /dev/ptp1 ts2phc[47.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[47.620]: /dev/ptp3 SKIP extts index 0 at 42.449191656 src 42.648117190 ts2phc[48.112]: adding tstamp 42.949187016 to clock /dev/ptp3 ts2phc[48.112]: adding tstamp 43.000000000 to clock /dev/ptp1 ts2phc[48.112]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[48.604]: /dev/ptp3 SKIP extts index 0 at 43.449182384 src 43.632112582 ts2phc[49.100]: adding tstamp 43.949177736 to clock /dev/ptp3 ts2phc[49.100]: adding tstamp 44.000000000 to clock /dev/ptp1 ts2phc[49.100]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[49.588]: /dev/ptp3 SKIP extts index 0 at 44.449173096 src 44.616136774 ts2phc[50.080]: adding tstamp 44.949168464 to clock /dev/ptp3 ts2phc[50.080]: adding tstamp 45.000000000 to clock /dev/ptp1 ts2phc[50.080]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[50.572]: /dev/ptp3 SKIP extts index 0 at 45.449163816 src 45.600134662 ts2phc[51.064]: adding tstamp 45.949159160 to clock /dev/ptp3 ts2phc[51.064]: adding tstamp 46.000000000 to clock /dev/ptp1 ts2phc[51.064]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[51.556]: /dev/ptp3 SKIP extts index 0 at 46.449154528 src 46.584588550 ts2phc[52.048]: adding tstamp 46.949149896 to clock /dev/ptp3 ts2phc[52.048]: adding tstamp 47.000000000 to clock /dev/ptp1 ts2phc[52.048]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[52.540]: /dev/ptp3 SKIP extts index 0 at 47.449145256 src 47.568132198 ts2phc[53.032]: adding tstamp 47.949140616 to clock /dev/ptp3 ts2phc[53.032]: adding tstamp 48.000000000 to clock /dev/ptp1 ts2phc[53.032]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[53.524]: /dev/ptp3 SKIP extts index 0 at 48.449135968 src 48.552121446 ts2phc[54.016]: adding tstamp 48.949131320 to clock /dev/ptp3 ts2phc[54.016]: adding tstamp 49.000000000 to clock /dev/ptp1 ts2phc[54.016]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[54.512]: /dev/ptp3 SKIP extts index 0 at 49.449126680 src 49.540147014 ts2phc[55.000]: adding tstamp 49.949122040 to clock /dev/ptp3 ts2phc[55.000]: adding tstamp 50.000000000 to clock /dev/ptp1 ts2phc[55.000]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[55.492]: /dev/ptp3 SKIP extts index 0 at 50.449117400 src 50.520119078 ts2phc[55.988]: adding tstamp 50.949112768 to clock /dev/ptp3 ts2phc[55.988]: adding tstamp 51.000000000 to clock /dev/ptp1 ts2phc[55.988]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[56.476]: /dev/ptp3 SKIP extts index 0 at 51.449108120 src 51.504175910 ts2phc[57.132]: adding tstamp 51.949103480 to clock /dev/ptp3 ts2phc[57.132]: adding tstamp 52.000000000 to clock /dev/ptp1 ts2phc[57.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[57.624]: /dev/ptp3 SKIP extts index 0 at 52.449098840 src 52.651833574 ts2phc[58.116]: adding tstamp 52.949094200 to clock /dev/ptp3 ts2phc[58.116]: adding tstamp 53.000000000 to clock /dev/ptp1 ts2phc[58.116]: /dev/ptp3 offset 8 s2 freq +4392 ts2phc[58.612]: /dev/ptp3 SKIP extts index 0 at 53.449089560 src 53.639826918 ts2phc[59.100]: adding tstamp 53.949084920 to clock /dev/ptp3 ts2phc[59.100]: adding tstamp 54.000000000 to clock /dev/ptp1 ts2phc[59.100]: /dev/ptp3 offset 8 s2 freq +4394 ts2phc[59.592]: /dev/ptp3 SKIP extts index 0 at 54.449080272 src 54.619842278 ts2phc[60.084]: adding tstamp 54.949075624 to clock /dev/ptp3 ts2phc[60.084]: adding tstamp 55.000000000 to clock /dev/ptp1 ts2phc[60.084]: /dev/ptp3 offset 8 s2 freq +4397 ts2phc[60.576]: /dev/ptp3 SKIP extts index 0 at 55.449070968 src 55.603885542 ts2phc[61.068]: adding tstamp 55.949066312 to clock /dev/ptp3 ts2phc[61.068]: adding tstamp 56.000000000 to clock /dev/ptp1 ts2phc[61.068]: /dev/ptp3 offset 0 s2 freq +4391 ts2phc[61.560]: /dev/ptp3 SKIP extts index 0 at 56.449061680 src 56.587885798 ts2phc[62.052]: adding tstamp 56.949057032 to clock /dev/ptp3 ts2phc[62.052]: adding tstamp 57.000000000 to clock /dev/ptp1 ts2phc[62.052]: /dev/ptp3 offset -8 s2 freq +4383 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-03 20:51:58 +03:00
static void sja1105_ptp_extts_setup_timer(struct sja1105_ptp_data *ptp_data)
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
{
net: dsa: sja1105: poll for extts events from a timer The current poll interval is enough to ensure that rising and falling edge events are not lost for a 1 PPS signal with 50% duty cycle. But when we deliver the events to user space, it will try to infer if they were corresponding to a rising or to a falling edge (the kernel driver doesn't know that either). User space will try to make that inference based on the time at which the PPS master had emitted the pulse (i.e. if it's a .0 time, it's rising edge, if it's .5 time, it's falling edge). But there is no in-kernel API for retrieving the precise timestamp corresponding to a PPS master (aka perout) pulse. So user space has to guess even that. It will read the PTP time on the PPS master right after we've delivered the extts event, and declare that the PPS master time was just the closest integer second, based on 2 thresholds (lower than .25, or higher than .75, and ignore anything else). Except that, if we poll for extts events (and our hardware doesn't really help us, by not providing an interrupt), then there is a risk that the poll period (and therefore the time at which the event is delivered) might confuse user space. Because we are always scheduling the next extts poll at SJA1105_EXTTS_INTERVAL "from now" (that's the only thing that the schedule_delayed_work() API gives us), it means that the start time of the next delayed workqueue will always be shifted to the right a little bit (shifted with the SPI access duration of this workqueue run). In turn, because user space sees extts events that are non-periodic compared to the PPS master's time, this means that it might start making wrong guesses about rising/falling edge. To understand the effect, here is the output of ts2phc currently. Notice the 'src' timestamps of the 'SKIP extts' events, and how they have a large wander. They keep increasing until the upper limit for the ignore threshold (.75 seconds), after which the application starts ignoring the _other_ edge. ts2phc[26.624]: /dev/ptp3 SKIP extts index 0 at 21.449898912 src 21.657784518 ts2phc[27.133]: adding tstamp 21.949894240 to clock /dev/ptp3 ts2phc[27.133]: adding tstamp 22.000000000 to clock /dev/ptp1 ts2phc[27.133]: /dev/ptp3 offset 640 s2 freq +5112 ts2phc[27.636]: /dev/ptp3 SKIP extts index 0 at 22.449889360 src 22.669398022 ts2phc[28.140]: adding tstamp 22.949884376 to clock /dev/ptp3 ts2phc[28.140]: adding tstamp 23.000000000 to clock /dev/ptp1 ts2phc[28.140]: /dev/ptp3 offset 96 s2 freq +4760 ts2phc[28.644]: /dev/ptp3 SKIP extts index 0 at 23.449879504 src 23.677420422 ts2phc[29.153]: adding tstamp 23.949874704 to clock /dev/ptp3 ts2phc[29.153]: adding tstamp 24.000000000 to clock /dev/ptp1 ts2phc[29.153]: /dev/ptp3 offset -264 s2 freq +4429 ts2phc[29.656]: /dev/ptp3 SKIP extts index 0 at 24.449870008 src 24.689407238 ts2phc[30.160]: adding tstamp 24.949865376 to clock /dev/ptp3 ts2phc[30.160]: adding tstamp 25.000000000 to clock /dev/ptp1 ts2phc[30.160]: /dev/ptp3 offset -280 s2 freq +4334 ts2phc[30.664]: /dev/ptp3 SKIP extts index 0 at 25.449860760 src 25.697449926 ts2phc[31.168]: adding tstamp 25.949856176 to clock /dev/ptp3 ts2phc[31.168]: adding tstamp 26.000000000 to clock /dev/ptp1 ts2phc[31.168]: /dev/ptp3 offset -176 s2 freq +4354 ts2phc[31.672]: /dev/ptp3 SKIP extts index 0 at 26.449851584 src 26.705433606 ts2phc[32.180]: adding tstamp 26.949846992 to clock /dev/ptp3 ts2phc[32.180]: adding tstamp 27.000000000 to clock /dev/ptp1 ts2phc[32.180]: /dev/ptp3 offset -80 s2 freq +4397 ts2phc[32.684]: /dev/ptp3 SKIP extts index 0 at 27.449842384 src 27.717415110 ts2phc[33.192]: adding tstamp 27.949837768 to clock /dev/ptp3 ts2phc[33.192]: adding tstamp 28.000000000 to clock /dev/ptp1 ts2phc[33.192]: /dev/ptp3 offset 0 s2 freq +4453 ts2phc[33.696]: /dev/ptp3 SKIP extts index 0 at 28.449833128 src 28.729412902 ts2phc[34.200]: adding tstamp 28.949828472 to clock /dev/ptp3 ts2phc[34.200]: adding tstamp 29.000000000 to clock /dev/ptp1 ts2phc[34.200]: /dev/ptp3 offset 8 s2 freq +4461 ts2phc[34.704]: /dev/ptp3 SKIP extts index 0 at 29.449823816 src 29.737416038 ts2phc[35.208]: adding tstamp 29.949819152 to clock /dev/ptp3 ts2phc[35.208]: adding tstamp 30.000000000 to clock /dev/ptp1 ts2phc[35.208]: /dev/ptp3 offset -8 s2 freq +4447 ts2phc[35.712]: /dev/ptp3 SKIP extts index 0 at 30.449814496 src 30.745554982 ts2phc[36.216]: adding tstamp 30.949809840 to clock /dev/ptp3 ts2phc[36.216]: adding tstamp 31.000000000 to clock /dev/ptp1 ts2phc[36.216]: /dev/ptp3 offset -8 s2 freq +4445 ts2phc[36.468]: /dev/ptp3 SKIP extts index 0 at 31.449805184 src 31.501109446 ts2phc[36.972]: adding tstamp 31.949800536 to clock /dev/ptp3 ts2phc[36.972]: adding tstamp 32.000000000 to clock /dev/ptp1 ts2phc[36.972]: /dev/ptp3 offset -8 s2 freq +4442 ts2phc[37.480]: /dev/ptp3 SKIP extts index 0 at 32.449795896 src 32.513320070 ts2phc[37.984]: adding tstamp 32.949791248 to clock /dev/ptp3 ts2phc[37.984]: adding tstamp 33.000000000 to clock /dev/ptp1 ts2phc[37.984]: /dev/ptp3 offset 0 s2 freq +4448 Fix that by taking the following measures: - Schedule the poll from a timer. Because we are really scheduling the timer periodically, the extts events delivered to user space are periodic too, and don't suffer from the "shift-to-the-right" effect. - Increase the poll period to 6 times a second. This imposes a smaller upper bound to the shift that can occur to the delivery time of extts events, and makes user space (ts2phc) to always interpret correctly which events should be skipped and which shouldn't. - Move the SPI readout itself to the main PTP kernel thread, instead of the generic workqueue. This is because the timer runs in atomic context, but is also better than before, because if needed, we can chrt & taskset this kernel thread, to ensure it gets enough priority under load. After this patch, one can notice that the wander is greatly reduced, and that the latencies of one extts poll are not propagated to the next. The 'src' timestamp that is skipped is never larger than .65 seconds (which means .15 seconds larger than the time at which the real event occurred at, and .10 seconds smaller than the .75 upper threshold for ignoring the falling edge): ts2phc[40.076]: adding tstamp 34.949261296 to clock /dev/ptp3 ts2phc[40.076]: adding tstamp 35.000000000 to clock /dev/ptp1 ts2phc[40.076]: /dev/ptp3 offset 48 s2 freq +4631 ts2phc[40.568]: /dev/ptp3 SKIP extts index 0 at 35.449256496 src 35.595791078 ts2phc[41.064]: adding tstamp 35.949251744 to clock /dev/ptp3 ts2phc[41.064]: adding tstamp 36.000000000 to clock /dev/ptp1 ts2phc[41.064]: /dev/ptp3 offset -224 s2 freq +4374 ts2phc[41.552]: /dev/ptp3 SKIP extts index 0 at 36.449247088 src 36.579825574 ts2phc[42.044]: adding tstamp 36.949242456 to clock /dev/ptp3 ts2phc[42.044]: adding tstamp 37.000000000 to clock /dev/ptp1 ts2phc[42.044]: /dev/ptp3 offset -240 s2 freq +4290 ts2phc[42.536]: /dev/ptp3 SKIP extts index 0 at 37.449237848 src 37.563828774 ts2phc[43.028]: adding tstamp 37.949233264 to clock /dev/ptp3 ts2phc[43.028]: adding tstamp 38.000000000 to clock /dev/ptp1 ts2phc[43.028]: /dev/ptp3 offset -144 s2 freq +4314 ts2phc[43.520]: /dev/ptp3 SKIP extts index 0 at 38.449228656 src 38.547823238 ts2phc[44.012]: adding tstamp 38.949224048 to clock /dev/ptp3 ts2phc[44.012]: adding tstamp 39.000000000 to clock /dev/ptp1 ts2phc[44.012]: /dev/ptp3 offset -80 s2 freq +4335 ts2phc[44.508]: /dev/ptp3 SKIP extts index 0 at 39.449219432 src 39.535846118 ts2phc[44.996]: adding tstamp 39.949214816 to clock /dev/ptp3 ts2phc[44.996]: adding tstamp 40.000000000 to clock /dev/ptp1 ts2phc[44.996]: /dev/ptp3 offset -32 s2 freq +4359 ts2phc[45.488]: /dev/ptp3 SKIP extts index 0 at 40.449210192 src 40.515824678 ts2phc[45.980]: adding tstamp 40.949205568 to clock /dev/ptp3 ts2phc[45.980]: adding tstamp 41.000000000 to clock /dev/ptp1 ts2phc[45.980]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[46.636]: /dev/ptp3 SKIP extts index 0 at 41.449200928 src 41.664176902 ts2phc[47.132]: adding tstamp 41.949196288 to clock /dev/ptp3 ts2phc[47.132]: adding tstamp 42.000000000 to clock /dev/ptp1 ts2phc[47.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[47.620]: /dev/ptp3 SKIP extts index 0 at 42.449191656 src 42.648117190 ts2phc[48.112]: adding tstamp 42.949187016 to clock /dev/ptp3 ts2phc[48.112]: adding tstamp 43.000000000 to clock /dev/ptp1 ts2phc[48.112]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[48.604]: /dev/ptp3 SKIP extts index 0 at 43.449182384 src 43.632112582 ts2phc[49.100]: adding tstamp 43.949177736 to clock /dev/ptp3 ts2phc[49.100]: adding tstamp 44.000000000 to clock /dev/ptp1 ts2phc[49.100]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[49.588]: /dev/ptp3 SKIP extts index 0 at 44.449173096 src 44.616136774 ts2phc[50.080]: adding tstamp 44.949168464 to clock /dev/ptp3 ts2phc[50.080]: adding tstamp 45.000000000 to clock /dev/ptp1 ts2phc[50.080]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[50.572]: /dev/ptp3 SKIP extts index 0 at 45.449163816 src 45.600134662 ts2phc[51.064]: adding tstamp 45.949159160 to clock /dev/ptp3 ts2phc[51.064]: adding tstamp 46.000000000 to clock /dev/ptp1 ts2phc[51.064]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[51.556]: /dev/ptp3 SKIP extts index 0 at 46.449154528 src 46.584588550 ts2phc[52.048]: adding tstamp 46.949149896 to clock /dev/ptp3 ts2phc[52.048]: adding tstamp 47.000000000 to clock /dev/ptp1 ts2phc[52.048]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[52.540]: /dev/ptp3 SKIP extts index 0 at 47.449145256 src 47.568132198 ts2phc[53.032]: adding tstamp 47.949140616 to clock /dev/ptp3 ts2phc[53.032]: adding tstamp 48.000000000 to clock /dev/ptp1 ts2phc[53.032]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[53.524]: /dev/ptp3 SKIP extts index 0 at 48.449135968 src 48.552121446 ts2phc[54.016]: adding tstamp 48.949131320 to clock /dev/ptp3 ts2phc[54.016]: adding tstamp 49.000000000 to clock /dev/ptp1 ts2phc[54.016]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[54.512]: /dev/ptp3 SKIP extts index 0 at 49.449126680 src 49.540147014 ts2phc[55.000]: adding tstamp 49.949122040 to clock /dev/ptp3 ts2phc[55.000]: adding tstamp 50.000000000 to clock /dev/ptp1 ts2phc[55.000]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[55.492]: /dev/ptp3 SKIP extts index 0 at 50.449117400 src 50.520119078 ts2phc[55.988]: adding tstamp 50.949112768 to clock /dev/ptp3 ts2phc[55.988]: adding tstamp 51.000000000 to clock /dev/ptp1 ts2phc[55.988]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[56.476]: /dev/ptp3 SKIP extts index 0 at 51.449108120 src 51.504175910 ts2phc[57.132]: adding tstamp 51.949103480 to clock /dev/ptp3 ts2phc[57.132]: adding tstamp 52.000000000 to clock /dev/ptp1 ts2phc[57.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[57.624]: /dev/ptp3 SKIP extts index 0 at 52.449098840 src 52.651833574 ts2phc[58.116]: adding tstamp 52.949094200 to clock /dev/ptp3 ts2phc[58.116]: adding tstamp 53.000000000 to clock /dev/ptp1 ts2phc[58.116]: /dev/ptp3 offset 8 s2 freq +4392 ts2phc[58.612]: /dev/ptp3 SKIP extts index 0 at 53.449089560 src 53.639826918 ts2phc[59.100]: adding tstamp 53.949084920 to clock /dev/ptp3 ts2phc[59.100]: adding tstamp 54.000000000 to clock /dev/ptp1 ts2phc[59.100]: /dev/ptp3 offset 8 s2 freq +4394 ts2phc[59.592]: /dev/ptp3 SKIP extts index 0 at 54.449080272 src 54.619842278 ts2phc[60.084]: adding tstamp 54.949075624 to clock /dev/ptp3 ts2phc[60.084]: adding tstamp 55.000000000 to clock /dev/ptp1 ts2phc[60.084]: /dev/ptp3 offset 8 s2 freq +4397 ts2phc[60.576]: /dev/ptp3 SKIP extts index 0 at 55.449070968 src 55.603885542 ts2phc[61.068]: adding tstamp 55.949066312 to clock /dev/ptp3 ts2phc[61.068]: adding tstamp 56.000000000 to clock /dev/ptp1 ts2phc[61.068]: /dev/ptp3 offset 0 s2 freq +4391 ts2phc[61.560]: /dev/ptp3 SKIP extts index 0 at 56.449061680 src 56.587885798 ts2phc[62.052]: adding tstamp 56.949057032 to clock /dev/ptp3 ts2phc[62.052]: adding tstamp 57.000000000 to clock /dev/ptp1 ts2phc[62.052]: /dev/ptp3 offset -8 s2 freq +4383 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-03 20:51:58 +03:00
unsigned long expires = ((jiffies / SJA1105_EXTTS_INTERVAL) + 1) *
SJA1105_EXTTS_INTERVAL;
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
net: dsa: sja1105: poll for extts events from a timer The current poll interval is enough to ensure that rising and falling edge events are not lost for a 1 PPS signal with 50% duty cycle. But when we deliver the events to user space, it will try to infer if they were corresponding to a rising or to a falling edge (the kernel driver doesn't know that either). User space will try to make that inference based on the time at which the PPS master had emitted the pulse (i.e. if it's a .0 time, it's rising edge, if it's .5 time, it's falling edge). But there is no in-kernel API for retrieving the precise timestamp corresponding to a PPS master (aka perout) pulse. So user space has to guess even that. It will read the PTP time on the PPS master right after we've delivered the extts event, and declare that the PPS master time was just the closest integer second, based on 2 thresholds (lower than .25, or higher than .75, and ignore anything else). Except that, if we poll for extts events (and our hardware doesn't really help us, by not providing an interrupt), then there is a risk that the poll period (and therefore the time at which the event is delivered) might confuse user space. Because we are always scheduling the next extts poll at SJA1105_EXTTS_INTERVAL "from now" (that's the only thing that the schedule_delayed_work() API gives us), it means that the start time of the next delayed workqueue will always be shifted to the right a little bit (shifted with the SPI access duration of this workqueue run). In turn, because user space sees extts events that are non-periodic compared to the PPS master's time, this means that it might start making wrong guesses about rising/falling edge. To understand the effect, here is the output of ts2phc currently. Notice the 'src' timestamps of the 'SKIP extts' events, and how they have a large wander. They keep increasing until the upper limit for the ignore threshold (.75 seconds), after which the application starts ignoring the _other_ edge. ts2phc[26.624]: /dev/ptp3 SKIP extts index 0 at 21.449898912 src 21.657784518 ts2phc[27.133]: adding tstamp 21.949894240 to clock /dev/ptp3 ts2phc[27.133]: adding tstamp 22.000000000 to clock /dev/ptp1 ts2phc[27.133]: /dev/ptp3 offset 640 s2 freq +5112 ts2phc[27.636]: /dev/ptp3 SKIP extts index 0 at 22.449889360 src 22.669398022 ts2phc[28.140]: adding tstamp 22.949884376 to clock /dev/ptp3 ts2phc[28.140]: adding tstamp 23.000000000 to clock /dev/ptp1 ts2phc[28.140]: /dev/ptp3 offset 96 s2 freq +4760 ts2phc[28.644]: /dev/ptp3 SKIP extts index 0 at 23.449879504 src 23.677420422 ts2phc[29.153]: adding tstamp 23.949874704 to clock /dev/ptp3 ts2phc[29.153]: adding tstamp 24.000000000 to clock /dev/ptp1 ts2phc[29.153]: /dev/ptp3 offset -264 s2 freq +4429 ts2phc[29.656]: /dev/ptp3 SKIP extts index 0 at 24.449870008 src 24.689407238 ts2phc[30.160]: adding tstamp 24.949865376 to clock /dev/ptp3 ts2phc[30.160]: adding tstamp 25.000000000 to clock /dev/ptp1 ts2phc[30.160]: /dev/ptp3 offset -280 s2 freq +4334 ts2phc[30.664]: /dev/ptp3 SKIP extts index 0 at 25.449860760 src 25.697449926 ts2phc[31.168]: adding tstamp 25.949856176 to clock /dev/ptp3 ts2phc[31.168]: adding tstamp 26.000000000 to clock /dev/ptp1 ts2phc[31.168]: /dev/ptp3 offset -176 s2 freq +4354 ts2phc[31.672]: /dev/ptp3 SKIP extts index 0 at 26.449851584 src 26.705433606 ts2phc[32.180]: adding tstamp 26.949846992 to clock /dev/ptp3 ts2phc[32.180]: adding tstamp 27.000000000 to clock /dev/ptp1 ts2phc[32.180]: /dev/ptp3 offset -80 s2 freq +4397 ts2phc[32.684]: /dev/ptp3 SKIP extts index 0 at 27.449842384 src 27.717415110 ts2phc[33.192]: adding tstamp 27.949837768 to clock /dev/ptp3 ts2phc[33.192]: adding tstamp 28.000000000 to clock /dev/ptp1 ts2phc[33.192]: /dev/ptp3 offset 0 s2 freq +4453 ts2phc[33.696]: /dev/ptp3 SKIP extts index 0 at 28.449833128 src 28.729412902 ts2phc[34.200]: adding tstamp 28.949828472 to clock /dev/ptp3 ts2phc[34.200]: adding tstamp 29.000000000 to clock /dev/ptp1 ts2phc[34.200]: /dev/ptp3 offset 8 s2 freq +4461 ts2phc[34.704]: /dev/ptp3 SKIP extts index 0 at 29.449823816 src 29.737416038 ts2phc[35.208]: adding tstamp 29.949819152 to clock /dev/ptp3 ts2phc[35.208]: adding tstamp 30.000000000 to clock /dev/ptp1 ts2phc[35.208]: /dev/ptp3 offset -8 s2 freq +4447 ts2phc[35.712]: /dev/ptp3 SKIP extts index 0 at 30.449814496 src 30.745554982 ts2phc[36.216]: adding tstamp 30.949809840 to clock /dev/ptp3 ts2phc[36.216]: adding tstamp 31.000000000 to clock /dev/ptp1 ts2phc[36.216]: /dev/ptp3 offset -8 s2 freq +4445 ts2phc[36.468]: /dev/ptp3 SKIP extts index 0 at 31.449805184 src 31.501109446 ts2phc[36.972]: adding tstamp 31.949800536 to clock /dev/ptp3 ts2phc[36.972]: adding tstamp 32.000000000 to clock /dev/ptp1 ts2phc[36.972]: /dev/ptp3 offset -8 s2 freq +4442 ts2phc[37.480]: /dev/ptp3 SKIP extts index 0 at 32.449795896 src 32.513320070 ts2phc[37.984]: adding tstamp 32.949791248 to clock /dev/ptp3 ts2phc[37.984]: adding tstamp 33.000000000 to clock /dev/ptp1 ts2phc[37.984]: /dev/ptp3 offset 0 s2 freq +4448 Fix that by taking the following measures: - Schedule the poll from a timer. Because we are really scheduling the timer periodically, the extts events delivered to user space are periodic too, and don't suffer from the "shift-to-the-right" effect. - Increase the poll period to 6 times a second. This imposes a smaller upper bound to the shift that can occur to the delivery time of extts events, and makes user space (ts2phc) to always interpret correctly which events should be skipped and which shouldn't. - Move the SPI readout itself to the main PTP kernel thread, instead of the generic workqueue. This is because the timer runs in atomic context, but is also better than before, because if needed, we can chrt & taskset this kernel thread, to ensure it gets enough priority under load. After this patch, one can notice that the wander is greatly reduced, and that the latencies of one extts poll are not propagated to the next. The 'src' timestamp that is skipped is never larger than .65 seconds (which means .15 seconds larger than the time at which the real event occurred at, and .10 seconds smaller than the .75 upper threshold for ignoring the falling edge): ts2phc[40.076]: adding tstamp 34.949261296 to clock /dev/ptp3 ts2phc[40.076]: adding tstamp 35.000000000 to clock /dev/ptp1 ts2phc[40.076]: /dev/ptp3 offset 48 s2 freq +4631 ts2phc[40.568]: /dev/ptp3 SKIP extts index 0 at 35.449256496 src 35.595791078 ts2phc[41.064]: adding tstamp 35.949251744 to clock /dev/ptp3 ts2phc[41.064]: adding tstamp 36.000000000 to clock /dev/ptp1 ts2phc[41.064]: /dev/ptp3 offset -224 s2 freq +4374 ts2phc[41.552]: /dev/ptp3 SKIP extts index 0 at 36.449247088 src 36.579825574 ts2phc[42.044]: adding tstamp 36.949242456 to clock /dev/ptp3 ts2phc[42.044]: adding tstamp 37.000000000 to clock /dev/ptp1 ts2phc[42.044]: /dev/ptp3 offset -240 s2 freq +4290 ts2phc[42.536]: /dev/ptp3 SKIP extts index 0 at 37.449237848 src 37.563828774 ts2phc[43.028]: adding tstamp 37.949233264 to clock /dev/ptp3 ts2phc[43.028]: adding tstamp 38.000000000 to clock /dev/ptp1 ts2phc[43.028]: /dev/ptp3 offset -144 s2 freq +4314 ts2phc[43.520]: /dev/ptp3 SKIP extts index 0 at 38.449228656 src 38.547823238 ts2phc[44.012]: adding tstamp 38.949224048 to clock /dev/ptp3 ts2phc[44.012]: adding tstamp 39.000000000 to clock /dev/ptp1 ts2phc[44.012]: /dev/ptp3 offset -80 s2 freq +4335 ts2phc[44.508]: /dev/ptp3 SKIP extts index 0 at 39.449219432 src 39.535846118 ts2phc[44.996]: adding tstamp 39.949214816 to clock /dev/ptp3 ts2phc[44.996]: adding tstamp 40.000000000 to clock /dev/ptp1 ts2phc[44.996]: /dev/ptp3 offset -32 s2 freq +4359 ts2phc[45.488]: /dev/ptp3 SKIP extts index 0 at 40.449210192 src 40.515824678 ts2phc[45.980]: adding tstamp 40.949205568 to clock /dev/ptp3 ts2phc[45.980]: adding tstamp 41.000000000 to clock /dev/ptp1 ts2phc[45.980]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[46.636]: /dev/ptp3 SKIP extts index 0 at 41.449200928 src 41.664176902 ts2phc[47.132]: adding tstamp 41.949196288 to clock /dev/ptp3 ts2phc[47.132]: adding tstamp 42.000000000 to clock /dev/ptp1 ts2phc[47.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[47.620]: /dev/ptp3 SKIP extts index 0 at 42.449191656 src 42.648117190 ts2phc[48.112]: adding tstamp 42.949187016 to clock /dev/ptp3 ts2phc[48.112]: adding tstamp 43.000000000 to clock /dev/ptp1 ts2phc[48.112]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[48.604]: /dev/ptp3 SKIP extts index 0 at 43.449182384 src 43.632112582 ts2phc[49.100]: adding tstamp 43.949177736 to clock /dev/ptp3 ts2phc[49.100]: adding tstamp 44.000000000 to clock /dev/ptp1 ts2phc[49.100]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[49.588]: /dev/ptp3 SKIP extts index 0 at 44.449173096 src 44.616136774 ts2phc[50.080]: adding tstamp 44.949168464 to clock /dev/ptp3 ts2phc[50.080]: adding tstamp 45.000000000 to clock /dev/ptp1 ts2phc[50.080]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[50.572]: /dev/ptp3 SKIP extts index 0 at 45.449163816 src 45.600134662 ts2phc[51.064]: adding tstamp 45.949159160 to clock /dev/ptp3 ts2phc[51.064]: adding tstamp 46.000000000 to clock /dev/ptp1 ts2phc[51.064]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[51.556]: /dev/ptp3 SKIP extts index 0 at 46.449154528 src 46.584588550 ts2phc[52.048]: adding tstamp 46.949149896 to clock /dev/ptp3 ts2phc[52.048]: adding tstamp 47.000000000 to clock /dev/ptp1 ts2phc[52.048]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[52.540]: /dev/ptp3 SKIP extts index 0 at 47.449145256 src 47.568132198 ts2phc[53.032]: adding tstamp 47.949140616 to clock /dev/ptp3 ts2phc[53.032]: adding tstamp 48.000000000 to clock /dev/ptp1 ts2phc[53.032]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[53.524]: /dev/ptp3 SKIP extts index 0 at 48.449135968 src 48.552121446 ts2phc[54.016]: adding tstamp 48.949131320 to clock /dev/ptp3 ts2phc[54.016]: adding tstamp 49.000000000 to clock /dev/ptp1 ts2phc[54.016]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[54.512]: /dev/ptp3 SKIP extts index 0 at 49.449126680 src 49.540147014 ts2phc[55.000]: adding tstamp 49.949122040 to clock /dev/ptp3 ts2phc[55.000]: adding tstamp 50.000000000 to clock /dev/ptp1 ts2phc[55.000]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[55.492]: /dev/ptp3 SKIP extts index 0 at 50.449117400 src 50.520119078 ts2phc[55.988]: adding tstamp 50.949112768 to clock /dev/ptp3 ts2phc[55.988]: adding tstamp 51.000000000 to clock /dev/ptp1 ts2phc[55.988]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[56.476]: /dev/ptp3 SKIP extts index 0 at 51.449108120 src 51.504175910 ts2phc[57.132]: adding tstamp 51.949103480 to clock /dev/ptp3 ts2phc[57.132]: adding tstamp 52.000000000 to clock /dev/ptp1 ts2phc[57.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[57.624]: /dev/ptp3 SKIP extts index 0 at 52.449098840 src 52.651833574 ts2phc[58.116]: adding tstamp 52.949094200 to clock /dev/ptp3 ts2phc[58.116]: adding tstamp 53.000000000 to clock /dev/ptp1 ts2phc[58.116]: /dev/ptp3 offset 8 s2 freq +4392 ts2phc[58.612]: /dev/ptp3 SKIP extts index 0 at 53.449089560 src 53.639826918 ts2phc[59.100]: adding tstamp 53.949084920 to clock /dev/ptp3 ts2phc[59.100]: adding tstamp 54.000000000 to clock /dev/ptp1 ts2phc[59.100]: /dev/ptp3 offset 8 s2 freq +4394 ts2phc[59.592]: /dev/ptp3 SKIP extts index 0 at 54.449080272 src 54.619842278 ts2phc[60.084]: adding tstamp 54.949075624 to clock /dev/ptp3 ts2phc[60.084]: adding tstamp 55.000000000 to clock /dev/ptp1 ts2phc[60.084]: /dev/ptp3 offset 8 s2 freq +4397 ts2phc[60.576]: /dev/ptp3 SKIP extts index 0 at 55.449070968 src 55.603885542 ts2phc[61.068]: adding tstamp 55.949066312 to clock /dev/ptp3 ts2phc[61.068]: adding tstamp 56.000000000 to clock /dev/ptp1 ts2phc[61.068]: /dev/ptp3 offset 0 s2 freq +4391 ts2phc[61.560]: /dev/ptp3 SKIP extts index 0 at 56.449061680 src 56.587885798 ts2phc[62.052]: adding tstamp 56.949057032 to clock /dev/ptp3 ts2phc[62.052]: adding tstamp 57.000000000 to clock /dev/ptp1 ts2phc[62.052]: /dev/ptp3 offset -8 s2 freq +4383 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-03 20:51:58 +03:00
mod_timer(&ptp_data->extts_timer, expires);
}
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
net: dsa: sja1105: poll for extts events from a timer The current poll interval is enough to ensure that rising and falling edge events are not lost for a 1 PPS signal with 50% duty cycle. But when we deliver the events to user space, it will try to infer if they were corresponding to a rising or to a falling edge (the kernel driver doesn't know that either). User space will try to make that inference based on the time at which the PPS master had emitted the pulse (i.e. if it's a .0 time, it's rising edge, if it's .5 time, it's falling edge). But there is no in-kernel API for retrieving the precise timestamp corresponding to a PPS master (aka perout) pulse. So user space has to guess even that. It will read the PTP time on the PPS master right after we've delivered the extts event, and declare that the PPS master time was just the closest integer second, based on 2 thresholds (lower than .25, or higher than .75, and ignore anything else). Except that, if we poll for extts events (and our hardware doesn't really help us, by not providing an interrupt), then there is a risk that the poll period (and therefore the time at which the event is delivered) might confuse user space. Because we are always scheduling the next extts poll at SJA1105_EXTTS_INTERVAL "from now" (that's the only thing that the schedule_delayed_work() API gives us), it means that the start time of the next delayed workqueue will always be shifted to the right a little bit (shifted with the SPI access duration of this workqueue run). In turn, because user space sees extts events that are non-periodic compared to the PPS master's time, this means that it might start making wrong guesses about rising/falling edge. To understand the effect, here is the output of ts2phc currently. Notice the 'src' timestamps of the 'SKIP extts' events, and how they have a large wander. They keep increasing until the upper limit for the ignore threshold (.75 seconds), after which the application starts ignoring the _other_ edge. ts2phc[26.624]: /dev/ptp3 SKIP extts index 0 at 21.449898912 src 21.657784518 ts2phc[27.133]: adding tstamp 21.949894240 to clock /dev/ptp3 ts2phc[27.133]: adding tstamp 22.000000000 to clock /dev/ptp1 ts2phc[27.133]: /dev/ptp3 offset 640 s2 freq +5112 ts2phc[27.636]: /dev/ptp3 SKIP extts index 0 at 22.449889360 src 22.669398022 ts2phc[28.140]: adding tstamp 22.949884376 to clock /dev/ptp3 ts2phc[28.140]: adding tstamp 23.000000000 to clock /dev/ptp1 ts2phc[28.140]: /dev/ptp3 offset 96 s2 freq +4760 ts2phc[28.644]: /dev/ptp3 SKIP extts index 0 at 23.449879504 src 23.677420422 ts2phc[29.153]: adding tstamp 23.949874704 to clock /dev/ptp3 ts2phc[29.153]: adding tstamp 24.000000000 to clock /dev/ptp1 ts2phc[29.153]: /dev/ptp3 offset -264 s2 freq +4429 ts2phc[29.656]: /dev/ptp3 SKIP extts index 0 at 24.449870008 src 24.689407238 ts2phc[30.160]: adding tstamp 24.949865376 to clock /dev/ptp3 ts2phc[30.160]: adding tstamp 25.000000000 to clock /dev/ptp1 ts2phc[30.160]: /dev/ptp3 offset -280 s2 freq +4334 ts2phc[30.664]: /dev/ptp3 SKIP extts index 0 at 25.449860760 src 25.697449926 ts2phc[31.168]: adding tstamp 25.949856176 to clock /dev/ptp3 ts2phc[31.168]: adding tstamp 26.000000000 to clock /dev/ptp1 ts2phc[31.168]: /dev/ptp3 offset -176 s2 freq +4354 ts2phc[31.672]: /dev/ptp3 SKIP extts index 0 at 26.449851584 src 26.705433606 ts2phc[32.180]: adding tstamp 26.949846992 to clock /dev/ptp3 ts2phc[32.180]: adding tstamp 27.000000000 to clock /dev/ptp1 ts2phc[32.180]: /dev/ptp3 offset -80 s2 freq +4397 ts2phc[32.684]: /dev/ptp3 SKIP extts index 0 at 27.449842384 src 27.717415110 ts2phc[33.192]: adding tstamp 27.949837768 to clock /dev/ptp3 ts2phc[33.192]: adding tstamp 28.000000000 to clock /dev/ptp1 ts2phc[33.192]: /dev/ptp3 offset 0 s2 freq +4453 ts2phc[33.696]: /dev/ptp3 SKIP extts index 0 at 28.449833128 src 28.729412902 ts2phc[34.200]: adding tstamp 28.949828472 to clock /dev/ptp3 ts2phc[34.200]: adding tstamp 29.000000000 to clock /dev/ptp1 ts2phc[34.200]: /dev/ptp3 offset 8 s2 freq +4461 ts2phc[34.704]: /dev/ptp3 SKIP extts index 0 at 29.449823816 src 29.737416038 ts2phc[35.208]: adding tstamp 29.949819152 to clock /dev/ptp3 ts2phc[35.208]: adding tstamp 30.000000000 to clock /dev/ptp1 ts2phc[35.208]: /dev/ptp3 offset -8 s2 freq +4447 ts2phc[35.712]: /dev/ptp3 SKIP extts index 0 at 30.449814496 src 30.745554982 ts2phc[36.216]: adding tstamp 30.949809840 to clock /dev/ptp3 ts2phc[36.216]: adding tstamp 31.000000000 to clock /dev/ptp1 ts2phc[36.216]: /dev/ptp3 offset -8 s2 freq +4445 ts2phc[36.468]: /dev/ptp3 SKIP extts index 0 at 31.449805184 src 31.501109446 ts2phc[36.972]: adding tstamp 31.949800536 to clock /dev/ptp3 ts2phc[36.972]: adding tstamp 32.000000000 to clock /dev/ptp1 ts2phc[36.972]: /dev/ptp3 offset -8 s2 freq +4442 ts2phc[37.480]: /dev/ptp3 SKIP extts index 0 at 32.449795896 src 32.513320070 ts2phc[37.984]: adding tstamp 32.949791248 to clock /dev/ptp3 ts2phc[37.984]: adding tstamp 33.000000000 to clock /dev/ptp1 ts2phc[37.984]: /dev/ptp3 offset 0 s2 freq +4448 Fix that by taking the following measures: - Schedule the poll from a timer. Because we are really scheduling the timer periodically, the extts events delivered to user space are periodic too, and don't suffer from the "shift-to-the-right" effect. - Increase the poll period to 6 times a second. This imposes a smaller upper bound to the shift that can occur to the delivery time of extts events, and makes user space (ts2phc) to always interpret correctly which events should be skipped and which shouldn't. - Move the SPI readout itself to the main PTP kernel thread, instead of the generic workqueue. This is because the timer runs in atomic context, but is also better than before, because if needed, we can chrt & taskset this kernel thread, to ensure it gets enough priority under load. After this patch, one can notice that the wander is greatly reduced, and that the latencies of one extts poll are not propagated to the next. The 'src' timestamp that is skipped is never larger than .65 seconds (which means .15 seconds larger than the time at which the real event occurred at, and .10 seconds smaller than the .75 upper threshold for ignoring the falling edge): ts2phc[40.076]: adding tstamp 34.949261296 to clock /dev/ptp3 ts2phc[40.076]: adding tstamp 35.000000000 to clock /dev/ptp1 ts2phc[40.076]: /dev/ptp3 offset 48 s2 freq +4631 ts2phc[40.568]: /dev/ptp3 SKIP extts index 0 at 35.449256496 src 35.595791078 ts2phc[41.064]: adding tstamp 35.949251744 to clock /dev/ptp3 ts2phc[41.064]: adding tstamp 36.000000000 to clock /dev/ptp1 ts2phc[41.064]: /dev/ptp3 offset -224 s2 freq +4374 ts2phc[41.552]: /dev/ptp3 SKIP extts index 0 at 36.449247088 src 36.579825574 ts2phc[42.044]: adding tstamp 36.949242456 to clock /dev/ptp3 ts2phc[42.044]: adding tstamp 37.000000000 to clock /dev/ptp1 ts2phc[42.044]: /dev/ptp3 offset -240 s2 freq +4290 ts2phc[42.536]: /dev/ptp3 SKIP extts index 0 at 37.449237848 src 37.563828774 ts2phc[43.028]: adding tstamp 37.949233264 to clock /dev/ptp3 ts2phc[43.028]: adding tstamp 38.000000000 to clock /dev/ptp1 ts2phc[43.028]: /dev/ptp3 offset -144 s2 freq +4314 ts2phc[43.520]: /dev/ptp3 SKIP extts index 0 at 38.449228656 src 38.547823238 ts2phc[44.012]: adding tstamp 38.949224048 to clock /dev/ptp3 ts2phc[44.012]: adding tstamp 39.000000000 to clock /dev/ptp1 ts2phc[44.012]: /dev/ptp3 offset -80 s2 freq +4335 ts2phc[44.508]: /dev/ptp3 SKIP extts index 0 at 39.449219432 src 39.535846118 ts2phc[44.996]: adding tstamp 39.949214816 to clock /dev/ptp3 ts2phc[44.996]: adding tstamp 40.000000000 to clock /dev/ptp1 ts2phc[44.996]: /dev/ptp3 offset -32 s2 freq +4359 ts2phc[45.488]: /dev/ptp3 SKIP extts index 0 at 40.449210192 src 40.515824678 ts2phc[45.980]: adding tstamp 40.949205568 to clock /dev/ptp3 ts2phc[45.980]: adding tstamp 41.000000000 to clock /dev/ptp1 ts2phc[45.980]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[46.636]: /dev/ptp3 SKIP extts index 0 at 41.449200928 src 41.664176902 ts2phc[47.132]: adding tstamp 41.949196288 to clock /dev/ptp3 ts2phc[47.132]: adding tstamp 42.000000000 to clock /dev/ptp1 ts2phc[47.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[47.620]: /dev/ptp3 SKIP extts index 0 at 42.449191656 src 42.648117190 ts2phc[48.112]: adding tstamp 42.949187016 to clock /dev/ptp3 ts2phc[48.112]: adding tstamp 43.000000000 to clock /dev/ptp1 ts2phc[48.112]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[48.604]: /dev/ptp3 SKIP extts index 0 at 43.449182384 src 43.632112582 ts2phc[49.100]: adding tstamp 43.949177736 to clock /dev/ptp3 ts2phc[49.100]: adding tstamp 44.000000000 to clock /dev/ptp1 ts2phc[49.100]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[49.588]: /dev/ptp3 SKIP extts index 0 at 44.449173096 src 44.616136774 ts2phc[50.080]: adding tstamp 44.949168464 to clock /dev/ptp3 ts2phc[50.080]: adding tstamp 45.000000000 to clock /dev/ptp1 ts2phc[50.080]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[50.572]: /dev/ptp3 SKIP extts index 0 at 45.449163816 src 45.600134662 ts2phc[51.064]: adding tstamp 45.949159160 to clock /dev/ptp3 ts2phc[51.064]: adding tstamp 46.000000000 to clock /dev/ptp1 ts2phc[51.064]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[51.556]: /dev/ptp3 SKIP extts index 0 at 46.449154528 src 46.584588550 ts2phc[52.048]: adding tstamp 46.949149896 to clock /dev/ptp3 ts2phc[52.048]: adding tstamp 47.000000000 to clock /dev/ptp1 ts2phc[52.048]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[52.540]: /dev/ptp3 SKIP extts index 0 at 47.449145256 src 47.568132198 ts2phc[53.032]: adding tstamp 47.949140616 to clock /dev/ptp3 ts2phc[53.032]: adding tstamp 48.000000000 to clock /dev/ptp1 ts2phc[53.032]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[53.524]: /dev/ptp3 SKIP extts index 0 at 48.449135968 src 48.552121446 ts2phc[54.016]: adding tstamp 48.949131320 to clock /dev/ptp3 ts2phc[54.016]: adding tstamp 49.000000000 to clock /dev/ptp1 ts2phc[54.016]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[54.512]: /dev/ptp3 SKIP extts index 0 at 49.449126680 src 49.540147014 ts2phc[55.000]: adding tstamp 49.949122040 to clock /dev/ptp3 ts2phc[55.000]: adding tstamp 50.000000000 to clock /dev/ptp1 ts2phc[55.000]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[55.492]: /dev/ptp3 SKIP extts index 0 at 50.449117400 src 50.520119078 ts2phc[55.988]: adding tstamp 50.949112768 to clock /dev/ptp3 ts2phc[55.988]: adding tstamp 51.000000000 to clock /dev/ptp1 ts2phc[55.988]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[56.476]: /dev/ptp3 SKIP extts index 0 at 51.449108120 src 51.504175910 ts2phc[57.132]: adding tstamp 51.949103480 to clock /dev/ptp3 ts2phc[57.132]: adding tstamp 52.000000000 to clock /dev/ptp1 ts2phc[57.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[57.624]: /dev/ptp3 SKIP extts index 0 at 52.449098840 src 52.651833574 ts2phc[58.116]: adding tstamp 52.949094200 to clock /dev/ptp3 ts2phc[58.116]: adding tstamp 53.000000000 to clock /dev/ptp1 ts2phc[58.116]: /dev/ptp3 offset 8 s2 freq +4392 ts2phc[58.612]: /dev/ptp3 SKIP extts index 0 at 53.449089560 src 53.639826918 ts2phc[59.100]: adding tstamp 53.949084920 to clock /dev/ptp3 ts2phc[59.100]: adding tstamp 54.000000000 to clock /dev/ptp1 ts2phc[59.100]: /dev/ptp3 offset 8 s2 freq +4394 ts2phc[59.592]: /dev/ptp3 SKIP extts index 0 at 54.449080272 src 54.619842278 ts2phc[60.084]: adding tstamp 54.949075624 to clock /dev/ptp3 ts2phc[60.084]: adding tstamp 55.000000000 to clock /dev/ptp1 ts2phc[60.084]: /dev/ptp3 offset 8 s2 freq +4397 ts2phc[60.576]: /dev/ptp3 SKIP extts index 0 at 55.449070968 src 55.603885542 ts2phc[61.068]: adding tstamp 55.949066312 to clock /dev/ptp3 ts2phc[61.068]: adding tstamp 56.000000000 to clock /dev/ptp1 ts2phc[61.068]: /dev/ptp3 offset 0 s2 freq +4391 ts2phc[61.560]: /dev/ptp3 SKIP extts index 0 at 56.449061680 src 56.587885798 ts2phc[62.052]: adding tstamp 56.949057032 to clock /dev/ptp3 ts2phc[62.052]: adding tstamp 57.000000000 to clock /dev/ptp1 ts2phc[62.052]: /dev/ptp3 offset -8 s2 freq +4383 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-03 20:51:58 +03:00
static void sja1105_ptp_extts_timer(struct timer_list *t)
{
struct sja1105_ptp_data *ptp_data = extts_to_data(t);
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
net: dsa: sja1105: poll for extts events from a timer The current poll interval is enough to ensure that rising and falling edge events are not lost for a 1 PPS signal with 50% duty cycle. But when we deliver the events to user space, it will try to infer if they were corresponding to a rising or to a falling edge (the kernel driver doesn't know that either). User space will try to make that inference based on the time at which the PPS master had emitted the pulse (i.e. if it's a .0 time, it's rising edge, if it's .5 time, it's falling edge). But there is no in-kernel API for retrieving the precise timestamp corresponding to a PPS master (aka perout) pulse. So user space has to guess even that. It will read the PTP time on the PPS master right after we've delivered the extts event, and declare that the PPS master time was just the closest integer second, based on 2 thresholds (lower than .25, or higher than .75, and ignore anything else). Except that, if we poll for extts events (and our hardware doesn't really help us, by not providing an interrupt), then there is a risk that the poll period (and therefore the time at which the event is delivered) might confuse user space. Because we are always scheduling the next extts poll at SJA1105_EXTTS_INTERVAL "from now" (that's the only thing that the schedule_delayed_work() API gives us), it means that the start time of the next delayed workqueue will always be shifted to the right a little bit (shifted with the SPI access duration of this workqueue run). In turn, because user space sees extts events that are non-periodic compared to the PPS master's time, this means that it might start making wrong guesses about rising/falling edge. To understand the effect, here is the output of ts2phc currently. Notice the 'src' timestamps of the 'SKIP extts' events, and how they have a large wander. They keep increasing until the upper limit for the ignore threshold (.75 seconds), after which the application starts ignoring the _other_ edge. ts2phc[26.624]: /dev/ptp3 SKIP extts index 0 at 21.449898912 src 21.657784518 ts2phc[27.133]: adding tstamp 21.949894240 to clock /dev/ptp3 ts2phc[27.133]: adding tstamp 22.000000000 to clock /dev/ptp1 ts2phc[27.133]: /dev/ptp3 offset 640 s2 freq +5112 ts2phc[27.636]: /dev/ptp3 SKIP extts index 0 at 22.449889360 src 22.669398022 ts2phc[28.140]: adding tstamp 22.949884376 to clock /dev/ptp3 ts2phc[28.140]: adding tstamp 23.000000000 to clock /dev/ptp1 ts2phc[28.140]: /dev/ptp3 offset 96 s2 freq +4760 ts2phc[28.644]: /dev/ptp3 SKIP extts index 0 at 23.449879504 src 23.677420422 ts2phc[29.153]: adding tstamp 23.949874704 to clock /dev/ptp3 ts2phc[29.153]: adding tstamp 24.000000000 to clock /dev/ptp1 ts2phc[29.153]: /dev/ptp3 offset -264 s2 freq +4429 ts2phc[29.656]: /dev/ptp3 SKIP extts index 0 at 24.449870008 src 24.689407238 ts2phc[30.160]: adding tstamp 24.949865376 to clock /dev/ptp3 ts2phc[30.160]: adding tstamp 25.000000000 to clock /dev/ptp1 ts2phc[30.160]: /dev/ptp3 offset -280 s2 freq +4334 ts2phc[30.664]: /dev/ptp3 SKIP extts index 0 at 25.449860760 src 25.697449926 ts2phc[31.168]: adding tstamp 25.949856176 to clock /dev/ptp3 ts2phc[31.168]: adding tstamp 26.000000000 to clock /dev/ptp1 ts2phc[31.168]: /dev/ptp3 offset -176 s2 freq +4354 ts2phc[31.672]: /dev/ptp3 SKIP extts index 0 at 26.449851584 src 26.705433606 ts2phc[32.180]: adding tstamp 26.949846992 to clock /dev/ptp3 ts2phc[32.180]: adding tstamp 27.000000000 to clock /dev/ptp1 ts2phc[32.180]: /dev/ptp3 offset -80 s2 freq +4397 ts2phc[32.684]: /dev/ptp3 SKIP extts index 0 at 27.449842384 src 27.717415110 ts2phc[33.192]: adding tstamp 27.949837768 to clock /dev/ptp3 ts2phc[33.192]: adding tstamp 28.000000000 to clock /dev/ptp1 ts2phc[33.192]: /dev/ptp3 offset 0 s2 freq +4453 ts2phc[33.696]: /dev/ptp3 SKIP extts index 0 at 28.449833128 src 28.729412902 ts2phc[34.200]: adding tstamp 28.949828472 to clock /dev/ptp3 ts2phc[34.200]: adding tstamp 29.000000000 to clock /dev/ptp1 ts2phc[34.200]: /dev/ptp3 offset 8 s2 freq +4461 ts2phc[34.704]: /dev/ptp3 SKIP extts index 0 at 29.449823816 src 29.737416038 ts2phc[35.208]: adding tstamp 29.949819152 to clock /dev/ptp3 ts2phc[35.208]: adding tstamp 30.000000000 to clock /dev/ptp1 ts2phc[35.208]: /dev/ptp3 offset -8 s2 freq +4447 ts2phc[35.712]: /dev/ptp3 SKIP extts index 0 at 30.449814496 src 30.745554982 ts2phc[36.216]: adding tstamp 30.949809840 to clock /dev/ptp3 ts2phc[36.216]: adding tstamp 31.000000000 to clock /dev/ptp1 ts2phc[36.216]: /dev/ptp3 offset -8 s2 freq +4445 ts2phc[36.468]: /dev/ptp3 SKIP extts index 0 at 31.449805184 src 31.501109446 ts2phc[36.972]: adding tstamp 31.949800536 to clock /dev/ptp3 ts2phc[36.972]: adding tstamp 32.000000000 to clock /dev/ptp1 ts2phc[36.972]: /dev/ptp3 offset -8 s2 freq +4442 ts2phc[37.480]: /dev/ptp3 SKIP extts index 0 at 32.449795896 src 32.513320070 ts2phc[37.984]: adding tstamp 32.949791248 to clock /dev/ptp3 ts2phc[37.984]: adding tstamp 33.000000000 to clock /dev/ptp1 ts2phc[37.984]: /dev/ptp3 offset 0 s2 freq +4448 Fix that by taking the following measures: - Schedule the poll from a timer. Because we are really scheduling the timer periodically, the extts events delivered to user space are periodic too, and don't suffer from the "shift-to-the-right" effect. - Increase the poll period to 6 times a second. This imposes a smaller upper bound to the shift that can occur to the delivery time of extts events, and makes user space (ts2phc) to always interpret correctly which events should be skipped and which shouldn't. - Move the SPI readout itself to the main PTP kernel thread, instead of the generic workqueue. This is because the timer runs in atomic context, but is also better than before, because if needed, we can chrt & taskset this kernel thread, to ensure it gets enough priority under load. After this patch, one can notice that the wander is greatly reduced, and that the latencies of one extts poll are not propagated to the next. The 'src' timestamp that is skipped is never larger than .65 seconds (which means .15 seconds larger than the time at which the real event occurred at, and .10 seconds smaller than the .75 upper threshold for ignoring the falling edge): ts2phc[40.076]: adding tstamp 34.949261296 to clock /dev/ptp3 ts2phc[40.076]: adding tstamp 35.000000000 to clock /dev/ptp1 ts2phc[40.076]: /dev/ptp3 offset 48 s2 freq +4631 ts2phc[40.568]: /dev/ptp3 SKIP extts index 0 at 35.449256496 src 35.595791078 ts2phc[41.064]: adding tstamp 35.949251744 to clock /dev/ptp3 ts2phc[41.064]: adding tstamp 36.000000000 to clock /dev/ptp1 ts2phc[41.064]: /dev/ptp3 offset -224 s2 freq +4374 ts2phc[41.552]: /dev/ptp3 SKIP extts index 0 at 36.449247088 src 36.579825574 ts2phc[42.044]: adding tstamp 36.949242456 to clock /dev/ptp3 ts2phc[42.044]: adding tstamp 37.000000000 to clock /dev/ptp1 ts2phc[42.044]: /dev/ptp3 offset -240 s2 freq +4290 ts2phc[42.536]: /dev/ptp3 SKIP extts index 0 at 37.449237848 src 37.563828774 ts2phc[43.028]: adding tstamp 37.949233264 to clock /dev/ptp3 ts2phc[43.028]: adding tstamp 38.000000000 to clock /dev/ptp1 ts2phc[43.028]: /dev/ptp3 offset -144 s2 freq +4314 ts2phc[43.520]: /dev/ptp3 SKIP extts index 0 at 38.449228656 src 38.547823238 ts2phc[44.012]: adding tstamp 38.949224048 to clock /dev/ptp3 ts2phc[44.012]: adding tstamp 39.000000000 to clock /dev/ptp1 ts2phc[44.012]: /dev/ptp3 offset -80 s2 freq +4335 ts2phc[44.508]: /dev/ptp3 SKIP extts index 0 at 39.449219432 src 39.535846118 ts2phc[44.996]: adding tstamp 39.949214816 to clock /dev/ptp3 ts2phc[44.996]: adding tstamp 40.000000000 to clock /dev/ptp1 ts2phc[44.996]: /dev/ptp3 offset -32 s2 freq +4359 ts2phc[45.488]: /dev/ptp3 SKIP extts index 0 at 40.449210192 src 40.515824678 ts2phc[45.980]: adding tstamp 40.949205568 to clock /dev/ptp3 ts2phc[45.980]: adding tstamp 41.000000000 to clock /dev/ptp1 ts2phc[45.980]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[46.636]: /dev/ptp3 SKIP extts index 0 at 41.449200928 src 41.664176902 ts2phc[47.132]: adding tstamp 41.949196288 to clock /dev/ptp3 ts2phc[47.132]: adding tstamp 42.000000000 to clock /dev/ptp1 ts2phc[47.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[47.620]: /dev/ptp3 SKIP extts index 0 at 42.449191656 src 42.648117190 ts2phc[48.112]: adding tstamp 42.949187016 to clock /dev/ptp3 ts2phc[48.112]: adding tstamp 43.000000000 to clock /dev/ptp1 ts2phc[48.112]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[48.604]: /dev/ptp3 SKIP extts index 0 at 43.449182384 src 43.632112582 ts2phc[49.100]: adding tstamp 43.949177736 to clock /dev/ptp3 ts2phc[49.100]: adding tstamp 44.000000000 to clock /dev/ptp1 ts2phc[49.100]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[49.588]: /dev/ptp3 SKIP extts index 0 at 44.449173096 src 44.616136774 ts2phc[50.080]: adding tstamp 44.949168464 to clock /dev/ptp3 ts2phc[50.080]: adding tstamp 45.000000000 to clock /dev/ptp1 ts2phc[50.080]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[50.572]: /dev/ptp3 SKIP extts index 0 at 45.449163816 src 45.600134662 ts2phc[51.064]: adding tstamp 45.949159160 to clock /dev/ptp3 ts2phc[51.064]: adding tstamp 46.000000000 to clock /dev/ptp1 ts2phc[51.064]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[51.556]: /dev/ptp3 SKIP extts index 0 at 46.449154528 src 46.584588550 ts2phc[52.048]: adding tstamp 46.949149896 to clock /dev/ptp3 ts2phc[52.048]: adding tstamp 47.000000000 to clock /dev/ptp1 ts2phc[52.048]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[52.540]: /dev/ptp3 SKIP extts index 0 at 47.449145256 src 47.568132198 ts2phc[53.032]: adding tstamp 47.949140616 to clock /dev/ptp3 ts2phc[53.032]: adding tstamp 48.000000000 to clock /dev/ptp1 ts2phc[53.032]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[53.524]: /dev/ptp3 SKIP extts index 0 at 48.449135968 src 48.552121446 ts2phc[54.016]: adding tstamp 48.949131320 to clock /dev/ptp3 ts2phc[54.016]: adding tstamp 49.000000000 to clock /dev/ptp1 ts2phc[54.016]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[54.512]: /dev/ptp3 SKIP extts index 0 at 49.449126680 src 49.540147014 ts2phc[55.000]: adding tstamp 49.949122040 to clock /dev/ptp3 ts2phc[55.000]: adding tstamp 50.000000000 to clock /dev/ptp1 ts2phc[55.000]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[55.492]: /dev/ptp3 SKIP extts index 0 at 50.449117400 src 50.520119078 ts2phc[55.988]: adding tstamp 50.949112768 to clock /dev/ptp3 ts2phc[55.988]: adding tstamp 51.000000000 to clock /dev/ptp1 ts2phc[55.988]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[56.476]: /dev/ptp3 SKIP extts index 0 at 51.449108120 src 51.504175910 ts2phc[57.132]: adding tstamp 51.949103480 to clock /dev/ptp3 ts2phc[57.132]: adding tstamp 52.000000000 to clock /dev/ptp1 ts2phc[57.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[57.624]: /dev/ptp3 SKIP extts index 0 at 52.449098840 src 52.651833574 ts2phc[58.116]: adding tstamp 52.949094200 to clock /dev/ptp3 ts2phc[58.116]: adding tstamp 53.000000000 to clock /dev/ptp1 ts2phc[58.116]: /dev/ptp3 offset 8 s2 freq +4392 ts2phc[58.612]: /dev/ptp3 SKIP extts index 0 at 53.449089560 src 53.639826918 ts2phc[59.100]: adding tstamp 53.949084920 to clock /dev/ptp3 ts2phc[59.100]: adding tstamp 54.000000000 to clock /dev/ptp1 ts2phc[59.100]: /dev/ptp3 offset 8 s2 freq +4394 ts2phc[59.592]: /dev/ptp3 SKIP extts index 0 at 54.449080272 src 54.619842278 ts2phc[60.084]: adding tstamp 54.949075624 to clock /dev/ptp3 ts2phc[60.084]: adding tstamp 55.000000000 to clock /dev/ptp1 ts2phc[60.084]: /dev/ptp3 offset 8 s2 freq +4397 ts2phc[60.576]: /dev/ptp3 SKIP extts index 0 at 55.449070968 src 55.603885542 ts2phc[61.068]: adding tstamp 55.949066312 to clock /dev/ptp3 ts2phc[61.068]: adding tstamp 56.000000000 to clock /dev/ptp1 ts2phc[61.068]: /dev/ptp3 offset 0 s2 freq +4391 ts2phc[61.560]: /dev/ptp3 SKIP extts index 0 at 56.449061680 src 56.587885798 ts2phc[62.052]: adding tstamp 56.949057032 to clock /dev/ptp3 ts2phc[62.052]: adding tstamp 57.000000000 to clock /dev/ptp1 ts2phc[62.052]: /dev/ptp3 offset -8 s2 freq +4383 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-03 20:51:58 +03:00
ptp_schedule_worker(ptp_data->clock, 0);
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
net: dsa: sja1105: poll for extts events from a timer The current poll interval is enough to ensure that rising and falling edge events are not lost for a 1 PPS signal with 50% duty cycle. But when we deliver the events to user space, it will try to infer if they were corresponding to a rising or to a falling edge (the kernel driver doesn't know that either). User space will try to make that inference based on the time at which the PPS master had emitted the pulse (i.e. if it's a .0 time, it's rising edge, if it's .5 time, it's falling edge). But there is no in-kernel API for retrieving the precise timestamp corresponding to a PPS master (aka perout) pulse. So user space has to guess even that. It will read the PTP time on the PPS master right after we've delivered the extts event, and declare that the PPS master time was just the closest integer second, based on 2 thresholds (lower than .25, or higher than .75, and ignore anything else). Except that, if we poll for extts events (and our hardware doesn't really help us, by not providing an interrupt), then there is a risk that the poll period (and therefore the time at which the event is delivered) might confuse user space. Because we are always scheduling the next extts poll at SJA1105_EXTTS_INTERVAL "from now" (that's the only thing that the schedule_delayed_work() API gives us), it means that the start time of the next delayed workqueue will always be shifted to the right a little bit (shifted with the SPI access duration of this workqueue run). In turn, because user space sees extts events that are non-periodic compared to the PPS master's time, this means that it might start making wrong guesses about rising/falling edge. To understand the effect, here is the output of ts2phc currently. Notice the 'src' timestamps of the 'SKIP extts' events, and how they have a large wander. They keep increasing until the upper limit for the ignore threshold (.75 seconds), after which the application starts ignoring the _other_ edge. ts2phc[26.624]: /dev/ptp3 SKIP extts index 0 at 21.449898912 src 21.657784518 ts2phc[27.133]: adding tstamp 21.949894240 to clock /dev/ptp3 ts2phc[27.133]: adding tstamp 22.000000000 to clock /dev/ptp1 ts2phc[27.133]: /dev/ptp3 offset 640 s2 freq +5112 ts2phc[27.636]: /dev/ptp3 SKIP extts index 0 at 22.449889360 src 22.669398022 ts2phc[28.140]: adding tstamp 22.949884376 to clock /dev/ptp3 ts2phc[28.140]: adding tstamp 23.000000000 to clock /dev/ptp1 ts2phc[28.140]: /dev/ptp3 offset 96 s2 freq +4760 ts2phc[28.644]: /dev/ptp3 SKIP extts index 0 at 23.449879504 src 23.677420422 ts2phc[29.153]: adding tstamp 23.949874704 to clock /dev/ptp3 ts2phc[29.153]: adding tstamp 24.000000000 to clock /dev/ptp1 ts2phc[29.153]: /dev/ptp3 offset -264 s2 freq +4429 ts2phc[29.656]: /dev/ptp3 SKIP extts index 0 at 24.449870008 src 24.689407238 ts2phc[30.160]: adding tstamp 24.949865376 to clock /dev/ptp3 ts2phc[30.160]: adding tstamp 25.000000000 to clock /dev/ptp1 ts2phc[30.160]: /dev/ptp3 offset -280 s2 freq +4334 ts2phc[30.664]: /dev/ptp3 SKIP extts index 0 at 25.449860760 src 25.697449926 ts2phc[31.168]: adding tstamp 25.949856176 to clock /dev/ptp3 ts2phc[31.168]: adding tstamp 26.000000000 to clock /dev/ptp1 ts2phc[31.168]: /dev/ptp3 offset -176 s2 freq +4354 ts2phc[31.672]: /dev/ptp3 SKIP extts index 0 at 26.449851584 src 26.705433606 ts2phc[32.180]: adding tstamp 26.949846992 to clock /dev/ptp3 ts2phc[32.180]: adding tstamp 27.000000000 to clock /dev/ptp1 ts2phc[32.180]: /dev/ptp3 offset -80 s2 freq +4397 ts2phc[32.684]: /dev/ptp3 SKIP extts index 0 at 27.449842384 src 27.717415110 ts2phc[33.192]: adding tstamp 27.949837768 to clock /dev/ptp3 ts2phc[33.192]: adding tstamp 28.000000000 to clock /dev/ptp1 ts2phc[33.192]: /dev/ptp3 offset 0 s2 freq +4453 ts2phc[33.696]: /dev/ptp3 SKIP extts index 0 at 28.449833128 src 28.729412902 ts2phc[34.200]: adding tstamp 28.949828472 to clock /dev/ptp3 ts2phc[34.200]: adding tstamp 29.000000000 to clock /dev/ptp1 ts2phc[34.200]: /dev/ptp3 offset 8 s2 freq +4461 ts2phc[34.704]: /dev/ptp3 SKIP extts index 0 at 29.449823816 src 29.737416038 ts2phc[35.208]: adding tstamp 29.949819152 to clock /dev/ptp3 ts2phc[35.208]: adding tstamp 30.000000000 to clock /dev/ptp1 ts2phc[35.208]: /dev/ptp3 offset -8 s2 freq +4447 ts2phc[35.712]: /dev/ptp3 SKIP extts index 0 at 30.449814496 src 30.745554982 ts2phc[36.216]: adding tstamp 30.949809840 to clock /dev/ptp3 ts2phc[36.216]: adding tstamp 31.000000000 to clock /dev/ptp1 ts2phc[36.216]: /dev/ptp3 offset -8 s2 freq +4445 ts2phc[36.468]: /dev/ptp3 SKIP extts index 0 at 31.449805184 src 31.501109446 ts2phc[36.972]: adding tstamp 31.949800536 to clock /dev/ptp3 ts2phc[36.972]: adding tstamp 32.000000000 to clock /dev/ptp1 ts2phc[36.972]: /dev/ptp3 offset -8 s2 freq +4442 ts2phc[37.480]: /dev/ptp3 SKIP extts index 0 at 32.449795896 src 32.513320070 ts2phc[37.984]: adding tstamp 32.949791248 to clock /dev/ptp3 ts2phc[37.984]: adding tstamp 33.000000000 to clock /dev/ptp1 ts2phc[37.984]: /dev/ptp3 offset 0 s2 freq +4448 Fix that by taking the following measures: - Schedule the poll from a timer. Because we are really scheduling the timer periodically, the extts events delivered to user space are periodic too, and don't suffer from the "shift-to-the-right" effect. - Increase the poll period to 6 times a second. This imposes a smaller upper bound to the shift that can occur to the delivery time of extts events, and makes user space (ts2phc) to always interpret correctly which events should be skipped and which shouldn't. - Move the SPI readout itself to the main PTP kernel thread, instead of the generic workqueue. This is because the timer runs in atomic context, but is also better than before, because if needed, we can chrt & taskset this kernel thread, to ensure it gets enough priority under load. After this patch, one can notice that the wander is greatly reduced, and that the latencies of one extts poll are not propagated to the next. The 'src' timestamp that is skipped is never larger than .65 seconds (which means .15 seconds larger than the time at which the real event occurred at, and .10 seconds smaller than the .75 upper threshold for ignoring the falling edge): ts2phc[40.076]: adding tstamp 34.949261296 to clock /dev/ptp3 ts2phc[40.076]: adding tstamp 35.000000000 to clock /dev/ptp1 ts2phc[40.076]: /dev/ptp3 offset 48 s2 freq +4631 ts2phc[40.568]: /dev/ptp3 SKIP extts index 0 at 35.449256496 src 35.595791078 ts2phc[41.064]: adding tstamp 35.949251744 to clock /dev/ptp3 ts2phc[41.064]: adding tstamp 36.000000000 to clock /dev/ptp1 ts2phc[41.064]: /dev/ptp3 offset -224 s2 freq +4374 ts2phc[41.552]: /dev/ptp3 SKIP extts index 0 at 36.449247088 src 36.579825574 ts2phc[42.044]: adding tstamp 36.949242456 to clock /dev/ptp3 ts2phc[42.044]: adding tstamp 37.000000000 to clock /dev/ptp1 ts2phc[42.044]: /dev/ptp3 offset -240 s2 freq +4290 ts2phc[42.536]: /dev/ptp3 SKIP extts index 0 at 37.449237848 src 37.563828774 ts2phc[43.028]: adding tstamp 37.949233264 to clock /dev/ptp3 ts2phc[43.028]: adding tstamp 38.000000000 to clock /dev/ptp1 ts2phc[43.028]: /dev/ptp3 offset -144 s2 freq +4314 ts2phc[43.520]: /dev/ptp3 SKIP extts index 0 at 38.449228656 src 38.547823238 ts2phc[44.012]: adding tstamp 38.949224048 to clock /dev/ptp3 ts2phc[44.012]: adding tstamp 39.000000000 to clock /dev/ptp1 ts2phc[44.012]: /dev/ptp3 offset -80 s2 freq +4335 ts2phc[44.508]: /dev/ptp3 SKIP extts index 0 at 39.449219432 src 39.535846118 ts2phc[44.996]: adding tstamp 39.949214816 to clock /dev/ptp3 ts2phc[44.996]: adding tstamp 40.000000000 to clock /dev/ptp1 ts2phc[44.996]: /dev/ptp3 offset -32 s2 freq +4359 ts2phc[45.488]: /dev/ptp3 SKIP extts index 0 at 40.449210192 src 40.515824678 ts2phc[45.980]: adding tstamp 40.949205568 to clock /dev/ptp3 ts2phc[45.980]: adding tstamp 41.000000000 to clock /dev/ptp1 ts2phc[45.980]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[46.636]: /dev/ptp3 SKIP extts index 0 at 41.449200928 src 41.664176902 ts2phc[47.132]: adding tstamp 41.949196288 to clock /dev/ptp3 ts2phc[47.132]: adding tstamp 42.000000000 to clock /dev/ptp1 ts2phc[47.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[47.620]: /dev/ptp3 SKIP extts index 0 at 42.449191656 src 42.648117190 ts2phc[48.112]: adding tstamp 42.949187016 to clock /dev/ptp3 ts2phc[48.112]: adding tstamp 43.000000000 to clock /dev/ptp1 ts2phc[48.112]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[48.604]: /dev/ptp3 SKIP extts index 0 at 43.449182384 src 43.632112582 ts2phc[49.100]: adding tstamp 43.949177736 to clock /dev/ptp3 ts2phc[49.100]: adding tstamp 44.000000000 to clock /dev/ptp1 ts2phc[49.100]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[49.588]: /dev/ptp3 SKIP extts index 0 at 44.449173096 src 44.616136774 ts2phc[50.080]: adding tstamp 44.949168464 to clock /dev/ptp3 ts2phc[50.080]: adding tstamp 45.000000000 to clock /dev/ptp1 ts2phc[50.080]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[50.572]: /dev/ptp3 SKIP extts index 0 at 45.449163816 src 45.600134662 ts2phc[51.064]: adding tstamp 45.949159160 to clock /dev/ptp3 ts2phc[51.064]: adding tstamp 46.000000000 to clock /dev/ptp1 ts2phc[51.064]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[51.556]: /dev/ptp3 SKIP extts index 0 at 46.449154528 src 46.584588550 ts2phc[52.048]: adding tstamp 46.949149896 to clock /dev/ptp3 ts2phc[52.048]: adding tstamp 47.000000000 to clock /dev/ptp1 ts2phc[52.048]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[52.540]: /dev/ptp3 SKIP extts index 0 at 47.449145256 src 47.568132198 ts2phc[53.032]: adding tstamp 47.949140616 to clock /dev/ptp3 ts2phc[53.032]: adding tstamp 48.000000000 to clock /dev/ptp1 ts2phc[53.032]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[53.524]: /dev/ptp3 SKIP extts index 0 at 48.449135968 src 48.552121446 ts2phc[54.016]: adding tstamp 48.949131320 to clock /dev/ptp3 ts2phc[54.016]: adding tstamp 49.000000000 to clock /dev/ptp1 ts2phc[54.016]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[54.512]: /dev/ptp3 SKIP extts index 0 at 49.449126680 src 49.540147014 ts2phc[55.000]: adding tstamp 49.949122040 to clock /dev/ptp3 ts2phc[55.000]: adding tstamp 50.000000000 to clock /dev/ptp1 ts2phc[55.000]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[55.492]: /dev/ptp3 SKIP extts index 0 at 50.449117400 src 50.520119078 ts2phc[55.988]: adding tstamp 50.949112768 to clock /dev/ptp3 ts2phc[55.988]: adding tstamp 51.000000000 to clock /dev/ptp1 ts2phc[55.988]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[56.476]: /dev/ptp3 SKIP extts index 0 at 51.449108120 src 51.504175910 ts2phc[57.132]: adding tstamp 51.949103480 to clock /dev/ptp3 ts2phc[57.132]: adding tstamp 52.000000000 to clock /dev/ptp1 ts2phc[57.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[57.624]: /dev/ptp3 SKIP extts index 0 at 52.449098840 src 52.651833574 ts2phc[58.116]: adding tstamp 52.949094200 to clock /dev/ptp3 ts2phc[58.116]: adding tstamp 53.000000000 to clock /dev/ptp1 ts2phc[58.116]: /dev/ptp3 offset 8 s2 freq +4392 ts2phc[58.612]: /dev/ptp3 SKIP extts index 0 at 53.449089560 src 53.639826918 ts2phc[59.100]: adding tstamp 53.949084920 to clock /dev/ptp3 ts2phc[59.100]: adding tstamp 54.000000000 to clock /dev/ptp1 ts2phc[59.100]: /dev/ptp3 offset 8 s2 freq +4394 ts2phc[59.592]: /dev/ptp3 SKIP extts index 0 at 54.449080272 src 54.619842278 ts2phc[60.084]: adding tstamp 54.949075624 to clock /dev/ptp3 ts2phc[60.084]: adding tstamp 55.000000000 to clock /dev/ptp1 ts2phc[60.084]: /dev/ptp3 offset 8 s2 freq +4397 ts2phc[60.576]: /dev/ptp3 SKIP extts index 0 at 55.449070968 src 55.603885542 ts2phc[61.068]: adding tstamp 55.949066312 to clock /dev/ptp3 ts2phc[61.068]: adding tstamp 56.000000000 to clock /dev/ptp1 ts2phc[61.068]: /dev/ptp3 offset 0 s2 freq +4391 ts2phc[61.560]: /dev/ptp3 SKIP extts index 0 at 56.449061680 src 56.587885798 ts2phc[62.052]: adding tstamp 56.949057032 to clock /dev/ptp3 ts2phc[62.052]: adding tstamp 57.000000000 to clock /dev/ptp1 ts2phc[62.052]: /dev/ptp3 offset -8 s2 freq +4383 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-03 20:51:58 +03:00
sja1105_ptp_extts_setup_timer(ptp_data);
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
}
static int sja1105_change_ptp_clk_pin_func(struct sja1105_private *priv,
enum ptp_pin_function func)
{
struct sja1105_avb_params_entry *avb;
enum ptp_pin_function old_func;
avb = priv->static_config.tables[BLK_IDX_AVB_PARAMS].entries;
if (priv->info->device_id == SJA1105E_DEVICE_ID ||
priv->info->device_id == SJA1105T_DEVICE_ID ||
avb->cas_master)
old_func = PTP_PF_PEROUT;
else
old_func = PTP_PF_EXTTS;
if (func == old_func)
return 0;
avb->cas_master = (func == PTP_PF_PEROUT);
return sja1105_dynamic_config_write(priv, BLK_IDX_AVB_PARAMS, 0, avb,
true);
}
/* The PTP_CLK pin may be configured to toggle with a 50% duty cycle and a
* frequency f:
*
* NSEC_PER_SEC
* f = ----------------------
* (PTPPINDUR * 8 ns) * 2
*/
static int sja1105_per_out_enable(struct sja1105_private *priv,
struct ptp_perout_request *perout,
bool on)
{
struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
const struct sja1105_regs *regs = priv->info->regs;
struct sja1105_ptp_cmd cmd = ptp_data->cmd;
int rc;
/* We only support one channel */
if (perout->index != 0)
return -EOPNOTSUPP;
mutex_lock(&ptp_data->lock);
rc = sja1105_change_ptp_clk_pin_func(priv, PTP_PF_PEROUT);
if (rc)
goto out;
if (on) {
struct timespec64 pin_duration_ts = {
.tv_sec = perout->period.sec,
.tv_nsec = perout->period.nsec,
};
struct timespec64 pin_start_ts = {
.tv_sec = perout->start.sec,
.tv_nsec = perout->start.nsec,
};
u64 pin_duration = timespec64_to_ns(&pin_duration_ts);
u64 pin_start = timespec64_to_ns(&pin_start_ts);
u32 pin_duration32;
u64 now;
/* ptppindur: 32 bit register which holds the interval between
* 2 edges on PTP_CLK. So check for truncation which happens
* at periods larger than around 68.7 seconds.
*/
pin_duration = ns_to_sja1105_ticks(pin_duration / 2);
if (pin_duration > U32_MAX) {
rc = -ERANGE;
goto out;
}
pin_duration32 = pin_duration;
/* ptppins: 64 bit register which needs to hold a PTP time
* larger than the current time, otherwise the startptpcp
* command won't do anything. So advance the current time
* by a number of periods in a way that won't alter the
* phase offset.
*/
rc = __sja1105_ptp_gettimex(priv->ds, &now, NULL);
if (rc < 0)
goto out;
pin_start = future_base_time(pin_start, pin_duration,
now + 1ull * NSEC_PER_SEC);
pin_start = ns_to_sja1105_ticks(pin_start);
rc = sja1105_xfer_u64(priv, SPI_WRITE, regs->ptppinst,
&pin_start, NULL);
if (rc < 0)
goto out;
rc = sja1105_xfer_u32(priv, SPI_WRITE, regs->ptppindur,
&pin_duration32, NULL);
if (rc < 0)
goto out;
}
if (on)
cmd.startptpcp = true;
else
cmd.stopptpcp = true;
rc = sja1105_ptp_commit(priv->ds, &cmd, SPI_WRITE);
out:
mutex_unlock(&ptp_data->lock);
return rc;
}
static int sja1105_extts_enable(struct sja1105_private *priv,
struct ptp_extts_request *extts,
bool on)
{
int rc;
/* We only support one channel */
if (extts->index != 0)
return -EOPNOTSUPP;
/* We can only enable time stamping on both edges, sadly. */
if ((extts->flags & PTP_STRICT_FLAGS) &&
(extts->flags & PTP_ENABLE_FEATURE) &&
(extts->flags & PTP_EXTTS_EDGES) != PTP_EXTTS_EDGES)
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
return -EOPNOTSUPP;
rc = sja1105_change_ptp_clk_pin_func(priv, PTP_PF_EXTTS);
if (rc)
return rc;
net: dsa: sja1105: poll for extts events from a timer The current poll interval is enough to ensure that rising and falling edge events are not lost for a 1 PPS signal with 50% duty cycle. But when we deliver the events to user space, it will try to infer if they were corresponding to a rising or to a falling edge (the kernel driver doesn't know that either). User space will try to make that inference based on the time at which the PPS master had emitted the pulse (i.e. if it's a .0 time, it's rising edge, if it's .5 time, it's falling edge). But there is no in-kernel API for retrieving the precise timestamp corresponding to a PPS master (aka perout) pulse. So user space has to guess even that. It will read the PTP time on the PPS master right after we've delivered the extts event, and declare that the PPS master time was just the closest integer second, based on 2 thresholds (lower than .25, or higher than .75, and ignore anything else). Except that, if we poll for extts events (and our hardware doesn't really help us, by not providing an interrupt), then there is a risk that the poll period (and therefore the time at which the event is delivered) might confuse user space. Because we are always scheduling the next extts poll at SJA1105_EXTTS_INTERVAL "from now" (that's the only thing that the schedule_delayed_work() API gives us), it means that the start time of the next delayed workqueue will always be shifted to the right a little bit (shifted with the SPI access duration of this workqueue run). In turn, because user space sees extts events that are non-periodic compared to the PPS master's time, this means that it might start making wrong guesses about rising/falling edge. To understand the effect, here is the output of ts2phc currently. Notice the 'src' timestamps of the 'SKIP extts' events, and how they have a large wander. They keep increasing until the upper limit for the ignore threshold (.75 seconds), after which the application starts ignoring the _other_ edge. ts2phc[26.624]: /dev/ptp3 SKIP extts index 0 at 21.449898912 src 21.657784518 ts2phc[27.133]: adding tstamp 21.949894240 to clock /dev/ptp3 ts2phc[27.133]: adding tstamp 22.000000000 to clock /dev/ptp1 ts2phc[27.133]: /dev/ptp3 offset 640 s2 freq +5112 ts2phc[27.636]: /dev/ptp3 SKIP extts index 0 at 22.449889360 src 22.669398022 ts2phc[28.140]: adding tstamp 22.949884376 to clock /dev/ptp3 ts2phc[28.140]: adding tstamp 23.000000000 to clock /dev/ptp1 ts2phc[28.140]: /dev/ptp3 offset 96 s2 freq +4760 ts2phc[28.644]: /dev/ptp3 SKIP extts index 0 at 23.449879504 src 23.677420422 ts2phc[29.153]: adding tstamp 23.949874704 to clock /dev/ptp3 ts2phc[29.153]: adding tstamp 24.000000000 to clock /dev/ptp1 ts2phc[29.153]: /dev/ptp3 offset -264 s2 freq +4429 ts2phc[29.656]: /dev/ptp3 SKIP extts index 0 at 24.449870008 src 24.689407238 ts2phc[30.160]: adding tstamp 24.949865376 to clock /dev/ptp3 ts2phc[30.160]: adding tstamp 25.000000000 to clock /dev/ptp1 ts2phc[30.160]: /dev/ptp3 offset -280 s2 freq +4334 ts2phc[30.664]: /dev/ptp3 SKIP extts index 0 at 25.449860760 src 25.697449926 ts2phc[31.168]: adding tstamp 25.949856176 to clock /dev/ptp3 ts2phc[31.168]: adding tstamp 26.000000000 to clock /dev/ptp1 ts2phc[31.168]: /dev/ptp3 offset -176 s2 freq +4354 ts2phc[31.672]: /dev/ptp3 SKIP extts index 0 at 26.449851584 src 26.705433606 ts2phc[32.180]: adding tstamp 26.949846992 to clock /dev/ptp3 ts2phc[32.180]: adding tstamp 27.000000000 to clock /dev/ptp1 ts2phc[32.180]: /dev/ptp3 offset -80 s2 freq +4397 ts2phc[32.684]: /dev/ptp3 SKIP extts index 0 at 27.449842384 src 27.717415110 ts2phc[33.192]: adding tstamp 27.949837768 to clock /dev/ptp3 ts2phc[33.192]: adding tstamp 28.000000000 to clock /dev/ptp1 ts2phc[33.192]: /dev/ptp3 offset 0 s2 freq +4453 ts2phc[33.696]: /dev/ptp3 SKIP extts index 0 at 28.449833128 src 28.729412902 ts2phc[34.200]: adding tstamp 28.949828472 to clock /dev/ptp3 ts2phc[34.200]: adding tstamp 29.000000000 to clock /dev/ptp1 ts2phc[34.200]: /dev/ptp3 offset 8 s2 freq +4461 ts2phc[34.704]: /dev/ptp3 SKIP extts index 0 at 29.449823816 src 29.737416038 ts2phc[35.208]: adding tstamp 29.949819152 to clock /dev/ptp3 ts2phc[35.208]: adding tstamp 30.000000000 to clock /dev/ptp1 ts2phc[35.208]: /dev/ptp3 offset -8 s2 freq +4447 ts2phc[35.712]: /dev/ptp3 SKIP extts index 0 at 30.449814496 src 30.745554982 ts2phc[36.216]: adding tstamp 30.949809840 to clock /dev/ptp3 ts2phc[36.216]: adding tstamp 31.000000000 to clock /dev/ptp1 ts2phc[36.216]: /dev/ptp3 offset -8 s2 freq +4445 ts2phc[36.468]: /dev/ptp3 SKIP extts index 0 at 31.449805184 src 31.501109446 ts2phc[36.972]: adding tstamp 31.949800536 to clock /dev/ptp3 ts2phc[36.972]: adding tstamp 32.000000000 to clock /dev/ptp1 ts2phc[36.972]: /dev/ptp3 offset -8 s2 freq +4442 ts2phc[37.480]: /dev/ptp3 SKIP extts index 0 at 32.449795896 src 32.513320070 ts2phc[37.984]: adding tstamp 32.949791248 to clock /dev/ptp3 ts2phc[37.984]: adding tstamp 33.000000000 to clock /dev/ptp1 ts2phc[37.984]: /dev/ptp3 offset 0 s2 freq +4448 Fix that by taking the following measures: - Schedule the poll from a timer. Because we are really scheduling the timer periodically, the extts events delivered to user space are periodic too, and don't suffer from the "shift-to-the-right" effect. - Increase the poll period to 6 times a second. This imposes a smaller upper bound to the shift that can occur to the delivery time of extts events, and makes user space (ts2phc) to always interpret correctly which events should be skipped and which shouldn't. - Move the SPI readout itself to the main PTP kernel thread, instead of the generic workqueue. This is because the timer runs in atomic context, but is also better than before, because if needed, we can chrt & taskset this kernel thread, to ensure it gets enough priority under load. After this patch, one can notice that the wander is greatly reduced, and that the latencies of one extts poll are not propagated to the next. The 'src' timestamp that is skipped is never larger than .65 seconds (which means .15 seconds larger than the time at which the real event occurred at, and .10 seconds smaller than the .75 upper threshold for ignoring the falling edge): ts2phc[40.076]: adding tstamp 34.949261296 to clock /dev/ptp3 ts2phc[40.076]: adding tstamp 35.000000000 to clock /dev/ptp1 ts2phc[40.076]: /dev/ptp3 offset 48 s2 freq +4631 ts2phc[40.568]: /dev/ptp3 SKIP extts index 0 at 35.449256496 src 35.595791078 ts2phc[41.064]: adding tstamp 35.949251744 to clock /dev/ptp3 ts2phc[41.064]: adding tstamp 36.000000000 to clock /dev/ptp1 ts2phc[41.064]: /dev/ptp3 offset -224 s2 freq +4374 ts2phc[41.552]: /dev/ptp3 SKIP extts index 0 at 36.449247088 src 36.579825574 ts2phc[42.044]: adding tstamp 36.949242456 to clock /dev/ptp3 ts2phc[42.044]: adding tstamp 37.000000000 to clock /dev/ptp1 ts2phc[42.044]: /dev/ptp3 offset -240 s2 freq +4290 ts2phc[42.536]: /dev/ptp3 SKIP extts index 0 at 37.449237848 src 37.563828774 ts2phc[43.028]: adding tstamp 37.949233264 to clock /dev/ptp3 ts2phc[43.028]: adding tstamp 38.000000000 to clock /dev/ptp1 ts2phc[43.028]: /dev/ptp3 offset -144 s2 freq +4314 ts2phc[43.520]: /dev/ptp3 SKIP extts index 0 at 38.449228656 src 38.547823238 ts2phc[44.012]: adding tstamp 38.949224048 to clock /dev/ptp3 ts2phc[44.012]: adding tstamp 39.000000000 to clock /dev/ptp1 ts2phc[44.012]: /dev/ptp3 offset -80 s2 freq +4335 ts2phc[44.508]: /dev/ptp3 SKIP extts index 0 at 39.449219432 src 39.535846118 ts2phc[44.996]: adding tstamp 39.949214816 to clock /dev/ptp3 ts2phc[44.996]: adding tstamp 40.000000000 to clock /dev/ptp1 ts2phc[44.996]: /dev/ptp3 offset -32 s2 freq +4359 ts2phc[45.488]: /dev/ptp3 SKIP extts index 0 at 40.449210192 src 40.515824678 ts2phc[45.980]: adding tstamp 40.949205568 to clock /dev/ptp3 ts2phc[45.980]: adding tstamp 41.000000000 to clock /dev/ptp1 ts2phc[45.980]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[46.636]: /dev/ptp3 SKIP extts index 0 at 41.449200928 src 41.664176902 ts2phc[47.132]: adding tstamp 41.949196288 to clock /dev/ptp3 ts2phc[47.132]: adding tstamp 42.000000000 to clock /dev/ptp1 ts2phc[47.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[47.620]: /dev/ptp3 SKIP extts index 0 at 42.449191656 src 42.648117190 ts2phc[48.112]: adding tstamp 42.949187016 to clock /dev/ptp3 ts2phc[48.112]: adding tstamp 43.000000000 to clock /dev/ptp1 ts2phc[48.112]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[48.604]: /dev/ptp3 SKIP extts index 0 at 43.449182384 src 43.632112582 ts2phc[49.100]: adding tstamp 43.949177736 to clock /dev/ptp3 ts2phc[49.100]: adding tstamp 44.000000000 to clock /dev/ptp1 ts2phc[49.100]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[49.588]: /dev/ptp3 SKIP extts index 0 at 44.449173096 src 44.616136774 ts2phc[50.080]: adding tstamp 44.949168464 to clock /dev/ptp3 ts2phc[50.080]: adding tstamp 45.000000000 to clock /dev/ptp1 ts2phc[50.080]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[50.572]: /dev/ptp3 SKIP extts index 0 at 45.449163816 src 45.600134662 ts2phc[51.064]: adding tstamp 45.949159160 to clock /dev/ptp3 ts2phc[51.064]: adding tstamp 46.000000000 to clock /dev/ptp1 ts2phc[51.064]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[51.556]: /dev/ptp3 SKIP extts index 0 at 46.449154528 src 46.584588550 ts2phc[52.048]: adding tstamp 46.949149896 to clock /dev/ptp3 ts2phc[52.048]: adding tstamp 47.000000000 to clock /dev/ptp1 ts2phc[52.048]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[52.540]: /dev/ptp3 SKIP extts index 0 at 47.449145256 src 47.568132198 ts2phc[53.032]: adding tstamp 47.949140616 to clock /dev/ptp3 ts2phc[53.032]: adding tstamp 48.000000000 to clock /dev/ptp1 ts2phc[53.032]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[53.524]: /dev/ptp3 SKIP extts index 0 at 48.449135968 src 48.552121446 ts2phc[54.016]: adding tstamp 48.949131320 to clock /dev/ptp3 ts2phc[54.016]: adding tstamp 49.000000000 to clock /dev/ptp1 ts2phc[54.016]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[54.512]: /dev/ptp3 SKIP extts index 0 at 49.449126680 src 49.540147014 ts2phc[55.000]: adding tstamp 49.949122040 to clock /dev/ptp3 ts2phc[55.000]: adding tstamp 50.000000000 to clock /dev/ptp1 ts2phc[55.000]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[55.492]: /dev/ptp3 SKIP extts index 0 at 50.449117400 src 50.520119078 ts2phc[55.988]: adding tstamp 50.949112768 to clock /dev/ptp3 ts2phc[55.988]: adding tstamp 51.000000000 to clock /dev/ptp1 ts2phc[55.988]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[56.476]: /dev/ptp3 SKIP extts index 0 at 51.449108120 src 51.504175910 ts2phc[57.132]: adding tstamp 51.949103480 to clock /dev/ptp3 ts2phc[57.132]: adding tstamp 52.000000000 to clock /dev/ptp1 ts2phc[57.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[57.624]: /dev/ptp3 SKIP extts index 0 at 52.449098840 src 52.651833574 ts2phc[58.116]: adding tstamp 52.949094200 to clock /dev/ptp3 ts2phc[58.116]: adding tstamp 53.000000000 to clock /dev/ptp1 ts2phc[58.116]: /dev/ptp3 offset 8 s2 freq +4392 ts2phc[58.612]: /dev/ptp3 SKIP extts index 0 at 53.449089560 src 53.639826918 ts2phc[59.100]: adding tstamp 53.949084920 to clock /dev/ptp3 ts2phc[59.100]: adding tstamp 54.000000000 to clock /dev/ptp1 ts2phc[59.100]: /dev/ptp3 offset 8 s2 freq +4394 ts2phc[59.592]: /dev/ptp3 SKIP extts index 0 at 54.449080272 src 54.619842278 ts2phc[60.084]: adding tstamp 54.949075624 to clock /dev/ptp3 ts2phc[60.084]: adding tstamp 55.000000000 to clock /dev/ptp1 ts2phc[60.084]: /dev/ptp3 offset 8 s2 freq +4397 ts2phc[60.576]: /dev/ptp3 SKIP extts index 0 at 55.449070968 src 55.603885542 ts2phc[61.068]: adding tstamp 55.949066312 to clock /dev/ptp3 ts2phc[61.068]: adding tstamp 56.000000000 to clock /dev/ptp1 ts2phc[61.068]: /dev/ptp3 offset 0 s2 freq +4391 ts2phc[61.560]: /dev/ptp3 SKIP extts index 0 at 56.449061680 src 56.587885798 ts2phc[62.052]: adding tstamp 56.949057032 to clock /dev/ptp3 ts2phc[62.052]: adding tstamp 57.000000000 to clock /dev/ptp1 ts2phc[62.052]: /dev/ptp3 offset -8 s2 freq +4383 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-03 20:51:58 +03:00
priv->ptp_data.extts_enabled = on;
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
if (on)
net: dsa: sja1105: poll for extts events from a timer The current poll interval is enough to ensure that rising and falling edge events are not lost for a 1 PPS signal with 50% duty cycle. But when we deliver the events to user space, it will try to infer if they were corresponding to a rising or to a falling edge (the kernel driver doesn't know that either). User space will try to make that inference based on the time at which the PPS master had emitted the pulse (i.e. if it's a .0 time, it's rising edge, if it's .5 time, it's falling edge). But there is no in-kernel API for retrieving the precise timestamp corresponding to a PPS master (aka perout) pulse. So user space has to guess even that. It will read the PTP time on the PPS master right after we've delivered the extts event, and declare that the PPS master time was just the closest integer second, based on 2 thresholds (lower than .25, or higher than .75, and ignore anything else). Except that, if we poll for extts events (and our hardware doesn't really help us, by not providing an interrupt), then there is a risk that the poll period (and therefore the time at which the event is delivered) might confuse user space. Because we are always scheduling the next extts poll at SJA1105_EXTTS_INTERVAL "from now" (that's the only thing that the schedule_delayed_work() API gives us), it means that the start time of the next delayed workqueue will always be shifted to the right a little bit (shifted with the SPI access duration of this workqueue run). In turn, because user space sees extts events that are non-periodic compared to the PPS master's time, this means that it might start making wrong guesses about rising/falling edge. To understand the effect, here is the output of ts2phc currently. Notice the 'src' timestamps of the 'SKIP extts' events, and how they have a large wander. They keep increasing until the upper limit for the ignore threshold (.75 seconds), after which the application starts ignoring the _other_ edge. ts2phc[26.624]: /dev/ptp3 SKIP extts index 0 at 21.449898912 src 21.657784518 ts2phc[27.133]: adding tstamp 21.949894240 to clock /dev/ptp3 ts2phc[27.133]: adding tstamp 22.000000000 to clock /dev/ptp1 ts2phc[27.133]: /dev/ptp3 offset 640 s2 freq +5112 ts2phc[27.636]: /dev/ptp3 SKIP extts index 0 at 22.449889360 src 22.669398022 ts2phc[28.140]: adding tstamp 22.949884376 to clock /dev/ptp3 ts2phc[28.140]: adding tstamp 23.000000000 to clock /dev/ptp1 ts2phc[28.140]: /dev/ptp3 offset 96 s2 freq +4760 ts2phc[28.644]: /dev/ptp3 SKIP extts index 0 at 23.449879504 src 23.677420422 ts2phc[29.153]: adding tstamp 23.949874704 to clock /dev/ptp3 ts2phc[29.153]: adding tstamp 24.000000000 to clock /dev/ptp1 ts2phc[29.153]: /dev/ptp3 offset -264 s2 freq +4429 ts2phc[29.656]: /dev/ptp3 SKIP extts index 0 at 24.449870008 src 24.689407238 ts2phc[30.160]: adding tstamp 24.949865376 to clock /dev/ptp3 ts2phc[30.160]: adding tstamp 25.000000000 to clock /dev/ptp1 ts2phc[30.160]: /dev/ptp3 offset -280 s2 freq +4334 ts2phc[30.664]: /dev/ptp3 SKIP extts index 0 at 25.449860760 src 25.697449926 ts2phc[31.168]: adding tstamp 25.949856176 to clock /dev/ptp3 ts2phc[31.168]: adding tstamp 26.000000000 to clock /dev/ptp1 ts2phc[31.168]: /dev/ptp3 offset -176 s2 freq +4354 ts2phc[31.672]: /dev/ptp3 SKIP extts index 0 at 26.449851584 src 26.705433606 ts2phc[32.180]: adding tstamp 26.949846992 to clock /dev/ptp3 ts2phc[32.180]: adding tstamp 27.000000000 to clock /dev/ptp1 ts2phc[32.180]: /dev/ptp3 offset -80 s2 freq +4397 ts2phc[32.684]: /dev/ptp3 SKIP extts index 0 at 27.449842384 src 27.717415110 ts2phc[33.192]: adding tstamp 27.949837768 to clock /dev/ptp3 ts2phc[33.192]: adding tstamp 28.000000000 to clock /dev/ptp1 ts2phc[33.192]: /dev/ptp3 offset 0 s2 freq +4453 ts2phc[33.696]: /dev/ptp3 SKIP extts index 0 at 28.449833128 src 28.729412902 ts2phc[34.200]: adding tstamp 28.949828472 to clock /dev/ptp3 ts2phc[34.200]: adding tstamp 29.000000000 to clock /dev/ptp1 ts2phc[34.200]: /dev/ptp3 offset 8 s2 freq +4461 ts2phc[34.704]: /dev/ptp3 SKIP extts index 0 at 29.449823816 src 29.737416038 ts2phc[35.208]: adding tstamp 29.949819152 to clock /dev/ptp3 ts2phc[35.208]: adding tstamp 30.000000000 to clock /dev/ptp1 ts2phc[35.208]: /dev/ptp3 offset -8 s2 freq +4447 ts2phc[35.712]: /dev/ptp3 SKIP extts index 0 at 30.449814496 src 30.745554982 ts2phc[36.216]: adding tstamp 30.949809840 to clock /dev/ptp3 ts2phc[36.216]: adding tstamp 31.000000000 to clock /dev/ptp1 ts2phc[36.216]: /dev/ptp3 offset -8 s2 freq +4445 ts2phc[36.468]: /dev/ptp3 SKIP extts index 0 at 31.449805184 src 31.501109446 ts2phc[36.972]: adding tstamp 31.949800536 to clock /dev/ptp3 ts2phc[36.972]: adding tstamp 32.000000000 to clock /dev/ptp1 ts2phc[36.972]: /dev/ptp3 offset -8 s2 freq +4442 ts2phc[37.480]: /dev/ptp3 SKIP extts index 0 at 32.449795896 src 32.513320070 ts2phc[37.984]: adding tstamp 32.949791248 to clock /dev/ptp3 ts2phc[37.984]: adding tstamp 33.000000000 to clock /dev/ptp1 ts2phc[37.984]: /dev/ptp3 offset 0 s2 freq +4448 Fix that by taking the following measures: - Schedule the poll from a timer. Because we are really scheduling the timer periodically, the extts events delivered to user space are periodic too, and don't suffer from the "shift-to-the-right" effect. - Increase the poll period to 6 times a second. This imposes a smaller upper bound to the shift that can occur to the delivery time of extts events, and makes user space (ts2phc) to always interpret correctly which events should be skipped and which shouldn't. - Move the SPI readout itself to the main PTP kernel thread, instead of the generic workqueue. This is because the timer runs in atomic context, but is also better than before, because if needed, we can chrt & taskset this kernel thread, to ensure it gets enough priority under load. After this patch, one can notice that the wander is greatly reduced, and that the latencies of one extts poll are not propagated to the next. The 'src' timestamp that is skipped is never larger than .65 seconds (which means .15 seconds larger than the time at which the real event occurred at, and .10 seconds smaller than the .75 upper threshold for ignoring the falling edge): ts2phc[40.076]: adding tstamp 34.949261296 to clock /dev/ptp3 ts2phc[40.076]: adding tstamp 35.000000000 to clock /dev/ptp1 ts2phc[40.076]: /dev/ptp3 offset 48 s2 freq +4631 ts2phc[40.568]: /dev/ptp3 SKIP extts index 0 at 35.449256496 src 35.595791078 ts2phc[41.064]: adding tstamp 35.949251744 to clock /dev/ptp3 ts2phc[41.064]: adding tstamp 36.000000000 to clock /dev/ptp1 ts2phc[41.064]: /dev/ptp3 offset -224 s2 freq +4374 ts2phc[41.552]: /dev/ptp3 SKIP extts index 0 at 36.449247088 src 36.579825574 ts2phc[42.044]: adding tstamp 36.949242456 to clock /dev/ptp3 ts2phc[42.044]: adding tstamp 37.000000000 to clock /dev/ptp1 ts2phc[42.044]: /dev/ptp3 offset -240 s2 freq +4290 ts2phc[42.536]: /dev/ptp3 SKIP extts index 0 at 37.449237848 src 37.563828774 ts2phc[43.028]: adding tstamp 37.949233264 to clock /dev/ptp3 ts2phc[43.028]: adding tstamp 38.000000000 to clock /dev/ptp1 ts2phc[43.028]: /dev/ptp3 offset -144 s2 freq +4314 ts2phc[43.520]: /dev/ptp3 SKIP extts index 0 at 38.449228656 src 38.547823238 ts2phc[44.012]: adding tstamp 38.949224048 to clock /dev/ptp3 ts2phc[44.012]: adding tstamp 39.000000000 to clock /dev/ptp1 ts2phc[44.012]: /dev/ptp3 offset -80 s2 freq +4335 ts2phc[44.508]: /dev/ptp3 SKIP extts index 0 at 39.449219432 src 39.535846118 ts2phc[44.996]: adding tstamp 39.949214816 to clock /dev/ptp3 ts2phc[44.996]: adding tstamp 40.000000000 to clock /dev/ptp1 ts2phc[44.996]: /dev/ptp3 offset -32 s2 freq +4359 ts2phc[45.488]: /dev/ptp3 SKIP extts index 0 at 40.449210192 src 40.515824678 ts2phc[45.980]: adding tstamp 40.949205568 to clock /dev/ptp3 ts2phc[45.980]: adding tstamp 41.000000000 to clock /dev/ptp1 ts2phc[45.980]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[46.636]: /dev/ptp3 SKIP extts index 0 at 41.449200928 src 41.664176902 ts2phc[47.132]: adding tstamp 41.949196288 to clock /dev/ptp3 ts2phc[47.132]: adding tstamp 42.000000000 to clock /dev/ptp1 ts2phc[47.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[47.620]: /dev/ptp3 SKIP extts index 0 at 42.449191656 src 42.648117190 ts2phc[48.112]: adding tstamp 42.949187016 to clock /dev/ptp3 ts2phc[48.112]: adding tstamp 43.000000000 to clock /dev/ptp1 ts2phc[48.112]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[48.604]: /dev/ptp3 SKIP extts index 0 at 43.449182384 src 43.632112582 ts2phc[49.100]: adding tstamp 43.949177736 to clock /dev/ptp3 ts2phc[49.100]: adding tstamp 44.000000000 to clock /dev/ptp1 ts2phc[49.100]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[49.588]: /dev/ptp3 SKIP extts index 0 at 44.449173096 src 44.616136774 ts2phc[50.080]: adding tstamp 44.949168464 to clock /dev/ptp3 ts2phc[50.080]: adding tstamp 45.000000000 to clock /dev/ptp1 ts2phc[50.080]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[50.572]: /dev/ptp3 SKIP extts index 0 at 45.449163816 src 45.600134662 ts2phc[51.064]: adding tstamp 45.949159160 to clock /dev/ptp3 ts2phc[51.064]: adding tstamp 46.000000000 to clock /dev/ptp1 ts2phc[51.064]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[51.556]: /dev/ptp3 SKIP extts index 0 at 46.449154528 src 46.584588550 ts2phc[52.048]: adding tstamp 46.949149896 to clock /dev/ptp3 ts2phc[52.048]: adding tstamp 47.000000000 to clock /dev/ptp1 ts2phc[52.048]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[52.540]: /dev/ptp3 SKIP extts index 0 at 47.449145256 src 47.568132198 ts2phc[53.032]: adding tstamp 47.949140616 to clock /dev/ptp3 ts2phc[53.032]: adding tstamp 48.000000000 to clock /dev/ptp1 ts2phc[53.032]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[53.524]: /dev/ptp3 SKIP extts index 0 at 48.449135968 src 48.552121446 ts2phc[54.016]: adding tstamp 48.949131320 to clock /dev/ptp3 ts2phc[54.016]: adding tstamp 49.000000000 to clock /dev/ptp1 ts2phc[54.016]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[54.512]: /dev/ptp3 SKIP extts index 0 at 49.449126680 src 49.540147014 ts2phc[55.000]: adding tstamp 49.949122040 to clock /dev/ptp3 ts2phc[55.000]: adding tstamp 50.000000000 to clock /dev/ptp1 ts2phc[55.000]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[55.492]: /dev/ptp3 SKIP extts index 0 at 50.449117400 src 50.520119078 ts2phc[55.988]: adding tstamp 50.949112768 to clock /dev/ptp3 ts2phc[55.988]: adding tstamp 51.000000000 to clock /dev/ptp1 ts2phc[55.988]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[56.476]: /dev/ptp3 SKIP extts index 0 at 51.449108120 src 51.504175910 ts2phc[57.132]: adding tstamp 51.949103480 to clock /dev/ptp3 ts2phc[57.132]: adding tstamp 52.000000000 to clock /dev/ptp1 ts2phc[57.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[57.624]: /dev/ptp3 SKIP extts index 0 at 52.449098840 src 52.651833574 ts2phc[58.116]: adding tstamp 52.949094200 to clock /dev/ptp3 ts2phc[58.116]: adding tstamp 53.000000000 to clock /dev/ptp1 ts2phc[58.116]: /dev/ptp3 offset 8 s2 freq +4392 ts2phc[58.612]: /dev/ptp3 SKIP extts index 0 at 53.449089560 src 53.639826918 ts2phc[59.100]: adding tstamp 53.949084920 to clock /dev/ptp3 ts2phc[59.100]: adding tstamp 54.000000000 to clock /dev/ptp1 ts2phc[59.100]: /dev/ptp3 offset 8 s2 freq +4394 ts2phc[59.592]: /dev/ptp3 SKIP extts index 0 at 54.449080272 src 54.619842278 ts2phc[60.084]: adding tstamp 54.949075624 to clock /dev/ptp3 ts2phc[60.084]: adding tstamp 55.000000000 to clock /dev/ptp1 ts2phc[60.084]: /dev/ptp3 offset 8 s2 freq +4397 ts2phc[60.576]: /dev/ptp3 SKIP extts index 0 at 55.449070968 src 55.603885542 ts2phc[61.068]: adding tstamp 55.949066312 to clock /dev/ptp3 ts2phc[61.068]: adding tstamp 56.000000000 to clock /dev/ptp1 ts2phc[61.068]: /dev/ptp3 offset 0 s2 freq +4391 ts2phc[61.560]: /dev/ptp3 SKIP extts index 0 at 56.449061680 src 56.587885798 ts2phc[62.052]: adding tstamp 56.949057032 to clock /dev/ptp3 ts2phc[62.052]: adding tstamp 57.000000000 to clock /dev/ptp1 ts2phc[62.052]: /dev/ptp3 offset -8 s2 freq +4383 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-03 20:51:58 +03:00
sja1105_ptp_extts_setup_timer(&priv->ptp_data);
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
else
timer_delete_sync(&priv->ptp_data.extts_timer);
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
return 0;
}
static int sja1105_ptp_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *req, int on)
{
struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp);
struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data);
int rc = -EOPNOTSUPP;
if (req->type == PTP_CLK_REQ_PEROUT)
rc = sja1105_per_out_enable(priv, &req->perout, on);
else if (req->type == PTP_CLK_REQ_EXTTS)
rc = sja1105_extts_enable(priv, &req->extts, on);
return rc;
}
static int sja1105_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin,
enum ptp_pin_function func, unsigned int chan)
{
struct sja1105_ptp_data *ptp_data = ptp_caps_to_data(ptp);
struct sja1105_private *priv = ptp_data_to_sja1105(ptp_data);
if (chan != 0 || pin != 0)
return -1;
switch (func) {
case PTP_PF_NONE:
case PTP_PF_PEROUT:
break;
case PTP_PF_EXTTS:
if (priv->info->device_id == SJA1105E_DEVICE_ID ||
priv->info->device_id == SJA1105T_DEVICE_ID)
return -1;
break;
default:
return -1;
}
return 0;
}
static struct ptp_pin_desc sja1105_ptp_pin = {
.name = "ptp_clk",
.index = 0,
.func = PTP_PF_NONE,
};
int sja1105_ptp_clock_register(struct dsa_switch *ds)
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
{
struct sja1105_private *priv = ds->priv;
struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
ptp_data->caps = (struct ptp_clock_info) {
.owner = THIS_MODULE,
.name = "SJA1105 PHC",
.adjfine = sja1105_ptp_adjfine,
.adjtime = sja1105_ptp_adjtime,
net: dsa: sja1105: Implement the .gettimex64 system call for PTP Through the PTP_SYS_OFFSET_EXTENDED ioctl, it is possible for userspace applications (i.e. phc2sys) to compensate for the delays incurred while reading the PHC's time. The task itself of taking the software timestamp is delegated to the SPI subsystem, through the newly introduced API in struct spi_transfer. The goal is to cross-timestamp I/O operations on the switch's PTP clock with values in the local system clock (CLOCK_REALTIME). For that we need to understand a bit of the hardware internals. The 'read PTP time' message is a 12 byte structure, first 4 bytes of which represent the SPI header, and the last 8 bytes represent the 64-bit PTP time. The switch itself starts processing the command immediately after receiving the last bit of the address, i.e. at the middle of byte 3 (last byte of header). The PTP time is shadowed to a buffer register in the switch, and retrieved atomically during the subsequent SPI frames. A similar thing goes on for the 'write PTP time' message, although in that case the switch waits until the 64-bit PTP time becomes fully available before taking any action. So the byte that needs to be software-timestamped is byte 11 (last) of the transfer. The patch creates a common (and local) sja1105_xfer implementation for the SPI I/O, and offers 3 front-ends: - sja1105_xfer_u32 and sja1105_xfer_u64: these are capable of optionally requesting a PTP timestamp - sja1105_xfer_buf: this is for large transfers (e.g. the static config buffer) and other misc data, and there is no point in giving timestamping capabilities to this. Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-11-09 13:32:22 +02:00
.gettimex64 = sja1105_ptp_gettimex,
.settime64 = sja1105_ptp_settime,
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
.enable = sja1105_ptp_enable,
.verify = sja1105_ptp_verify_pin,
.do_aux_work = sja1105_rxtstamp_work,
.max_adj = SJA1105_MAX_ADJ_PPB,
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
.pin_config = &sja1105_ptp_pin,
.n_pins = 1,
.n_ext_ts = 1,
.n_per_out = 1,
net: ptp: introduce .supported_extts_flags to ptp_clock_info The PTP_EXTTS_REQUEST(2) ioctl has a flags field which specifies how the external timestamp request should behave. This includes which edge of the signal to timestamp, as well as a specialized "offset" mode. It is expected that more flags will be added in the future. Driver authors routinely do not check the flags, often accepting requests with flags which they do not support. Even drivers which do check flags may not be future-proofed to reject flags not yet defined. Thus, any future flag additions often require manually updating drivers to reject these flags. This approach of hoping we catch flag checks during review, or playing whack-a-mole after the fact is the wrong approach. Introduce the "supported_extts_flags" field to the ptp_clock_info structure. This field defines the set of flags the device actually supports. Update the core character device logic to check this field and reject unsupported requests. Getting this right is somewhat tricky. First, to avoid unnecessary repetition and make basic functionality work when .supported_extts_flags is 0, the core always accepts the PTP_ENABLE_FEATURE flag. This flag is used to set the 'on' parameter to the .enable function and is thus always 'supported' by all drivers. For backwards compatibility, the PTP_RISING_EDGE and PTP_FALLING_EDGE flags are merely "hints" when using the old PTP_EXTTS_REQUEST ioctl, and are not expected to be enforced. If the user issues PTP_EXTTS_REQUEST2, the PTP_STRICT_FLAGS flag is added which is supposed to inform the driver to strictly validate the flags and reject unsupported requests. To handle this, first check if the driver reports PTP_STRICT_FLAGS support. If it does not, then always allow the PTP_RISING_EDGE and PTP_FALLING_EDGE flags. This keeps backwards compatibility with the original PTP_EXTTS_REQUEST ioctl where these flags are not guaranteed to be honored. This way, drivers which do not set the supported_extts_flags will continue to accept requests for the original PTP_EXTTS_REQUEST ioctl. The core will automatically reject requests with new flags, and correctly reject requests with PTP_STRICT_FLAGS, where the driver is supposed to strictly validate the flags. Update the various drivers, refactoring their validation logic into the .supported_extts_flags field. For consistency and readability, PTP_ENABLE_FEATURE is not set in the supported flags list, and PTP_EXTTS_EDGES is expanded to PTP_RISING_EDGE | PTP_FALLING_EDGE in all cases. Note the following driver files set n_ext_ts to a non-zero value but did not check flags at all: • drivers/net/ethernet/freescale/dpaa2/dpaa2-ptp.c • drivers/net/ethernet/freescale/enetc/enetc_ptp.c • drivers/net/ethernet/intel/i40e/i40e_ptp.c • drivers/net/ethernet/marvell/octeontx2/nic/otx2_ptp.c • drivers/net/ethernet/renesas/ravb_ptp.c • drivers/net/ethernet/renesas/rtsn.c • drivers/net/ethernet/renesas/rtsn.h • drivers/net/ethernet/ti/am65-cpts.c • drivers/net/ethernet/ti/cpts.h • drivers/net/ethernet/ti/icssg/icss_iep.c • drivers/net/ethernet/xscale/ptp_ixp46x.c • drivers/net/phy/bcm-phy-ptp.c • drivers/ptp/ptp_ocp.c • drivers/ptp/ptp_pch.c • drivers/ptp/ptp_qoriq.c These drivers behavior does change slightly: they will now reject the PTP_EXTTS_REQUEST2 ioctl, because they do not strictly validate their flags. This also makes them no longer incorrectly accept PTP_EXT_OFFSET. Also note that the renesas ravb driver does not support PTP_STRICT_FLAGS. We could leave the .supported_extts_flags as 0, but I added the PTP_RISING_EDGE | PTP_FALLING_EDGE since the driver previously manually validated these flags. This is equivalent to 0 because the core will allow these flags regardless unless PTP_STRICT_FLAGS is also set. Signed-off-by: Jacob Keller <jacob.e.keller@intel.com> Reviewed-by: Kory Maincent <kory.maincent@bootlin.com> Link: https://patch.msgid.link/20250414-jk-supported-perout-flags-v2-1-f6b17d15475c@intel.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
2025-04-14 14:26:30 -07:00
.supported_extts_flags = PTP_RISING_EDGE |
PTP_FALLING_EDGE |
PTP_STRICT_FLAGS,
};
net: dsa: sja1105: implement TX timestamping for SJA1110 The TX timestamping procedure for SJA1105 is a bit unconventional because the transmit procedure itself is unconventional. Control packets (and therefore PTP as well) are transmitted to a specific port in SJA1105 using "management routes" which must be written over SPI to the switch. These are one-shot rules that match by destination MAC address on traffic coming from the CPU port, and select the precise destination port for that packet. So to transmit a packet from NET_TX softirq context, we actually need to defer to a process context so that we can perform that SPI write before we send the packet. The DSA master dev_queue_xmit() runs in process context, and we poll until the switch confirms it took the TX timestamp, then we annotate the skb clone with that TX timestamp. This is why the sja1105 driver does not need an skb queue for TX timestamping. But the SJA1110 is a bit (not much!) more conventional, and you can request 2-step TX timestamping through the DSA header, as well as give the switch a cookie (timestamp ID) which it will give back to you when it has the timestamp. So now we do need a queue for keeping the skb clones until their TX timestamps become available. The interesting part is that the metadata frames from SJA1105 haven't disappeared completely. On SJA1105 they were used as follow-ups which contained RX timestamps, but on SJA1110 they are actually TX completion packets, which contain a variable (up to 32) array of timestamps. Why an array? Because: - not only is the TX timestamp on the egress port being communicated, but also the RX timestamp on the CPU port. Nice, but we don't care about that, so we ignore it. - because a packet could be multicast to multiple egress ports, each port takes its own timestamp, and the TX completion packet contains the individual timestamps on each port. This is unconventional because switches typically have a timestamping FIFO and raise an interrupt, but this one doesn't. So the tagger needs to detect and parse meta frames, and call into the main switch driver, which pairs the timestamps with the skbs in the TX timestamping queue which are waiting for one. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2021-06-11 22:01:31 +03:00
/* Only used on SJA1105 */
skb_queue_head_init(&ptp_data->skb_rxtstamp_queue);
/* Only used on SJA1110 */
skb_queue_head_init(&ptp_data->skb_txtstamp_queue);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
ptp_data->clock = ptp_clock_register(&ptp_data->caps, ds->dev);
if (IS_ERR_OR_NULL(ptp_data->clock))
return PTR_ERR(ptp_data->clock);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
ptp_data->cmd.corrclk4ts = true;
ptp_data->cmd.ptpclkadd = PTP_SET_MODE;
net: dsa: sja1105: poll for extts events from a timer The current poll interval is enough to ensure that rising and falling edge events are not lost for a 1 PPS signal with 50% duty cycle. But when we deliver the events to user space, it will try to infer if they were corresponding to a rising or to a falling edge (the kernel driver doesn't know that either). User space will try to make that inference based on the time at which the PPS master had emitted the pulse (i.e. if it's a .0 time, it's rising edge, if it's .5 time, it's falling edge). But there is no in-kernel API for retrieving the precise timestamp corresponding to a PPS master (aka perout) pulse. So user space has to guess even that. It will read the PTP time on the PPS master right after we've delivered the extts event, and declare that the PPS master time was just the closest integer second, based on 2 thresholds (lower than .25, or higher than .75, and ignore anything else). Except that, if we poll for extts events (and our hardware doesn't really help us, by not providing an interrupt), then there is a risk that the poll period (and therefore the time at which the event is delivered) might confuse user space. Because we are always scheduling the next extts poll at SJA1105_EXTTS_INTERVAL "from now" (that's the only thing that the schedule_delayed_work() API gives us), it means that the start time of the next delayed workqueue will always be shifted to the right a little bit (shifted with the SPI access duration of this workqueue run). In turn, because user space sees extts events that are non-periodic compared to the PPS master's time, this means that it might start making wrong guesses about rising/falling edge. To understand the effect, here is the output of ts2phc currently. Notice the 'src' timestamps of the 'SKIP extts' events, and how they have a large wander. They keep increasing until the upper limit for the ignore threshold (.75 seconds), after which the application starts ignoring the _other_ edge. ts2phc[26.624]: /dev/ptp3 SKIP extts index 0 at 21.449898912 src 21.657784518 ts2phc[27.133]: adding tstamp 21.949894240 to clock /dev/ptp3 ts2phc[27.133]: adding tstamp 22.000000000 to clock /dev/ptp1 ts2phc[27.133]: /dev/ptp3 offset 640 s2 freq +5112 ts2phc[27.636]: /dev/ptp3 SKIP extts index 0 at 22.449889360 src 22.669398022 ts2phc[28.140]: adding tstamp 22.949884376 to clock /dev/ptp3 ts2phc[28.140]: adding tstamp 23.000000000 to clock /dev/ptp1 ts2phc[28.140]: /dev/ptp3 offset 96 s2 freq +4760 ts2phc[28.644]: /dev/ptp3 SKIP extts index 0 at 23.449879504 src 23.677420422 ts2phc[29.153]: adding tstamp 23.949874704 to clock /dev/ptp3 ts2phc[29.153]: adding tstamp 24.000000000 to clock /dev/ptp1 ts2phc[29.153]: /dev/ptp3 offset -264 s2 freq +4429 ts2phc[29.656]: /dev/ptp3 SKIP extts index 0 at 24.449870008 src 24.689407238 ts2phc[30.160]: adding tstamp 24.949865376 to clock /dev/ptp3 ts2phc[30.160]: adding tstamp 25.000000000 to clock /dev/ptp1 ts2phc[30.160]: /dev/ptp3 offset -280 s2 freq +4334 ts2phc[30.664]: /dev/ptp3 SKIP extts index 0 at 25.449860760 src 25.697449926 ts2phc[31.168]: adding tstamp 25.949856176 to clock /dev/ptp3 ts2phc[31.168]: adding tstamp 26.000000000 to clock /dev/ptp1 ts2phc[31.168]: /dev/ptp3 offset -176 s2 freq +4354 ts2phc[31.672]: /dev/ptp3 SKIP extts index 0 at 26.449851584 src 26.705433606 ts2phc[32.180]: adding tstamp 26.949846992 to clock /dev/ptp3 ts2phc[32.180]: adding tstamp 27.000000000 to clock /dev/ptp1 ts2phc[32.180]: /dev/ptp3 offset -80 s2 freq +4397 ts2phc[32.684]: /dev/ptp3 SKIP extts index 0 at 27.449842384 src 27.717415110 ts2phc[33.192]: adding tstamp 27.949837768 to clock /dev/ptp3 ts2phc[33.192]: adding tstamp 28.000000000 to clock /dev/ptp1 ts2phc[33.192]: /dev/ptp3 offset 0 s2 freq +4453 ts2phc[33.696]: /dev/ptp3 SKIP extts index 0 at 28.449833128 src 28.729412902 ts2phc[34.200]: adding tstamp 28.949828472 to clock /dev/ptp3 ts2phc[34.200]: adding tstamp 29.000000000 to clock /dev/ptp1 ts2phc[34.200]: /dev/ptp3 offset 8 s2 freq +4461 ts2phc[34.704]: /dev/ptp3 SKIP extts index 0 at 29.449823816 src 29.737416038 ts2phc[35.208]: adding tstamp 29.949819152 to clock /dev/ptp3 ts2phc[35.208]: adding tstamp 30.000000000 to clock /dev/ptp1 ts2phc[35.208]: /dev/ptp3 offset -8 s2 freq +4447 ts2phc[35.712]: /dev/ptp3 SKIP extts index 0 at 30.449814496 src 30.745554982 ts2phc[36.216]: adding tstamp 30.949809840 to clock /dev/ptp3 ts2phc[36.216]: adding tstamp 31.000000000 to clock /dev/ptp1 ts2phc[36.216]: /dev/ptp3 offset -8 s2 freq +4445 ts2phc[36.468]: /dev/ptp3 SKIP extts index 0 at 31.449805184 src 31.501109446 ts2phc[36.972]: adding tstamp 31.949800536 to clock /dev/ptp3 ts2phc[36.972]: adding tstamp 32.000000000 to clock /dev/ptp1 ts2phc[36.972]: /dev/ptp3 offset -8 s2 freq +4442 ts2phc[37.480]: /dev/ptp3 SKIP extts index 0 at 32.449795896 src 32.513320070 ts2phc[37.984]: adding tstamp 32.949791248 to clock /dev/ptp3 ts2phc[37.984]: adding tstamp 33.000000000 to clock /dev/ptp1 ts2phc[37.984]: /dev/ptp3 offset 0 s2 freq +4448 Fix that by taking the following measures: - Schedule the poll from a timer. Because we are really scheduling the timer periodically, the extts events delivered to user space are periodic too, and don't suffer from the "shift-to-the-right" effect. - Increase the poll period to 6 times a second. This imposes a smaller upper bound to the shift that can occur to the delivery time of extts events, and makes user space (ts2phc) to always interpret correctly which events should be skipped and which shouldn't. - Move the SPI readout itself to the main PTP kernel thread, instead of the generic workqueue. This is because the timer runs in atomic context, but is also better than before, because if needed, we can chrt & taskset this kernel thread, to ensure it gets enough priority under load. After this patch, one can notice that the wander is greatly reduced, and that the latencies of one extts poll are not propagated to the next. The 'src' timestamp that is skipped is never larger than .65 seconds (which means .15 seconds larger than the time at which the real event occurred at, and .10 seconds smaller than the .75 upper threshold for ignoring the falling edge): ts2phc[40.076]: adding tstamp 34.949261296 to clock /dev/ptp3 ts2phc[40.076]: adding tstamp 35.000000000 to clock /dev/ptp1 ts2phc[40.076]: /dev/ptp3 offset 48 s2 freq +4631 ts2phc[40.568]: /dev/ptp3 SKIP extts index 0 at 35.449256496 src 35.595791078 ts2phc[41.064]: adding tstamp 35.949251744 to clock /dev/ptp3 ts2phc[41.064]: adding tstamp 36.000000000 to clock /dev/ptp1 ts2phc[41.064]: /dev/ptp3 offset -224 s2 freq +4374 ts2phc[41.552]: /dev/ptp3 SKIP extts index 0 at 36.449247088 src 36.579825574 ts2phc[42.044]: adding tstamp 36.949242456 to clock /dev/ptp3 ts2phc[42.044]: adding tstamp 37.000000000 to clock /dev/ptp1 ts2phc[42.044]: /dev/ptp3 offset -240 s2 freq +4290 ts2phc[42.536]: /dev/ptp3 SKIP extts index 0 at 37.449237848 src 37.563828774 ts2phc[43.028]: adding tstamp 37.949233264 to clock /dev/ptp3 ts2phc[43.028]: adding tstamp 38.000000000 to clock /dev/ptp1 ts2phc[43.028]: /dev/ptp3 offset -144 s2 freq +4314 ts2phc[43.520]: /dev/ptp3 SKIP extts index 0 at 38.449228656 src 38.547823238 ts2phc[44.012]: adding tstamp 38.949224048 to clock /dev/ptp3 ts2phc[44.012]: adding tstamp 39.000000000 to clock /dev/ptp1 ts2phc[44.012]: /dev/ptp3 offset -80 s2 freq +4335 ts2phc[44.508]: /dev/ptp3 SKIP extts index 0 at 39.449219432 src 39.535846118 ts2phc[44.996]: adding tstamp 39.949214816 to clock /dev/ptp3 ts2phc[44.996]: adding tstamp 40.000000000 to clock /dev/ptp1 ts2phc[44.996]: /dev/ptp3 offset -32 s2 freq +4359 ts2phc[45.488]: /dev/ptp3 SKIP extts index 0 at 40.449210192 src 40.515824678 ts2phc[45.980]: adding tstamp 40.949205568 to clock /dev/ptp3 ts2phc[45.980]: adding tstamp 41.000000000 to clock /dev/ptp1 ts2phc[45.980]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[46.636]: /dev/ptp3 SKIP extts index 0 at 41.449200928 src 41.664176902 ts2phc[47.132]: adding tstamp 41.949196288 to clock /dev/ptp3 ts2phc[47.132]: adding tstamp 42.000000000 to clock /dev/ptp1 ts2phc[47.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[47.620]: /dev/ptp3 SKIP extts index 0 at 42.449191656 src 42.648117190 ts2phc[48.112]: adding tstamp 42.949187016 to clock /dev/ptp3 ts2phc[48.112]: adding tstamp 43.000000000 to clock /dev/ptp1 ts2phc[48.112]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[48.604]: /dev/ptp3 SKIP extts index 0 at 43.449182384 src 43.632112582 ts2phc[49.100]: adding tstamp 43.949177736 to clock /dev/ptp3 ts2phc[49.100]: adding tstamp 44.000000000 to clock /dev/ptp1 ts2phc[49.100]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[49.588]: /dev/ptp3 SKIP extts index 0 at 44.449173096 src 44.616136774 ts2phc[50.080]: adding tstamp 44.949168464 to clock /dev/ptp3 ts2phc[50.080]: adding tstamp 45.000000000 to clock /dev/ptp1 ts2phc[50.080]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[50.572]: /dev/ptp3 SKIP extts index 0 at 45.449163816 src 45.600134662 ts2phc[51.064]: adding tstamp 45.949159160 to clock /dev/ptp3 ts2phc[51.064]: adding tstamp 46.000000000 to clock /dev/ptp1 ts2phc[51.064]: /dev/ptp3 offset -8 s2 freq +4376 ts2phc[51.556]: /dev/ptp3 SKIP extts index 0 at 46.449154528 src 46.584588550 ts2phc[52.048]: adding tstamp 46.949149896 to clock /dev/ptp3 ts2phc[52.048]: adding tstamp 47.000000000 to clock /dev/ptp1 ts2phc[52.048]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[52.540]: /dev/ptp3 SKIP extts index 0 at 47.449145256 src 47.568132198 ts2phc[53.032]: adding tstamp 47.949140616 to clock /dev/ptp3 ts2phc[53.032]: adding tstamp 48.000000000 to clock /dev/ptp1 ts2phc[53.032]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[53.524]: /dev/ptp3 SKIP extts index 0 at 48.449135968 src 48.552121446 ts2phc[54.016]: adding tstamp 48.949131320 to clock /dev/ptp3 ts2phc[54.016]: adding tstamp 49.000000000 to clock /dev/ptp1 ts2phc[54.016]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[54.512]: /dev/ptp3 SKIP extts index 0 at 49.449126680 src 49.540147014 ts2phc[55.000]: adding tstamp 49.949122040 to clock /dev/ptp3 ts2phc[55.000]: adding tstamp 50.000000000 to clock /dev/ptp1 ts2phc[55.000]: /dev/ptp3 offset 0 s2 freq +4382 ts2phc[55.492]: /dev/ptp3 SKIP extts index 0 at 50.449117400 src 50.520119078 ts2phc[55.988]: adding tstamp 50.949112768 to clock /dev/ptp3 ts2phc[55.988]: adding tstamp 51.000000000 to clock /dev/ptp1 ts2phc[55.988]: /dev/ptp3 offset 8 s2 freq +4390 ts2phc[56.476]: /dev/ptp3 SKIP extts index 0 at 51.449108120 src 51.504175910 ts2phc[57.132]: adding tstamp 51.949103480 to clock /dev/ptp3 ts2phc[57.132]: adding tstamp 52.000000000 to clock /dev/ptp1 ts2phc[57.132]: /dev/ptp3 offset 0 s2 freq +4384 ts2phc[57.624]: /dev/ptp3 SKIP extts index 0 at 52.449098840 src 52.651833574 ts2phc[58.116]: adding tstamp 52.949094200 to clock /dev/ptp3 ts2phc[58.116]: adding tstamp 53.000000000 to clock /dev/ptp1 ts2phc[58.116]: /dev/ptp3 offset 8 s2 freq +4392 ts2phc[58.612]: /dev/ptp3 SKIP extts index 0 at 53.449089560 src 53.639826918 ts2phc[59.100]: adding tstamp 53.949084920 to clock /dev/ptp3 ts2phc[59.100]: adding tstamp 54.000000000 to clock /dev/ptp1 ts2phc[59.100]: /dev/ptp3 offset 8 s2 freq +4394 ts2phc[59.592]: /dev/ptp3 SKIP extts index 0 at 54.449080272 src 54.619842278 ts2phc[60.084]: adding tstamp 54.949075624 to clock /dev/ptp3 ts2phc[60.084]: adding tstamp 55.000000000 to clock /dev/ptp1 ts2phc[60.084]: /dev/ptp3 offset 8 s2 freq +4397 ts2phc[60.576]: /dev/ptp3 SKIP extts index 0 at 55.449070968 src 55.603885542 ts2phc[61.068]: adding tstamp 55.949066312 to clock /dev/ptp3 ts2phc[61.068]: adding tstamp 56.000000000 to clock /dev/ptp1 ts2phc[61.068]: /dev/ptp3 offset 0 s2 freq +4391 ts2phc[61.560]: /dev/ptp3 SKIP extts index 0 at 56.449061680 src 56.587885798 ts2phc[62.052]: adding tstamp 56.949057032 to clock /dev/ptp3 ts2phc[62.052]: adding tstamp 57.000000000 to clock /dev/ptp1 ts2phc[62.052]: /dev/ptp3 offset -8 s2 freq +4383 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-08-03 20:51:58 +03:00
timer_setup(&ptp_data->extts_timer, sja1105_ptp_extts_timer, 0);
net: dsa: sja1105: configure the PTP_CLK pin as EXT_TS or PER_OUT The SJA1105 switch family has a PTP_CLK pin which emits a signal with fixed 50% duty cycle, but variable frequency and programmable start time. On the second generation (P/Q/R/S) switches, this pin supports even more functionality. The use case described by the hardware documents talks about synchronization via oneshot pulses: given 2 sja1105 switches, arbitrarily designated as a master and a slave, the master emits a single pulse on PTP_CLK, while the slave is configured to timestamp this pulse received on its PTP_CLK pin (which must obviously be configured as input). The difference between the timestamps then exactly becomes the slave offset to the master. The only trouble with the above is that the hardware is very much tied into this use case only, and not very generic beyond that: - When emitting a oneshot pulse, instead of being told when to emit it, the switch just does it "now" and tells you later what time it was, via the PTPSYNCTS register. [ Incidentally, this is the same register that the slave uses to collect the ext_ts timestamp from, too. ] - On the sync slave, there is no interrupt mechanism on reception of a new extts, and no FIFO to buffer them, because in the foreseen use case, software is in control of both the master and the slave pins, so it "knows" when there's something to collect. These 2 problems mean that: - We don't support (at least yet) the quirky oneshot mode exposed by the hardware, just normal periodic output. - We abuse the hardware a little bit when we expose generic extts. Because there's no interrupt mechanism, we need to poll at double the frequency we expect to receive a pulse. Currently that means a non-configurable "twice a second". Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-03-24 00:59:24 +02:00
return sja1105_ptp_reset(ds);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
}
void sja1105_ptp_clock_unregister(struct dsa_switch *ds)
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
{
struct sja1105_private *priv = ds->priv;
struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
if (IS_ERR_OR_NULL(ptp_data->clock))
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
return;
timer_delete_sync(&ptp_data->extts_timer);
ptp_cancel_worker_sync(ptp_data->clock);
skb_queue_purge(&ptp_data->skb_txtstamp_queue);
skb_queue_purge(&ptp_data->skb_rxtstamp_queue);
ptp_clock_unregister(ptp_data->clock);
ptp_data->clock = NULL;
}
void sja1105_ptp_txtstamp_skb(struct dsa_switch *ds, int port,
struct sk_buff *skb)
{
struct sja1105_private *priv = ds->priv;
struct sja1105_ptp_data *ptp_data = &priv->ptp_data;
struct skb_shared_hwtstamps shwt = {0};
u64 ticks, ts;
int rc;
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
mutex_lock(&ptp_data->lock);
net: dsa: sja1105: fix PTP timestamping with large tc-taprio cycles It isn't actually described clearly at all in UM10944.pdf, but on TX of a management frame (such as PTP), this needs to happen: - The destination MAC address (i.e. 01-80-c2-00-00-0e), along with the desired destination port, need to be installed in one of the 4 management slots of the switch, over SPI. - The host can poll over SPI for that management slot's ENFPORT field. That gets unset when the switch has matched the slot to the frame. And therein lies the problem. ENFPORT does not mean that the packet has been transmitted. Just that it has been received over the CPU port, and that the mgmt slot is yet again available. This is relevant because of what we are doing in sja1105_ptp_txtstamp_skb, which is called right after sja1105_mgmt_xmit. We are in a hard real-time deadline, since the hardware only gives us 24 bits of TX timestamp, so we need to read the full PTP clock to reconstruct it. Because we're in a hurry (in an attempt to make sure that we have a full 64-bit PTP time which is as close as possible to the actual transmission time of the frame, to avoid 24-bit wraparounds), first we read the PTP clock, then we poll for the TX timestamp to become available. But of course, we don't know for sure that the frame has been transmitted when we read the full PTP clock. We had assumed that ENFPORT means it has, but the assumption is incorrect. And while in most real-life scenarios this has never been caught due to software delays, nowhere is this fact more obvious than with a tc-taprio offload, where PTP traffic gets a small timeslot very rarely (example: 1 packet per 10 ms). In that case, we will be reading the PTP clock for timestamp reconstruction too early (before the packet has been transmitted), and this renders the reconstruction procedure incorrect (see the assumptions described in the comments found on function sja1105_tstamp_reconstruct). So the PTP TX timestamps will be off by 1<<24 clock ticks, or 135 ms (1 tick is 8 ns). So fix this case of premature optimization by simply reordering the sja1105_ptpegr_ts_poll and the sja1105_ptpclkval_read function calls. It turns out that in practice, the 135 ms hard deadline for PTP timestamp wraparound is not so hard, since even the most bandwidth-intensive PTP profiles, such as 802.1AS-2011, have a sync frame interval of 125 ms. So if we couldn't deliver a timestamp in 135 ms (which we can), we're toast and have much bigger problems anyway. Fixes: 47ed985e97f5 ("net: dsa: sja1105: Add logic for TX timestamping") Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-06-14 23:54:09 +03:00
rc = sja1105_ptpegr_ts_poll(ds, port, &ts);
if (rc < 0) {
net: dsa: sja1105: fix PTP timestamping with large tc-taprio cycles It isn't actually described clearly at all in UM10944.pdf, but on TX of a management frame (such as PTP), this needs to happen: - The destination MAC address (i.e. 01-80-c2-00-00-0e), along with the desired destination port, need to be installed in one of the 4 management slots of the switch, over SPI. - The host can poll over SPI for that management slot's ENFPORT field. That gets unset when the switch has matched the slot to the frame. And therein lies the problem. ENFPORT does not mean that the packet has been transmitted. Just that it has been received over the CPU port, and that the mgmt slot is yet again available. This is relevant because of what we are doing in sja1105_ptp_txtstamp_skb, which is called right after sja1105_mgmt_xmit. We are in a hard real-time deadline, since the hardware only gives us 24 bits of TX timestamp, so we need to read the full PTP clock to reconstruct it. Because we're in a hurry (in an attempt to make sure that we have a full 64-bit PTP time which is as close as possible to the actual transmission time of the frame, to avoid 24-bit wraparounds), first we read the PTP clock, then we poll for the TX timestamp to become available. But of course, we don't know for sure that the frame has been transmitted when we read the full PTP clock. We had assumed that ENFPORT means it has, but the assumption is incorrect. And while in most real-life scenarios this has never been caught due to software delays, nowhere is this fact more obvious than with a tc-taprio offload, where PTP traffic gets a small timeslot very rarely (example: 1 packet per 10 ms). In that case, we will be reading the PTP clock for timestamp reconstruction too early (before the packet has been transmitted), and this renders the reconstruction procedure incorrect (see the assumptions described in the comments found on function sja1105_tstamp_reconstruct). So the PTP TX timestamps will be off by 1<<24 clock ticks, or 135 ms (1 tick is 8 ns). So fix this case of premature optimization by simply reordering the sja1105_ptpegr_ts_poll and the sja1105_ptpclkval_read function calls. It turns out that in practice, the 135 ms hard deadline for PTP timestamp wraparound is not so hard, since even the most bandwidth-intensive PTP profiles, such as 802.1AS-2011, have a sync frame interval of 125 ms. So if we couldn't deliver a timestamp in 135 ms (which we can), we're toast and have much bigger problems anyway. Fixes: 47ed985e97f5 ("net: dsa: sja1105: Add logic for TX timestamping") Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-06-14 23:54:09 +03:00
dev_err(ds->dev, "timed out polling for tstamp\n");
kfree_skb(skb);
goto out;
}
net: dsa: sja1105: fix PTP timestamping with large tc-taprio cycles It isn't actually described clearly at all in UM10944.pdf, but on TX of a management frame (such as PTP), this needs to happen: - The destination MAC address (i.e. 01-80-c2-00-00-0e), along with the desired destination port, need to be installed in one of the 4 management slots of the switch, over SPI. - The host can poll over SPI for that management slot's ENFPORT field. That gets unset when the switch has matched the slot to the frame. And therein lies the problem. ENFPORT does not mean that the packet has been transmitted. Just that it has been received over the CPU port, and that the mgmt slot is yet again available. This is relevant because of what we are doing in sja1105_ptp_txtstamp_skb, which is called right after sja1105_mgmt_xmit. We are in a hard real-time deadline, since the hardware only gives us 24 bits of TX timestamp, so we need to read the full PTP clock to reconstruct it. Because we're in a hurry (in an attempt to make sure that we have a full 64-bit PTP time which is as close as possible to the actual transmission time of the frame, to avoid 24-bit wraparounds), first we read the PTP clock, then we poll for the TX timestamp to become available. But of course, we don't know for sure that the frame has been transmitted when we read the full PTP clock. We had assumed that ENFPORT means it has, but the assumption is incorrect. And while in most real-life scenarios this has never been caught due to software delays, nowhere is this fact more obvious than with a tc-taprio offload, where PTP traffic gets a small timeslot very rarely (example: 1 packet per 10 ms). In that case, we will be reading the PTP clock for timestamp reconstruction too early (before the packet has been transmitted), and this renders the reconstruction procedure incorrect (see the assumptions described in the comments found on function sja1105_tstamp_reconstruct). So the PTP TX timestamps will be off by 1<<24 clock ticks, or 135 ms (1 tick is 8 ns). So fix this case of premature optimization by simply reordering the sja1105_ptpegr_ts_poll and the sja1105_ptpclkval_read function calls. It turns out that in practice, the 135 ms hard deadline for PTP timestamp wraparound is not so hard, since even the most bandwidth-intensive PTP profiles, such as 802.1AS-2011, have a sync frame interval of 125 ms. So if we couldn't deliver a timestamp in 135 ms (which we can), we're toast and have much bigger problems anyway. Fixes: 47ed985e97f5 ("net: dsa: sja1105: Add logic for TX timestamping") Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-06-14 23:54:09 +03:00
rc = sja1105_ptpclkval_read(priv, &ticks, NULL);
if (rc < 0) {
net: dsa: sja1105: fix PTP timestamping with large tc-taprio cycles It isn't actually described clearly at all in UM10944.pdf, but on TX of a management frame (such as PTP), this needs to happen: - The destination MAC address (i.e. 01-80-c2-00-00-0e), along with the desired destination port, need to be installed in one of the 4 management slots of the switch, over SPI. - The host can poll over SPI for that management slot's ENFPORT field. That gets unset when the switch has matched the slot to the frame. And therein lies the problem. ENFPORT does not mean that the packet has been transmitted. Just that it has been received over the CPU port, and that the mgmt slot is yet again available. This is relevant because of what we are doing in sja1105_ptp_txtstamp_skb, which is called right after sja1105_mgmt_xmit. We are in a hard real-time deadline, since the hardware only gives us 24 bits of TX timestamp, so we need to read the full PTP clock to reconstruct it. Because we're in a hurry (in an attempt to make sure that we have a full 64-bit PTP time which is as close as possible to the actual transmission time of the frame, to avoid 24-bit wraparounds), first we read the PTP clock, then we poll for the TX timestamp to become available. But of course, we don't know for sure that the frame has been transmitted when we read the full PTP clock. We had assumed that ENFPORT means it has, but the assumption is incorrect. And while in most real-life scenarios this has never been caught due to software delays, nowhere is this fact more obvious than with a tc-taprio offload, where PTP traffic gets a small timeslot very rarely (example: 1 packet per 10 ms). In that case, we will be reading the PTP clock for timestamp reconstruction too early (before the packet has been transmitted), and this renders the reconstruction procedure incorrect (see the assumptions described in the comments found on function sja1105_tstamp_reconstruct). So the PTP TX timestamps will be off by 1<<24 clock ticks, or 135 ms (1 tick is 8 ns). So fix this case of premature optimization by simply reordering the sja1105_ptpegr_ts_poll and the sja1105_ptpclkval_read function calls. It turns out that in practice, the 135 ms hard deadline for PTP timestamp wraparound is not so hard, since even the most bandwidth-intensive PTP profiles, such as 802.1AS-2011, have a sync frame interval of 125 ms. So if we couldn't deliver a timestamp in 135 ms (which we can), we're toast and have much bigger problems anyway. Fixes: 47ed985e97f5 ("net: dsa: sja1105: Add logic for TX timestamping") Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> Acked-by: Richard Cochran <richardcochran@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2020-06-14 23:54:09 +03:00
dev_err(ds->dev, "Failed to read PTP clock: %d\n", rc);
kfree_skb(skb);
goto out;
}
ts = sja1105_tstamp_reconstruct(ds, ticks, ts);
shwt.hwtstamp = ns_to_ktime(sja1105_ticks_to_ns(ts));
skb_complete_tx_timestamp(skb, &shwt);
out:
mutex_unlock(&ptp_data->lock);
net: dsa: sja1105: Add support for the PTP clock The design of this PHC driver is influenced by the switch's behavior w.r.t. timestamping. It exposes two PTP counters, one free-running (PTPTSCLK) and the other offset- and frequency-corrected in hardware through PTPCLKVAL, PTPCLKADD and PTPCLKRATE. The MACs can sample either of these for frame timestamps. However, the user manual warns that taking timestamps based on the corrected clock is less than useful, as the switch can deliver corrupted timestamps in a variety of circumstances. Therefore, this PHC uses the free-running PTPTSCLK together with a timecounter/cyclecounter structure that translates it into a software time domain. Thus, the settime/adjtime and adjfine callbacks are hardware no-ops. The timestamps (introduced in a further patch) will also be translated to the correct time domain before being handed over to the userspace PTP stack. The introduction of a second set of PHC operations that operate on the hardware PTPCLKVAL/PTPCLKADD/PTPCLKRATE in the future is somewhat unavoidable, as the TTEthernet core uses the corrected PTP time domain. However, the free-running counter + timecounter structure combination will suffice for now, as the resulting timestamps yield a sub-50 ns synchronization offset in steady state using linuxptp. For this patch, in absence of frame timestamping, the operations of the switch PHC were tested by syncing it to the system time as a local slave clock with: phc2sys -s CLOCK_REALTIME -c swp2 -O 0 -m -S 0.01 Signed-off-by: Vladimir Oltean <olteanv@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
2019-06-08 15:04:34 +03:00
}