diff mbox series

RFT: mips: implement __udivdi3

Message ID 20230918061139.810552-1-linus.walleij@linaro.org
State New
Headers show
Series RFT: mips: implement __udivdi3 | expand

Commit Message

Linus Walleij Sept. 18, 2023, 6:11 a.m. UTC
Squashfs wasn't compiling because the lldiv() directives
turn into __udivdi3 and we are using private libgcc.
This is just copied from the Linux kernel v6.6-rc1
arch/mips/include/asm/div64.h and then adjusted for
U-Boot.

After this squashfs compiles for MIPS.

Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
Cc: Mauro Condarelli <mc5686@mclink.it>
Cc: Ralf Baechle <ralf@linux-mips.org>
Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
---
I can't test this because it didn't work for MTD devices
as I had expected, but I saw Mauro had this problem
before so I think I might have fixed it. I better put
the patch out there rather than let it sit on my drive.
---
 arch/mips/lib/Makefile  |  2 +-
 arch/mips/lib/udivdi3.c | 86 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 87 insertions(+), 1 deletion(-)
 create mode 100644 arch/mips/lib/udivdi3.c

Comments

Daniel Schwierzeck Sept. 21, 2023, 1:42 p.m. UTC | #1
Hi Linus,

On 9/18/23 08:11, Linus Walleij wrote:
> Squashfs wasn't compiling because the lldiv() directives
> turn into __udivdi3 and we are using private libgcc.
> This is just copied from the Linux kernel v6.6-rc1
> arch/mips/include/asm/div64.h and then adjusted for
> U-Boot.
> 
> After this squashfs compiles for MIPS.
> 
> Cc: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
> Cc: Mauro Condarelli <mc5686@mclink.it>
> Cc: Ralf Baechle <ralf@linux-mips.org>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
> I can't test this because it didn't work for MTD devices
> as I had expected, but I saw Mauro had this problem
> before so I think I might have fixed it. I better put
> the patch out there rather than let it sit on my drive.

thanks for the patch. IIRC the problem was due to the usage of a/b vs. 
do_div(a,b). We already thought about two options: fix the SquashFS code 
or add __udivdi3(). Because no upstream MIPS board enabled SquashFS, 
this issue remained unresolved.


