[U-Boot] [PATCH] ARM: Use do_div() instead of division for "long long".

From: Sergei Poselenov sposelenov@emcraft.com
Signed-off-by: Sergei Poselenov sposelenov@emcraft.com Signed-off-by: Wolfgang Denk wd@denx.de ---
With some (more recent) compiler versions there are problems because of the use of "long long" divisions in the U-Boot code. For ARM, this requires the __udivdi3 GCC library function, which currently is not present in lib_arm. This function was present in older 2.6 kernels, but at some point it was removed from here, with suggestion to use do_div() instead. In U-boot, the do_div() function is available, too, so this patch generally does the replacement of the "long long" divisions to do_div() to avoid the aforementions issues.
board/integratorcp/integratorcp.c | 7 ++++++- board/trab/tsc2000.c | 10 ++++++---- cpu/arm1176/s3c64xx/interrupts.c | 5 ++++- cpu/arm946es/config.mk | 7 +++++++ cpu/arm_intcm/config.mk | 7 +++++++ 5 files changed, 30 insertions(+), 6 deletions(-)
diff --git a/board/integratorcp/integratorcp.c b/board/integratorcp/integratorcp.c index d6d6e13..220513f 100644 --- a/board/integratorcp/integratorcp.c +++ b/board/integratorcp/integratorcp.c @@ -34,6 +34,7 @@ */
#include <common.h> +#include <div64.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -244,7 +245,11 @@ ulong get_timer_masked (void) total_count += lastdec - now; } lastdec = now; - timestamp = (ulong)(total_count/div_timer); + + /* Reuse "now" */ + now = total_count; + do_div(now, div_timer); + timestamp = now;
return timestamp; } diff --git a/board/trab/tsc2000.c b/board/trab/tsc2000.c index 382a85b..f13a5a9 100644 --- a/board/trab/tsc2000.c +++ b/board/trab/tsc2000.c @@ -27,6 +27,7 @@
#include <common.h> #include <s3c2400.h> +#include <div64.h> #include "tsc2000.h"
#include "Pt1000_temp_data.h" @@ -332,6 +333,7 @@ void tsc2000_reg_init (void) int tsc2000_interpolate(long value, long data[][2], long *result) { int i; + unsigned long long val;
/* the data is sorted and the first element is upper * limit so we can easily check for out-of-band values @@ -347,10 +349,10 @@ int tsc2000_interpolate(long value, long data[][2], long *result) result in 'long long'. */
- *result = data[i-1][1] + - ((unsigned long long)(data[i][1] - data[i-1][1]) - * (unsigned long long)(value - data[i-1][0])) - / (data[i][0] - data[i-1][0]); + val = ((unsigned long long)(data[i][1] - data[i-1][1]) + * (unsigned long long)(value - data[i-1][0])); + do_div(val, (data[i][0] - data[i-1][0])); + *result = data[i-1][1] + val;
return 0; } diff --git a/cpu/arm1176/s3c64xx/interrupts.c b/cpu/arm1176/s3c64xx/interrupts.c index 8356ae4..e34369f 100644 --- a/cpu/arm1176/s3c64xx/interrupts.c +++ b/cpu/arm1176/s3c64xx/interrupts.c @@ -41,6 +41,7 @@ #include <common.h> #include <asm/proc-armv/ptrace.h> #include <s3c6400.h> +#include <div64.h>
static ulong timer_load_val;
@@ -148,7 +149,9 @@ void reset_timer(void)
ulong get_timer_masked(void) { - return get_ticks() / (timer_load_val / (100 * CFG_HZ)); + unsigned long long res = get_ticks(); + do_div (res, (timer_load_val / (100 * CFG_HZ))); + return res; }
ulong get_timer(ulong base) diff --git a/cpu/arm946es/config.mk b/cpu/arm946es/config.mk index 81ca288..f774c7e 100644 --- a/cpu/arm946es/config.mk +++ b/cpu/arm946es/config.mk @@ -25,3 +25,10 @@ PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 \ -msoft-float
PLATFORM_CPPFLAGS += -march=armv4 +# ========================================================================= +# +# Supply options according to compiler version +# +# ========================================================================= +PLATFORM_CPPFLAGS +=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) +PLATFORM_RELFLAGS +=$(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) diff --git a/cpu/arm_intcm/config.mk b/cpu/arm_intcm/config.mk index 81ca288..f774c7e 100644 --- a/cpu/arm_intcm/config.mk +++ b/cpu/arm_intcm/config.mk @@ -25,3 +25,10 @@ PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 \ -msoft-float
PLATFORM_CPPFLAGS += -march=armv4 +# ========================================================================= +# +# Supply options according to compiler version +# +# ========================================================================= +PLATFORM_CPPFLAGS +=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) +PLATFORM_RELFLAGS +=$(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))

