On Tue, Apr 26, 2011 at 1:48 PM, Barry Song <21cn...@gmail.com> wrote: > 2011/4/26 Barry Song <21cn...@gmail.com>: >> Hi Michael, >> >> 2011/4/26 Michael Hope <michael.h...@linaro.org>: >>> Hi Barry. I think the toolchain is operating correctly here. The >>> current version recognises a divide followed by a modulo and optimises >>> this into a call to the standard EABI function __aeabi__uldivmod(). >>> Note the code: >>> >>> do_div(Kpart, source); >>> >>> K = Kpart & 0xFFFFFFFF; >>> >>> /* Check if we need to round */ >>> if ((K % 10) >= 5) >>> K += 5; >>> >>> This function is provided by libgcc for normal applications. The >>> kernel provides it's own versions in arch/arm/lib/lib1funcs.s but is >>> missing __aeabi_uldivmod (note the 'l' for 64 bit). >> In fact the problem happen ealier: >> >> if (Ndiv < 6) { >> source /= 2; >> pll_div->pre_div = 1; >> Ndiv = target / source; >> } else >> pll_div->pre_div = 0; >> >> if ((Ndiv < 6) || (Ndiv > 12)) >> printk(KERN_WARNING >> "WM8974 N value %u outwith recommended range!\n", >> Ndiv); >> >> pll_div->n = Ndiv; >> Nmod = target % source; >> Kpart = FIXED_PLL_SIZE * (long long)Nmod; >> >> do_div(Kpart, source); >> >> If commenting "source /= 2", the problem disappear. >> >> > Or if adding one line before do_div, all will be ok. > asm("" : "+r"(source)); > do_div(Kpart, source);
Hi Barry. I can reproduce the problem in Linaro GCC 4.5-2011.04 and GCC 4.5.2. It does not exist in GCC 4.6.0. wm8974_set_dai_pll() inlines the call to pll_factors() and leaves a .globl reference to __aeabi_uldivmod in the code. This function is never called. Marking pll_factors() as __attribute__((noinline)) also works around the problem. I've logged http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48783 upstream and recorded this as LP: #771551. -- Michael _______________________________________________ linaro-toolchain mailing list linaro-toolchain@lists.linaro.org http://lists.linaro.org/mailman/listinfo/linaro-toolchain