3.1.7 branch.
[minix.git] / kernel / arch / i386 / arch_watchdog.c
blob91729e8a0230302a9614de788b345facac5523cb
1 #include "kernel/kernel.h"
2 #include "kernel/watchdog.h"
3 #include "proto.h"
4 #include <minix/minlib.h>
5 #include <minix/u64.h>
7 #include "apic.h"
9 #define CPUID_UNHALTED_CORE_CYCLES_AVAILABLE 0
11 #define MSR_PERFMON_CRT0 0xc1
12 #define MSR_PERFMON_SEL0 0x186
14 #define MSR_PERFMON_SEL0_ENABLE (1 << 22)
17 * Intel architecture performance counters watchdog
20 PRIVATE void intel_arch_watchdog_init(int cpu)
22 u64_t cpuf;
23 u32_t val;
25 ia32_msr_write(MSR_PERFMON_CRT0, 0, 0);
27 /* Int, OS, USR, Core ccyles */
28 val = 1 << 20 | 1 << 17 | 1 << 16 | 0x3c;
29 ia32_msr_write(MSR_PERFMON_SEL0, 0, val);
32 * should give as a tick approx. every 0.5-1s, the perf counter has only
33 * lowest 31 bits writable :(
35 cpuf = cpu_get_freq(cpu);
36 while (cpuf.hi || cpuf.lo > 0x7fffffffU)
37 cpuf = div64u64(cpuf, 2);
38 watchdog->resetval = cpuf.lo;
40 ia32_msr_write(MSR_PERFMON_CRT0, 0, -cpuf.lo);
42 ia32_msr_write(MSR_PERFMON_SEL0, 0, val | MSR_PERFMON_SEL0_ENABLE);
44 /* unmask the performance counter interrupt */
45 lapic_write(LAPIC_LVTPCR, APIC_ICR_DM_NMI);
48 PRIVATE void intel_arch_watchdog_reinit(const int cpu)
50 lapic_write(LAPIC_LVTPCR, APIC_ICR_DM_NMI);
51 ia32_msr_write(MSR_PERFMON_CRT0, 0, -watchdog->resetval);
54 PRIVATE struct arch_watchdog intel_arch_watchdog = {
55 /*.init = */ intel_arch_watchdog_init,
56 /*.reinit = */ intel_arch_watchdog_reinit
59 int arch_watchdog_init(void)
61 u32_t eax, ebx, ecx, edx;
63 eax = 0xA;
65 _cpuid(&eax, &ebx, &ecx, &edx);
67 /* FIXME currently we support only watchdog base on the intel
68 * architectural performance counters. Some Intel CPUs don't have this
69 * feature
71 if (ebx & (1 << CPUID_UNHALTED_CORE_CYCLES_AVAILABLE))
72 return -1;
73 if (!((((eax >> 8)) & 0xff) > 0))
74 return -1;
76 watchdog = &intel_arch_watchdog;
78 /* Setup PC tas NMI for watchdog, is is masked for now */
79 lapic_write(LAPIC_LVTPCR, APIC_ICR_INT_MASK | APIC_ICR_DM_NMI);
80 lapic_read(LAPIC_LVTPCR);
82 /* double check if LAPIC is enabled */
83 if (lapic_addr && watchdog_enabled && watchdog->init) {
84 watchdog->init(cpuid);
87 return 0;
90 void arch_watchdog_lockup(const struct nmi_frame * frame)
92 printf("KERNEL LOCK UP\n"
93 "eax 0x%08x\n"
94 "ecx 0x%08x\n"
95 "edx 0x%08x\n"
96 "ebx 0x%08x\n"
97 "ebp 0x%08x\n"
98 "esi 0x%08x\n"
99 "edi 0x%08x\n"
100 "gs 0x%08x\n"
101 "fs 0x%08x\n"
102 "es 0x%08x\n"
103 "ds 0x%08x\n"
104 "pc 0x%08x\n"
105 "cs 0x%08x\n"
106 "eflags 0x%08x\n",
107 frame->eax,
108 frame->ecx,
109 frame->edx,
110 frame->ebx,
111 frame->ebp,
112 frame->esi,
113 frame->edi,
114 frame->gs,
115 frame->fs,
116 frame->es,
117 frame->ds,
118 frame->pc,
119 frame->cs,
120 frame->eflags
122 panic("Kernel lockup");
125 void i386_watchdog_start(void)
127 if (watchdog_enabled) {
128 if (arch_watchdog_init()) {
129 printf("WARNING watchdog initialization "
130 "failed! Disabled\n");
131 watchdog_enabled = 0;
133 else
134 BOOT_VERBOSE(printf("Watchdog enabled\n"););