Remove building with NOCRYPTO option
[minix3.git] / minix / kernel / arch / i386 / arch_watchdog.c
blob775d487c007f0175830faa721a38b7c28694f6d8
1 #include "kernel/watchdog.h"
2 #include "glo.h"
3 #include <minix/minlib.h>
4 #include <minix/u64.h>
6 #include "apic.h"
8 #define CPUID_UNHALTED_CORE_CYCLES_AVAILABLE 0
11 * Intel architecture performance counters watchdog
14 static struct arch_watchdog intel_arch_watchdog;
15 static struct arch_watchdog amd_watchdog;
17 static void intel_arch_watchdog_init(const unsigned cpu)
19 u64_t cpuf;
20 u32_t val;
22 ia32_msr_write(INTEL_MSR_PERFMON_CRT0, 0, 0);
24 /* Int, OS, USR, Core ccyles */
25 val = 1 << 20 | 1 << 17 | 1 << 16 | 0x3c;
26 ia32_msr_write(INTEL_MSR_PERFMON_SEL0, 0, val);
29 * should give as a tick approx. every 0.5-1s, the perf counter has only
30 * lowest 31 bits writable :(
32 cpuf = cpu_get_freq(cpu);
33 while (ex64hi(cpuf) || ex64lo(cpuf) > 0x7fffffffU)
34 cpuf /= 2;
35 cpuf = make64(-ex64lo(cpuf), ex64hi(cpuf));
36 watchdog->resetval = watchdog->watchdog_resetval = cpuf;
38 ia32_msr_write(INTEL_MSR_PERFMON_CRT0, 0, ex64lo(cpuf));
40 ia32_msr_write(INTEL_MSR_PERFMON_SEL0, 0,
41 val | INTEL_MSR_PERFMON_SEL0_ENABLE);
43 /* unmask the performance counter interrupt */
44 lapic_write(LAPIC_LVTPCR, APIC_ICR_DM_NMI);
47 static void intel_arch_watchdog_reinit(const unsigned cpu)
49 lapic_write(LAPIC_LVTPCR, APIC_ICR_DM_NMI);
50 ia32_msr_write(INTEL_MSR_PERFMON_CRT0, 0, ex64lo(watchdog->resetval));
53 int arch_watchdog_init(void)
55 u32_t eax, ebx, ecx, edx;
56 unsigned cpu = cpuid;
58 if (!lapic_addr) {
59 printf("ERROR : Cannot use NMI watchdog if APIC is not enabled\n");
60 return -1;
63 if (cpu_info[cpu].vendor == CPU_VENDOR_INTEL) {
64 eax = 0xA;
66 _cpuid(&eax, &ebx, &ecx, &edx);
68 /* FIXME currently we support only watchdog based on the intel
69 * architectural performance counters. Some Intel CPUs don't have this
70 * feature
72 if (ebx & (1 << CPUID_UNHALTED_CORE_CYCLES_AVAILABLE))
73 return -1;
74 if (!((((eax >> 8)) & 0xff) > 0))
75 return -1;
77 watchdog = &intel_arch_watchdog;
78 } else if (cpu_info[cpu].vendor == CPU_VENDOR_AMD) {
79 if (cpu_info[cpu].family != 6 &&
80 cpu_info[cpu].family != 15 &&
81 cpu_info[cpu].family != 16 &&
82 cpu_info[cpu].family != 17)
83 return -1;
84 else
85 watchdog = &amd_watchdog;
86 } else
87 return -1;
89 /* Setup PC overflow as NMI for watchdog, it is masked for now */
90 lapic_write(LAPIC_LVTPCR, APIC_ICR_INT_MASK | APIC_ICR_DM_NMI);
91 (void) lapic_read(LAPIC_LVTPCR);
93 /* double check if LAPIC is enabled */
94 if (lapic_addr && watchdog->init) {
95 watchdog->init(cpuid);
98 return 0;
101 void arch_watchdog_stop(void)
105 void arch_watchdog_lockup(const struct nmi_frame * frame)
107 printf("KERNEL LOCK UP\n"
108 "eax 0x%08x\n"
109 "ecx 0x%08x\n"
110 "edx 0x%08x\n"
111 "ebx 0x%08x\n"
112 "ebp 0x%08x\n"
113 "esi 0x%08x\n"
114 "edi 0x%08x\n"
115 "gs 0x%08x\n"
116 "fs 0x%08x\n"
117 "es 0x%08x\n"
118 "ds 0x%08x\n"
119 "pc 0x%08x\n"
120 "cs 0x%08x\n"
121 "eflags 0x%08x\n",
122 frame->eax,
123 frame->ecx,
124 frame->edx,
125 frame->ebx,
126 frame->ebp,
127 frame->esi,
128 frame->edi,
129 frame->gs,
130 frame->fs,
131 frame->es,
132 frame->ds,
133 frame->pc,
134 frame->cs,
135 frame->eflags
137 panic("Kernel lockup");
140 int i386_watchdog_start(void)
142 if (arch_watchdog_init()) {
143 printf("WARNING watchdog initialization "
144 "failed! Disabled\n");
145 watchdog_enabled = 0;
146 return -1;
148 else
149 BOOT_VERBOSE(printf("Watchdog enabled\n"););
151 return 0;
154 static int intel_arch_watchdog_profile_init(const unsigned freq)
156 u64_t cpuf;
158 /* FIXME works only if all CPUs have the same freq */
159 cpuf = cpu_get_freq(cpuid);
160 cpuf /= freq;
163 * if freq is too low and the cpu freq too high we may get in a range of
164 * insane value which cannot be handled by the 31bit CPU perf counter
166 if (ex64hi(cpuf) != 0 || ex64lo(cpuf) > 0x7fffffffU) {
167 printf("ERROR : nmi watchdog ticks exceed 31bits, use higher frequency\n");
168 return EINVAL;
171 cpuf = make64(-ex64lo(cpuf), ex64hi(cpuf));
172 watchdog->profile_resetval = cpuf;
174 return OK;
177 static struct arch_watchdog intel_arch_watchdog = {
178 /*.init = */ intel_arch_watchdog_init,
179 /*.reinit = */ intel_arch_watchdog_reinit,
180 /*.profile_init = */ intel_arch_watchdog_profile_init
183 #define AMD_MSR_EVENT_SEL0 0xc0010000
184 #define AMD_MSR_EVENT_CTR0 0xc0010004
185 #define AMD_MSR_EVENT_SEL0_ENABLE (1 << 22)
187 static void amd_watchdog_init(const unsigned cpu)
189 u64_t cpuf;
190 u32_t val;
192 ia32_msr_write(AMD_MSR_EVENT_CTR0, 0, 0);
194 /* Int, OS, USR, Cycles cpu is running */
195 val = 1 << 20 | 1 << 17 | 1 << 16 | 0x76;
196 ia32_msr_write(AMD_MSR_EVENT_SEL0, 0, val);
198 cpuf = -cpu_get_freq(cpu);
199 watchdog->resetval = watchdog->watchdog_resetval = cpuf;
201 ia32_msr_write(AMD_MSR_EVENT_CTR0,
202 ex64hi(watchdog->resetval), ex64lo(watchdog->resetval));
204 ia32_msr_write(AMD_MSR_EVENT_SEL0, 0,
205 val | AMD_MSR_EVENT_SEL0_ENABLE);
207 /* unmask the performance counter interrupt */
208 lapic_write(LAPIC_LVTPCR, APIC_ICR_DM_NMI);
211 static void amd_watchdog_reinit(const unsigned cpu)
213 lapic_write(LAPIC_LVTPCR, APIC_ICR_DM_NMI);
214 ia32_msr_write(AMD_MSR_EVENT_CTR0,
215 ex64hi(watchdog->resetval), ex64lo(watchdog->resetval));
218 static int amd_watchdog_profile_init(const unsigned freq)
220 u64_t cpuf;
222 /* FIXME works only if all CPUs have the same freq */
223 cpuf = cpu_get_freq(cpuid);
224 cpuf = -cpuf / freq;
226 watchdog->profile_resetval = cpuf;
228 return OK;
231 static struct arch_watchdog amd_watchdog = {
232 /*.init = */ amd_watchdog_init,
233 /*.reinit = */ amd_watchdog_reinit,
234 /*.profile_init = */ amd_watchdog_profile_init