aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/kernel/nmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/i386/kernel/nmi.c')
-rw-r--r--arch/i386/kernel/nmi.c188
1 files changed, 156 insertions, 32 deletions
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c
index 1282d70ff971..5d58dfeacd59 100644
--- a/arch/i386/kernel/nmi.c
+++ b/arch/i386/kernel/nmi.c
@@ -34,6 +34,20 @@ static unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */
34static unsigned int nmi_p4_cccr_val; 34static unsigned int nmi_p4_cccr_val;
35extern void show_registers(struct pt_regs *regs); 35extern void show_registers(struct pt_regs *regs);
36 36
37/* perfctr_nmi_owner tracks the ownership of the perfctr registers:
38 * evtsel_nmi_owner tracks the ownership of the event selection
39 * - different performance counters/ event selection may be reserved for
40 * different subsystems this reservation system just tries to coordinate
41 * things a little
42 */
43static DEFINE_PER_CPU(unsigned long, perfctr_nmi_owner);
44static DEFINE_PER_CPU(unsigned long, evntsel_nmi_owner[3]);
45
46/* this number is calculated from Intel's MSR_P4_CRU_ESCR5 register and it's
47 * offset from MSR_P4_BSU_ESCR0. It will be the max for all platforms (for now)
48 */
49#define NMI_MAX_COUNTER_BITS 66
50
37/* 51/*
38 * lapic_nmi_owner tracks the ownership of the lapic NMI hardware: 52 * lapic_nmi_owner tracks the ownership of the lapic NMI hardware:
39 * - it may be reserved by some other driver, or not 53 * - it may be reserved by some other driver, or not
@@ -95,6 +109,105 @@ int nmi_active;
95 (P4_CCCR_OVF_PMI0|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT| \ 109 (P4_CCCR_OVF_PMI0|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT| \
96 P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE) 110 P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE)
97 111
112/* converts an msr to an appropriate reservation bit */
113static inline unsigned int nmi_perfctr_msr_to_bit(unsigned int msr)
114{
115 /* returns the bit offset of the performance counter register */
116 switch (boot_cpu_data.x86_vendor) {
117 case X86_VENDOR_AMD:
118 return (msr - MSR_K7_PERFCTR0);
119 case X86_VENDOR_INTEL:
120 switch (boot_cpu_data.x86) {
121 case 6:
122 return (msr - MSR_P6_PERFCTR0);
123 case 15:
124 return (msr - MSR_P4_BPU_PERFCTR0);
125 }
126 }
127 return 0;
128}
129
130/* converts an msr to an appropriate reservation bit */
131static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr)
132{
133 /* returns the bit offset of the event selection register */
134 switch (boot_cpu_data.x86_vendor) {
135 case X86_VENDOR_AMD:
136 return (msr - MSR_K7_EVNTSEL0);
137 case X86_VENDOR_INTEL:
138 switch (boot_cpu_data.x86) {
139 case 6:
140 return (msr - MSR_P6_EVNTSEL0);
141 case 15:
142 return (msr - MSR_P4_BSU_ESCR0);
143 }
144 }
145 return 0;
146}
147
148/* checks for a bit availability (hack for oprofile) */
149int avail_to_resrv_perfctr_nmi_bit(unsigned int counter)
150{
151 BUG_ON(counter > NMI_MAX_COUNTER_BITS);
152
153 return (!test_bit(counter, &__get_cpu_var(perfctr_nmi_owner)));
154}
155
156/* checks the an msr for availability */
157int avail_to_resrv_perfctr_nmi(unsigned int msr)
158{
159 unsigned int counter;
160
161 counter = nmi_perfctr_msr_to_bit(msr);
162 BUG_ON(counter > NMI_MAX_COUNTER_BITS);
163
164 return (!test_bit(counter, &__get_cpu_var(perfctr_nmi_owner)));
165}
166
167int reserve_perfctr_nmi(unsigned int msr)
168{
169 unsigned int counter;
170
171 counter = nmi_perfctr_msr_to_bit(msr);
172 BUG_ON(counter > NMI_MAX_COUNTER_BITS);
173
174 if (!test_and_set_bit(counter, &__get_cpu_var(perfctr_nmi_owner)))
175 return 1;
176 return 0;
177}
178
179void release_perfctr_nmi(unsigned int msr)
180{
181 unsigned int counter;
182
183 counter = nmi_perfctr_msr_to_bit(msr);
184 BUG_ON(counter > NMI_MAX_COUNTER_BITS);
185
186 clear_bit(counter, &__get_cpu_var(perfctr_nmi_owner));
187}
188
189int reserve_evntsel_nmi(unsigned int msr)
190{
191 unsigned int counter;
192
193 counter = nmi_evntsel_msr_to_bit(msr);
194 BUG_ON(counter > NMI_MAX_COUNTER_BITS);
195
196 if (!test_and_set_bit(counter, &__get_cpu_var(evntsel_nmi_owner)[0]))
197 return 1;
198 return 0;
199}
200
201void release_evntsel_nmi(unsigned int msr)
202{
203 unsigned int counter;
204
205 counter = nmi_evntsel_msr_to_bit(msr);
206 BUG_ON(counter > NMI_MAX_COUNTER_BITS);
207
208 clear_bit(counter, &__get_cpu_var(evntsel_nmi_owner)[0]);
209}
210
98#ifdef CONFIG_SMP 211#ifdef CONFIG_SMP
99/* The performance counters used by NMI_LOCAL_APIC don't trigger when 212/* The performance counters used by NMI_LOCAL_APIC don't trigger when
100 * the CPU is idle. To make sure the NMI watchdog really ticks on all 213 * the CPU is idle. To make sure the NMI watchdog really ticks on all
@@ -344,14 +457,6 @@ late_initcall(init_lapic_nmi_sysfs);
344 * Original code written by Keith Owens. 457 * Original code written by Keith Owens.
345 */ 458 */
346 459
347static void clear_msr_range(unsigned int base, unsigned int n)
348{
349 unsigned int i;
350
351 for(i = 0; i < n; ++i)
352 wrmsr(base+i, 0, 0);
353}
354
355static void write_watchdog_counter(const char *descr) 460static void write_watchdog_counter(const char *descr)
356{ 461{
357 u64 count = (u64)cpu_khz * 1000; 462 u64 count = (u64)cpu_khz * 1000;
@@ -362,14 +467,19 @@ static void write_watchdog_counter(const char *descr)
362 wrmsrl(nmi_perfctr_msr, 0 - count); 467 wrmsrl(nmi_perfctr_msr, 0 - count);
363} 468}
364 469
365static void setup_k7_watchdog(void) 470static int setup_k7_watchdog(void)
366{ 471{
367 unsigned int evntsel; 472 unsigned int evntsel;
368 473
369 nmi_perfctr_msr = MSR_K7_PERFCTR0; 474 nmi_perfctr_msr = MSR_K7_PERFCTR0;
370 475
371 clear_msr_range(MSR_K7_EVNTSEL0, 4); 476 if (!reserve_perfctr_nmi(nmi_perfctr_msr))
372 clear_msr_range(MSR_K7_PERFCTR0, 4); 477 goto fail;
478
479 if (!reserve_evntsel_nmi(MSR_K7_EVNTSEL0))
480 goto fail1;
481
482 wrmsrl(MSR_K7_PERFCTR0, 0UL);
373 483
374 evntsel = K7_EVNTSEL_INT 484 evntsel = K7_EVNTSEL_INT
375 | K7_EVNTSEL_OS 485 | K7_EVNTSEL_OS
@@ -381,16 +491,24 @@ static void setup_k7_watchdog(void)
381 apic_write(APIC_LVTPC, APIC_DM_NMI); 491 apic_write(APIC_LVTPC, APIC_DM_NMI);
382 evntsel |= K7_EVNTSEL_ENABLE; 492 evntsel |= K7_EVNTSEL_ENABLE;
383 wrmsr(MSR_K7_EVNTSEL0, evntsel, 0); 493 wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
494 return 1;
495fail1:
496 release_perfctr_nmi(nmi_perfctr_msr);
497fail:
498 return 0;
384} 499}
385 500
386static void setup_p6_watchdog(void) 501static int setup_p6_watchdog(void)
387{ 502{
388 unsigned int evntsel; 503 unsigned int evntsel;
389 504
390 nmi_perfctr_msr = MSR_P6_PERFCTR0; 505 nmi_perfctr_msr = MSR_P6_PERFCTR0;
391 506
392 clear_msr_range(MSR_P6_EVNTSEL0, 2); 507 if (!reserve_perfctr_nmi(nmi_perfctr_msr))
393 clear_msr_range(MSR_P6_PERFCTR0, 2); 508 goto fail;
509
510 if (!reserve_evntsel_nmi(MSR_P6_EVNTSEL0))
511 goto fail1;
394 512
395 evntsel = P6_EVNTSEL_INT 513 evntsel = P6_EVNTSEL_INT
396 | P6_EVNTSEL_OS 514 | P6_EVNTSEL_OS
@@ -402,6 +520,11 @@ static void setup_p6_watchdog(void)
402 apic_write(APIC_LVTPC, APIC_DM_NMI); 520 apic_write(APIC_LVTPC, APIC_DM_NMI);
403 evntsel |= P6_EVNTSEL0_ENABLE; 521 evntsel |= P6_EVNTSEL0_ENABLE;
404 wrmsr(MSR_P6_EVNTSEL0, evntsel, 0); 522 wrmsr(MSR_P6_EVNTSEL0, evntsel, 0);
523 return 1;
524fail1:
525 release_perfctr_nmi(nmi_perfctr_msr);
526fail:
527 return 0;
405} 528}
406 529
407static int setup_p4_watchdog(void) 530static int setup_p4_watchdog(void)
@@ -419,22 +542,11 @@ static int setup_p4_watchdog(void)
419 nmi_p4_cccr_val |= P4_CCCR_OVF_PMI1; 542 nmi_p4_cccr_val |= P4_CCCR_OVF_PMI1;
420#endif 543#endif
421 544
422 if (!(misc_enable & MSR_P4_MISC_ENABLE_PEBS_UNAVAIL)) 545 if (!reserve_perfctr_nmi(nmi_perfctr_msr))
423 clear_msr_range(0x3F1, 2); 546 goto fail;
424 /* MSR 0x3F0 seems to have a default value of 0xFC00, but current 547
425 docs doesn't fully define it, so leave it alone for now. */ 548 if (!reserve_evntsel_nmi(MSR_P4_CRU_ESCR0))
426 if (boot_cpu_data.x86_model >= 0x3) { 549 goto fail1;
427 /* MSR_P4_IQ_ESCR0/1 (0x3ba/0x3bb) removed */
428 clear_msr_range(0x3A0, 26);
429 clear_msr_range(0x3BC, 3);
430 } else {
431 clear_msr_range(0x3A0, 31);
432 }
433 clear_msr_range(0x3C0, 6);
434 clear_msr_range(0x3C8, 6);
435 clear_msr_range(0x3E0, 2);
436 clear_msr_range(MSR_P4_CCCR0, 18);
437 clear_msr_range(MSR_P4_PERFCTR0, 18);
438 550
439 wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0); 551 wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0);
440 wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0); 552 wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0);
@@ -442,6 +554,10 @@ static int setup_p4_watchdog(void)
442 apic_write(APIC_LVTPC, APIC_DM_NMI); 554 apic_write(APIC_LVTPC, APIC_DM_NMI);
443 wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0); 555 wrmsr(MSR_P4_IQ_CCCR0, nmi_p4_cccr_val, 0);
444 return 1; 556 return 1;
557fail1:
558 release_perfctr_nmi(nmi_perfctr_msr);
559fail:
560 return 0;
445} 561}
446 562
447void setup_apic_nmi_watchdog (void) 563void setup_apic_nmi_watchdog (void)
@@ -450,7 +566,8 @@ void setup_apic_nmi_watchdog (void)
450 case X86_VENDOR_AMD: 566 case X86_VENDOR_AMD:
451 if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15) 567 if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15)
452 return; 568 return;
453 setup_k7_watchdog(); 569 if (!setup_k7_watchdog())
570 return;
454 break; 571 break;
455 case X86_VENDOR_INTEL: 572 case X86_VENDOR_INTEL:
456 switch (boot_cpu_data.x86) { 573 switch (boot_cpu_data.x86) {
@@ -458,7 +575,8 @@ void setup_apic_nmi_watchdog (void)
458 if (boot_cpu_data.x86_model > 0xd) 575 if (boot_cpu_data.x86_model > 0xd)
459 return; 576 return;
460 577
461 setup_p6_watchdog(); 578 if(!setup_p6_watchdog())
579 return;
462 break; 580 break;
463 case 15: 581 case 15:
464 if (boot_cpu_data.x86_model > 0x4) 582 if (boot_cpu_data.x86_model > 0x4)
@@ -612,6 +730,12 @@ int proc_unknown_nmi_panic(ctl_table *table, int write, struct file *file,
612 730
613EXPORT_SYMBOL(nmi_active); 731EXPORT_SYMBOL(nmi_active);
614EXPORT_SYMBOL(nmi_watchdog); 732EXPORT_SYMBOL(nmi_watchdog);
733EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi);
734EXPORT_SYMBOL(avail_to_resrv_perfctr_nmi_bit);
735EXPORT_SYMBOL(reserve_perfctr_nmi);
736EXPORT_SYMBOL(release_perfctr_nmi);
737EXPORT_SYMBOL(reserve_evntsel_nmi);
738EXPORT_SYMBOL(release_evntsel_nmi);
615EXPORT_SYMBOL(reserve_lapic_nmi); 739EXPORT_SYMBOL(reserve_lapic_nmi);
616EXPORT_SYMBOL(release_lapic_nmi); 740EXPORT_SYMBOL(release_lapic_nmi);
617EXPORT_SYMBOL(disable_timer_nmi_watchdog); 741EXPORT_SYMBOL(disable_timer_nmi_watchdog);