diff options
Diffstat (limited to 'arch/x86_64')
-rw-r--r-- | arch/x86_64/kernel/apic.c | 34 | ||||
-rw-r--r-- | arch/x86_64/kernel/time.c | 45 |
2 files changed, 70 insertions, 9 deletions
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; |