nmi.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:9k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  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.  */
  13. #include <linux/config.h>
  14. #include <linux/mm.h>
  15. #include <linux/irq.h>
  16. #include <linux/delay.h>
  17. #include <linux/bootmem.h>
  18. #include <linux/smp_lock.h>
  19. #include <linux/interrupt.h>
  20. #include <linux/mc146818rtc.h>
  21. #include <linux/kernel_stat.h>
  22. #include <asm/smp.h>
  23. #include <asm/mtrr.h>
  24. #include <asm/mpspec.h>
  25. unsigned int nmi_watchdog = NMI_NONE;
  26. static unsigned int nmi_hz = HZ;
  27. unsigned int nmi_perfctr_msr; /* the MSR to reset in NMI handler */
  28. extern void show_registers(struct pt_regs *regs);
  29. #define K7_EVNTSEL_ENABLE (1 << 22)
  30. #define K7_EVNTSEL_INT (1 << 20)
  31. #define K7_EVNTSEL_OS (1 << 17)
  32. #define K7_EVNTSEL_USR (1 << 16)
  33. #define K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING 0x76
  34. #define K7_NMI_EVENT K7_EVENT_CYCLES_PROCESSOR_IS_RUNNING
  35. #define P6_EVNTSEL0_ENABLE (1 << 22)
  36. #define P6_EVNTSEL_INT (1 << 20)
  37. #define P6_EVNTSEL_OS (1 << 17)
  38. #define P6_EVNTSEL_USR (1 << 16)
  39. #define P6_EVENT_CPU_CLOCKS_NOT_HALTED 0x79
  40. #define P6_NMI_EVENT P6_EVENT_CPU_CLOCKS_NOT_HALTED
  41. #define MSR_P4_MISC_ENABLE 0x1A0
  42. #define MSR_P4_MISC_ENABLE_PERF_AVAIL (1<<7)
  43. #define MSR_P4_MISC_ENABLE_PEBS_UNAVAIL (1<<12)
  44. #define MSR_P4_PERFCTR0 0x300
  45. #define MSR_P4_CCCR0 0x360
  46. #define P4_ESCR_EVENT_SELECT(N) ((N)<<25)
  47. #define P4_ESCR_OS (1<<3)
  48. #define P4_ESCR_USR (1<<2)
  49. #define P4_CCCR_OVF_PMI (1<<26)
  50. #define P4_CCCR_THRESHOLD(N) ((N)<<20)
  51. #define P4_CCCR_COMPLEMENT (1<<19)
  52. #define P4_CCCR_COMPARE (1<<18)
  53. #define P4_CCCR_REQUIRED (3<<16)
  54. #define P4_CCCR_ESCR_SELECT(N) ((N)<<13)
  55. #define P4_CCCR_ENABLE (1<<12)
  56. /* Set up IQ_COUNTER0 to behave like a clock, by having IQ_CCCR0 filter
  57.    CRU_ESCR0 (with any non-null event selector) through a complemented
  58.    max threshold. [IA32-Vol3, Section 14.9.9] */
  59. #define MSR_P4_IQ_COUNTER0 0x30C
  60. #define MSR_P4_IQ_CCCR0 0x36C
  61. #define MSR_P4_CRU_ESCR0 0x3B8
  62. #define P4_NMI_CRU_ESCR0 (P4_ESCR_EVENT_SELECT(0x3F)|P4_ESCR_OS|P4_ESCR_USR)
  63. #define P4_NMI_IQ_CCCR0
  64. (P4_CCCR_OVF_PMI|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT|
  65.  P4_CCCR_COMPARE|P4_CCCR_REQUIRED|P4_CCCR_ESCR_SELECT(4)|P4_CCCR_ENABLE)
  66. int __init check_nmi_watchdog (void)
  67. {
  68. irq_cpustat_t tmp[NR_CPUS];
  69. int j, cpu;
  70. printk(KERN_INFO "testing NMI watchdog ... ");
  71. memcpy(tmp, irq_stat, sizeof(tmp));
  72. sti();
  73. mdelay((10*1000)/nmi_hz); // wait 10 ticks
  74. for (j = 0; j < smp_num_cpus; j++) {
  75. cpu = cpu_logical_map(j);
  76. if (nmi_count(cpu) - tmp[cpu].__nmi_count <= 5) {
  77. printk("CPU#%d: NMI appears to be stuck!n", cpu);
  78. return -1;
  79. }
  80. }
  81. printk("OK.n");
  82. /* now that we know it works we can reduce NMI frequency to
  83.    something more reasonable; makes a difference in some configs */
  84. if (nmi_watchdog == NMI_LOCAL_APIC)
  85. nmi_hz = 1;
  86. return 0;
  87. }
  88. static int __init setup_nmi_watchdog(char *str)
  89. {
  90. int nmi;
  91. get_option(&str, &nmi);
  92. if (nmi >= NMI_INVALID)
  93. return 0;
  94. if (nmi == NMI_NONE)
  95. nmi_watchdog = nmi;
  96. /*
  97.  * If any other x86 CPU has a local APIC, then
  98.  * please test the NMI stuff there and send me the
  99.  * missing bits. Right now Intel P6/P4 and AMD K7 only.
  100.  */
  101. if ((nmi == NMI_LOCAL_APIC) &&
  102. (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) &&
  103. (boot_cpu_data.x86 == 6 || boot_cpu_data.x86 == 15))
  104. nmi_watchdog = nmi;
  105. if ((nmi == NMI_LOCAL_APIC) &&
  106. (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) &&
  107. (boot_cpu_data.x86 == 6))
  108. nmi_watchdog = nmi;
  109. /*
  110.  * We can enable the IO-APIC watchdog
  111.  * unconditionally.
  112.  */
  113. if (nmi == NMI_IO_APIC)
  114. nmi_watchdog = nmi;
  115. return 1;
  116. }
  117. __setup("nmi_watchdog=", setup_nmi_watchdog);
  118. #ifdef CONFIG_PM
  119. #include <linux/pm.h>
  120. struct pm_dev *nmi_pmdev;
  121. static void disable_apic_nmi_watchdog(void)
  122. {
  123. switch (boot_cpu_data.x86_vendor) {
  124. case X86_VENDOR_AMD:
  125. wrmsr(MSR_K7_EVNTSEL0, 0, 0);
  126. break;
  127. case X86_VENDOR_INTEL:
  128. switch (boot_cpu_data.x86) {
  129. case 6:
  130. wrmsr(MSR_P6_EVNTSEL0, 0, 0);
  131. break;
  132. case 15:
  133. wrmsr(MSR_P4_IQ_CCCR0, 0, 0);
  134. wrmsr(MSR_P4_CRU_ESCR0, 0, 0);
  135. break;
  136. }
  137. break;
  138. }
  139. }
  140. static int nmi_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data)
  141. {
  142. switch (rqst) {
  143. case PM_SUSPEND:
  144. disable_apic_nmi_watchdog();
  145. break;
  146. case PM_RESUME:
  147. setup_apic_nmi_watchdog();
  148. break;
  149. }
  150. return 0;
  151. }
  152. static void nmi_pm_init(void)
  153. {
  154. if (!nmi_pmdev)
  155. nmi_pmdev = apic_pm_register(PM_SYS_DEV, 0, nmi_pm_callback);
  156. }
  157. #define __pminit /*empty*/
  158. #else /* CONFIG_PM */
  159. static inline void nmi_pm_init(void) { }
  160. #define __pminit __init
  161. #endif /* CONFIG_PM */
  162. /*
  163.  * Activate the NMI watchdog via the local APIC.
  164.  * Original code written by Keith Owens.
  165.  */
  166. static void __pminit clear_msr_range(unsigned int base, unsigned int n)
  167. {
  168. unsigned int i;
  169. for(i = 0; i < n; ++i)
  170. wrmsr(base+i, 0, 0);
  171. }
  172. static void __pminit setup_k7_watchdog(void)
  173. {
  174. unsigned int evntsel;
  175. nmi_perfctr_msr = MSR_K7_PERFCTR0;
  176. clear_msr_range(MSR_K7_EVNTSEL0, 4);
  177. clear_msr_range(MSR_K7_PERFCTR0, 4);
  178. evntsel = K7_EVNTSEL_INT
  179. | K7_EVNTSEL_OS
  180. | K7_EVNTSEL_USR
  181. | K7_NMI_EVENT;
  182. wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
  183. Dprintk("setting K7_PERFCTR0 to %08lxn", -(cpu_khz/nmi_hz*1000));
  184. wrmsr(MSR_K7_PERFCTR0, -(cpu_khz/nmi_hz*1000), -1);
  185. apic_write(APIC_LVTPC, APIC_DM_NMI);
  186. evntsel |= K7_EVNTSEL_ENABLE;
  187. wrmsr(MSR_K7_EVNTSEL0, evntsel, 0);
  188. }
  189. static void __pminit setup_p6_watchdog(void)
  190. {
  191. unsigned int evntsel;
  192. nmi_perfctr_msr = MSR_P6_PERFCTR0;
  193. clear_msr_range(MSR_P6_EVNTSEL0, 2);
  194. clear_msr_range(MSR_P6_PERFCTR0, 2);
  195. evntsel = P6_EVNTSEL_INT
  196. | P6_EVNTSEL_OS
  197. | P6_EVNTSEL_USR
  198. | P6_NMI_EVENT;
  199. wrmsr(MSR_P6_EVNTSEL0, evntsel, 0);
  200. Dprintk("setting P6_PERFCTR0 to %08lxn", -(cpu_khz/nmi_hz*1000));
  201. wrmsr(MSR_P6_PERFCTR0, -(cpu_khz/nmi_hz*1000), 0);
  202. apic_write(APIC_LVTPC, APIC_DM_NMI);
  203. evntsel |= P6_EVNTSEL0_ENABLE;
  204. wrmsr(MSR_P6_EVNTSEL0, evntsel, 0);
  205. }
  206. static int __pminit setup_p4_watchdog(void)
  207. {
  208. unsigned int misc_enable, dummy;
  209. rdmsr(MSR_P4_MISC_ENABLE, misc_enable, dummy);
  210. if (!(misc_enable & MSR_P4_MISC_ENABLE_PERF_AVAIL))
  211. return 0;
  212. nmi_perfctr_msr = MSR_P4_IQ_COUNTER0;
  213. if (!(misc_enable & MSR_P4_MISC_ENABLE_PEBS_UNAVAIL))
  214. clear_msr_range(0x3F1, 2);
  215. /* MSR 0x3F0 seems to have a default value of 0xFC00, but current
  216.    docs doesn't fully define it, so leave it alone for now. */
  217. clear_msr_range(0x3A0, 31);
  218. clear_msr_range(0x3C0, 6);
  219. clear_msr_range(0x3C8, 6);
  220. clear_msr_range(0x3E0, 2);
  221. clear_msr_range(MSR_P4_CCCR0, 18);
  222. clear_msr_range(MSR_P4_PERFCTR0, 18);
  223. wrmsr(MSR_P4_CRU_ESCR0, P4_NMI_CRU_ESCR0, 0);
  224. wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0 & ~P4_CCCR_ENABLE, 0);
  225. Dprintk("setting P4_IQ_COUNTER0 to 0x%08lxn", -(cpu_khz/nmi_hz*1000));
  226. wrmsr(MSR_P4_IQ_COUNTER0, -(cpu_khz/nmi_hz*1000), -1);
  227. apic_write(APIC_LVTPC, APIC_DM_NMI);
  228. wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
  229. return 1;
  230. }
  231. void __pminit setup_apic_nmi_watchdog (void)
  232. {
  233. switch (boot_cpu_data.x86_vendor) {
  234. case X86_VENDOR_AMD:
  235. if (boot_cpu_data.x86 != 6)
  236. return;
  237. setup_k7_watchdog();
  238. break;
  239. case X86_VENDOR_INTEL:
  240. switch (boot_cpu_data.x86) {
  241. case 6:
  242. setup_p6_watchdog();
  243. break;
  244. case 15:
  245. if (!setup_p4_watchdog())
  246. return;
  247. break;
  248. default:
  249. return;
  250. }
  251. break;
  252. default:
  253. return;
  254. }
  255. nmi_pm_init();
  256. }
  257. static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED;
  258. /*
  259.  * the best way to detect whether a CPU has a 'hard lockup' problem
  260.  * is to check it's local APIC timer IRQ counts. If they are not
  261.  * changing then that CPU has some problem.
  262.  *
  263.  * as these watchdog NMI IRQs are generated on every CPU, we only
  264.  * have to check the current processor.
  265.  *
  266.  * since NMIs dont listen to _any_ locks, we have to be extremely
  267.  * careful not to rely on unsafe variables. The printk might lock
  268.  * up though, so we have to break up any console locks first ...
  269.  * [when there will be more tty-related locks, break them up
  270.  *  here too!]
  271.  */
  272. static unsigned int
  273. last_irq_sums [NR_CPUS],
  274. alert_counter [NR_CPUS];
  275. void touch_nmi_watchdog (void)
  276. {
  277. int i;
  278. /*
  279.  * Just reset the alert counters, (other CPUs might be
  280.  * spinning on locks we hold):
  281.  */
  282. for (i = 0; i < smp_num_cpus; i++)
  283. alert_counter[i] = 0;
  284. }
  285. void nmi_watchdog_tick (struct pt_regs * regs)
  286. {
  287. /*
  288.  * Since current-> is always on the stack, and we always switch
  289.  * the stack NMI-atomically, it's safe to use smp_processor_id().
  290.  */
  291. int sum, cpu = smp_processor_id();
  292. sum = apic_timer_irqs[cpu];
  293. if (last_irq_sums[cpu] == sum) {
  294. /*
  295.  * Ayiee, looks like this CPU is stuck ...
  296.  * wait a few IRQs (5 seconds) before doing the oops ...
  297.  */
  298. alert_counter[cpu]++;
  299. if (alert_counter[cpu] == 5*nmi_hz) {
  300. spin_lock(&nmi_print_lock);
  301. /*
  302.  * We are in trouble anyway, lets at least try
  303.  * to get a message out.
  304.  */
  305. bust_spinlocks(1);
  306. printk("NMI Watchdog detected LOCKUP on CPU%d, eip %08lx, registers:n", cpu, regs->eip);
  307. show_registers(regs);
  308. printk("console shuts up ...n");
  309. console_silent();
  310. spin_unlock(&nmi_print_lock);
  311. bust_spinlocks(0);
  312. do_exit(SIGSEGV);
  313. }
  314. } else {
  315. last_irq_sums[cpu] = sum;
  316. alert_counter[cpu] = 0;
  317. }
  318. if (nmi_perfctr_msr) {
  319. if (nmi_perfctr_msr == MSR_P4_IQ_COUNTER0) {
  320. /*
  321.  * P4 quirks:
  322.  * - An overflown perfctr will assert its interrupt
  323.  *   until the OVF flag in its CCCR is cleared.
  324.  * - LVTPC is masked on interrupt and must be
  325.  *   unmasked by the LVTPC handler.
  326.  */
  327. wrmsr(MSR_P4_IQ_CCCR0, P4_NMI_IQ_CCCR0, 0);
  328. apic_write(APIC_LVTPC, APIC_DM_NMI);
  329. }
  330. wrmsr(nmi_perfctr_msr, -(cpu_khz/nmi_hz*1000), -1);
  331. }
  332. }