Subject: [PATCH] MIPS: Handle removal of 'h' constraint in GCC 4.4

From: David Daney <[email-masked]>
Date: Tue, 24 Feb 2009 15:04:22 -0800

Due to the removal of the 'h' asm constraint in GCC-4.4, we need to
adjust the computation in delay.h

Signed-off-by: David Daney <[email-masked]>
---

Tested on 64-bit kernel (Cavium Octeon).

 arch/mips/include/asm/compiler.h |    7 +++++++
 arch/mips/include/asm/delay.h    |   10 +++++++++-
 2 files changed, 16 insertions(+), 1 deletions(-)

diff --git a/arch/mips/include/asm/compiler.h b/arch/mips/include/asm/compiler.h
index 71f5c5c..1f0954d 100644
--- a/arch/mips/include/asm/compiler.h
+++ b/arch/mips/include/asm/compiler.h
@@ -16,4 +16,11 @@
 #define GCC_REG_ACCUM "accum"
 #endif
 
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
+#define GCC_NO_H_CONSTRAINT
+#ifdef CONFIG_64BIT
+typedef unsigned int uint128_t __attribute__((mode(TI)));
+#endif
+#endif
+
 #endif /* _ASM_COMPILER_H */
diff --git a/arch/mips/include/asm/delay.h b/arch/mips/include/asm/delay.h
index b0bccd2..9be0ba7 100644
--- a/arch/mips/include/asm/delay.h
+++ b/arch/mips/include/asm/delay.h
@@ -62,8 +62,9 @@ static inline void __delay(unsigned long loops)
 
 static inline void __udelay(unsigned long usecs, unsigned long lpj)
 {
+#ifndef GCC_NO_H_CONSTRAINT
 	unsigned long hi, lo;
-
+#endif
 	/*
 	 * The rates of 128 is rounded wrongly by the catchall case
 	 * for 64-bit.  Excessive precission?  Probably ...
@@ -77,6 +78,12 @@ static inline void __udelay(unsigned long usecs, unsigned long lpj)
 	                           0x80000000ULL) >> 32);
 #endif
 
+#ifdef GCC_NO_H_CONSTRAINT
+	if (sizeof(long) == 4)
+		usecs = ((u64)usecs * lpj) >> 32;
+	else
+		usecs = ((uint128_t)usecs * lpj) >> 64;
+#else
 	if (sizeof(long) == 4)
 		__asm__("multu\t%2, %3"
 		: "=h" (usecs), "=l" (lo)
@@ -92,6 +99,7 @@ static inline void __udelay(unsigned long usecs, unsigned long lpj)
 		: "=r" (usecs), "=h" (hi), "=l" (lo)
 		: "r" (usecs), "r" (lpj)
 		: GCC_REG_ACCUM);
+#endif
 
 	__delay(usecs);
 }
-- 
1.5.6.6

---

From: "Maciej W. Rozycki" <[email-masked]>
Date: Wed, 25 Feb 2009 01:25:07 +0000 (GMT)

I suggest to call it u128 in line with all the other such types (and 
place it in <asm/types.h>?).  Also it might be more reasonable to call the 
macro something like GCC_HAS_EXT64_MULT or suchlike as in my opinion we 
should prefer using C code for a calculation like this even if the "h" 
constraint still worked.  We might want to have i128 too. :)

>  		: "=r" (usecs), "=h" (hi), "=l" (lo)

 Ouch, this is horribly ugly.  It begs for making the conditional chunks a 
pair of separate static inline functions.  You could then do something 
like __delay(__usecs_to_loops(usecs, lpj)) and simply have two variants of 
__usecs_to_loops() with no need to chop code with #ifdefs in the middle.

  Maciej

---

From: Ralf Baechle <[email-masked]>
Date: Thu, 26 Feb 2009 16:58:00 +0000

> adjust the computation in delay.h

It's time to take a step back and think over the whole thing once more.

Inlining __udelay can be problematic on some processors where the
execution performance of the delay loop will be different if the loop is
crossing a cacheline or not.  That seems to particularly hit R10000
systems often.  The number of the loop interations does the wrong tradeoff
between accuracy and the value range needed.  The resulting overflows on a
HZ=128 4000 BogoMIPS machine are fantastic :-)

Time to reimplement udelay I'd say.

  Ralf