From: Sergei Poselenov sposelenov@emcraft.com
Signed-off-by: Sergei Poselenov sposelenov@emcraft.com Signed-off-by: Wolfgang Denk wd@denx.de ---
With some (more recent) compiler versions there are problems because of the use of "long long" divisions in the U-Boot code. For ARM, this requires the __udivdi3 GCC library function, which currently is not present in lib_arm. This function was present in older 2.6 kernels, but at some point it was removed from here, with suggestion to use do_div() instead. In U-boot, the do_div() function is available, too, so this patch generally does the replacement of the "long long" divisions to do_div() to avoid the aforementions issues.
board/integratorcp/integratorcp.c | 7 ++++++- board/trab/tsc2000.c | 10 ++++++---- cpu/arm1176/s3c64xx/interrupts.c | 5 ++++- 3 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/board/integratorcp/integratorcp.c b/board/integratorcp/integratorcp.c index d6d6e13..220513f 100644 --- a/board/integratorcp/integratorcp.c +++ b/board/integratorcp/integratorcp.c @@ -34,6 +34,7 @@ */
#include <common.h> +#include <div64.h>
DECLARE_GLOBAL_DATA_PTR;
@@ -244,7 +245,11 @@ ulong get_timer_masked (void) total_count += lastdec - now; } lastdec = now; - timestamp = (ulong)(total_count/div_timer); + + /* Reuse "now" */ + now = total_count; + do_div(now, div_timer); + timestamp = now;
return timestamp; } diff --git a/board/trab/tsc2000.c b/board/trab/tsc2000.c index 382a85b..f13a5a9 100644 --- a/board/trab/tsc2000.c +++ b/board/trab/tsc2000.c @@ -27,6 +27,7 @@
#include <common.h> #include <s3c2400.h> +#include <div64.h> #include "tsc2000.h"
#include "Pt1000_temp_data.h" @@ -332,6 +333,7 @@ void tsc2000_reg_init (void) int tsc2000_interpolate(long value, long data[][2], long *result) { int i; + unsigned long long val;
/* the data is sorted and the first element is upper * limit so we can easily check for out-of-band values @@ -347,10 +349,10 @@ int tsc2000_interpolate(long value, long data[][2], long *result) result in 'long long'. */
- *result = data[i-1][1] + - ((unsigned long long)(data[i][1] - data[i-1][1]) - * (unsigned long long)(value - data[i-1][0])) - / (data[i][0] - data[i-1][0]); + val = ((unsigned long long)(data[i][1] - data[i-1][1]) + * (unsigned long long)(value - data[i-1][0])); + do_div(val, (data[i][0] - data[i-1][0])); + *result = data[i-1][1] + val;
return 0; } diff --git a/cpu/arm1176/s3c64xx/interrupts.c b/cpu/arm1176/s3c64xx/interrupts.c index 8356ae4..e34369f 100644 --- a/cpu/arm1176/s3c64xx/interrupts.c +++ b/cpu/arm1176/s3c64xx/interrupts.c @@ -41,6 +41,7 @@ #include <common.h> #include <asm/proc-armv/ptrace.h> #include <s3c6400.h> +#include <div64.h>
static ulong timer_load_val;
@@ -148,7 +149,9 @@ void reset_timer(void)
ulong get_timer_masked(void) { - return get_ticks() / (timer_load_val / (100 * CFG_HZ)); + unsigned long long res = get_ticks(); + do_div (res, (timer_load_val / (100 * CFG_HZ))); + return res; }
ulong get_timer(ulong base)

From: Sergei Poselenov sposelenov@emcraft.com
This patch fixes warnings like this:
start.S:0: warning: target CPU does not support interworking
which come from some ARM cross compilers and are caused by hard-coded (with "--with-cpu=arm9" configuration option) ARM targets (which support ARM Thumb instructions), while the ARM target selected from the command line (with "-march=armv4") doesn't support Thumb instructions.
This warning is issued by the compiler regardless of the real use of the Thumb instructions in code.
To fix this problem, we use options according to compiler version being used.
Signed-off-by: Sergei Poselenov sposelenov@emcraft.com Signed-off-by: Wolfgang Denk wd@denx.de ---
cpu/arm946es/config.mk | 7 +++++++ cpu/arm_intcm/config.mk | 7 +++++++ 2 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/cpu/arm946es/config.mk b/cpu/arm946es/config.mk index 81ca288..f774c7e 100644 --- a/cpu/arm946es/config.mk +++ b/cpu/arm946es/config.mk @@ -25,3 +25,10 @@ PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 \ -msoft-float
PLATFORM_CPPFLAGS += -march=armv4 +# ========================================================================= +# +# Supply options according to compiler version +# +# ========================================================================= +PLATFORM_CPPFLAGS +=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) +PLATFORM_RELFLAGS +=$(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,)) diff --git a/cpu/arm_intcm/config.mk b/cpu/arm_intcm/config.mk index 81ca288..f774c7e 100644 --- a/cpu/arm_intcm/config.mk +++ b/cpu/arm_intcm/config.mk @@ -25,3 +25,10 @@ PLATFORM_RELFLAGS += -fno-strict-aliasing -fno-common -ffixed-r8 \ -msoft-float
PLATFORM_CPPFLAGS += -march=armv4 +# ========================================================================= +# +# Supply options according to compiler version +# +# ========================================================================= +PLATFORM_CPPFLAGS +=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) +PLATFORM_RELFLAGS +=$(call cc-option,-mshort-load-bytes,$(call cc-option,-malignment-traps,))

