x86: Add timer_init to x86_init_ops
authorThomas Gleixner <tglx@linutronix.de>
Wed, 19 Aug 2009 13:37:03 +0000 (15:37 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Mon, 31 Aug 2009 07:35:46 +0000 (09:35 +0200)
The timer init code is convoluted with several quirks and the paravirt
timer chooser. Figuring out which code path is actually taken is not
for the faint hearted.

Move the numaq TSC quirk to tsc_pre_init x86_init_ops function and
replace the paravirt time chooser and the remaining x86 quirk with a
simple x86_init_ops function.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
17 files changed:
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/setup.h
arch/x86/include/asm/time.h
arch/x86/include/asm/timer.h
arch/x86/include/asm/x86_init.h
arch/x86/kernel/apic/numaq_32.c
arch/x86/kernel/paravirt.c
arch/x86/kernel/setup.c
arch/x86/kernel/time_32.c
arch/x86/kernel/time_64.c
arch/x86/kernel/tsc.c
arch/x86/kernel/visws_quirks.c
arch/x86/kernel/vmi_32.c
arch/x86/kernel/x86_init.c
arch/x86/lguest/boot.c
arch/x86/xen/enlighten.c

index 825674a968d11ddaf21220c729aba27ea657f5c7..11a4ba7b209cb24d2707a272ed31912258e10727 100644 (file)
@@ -34,11 +34,6 @@ static inline int set_wallclock(unsigned long nowtime)
        return PVOP_CALL1(int, pv_time_ops.set_wallclock, nowtime);
 }
 
-static inline void (*choose_time_init(void))(void)
-{
-       return pv_time_ops.time_init;
-}
-
 /* The paravirtualized CPUID instruction. */
 static inline void __cpuid(unsigned int *eax, unsigned int *ebx,
                           unsigned int *ecx, unsigned int *edx)
