diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-11 23:01:33 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-12-11 23:01:33 -0500 |
commit | 1ebaf4f4e6912199f8a4e30ba3ab55da2b71bcdf (patch) | |
tree | d2073d669e6eaf15ece6fc6ce563438d74824412 | |
parent | 743aa456c1834f76982af44e8b71d1a0b2a82e21 (diff) | |
parent | 5074b85bdd3a464efe7b6de2ec163f4c07696a20 (diff) |
Merge branch 'x86-timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 timer update from Ingo Molnar:
"This tree includes HPET fixes and also implements a calibration-free,
TSC match driven APIC timer interrupt mode: 'TSC deadline mode'
supported in SandyBridge and later CPUs."
* 'x86-timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
x86: hpet: Fix inverted return value check in arch_setup_hpet_msi()
x86: hpet: Fix masking of MSI interrupts
x86: apic: Use tsc deadline for oneshot when available
-rw-r--r-- | Documentation/kernel-parameters.txt | 4 | ||||
-rw-r--r-- | arch/x86/include/asm/msr-index.h | 2 | ||||
-rw-r--r-- | arch/x86/kernel/apic/apic.c | 73 | ||||
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 5 | ||||
-rw-r--r-- | arch/x86/kernel/hpet.c | 4 |
5 files changed, 64 insertions, 24 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 5190f1706414..28bd0f0e32c5 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -1304,6 +1304,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
1304 | lapic [X86-32,APIC] Enable the local APIC even if BIOS | 1304 | lapic [X86-32,APIC] Enable the local APIC even if BIOS |
1305 | disabled it. | 1305 | disabled it. |
1306 | 1306 | ||
1307 | lapic= [x86,APIC] "notscdeadline" Do not use TSC deadline | ||
1308 | value for LAPIC timer one-shot implementation. Default | ||
1309 | back to the programmable timer unit in the LAPIC. | ||
1310 | |||
1307 | lapic_timer_c2_ok [X86,APIC] trust the local apic timer | 1311 | lapic_timer_c2_ok [X86,APIC] trust the local apic timer |
1308 | in C2 power state. | 1312 | in C2 power state. |
1309 | 1313 | ||
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 7f0edceb7563..e400cdb2dd65 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h | |||
@@ -337,6 +337,8 @@ | |||
337 | #define MSR_IA32_MISC_ENABLE_TURBO_DISABLE (1ULL << 38) | 337 | #define MSR_IA32_MISC_ENABLE_TURBO_DISABLE (1ULL << 38) |
338 | #define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE (1ULL << 39) | 338 | #define MSR_IA32_MISC_ENABLE_IP_PREF_DISABLE (1ULL << 39) |
339 | 339 | ||
340 | #define MSR_IA32_TSC_DEADLINE 0x000006E0 | ||
341 | |||
340 | /* P4/Xeon+ specific */ | 342 | /* P4/Xeon+ specific */ |
341 | #define MSR_IA32_MCG_EAX 0x00000180 | 343 | #define MSR_IA32_MCG_EAX 0x00000180 |
342 | #define MSR_IA32_MCG_EBX 0x00000181 | 344 | #define MSR_IA32_MCG_EBX 0x00000181 |
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index b17416e72fbd..b994cc84aa7e 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -90,21 +90,6 @@ EXPORT_EARLY_PER_CPU_SYMBOL(x86_bios_cpu_apicid); | |||
90 | */ | 90 | */ |
91 | DEFINE_EARLY_PER_CPU_READ_MOSTLY(int, x86_cpu_to_logical_apicid, BAD_APICID); | 91 | DEFINE_EARLY_PER_CPU_READ_MOSTLY(int, x86_cpu_to_logical_apicid, BAD_APICID); |
92 | 92 | ||
93 | /* | ||
94 | * Knob to control our willingness to enable the local APIC. | ||
95 | * | ||
96 | * +1=force-enable | ||
97 | */ | ||
98 | static int force_enable_local_apic __initdata; | ||
99 | /* | ||
100 | * APIC command line parameters | ||
101 | */ | ||
102 | static int __init parse_lapic(char *arg) | ||
103 | { | ||
104 | force_enable_local_apic = 1; | ||
105 | return 0; | ||
106 | } | ||
107 | early_param("lapic", parse_lapic); | ||
108 | /* Local APIC was disabled by the BIOS and enabled by the kernel */ | 93 | /* Local APIC was disabled by the BIOS and enabled by the kernel */ |
109 | static int enabled_via_apicbase; | 94 | static int enabled_via_apicbase; |
110 | 95 | ||
@@ -133,6 +118,25 @@ static inline void imcr_apic_to_pic(void) | |||
133 | } | 118 | } |
134 | #endif | 119 | #endif |
135 | 120 | ||
121 | /* | ||
122 | * Knob to control our willingness to enable the local APIC. | ||
123 | * | ||
124 | * +1=force-enable | ||
125 | */ | ||
126 | static int force_enable_local_apic __initdata; | ||
127 | /* | ||
128 | * APIC command line parameters | ||
129 | */ | ||
130 | static int __init parse_lapic(char *arg) | ||
131 | { | ||
132 | if (config_enabled(CONFIG_X86_32) && !arg) | ||
133 | force_enable_local_apic = 1; | ||
134 | else if (!strncmp(arg, "notscdeadline", 13)) | ||
135 | setup_clear_cpu_cap(X86_FEATURE_TSC_DEADLINE_TIMER); | ||
136 | return 0; | ||
137 | } | ||
138 | early_param("lapic", parse_lapic); | ||
139 | |||
136 | #ifdef CONFIG_X86_64 | 140 | #ifdef CONFIG_X86_64 |
137 | static int apic_calibrate_pmtmr __initdata; | 141 | static int apic_calibrate_pmtmr __initdata; |
138 | static __init int setup_apicpmtimer(char *s) | 142 | static __init int setup_apicpmtimer(char *s) |
@@ -315,6 +319,7 @@ int lapic_get_maxlvt(void) | |||
315 | 319 | ||
316 | /* Clock divisor */ | 320 | /* Clock divisor */ |
317 | #define APIC_DIVISOR 16 | 321 | #define APIC_DIVISOR 16 |
322 | #define TSC_DIVISOR 32 | ||
318 | 323 | ||
319 | /* | 324 | /* |
320 | * This function sets up the local APIC timer, with a timeout of | 325 | * This function sets up the local APIC timer, with a timeout of |
@@ -333,6 +338,9 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) | |||
333 | lvtt_value = LOCAL_TIMER_VECTOR; | 338 | lvtt_value = LOCAL_TIMER_VECTOR; |
334 | if (!oneshot) | 339 | if (!oneshot) |
335 | lvtt_value |= APIC_LVT_TIMER_PERIODIC; | 340 | lvtt_value |= APIC_LVT_TIMER_PERIODIC; |
341 | else if (boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) | ||
342 | lvtt_value |= APIC_LVT_TIMER_TSCDEADLINE; | ||
343 | |||
336 | if (!lapic_is_integrated()) | 344 | if (!lapic_is_integrated()) |
337 | lvtt_value |= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV); | 345 | lvtt_value |= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV); |
338 | 346 | ||
@@ -341,6 +349,11 @@ static void __setup_APIC_LVTT(unsigned int clocks, int oneshot, int irqen) | |||
341 | 349 | ||
342 | apic_write(APIC_LVTT, lvtt_value); | 350 | apic_write(APIC_LVTT, lvtt_value); |
343 | 351 | ||
352 | if (lvtt_value & APIC_LVT_TIMER_TSCDEADLINE) { | ||
353 | printk_once(KERN_DEBUG "TSC deadline timer enabled\n"); | ||
354 | return; | ||
355 | } | ||
356 | |||
344 | /* | 357 | /* |
345 | * Divide PICLK by 16 | 358 | * Divide PICLK by 16 |
346 | */ | 359 | */ |
@@ -453,6 +466,16 @@ static int lapic_next_event(unsigned long delta, | |||
453 | return 0; | 466 | return 0; |
454 | } | 467 | } |
455 | 468 | ||
469 | static int lapic_next_deadline(unsigned long delta, | ||
470 | struct clock_event_device *evt) | ||
471 | { | ||
472 | u64 tsc; | ||
473 | |||
474 | rdtscll(tsc); | ||
475 | wrmsrl(MSR_IA32_TSC_DEADLINE, tsc + (((u64) delta) * TSC_DIVISOR)); | ||
476 | return 0; | ||
477 | } | ||
478 | |||
456 | /* | 479 | /* |
457 | * Setup the lapic timer in periodic or oneshot mode | 480 | * Setup the lapic timer in periodic or oneshot mode |
458 | */ | 481 | */ |
@@ -533,7 +556,15 @@ static void __cpuinit setup_APIC_timer(void) | |||
533 | memcpy(levt, &lapic_clockevent, sizeof(*levt)); | 556 | memcpy(levt, &lapic_clockevent, sizeof(*levt)); |
534 | levt->cpumask = cpumask_of(smp_processor_id()); | 557 | levt->cpumask = cpumask_of(smp_processor_id()); |
535 | 558 | ||
536 | clockevents_register_device(levt); | 559 | if (this_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) { |
560 | levt->features &= ~(CLOCK_EVT_FEAT_PERIODIC | | ||
561 | CLOCK_EVT_FEAT_DUMMY); | ||
562 | levt->set_next_event = lapic_next_deadline; | ||
563 | clockevents_config_and_register(levt, | ||
564 | (tsc_khz / TSC_DIVISOR) * 1000, | ||
565 | 0xF, ~0UL); | ||
566 | } else | ||
567 | clockevents_register_device(levt); | ||
537 | } | 568 | } |
538 | 569 | ||
539 | /* | 570 | /* |
@@ -661,7 +692,9 @@ static int __init calibrate_APIC_clock(void) | |||
661 | * in the clockevent structure and return. | 692 | * in the clockevent structure and return. |
662 | */ | 693 | */ |
663 | 694 | ||
664 | if (lapic_timer_frequency) { | 695 | if (boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) { |
696 | return 0; | ||
697 | } else if (lapic_timer_frequency) { | ||
665 | apic_printk(APIC_VERBOSE, "lapic timer already calibrated %d\n", | 698 | apic_printk(APIC_VERBOSE, "lapic timer already calibrated %d\n", |
666 | lapic_timer_frequency); | 699 | lapic_timer_frequency); |
667 | lapic_clockevent.mult = div_sc(lapic_timer_frequency/APIC_DIVISOR, | 700 | lapic_clockevent.mult = div_sc(lapic_timer_frequency/APIC_DIVISOR, |
@@ -674,6 +707,9 @@ static int __init calibrate_APIC_clock(void) | |||
674 | return 0; | 707 | return 0; |
675 | } | 708 | } |
676 | 709 | ||
710 | apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n" | ||
711 | "calibrating APIC timer ...\n"); | ||
712 | |||
677 | local_irq_disable(); | 713 | local_irq_disable(); |
678 | 714 | ||
679 | /* Replace the global interrupt handler */ | 715 | /* Replace the global interrupt handler */ |
@@ -811,9 +847,6 @@ void __init setup_boot_APIC_clock(void) | |||
811 | return; | 847 | return; |
812 | } | 848 | } |
813 | 849 | ||
814 | apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n" | ||
815 | "calibrating APIC timer ...\n"); | ||
816 | |||
817 | if (calibrate_APIC_clock()) { | 850 | if (calibrate_APIC_clock()) { |
818 | /* No broadcast on UP ! */ | 851 | /* No broadcast on UP ! */ |
819 | if (num_possible_cpus() > 1) | 852 | if (num_possible_cpus() > 1) |
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 70aa621df118..b739d398bb29 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -3305,8 +3305,9 @@ int arch_setup_hpet_msi(unsigned int irq, unsigned int id) | |||
3305 | int ret; | 3305 | int ret; |
3306 | 3306 | ||
3307 | if (irq_remapping_enabled) { | 3307 | if (irq_remapping_enabled) { |
3308 | if (!setup_hpet_msi_remapped(irq, id)) | 3308 | ret = setup_hpet_msi_remapped(irq, id); |
3309 | return -1; | 3309 | if (ret) |
3310 | return ret; | ||
3310 | } | 3311 | } |
3311 | 3312 | ||
3312 | ret = msi_compose_msg(NULL, irq, &msg, id); | 3313 | ret = msi_compose_msg(NULL, irq, &msg, id); |
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 1460a5df92f7..e28670f9a589 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c | |||
@@ -434,7 +434,7 @@ void hpet_msi_unmask(struct irq_data *data) | |||
434 | 434 | ||
435 | /* unmask it */ | 435 | /* unmask it */ |
436 | cfg = hpet_readl(HPET_Tn_CFG(hdev->num)); | 436 | cfg = hpet_readl(HPET_Tn_CFG(hdev->num)); |
437 | cfg |= HPET_TN_FSB; | 437 | cfg |= HPET_TN_ENABLE | HPET_TN_FSB; |
438 | hpet_writel(cfg, HPET_Tn_CFG(hdev->num)); | 438 | hpet_writel(cfg, HPET_Tn_CFG(hdev->num)); |
439 | } | 439 | } |
440 | 440 | ||
@@ -445,7 +445,7 @@ void hpet_msi_mask(struct irq_data *data) | |||
445 | 445 | ||
446 | /* mask it */ | 446 | /* mask it */ |
447 | cfg = hpet_readl(HPET_Tn_CFG(hdev->num)); | 447 | cfg = hpet_readl(HPET_Tn_CFG(hdev->num)); |
448 | cfg &= ~HPET_TN_FSB; | 448 | cfg &= ~(HPET_TN_ENABLE | HPET_TN_FSB); |
449 | hpet_writel(cfg, HPET_Tn_CFG(hdev->num)); | 449 | hpet_writel(cfg, HPET_Tn_CFG(hdev->num)); |
450 | } | 450 | } |
451 | 451 | ||