]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob
1f74b8e59916adf3b33fc5dedd1955fbd34278ac
[thirdparty/kernel/stable-queue.git] /
1 From 5a1e9ceca163ffd944ea01f6efbade9c33f353f4 Mon Sep 17 00:00:00 2001
2 From: Sasha Levin <sashal@kernel.org>
3 Date: Wed, 14 Oct 2020 10:56:31 +0200
4 Subject: can: peak_usb: peak_usb_get_ts_time(): fix timestamp wrapping
5
6 From: Stephane Grosjean <s.grosjean@peak-system.com>
7
8 [ Upstream commit ecc7b4187dd388549544195fb13a11b4ea8e6a84 ]
9
10 Fabian Inostroza <fabianinostrozap@gmail.com> has discovered a potential
11 problem in the hardware timestamp reporting from the PCAN-USB USB CAN interface
12 (only), related to the fact that a timestamp of an event may precede the
13 timestamp used for synchronization when both records are part of the same USB
14 packet. However, this case was used to detect the wrapping of the time counter.
15
16 This patch details and fixes the two identified cases where this problem can
17 occur.
18
19 Reported-by: Fabian Inostroza <fabianinostrozap@gmail.com>
20 Signed-off-by: Stephane Grosjean <s.grosjean@peak-system.com>
21 Link: https://lore.kernel.org/r/20201014085631.15128-1-s.grosjean@peak-system.com
22 Fixes: bb4785551f64 ("can: usb: PEAK-System Technik USB adapters driver core")
23 Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
24 Signed-off-by: Sasha Levin <sashal@kernel.org>
25 ---
26 drivers/net/can/usb/peak_usb/pcan_usb_core.c | 51 ++++++++++++++++++--
27 1 file changed, 46 insertions(+), 5 deletions(-)
28
29 diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
30 index d91df34e7fa88..c2764799f9efb 100644
31 --- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
32 +++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
33 @@ -130,14 +130,55 @@ void peak_usb_get_ts_time(struct peak_time_ref *time_ref, u32 ts, ktime_t *time)
34 /* protect from getting time before setting now */
35 if (ktime_to_ns(time_ref->tv_host)) {
36 u64 delta_us;
37 + s64 delta_ts = 0;
38 +
39 + /* General case: dev_ts_1 < dev_ts_2 < ts, with:
40 + *
41 + * - dev_ts_1 = previous sync timestamp
42 + * - dev_ts_2 = last sync timestamp
43 + * - ts = event timestamp
44 + * - ts_period = known sync period (theoretical)
45 + * ~ dev_ts2 - dev_ts1
46 + * *but*:
47 + *
48 + * - time counters wrap (see adapter->ts_used_bits)
49 + * - sometimes, dev_ts_1 < ts < dev_ts2
50 + *
51 + * "normal" case (sync time counters increase):
52 + * must take into account case when ts wraps (tsw)
53 + *
54 + * < ts_period > < >
55 + * | | |
56 + * ---+--------+----+-------0-+--+-->
57 + * ts_dev_1 | ts_dev_2 |
58 + * ts tsw
59 + */
60 + if (time_ref->ts_dev_1 < time_ref->ts_dev_2) {
61 + /* case when event time (tsw) wraps */
62 + if (ts < time_ref->ts_dev_1)
63 + delta_ts = 1 << time_ref->adapter->ts_used_bits;
64 +
65 + /* Otherwise, sync time counter (ts_dev_2) has wrapped:
66 + * handle case when event time (tsn) hasn't.
67 + *
68 + * < ts_period > < >
69 + * | | |
70 + * ---+--------+--0-+---------+--+-->
71 + * ts_dev_1 | ts_dev_2 |
72 + * tsn ts
73 + */
74 + } else if (time_ref->ts_dev_1 < ts) {
75 + delta_ts = -(1 << time_ref->adapter->ts_used_bits);
76 + }
77
78 - delta_us = ts - time_ref->ts_dev_2;
79 - if (ts < time_ref->ts_dev_2)
80 - delta_us &= (1 << time_ref->adapter->ts_used_bits) - 1;
81 + /* add delay between last sync and event timestamps */
82 + delta_ts += (signed int)(ts - time_ref->ts_dev_2);
83
84 - delta_us += time_ref->ts_total;
85 + /* add time from beginning to last sync */
86 + delta_ts += time_ref->ts_total;
87
88 - delta_us *= time_ref->adapter->us_per_ts_scale;
89 + /* convert ticks number into microseconds */
90 + delta_us = delta_ts * time_ref->adapter->us_per_ts_scale;
91 delta_us >>= time_ref->adapter->us_per_ts_shift;
92
93 *time = ktime_add_us(time_ref->tv_host_0, delta_us);
94 --
95 2.27.0
96