[PATCH net v7 7/7] can: rockchip_canfd: serialize timecounter timestamp conversion

From: Cunhao Lu via B4 Relay

Date: Fri Nov 06 2026 - 05:02:04 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 1d2a122770dc..e255bb33a20d 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 078876769a05..ecb9e2d6aa19 100644
--- a/drivers/net/can/rockchip/rockchip_canfd.h
+++ b/drivers/net/can/rockchip/rockchip_canfd.h
@@ -477,7 +477,7 @@ struct rkcanfd_priv {

/* Serialize TX submission/completion with bus-off and restart. */
spinlock_t tx_lock;
- /* Protects timestamp_active and worker reads/requeueing. */
+ /* Protects tc, timestamp_active and worker requeueing. */
spinlock_t timestamp_lock;
void __iomem *regs;
unsigned int tx_head;
@@ -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