The problem: The system clock under QEMU (PREP architecture) increments at four times the correct wall clock rate.
Comments: prep_calibrate_decr() hardcoded the divisor for the timebase to be '4'. This value should be read from the residual data that is provided by PREP at boot. QEMU for example provides '1000' for this value. The other constants in the calculation have been adjusted to correct account for the scaling (x1000). If the residual data is not correct, the problem can also be worked around by specifying 'noresidual' on the command line. This specification forces the code to use the real time clock to calculate the correct decrementer value. Also provided is the inclusion of some additional debug data (printk) and the correction of an unrelated printk to include KERN_CRIT. These printk statements are only executed on a PREP machine boot. Tested on: QEMU This fix has not been tested on real PREP hardware. If it doesn't appear to work on such hardware, please return the kernel boot printk's to the patch author for further work. Test: # Watch the ticks... they should be 1/second. while : do sleep 1 echo -n . done Note: This code is ppc (not powerpc) architure -- and is in neither -tip nor -mm tree. The patch is directly useful for the 2.6.27 prepatch tree and for 2.6.26 and below. It may be necessary to re-work the patch for the tip tree... once PREP is added to it. Signed-off-by: Bruce Beare <[EMAIL PROTECTED]> --- linux-2.6.26/arch/ppc/platforms/prep_setup.orig.c Wed Aug 13 15:29:04 2008 +++ linux-2.6.26/arch/ppc/platforms/prep_setup.c Wed Aug 13 16:17:41 2008 @@ -847,15 +847,19 @@ static void __init prep_calibrate_decr(void) { if (have_residual_data) { - unsigned long freq, divisor = 4; + unsigned long freq, divisor; if ( res->VitalProductData.ProcessorBusHz ) { + divisor = res->VitalProductData.TimeBaseDivisor; freq = res->VitalProductData.ProcessorBusHz; - printk("time_init: decrementer frequency = %lu.%.6lu MHz\n", - (freq/divisor)/1000000, - (freq/divisor)%1000000); - tb_to_us = mulhwu_scale_factor(freq/divisor, 1000000); - tb_ticks_per_jiffy = freq / HZ / divisor; + tb_to_us = mulhwu_scale_factor(freq/divisor, 1000); + tb_ticks_per_jiffy = freq / HZ / divisor * 1000; + + printk(KERN_CRIT "prep_calibrate_decr: " + "frequency = %lu.%.6lu MHz," + " tb_to_us: %d, tb_ticks_per_jiffy: %d\n", + (freq/divisor)/1000, (freq/divisor)%1000, + tb_to_us, tb_ticks_per_jiffy); } } else @@ -914,7 +918,7 @@ smp_prep_kick_cpu(int nr) { *(unsigned long *)KERNELBASE = nr; asm volatile("dcbf 0,%0"::"r"(KERNELBASE):"memory"); - printk("CPU1 released, waiting\n"); + printk(KERN_CRIT "CPU1 released, waiting\n"); } static void __init @@ -972,6 +976,13 @@ prep_init(unsigned long r3, unsigned lon memcpy((void *)res,(void *)(r3+KERNELBASE), sizeof(RESIDUAL)); } + if (have_residual_data) + printk(KERN_INFO "Residual data for model: %s, " + "TimeBaseDivisor: %lu, ProcHz: %lu, BusHz: %lu\n", + res->VitalProductData.PrintableModel, + res->VitalProductData.TimeBaseDivisor, + res->VitalProductData.ProcessorHz, + res->VitalProductData.ProcessorBusHz); #endif isa_io_base = PREP_ISA_IO_BASE; @@ -996,8 +1007,10 @@ prep_init(unsigned long r3, unsigned lon #ifdef CONFIG_PREP_RESIDUAL /* Switch off all residual data processing if the user requests it */ - if (strstr(cmd_line, "noresidual") != NULL) - res = NULL; + if (strstr(cmd_line, "noresidual") != NULL) { + printk(KERN_INFO "Disabled PREP residual data\n"); + res = NULL; + } #endif /* Initialise progress early to get maximum benefit */ _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@ozlabs.org https://ozlabs.org/mailman/listinfo/linuxppc-dev