diff options
Diffstat (limited to 'arch/x86_64/kernel')
-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 @@ #include <asm/mach_apic.h> #include <asm/nmi.h> #include <asm/idle.h> +#include <asm/proto.h> +#include <asm/timex.h> int apic_verbosity; +int apic_runs_main_timer; int disable_apic_timer __initdata; @@ -702,9 +705,17 @@ static void setup_APIC_timer(unsigned int clocks) c2 |= inb_p(0x40) << 8; } while (c2 - c1 < 300); } - __setup_APIC_LVTT(clocks); - + /* Turn off PIT interrupt if we use APIC timer as main timer. + Only works with the PM timer right now + TBD fix it for HPET too. */ + if (vxtime.mode == VXTIME_PMTMR && + smp_processor_id() == boot_cpu_id && + apic_runs_main_timer == 1 && + !cpu_isset(boot_cpu_id, timer_interrupt_broadcast_ipi_mask)) { + stop_timer_interrupt(); + apic_runs_main_timer++; + } local_irq_restore(flags); } @@ -872,6 +883,8 @@ void smp_local_timer_interrupt(struct pt_regs *regs) #ifdef CONFIG_SMP update_process_times(user_mode(regs)); #endif + if (apic_runs_main_timer > 1 && smp_processor_id() == boot_cpu_id) + main_timer_handler(regs); /* * We take the 'long' return path, and there every subsystem * grabs the appropriate locks (kernel lock/ irq lock). @@ -1081,10 +1094,27 @@ static __init int setup_nolapic(char *str) static __init int setup_noapictimer(char *str) { + if (str[0] != ' ' && str[0] != 0) + return -1; disable_apic_timer = 1; return 0; } +static __init int setup_apicmaintimer(char *str) +{ + apic_runs_main_timer = 1; + nohpet = 1; + return 0; +} +__setup("apicmaintimer", setup_apicmaintimer); + +static __init int setup_noapicmaintimer(char *str) +{ + apic_runs_main_timer = -1; + return 0; +} +__setup("noapicmaintimer", setup_noapicmaintimer); + /* dummy parsing: see setup.c */ __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; DEFINE_SPINLOCK(rtc_lock); DEFINE_SPINLOCK(i8253_lock); -static int nohpet __initdata = 0; +int nohpet __initdata = 0; static int notsc __initdata = 0; #undef HPET_HACK_ENABLE_DANGEROUS @@ -345,7 +345,7 @@ static noinline void handle_lost_ticks(int lost, struct pt_regs *regs) #endif } -static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +void main_timer_handler(struct pt_regs *regs) { static unsigned long rtc_update = 0; unsigned long tsc; @@ -458,12 +458,17 @@ static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) } write_sequnlock(&xtime_lock); +} +static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + if (apic_runs_main_timer > 1) + return IRQ_HANDLED; + main_timer_handler(regs); #ifdef CONFIG_X86_LOCAL_APIC if (using_apic_timer) smp_send_timer_broadcast_ipi(); #endif - return IRQ_HANDLED; } @@ -843,17 +848,43 @@ static int hpet_reenable(void) return hpet_timer_stop_set_go(hpet_tick); } -void __init pit_init(void) +#define PIT_MODE 0x43 +#define PIT_CH0 0x40 + +static void __init __pit_init(int val, u8 mode) { unsigned long flags; spin_lock_irqsave(&i8253_lock, flags); - outb_p(0x34, 0x43); /* binary, mode 2, LSB/MSB, ch 0 */ - outb_p(LATCH & 0xff, 0x40); /* LSB */ - outb_p(LATCH >> 8, 0x40); /* MSB */ + outb_p(mode, PIT_MODE); + outb_p(val & 0xff, PIT_CH0); /* LSB */ + outb_p(val >> 8, PIT_CH0); /* MSB */ spin_unlock_irqrestore(&i8253_lock, flags); } +void __init pit_init(void) +{ + __pit_init(LATCH, 0x34); /* binary, mode 2, LSB/MSB, ch 0 */ +} + +void __init pit_stop_interrupt(void) +{ + __pit_init(0, 0x30); /* mode 0 */ +} + +void __init stop_timer_interrupt(void) +{ + char *name; + if (vxtime.hpet_address) { + name = "HPET"; + hpet_timer_stop_set_go(0); + } else { + name = "PIT"; + pit_stop_interrupt(); + } + printk(KERN_INFO "timer: %s interrupt stopped.\n", name); +} + int __init time_setup(char *str) { report_lost_ticks = 1; |