> ---
>   arch/mips/lib/Makefile  |  2 +-
>   arch/mips/lib/udivdi3.c | 86 +++++++++++++++++++++++++++++++++++++++++
>   2 files changed, 87 insertions(+), 1 deletion(-)
>   create mode 100644 arch/mips/lib/udivdi3.c
> 
> diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
> index 9ee1fcb5c702..1621cc9a1ff9 100644
> --- a/arch/mips/lib/Makefile
> +++ b/arch/mips/lib/Makefile
> @@ -14,4 +14,4 @@ obj-$(CONFIG_CMD_BOOTM) += bootm.o
>   obj-$(CONFIG_CMD_GO) += boot.o
>   obj-$(CONFIG_SPL_BUILD) += spl.o
>   
> -lib-$(CONFIG_USE_PRIVATE_LIBGCC) += ashldi3.o ashrdi3.o lshrdi3.o
> +lib-$(CONFIG_USE_PRIVATE_LIBGCC) += ashldi3.o ashrdi3.o lshrdi3.o udivdi3.o
> diff --git a/arch/mips/lib/udivdi3.c b/arch/mips/lib/udivdi3.c
> new file mode 100644
> index 000000000000..6a4ee5fa46ab
> --- /dev/null
> +++ b/arch/mips/lib/udivdi3.c
> @@ -0,0 +1,86 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Copyright (C) 2000, 2004, 2021  Maciej W. Rozycki
> + * Copyright (C) 2003, 07 Ralf Baechle (ralf@linux-mips.org)
> + */
> +
> +#include "libgcc.h"
> +
> +/*
> + * No traps on overflows for any of these...
> + */
> +
> +#define do_div64_32(res, high, low, base) ({				\
> +	unsigned long __cf, __tmp, __tmp2, __i;				\
> +	unsigned long __quot32, __mod32;				\
> +									\
> +	__asm__(							\
> +	"	.set	push					\n"	\
> +	"	.set	noat					\n"	\
> +	"	.set	noreorder				\n"	\
> +	"	move	%2, $0					\n"	\
> +	"	move	%3, $0					\n"	\
> +	"	b	1f					\n"	\
> +	"	 li	%4, 0x21				\n"	\
> +	"0:							\n"	\
> +	"	sll	$1, %0, 0x1				\n"	\
> +	"	srl	%3, %0, 0x1f				\n"	\
> +	"	or	%0, $1, %5				\n"	\
> +	"	sll	%1, %1, 0x1				\n"	\
> +	"	sll	%2, %2, 0x1				\n"	\
> +	"1:							\n"	\
> +	"	bnez	%3, 2f					\n"	\
> +	"	 sltu	%5, %0, %z6				\n"	\
> +	"	bnez	%5, 3f					\n"	\
> +	"2:							\n"	\
> +	"	 addiu	%4, %4, -1				\n"	\
> +	"	subu	%0, %0, %z6				\n"	\
> +	"	addiu	%2, %2, 1				\n"	\
> +	"3:							\n"	\
> +	"	bnez	%4, 0b					\n"	\
> +	"	 srl	%5, %1, 0x1f				\n"	\
> +	"	.set	pop"						\
> +	: "=&r" (__mod32), "=&r" (__tmp),				\
> +	  "=&r" (__quot32), "=&r" (__cf),				\
> +	  "=&r" (__i), "=&r" (__tmp2)					\
> +	: "Jr" (base), "0" (high), "1" (low));				\
> +									\
> +	(res) = __quot32;						\
> +	__mod32;							\
> +})
> +
> +#define __div64_32(n, base) ({						\
> +	unsigned long __upper, __low, __high, __radix;			\
> +	unsigned long long __quot;					\
> +	unsigned long long __div;					\
> +	unsigned long __mod;						\
> +									\
> +	__div = (*n);							\
> +	__radix = (base);						\
> +									\
> +	__high = __div >> 32;						\
> +	__low = __div;							\
> +									\
> +	if (__high < __radix) {						\
> +		__upper = __high;					\
> +		__high = 0;						\
> +	} else {							\
> +		__upper = __high % __radix;				\
> +		__high /= __radix;					\
> +	}								\
> +									\
> +	__mod = do_div64_32(__low, __upper, __low, __radix);		\
> +									\
> +	__quot = __high;						\
> +	__quot = __quot << 32 | __low;					\
> +	(*n) = __quot;							\
> +	__mod;								\
> +})
> +
> +long long __udivdi3(long long u, word_type b)
> +{
> +	long long ret = u;
> +
> +	__div64_32(&ret, b);
> +	return ret;
> +}

the call to __udivdi3() won't be generated on MIPS64, so the code should 
be guarded with #if BITS_PER_LONG == 32 as done in Linux. Also we could 
simply use the generic div64.h implementation.

