mcp251xfd-timestamp.c (1888B)
1// SPDX-License-Identifier: GPL-2.0 2// 3// mcp251xfd - Microchip MCP251xFD Family CAN controller driver 4// 5// Copyright (c) 2021 Pengutronix, 6// Marc Kleine-Budde <kernel@pengutronix.de> 7// 8 9#include <linux/clocksource.h> 10#include <linux/workqueue.h> 11 12#include "mcp251xfd.h" 13 14static u64 mcp251xfd_timestamp_read(const struct cyclecounter *cc) 15{ 16 const struct mcp251xfd_priv *priv; 17 u32 timestamp = 0; 18 int err; 19 20 priv = container_of(cc, struct mcp251xfd_priv, cc); 21 err = mcp251xfd_get_timestamp(priv, ×tamp); 22 if (err) 23 netdev_err(priv->ndev, 24 "Error %d while reading timestamp. HW timestamps may be inaccurate.", 25 err); 26 27 return timestamp; 28} 29 30static void mcp251xfd_timestamp_work(struct work_struct *work) 31{ 32 struct delayed_work *delayed_work = to_delayed_work(work); 33 struct mcp251xfd_priv *priv; 34 35 priv = container_of(delayed_work, struct mcp251xfd_priv, timestamp); 36 timecounter_read(&priv->tc); 37 38 schedule_delayed_work(&priv->timestamp, 39 MCP251XFD_TIMESTAMP_WORK_DELAY_SEC * HZ); 40} 41 42void mcp251xfd_skb_set_timestamp(const struct mcp251xfd_priv *priv, 43 struct sk_buff *skb, u32 timestamp) 44{ 45 struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb); 46 u64 ns; 47 48 ns = timecounter_cyc2time(&priv->tc, timestamp); 49 hwtstamps->hwtstamp = ns_to_ktime(ns); 50} 51 52void mcp251xfd_timestamp_init(struct mcp251xfd_priv *priv) 53{ 54 struct cyclecounter *cc = &priv->cc; 55 56 cc->read = mcp251xfd_timestamp_read; 57 cc->mask = CYCLECOUNTER_MASK(32); 58 cc->shift = 1; 59 cc->mult = clocksource_hz2mult(priv->can.clock.freq, cc->shift); 60 61 timecounter_init(&priv->tc, &priv->cc, ktime_get_real_ns()); 62 63 INIT_DELAYED_WORK(&priv->timestamp, mcp251xfd_timestamp_work); 64 schedule_delayed_work(&priv->timestamp, 65 MCP251XFD_TIMESTAMP_WORK_DELAY_SEC * HZ); 66} 67 68void mcp251xfd_timestamp_stop(struct mcp251xfd_priv *priv) 69{ 70 cancel_delayed_work_sync(&priv->timestamp); 71}