1 #include "kernel/watchdog.h"
3 #include <minix/minlib.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
)
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
)
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
;
59 printf("ERROR : Cannot use NMI watchdog if APIC is not enabled\n");
63 if (cpu_info
[cpu
].vendor
== CPU_VENDOR_INTEL
) {
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
72 if (ebx
& (1 << CPUID_UNHALTED_CORE_CYCLES_AVAILABLE
))
74 if (!((((eax
>> 8)) & 0xff) > 0))
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)
85 watchdog
= &amd_watchdog
;
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
);
101 void arch_watchdog_stop(void)
105 void arch_watchdog_lockup(const struct nmi_frame
* frame
)
107 printf("KERNEL LOCK UP\n"
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;
149 BOOT_VERBOSE(printf("Watchdog enabled\n"););
154 static int intel_arch_watchdog_profile_init(const unsigned freq
)
158 /* FIXME works only if all CPUs have the same freq */
159 cpuf
= cpu_get_freq(cpuid
);
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");
171 cpuf
= make64(-ex64lo(cpuf
), ex64hi(cpuf
));
172 watchdog
->profile_resetval
= cpuf
;
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
)
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
)
222 /* FIXME works only if all CPUs have the same freq */
223 cpuf
= cpu_get_freq(cpuid
);
226 watchdog
->profile_resetval
= cpuf
;
231 static struct arch_watchdog amd_watchdog
= {
232 /*.init = */ amd_watchdog_init
,
233 /*.reinit = */ amd_watchdog_reinit
,
234 /*.profile_init = */ amd_watchdog_profile_init