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

Linux/Unix编程

开发平台:

Unix_Linux

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