aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/apic_32.c5
-rw-r--r--arch/x86/kernel/apic_64.c26
-rw-r--r--arch/x86/kernel/cpu/amd.c30
-rw-r--r--arch/x86/kernel/cpu/amd_64.c25
-rw-r--r--arch/x86/kernel/process.c66
-rw-r--r--include/asm-x86/apic.h3
-rw-r--r--kernel/time/tick-broadcast.c6
7 files changed, 73 insertions, 88 deletions
diff --git a/arch/x86/kernel/apic_32.c b/arch/x86/kernel/apic_32.c
index 4b99b1bdeb6c..c44206e731d4 100644
--- a/arch/x86/kernel/apic_32.c
+++ b/arch/x86/kernel/apic_32.c
@@ -64,9 +64,8 @@ static int enable_local_apic __initdata;
64 64
65/* Local APIC timer verification ok */ 65/* Local APIC timer verification ok */
66static int local_apic_timer_verify_ok; 66static int local_apic_timer_verify_ok;
67/* Disable local APIC timer from the kernel commandline or via dmi quirk 67/* Disable local APIC timer from the kernel commandline or via dmi quirk */
68 or using CPU MSR check */ 68static int local_apic_timer_disabled;
69int local_apic_timer_disabled;
70/* Local APIC timer works in C2 */ 69/* Local APIC timer works in C2 */
71int local_apic_timer_c2_ok; 70int local_apic_timer_c2_ok;
72EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok); 71EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
diff --git a/arch/x86/kernel/apic_64.c b/arch/x86/kernel/apic_64.c
index 0633cfd0dc29..a5cc8447cf4d 100644
--- a/arch/x86/kernel/apic_64.c
+++ b/arch/x86/kernel/apic_64.c
@@ -43,7 +43,7 @@
43#include <mach_ipi.h> 43#include <mach_ipi.h>
44#include <mach_apic.h> 44#include <mach_apic.h>
45 45
46int disable_apic_timer __cpuinitdata; 46static int disable_apic_timer __cpuinitdata;
47static int apic_calibrate_pmtmr __initdata; 47static int apic_calibrate_pmtmr __initdata;
48int disable_apic; 48int disable_apic;
49 49
@@ -422,32 +422,8 @@ void __init setup_boot_APIC_clock(void)
422 setup_APIC_timer(); 422 setup_APIC_timer();
423} 423}
424 424
425/*
426 * AMD C1E enabled CPUs have a real nasty problem: Some BIOSes set the
427 * C1E flag only in the secondary CPU, so when we detect the wreckage
428 * we already have enabled the boot CPU local apic timer. Check, if
429 * disable_apic_timer is set and the DUMMY flag is cleared. If yes,
430 * set the DUMMY flag again and force the broadcast mode in the
431 * clockevents layer.
432 */
433static void __cpuinit check_boot_apic_timer_broadcast(void)
434{
435 if (!disable_apic_timer ||
436 (lapic_clockevent.features & CLOCK_EVT_FEAT_DUMMY))
437 return;
438
439 printk(KERN_INFO "AMD C1E detected late. Force timer broadcast.\n");
440 lapic_clockevent.features |= CLOCK_EVT_FEAT_DUMMY;
441
442 local_irq_enable();
443 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_FORCE,
444 &boot_cpu_physical_apicid);
445 local_irq_disable();
446}
447
448void __cpuinit setup_secondary_APIC_clock(void) 425void __cpuinit setup_secondary_APIC_clock(void)
449{ 426{
450 check_boot_apic_timer_broadcast();
451 setup_APIC_timer(); 427 setup_APIC_timer();
452} 428}
453 429
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index e76b49e7a916..acc891ae5901 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -24,31 +24,6 @@
24extern void vide(void); 24extern void vide(void);
25__asm__(".align 4\nvide: ret"); 25__asm__(".align 4\nvide: ret");
26 26
27#ifdef CONFIG_X86_LOCAL_APIC
28
29/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */
30static __cpuinit int amd_apic_timer_broken(struct cpuinfo_x86 *c)
31{
32 u32 lo, hi;
33
34 if (c->x86 < 0x0F)
35 return 0;
36
37 /* Family 0x0f models < rev F do not have this MSR */
38 if (c->x86 == 0x0f && c->x86_model < 0x40)
39 return 0;
40
41 rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi);
42 if (lo & K8_INTP_C1E_ACTIVE_MASK) {
43 if (smp_processor_id() != boot_cpu_physical_apicid)
44 printk(KERN_INFO "AMD C1E detected late. "
45 "Force timer broadcast.\n");
46 return 1;
47 }
48 return 0;
49}
50#endif
51
52int force_mwait __cpuinitdata; 27int force_mwait __cpuinitdata;
53 28
54static void __cpuinit early_init_amd(struct cpuinfo_x86 *c) 29static void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
@@ -285,11 +260,6 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
285 num_cache_leaves = 3; 260 num_cache_leaves = 3;
286 } 261 }
287 262
288#ifdef CONFIG_X86_LOCAL_APIC
289 if (amd_apic_timer_broken(c))
290 local_apic_timer_disabled = 1;
291#endif
292
293 /* K6s reports MCEs but don't actually have all the MSRs */ 263 /* K6s reports MCEs but don't actually have all the MSRs */
294 if (c->x86 < 6) 264 if (c->x86 < 6)
295 clear_cpu_cap(c, X86_FEATURE_MCE); 265 clear_cpu_cap(c, X86_FEATURE_MCE);
diff --git a/arch/x86/kernel/cpu/amd_64.c b/arch/x86/kernel/cpu/amd_64.c
index f5fc161d8f2a..f8d20588bde9 100644
--- a/arch/x86/kernel/cpu/amd_64.c
+++ b/arch/x86/kernel/cpu/amd_64.c
@@ -110,28 +110,6 @@ static void __cpuinit early_init_amd_mc(struct cpuinfo_x86 *c)
110#endif 110#endif
111} 111}
112 112
113/* AMD systems with C1E don't have a working lAPIC timer. Check for that. */
114static __cpuinit int amd_apic_timer_broken(struct cpuinfo_x86 *c)
115{
116 u32 lo, hi;
117
118 if (c->x86 < 0x0F)
119 return 0;
120
121 /* Family 0x0f models < rev F do not have this MSR */
122 if (c->x86 == 0x0f && c->x86_model < 0x40)
123 return 0;
124
125 rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi);
126 if (lo & K8_INTP_C1E_ACTIVE_MASK) {
127 if (smp_processor_id() != boot_cpu_physical_apicid)
128 printk(KERN_INFO "AMD C1E detected late. "
129 "Force timer broadcast.\n");
130 return 1;
131 }
132 return 0;
133}
134
135void __cpuinit early_init_amd(struct cpuinfo_x86 *c) 113void __cpuinit early_init_amd(struct cpuinfo_x86 *c)
136{ 114{
137 early_init_amd_mc(c); 115 early_init_amd_mc(c);
@@ -212,9 +190,6 @@ void __cpuinit init_amd(struct cpuinfo_x86 *c)
212 if (c->x86 == 0x10) 190 if (c->x86 == 0x10)
213 amd_enable_pci_ext_cfg(c); 191 amd_enable_pci_ext_cfg(c);
214 192
215 if (amd_apic_timer_broken(c))
216 disable_apic_timer = 1;
217
218 if (c == &boot_cpu_data && c->x86 >= 0xf && c->x86 <= 0x11) { 193 if (c == &boot_cpu_data && c->x86 >= 0xf && c->x86 <= 0x11) {
219 unsigned long long tseg; 194 unsigned long long tseg;
220 195
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 9fea14607dfe..68ad3539b143 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -6,6 +6,7 @@
6#include <linux/sched.h> 6#include <linux/sched.h>
7#include <linux/module.h> 7#include <linux/module.h>
8#include <linux/pm.h> 8#include <linux/pm.h>
9#include <linux/clockchips.h>
9 10
10struct kmem_cache *task_xstate_cachep; 11struct kmem_cache *task_xstate_cachep;
11 12
@@ -219,6 +220,68 @@ static int __cpuinit mwait_usable(const struct cpuinfo_x86 *c)
219 return (edx & MWAIT_EDX_C1); 220 return (edx & MWAIT_EDX_C1);
220} 221}
221 222
223/*
224 * Check for AMD CPUs, which have potentially C1E support
225 */
226static int __cpuinit check_c1e_idle(const struct cpuinfo_x86 *c)
227{
228 if (c->x86_vendor != X86_VENDOR_AMD)
229 return 0;
230
231 if (c->x86 < 0x0F)
232 return 0;
233
234 /* Family 0x0f models < rev F do not have C1E */
235 if (c->x86 == 0x0f && c->x86_model < 0x40)
236 return 0;
237
238 return 1;
239}
240
241/*
242 * C1E aware idle routine. We check for C1E active in the interrupt
243 * pending message MSR. If we detect C1E, then we handle it the same
244 * way as C3 power states (local apic timer and TSC stop)
245 */
246static void c1e_idle(void)
247{
248 static cpumask_t c1e_mask = CPU_MASK_NONE;
249 static int c1e_detected;
250
251 if (need_resched())
252 return;
253
254 if (!c1e_detected) {
255 u32 lo, hi;
256
257 rdmsr(MSR_K8_INT_PENDING_MSG, lo, hi);
258 if (lo & K8_INTP_C1E_ACTIVE_MASK) {
259 c1e_detected = 1;
260 mark_tsc_unstable("TSC halt in C1E");
261 printk(KERN_INFO "System has C1E enabled\n");
262 }
263 }
264
265 if (c1e_detected) {
266 int cpu = smp_processor_id();
267
268 if (!cpu_isset(cpu, c1e_mask)) {
269 cpu_set(cpu, c1e_mask);
270 /* Force broadcast so ACPI can not interfere */
271 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_FORCE,
272 &cpu);
273 printk(KERN_INFO "Switch to broadcast mode on CPU%d\n",
274 cpu);
275 }
276 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_ENTER, &cpu);
277 default_idle();
278 local_irq_disable();
279 clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &cpu);
280 local_irq_enable();
281 } else
282 default_idle();
283}
284
222void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) 285void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
223{ 286{
224#ifdef CONFIG_X86_SMP 287#ifdef CONFIG_X86_SMP
@@ -236,6 +299,9 @@ void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
236 */ 299 */
237 printk(KERN_INFO "using mwait in idle threads.\n"); 300 printk(KERN_INFO "using mwait in idle threads.\n");
238 pm_idle = mwait_idle; 301 pm_idle = mwait_idle;
302 } else if (check_c1e_idle(c)) {
303 printk(KERN_INFO "using C1E aware idle routine\n");
304 pm_idle = c1e_idle;
239 } else 305 } else
240 pm_idle = default_idle; 306 pm_idle = default_idle;
241} 307}
diff --git a/include/asm-x86/apic.h b/include/asm-x86/apic.h
index be9639a9a186..3c387cda95fa 100644
--- a/include/asm-x86/apic.h
+++ b/include/asm-x86/apic.h
@@ -38,12 +38,9 @@ extern void generic_apic_probe(void);
38extern int apic_verbosity; 38extern int apic_verbosity;
39extern int timer_over_8254; 39extern int timer_over_8254;
40extern int local_apic_timer_c2_ok; 40extern int local_apic_timer_c2_ok;
41extern int local_apic_timer_disabled;
42 41
43extern int apic_runs_main_timer;
44extern int ioapic_force; 42extern int ioapic_force;
45extern int disable_apic; 43extern int disable_apic;
46extern int disable_apic_timer;
47 44
48/* 45/*
49 * Basic functions accessing APICs. 46 * Basic functions accessing APICs.
diff --git a/kernel/time/tick-broadcast.c b/kernel/time/tick-broadcast.c
index 57a1f02e5ec0..67f80c261709 100644
--- a/kernel/time/tick-broadcast.c
+++ b/kernel/time/tick-broadcast.c
@@ -30,6 +30,7 @@
30struct tick_device tick_broadcast_device; 30struct tick_device tick_broadcast_device;
31static cpumask_t tick_broadcast_mask; 31static cpumask_t tick_broadcast_mask;
32static DEFINE_SPINLOCK(tick_broadcast_lock); 32static DEFINE_SPINLOCK(tick_broadcast_lock);
33static int tick_broadcast_force;
33 34
34#ifdef CONFIG_TICK_ONESHOT 35#ifdef CONFIG_TICK_ONESHOT
35static void tick_broadcast_clear_oneshot(int cpu); 36static void tick_broadcast_clear_oneshot(int cpu);
@@ -232,10 +233,11 @@ static void tick_do_broadcast_on_off(void *why)
232 CLOCK_EVT_MODE_SHUTDOWN); 233 CLOCK_EVT_MODE_SHUTDOWN);
233 } 234 }
234 if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_FORCE) 235 if (*reason == CLOCK_EVT_NOTIFY_BROADCAST_FORCE)
235 dev->features |= CLOCK_EVT_FEAT_DUMMY; 236 tick_broadcast_force = 1;
236 break; 237 break;
237 case CLOCK_EVT_NOTIFY_BROADCAST_OFF: 238 case CLOCK_EVT_NOTIFY_BROADCAST_OFF:
238 if (cpu_isset(cpu, tick_broadcast_mask)) { 239 if (!tick_broadcast_force &&
240 cpu_isset(cpu, tick_broadcast_mask)) {
239 cpu_clear(cpu, tick_broadcast_mask); 241 cpu_clear(cpu, tick_broadcast_mask);
240 if (td->mode == TICKDEV_MODE_PERIODIC) 242 if (td->mode == TICKDEV_MODE_PERIODIC)
241 tick_setup_periodic(dev, 0); 243 tick_setup_periodic(dev, 0);