Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

vdso, math64: Provide mul_u64_u32_add_u64_shr()

Provide mul_u64_u32_add_u64_shr() which is a calculation that will be used
by timekeeping and VDSO.

Place #include <vdso/math64.h> after #include <asm/div64.h> to allow
architecture-specific overrides, at least for the kernel.

Signed-off-by: Adrian Hunter <adrian.hunter@intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: https://lore.kernel.org/r/20240325064023.2997-6-adrian.hunter@intel.com

authored by

Adrian Hunter and committed by
Thomas Gleixner
1beb35ec 5e5e5142

+39 -1
+1 -1
include/linux/math64.h
··· 4 4 5 5 #include <linux/types.h> 6 6 #include <linux/math.h> 7 - #include <vdso/math64.h> 8 7 #include <asm/div64.h> 8 + #include <vdso/math64.h> 9 9 10 10 #if BITS_PER_LONG == 64 11 11
+38
include/vdso/math64.h
··· 21 21 return ret; 22 22 } 23 23 24 + #if defined(CONFIG_ARCH_SUPPORTS_INT128) && defined(__SIZEOF_INT128__) 25 + 26 + #ifndef mul_u64_u32_add_u64_shr 27 + static __always_inline u64 mul_u64_u32_add_u64_shr(u64 a, u32 mul, u64 b, unsigned int shift) 28 + { 29 + return (u64)((((unsigned __int128)a * mul) + b) >> shift); 30 + } 31 + #endif /* mul_u64_u32_add_u64_shr */ 32 + 33 + #else 34 + 35 + #ifndef mul_u64_u32_add_u64_shr 36 + #ifndef mul_u32_u32 37 + static inline u64 mul_u32_u32(u32 a, u32 b) 38 + { 39 + return (u64)a * b; 40 + } 41 + #define mul_u32_u32 mul_u32_u32 42 + #endif 43 + static __always_inline u64 mul_u64_u32_add_u64_shr(u64 a, u32 mul, u64 b, unsigned int shift) 44 + { 45 + u32 ah = a >> 32, al = a; 46 + bool ovf; 47 + u64 ret; 48 + 49 + ovf = __builtin_add_overflow(mul_u32_u32(al, mul), b, &ret); 50 + ret >>= shift; 51 + if (ovf && shift) 52 + ret += 1ULL << (64 - shift); 53 + if (ah) 54 + ret += mul_u32_u32(ah, mul) << (32 - shift); 55 + 56 + return ret; 57 + } 58 + #endif /* mul_u64_u32_add_u64_shr */ 59 + 60 + #endif 61 + 24 62 #endif /* __VDSO_MATH64_H */