index 1da89276d14202eea2d1915b81a7759deed681de..0d812e592e3bbe9d724b52a60e5f7c8c08ccacf5 100644 (file)
@@ -88,8 +88,6 @@ struct pv_lazy_ops {
 };
 
 struct pv_time_ops {
-       void (*time_init)(void);
-
        /* Set and set time of day */
        unsigned long (*get_wallclock)(void);
        int (*set_wallclock)(unsigned long);
index 58b58952b80dcaf0e1387cba3d98a4107c4fc8d9..861e1fe2303b7a6333e3bcf7a03fdef854776666 100644 (file)
@@ -5,24 +5,6 @@
 
 #define COMMAND_LINE_SIZE 2048
 
-#ifndef __ASSEMBLY__
-
-#include <asm/x86_init.h>
-
-/*
- * Any setup quirks to be performed?
- */
-
-struct x86_quirks {
-       int (*arch_pre_time_init)(void);
-       int (*arch_time_init)(void);
-};
-
-extern void x86_quirk_pre_time_init(void);
-extern void x86_quirk_time_init(void);
-
-#endif /* __ASSEMBLY__ */
-
 #ifdef __i386__
 
 #include <linux/pfn.h>
@@ -42,6 +24,7 @@ extern void x86_quirk_time_init(void);
 
 #ifndef __ASSEMBLY__
 #include <asm/bootparam.h>
+#include <asm/x86_init.h>
 
 /* Interrupt control for vSMPowered x86_64 systems */
 #ifdef CONFIG_X86_64
@@ -60,11 +43,11 @@ static inline void visws_early_detect(void) { }
 static inline int is_visws_box(void) { return 0; }
 #endif
 
-extern struct x86_quirks *x86_quirks;
 extern unsigned long saved_video_mode;
 
 extern void reserve_standard_io_resources(void);
 extern void i386_reserve_resources(void);
+extern void setup_default_timer_irq(void);
 
 #ifndef _SETUP
 
index 50c733aac421b2a850238590fd0820a186bfcab7..91bb162b5a3185b198b98d0e934e06ef8000346d 100644 (file)
@@ -54,7 +54,6 @@ extern void time_init(void);
 
 #define get_wallclock() native_get_wallclock()
 #define set_wallclock(x) native_set_wallclock(x)
-#define choose_time_init() hpet_time_init
 
 #endif /* CONFIG_PARAVIRT */
 
index 20ca9c4d46867c7cbdf7228951e818101350159b..e854c7ab41697c00fba0d0afd37cd0822dc1b98d 100644 (file)
@@ -12,8 +12,7 @@ unsigned long native_calibrate_tsc(void);
 
 #ifdef CONFIG_X86_32
 extern int timer_ack;
-extern irqreturn_t timer_interrupt(int irq, void *dev_id);
-#endif /* CONFIG_X86_32 */
+#endif
 extern int recalibrate_cpu_khz(void);
 
 extern int no_timer_check;
index b7d258f4c40148bf47680dc8a9f3a197717fda71..f8bdd2271a04cd3e3f09a431e2edb5c6a271382b 100644 (file)
@@ -82,9 +82,13 @@ struct x86_init_paging {
  * struct x86_init_timers - platform specific timer setup
  * @setup_perpcu_clockev:      set up the per cpu clock event device for the
  *                             boot cpu
+ * @tsc_pre_init:              platform function called before TSC init
+ * @timer_init:                        initialize the platform timer (default PIT/HPET)
  */
 struct x86_init_timers {
        void (*setup_percpu_clockev)(void);
+       void (*tsc_pre_init)(void);
+       void (*timer_init)(void);
 };
 
 /**
index 71c5ea6458650913acaee3081fe3a863c2953239..f1ebed6bd15076840dfa5474f1c2a9c6a7e9e3af 100644 (file)
@@ -129,10 +129,9 @@ void __cpuinit numaq_tsc_disable(void)
        }
 }
 
-static int __init numaq_pre_time_init(void)
+static void __init numaq_tsc_init(void)
 {
        numaq_tsc_disable();
-       return 0;
 }
 
 static inline int generate_logical_apicid(int quad, int phys_apicid)
@@ -262,11 +261,6 @@ static void __init smp_read_mpc_oem(struct mpc_table *mpc)
        }
 }
 
-static struct x86_quirks numaq_x86_quirks __initdata = {
-       .arch_pre_time_init             = numaq_pre_time_init,
-       .arch_time_init                 = NULL,
-};
-
 static __init void early_check_numaq(void)
 {
        /*
@@ -281,13 +275,13 @@ static __init void early_check_numaq(void)
                early_get_smp_config();
 
        if (found_numaq) {
-               x86_quirks = &numaq_x86_quirks;
                x86_init.mpparse.mpc_record = numaq_mpc_record;
                x86_init.mpparse.setup_ioapic_ids = x86_init_noop;
                x86_init.mpparse.mpc_apic_id = mpc_apic_id;
                x86_init.mpparse.smp_read_mpc_oem = smp_read_mpc_oem;
                x86_init.mpparse.mpc_oem_pci_bus = mpc_oem_pci_bus;
                x86_init.mpparse.mpc_oem_bus_info = mpc_oem_bus_info;
+               x86_init.timers.tsc_pre_init = numaq_tsc_init;
        }
 }
 
index 1ed32c79679de10b0c6ab600d5bc922afc246928..9c0e644a76dc0cca091d099432dea463926f8554 100644 (file)
@@ -306,7 +306,6 @@ struct pv_init_ops pv_init_ops = {
 };
 
 struct pv_time_ops pv_time_ops = {
-       .time_init = hpet_time_init,
        .get_wallclock = native_get_wallclock,
        .set_wallclock = native_set_wallclock,
        .sched_clock = native_sched_clock,
index 43ec6aa175bd931f00585d43811b77ddceef1c2f..bb207a47c631cbfb4773edfdb5d19846504f4e1a 100644 (file)
@@ -626,10 +626,6 @@ static int __init setup_elfcorehdr(char *arg)
 early_param("elfcorehdr", setup_elfcorehdr);
 #endif
 
-static struct x86_quirks default_x86_quirks __initdata;
-
-struct x86_quirks *x86_quirks __initdata = &default_x86_quirks;
-
 #ifdef CONFIG_X86_RESERVE_LOW_64K
 static int __init dmi_low_memory_corruption(const struct dmi_system_id *d)
 {
@@ -1016,45 +1012,6 @@ void __init setup_arch(char **cmdline_p)
 
 #ifdef CONFIG_X86_32
 
-static struct irqaction irq0  = {
-       .handler = timer_interrupt,
-       .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
-       .name = "timer"
-};
-
-/**
- * x86_quirk_pre_time_init - do any specific initialisations before.
- *
- **/
-void __init x86_quirk_pre_time_init(void)
-{
-       if (x86_quirks->arch_pre_time_init)
-               x86_quirks->arch_pre_time_init();
-}
-
-/**
- * x86_quirk_time_init - do any specific initialisations for the system timer.
- *
- * Description:
- *     Must plug the system timer interrupt source at HZ into the IRQ listed
- *     in irq_vectors.h:TIMER_IRQ
- **/
-void __init x86_quirk_time_init(void)
-{
-       if (x86_quirks->arch_time_init) {
-               /*
-                * A nonzero return code does not mean failure, it means
-                * that the architecture quirk does not want any
-                * generic (timer) setup to be performed after this:
-                */
-               if (x86_quirks->arch_time_init())
-                       return;
-       }
-
-       irq0.mask = cpumask_of_cpu(0);
-       setup_irq(0, &irq0);
-}
-
 static struct resource video_ram_resource = {
        .name   = "Video RAM area",
        .start  = 0xa0000,
index 5c5d87f0b2e1939988c3d642ea08cbbccd6a828a..89bbb52218b84a537d927ddd0aebcb8f6101316c 100644 (file)
@@ -72,7 +72,7 @@ EXPORT_SYMBOL(profile_pc);
  * Time Stamp Counter value at the time of the timer interrupt, so that
  * we later on can estimate the time of day more exactly.
  */
-irqreturn_t timer_interrupt(int irq, void *dev_id)
+static irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
        /* Keep nmi watchdog up to date */
        inc_irq_stat(irq0_irqs);
@@ -113,25 +113,37 @@ irqreturn_t timer_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-/* Duplicate of time_init() below, with hpet_enable part added */
+static struct irqaction irq0  = {
+       .handler = timer_interrupt,
+       .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
+       .name = "timer"
+};
+
+void __init setup_default_timer_irq(void)
+{
+       irq0.mask = cpumask_of_cpu(0);
+       setup_irq(0, &irq0);
+}
+
+/* Default timer init function */
 void __init hpet_time_init(void)
 {
        if (!hpet_enable())
                setup_pit_timer();
-       x86_quirk_time_init();
+       setup_default_timer_irq();
+}
+
+static void x86_late_time_init(void)
+{
+       x86_init.timers.timer_init();
 }
 
 /*
- * This is called directly from init code; we must delay timer setup in the
- * HPET case as we can't make the decision to turn on HPET this early in the
- * boot process.
- *
- * The chosen time_init function will usually be hpet_time_init, above, but
- * in the case of virtual hardware, an alternative function may be substituted.
+ * Initialize TSC and delay the periodic timer init to
+ * late x86_late_time_init() so ioremap works.
  */
 void __init time_init(void)
 {
-       x86_quirk_pre_time_init();
        tsc_init();
-       late_time_init = choose_time_init();
+       late_time_init = x86_late_time_init;
 }
index 5ba343e6184449775c51f21717ef985f8d7249d0..38a7df94c1075433ad8b59262f98b71514ff8993 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mca.h>
 #include <linux/nmi.h>
 
+#include <asm/x86_init.h>
 #include <asm/i8253.h>
 #include <asm/hpet.h>
 #include <asm/vgtod.h>
@@ -127,9 +128,13 @@ void __init hpet_time_init(void)
        setup_irq(0, &irq0);
 }
 
+static void x86_late_time_init(void)
+{
+       x86_init.timers.timer_init();
+}
+
 void __init time_init(void)
 {
        tsc_init();
-
-       late_time_init = choose_time_init();
+       late_time_init = x86_late_time_init;
 }
index 71f4368b357edf2a47fd035349bfbcd8c595e882..652bc214eebf4f669a60647a7793bedf0a98cd0c 100644 (file)
@@ -857,6 +857,8 @@ void __init tsc_init(void)
        u64 lpj;
        int cpu;
 
+       x86_init.timers.tsc_pre_init();
+
        if (!cpu_has_tsc)
                return;
 
index 2719091b335138d0b76f28e0fca6e94a1dd3e9f8..f068553a1b172121c76da62db29bebccf8272da5 100644 (file)
@@ -30,6 +30,7 @@
 #include <asm/setup.h>
 #include <asm/apic.h>
 #include <asm/e820.h>
+#include <asm/time.h>
 #include <asm/io.h>
 
 #include <linux/kernel_stat.h>
@@ -53,7 +54,7 @@ int is_visws_box(void)
        return visws_board_type >= 0;
 }
 
-static int __init visws_time_init(void)
+static void __init visws_time_init(void)
 {
        printk(KERN_INFO "Starting Cobalt Timer system clock\n");
 
@@ -66,11 +67,7 @@ static int __init visws_time_init(void)
        /* Enable (unmask) the timer interrupt */
        co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK);
 
-       /*
-        * Zero return means the generic timer setup code will set up
-        * the standard vector:
-        */
-       return 0;
+       setup_default_timer_irq();
 }
 
 /* Replaces the default init_ISA_irqs in the generic setup */
