aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64')
-rw-r--r--arch/x86_64/kernel/apic.c34
-rw-r--r--arch/x86_64/kernel/time.c45
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
39int apic_verbosity; 41int apic_verbosity;
42int apic_runs_main_timer;
40 43
41int disable_apic_timer __initdata; 44int 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
1082static __init int setup_noapictimer(char *str) 1095static __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
1103static __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
1111static __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;
51DEFINE_SPINLOCK(rtc_lock); 51DEFINE_SPINLOCK(rtc_lock);
52DEFINE_SPINLOCK(i8253_lock); 52DEFINE_SPINLOCK(i8253_lock);
53 53
54static int nohpet __initdata = 0; 54int nohpet __initdata = 0;
55static int notsc __initdata = 0; 55static 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
348static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) 348void 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
463static 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
846void __init pit_init(void) 851#define PIT_MODE 0x43
852#define PIT_CH0 0x40
853
854static 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
865void __init pit_init(void)
866{
867 __pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */
868}
869
870void __init pit_stop_interrupt(void)
871{
872 __pit_init(0, 0x30); /* mode 0 */
873}
874
875void __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
857int __init time_setup(char *str) 888int __init time_setup(char *str)
858{ 889{
859 report_lost_ticks = 1; 890 report_lost_ticks = 1;