|
Takashi Iwai |
7a138b |
From ecc7b4187dd388549544195fb13a11b4ea8e6a84 Mon Sep 17 00:00:00 2001
|
|
Takashi Iwai |
7a138b |
From: Stephane Grosjean <s.grosjean@peak-system.com>
|
|
Takashi Iwai |
7a138b |
Date: Wed, 14 Oct 2020 10:56:31 +0200
|
|
Takashi Iwai |
7a138b |
Subject: [PATCH] can: peak_usb: peak_usb_get_ts_time(): fix timestamp wrapping
|
|
Takashi Iwai |
7a138b |
Git-commit: ecc7b4187dd388549544195fb13a11b4ea8e6a84
|
|
Takashi Iwai |
7a138b |
Patch-mainline: v5.10-rc3
|
|
Takashi Iwai |
7a138b |
References: git-fixes
|
|
Takashi Iwai |
7a138b |
|
|
Takashi Iwai |
7a138b |
Fabian Inostroza <fabianinostrozap@gmail.com> has discovered a potential
|
|
Takashi Iwai |
7a138b |
problem in the hardware timestamp reporting from the PCAN-USB USB CAN interface
|
|
Takashi Iwai |
7a138b |
(only), related to the fact that a timestamp of an event may precede the
|
|
Takashi Iwai |
7a138b |
timestamp used for synchronization when both records are part of the same USB
|
|
Takashi Iwai |
7a138b |
packet. However, this case was used to detect the wrapping of the time counter.
|
|
Takashi Iwai |
7a138b |
|
|
Takashi Iwai |
7a138b |
This patch details and fixes the two identified cases where this problem can
|
|
Takashi Iwai |
7a138b |
occur.
|
|
Takashi Iwai |
7a138b |
|
|
Takashi Iwai |
7a138b |
Reported-by: Fabian Inostroza <fabianinostrozap@gmail.com>
|
|
Takashi Iwai |
7a138b |
Signed-off-by: Stephane Grosjean <s.grosjean@peak-system.com>
|
|
Takashi Iwai |
7a138b |
Link: https://lore.kernel.org/r/20201014085631.15128-1-s.grosjean@peak-system.com
|
|
Takashi Iwai |
7a138b |
Fixes: bb4785551f64 ("can: usb: PEAK-System Technik USB adapters driver core")
|
|
Takashi Iwai |
7a138b |
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
|
|
Takashi Iwai |
7a138b |
Acked-by: Takashi Iwai <tiwai@suse.de>
|
|
Takashi Iwai |
7a138b |
|
|
Takashi Iwai |
7a138b |
---
|
|
Takashi Iwai |
7a138b |
drivers/net/can/usb/peak_usb/pcan_usb_core.c | 51 ++++++++++++++++++++++++---
|
|
Takashi Iwai |
7a138b |
1 file changed, 46 insertions(+), 5 deletions(-)
|
|
Takashi Iwai |
7a138b |
|
|
Takashi Iwai |
7a138b |
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
|
|
Takashi Iwai |
7a138b |
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
|
|
Takashi Iwai |
7a138b |
@@ -154,14 +154,55 @@ void peak_usb_get_ts_tv(struct peak_time
|
|
Takashi Iwai |
7a138b |
/* protect from getting timeval before setting now */
|
|
Takashi Iwai |
7a138b |
if (time_ref->tv_host.tv_sec > 0) {
|
|
Takashi Iwai |
7a138b |
u64 delta_us;
|
|
Takashi Iwai |
7a138b |
+ s64 delta_ts = 0;
|
|
Takashi Iwai |
7a138b |
|
|
Takashi Iwai |
7a138b |
- delta_us = ts - time_ref->ts_dev_2;
|
|
Takashi Iwai |
7a138b |
- if (ts < time_ref->ts_dev_2)
|
|
Takashi Iwai |
7a138b |
- delta_us &= (1 << time_ref->adapter->ts_used_bits) - 1;
|
|
Takashi Iwai |
7a138b |
+ /* General case: dev_ts_1 < dev_ts_2 < ts, with:
|
|
Takashi Iwai |
7a138b |
+ *
|
|
Takashi Iwai |
7a138b |
+ * - dev_ts_1 = previous sync timestamp
|
|
Takashi Iwai |
7a138b |
+ * - dev_ts_2 = last sync timestamp
|
|
Takashi Iwai |
7a138b |
+ * - ts = event timestamp
|
|
Takashi Iwai |
7a138b |
+ * - ts_period = known sync period (theoretical)
|
|
Takashi Iwai |
7a138b |
+ * ~ dev_ts2 - dev_ts1
|
|
Takashi Iwai |
7a138b |
+ * *but*:
|
|
Takashi Iwai |
7a138b |
+ *
|
|
Takashi Iwai |
7a138b |
+ * - time counters wrap (see adapter->ts_used_bits)
|
|
Takashi Iwai |
7a138b |
+ * - sometimes, dev_ts_1 < ts < dev_ts2
|
|
Takashi Iwai |
7a138b |
+ *
|
|
Takashi Iwai |
7a138b |
+ * "normal" case (sync time counters increase):
|
|
Takashi Iwai |
7a138b |
+ * must take into account case when ts wraps (tsw)
|
|
Takashi Iwai |
7a138b |
+ *
|
|
Takashi Iwai |
7a138b |
+ * < ts_period > < >
|
|
Takashi Iwai |
7a138b |
+ * | | |
|
|
Takashi Iwai |
7a138b |
+ * ---+--------+----+-------0-+--+-->
|
|
Takashi Iwai |
7a138b |
+ * ts_dev_1 | ts_dev_2 |
|
|
Takashi Iwai |
7a138b |
+ * ts tsw
|
|
Takashi Iwai |
7a138b |
+ */
|
|
Takashi Iwai |
7a138b |
+ if (time_ref->ts_dev_1 < time_ref->ts_dev_2) {
|
|
Takashi Iwai |
7a138b |
+ /* case when event time (tsw) wraps */
|
|
Takashi Iwai |
7a138b |
+ if (ts < time_ref->ts_dev_1)
|
|
Takashi Iwai |
7a138b |
+ delta_ts = 1 << time_ref->adapter->ts_used_bits;
|
|
Takashi Iwai |
7a138b |
|
|
Takashi Iwai |
7a138b |
- delta_us += time_ref->ts_total;
|
|
Takashi Iwai |
7a138b |
+ /* Otherwise, sync time counter (ts_dev_2) has wrapped:
|
|
Takashi Iwai |
7a138b |
+ * handle case when event time (tsn) hasn't.
|
|
Takashi Iwai |
7a138b |
+ *
|
|
Takashi Iwai |
7a138b |
+ * < ts_period > < >
|
|
Takashi Iwai |
7a138b |
+ * | | |
|
|
Takashi Iwai |
7a138b |
+ * ---+--------+--0-+---------+--+-->
|
|
Takashi Iwai |
7a138b |
+ * ts_dev_1 | ts_dev_2 |
|
|
Takashi Iwai |
7a138b |
+ * tsn ts
|
|
Takashi Iwai |
7a138b |
+ */
|
|
Takashi Iwai |
7a138b |
+ } else if (time_ref->ts_dev_1 < ts) {
|
|
Takashi Iwai |
7a138b |
+ delta_ts = -(1 << time_ref->adapter->ts_used_bits);
|
|
Takashi Iwai |
7a138b |
+ }
|
|
Takashi Iwai |
7a138b |
|
|
Takashi Iwai |
7a138b |
- delta_us *= time_ref->adapter->us_per_ts_scale;
|
|
Takashi Iwai |
7a138b |
+ /* add delay between last sync and event timestamps */
|
|
Takashi Iwai |
7a138b |
+ delta_ts += (signed int)(ts - time_ref->ts_dev_2);
|
|
Takashi Iwai |
7a138b |
+
|
|
Takashi Iwai |
7a138b |
+ /* add time from beginning to last sync */
|
|
Takashi Iwai |
7a138b |
+ delta_ts += time_ref->ts_total;
|
|
Takashi Iwai |
7a138b |
+
|
|
Takashi Iwai |
7a138b |
+ /* convert ticks number into microseconds */
|
|
Takashi Iwai |
7a138b |
+ delta_us = delta_ts * time_ref->adapter->us_per_ts_scale;
|
|
Takashi Iwai |
7a138b |
delta_us >>= time_ref->adapter->us_per_ts_shift;
|
|
Takashi Iwai |
7a138b |
|
|
Takashi Iwai |
7a138b |
*tv = time_ref->tv_host_0;
|