From: Thomas Gleixner <hidden> Date: 2021-11-15 15:21:44
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 <redacted>
Signed-off-by: Thomas Gleixner <redacted>
Tested-by: Benedikt Spranger <redacted>
Cc: stable@vger.kernel.org
---
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 23 +++++++++-------------
1 file changed, 10 insertions(+), 13 deletions(-)
From: Kurt Kanzenbach <kurt@linutronix.de> Date: 2021-11-16 07:13:19
+ 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 <redacted>
Signed-off-by: Thomas Gleixner <redacted>
Tested-by: Benedikt Spranger <redacted>
Cc: stable@vger.kernel.org
Thanks!
Tested-by: Kurt Kanzenbach <kurt@linutronix.de> # Intel EHL
From: David Laight <hidden> Date: 2021-11-16 13:06:57
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)
From: Wong Vee Khee <hidden> Date: 2021-11-17 03:57:34
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 <redacted>
Signed-off-by: Thomas Gleixner <redacted>
Tested-by: Benedikt Spranger <redacted>
Cc: stable@vger.kernel.org
Tested-by: Kurt Kanzenbach <kurt@linutronix.de> # Intel EHL
Thanks for the fix!
Tested-by: Wong Vee Khee <redacted> # Intel ADL
Hello:
This patch was applied to netdev/net.git (master)
by Jakub Kicinski [off-list ref]:
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;
[...]