[PATCH net v6 6/6] can: rockchip_canfd: serialize timecounter timestamp conversion

From: Cunhao Lu via B4 Relay

Date: Sat Oct 17 2026 - 10:55:44 EST


From: Cunhao Lu <1579567540@xxxxxx>

The timestamp worker advances the timecounter with timecounter_read()
while RX, TX completion and error-frame paths use timecounter_cyc2time()
to convert hardware timestamps without holding timestamp_lock.

timecounter_read() updates frac, cycle_last and nsec in separate steps.
A concurrent conversion can observe the new cycle_last with the old
nsec and produce an incorrect timestamp.

Hold timestamp_lock across timecounter_cyc2time(), using the same lock
as timecounter_read() and timecounter_init(). Keep the SKB timestamp
assignment outside the critical section.

TX completion nests timestamp_lock inside tx_lock; no timestamp-lock
holder acquires tx_lock.

Fixes: 4e1a18bab124 ("can: rockchip_canfd: add hardware timestamping support")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Cunhao Lu <1579567540@xxxxxx>
---
drivers/net/can/rockchip/rockchip_canfd-timestamp.c | 5 ++++-
drivers/net/can/rockchip/rockchip_canfd.h | 4 ++--
2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/net/can/rockchip/rockchip_canfd-timestamp.c b/drivers/net/can/rockchip/rockchip_canfd-timestamp.c
index 0fa791849c95..05f1005ee506 100644
--- a/drivers/net/can/rockchip/rockchip_canfd-timestamp.c
+++ b/drivers/net/can/rockchip/rockchip_canfd-timestamp.c
@@ -15,13 +15,16 @@ static u64 rkcanfd_timestamp_read(struct cyclecounter *cc)
return rkcanfd_get_timestamp(priv);
}

-void rkcanfd_skb_set_timestamp(const struct rkcanfd_priv *priv,
+void rkcanfd_skb_set_timestamp(struct rkcanfd_priv *priv,
struct sk_buff *skb, const u32 timestamp)
{
struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb);
+ unsigned long flags;
u64 ns;

+ spin_lock_irqsave(&priv->timestamp_lock, flags);
ns = timecounter_cyc2time(&priv->tc, timestamp);
+ spin_unlock_irqrestore(&priv->timestamp_lock, flags);

hwtstamps->hwtstamp = ns_to_ktime(ns);
}
diff --git a/drivers/net/can/rockchip/rockchip_canfd.h b/drivers/net/can/rockchip/rockchip_canfd.h
index 4a2bdc205296..63f146ff8e6b 100644
--- a/drivers/net/can/rockchip/rockchip_canfd.h
+++ b/drivers/net/can/rockchip/rockchip_canfd.h
@@ -489,7 +489,7 @@ struct rkcanfd_priv {

struct cyclecounter cc;
struct timecounter tc;
- /* Protects timestamp_active and worker reads/requeueing. */
+ /* Protects tc, timestamp_active and worker requeueing. */
spinlock_t timestamp_lock;
struct delayed_work timestamp;
unsigned long work_delay_jiffies;
@@ -557,7 +557,7 @@ void rkcanfd_ethtool_init(struct rkcanfd_priv *priv);

int rkcanfd_handle_rx_int(struct rkcanfd_priv *priv);

-void rkcanfd_skb_set_timestamp(const struct rkcanfd_priv *priv,
+void rkcanfd_skb_set_timestamp(struct rkcanfd_priv *priv,
struct sk_buff *skb, const u32 timestamp);
void rkcanfd_timestamp_work_init(struct rkcanfd_priv *priv);
void rkcanfd_timestamp_init(struct rkcanfd_priv *priv);

--
2.34.1