~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/i386/kernel/nmi.c

Version: ~ [ linux-5.16-rc3 ] ~ [ linux-5.15.5 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.82 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.162 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.218 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.256 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.291 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.293 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  linux/arch/i386/nmi.c
  3  *
  4  *  NMI watchdog support on APIC systems
  5  *
  6  *  Started by Ingo Molnar <mingo@redhat.com>
  7  *
  8  *  Fixes:
  9  *  Mikael Pettersson   : AMD K7 support for local APIC NMI watchdog.
 10  *  Mikael Pettersson   : Power Management for local APIC NMI watchdog.
 11  *  Mikael Pettersson   : Pentium 4 support for local APIC NMI watchdog.
 12  *  Pavel Machek and
 13  *  Mikael Pettersson   : PM converted to driver model. Disable/enable API.
 14  */
 15 
 16 #include <linux/config.h>
 17 #include <linux/mm.h>
 18 #include <linux/irq.h>
 19 #include <linux/delay.h>
 20 #include <linux/bootmem.h>
 21 #include <linux/smp_lock.h>
 22 #include <linux/interrupt.h>
 23 #include <linux/mc146818rtc.h>
 24 #include <linux/kernel_stat.h>
 25 #include <linux/module.h>
 26 #include <linux/nmi.h>
 27 #include <linux/sysdev.h>
 28 
 29 #include <asm/smp.h>
 30 #include <asm/mtrr.h>
 31 #include <asm/mpspec.h>
 32 #include <asm/nmi.h>
 33 
 34 unsigned int nmi_watchdog = NMI_NONE;
 35 static unsigned int nmi_hz = HZ;
 36 unsigned int nmi_perfctr_msr;   /* the MSR to reset in NMI handler */
 37 extern void show_registers(struct pt_regs *regs);
 38 
 39 /* nmi_active:
 40  * +1: the lapic NMI watchdog is active, but can be disabled
 41  *  0: the lapic NMI watchdog has not been set up, and cannot
 42  *     be enabled
 43  * -1: the lapic NMI watchdog is disabled, but can be enabled
 44  */
 45 static int nmi_active;
 46 
 47 #define K7_EVNTSEL_ENABLE       (1 << 22)
 48 #define K7_EVNTSEL_INT          (1 << 20)
 49 #define K7_EVNTSEL_OS           (1 << 17)
 50 #define K7_EVNTSEL_USR          (1 << 16)
 51 #define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING    0x76
 52 #define K7_NMI_EVENT            K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING
 53 
 54 #define P6_EVNTSEL0_ENABLE      (1 << 22)
 55 #define P6_EVNTSEL_INT          (1 << 20)
 56 #define P6_EVNTSEL_OS           (1 << 17)
 57 #define P6_EVNTSEL_USR          (1 << 16)
 58 #define P6_EVENT_CPU_CLOCKS_NOT_HALTED  0x79
 59 #define P6_NMI_EVENT            P6_EVENT_CPU_CLOCKS_NOT_HALTED
 60 
 61 #define MSR_P4_MISC_ENABLE      0x1A0
 62 #define MSR_P4_MISC_ENABLE_PERF_AVAIL   (1<<7)
 63 #define MSR_P4_MISC_ENABLE_PEBS_UNAVAIL (1<<12)
 64 #define MSR_P4_PERFCTR0         0x300
 65 #define MSR_P4_CCCR0            0x360
 66 #define P4_ESCR_EVENT_SELECT(N) ((N)<<25)
 67 #define P4_ESCR_OS              (1<<3)
 68 #define P4_ESCR_USR             (1<<2)
 69 #define P4_CCCR_OVF_PMI         (1<<26)
 70 #define P4_CCCR_THRESHOLD(N)    ((N)<<20)
 71 #define P4_CCCR_COMPLEMENT      (1<<19)
 72 #define P4_CCCR_COMPARE         (1<<18)
 73 #define P4_CCCR_REQUIRED        (3<<16)
 74 #define P4_CCCR_ESCR_SELECT(N)  ((N)<<13)
 75 #define P4_CCCR_ENABLE          (1<<12)
 76 /* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
 77    CRU_ESCR0 (with any non-null event selector) through a complemented
 78    max threshold. [IA32-Vol3, Section 14.9.9] */
 79 #define MSR_P4_IQ_COUNTER0      0x30C
 80 #define P4_NMI_CRU_ESCR0        (P4_ESCR_EVENT_SELECT(0x3F)|P4_ESCR_OS|P4_ESCR_USR)
 81 #define P4_NMI_IQ_CCCR0 \
 82         (P4_CCCR_OVF_PMI|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT|      \
 83          P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE)
 84 
 85 int __init check_nmi_watchdog (void)
 86 {
 87         unsigned int prev_nmi_count[NR_CPUS];
 88         int cpu;
 89 
 90         printk(KERN_INFO "testing NMI watchdog ... ");
 91 
 92         for (cpu = 0; cpu < NR_CPUS; cpu++)
 93                 prev_nmi_count[cpu] = irq_stat[cpu].__nmi_count;
 94         local_irq_enable();
 95         mdelay((10*1000)/nmi_hz); // wait 10 ticks
 96 
 97         /* FIXME: Only boot CPU is online at this stage.  Check CPUs
 98            as they come up. */
 99         for (cpu = 0; cpu < NR_CPUS; cpu++) {
100                 if (!cpu_online(cpu))
101                         continue;
102                 if (nmi_count(cpu) - prev_nmi_count[cpu] <= 5) {
103                         printk("CPU#%d: NMI appears to be stuck!\n", cpu);
104                         nmi_active = 0;
105                         return -1;
106                 }
107         }
108         printk("OK.\n");
109 
110         /* now that we know it works we can reduce NMI frequency to
111            something more reasonable; makes a difference in some configs */
112         if (nmi_watchdog == NMI_LOCAL_APIC)
113                 nmi_hz = 1;
114 
115         return 0;
116 }
117 
118 static int __init setup_nmi_watchdog(char *str)
119 {
120         int nmi;
121 
122         get_option(&str, &nmi);
123 
124         if (nmi >= NMI_INVALID)
125                 return 0;
126         if (nmi == NMI_NONE)
127                 nmi_watchdog = nmi;
128         /*
129          * If any other x86 CPU has a local APIC, then
130          * please test the NMI stuff there and send me the
131          * missing bits. Right now Intel P6/P4 and AMD K7 only.
132          */
133         if ((nmi == NMI_LOCAL_APIC) &&
134                         (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
135                         (boot_cpu_data.x86 == 6 || boot_cpu_data.x86 == 15))
136                 nmi_watchdog = nmi;
137         if ((nmi == NMI_LOCAL_APIC) &&
138                         (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
139                         (boot_cpu_data.x86 == 6 || boot_cpu_data.x86 == 15))
140                 nmi_watchdog = nmi;
141         /*
142          * We can enable the IO-APIC watchdog
143          * unconditionally.
144          */
145         if (nmi == NMI_IO_APIC) {
146                 nmi_active = 1;
147                 nmi_watchdog = nmi;
148         }
149         return 1;
150 }
151 
152 __setup("nmi_watchdog=", setup_nmi_watchdog);
153 
154 void disable_lapic_nmi_watchdog(void)
155 {
156         if (nmi_active <= 0)
157                 return;
158         switch (boot_cpu_data.x86_vendor) {
159         case X86_VENDOR_AMD:
160                 wrmsr(MSR_K7_EVNTSEL0, 0, 0);
161                 break;
162         case X86_VENDOR_INTEL:
163                 switch (boot_cpu_data.x86) {
164                 case 6:
165                         if (boot_cpu_data.x86_model > 0xd)
166                                 break;
167 
168                         wrmsr(MSR_P6_EVNTSEL0, 0, 0);
169                         break;
170                 case 15:
171                         if (boot_cpu_data.x86_model > 0x3)
172                                 break;
173 
174                         wrmsr(MSR_P4_IQ_CCCR0, 0, 0);
175                         wrmsr(MSR_P4_CRU_ESCR0, 0, 0);
176                         break;
177                 }
178                 break;
179         }
180         nmi_active = -1;
181         /* tell do_nmi() and others that we're not active any more */
182         nmi_watchdog = 0;
183 }
184 
185 void enable_lapic_nmi_watchdog(void)
186 {
187         if (nmi_active < 0) {
188                 nmi_watchdog = NMI_LOCAL_APIC;
189                 setup_apic_nmi_watchdog();
190         }
191 }
192 
193 void disable_timer_nmi_watchdog(void)
194 {
195         if ((nmi_watchdog != NMI_IO_APIC) || (nmi_active <= 0))
196                 return;
197 
198         unset_nmi_callback();
199         nmi_active = -1;
200         nmi_watchdog = NMI_NONE;
201 }
202 
203 void enable_timer_nmi_watchdog(void)
204 {
205         if (nmi_active < 0) {
206                 nmi_watchdog = NMI_IO_APIC;
207                 touch_nmi_watchdog();
208                 nmi_active = 1;
209         }
210 }
211 
212 #ifdef CONFIG_PM
213 
214 static int nmi_pm_active; /* nmi_active before suspend */
215 
216 static int lapic_nmi_suspend(struct sys_device *dev, u32 state)
217 {
218         nmi_pm_active = nmi_active;
219         disable_lapic_nmi_watchdog();
220         return 0;
221 }
222 
223 static int lapic_nmi_resume(struct sys_device *dev)
224 {
225         if (nmi_pm_active > 0)
226                 enable_lapic_nmi_watchdog();
227         return 0;
228 }
229 
230 
231 static struct sysdev_class nmi_sysclass = {
232         set_kset_name("lapic_nmi"),
233         .resume         = lapic_nmi_resume,
234         .suspend        = lapic_nmi_suspend,
235 };
236 
237 static struct sys_device device_lapic_nmi = {
238         .id     = 0,
239         .cls    = &nmi_sysclass,
240 };
241 
242 static int __init init_lapic_nmi_sysfs(void)
243 {
244         int error;
245 
246         if (nmi_active == 0)
247                 return 0;
248 
249         error = sysdev_class_register(&nmi_sysclass);
250         if (!error)
251                 error = sys_device_register(&device_lapic_nmi);
252         return error;
253 }
254 /* must come after the local APIC's device_initcall() */
255 late_initcall(init_lapic_nmi_sysfs);
256 
257 #endif  /* CONFIG_PM */
258 
259 /*
260  * Activate the NMI watchdog via the local APIC.
261  * Original code written by Keith Owens.
262  */
263 
264 static void clear_msr_range(unsigned int base, unsigned int n)
265 {
266         unsigned int i;
267 
268         for(i = 0; i < n; ++i)
269                 wrmsr(base+i, 0, 0);
270 }
271 
272 static void setup_k7_watchdog(void)
273 {
274         unsigned int evntsel;
275 
276         nmi_perfctr_msr = MSR_K7_PERFCTR0;
277 
278         clear_msr_range(MSR_K7_EVNTSEL0, 4);
279         clear_msr_range(MSR_K7_PERFCTR0, 4);
280 
281         evntsel = K7_EVNTSEL_INT
282                 | K7_EVNTSEL_OS
283                 | K7_EVNTSEL_USR
284                 | K7_NMI_EVENT;
285 
286         wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
287         Dprintk("setting K7_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000));
288         wrmsr(MSR_K7_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1);
289         apic_write(APIC_LVTPC, APIC_DM_NMI);
290         evntsel |= K7_EVNTSEL_ENABLE;
291         wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
292 }
293 
294 static void setup_p6_watchdog(void)
295 {
296         unsigned int evntsel;
297 
298         nmi_perfctr_msr = MSR_P6_PERFCTR0;
299 
300         clear_msr_range(MSR_P6_EVNTSEL0, 2);
301         clear_msr_range(MSR_P6_PERFCTR0, 2);
302 
303         evntsel = P6_EVNTSEL_INT
304                 | P6_EVNTSEL_OS
305                 | P6_EVNTSEL_USR
306                 | P6_NMI_EVENT;
307 
308         wrmsr(MSR_P6_EVNTSEL0, evntsel, 0);
309         Dprintk("setting P6_PERFCTR0 to %08lx\n", -(cpu_khz/nmi_hz*1000));
310         wrmsr(MSR_P6_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0);
311         apic_write(APIC_LVTPC, APIC_DM_NMI);
312         evntsel |= P6_EVNTSEL0_ENABLE;
313         wrmsr(MSR_P6_EVNTSEL0, evntsel, 0);
314 }
315 
316 static int setup_p4_watchdog(void)
317 {
318         unsigned int misc_enable, dummy;
319 
320         rdmsr(MSR_P4_MISC_ENABLE, misc_enable, dummy);
321         if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL))
322                 return 0;
323 
324         nmi_perfctr_msr = MSR_P4_IQ_COUNTER0;
325 
326         if (!(misc_enable & MSR_P4_MISC_ENABLE_PEBS_UNAVAIL))
327                 clear_msr_range(0x3F1, 2);
328         /* MSR 0x3F0 seems to have a default value of 0xFC00, but current
329            docs doesn't fully define it, so leave it alone for now. */
330         clear_msr_range(0x3A0, 31);
331         clear_msr_range(0x3C0, 6);
332         clear_msr_range(0x3C8, 6);
333         clear_msr_range(0x3E0, 2);
334         clear_msr_range(MSR_P4_CCCR0, 18);
335         clear_msr_range(MSR_P4_PERFCTR0, 18);
336 
337         wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0);
338         wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0);
339         Dprintk("setting P4_IQ_COUNTER0 to 0x%08lx\n", -(cpu_khz/nmi_hz*1000));
340         wrmsr(MSR_P4_IQ_COUNTER0, -(cpu_khz/nmi_hz*1000), -1);
341         apic_write(APIC_LVTPC, APIC_DM_NMI);
342         wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
343         return 1;
344 }
345 
346 void setup_apic_nmi_watchdog (void)
347 {
348         switch (boot_cpu_data.x86_vendor) {
349         case X86_VENDOR_AMD:
350                 if (boot_cpu_data.x86 != 6 && boot_cpu_data.x86 != 15)
351                         return;
352                 setup_k7_watchdog();
353                 break;
354         case X86_VENDOR_INTEL:
355                 switch (boot_cpu_data.x86) {
356                 case 6:
357                         if (boot_cpu_data.x86_model > 0xd)
358                                 return;
359 
360                         setup_p6_watchdog();
361                         break;
362                 case 15:
363                         if (boot_cpu_data.x86_model > 0x3)
364                                 return;
365 
366                         if (!setup_p4_watchdog())
367                                 return;
368                         break;
369                 default:
370                         return;
371                 }
372                 break;
373         default:
374                 return;
375         }
376         nmi_active = 1;
377 }
378 
379 static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED;
380 
381 /*
382  * the best way to detect whether a CPU has a 'hard lockup' problem
383  * is to check it's local APIC timer IRQ counts. If they are not
384  * changing then that CPU has some problem.
385  *
386  * as these watchdog NMI IRQs are generated on every CPU, we only
387  * have to check the current processor.
388  *
389  * since NMIs don't listen to _any_ locks, we have to be extremely
390  * careful not to rely on unsafe variables. The printk might lock
391  * up though, so we have to break up any console locks first ...
392  * [when there will be more tty-related locks, break them up
393  *  here too!]
394  */
395 
396 static unsigned int
397         last_irq_sums [NR_CPUS],
398         alert_counter [NR_CPUS];
399 
400 void touch_nmi_watchdog (void)
401 {
402         int i;
403 
404         /*
405          * Just reset the alert counters, (other CPUs might be
406          * spinning on locks we hold):
407          */
408         for (i = 0; i < NR_CPUS; i++)
409                 alert_counter[i] = 0;
410 }
411 
412 void nmi_watchdog_tick (struct pt_regs * regs)
413 {
414 
415         /*
416          * Since current_thread_info()-> is always on the stack, and we
417          * always switch the stack NMI-atomically, it's safe to use
418          * smp_processor_id().
419          */
420         int sum, cpu = smp_processor_id();
421 
422         sum = irq_stat[cpu].apic_timer_irqs;
423 
424         if (last_irq_sums[cpu] == sum) {
425                 /*
426                  * Ayiee, looks like this CPU is stuck ...
427                  * wait a few IRQs (5 seconds) before doing the oops ...
428                  */
429                 alert_counter[cpu]++;
430                 if (alert_counter[cpu] == 5*nmi_hz) {
431                         spin_lock(&nmi_print_lock);
432                         /*
433                          * We are in trouble anyway, lets at least try
434                          * to get a message out.
435                          */
436                         bust_spinlocks(1);
437                         printk("NMI Watchdog detected LOCKUP on CPU%d, eip %08lx, registers:\n", cpu, regs->eip);
438                         show_registers(regs);
439                         printk("console shuts up ...\n");
440                         console_silent();
441                         spin_unlock(&nmi_print_lock);
442                         bust_spinlocks(0);
443                         do_exit(SIGSEGV);
444                 }
445         } else {
446                 last_irq_sums[cpu] = sum;
447                 alert_counter[cpu] = 0;
448         }
449         if (nmi_perfctr_msr) {
450                 if (nmi_perfctr_msr == MSR_P4_IQ_COUNTER0) {
451                         /*
452                          * P4 quirks:
453                          * - An overflown perfctr will assert its interrupt
454                          *   until the OVF flag in its CCCR is cleared.
455                          * - LVTPC is masked on interrupt and must be
456                          *   unmasked by the LVTPC handler.
457                          */
458                         wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
459                         apic_write(APIC_LVTPC, APIC_DM_NMI);
460                 }
461                 wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1);
462         }
463 }
464 
465 EXPORT_SYMBOL(nmi_watchdog);
466 EXPORT_SYMBOL(disable_lapic_nmi_watchdog);
467 EXPORT_SYMBOL(enable_lapic_nmi_watchdog);
468 EXPORT_SYMBOL(disable_timer_nmi_watchdog);
469 EXPORT_SYMBOL(enable_timer_nmi_watchdog);
470 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp