netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] net: stmmac: Fix signed/unsigned wreckage
@ 2021-11-15 15:21 Thomas Gleixner
  2021-11-16  7:11 ` Kurt Kanzenbach
                   ` (3 more replies)
  0 siblings, 4 replies; 5+ messages in thread
From: Thomas Gleixner @ 2021-11-15 15:21 UTC (permalink / raw)
  To: netdev
  Cc: David S. Miller, Voon Weifeng, Wong Vee Khee, Giuseppe Cavallaro,
	Alexandre Torgue, Jose Abreu, Benedikt Spranger

The recent addition of timestamp correction to compensate the CDC error
introduced a subtle signed/unsigned bug in stmmac_get_tx_hwtstamp() while
it managed for some obscure reason to avoid that in stmmac_get_rx_hwtstamp().

The issue is:

    s64 adjust = 0;
    u64 ns;

    adjust += -(2 * (NSEC_PER_SEC / priv->plat->clk_ptp_rate));
    ns += adjust;

works by chance on 64bit, but falls apart on 32bit because the compiler
knows that adjust fits into 32bit and then treats the addition as a u64 +
u32 resulting in an off by ~2 seconds failure.

The RX variant uses an u64 for adjust and does the adjustment via

    ns -= adjust;

because consistency is obviously overrated.

Get rid of the pointless zero initialized adjust variable and do:

	ns -= (2 * NSEC_PER_SEC) / priv->plat->clk_ptp_rate;

which is obviously correct and spares the adjust obfuscation. Aside of that
it yields a more accurate result because the multiplication takes place
before the integer divide truncation and not afterwards.

Stick the calculation into an inline so it can't be accidentaly
disimproved. Return an u32 from that inline as the result is guaranteed
to fit which lets the compiler optimize the substraction.

Fixes: 3600be5f58c1 ("net: stmmac: add timestamp correction to rid CDC sync error")
Reported-by: Benedikt Spranger <b.spranger@linutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Benedikt Spranger <b.spranger@linutronix.de>
Cc: stable@vger.kernel.org
---
 drivers/net/ethernet/stmicro/stmmac/stmmac_main.c |   23 +++++++++-------------
 1 file changed, 10 insertions(+), 13 deletions(-)

--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -511,6 +511,14 @@ bool stmmac_eee_init(struct stmmac_priv
 	return true;
 }
 
+static inline u32 stmmac_cdc_adjust(struct stmmac_priv *priv)
+{
+	/* Correct the clk domain crossing(CDC) error */
+	if (priv->plat->has_gmac4 && priv->plat->clk_ptp_rate)
+		return (2 * NSEC_PER_SEC) / priv->plat->clk_ptp_rate;
+	return 0;
+}
+
 /* stmmac_get_tx_hwtstamp - get HW TX timestamps
  * @priv: driver private structure
  * @p : descriptor pointer
@@ -524,7 +532,6 @@ static void stmmac_get_tx_hwtstamp(struc
 {
 	struct skb_shared_hwtstamps shhwtstamp;
 	bool found = false;
-	s64 adjust = 0;
 	u64 ns = 0;
 
 	if (!priv->hwts_tx_en)
@@ -543,12 +550,7 @@ static void stmmac_get_tx_hwtstamp(struc
 	}
 
 	if (found) {
-		/* Correct the clk domain crossing(CDC) error */
-		if (priv->plat->has_gmac4 && priv->plat->clk_ptp_rate) {
-			adjust += -(2 * (NSEC_PER_SEC /
-					 priv->plat->clk_ptp_rate));
-			ns += adjust;
-		}
+		ns -= stmmac_cdc_adjust(priv);
 
 		memset(&shhwtstamp, 0, sizeof(struct skb_shared_hwtstamps));
 		shhwtstamp.hwtstamp = ns_to_ktime(ns);