On Tue, 9 Sep 2008, Wolfgang Denk wrote:
diff --git a/board/trab/tsc2000.c b/board/trab/tsc2000.c index 382a85b..f13a5a9 100644 --- a/board/trab/tsc2000.c +++ b/board/trab/tsc2000.c @@ -27,6 +27,7 @@
#include <common.h> #include <s3c2400.h> +#include <div64.h> #include "tsc2000.h"
#include "Pt1000_temp_data.h" @@ -332,6 +333,7 @@ void tsc2000_reg_init (void) int tsc2000_interpolate(long value, long data[][2], long *result) { int i;
unsigned long long val;
/* the data is sorted and the first element is upper
- limit so we can easily check for out-of-band values
@@ -347,10 +349,10 @@ int tsc2000_interpolate(long value, long data[][2], long *result) result in 'long long'. */
- *result = data[i-1][1] +
((unsigned long long)(data[i][1] - data[i-1][1])
* (unsigned long long)(value - data[i-1][0]))
/ (data[i][0] - data[i-1][0]);
- val = ((unsigned long long)(data[i][1] - data[i-1][1])
* (unsigned long long)(value - data[i-1][0]));
- do_div(val, (data[i][0] - data[i-1][0]));
Looking at how do_div() is defined, and it handles its parameters carefully, one shouldn't need the extra parenthesis here, i.e.,
+ do_div(val, data[i][0] - data[i-1][0]);
should be enough.
*result = data[i-1][1] + val;
return 0;
} diff --git a/cpu/arm1176/s3c64xx/interrupts.c b/cpu/arm1176/s3c64xx/interrupts.c index 8356ae4..e34369f 100644 --- a/cpu/arm1176/s3c64xx/interrupts.c +++ b/cpu/arm1176/s3c64xx/interrupts.c @@ -41,6 +41,7 @@ #include <common.h> #include <asm/proc-armv/ptrace.h> #include <s3c6400.h> +#include <div64.h>
static ulong timer_load_val;
@@ -148,7 +149,9 @@ void reset_timer(void)
ulong get_timer_masked(void) {
- return get_ticks() / (timer_load_val / (100 * CFG_HZ));
- unsigned long long res = get_ticks();
- do_div (res, (timer_load_val / (100 * CFG_HZ)));
Same here.
+ do_div (res, timer_load_val / (100 * CFG_HZ));
Thanks Guennadi --- Guennadi Liakhovetski, Ph.D.
DENX Software Engineering GmbH, MD: Wolfgang Denk & Detlev Zundel HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany Phone: +49-8142-66989-0 Fax: +49-8142-66989-80 Email: office@denx.de

Dear Guennadi Liakhovetski,
In message Pine.LNX.4.64.0809092249070.9737@axis700.grange you wrote:
- do_div(val, (data[i][0] - data[i-1][0]));
Looking at how do_div() is defined, and it handles its parameters carefully, one shouldn't need the extra parenthesis here, i.e.,
The are not exactly need (and actually a remainder from the copy & paste of the old code), but on the other hand they don't hurt either, and they make the argument's easier to parse, at least to my eyes.
Best regards,
Wolfgang Denk

On Tue, 9 Sep 2008 02:08:31 +0200 Wolfgang Denk wd@denx.de wrote:
From: Sergei Poselenov sposelenov@emcraft.com
Signed-off-by: Sergei Poselenov sposelenov@emcraft.com Signed-off-by: Wolfgang Denk wd@denx.de
With some (more recent) compiler versions there are problems because of the use of "long long" divisions in the U-Boot code. For ARM, this requires the __udivdi3 GCC library function, which currently is not present in lib_arm. This function was present in older 2.6 kernels, but at some point it was removed from here, with suggestion to use do_div() instead. In U-boot, the do_div() function is available, too, so this patch generally does the replacement of the "long long" divisions to do_div() to avoid the aforementions issues.
Could you please move that nice explanation above the '---' line? I think it's really useful to have the reason behind a particular change in the commit history.
Haavard
participants (3)
-
Guennadi Liakhovetski
-
Haavard Skinnemoen
-
Wolfgang Denk