From patchwork Wed Jul 31 09:37:20 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marc Kleine-Budde X-Patchwork-Id: 13748408 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id BDD6DC3DA7F for ; Wed, 31 Jul 2024 09:46:55 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Cc:To:In-Reply-To:References :Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From: Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=qZ18qEREEMujL3Ckjxr0kB4jIzZfJqTv1ef7O9PgrhI=; b=ItnvQjsXWxabm7mcLTKLkEv321 81yAU45x9k2/zfJXxcJ8bmt6P1kdzDQ2+IZwudlab2bjShQap2xslqhFarp9aRgnBD8E3YlIWbW8D 2t2cPPbbhBv3esIXFIR8FK+lESvlhvaadiWqvgw5fm0kfNHqyHtYFjCmg1IqeG2OHa7RVP6w3V6LT W0MDvhZC4Zdsuxl2IJ2oNKQRmN+SpTpYQgybHv80ETqGTK0Aafz4X++q0pRavstph3UFv24kRniyg HW4jpjLTYHgghvpQzFrqokTwAomNasugguoAr5gROrjM5+Powt9VRQcpD64RT4boJ/ovLPGG5BbcY l8Wyztcg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.97.1 #2 (Red Hat Linux)) id 1sZ5uu-00000000ar5-2jav; Wed, 31 Jul 2024 09:46:44 +0000 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by bombadil.infradead.org with esmtps (Exim 4.97.1 #2 (Red Hat Linux)) id 1sZ5mi-00000000XMk-05mC for linux-arm-kernel@bombadil.infradead.org; Wed, 31 Jul 2024 09:38:16 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Sender:Reply-To:Content-ID:Content-Description; bh=qZ18qEREEMujL3Ckjxr0kB4jIzZfJqTv1ef7O9PgrhI=; b=ps71u5JvCDRxW++DmgYOdP3GTE YIiFgpLjCMNFxMjgA0msTC5214ICORLPlZB74xIX3kkvUnuPa1X+TWIlMf1hKw6eMJ8WAYDoIZeKL cxag0MFtqr0LmOcziaCeWxTi2rW7nM17nXm4ECQjjPjpp9sTySiwEebTKmtnHdWCtqWShd8R3rrey mY9/73RsMzrwnOm2uV0x8SGQeZ4mAk3wrAUfGKk3oetvV//IuQoesn/Z+oDMDV0inPsORAmLeQ66S X1Enge+S0IJIr53B4XU4lD/ng/iuS/M1jD+CcRNv3WU/tY6zT4BuEmSJUK9lPBcuNR/WP+Fej/7d8 Dx500nJA==; Received: from metis.whiteo.stw.pengutronix.de ([2a0a:edc0:2:b01:1d::104]) by desiato.infradead.org with esmtps (Exim 4.97.1 #2 (Red Hat Linux)) id 1sZ5md-00000005BST-2ovO for linux-arm-kernel@lists.infradead.org; Wed, 31 Jul 2024 09:38:14 +0000 Received: from drehscheibe.grey.stw.pengutronix.de ([2a0a:edc0:0:c01:1d::a2]) by metis.whiteo.stw.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1sZ5mc-0005n1-FY for linux-arm-kernel@lists.infradead.org; Wed, 31 Jul 2024 11:38:10 +0200 Received: from [2a0a:edc0:0:b01:1d::7b] (helo=bjornoya.blackshift.org) by drehscheibe.grey.stw.pengutronix.de with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.94.2) (envelope-from ) id 1sZ5mS-003UwD-Ol for linux-arm-kernel@lists.infradead.org; Wed, 31 Jul 2024 11:38:00 +0200 Received: from dspam.blackshift.org (localhost [127.0.0.1]) by bjornoya.blackshift.org (Postfix) with SMTP id 44E1C312944 for ; Wed, 31 Jul 2024 09:38:00 +0000 (UTC) Received: from hardanger.blackshift.org (unknown [172.20.34.65]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by bjornoya.blackshift.org (Postfix) with ESMTPS id 0FE9C3128BD; Wed, 31 Jul 2024 09:37:56 +0000 (UTC) Received: from [172.20.34.65] (localhost [::1]) by hardanger.blackshift.org (OpenSMTPD) with ESMTP id a561f156; Wed, 31 Jul 2024 09:37:42 +0000 (UTC) From: Marc Kleine-Budde Date: Wed, 31 Jul 2024 11:37:20 +0200 Subject: [PATCH can-next v2 18/20] can: rockchip_canfd: add hardware timestamping support MIME-Version: 1.0 Message-Id: <20240731-rockchip-canfd-v2-18-d9604c5b4be8@pengutronix.de> References: <20240731-rockchip-canfd-v2-0-d9604c5b4be8@pengutronix.de> In-Reply-To: <20240731-rockchip-canfd-v2-0-d9604c5b4be8@pengutronix.de> To: kernel@pengutronix.de, Vincent Mailhol , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Heiko Stuebner , Philipp Zabel , Elaine Zhang , David Jander Cc: Simon Horman , linux-can@vger.kernel.org, netdev@vger.kernel.org, devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org, linux-rockchip@lists.infradead.org, linux-kernel@vger.kernel.org, Marc Kleine-Budde X-Mailer: b4 0.15-dev-37811 X-Developer-Signature: v=1; a=openpgp-sha256; l=9046; i=mkl@pengutronix.de; h=from:subject:message-id; bh=pRwkmcTSon5zNS9Ey+EGf7Jc9nHobbREvrQEd70TC+o=; b=owEBbQGS/pANAwAKASg4oj56LbxvAcsmYgBmqgXhj5J/qIFbEUTIs7Kh19JKG9P5eD2LpnOJJ 8Nw6v6VhsOJATMEAAEKAB0WIQRQQLqG4LYE3Sm8Pl8oOKI+ei28bwUCZqoF4QAKCRAoOKI+ei28 b3pECACZuWzFpMbE+8d3KQcPko9DNAp1cZ3fHuKZUCeBPNkk4AQKj6s1JfskZ0tp8NWXYcv9JCS IMg5b7HWiV+POXo1QPm19aqy2xQ7QmNMP2VICxjfhP2Dw078aP6tnJaemqxLRwxGgIBdJn+Vkl0 eI5Bze9NBJzm5IKy0od6DA8IIMipXAIpRn53sNAiFiOINsu0SlHKRyz+n+0r2CfrT7TwkaP/FZR 5QjeMhppwjFVkEQf4AxAeOciMm5+8u+Ln9KG3iAOpf7tGRCZkTIfTHILhMNLp4pTHNbfnqD2lrY W21DbsrOmsG/0KVD6d41J2KKftcRoSmb6wNRRu5JmrtUpMIn X-Developer-Key: i=mkl@pengutronix.de; a=openpgp; fpr=C1400BA0B3989E6FBC7D5B5C2B5EE211C58AEA54 X-SA-Exim-Connect-IP: 2a0a:edc0:0:c01:1d::a2 X-SA-Exim-Mail-From: mkl@pengutronix.de X-SA-Exim-Scanned: No (on metis.whiteo.stw.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-arm-kernel@lists.infradead.org X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20240731_103812_116312_73615237 X-CRM114-Status: GOOD ( 22.21 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add support for hardware based timestamping. Signed-off-by: Marc Kleine-Budde --- drivers/net/can/rockchip/rockchip_canfd-core.c | 6 ++ drivers/net/can/rockchip/rockchip_canfd-ethtool.c | 2 +- drivers/net/can/rockchip/rockchip_canfd-rx.c | 1 + .../net/can/rockchip/rockchip_canfd-timestamp.c | 94 +++++++++++++++++++++- drivers/net/can/rockchip/rockchip_canfd-tx.c | 4 + drivers/net/can/rockchip/rockchip_canfd.h | 11 +++ 6 files changed, 115 insertions(+), 3 deletions(-) diff --git a/drivers/net/can/rockchip/rockchip_canfd-core.c b/drivers/net/can/rockchip/rockchip_canfd-core.c index 9c762b59e310..acbbfdd4cb69 100644 --- a/drivers/net/can/rockchip/rockchip_canfd-core.c +++ b/drivers/net/can/rockchip/rockchip_canfd-core.c @@ -292,6 +292,8 @@ static void rkcanfd_chip_start(struct rkcanfd_priv *priv) rkcanfd_chip_fifo_setup(priv); rkcanfd_timestamp_init(priv); + rkcanfd_timestamp_start(priv); + rkcanfd_set_bittiming(priv); rkcanfd_chip_interrupts_disable(priv); @@ -315,6 +317,7 @@ static void rkcanfd_chip_stop(struct rkcanfd_priv *priv, const enum can_state st { priv->can.state = state; + rkcanfd_timestamp_stop(priv); __rkcanfd_chip_stop(priv, state); } @@ -322,6 +325,7 @@ static void rkcanfd_chip_stop_sync(struct rkcanfd_priv *priv, const enum can_sta { priv->can.state = state; + rkcanfd_timestamp_stop_sync(priv); __rkcanfd_chip_stop(priv, state); } @@ -353,6 +357,8 @@ rkcanfd_alloc_can_err_skb(struct rkcanfd_priv *priv, *timestamp = rkcanfd_get_timestamp(priv); skb = alloc_can_err_skb(priv->ndev, cf); + if (skb) + rkcanfd_skb_set_timestamp(priv, skb, *timestamp); return skb; } diff --git a/drivers/net/can/rockchip/rockchip_canfd-ethtool.c b/drivers/net/can/rockchip/rockchip_canfd-ethtool.c index 0084f37b2b9f..5aeeef64a67a 100644 --- a/drivers/net/can/rockchip/rockchip_canfd-ethtool.c +++ b/drivers/net/can/rockchip/rockchip_canfd-ethtool.c @@ -59,7 +59,7 @@ rkcanfd_ethtool_get_ethtool_stats(struct net_device *ndev, } static const struct ethtool_ops rkcanfd_ethtool_ops = { - .get_ts_info = ethtool_op_get_ts_info, + .get_ts_info = can_ethtool_op_get_ts_info_hwts, .get_strings = rkcanfd_ethtool_get_strings, .get_sset_count = rkcanfd_ethtool_get_sset_count, .get_ethtool_stats = rkcanfd_ethtool_get_ethtool_stats, diff --git a/drivers/net/can/rockchip/rockchip_canfd-rx.c b/drivers/net/can/rockchip/rockchip_canfd-rx.c index bacef5e5dc39..d862116840eb 100644 --- a/drivers/net/can/rockchip/rockchip_canfd-rx.c +++ b/drivers/net/can/rockchip/rockchip_canfd-rx.c @@ -267,6 +267,7 @@ static int rkcanfd_handle_rx_int_one(struct rkcanfd_priv *priv) } memcpy(skb_cfd, cfd, len); + rkcanfd_skb_set_timestamp(priv, skb, header->ts); err = can_rx_offload_queue_timestamp(&priv->offload, skb, header->ts); if (err) diff --git a/drivers/net/can/rockchip/rockchip_canfd-timestamp.c b/drivers/net/can/rockchip/rockchip_canfd-timestamp.c index 9301b3ceceb0..81cccc5fd838 100644 --- a/drivers/net/can/rockchip/rockchip_canfd-timestamp.c +++ b/drivers/net/can/rockchip/rockchip_canfd-timestamp.c @@ -4,12 +4,102 @@ // Marc Kleine-Budde // +#include + #include "rockchip_canfd.h" +static u64 rkcanfd_timestamp_read(const struct cyclecounter *cc) +{ + const struct rkcanfd_priv *priv = container_of(cc, struct rkcanfd_priv, cc); + + return rkcanfd_get_timestamp(priv); +} + +void rkcanfd_skb_set_timestamp(const struct rkcanfd_priv *priv, + struct sk_buff *skb, const u32 timestamp) +{ + struct skb_shared_hwtstamps *hwtstamps = skb_hwtstamps(skb); + u64 ns; + + ns = timecounter_cyc2time(&priv->tc, timestamp); + + hwtstamps->hwtstamp = ns_to_ktime(ns); +} + +static void rkcanfd_timestamp_work(struct work_struct *work) +{ + const struct delayed_work *delayed_work = to_delayed_work(work); + struct rkcanfd_priv *priv; + + priv = container_of(delayed_work, struct rkcanfd_priv, timestamp); + timecounter_read(&priv->tc); + + schedule_delayed_work(&priv->timestamp, priv->work_delay_jiffies); +} + void rkcanfd_timestamp_init(struct rkcanfd_priv *priv) { - u32 reg; + const struct can_bittiming *dbt = &priv->can.data_bittiming; + const struct can_bittiming *bt = &priv->can.bittiming; + struct cyclecounter *cc = &priv->cc; + u32 bitrate, div, reg, rate; + u64 work_delay_ns; + u64 max_cycles; - reg = RKCANFD_REG_TIMESTAMP_CTRL_TIME_BASE_COUNTER_ENABLE; + /* At the standard clock rate of 300Mhz on the rk3658, the 32 + * bit timer overflows every 14s. This means that we have to + * poll it quite often to avoid missing a wrap around. + * + * Divide it down to a reasonable rate, at least twice the bit + * rate. + */ + bitrate = max(bt->bitrate, dbt->bitrate); + div = min(DIV_ROUND_UP(priv->can.clock.freq, bitrate * 2), + FIELD_MAX(RKCANFD_REG_TIMESTAMP_CTRL_TIME_BASE_COUNTER_PRESCALE) + 1); + + reg = FIELD_PREP(RKCANFD_REG_TIMESTAMP_CTRL_TIME_BASE_COUNTER_PRESCALE, + div - 1) | + RKCANFD_REG_TIMESTAMP_CTRL_TIME_BASE_COUNTER_ENABLE; rkcanfd_write(priv, RKCANFD_REG_TIMESTAMP_CTRL, reg); + + cc->read = rkcanfd_timestamp_read; + cc->mask = CYCLECOUNTER_MASK(32); + + rate = priv->can.clock.freq / div; + clocks_calc_mult_shift(&cc->mult, &cc->shift, rate, NSEC_PER_SEC, + RKCANFD_TIMESTAMP_WORK_MAX_DELAY_SEC); + + max_cycles = div_u64(ULLONG_MAX, cc->mult); + max_cycles = min(max_cycles, cc->mask); + work_delay_ns = clocksource_cyc2ns(max_cycles, cc->mult, cc->shift) / 3; + priv->work_delay_jiffies = nsecs_to_jiffies(work_delay_ns); + INIT_DELAYED_WORK(&priv->timestamp, rkcanfd_timestamp_work); + + netdev_dbg(priv->ndev, "clock=%lu.%02luMHz bitrate=%lu.%02luMBit/s div=%u rate=%lu.%02luMHz mult=%u shift=%u delay=%lus\n", + priv->can.clock.freq / MEGA, + priv->can.clock.freq % MEGA / KILO / 10, + bitrate / MEGA, + bitrate % MEGA / KILO / 100, + div, + rate / MEGA, + rate % MEGA / KILO / 10, + cc->mult, cc->shift, + priv->work_delay_jiffies / HZ); +} + +void rkcanfd_timestamp_start(struct rkcanfd_priv *priv) +{ + timecounter_init(&priv->tc, &priv->cc, ktime_get_real_ns()); + + schedule_delayed_work(&priv->timestamp, priv->work_delay_jiffies); +} + +void rkcanfd_timestamp_stop(struct rkcanfd_priv *priv) +{ + cancel_delayed_work(&priv->timestamp); +} + +void rkcanfd_timestamp_stop_sync(struct rkcanfd_priv *priv) +{ + cancel_delayed_work_sync(&priv->timestamp); } diff --git a/drivers/net/can/rockchip/rockchip_canfd-tx.c b/drivers/net/can/rockchip/rockchip_canfd-tx.c index d10da548ba71..f954f38b955f 100644 --- a/drivers/net/can/rockchip/rockchip_canfd-tx.c +++ b/drivers/net/can/rockchip/rockchip_canfd-tx.c @@ -145,8 +145,10 @@ void rkcanfd_handle_tx_done_one(struct rkcanfd_priv *priv, const u32 ts, { struct net_device_stats *stats = &priv->ndev->stats; unsigned int tx_tail; + struct sk_buff *skb; tx_tail = rkcanfd_get_tx_tail(priv); + skb = priv->can.echo_skb[tx_tail]; /* Manual handling of CAN Bus Error counters. See * rkcanfd_get_corrected_berr_counter() for detailed @@ -155,6 +157,8 @@ void rkcanfd_handle_tx_done_one(struct rkcanfd_priv *priv, const u32 ts, if (priv->bec.txerr) priv->bec.txerr--; + if (skb) + rkcanfd_skb_set_timestamp(priv, skb, ts); stats->tx_bytes += can_rx_offload_get_echo_skb_queue_timestamp(&priv->offload, tx_tail, ts, diff --git a/drivers/net/can/rockchip/rockchip_canfd.h b/drivers/net/can/rockchip/rockchip_canfd.h index 6be2865ec95a..3efd7f174e14 100644 --- a/drivers/net/can/rockchip/rockchip_canfd.h +++ b/drivers/net/can/rockchip/rockchip_canfd.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #include #include @@ -469,6 +470,11 @@ struct rkcanfd_priv { u32 reg_int_mask_default; struct rkcanfd_devtype_data devtype_data; + struct cyclecounter cc; + struct timecounter tc; + struct delayed_work timestamp; + unsigned long work_delay_jiffies; + struct can_berr_counter bec; struct rkcanfd_stats stats; @@ -531,7 +537,12 @@ 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, + struct sk_buff *skb, const u32 timestamp); void rkcanfd_timestamp_init(struct rkcanfd_priv *priv); +void rkcanfd_timestamp_start(struct rkcanfd_priv *priv); +void rkcanfd_timestamp_stop(struct rkcanfd_priv *priv); +void rkcanfd_timestamp_stop_sync(struct rkcanfd_priv *priv); unsigned int rkcanfd_get_effective_tx_free(const struct rkcanfd_priv *priv); void rkcanfd_xmit_retry(struct rkcanfd_priv *priv);