1 #include "kernel/kernel.h"
2 #include "kernel/watchdog.h"
3 #include "arch_proto.h"
5 #include <minix/minlib.h>
10 #define CPUID_UNHALTED_CORE_CYCLES_AVAILABLE 0
13 * Intel architecture performance counters watchdog
16 static struct arch_watchdog intel_arch_watchdog
;
17 static struct arch_watchdog amd_watchdog
;
19 static void intel_arch_watchdog_init(const unsigned cpu
)
24 ia32_msr_write(INTEL_MSR_PERFMON_CRT0
, 0, 0);
26 /* Int, OS, USR, Core ccyles */
27 val
= 1 << 20 | 1 << 17 | 1 << 16 | 0x3c;
28 ia32_msr_write(INTEL_MSR_PERFMON_SEL0
, 0, val
);
31 * should give as a tick approx. every 0.5-1s, the perf counter has only
32 * lowest 31 bits writable :(
34 cpuf
= cpu_get_freq(cpu
);
35 while (ex64hi(cpuf
) || ex64lo(cpuf
) > 0x7fffffffU
)
36 cpuf
= div64u64(cpuf
, 2);
37 cpuf
= make64(-ex64lo(cpuf
), ex64hi(cpuf
));
38 watchdog
->resetval
= watchdog
->watchdog_resetval
= cpuf
;
40 ia32_msr_write(INTEL_MSR_PERFMON_CRT0
, 0, ex64lo(cpuf
));
42 ia32_msr_write(INTEL_MSR_PERFMON_SEL0
, 0,
43 val
| INTEL_MSR_PERFMON_SEL0_ENABLE
);
45 /* unmask the performance counter interrupt */
46 lapic_write(LAPIC_LVTPCR
, APIC_ICR_DM_NMI
);
49 static void intel_arch_watchdog_reinit(const unsigned cpu
)
51 lapic_write(LAPIC_LVTPCR
, APIC_ICR_DM_NMI
);
52 ia32_msr_write(INTEL_MSR_PERFMON_CRT0
, 0, ex64lo(watchdog
->resetval
));
55 int arch_watchdog_init(void)
57 u32_t eax
, ebx
, ecx
, edx
;
61 printf("ERROR : Cannot use NMI watchdog if APIC is not enabled\n");
65 if (cpu_info
[cpu
].vendor
== CPU_VENDOR_INTEL
) {
68 _cpuid(&eax
, &ebx
, &ecx
, &edx
);
70 /* FIXME currently we support only watchdog based on the intel
71 * architectural performance counters. Some Intel CPUs don't have this
74 if (ebx
& (1 << CPUID_UNHALTED_CORE_CYCLES_AVAILABLE
))
76 if (!((((eax
>> 8)) & 0xff) > 0))
79 watchdog
= &intel_arch_watchdog
;
80 } else if (cpu_info
[cpu
].vendor
== CPU_VENDOR_AMD
) {
81 if (cpu_info
[cpu
].family
!= 6 &&
82 cpu_info
[cpu
].family
!= 15 &&
83 cpu_info
[cpu
].family
!= 16 &&
84 cpu_info
[cpu
].family
!= 17)
87 watchdog
= &amd_watchdog
;
91 /* Setup PC overflow as NMI for watchdog, it is masked for now */
92 lapic_write(LAPIC_LVTPCR
, APIC_ICR_INT_MASK
| APIC_ICR_DM_NMI
);
93 (void) lapic_read(LAPIC_LVTPCR
);
95 /* double check if LAPIC is enabled */
96 if (lapic_addr
&& watchdog
->init
) {
97 watchdog
->init(cpuid
);
103 void arch_watchdog_stop(void)
107 void arch_watchdog_lockup(const struct nmi_frame
* frame
)
109 printf("KERNEL LOCK UP\n"
139 panic("Kernel lockup");
142 int i386_watchdog_start(void)
144 if (arch_watchdog_init()) {
145 printf("WARNING watchdog initialization "
146 "failed! Disabled\n");
147 watchdog_enabled
= 0;
151 BOOT_VERBOSE(printf("Watchdog enabled\n"););
156 static int intel_arch_watchdog_profile_init(const unsigned freq
)
160 /* FIXME works only if all CPUs have the same freq */
161 cpuf
= cpu_get_freq(cpuid
);
162 cpuf
= div64u64(cpuf
, freq
);
165 * if freq is too low and the cpu freq too high we may get in a range of
166 * insane value which cannot be handled by the 31bit CPU perf counter
168 if (ex64hi(cpuf
) != 0 || ex64lo(cpuf
) > 0x7fffffffU
) {
169 printf("ERROR : nmi watchdog ticks exceed 31bits, use higher frequency\n");
173 cpuf
= make64(-ex64lo(cpuf
), ex64hi(cpuf
));
174 watchdog
->profile_resetval
= cpuf
;
179 static struct arch_watchdog intel_arch_watchdog
= {
180 /*.init = */ intel_arch_watchdog_init
,
181 /*.reinit = */ intel_arch_watchdog_reinit
,
182 /*.profile_init = */ intel_arch_watchdog_profile_init
185 #define AMD_MSR_EVENT_SEL0 0xc0010000
186 #define AMD_MSR_EVENT_CTR0 0xc0010004
187 #define AMD_MSR_EVENT_SEL0_ENABLE (1 << 22)
189 static void amd_watchdog_init(const unsigned cpu
)
194 ia32_msr_write(AMD_MSR_EVENT_CTR0
, 0, 0);
196 /* Int, OS, USR, Cycles cpu is running */
197 val
= 1 << 20 | 1 << 17 | 1 << 16 | 0x76;
198 ia32_msr_write(AMD_MSR_EVENT_SEL0
, 0, val
);
200 cpuf
= cpu_get_freq(cpu
);
202 watchdog
->resetval
= watchdog
->watchdog_resetval
= cpuf
;
204 ia32_msr_write(AMD_MSR_EVENT_CTR0
,
205 ex64hi(watchdog
->resetval
), ex64lo(watchdog
->resetval
));
207 ia32_msr_write(AMD_MSR_EVENT_SEL0
, 0,
208 val
| AMD_MSR_EVENT_SEL0_ENABLE
);
210 /* unmask the performance counter interrupt */
211 lapic_write(LAPIC_LVTPCR
, APIC_ICR_DM_NMI
);
214 static void amd_watchdog_reinit(const unsigned cpu
)
216 lapic_write(LAPIC_LVTPCR
, APIC_ICR_DM_NMI
);
217 ia32_msr_write(AMD_MSR_EVENT_CTR0
,
218 ex64hi(watchdog
->resetval
), ex64lo(watchdog
->resetval
));
221 static int amd_watchdog_profile_init(const unsigned freq
)
225 /* FIXME works only if all CPUs have the same freq */
226 cpuf
= cpu_get_freq(cpuid
);
227 cpuf
= div64u64(cpuf
, freq
);
230 watchdog
->profile_resetval
= cpuf
;
235 static struct arch_watchdog amd_watchdog
= {
236 /*.init = */ amd_watchdog_init
,
237 /*.reinit = */ amd_watchdog_reinit
,
238 /*.profile_init = */ amd_watchdog_profile_init