[POWERPC] Move iSeries_tb_recal into its own late_initcall.
authorTony Breeds <tony@bakeyournoodle.com>
Fri, 22 Jun 2007 06:54:30 +0000 (16:54 +1000)
committerPaul Mackerras <paulus@samba.org>
Thu, 28 Jun 2007 09:19:23 +0000 (19:19 +1000)
Currently iSeries will recalibrate the cputime_factors in the first
settimeofday() call.

It seems the reason for doing this is to ensure a resaonable time delta after
time_init().  On current kernels (with udev), this call is made 40-60 seconds
into the boot process, by moving it to a late initcall it is called
approximately 5 seconds after time_init() is called.  This is sufficient to
recalibrate the timebase.

Signed-off-by: Tony Breeds <tony@bakeyournoodle.com>
CC: Stephen Rothwell <sfr@canb.auug.org.au>
Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/kernel/time.c
arch/powerpc/platforms/iseries/setup.c
include/asm-powerpc/time.h

index 43c687a..66d2db7 100644 (file)
@@ -77,9 +77,8 @@
 /* keep track of when we need to update the rtc */
 time_t last_rtc_update;
 #ifdef CONFIG_PPC_ISERIES
-unsigned long iSeries_recal_titan = 0;
-unsigned long iSeries_recal_tb = 0; 
-static unsigned long first_settimeofday = 1;
+static unsigned long __initdata iSeries_recal_titan;
+static signed long __initdata iSeries_recal_tb;
 #endif
 
 /* The decrementer counts down by 128 every 128ns on a 601. */
@@ -556,10 +555,15 @@ EXPORT_SYMBOL(profile_pc);
  * returned by the service processor for the timebase frequency.  
  */
 
-static void iSeries_tb_recal(void)
+static int __init iSeries_tb_recal(void)
 {
        struct div_result divres;
        unsigned long titan, tb;
+
+       /* Make sure we only run on iSeries */
+       if (!firmware_has_feature(FW_FEATURE_ISERIES))
+               return -ENODEV;
+
        tb = get_tb();
        titan = HvCallXm_loadTod();
        if ( iSeries_recal_titan ) {
@@ -600,8 +604,18 @@ static void iSeries_tb_recal(void)
        }
        iSeries_recal_titan = titan;
        iSeries_recal_tb = tb;
+
+       return 0;
 }
-#endif
+late_initcall(iSeries_tb_recal);
+
+/* Called from platform early init */
+void __init iSeries_time_init_early(void)
+{
+       iSeries_recal_tb = get_tb();
+       iSeries_recal_titan = HvCallXm_loadTod();
+}
+#endif /* CONFIG_PPC_ISERIES */
 
 /*
  * For iSeries shared processors, we have to let the hypervisor
@@ -765,12 +779,6 @@ int do_settimeofday(struct timespec *tv)
         * to the RTC again, or write to the RTC but then they don't call
         * settimeofday to perform this operation.
         */
-#ifdef CONFIG_PPC_ISERIES
-       if (firmware_has_feature(FW_FEATURE_ISERIES) && first_settimeofday) {
-               iSeries_tb_recal();
-               first_settimeofday = 0;
-       }
-#endif
 
        /* Make userspace gettimeofday spin until we're done. */
        ++vdso_data->tb_update_count;
index 7f5dcee..13a8b19 100644 (file)
@@ -79,8 +79,6 @@ extern void iSeries_pci_final_fixup(void);
 static void iSeries_pci_final_fixup(void) { }
 #endif
 
-extern unsigned long iSeries_recal_tb;
-extern unsigned long iSeries_recal_titan;
 
 struct MemoryBlock {
        unsigned long absStart;
@@ -292,8 +290,8 @@ static void __init iSeries_init_early(void)
 {
        DBG(" -> iSeries_init_early()\n");
 
-       iSeries_recal_tb = get_tb();
-       iSeries_recal_titan = HvCallXm_loadTod();
+       /* Snapshot the timebase, for use in later recalibration */
+       iSeries_time_init_early();
 
        /*
         * Initialize the DMA/TCE management
index 2d00e13..d7f5ddf 100644 (file)
@@ -240,5 +240,7 @@ extern void snapshot_timebases(void);
 #define snapshot_timebases()                   do { } while (0)
 #endif
 
+extern void iSeries_time_init_early(void);
+
 #endif /* __KERNEL__ */
 #endif /* __POWERPC_TIME_H */