I played around a bit and following simplified code compiles on various 
MIPS32 and MIPS64 boards. (E.g. "echo CONFIG_FS_SQUASHFS=y >> 
configs/malta[|64|el|64el]_defconfig && make malta[|64|el|64el]_defconfig")



/* SPDX-License-Identifier: GPL-2.0 */

#include "libgcc.h"

#if BITS_PER_LONG == 32

#include <div64.h>

long long __udivdi3(long long u, word_type b)
{
	long long ret = u;

	__div64_32(&ret, b);
	return ret;
}

#endif /* BITS_PER_LONG == 32 */

What do you think?
Linus Walleij Sept. 21, 2023, 8:45 p.m. UTC | #2
On Thu, Sep 21, 2023 at 3:42 PM Daniel Schwierzeck
<daniel.schwierzeck@gmail.com> wrote:

> I played around a bit and following simplified code compiles on various
> MIPS32 and MIPS64 boards. (E.g. "echo CONFIG_FS_SQUASHFS=y >>
> configs/malta[|64|el|64el]_defconfig && make malta[|64|el|64el]_defconfig")
>
>
>
> /* SPDX-License-Identifier: GPL-2.0 */
>
> #include "libgcc.h"
>
> #if BITS_PER_LONG == 32
>
> #include <div64.h>
>
> long long __udivdi3(long long u, word_type b)
> {
>         long long ret = u;
>
>         __div64_32(&ret, b);
>         return ret;
> }
>
> #endif /* BITS_PER_LONG == 32 */
>
> What do you think?

Looks good to me!

You can just modify the patch, sign off and apply,
I guess? Go ahead!

Yours,
Linus Walleij
diff mbox series

Patch

diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index 9ee1fcb5c702..1621cc9a1ff9 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -14,4 +14,4 @@  obj-$(CONFIG_CMD_BOOTM) += bootm.o
 obj-$(CONFIG_CMD_GO) += boot.o
 obj-$(CONFIG_SPL_BUILD) += spl.o
 
-lib-$(CONFIG_USE_PRIVATE_LIBGCC) += ashldi3.o ashrdi3.o lshrdi3.o
+lib-$(CONFIG_USE_PRIVATE_LIBGCC) += ashldi3.o ashrdi3.o lshrdi3.o udivdi3.o
diff --git a/arch/mips/lib/udivdi3.c b/arch/mips/lib/udivdi3.c
new file mode 100644
index 000000000000..6a4ee5fa46ab
--- /dev/null
+++ b/arch/mips/lib/udivdi3.c
@@ -0,0 +1,86 @@ 
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (C) 2000, 2004, 2021  Maciej W. Rozycki
+ * Copyright (C) 2003, 07 Ralf Baechle (ralf@linux-mips.org)
+ */
+
+#include "libgcc.h"
+
+/*
+ * No traps on overflows for any of these...
+ */
+
+#define do_div64_32(res, high, low, base) ({				\
+	unsigned long __cf, __tmp, __tmp2, __i;				\
+	unsigned long __quot32, __mod32;				\
+									\
+	__asm__(							\
+	"	.set	push					\n"	\
+	"	.set	noat					\n"	\
+	"	.set	noreorder				\n"	\
+	"	move	%2, $0					\n"	\
+	"	move	%3, $0					\n"	\
+	"	b	1f					\n"	\
+	"	 li	%4, 0x21				\n"	\
+	"0:							\n"	\
+	"	sll	$1, %0, 0x1				\n"	\
+	"	srl	%3, %0, 0x1f				\n"	\
+	"	or	%0, $1, %5				\n"	\
+	"	sll	%1, %1, 0x1				\n"	\
+	"	sll	%2, %2, 0x1				\n"	\
+	"1:							\n"	\
+	"	bnez	%3, 2f					\n"	\
+	"	 sltu	%5, %0, %z6				\n"	\
+	"	bnez	%5, 3f					\n"	\
+	"2:							\n"	\
+	"	 addiu	%4, %4, -1				\n"	\
+	"	subu	%0, %0, %z6				\n"	\
+	"	addiu	%2, %2, 1				\n"	\
+	"3:							\n"	\
+	"	bnez	%4, 0b					\n"	\
+	"	 srl	%5, %1, 0x1f				\n"	\
+	"	.set	pop"						\
+	: "=&r" (__mod32), "=&r" (__tmp),				\
+	  "=&r" (__quot32), "=&r" (__cf),				\
+	  "=&r" (__i), "=&r" (__tmp2)					\
+	: "Jr" (base), "0" (high), "1" (low));				\
+									\
+	(res) = __quot32;						\
+	__mod32;							\
+})
+
+#define __div64_32(n, base) ({						\
+	unsigned long __upper, __low, __high, __radix;			\
+	unsigned long long __quot;					\
+	unsigned long long __div;					\
+	unsigned long __mod;						\
+									\
+	__div = (*n);							\
+	__radix = (base);						\
+									\
+	__high = __div >> 32;						\
+	__low = __div;							\
+									\
+	if (__high < __radix) {						\
+		__upper = __high;					\
+		__high = 0;						\
+	} else {							\
+		__upper = __high % __radix;				\
+		__high /= __radix;					\
+	}								\
+									\
+	__mod = do_div64_32(__low, __upper, __low, __radix);		\
+									\
+	__quot = __high;						\
+	__quot = __quot << 32 | __low;					\
+	(*n) = __quot;							\
+	__mod;								\
+})
+
+long long __udivdi3(long long u, word_type b)
+{
+	long long ret = u;
+
+	__div64_32(&ret, b);
+	return ret;
+}