Thread (5 messages) flat view 5 messages, 3 authors, 2021-08-17

Re: [PATCH v2 1/1] can: esd: add support for esd GmbH PCIe/402 CAN interface family

From: Vincent MAILHOL <hidden>
Date: 2021-08-17 00:14:34
Also in: linux-can

Hi Stefan,

On Tue. 17 Aug 2021 at 07:04, Stefan Mätje [off-list ref] wrote:
Am Freitag, den 06.08.2021, 15:31 +0200 schrieb Marc Kleine-Budde:
quoted
On 30.07.2021 19:38:05, Stefan Mätje wrote:
...
quoted
This device supports HW timestamping. Please don't roll your own
conversion functions. Please make use of the timecounter/cyclecounter
API, have a look at the mcp251xfd driver for example:

https://elixir.bootlin.com/linux/v5.13/source/drivers/net/can/spi/mcp251xfd/mcp251xfd-timestamp.c#L52

The idea is that there is a counter of a certain with (here 32 bit) that
has a certain frequency (here: priv->can.clock.freq).
quoted
    cc->read = mcp251xfd_timestamp_read;
    cc->mask = CYCLECOUNTER_MASK(32);
    cc->shift = 1;
    cc->mult = clocksource_hz2mult(priv->can.clock.freq, cc->shift);
The conversion from the register value to ns in done with:
quoted
ns = ((reg & mask) * mult) >> shift;
In the above example I'm using a shift of "1" as 1ns is an integer
multiple of the used frequency (which is 20 or 40 MHz).

To cope with overflows of the cycle counter, read the current timestamp
with timecounter_read() with at least the double frequency of the
overflows happening (plus some slack). The mcp251xfd driver sets up a
worker for this. The mcp251xfd drive does this every 45 seconds, with an
overflow happening every 107s.
At the moment I can't see the real benefit of this API. This is because the
device delivers the HW timestamp as a 64-bit value with a certain frequency
(atm. 80MHz). This timestamp will wrap after(!) the the result in ns of
ktime_t.

The other devices with 64-bit native timestamps (like etas_58x, peak_canfd.c
and kvaser_pciefd.c) also do simple multiplication / division operations on
the 64-bit HW timestamp

Using the struct cyclecounter to hold the multiplier and divisor in the
struct acc_ov (instead of the members ts2ns_numerator and ts2ns_denominator)
would result in such an initialization for a struct cyclecounter cc:

struct cyclecounter cc = {
        .read = NULL,
        .mask = CYCLECOUNTER_MASK(64),
        .shift = 1,
        .mult = clocksource_hz2mult(ov->timestamp_frequency, cc->shift),/* 25 */
}

Then in acc_ts2ktime() the function cyclecounter_cyc2ns() could be used like this:

static ktime_t acc_ts2ktime(struct acc_ov *ov, u64 ts)
{
        u64 unused_frac;
        u64 ns;

        ns = cyclecounter_cyc2ns(ov->cc, ts, 0, &unused_frac);

        return ns_to_ktime(ns);
}

One concluding question. Need the HW timestamps be only in ns (since powerup) or should they also be in relation to the kernel time
of the startup like it is done in Vincent's etas_58x driver?
In a nutshell, I converted the hardware timestamps to kernel
time (UNIX format) because I like to be able to derive the date
and time from my timestamps. I explained it in more details in
below message:

https://lore.kernel.org/linux-can/CAMZ6RqL+n4tRy-B-W+fzW5B3QV6Bedrko57pU_0TE023Oxw_5w@mail.gmail.com/ (local)

Yours sincerely,
Vincent
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help