diff options
Diffstat (limited to 'arch/i386/kernel/nmi.c')
-rw-r--r-- | arch/i386/kernel/nmi.c | 137 |
1 files changed, 97 insertions, 40 deletions
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index 821df34d2b3a..a98ba88a8c0c 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c | |||
@@ -122,64 +122,129 @@ static inline unsigned int nmi_evntsel_msr_to_bit(unsigned int msr) | |||
122 | /* checks for a bit availability (hack for oprofile) */ | 122 | /* checks for a bit availability (hack for oprofile) */ |
123 | int avail_to_resrv_perfctr_nmi_bit(unsigned int counter) | 123 | int avail_to_resrv_perfctr_nmi_bit(unsigned int counter) |
124 | { | 124 | { |
125 | int cpu; | ||
125 | BUG_ON(counter > NMI_MAX_COUNTER_BITS); | 126 | BUG_ON(counter > NMI_MAX_COUNTER_BITS); |
126 | 127 | for_each_possible_cpu (cpu) { | |
127 | return (!test_bit(counter, &__get_cpu_var(perfctr_nmi_owner))); | 128 | if (test_bit(counter, &per_cpu(perfctr_nmi_owner, cpu))) |
129 | return 0; | ||
130 | } | ||
131 | return 1; | ||
128 | } | 132 | } |
129 | 133 | ||
130 | /* checks the an msr for availability */ | 134 | /* checks the an msr for availability */ |
131 | int avail_to_resrv_perfctr_nmi(unsigned int msr) | 135 | int avail_to_resrv_perfctr_nmi(unsigned int msr) |
132 | { | 136 | { |
133 | unsigned int counter; | 137 | unsigned int counter; |
138 | int cpu; | ||
134 | 139 | ||
135 | counter = nmi_perfctr_msr_to_bit(msr); | 140 | counter = nmi_perfctr_msr_to_bit(msr); |
136 | BUG_ON(counter > NMI_MAX_COUNTER_BITS); | 141 | BUG_ON(counter > NMI_MAX_COUNTER_BITS); |
137 | 142 | ||
138 | return (!test_bit(counter, &__get_cpu_var(perfctr_nmi_owner))); | 143 | for_each_possible_cpu (cpu) { |
144 | if (test_bit(counter, &per_cpu(perfctr_nmi_owner, cpu))) | ||
145 | return 0; | ||
146 | } | ||
147 | return 1; | ||
139 | } | 148 | } |
140 | 149 | ||
141 | int reserve_perfctr_nmi(unsigned int msr) | 150 | static int __reserve_perfctr_nmi(int cpu, unsigned int msr) |
142 | { | 151 | { |
143 | unsigned int counter; | 152 | unsigned int counter; |
153 | if (cpu < 0) | ||
154 | cpu = smp_processor_id(); | ||
144 | 155 | ||
145 | counter = nmi_perfctr_msr_to_bit(msr); | 156 | counter = nmi_perfctr_msr_to_bit(msr); |
146 | BUG_ON(counter > NMI_MAX_COUNTER_BITS); | 157 | BUG_ON(counter > NMI_MAX_COUNTER_BITS); |
147 | 158 | ||
148 | if (!test_and_set_bit(counter, &__get_cpu_var(perfctr_nmi_owner))) | 159 | if (!test_and_set_bit(counter, &per_cpu(perfctr_nmi_owner, cpu))) |
149 | return 1; | 160 | return 1; |
150 | return 0; | 161 | return 0; |
151 | } | 162 | } |
152 | 163 | ||
153 | void release_perfctr_nmi(unsigned int msr) | 164 | static void __release_perfctr_nmi(int cpu, unsigned int msr) |
154 | { | 165 | { |
155 | unsigned int counter; | 166 | unsigned int counter; |
167 | if (cpu < 0) | ||
168 | cpu = smp_processor_id(); | ||
156 | 169 | ||
157 | counter = nmi_perfctr_msr_to_bit(msr); | 170 | counter = nmi_perfctr_msr_to_bit(msr); |
158 | BUG_ON(counter > NMI_MAX_COUNTER_BITS); | 171 | BUG_ON(counter > NMI_MAX_COUNTER_BITS); |
159 | 172 | ||
160 | clear_bit(counter, &__get_cpu_var(perfctr_nmi_owner)); | 173 | clear_bit(counter, &per_cpu(perfctr_nmi_owner, cpu)); |
161 | } | 174 | } |
162 | 175 | ||
163 | int reserve_evntsel_nmi(unsigned int msr) | 176 | int reserve_perfctr_nmi(unsigned int msr) |
177 | { | ||
178 | int cpu, i; | ||
179 | for_each_possible_cpu (cpu) { | ||
180 | if (!__reserve_perfctr_nmi(cpu, msr)) { | ||
181 | for_each_possible_cpu (i) { | ||
182 | if (i >= cpu) | ||
183 | break; | ||
184 | __release_perfctr_nmi(i, msr); | ||
185 | } | ||
186 | return 0; | ||
187 | } | ||
188 | } | ||
189 | return 1; | ||
190 | } | ||
191 | |||
192 | void release_perfctr_nmi(unsigned int msr) | ||
193 | { | ||
194 | int cpu; | ||
195 | for_each_possible_cpu (cpu) { | ||
196 | __release_perfctr_nmi(cpu, msr); | ||
197 | } | ||
198 | } | ||
199 | |||
200 | int __reserve_evntsel_nmi(int cpu, unsigned int msr) | ||
164 | { | 201 | { |
165 | unsigned int counter; | 202 | unsigned int counter; |
203 | if (cpu < 0) | ||
204 | cpu = smp_processor_id(); | ||
166 | 205 | ||
167 | counter = nmi_evntsel_msr_to_bit(msr); | 206 | counter = nmi_evntsel_msr_to_bit(msr); |
168 | BUG_ON(counter > NMI_MAX_COUNTER_BITS); | 207 | BUG_ON(counter > NMI_MAX_COUNTER_BITS); |
169 | 208 | ||
170 | if (!test_and_set_bit(counter, &__get_cpu_var(evntsel_nmi_owner)[0])) | 209 | if (!test_and_set_bit(counter, &per_cpu(evntsel_nmi_owner, cpu)[0])) |
171 | return 1; | 210 | return 1; |
172 | return 0; | 211 | return 0; |
173 | } | 212 | } |
174 | 213 | ||
175 | void release_evntsel_nmi(unsigned int msr) | 214 | static void __release_evntsel_nmi(int cpu, unsigned int msr) |
176 | { | 215 | { |
177 | unsigned int counter; | 216 | unsigned int counter; |
217 | if (cpu < 0) | ||
218 | cpu = smp_processor_id(); | ||
178 | 219 | ||
179 | counter = nmi_evntsel_msr_to_bit(msr); | 220 | counter = nmi_evntsel_msr_to_bit(msr); |
180 | BUG_ON(counter > NMI_MAX_COUNTER_BITS); | 221 | BUG_ON(counter > NMI_MAX_COUNTER_BITS); |
181 | 222 | ||
182 | clear_bit(counter, &__get_cpu_var(evntsel_nmi_owner)[0]); | 223 | clear_bit(counter, &per_cpu(evntsel_nmi_owner, cpu)[0]); |
224 | } | ||
225 | |||
226 | int reserve_evntsel_nmi(unsigned int msr) | ||
227 | { | ||
228 | int cpu, i; | ||
229 | for_each_possible_cpu (cpu) { | ||
230 | if (!__reserve_evntsel_nmi(cpu, msr)) { | ||
231 | for_each_possible_cpu (i) { | ||
232 | if (i >= cpu) | ||
233 | break; | ||
234 | __release_evntsel_nmi(i, msr); | ||
235 | } | ||
236 | return 0; | ||
237 | } | ||
238 | } | ||
239 | return 1; | ||
240 | } | ||
241 | |||
242 | void release_evntsel_nmi(unsigned int msr) | ||
243 | { | ||
244 | int cpu; | ||
245 | for_each_possible_cpu (cpu) { | ||
246 | __release_evntsel_nmi(cpu, msr); | ||
247 | } | ||
183 | } | 248 | } |
184 | 249 | ||
185 | static __cpuinit inline int nmi_known_cpu(void) | 250 | static __cpuinit inline int nmi_known_cpu(void) |
@@ -245,14 +310,6 @@ static int __init check_nmi_watchdog(void) | |||
245 | unsigned int *prev_nmi_count; | 310 | unsigned int *prev_nmi_count; |
246 | int cpu; | 311 | int cpu; |
247 | 312 | ||
248 | /* Enable NMI watchdog for newer systems. | ||
249 | Probably safe on most older systems too, but let's be careful. | ||
250 | IBM ThinkPads use INT10 inside SMM and that allows early NMI inside SMM | ||
251 | which hangs the system. Disable watchdog for all thinkpads */ | ||
252 | if (nmi_watchdog == NMI_DEFAULT && dmi_get_year(DMI_BIOS_DATE) >= 2004 && | ||
253 | !dmi_name_in_vendors("ThinkPad")) | ||
254 | nmi_watchdog = NMI_LOCAL_APIC; | ||
255 | |||
256 | if ((nmi_watchdog == NMI_NONE) || (nmi_watchdog == NMI_DEFAULT)) | 313 | if ((nmi_watchdog == NMI_NONE) || (nmi_watchdog == NMI_DEFAULT)) |
257 | return 0; | 314 | return 0; |
258 | 315 | ||
@@ -271,7 +328,7 @@ static int __init check_nmi_watchdog(void) | |||
271 | for_each_possible_cpu(cpu) | 328 | for_each_possible_cpu(cpu) |
272 | prev_nmi_count[cpu] = per_cpu(irq_stat, cpu).__nmi_count; | 329 | prev_nmi_count[cpu] = per_cpu(irq_stat, cpu).__nmi_count; |
273 | local_irq_enable(); | 330 | local_irq_enable(); |
274 | mdelay((10*1000)/nmi_hz); // wait 10 ticks | 331 | mdelay((20*1000)/nmi_hz); // wait 20 ticks |
275 | 332 | ||
276 | for_each_possible_cpu(cpu) { | 333 | for_each_possible_cpu(cpu) { |
277 | #ifdef CONFIG_SMP | 334 | #ifdef CONFIG_SMP |
@@ -515,10 +572,10 @@ static int setup_k7_watchdog(void) | |||
515 | 572 | ||
516 | perfctr_msr = MSR_K7_PERFCTR0; | 573 | perfctr_msr = MSR_K7_PERFCTR0; |
517 | evntsel_msr = MSR_K7_EVNTSEL0; | 574 | evntsel_msr = MSR_K7_EVNTSEL0; |
518 | if (!reserve_perfctr_nmi(perfctr_msr)) | 575 | if (!__reserve_perfctr_nmi(-1, perfctr_msr)) |
519 | goto fail; | 576 | goto fail; |
520 | 577 | ||
521 | if (!reserve_evntsel_nmi(evntsel_msr)) | 578 | if (!__reserve_evntsel_nmi(-1, evntsel_msr)) |
522 | goto fail1; | 579 | goto fail1; |
523 | 580 | ||
524 | wrmsrl(perfctr_msr, 0UL); | 581 | wrmsrl(perfctr_msr, 0UL); |
@@ -541,7 +598,7 @@ static int setup_k7_watchdog(void) | |||
541 | wd->check_bit = 1ULL<<63; | 598 | wd->check_bit = 1ULL<<63; |
542 | return 1; | 599 | return 1; |
543 | fail1: | 600 | fail1: |
544 | release_perfctr_nmi(perfctr_msr); | 601 | __release_perfctr_nmi(-1, perfctr_msr); |
545 | fail: | 602 | fail: |
546 | return 0; | 603 | return 0; |
547 | } | 604 | } |
@@ -552,8 +609,8 @@ static void stop_k7_watchdog(void) | |||
552 | 609 | ||
553 | wrmsr(wd->evntsel_msr, 0, 0); | 610 | wrmsr(wd->evntsel_msr, 0, 0); |
554 | 611 | ||
555 | release_evntsel_nmi(wd->evntsel_msr); | 612 | __release_evntsel_nmi(-1, wd->evntsel_msr); |
556 | release_perfctr_nmi(wd->perfctr_msr); | 613 | __release_perfctr_nmi(-1, wd->perfctr_msr); |
557 | } | 614 | } |
558 | 615 | ||
559 | #define P6_EVNTSEL0_ENABLE (1 << 22) | 616 | #define P6_EVNTSEL0_ENABLE (1 << 22) |
@@ -571,10 +628,10 @@ static int setup_p6_watchdog(void) | |||
571 | 628 | ||
572 | perfctr_msr = MSR_P6_PERFCTR0; | 629 | perfctr_msr = MSR_P6_PERFCTR0; |
573 | evntsel_msr = MSR_P6_EVNTSEL0; | 630 | evntsel_msr = MSR_P6_EVNTSEL0; |
574 | if (!reserve_perfctr_nmi(perfctr_msr)) | 631 | if (!__reserve_perfctr_nmi(-1, perfctr_msr)) |
575 | goto fail; | 632 | goto fail; |
576 | 633 | ||
577 | if (!reserve_evntsel_nmi(evntsel_msr)) | 634 | if (!__reserve_evntsel_nmi(-1, evntsel_msr)) |
578 | goto fail1; | 635 | goto fail1; |
579 | 636 | ||
580 | wrmsrl(perfctr_msr, 0UL); | 637 | wrmsrl(perfctr_msr, 0UL); |
@@ -598,7 +655,7 @@ static int setup_p6_watchdog(void) | |||
598 | wd->check_bit = 1ULL<<39; | 655 | wd->check_bit = 1ULL<<39; |
599 | return 1; | 656 | return 1; |
600 | fail1: | 657 | fail1: |
601 | release_perfctr_nmi(perfctr_msr); | 658 | __release_perfctr_nmi(-1, perfctr_msr); |
602 | fail: | 659 | fail: |
603 | return 0; | 660 | return 0; |
604 | } | 661 | } |
@@ -609,8 +666,8 @@ static void stop_p6_watchdog(void) | |||
609 | 666 | ||
610 | wrmsr(wd->evntsel_msr, 0, 0); | 667 | wrmsr(wd->evntsel_msr, 0, 0); |
611 | 668 | ||
612 | release_evntsel_nmi(wd->evntsel_msr); | 669 | __release_evntsel_nmi(-1, wd->evntsel_msr); |
613 | release_perfctr_nmi(wd->perfctr_msr); | 670 | __release_perfctr_nmi(-1, wd->perfctr_msr); |
614 | } | 671 | } |
615 | 672 | ||
616 | /* Note that these events don't tick when the CPU idles. This means | 673 | /* Note that these events don't tick when the CPU idles. This means |
@@ -676,10 +733,10 @@ static int setup_p4_watchdog(void) | |||
676 | cccr_val = P4_CCCR_OVF_PMI1 | P4_CCCR_ESCR_SELECT(4); | 733 | cccr_val = P4_CCCR_OVF_PMI1 | P4_CCCR_ESCR_SELECT(4); |
677 | } | 734 | } |
678 | 735 | ||
679 | if (!reserve_perfctr_nmi(perfctr_msr)) | 736 | if (!__reserve_perfctr_nmi(-1, perfctr_msr)) |
680 | goto fail; | 737 | goto fail; |
681 | 738 | ||
682 | if (!reserve_evntsel_nmi(evntsel_msr)) | 739 | if (!__reserve_evntsel_nmi(-1, evntsel_msr)) |
683 | goto fail1; | 740 | goto fail1; |
684 | 741 | ||
685 | evntsel = P4_ESCR_EVENT_SELECT(0x3F) | 742 | evntsel = P4_ESCR_EVENT_SELECT(0x3F) |
@@ -703,7 +760,7 @@ static int setup_p4_watchdog(void) | |||
703 | wd->check_bit = 1ULL<<39; | 760 | wd->check_bit = 1ULL<<39; |
704 | return 1; | 761 | return 1; |
705 | fail1: | 762 | fail1: |
706 | release_perfctr_nmi(perfctr_msr); | 763 | __release_perfctr_nmi(-1, perfctr_msr); |
707 | fail: | 764 | fail: |
708 | return 0; | 765 | return 0; |
709 | } | 766 | } |
@@ -715,8 +772,8 @@ static void stop_p4_watchdog(void) | |||
715 | wrmsr(wd->cccr_msr, 0, 0); | 772 | wrmsr(wd->cccr_msr, 0, 0); |
716 | wrmsr(wd->evntsel_msr, 0, 0); | 773 | wrmsr(wd->evntsel_msr, 0, 0); |
717 | 774 | ||
718 | release_evntsel_nmi(wd->evntsel_msr); | 775 | __release_evntsel_nmi(-1, wd->evntsel_msr); |
719 | release_perfctr_nmi(wd->perfctr_msr); | 776 | __release_perfctr_nmi(-1, wd->perfctr_msr); |
720 | } | 777 | } |
721 | 778 | ||
722 | #define ARCH_PERFMON_NMI_EVENT_SEL ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL | 779 | #define ARCH_PERFMON_NMI_EVENT_SEL ARCH_PERFMON_UNHALTED_CORE_CYCLES_SEL |
@@ -744,10 +801,10 @@ static int setup_intel_arch_watchdog(void) | |||
744 | perfctr_msr = MSR_ARCH_PERFMON_PERFCTR0; | 801 | perfctr_msr = MSR_ARCH_PERFMON_PERFCTR0; |
745 | evntsel_msr = MSR_ARCH_PERFMON_EVENTSEL0; | 802 | evntsel_msr = MSR_ARCH_PERFMON_EVENTSEL0; |
746 | 803 | ||
747 | if (!reserve_perfctr_nmi(perfctr_msr)) | 804 | if (!__reserve_perfctr_nmi(-1, perfctr_msr)) |
748 | goto fail; | 805 | goto fail; |
749 | 806 | ||
750 | if (!reserve_evntsel_nmi(evntsel_msr)) | 807 | if (!__reserve_evntsel_nmi(-1, evntsel_msr)) |
751 | goto fail1; | 808 | goto fail1; |
752 | 809 | ||
753 | wrmsrl(perfctr_msr, 0UL); | 810 | wrmsrl(perfctr_msr, 0UL); |
@@ -772,7 +829,7 @@ static int setup_intel_arch_watchdog(void) | |||
772 | wd->check_bit = 1ULL << (eax.split.bit_width - 1); | 829 | wd->check_bit = 1ULL << (eax.split.bit_width - 1); |
773 | return 1; | 830 | return 1; |
774 | fail1: | 831 | fail1: |
775 | release_perfctr_nmi(perfctr_msr); | 832 | __release_perfctr_nmi(-1, perfctr_msr); |
776 | fail: | 833 | fail: |
777 | return 0; | 834 | return 0; |
778 | } | 835 | } |
@@ -795,8 +852,8 @@ static void stop_intel_arch_watchdog(void) | |||
795 | return; | 852 | return; |
796 | 853 | ||
797 | wrmsr(wd->evntsel_msr, 0, 0); | 854 | wrmsr(wd->evntsel_msr, 0, 0); |
798 | release_evntsel_nmi(wd->evntsel_msr); | 855 | __release_evntsel_nmi(-1, wd->evntsel_msr); |
799 | release_perfctr_nmi(wd->perfctr_msr); | 856 | __release_perfctr_nmi(-1, wd->perfctr_msr); |
800 | } | 857 | } |
801 | 858 | ||
802 | void setup_apic_nmi_watchdog (void *unused) | 859 | void setup_apic_nmi_watchdog (void *unused) |