@@ -573,7 +575,6 @@ static void stmmac_get_rx_hwtstamp(struc
 {
 	struct skb_shared_hwtstamps *shhwtstamp = NULL;
 	struct dma_desc *desc = p;
-	u64 adjust = 0;
 	u64 ns = 0;
 
 	if (!priv->hwts_rx_en)
@@ -586,11 +587,7 @@ static void stmmac_get_rx_hwtstamp(struc
 	if (stmmac_get_rx_timestamp_status(priv, p, np, priv->adv_ts)) {
 		stmmac_get_timestamp(priv, desc, priv->adv_ts, &ns);
 
-		/* Correct the clk domain crossing(CDC) error */
-		if (priv->plat->has_gmac4 && priv->plat->clk_ptp_rate) {
-			adjust += 2 * (NSEC_PER_SEC / priv->plat->clk_ptp_rate);
-			ns -= adjust;
-		}
+		ns -= stmmac_cdc_adjust(priv);
 
 		netdev_dbg(priv->dev, "get valid RX hw timestamp %llu\n", ns);
 		shhwtstamp = skb_hwtstamps(skb);

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] net: stmmac: Fix signed/unsigned wreckage
  2021-11-15 15:21 [PATCH] net: stmmac: Fix signed/unsigned wreckage Thomas Gleixner
@ 2021-11-16  7:11 ` Kurt Kanzenbach
  2021-11-16 13:06 ` David Laight
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 5+ messages in thread
From: Kurt Kanzenbach @ 2021-11-16  7:11 UTC (permalink / raw)
  To: Thomas Gleixner, netdev
  Cc: David S. Miller, Voon Weifeng, Wong Vee Khee, Giuseppe Cavallaro,
	Alexandre Torgue, Jose Abreu, Benedikt Spranger, Ong, Boon Leong

[-- Attachment #1: Type: text/plain, Size: 1667 bytes --]


+ BL

On Mon Nov 15 2021, Thomas Gleixner wrote:
> The recent addition of timestamp correction to compensate the CDC error
> introduced a subtle signed/unsigned bug in stmmac_get_tx_hwtstamp() while
> it managed for some obscure reason to avoid that in stmmac_get_rx_hwtstamp().
>
> The issue is:
>
>     s64 adjust = 0;
>     u64 ns;
>
>     adjust += -(2 * (NSEC_PER_SEC / priv->plat->clk_ptp_rate));
>     ns += adjust;
>
> works by chance on 64bit, but falls apart on 32bit because the compiler
> knows that adjust fits into 32bit and then treats the addition as a u64 +
> u32 resulting in an off by ~2 seconds failure.
>
> The RX variant uses an u64 for adjust and does the adjustment via
>
>     ns -= adjust;
>
> because consistency is obviously overrated.
>
> Get rid of the pointless zero initialized adjust variable and do:
>
> 	ns -= (2 * NSEC_PER_SEC) / priv->plat->clk_ptp_rate;
>
> which is obviously correct and spares the adjust obfuscation. Aside of that
> it yields a more accurate result because the multiplication takes place
> before the integer divide truncation and not afterwards.
>
> Stick the calculation into an inline so it can't be accidentaly
> disimproved. Return an u32 from that inline as the result is guaranteed
> to fit which lets the compiler optimize the substraction.
>
> Fixes: 3600be5f58c1 ("net: stmmac: add timestamp correction to rid CDC sync error")
> Reported-by: Benedikt Spranger <b.spranger@linutronix.de>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Benedikt Spranger <b.spranger@linutronix.de>
> Cc: stable@vger.kernel.org

Thanks!

Tested-by: Kurt Kanzenbach <kurt@linutronix.de> # Intel EHL

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 861 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* RE: [PATCH] net: stmmac: Fix signed/unsigned wreckage
  2021-11-15 15:21 [PATCH] net: stmmac: Fix signed/unsigned wreckage Thomas Gleixner
  2021-11-16  7:11 ` Kurt Kanzenbach
@ 2021-11-16 13:06 ` David Laight
  2021-11-17  3:57 ` Wong Vee Khee
  2021-11-17  4:00 ` patchwork-bot+netdevbpf
  3 siblings, 0 replies; 5+ messages in thread
From: David Laight @ 2021-11-16 13:06 UTC (permalink / raw)
  To: 'Thomas Gleixner', netdev
  Cc: David S. Miller, Voon Weifeng, Wong Vee Khee, Giuseppe Cavallaro,
	Alexandre Torgue, Jose Abreu, Benedikt Spranger

From: Thomas Gleixner
> Sent: 15 November 2021 15:21
> 
> The recent addition of timestamp correction to compensate the CDC error
> introduced a subtle signed/unsigned bug in stmmac_get_tx_hwtstamp() while
> it managed for some obscure reason to avoid that in stmmac_get_rx_hwtstamp().
> 
> The issue is:
> 
>     s64 adjust = 0;
>     u64 ns;
> 
>     adjust += -(2 * (NSEC_PER_SEC / priv->plat->clk_ptp_rate));
>     ns += adjust;
> 
> works by chance on 64bit, but falls apart on 32bit because the compiler
> knows that adjust fits into 32bit and then treats the addition as a u64 +
> u32 resulting in an off by ~2 seconds failure.

The problem is earlier.
NSEC_PER_SEC and clk_ptp_rate are almost certainly 32bit and unsigned.
So you have:
	adjust = (s64)((u64)adjust + (u32)-(2 * (NSEC_PER_SEC/...)));

	David

-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK
Registration No: 1397386 (Wales)


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] net: stmmac: Fix signed/unsigned wreckage
  2021-11-15 15:21 [PATCH] net: stmmac: Fix signed/unsigned wreckage Thomas Gleixner
  2021-11-16  7:11 ` Kurt Kanzenbach
  2021-11-16 13:06 ` David Laight
@ 2021-11-17  3:57 ` Wong Vee Khee
  2021-11-17  4:00 ` patchwork-bot+netdevbpf
  3 siblings, 0 replies; 5+ messages in thread
From: Wong Vee Khee @ 2021-11-17  3:57 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: netdev, David S. Miller, Voon Weifeng, Wong Vee Khee,
	Giuseppe Cavallaro, Alexandre Torgue, Jose Abreu,
	Benedikt Spranger

On Mon, Nov 15, 2021 at 04:21:23PM +0100, Thomas Gleixner wrote:
> The recent addition of timestamp correction to compensate the CDC error
> introduced a subtle signed/unsigned bug in stmmac_get_tx_hwtstamp() while
> it managed for some obscure reason to avoid that in stmmac_get_rx_hwtstamp().
> 
> The issue is:
> 
>     s64 adjust = 0;
>     u64 ns;
> 
>     adjust += -(2 * (NSEC_PER_SEC / priv->plat->clk_ptp_rate));
>     ns += adjust;
> 
> works by chance on 64bit, but falls apart on 32bit because the compiler
> knows that adjust fits into 32bit and then treats the addition as a u64 +
> u32 resulting in an off by ~2 seconds failure.
> 
> The RX variant uses an u64 for adjust and does the adjustment via
> 
>     ns -= adjust;
> 
> because consistency is obviously overrated.
> 
> Get rid of the pointless zero initialized adjust variable and do:
> 
> 	ns -= (2 * NSEC_PER_SEC) / priv->plat->clk_ptp_rate;
> 
> which is obviously correct and spares the adjust obfuscation. Aside of that
> it yields a more accurate result because the multiplication takes place
> before the integer divide truncation and not afterwards.
> 
> Stick the calculation into an inline so it can't be accidentaly
> disimproved. Return an u32 from that inline as the result is guaranteed
> to fit which lets the compiler optimize the substraction.
> 
> Fixes: 3600be5f58c1 ("net: stmmac: add timestamp correction to rid CDC sync error")
> Reported-by: Benedikt Spranger <b.spranger@linutronix.de>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Tested-by: Benedikt Spranger <b.spranger@linutronix.de>
> Cc: stable@vger.kernel.org
> Tested-by: Kurt Kanzenbach <kurt@linutronix.de> # Intel EHL

Thanks for the fix!

Tested-by: Wong Vee Khee <vee.khee.wong@linux.intel.com> # Intel ADL


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH] net: stmmac: Fix signed/unsigned wreckage
  2021-11-15 15:21 [PATCH] net: stmmac: Fix signed/unsigned wreckage Thomas Gleixner
                   ` (2 preceding siblings ...)
  2021-11-17  3:57 ` Wong Vee Khee
@ 2021-11-17  4:00 ` patchwork-bot+netdevbpf
  3 siblings, 0 replies; 5+ messages in thread
From: patchwork-bot+netdevbpf @ 2021-11-17  4:00 UTC (permalink / raw)
  To: Thomas Gleixner
  Cc: netdev, davem, weifeng.voon, vee.khee.wong, peppe.cavallaro,
	alexandre.torgue, joabreu, b.spranger

Hello:

This patch was applied to netdev/net.git (master)
by Jakub Kicinski <kuba@kernel.org>:

On Mon, 15 Nov 2021 16:21:23 +0100 you wrote:
> The recent addition of timestamp correction to compensate the CDC error
> introduced a subtle signed/unsigned bug in stmmac_get_tx_hwtstamp() while
> it managed for some obscure reason to avoid that in stmmac_get_rx_hwtstamp().
> 
> The issue is:
> 
>     s64 adjust = 0;
>     u64 ns;
> 
> [...]

Here is the summary with links:
  - net: stmmac: Fix signed/unsigned wreckage
    https://git.kernel.org/netdev/net/c/3751c3d34cd5

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2021-11-17  4:00 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-11-15 15:21 [PATCH] net: stmmac: Fix signed/unsigned wreckage Thomas Gleixner
2021-11-16  7:11 ` Kurt Kanzenbach
2021-11-16 13:06 ` David Laight
2021-11-17  3:57 ` Wong Vee Khee
2021-11-17  4:00 ` patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).