diff options
-rw-r--r-- | Documentation/x86_64/boot-options.txt | 7 | ||||
-rw-r--r-- | arch/x86_64/kernel/apic.c | 34 | ||||
-rw-r--r-- | arch/x86_64/kernel/time.c | 45 | ||||
-rw-r--r-- | include/asm-x86_64/apic.h | 1 | ||||
-rw-r--r-- | include/asm-x86_64/proto.h | 5 |
5 files changed, 83 insertions, 9 deletions
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt index 9c5fc15d03d1..654ea4fccff8 100644 --- a/Documentation/x86_64/boot-options.txt +++ b/Documentation/x86_64/boot-options.txt | |||
@@ -40,6 +40,13 @@ APICs | |||
40 | no_timer_check Don't check the IO-APIC timer. This can work around | 40 | no_timer_check Don't check the IO-APIC timer. This can work around |
41 | problems with incorrect timer initialization on some boards. | 41 | problems with incorrect timer initialization on some boards. |
42 | 42 | ||
43 | apicmaintimer Run time keeping from the local APIC timer instead | ||
44 | of using the PIT/HPET interrupt for this. This is useful | ||
45 | when the PIT/HPET interrupts are unreliable. | ||
46 | |||
47 | noapicmaintimer Don't do time keeping using the APIC timer. | ||
48 | Useful when this option was auto selected, but doesn't work. | ||
49 | |||
43 | Early Console | 50 | Early Console |
44 | 51 | ||
45 | syntax: earlyprintk=vga | 52 | syntax: earlyprintk=vga |
diff --git a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c index 5d3c5b07b8db..14751dda7dcf 100644 --- a/arch/x86_64/kernel/apic.c +++ b/arch/x86_64/kernel/apic.c | |||
@@ -35,8 +35,11 @@ | |||
35 | #include <asm/mach_apic.h> | 35 | #include <asm/mach_apic.h> |
36 | #include <asm/nmi.h> | 36 | #include <asm/nmi.h> |
37 | #include <asm/idle.h> | 37 | #include <asm/idle.h> |
38 | #include <asm/proto.h> | ||
39 | #include <asm/timex.h> | ||
38 | 40 | ||
39 | int apic_verbosity; | 41 | int apic_verbosity; |
42 | int apic_runs_main_timer; | ||
40 | 43 | ||
41 | int disable_apic_timer __initdata; | 44 | int disable_apic_timer __initdata; |
42 | 45 | ||
@@ -702,9 +705,17 @@ static void setup_APIC_timer(unsigned int clocks) | |||
702 | c2 |= inb_p(0x40) << 8; | 705 | c2 |= inb_p(0x40) << 8; |
703 | } while (c2 - c1 < 300); | 706 | } while (c2 - c1 < 300); |
704 | } | 707 | } |
705 | |||
706 | __setup_APIC_LVTT(clocks); | 708 | __setup_APIC_LVTT(clocks); |
707 | 709 | /* Turn off PIT interrupt if we use APIC timer as main timer. | |
710 | Only works with the PM timer right now | ||
711 | TBD fix it for HPET too. */ | ||
712 | if (vxtime.mode == VXTIME_PMTMR && | ||
713 | smp_processor_id() == boot_cpu_id && | ||
714 | apic_runs_main_timer == 1 && | ||
715 | !cpu_isset(boot_cpu_id, timer_interrupt_broadcast_ipi_mask)) { | ||
716 | stop_timer_interrupt(); | ||
717 | apic_runs_main_timer++; | ||
718 | } | ||
708 | local_irq_restore(flags); | 719 | local_irq_restore(flags); |
709 | } | 720 | } |
710 | 721 | ||
@@ -872,6 +883,8 @@ void smp_local_timer_interrupt(struct pt_regs *regs) | |||
872 | #ifdef CONFIG_SMP | 883 | #ifdef CONFIG_SMP |
873 | update_process_times(user_mode(regs)); | 884 | update_process_times(user_mode(regs)); |
874 | #endif | 885 | #endif |
886 | if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id) | ||
887 | main_timer_handler(regs); | ||
875 | /* | 888 | /* |
876 | * We take the 'long' return path, and there every subsystem | 889 | * We take the 'long' return path, and there every subsystem |
877 | * grabs the appropriate locks (kernel lock/ irq lock). | 890 | * grabs the appropriate locks (kernel lock/ irq lock). |
@@ -1081,10 +1094,27 @@ static __init int setup_nolapic(char *str) | |||
1081 | 1094 | ||
1082 | static __init int setup_noapictimer(char *str) | 1095 | static __init int setup_noapictimer(char *str) |
1083 | { | 1096 | { |
1097 | if (str[0] != ' ' && str[0] != 0) | ||
1098 | return -1; | ||
1084 | disable_apic_timer = 1; | 1099 | disable_apic_timer = 1; |
1085 | return 0; | 1100 | return 0; |
1086 | } | 1101 | } |
1087 | 1102 | ||
1103 | static __init int setup_apicmaintimer(char *str) | ||
1104 | { | ||
1105 | apic_runs_main_timer = 1; | ||
1106 | nohpet = 1; | ||
1107 | return 0; | ||
1108 | } | ||
1109 | __setup("apicmaintimer", setup_apicmaintimer); | ||
1110 | |||
1111 | static __init int setup_noapicmaintimer(char *str) | ||
1112 | { | ||
1113 | apic_runs_main_timer = -1; | ||
1114 | return 0; | ||
1115 | } | ||
1116 | __setup("noapicmaintimer", setup_noapicmaintimer); | ||
1117 | |||
1088 | /* dummy parsing: see setup.c */ | 1118 | /* dummy parsing: see setup.c */ |
1089 | 1119 | ||
1090 | __setup("disableapic", setup_disableapic); | 1120 | __setup("disableapic", setup_disableapic); |
diff --git a/arch/x86_64/kernel/time.c b/arch/x86_64/kernel/time.c index f8c47c688443..91a448a86ebd 100644 --- a/arch/x86_64/kernel/time.c +++ b/arch/x86_64/kernel/time.c | |||
@@ -51,7 +51,7 @@ extern int using_apic_timer; | |||
51 | DEFINE_SPINLOCK(rtc_lock); | 51 | DEFINE_SPINLOCK(rtc_lock); |
52 | DEFINE_SPINLOCK(i8253_lock); | 52 | DEFINE_SPINLOCK(i8253_lock); |
53 | 53 | ||
54 | static int nohpet __initdata = 0; | 54 | int nohpet __initdata = 0; |
55 | static int notsc __initdata = 0; | 55 | static int notsc __initdata = 0; |
56 | 56 | ||
57 | #undef HPET_HACK_ENABLE_DANGEROUS | 57 | #undef HPET_HACK_ENABLE_DANGEROUS |
@@ -345,7 +345,7 @@ static noinline void handle_lost_ticks(int lost, struct pt_regs *regs) | |||
345 | #endif | 345 | #endif |
346 | } | 346 | } |
347 | 347 | ||
348 | static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | 348 | void main_timer_handler(struct pt_regs *regs) |
349 | { | 349 | { |
350 | static unsigned long rtc_update = 0; | 350 | static unsigned long rtc_update = 0; |
351 | unsigned long tsc; | 351 | unsigned long tsc; |
@@ -458,12 +458,17 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | |||
458 | } | 458 | } |
459 | 459 | ||
460 | write_sequnlock(&xtime_lock); | 460 | write_sequnlock(&xtime_lock); |
461 | } | ||
461 | 462 | ||
463 | static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
464 | { | ||
465 | if (apic_runs_main_timer > 1) | ||
466 | return IRQ_HANDLED; | ||
467 | main_timer_handler(regs); | ||
462 | #ifdef CONFIG_X86_LOCAL_APIC | 468 | #ifdef CONFIG_X86_LOCAL_APIC |
463 | if (using_apic_timer) | 469 | if (using_apic_timer) |
464 | smp_send_timer_broadcast_ipi(); | 470 | smp_send_timer_broadcast_ipi(); |
465 | #endif | 471 | #endif |
466 | |||
467 | return IRQ_HANDLED; | 472 | return IRQ_HANDLED; |
468 | } | 473 | } |
469 | 474 | ||
@@ -843,17 +848,43 @@ static int hpet_reenable(void) | |||
843 | return hpet_timer_stop_set_go(hpet_tick); | 848 | return hpet_timer_stop_set_go(hpet_tick); |
844 | } | 849 | } |
845 | 850 | ||
846 | void __init pit_init(void) | 851 | #define PIT_MODE 0x43 |
852 | #define PIT_CH0 0x40 | ||
853 | |||
854 | static void __init __pit_init(int val, u8 mode) | ||
847 | { | 855 | { |
848 | unsigned long flags; | 856 | unsigned long flags; |
849 | 857 | ||
850 | spin_lock_irqsave(&i8253_lock, flags); | 858 | spin_lock_irqsave(&i8253_lock, flags); |
851 | outb_p(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */ | 859 | outb_p(mode, PIT_MODE); |
852 | outb_p(LATCH & 0xff, 0x40); /* LSB */ | 860 | outb_p(val & 0xff, PIT_CH0); /* LSB */ |
853 | outb_p(LATCH >> 8, 0x40); /* MSB */ | 861 | outb_p(val >> 8, PIT_CH0); /* MSB */ |
854 | spin_unlock_irqrestore(&i8253_lock, flags); | 862 | spin_unlock_irqrestore(&i8253_lock, flags); |
855 | } | 863 | } |
856 | 864 | ||
865 | void __init pit_init(void) | ||
866 | { | ||
867 | __pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */ | ||
868 | } | ||
869 | |||
870 | void __init pit_stop_interrupt(void) | ||
871 | { | ||
872 | __pit_init(0, 0x30); /* mode 0 */ | ||
873 | } | ||
874 | |||
875 | void __init stop_timer_interrupt(void) | ||
876 | { | ||
877 | char *name; | ||
878 | if (vxtime.hpet_address) { | ||
879 | name = "HPET"; | ||
880 | hpet_timer_stop_set_go(0); | ||
881 | } else { | ||
882 | name = "PIT"; | ||
883 | pit_stop_interrupt(); | ||
884 | } | ||
885 | printk(KERN_INFO "timer: %s interrupt stopped.\n", name); | ||
886 | } | ||
887 | |||
857 | int __init time_setup(char *str) | 888 | int __init time_setup(char *str) |
858 | { | 889 | { |
859 | report_lost_ticks = 1; | 890 | report_lost_ticks = 1; |
diff --git a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h index 4f6a4dc455bb..bdbd8935612a 100644 --- a/include/asm-x86_64/apic.h +++ b/include/asm-x86_64/apic.h | |||
@@ -17,6 +17,7 @@ | |||
17 | #define APIC_DEBUG 2 | 17 | #define APIC_DEBUG 2 |
18 | 18 | ||
19 | extern int apic_verbosity; | 19 | extern int apic_verbosity; |
20 | extern int apic_runs_main_timer; | ||
20 | 21 | ||
21 | /* | 22 | /* |
22 | * Define the default level of output to be very little | 23 | * Define the default level of output to be very little |
diff --git a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h index d35c7e06f340..c1e2307445d4 100644 --- a/include/asm-x86_64/proto.h +++ b/include/asm-x86_64/proto.h | |||
@@ -49,6 +49,8 @@ extern u32 pmtmr_ioport; | |||
49 | #endif | 49 | #endif |
50 | extern unsigned long long monotonic_base; | 50 | extern unsigned long long monotonic_base; |
51 | extern int sysctl_vsyscall; | 51 | extern int sysctl_vsyscall; |
52 | extern int nohpet; | ||
53 | extern unsigned long vxtime_hz; | ||
52 | 54 | ||
53 | extern void do_softirq_thunk(void); | 55 | extern void do_softirq_thunk(void); |
54 | 56 | ||
@@ -69,6 +71,9 @@ extern void free_bootmem_generic(unsigned long phys, unsigned len); | |||
69 | 71 | ||
70 | extern void load_gs_index(unsigned gs); | 72 | extern void load_gs_index(unsigned gs); |
71 | 73 | ||
74 | extern void stop_timer_interrupt(void); | ||
75 | extern void main_timer_handler(struct pt_regs *regs); | ||
76 | |||
72 | extern unsigned long end_pfn_map; | 77 | extern unsigned long end_pfn_map; |
73 | 78 | ||
74 | extern void show_trace(unsigned long * rsp); | 79 | extern void show_trace(unsigned long * rsp); |