@@ -226,10 +223,6 @@ static void __init visws_find_smp_config(unsigned int reserve)
 
 static void visws_trap_init(void);
 
-static struct x86_quirks visws_x86_quirks __initdata = {
-       .arch_time_init         = visws_time_init,
-};
-
 void __init visws_early_detect(void)
 {
        int raw;
@@ -241,17 +234,14 @@ void __init visws_early_detect(void)
                return;
 
        /*
-        * Install special quirks for timer, interrupt and memory setup:
-        * Fall back to generic behavior for traps:
-        * Override generic MP-table parsing:
+        * Override the default platform setup functions
         */
-       x86_quirks = &visws_x86_quirks;
-
        x86_init.resources.memory_setup = visws_memory_setup;
        x86_init.mpparse.get_smp_config = visws_get_smp_config;
        x86_init.mpparse.find_smp_config = visws_find_smp_config;
        x86_init.irqs.pre_vector_init = visws_pre_intr_init;
        x86_init.irqs.trap_init = visws_trap_init;
+       x86_init.timers.timer_init = visws_time_init;
 
        /*
         * Install reboot quirks:
index b43b6685cae1e8b205573152838c1bec7908edf8..cd7d0fbbf66ebe7add2557e7f069f16b07338c6c 100644 (file)
@@ -817,7 +817,7 @@ static inline int __init activate_vmi(void)
                vmi_timer_ops.set_alarm = vmi_get_function(VMI_CALL_SetAlarm);
                vmi_timer_ops.cancel_alarm =
                         vmi_get_function(VMI_CALL_CancelAlarm);
-               pv_time_ops.time_init = vmi_time_init;
+               x86_init.timers.timer_init = vmi_time_init;
                pv_time_ops.get_wallclock = vmi_get_wallclock;
                pv_time_ops.set_wallclock = vmi_set_wallclock;
 #ifdef CONFIG_X86_LOCAL_APIC
index e666a98db7cd21ce888c307d734c475fe72a17f7..4790b92714a6cdc297833036eac626aacda7a762 100644 (file)
@@ -11,6 +11,7 @@
 #include <asm/setup.h>
 #include <asm/apic.h>
 #include <asm/e820.h>
+#include <asm/time.h>
 #include <asm/irq.h>
 
 void __cpuinit x86_init_noop(void) { }
@@ -58,6 +59,8 @@ struct __initdata x86_init_ops x86_init = {
 
        .timers = {
                .setup_percpu_clockev   = setup_boot_APIC_clock,
+               .tsc_pre_init           = x86_init_noop,
+               .timer_init             = hpet_time_init,
        },
 };
 
index 1ff986511f1d881b43d39ed33b5947e3f397676c..6caa8c0c793b732b49b22a9375f989037cc552d3 100644 (file)
@@ -1320,11 +1320,11 @@ __init void lguest_init(void)
 
        /* Time operations */
        pv_time_ops.get_wallclock = lguest_get_wallclock;
-       pv_time_ops.time_init = lguest_time_init;
        pv_time_ops.get_tsc_khz = lguest_tsc_khz;
 
        x86_init.resources.memory_setup = lguest_memory_setup;
        x86_init.irqs.intr_init = lguest_init_IRQ;
+       x86_init.timers.timer_init = lguest_time_init;
 
        /*
         * Now is a good time to look at the implementations of these functions
index 14e597e0c160e6d36fe9e331cf678e940f9b9b1b..84826b842b54cc6dd4ff74ab0ca1a7848e5f5b82 100644 (file)
@@ -842,8 +842,6 @@ static const struct pv_init_ops xen_init_ops __initdata = {
 };
 
 static const struct pv_time_ops xen_time_ops __initdata = {
-       .time_init = xen_time_init,
-
        .set_wallclock = xen_set_wallclock,
        .get_wallclock = xen_get_wallclock,
        .get_tsc_khz = xen_tsc_khz,
@@ -977,6 +975,8 @@ asmlinkage void __init xen_start_kernel(void)
        x86_init.resources.memory_setup = xen_memory_setup;
        x86_init.oem.arch_setup = xen_arch_setup;
        x86_init.oem.banner = xen_banner;
+
+       x86_init.timers.timer_init = xen_time_init;
        x86_init.timers.setup_percpu_clockev = x86_init_noop;
        x86_cpuinit.setup_percpu_clockev = x86_init_noop;