On 32-bit PowerPC, GCC lowers '/' and '%' on unsigned 64-bit operands to calls to __udivdi3() and __umoddi3(). U-Boot's private libgcc lacks these routines, so turris_1x_sdcard fails to link with CONFIG_USE_PRIVATE_LIBGCC=y:
undefined reference to `__udivdi3' Implement both with a copy of __div64_32() from lib/div64.c whose divisor is widened to 64 bits. The copy keeps the private libgcc independent of lib/, which not every xPL phase links. Build the file without LTO, as ARM does for eabi_compat.o: LTO can drop these functions before GCC generates the calls that need them. Signed-off-by: Josef Schlehofer <[email protected]> Cc: Tom Rini <[email protected]> Cc: Marek BehĂșn <[email protected]> --- Changes in v2: - new patch At -Os the two take 300 bytes, against 1036 and 992 bytes of _udivdi3.o and _umoddi3.o in Debian's libgcc 14.2. --- arch/powerpc/lib/Makefile | 3 +- arch/powerpc/lib/udivdi3.c | 82 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 arch/powerpc/lib/udivdi3.c diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 90f0e1e5fa9..23e62996701 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile @@ -6,7 +6,8 @@ ## Build a couple of necessary functions into a private libgcc ## if the user asked for it lib-$(CONFIG_USE_PRIVATE_LIBGCC) += _ashldi3.o _ashrdi3.o _lshrdi3.o \ - crtsavres.o + crtsavres.o udivdi3.o +CFLAGS_REMOVE_udivdi3.o := $(LTO_CFLAGS) MINIMAL= diff --git a/arch/powerpc/lib/udivdi3.c b/arch/powerpc/lib/udivdi3.c new file mode 100644 index 00000000000..deb0b5d49e1 --- /dev/null +++ b/arch/powerpc/lib/udivdi3.c @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * 64-bit unsigned division and modulo for the private libgcc + * + * GCC calls __udivdi3() and __umoddi3() for '/' and '%' on unsigned 64-bit + * operands on 32-bit PowerPC. udivmod64() is __div64_32() from lib/div64.c + * with a 64-bit divisor: its shift-and-subtract loop already works on one, + * and the step that first divides the high word now only runs when the + * divisor fits into 32 bits. Like __div64_32(), the functions are not + * instrumented, as tracing code may divide. The source file copyrights are + * as follows: + * + * Copyright (C) 2003 Bernardo Innocenti <[email protected]> + * + * Based on former do_div() implementation from asm-parisc/div64.h: + * Copyright (C) 1999 Hewlett-Packard Co + * Copyright (C) 1999 David Mosberger-Tang <[email protected]> + */ + +#include <linux/types.h> + +static notrace u64 udivmod64(u64 n, u64 base, u64 *rem) +{ + u64 b = base; + u64 res, d = 1; + u32 high = n >> 32; + + /* Reduce the thing a bit first */ + res = 0; + if (!(base >> 32) && high >= base) { + high /= (u32)base; + res = (u64)high << 32; + n -= (u64)(high * (u32)base) << 32; + } + + while ((s64)b > 0 && b < n) { + b = b + b; + d = d + d; + } + + do { + if (n >= b) { + n -= b; + res += d; + } + b >>= 1; + d >>= 1; + } while (d); + + *rem = n; + return res; +} + +/** + * __udivdi3() - divide two 64-bit unsigned integers + * + * @n: dividend + * @d: divisor + * Return: quotient + */ +notrace u64 __udivdi3(u64 n, u64 d) +{ + u64 rem; + + return udivmod64(n, d, &rem); +} + +/** + * __umoddi3() - remainder of the division of two 64-bit unsigned integers + * + * @n: dividend + * @d: divisor + * Return: remainder + */ +notrace u64 __umoddi3(u64 n, u64 d) +{ + u64 rem; + + udivmod64(n, d, &rem); + + return rem; +} -- 2.54.0 (Apple Git-157)
