mkfs: move directory entry manipulation
[minix.git] / kernel / arch / i386 / arch_watchdog.c
blob80647af0dee542157e3bfb4f8c5ee50e76240c6d
1 #include "kernel/kernel.h"
2 #include "kernel/watchdog.h"
3 #include "arch_proto.h"
4 #include "glo.h"
5 #include <minix/minlib.h>
6 #include <minix/u64.h>
8 #include "apic.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)
21 u64_t cpuf;
22 u32_t val;
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;
58 unsigned cpu = cpuid;
60 if (!lapic_addr) {
61 printf("ERROR : Cannot use NMI watchdog if APIC is not enabled\n");
62 return -1;
65 if (cpu_info[cpu].vendor == CPU_VENDOR_INTEL) {
66 eax = 0xA;
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
72 * feature
74 if (ebx & (1 << CPUID_UNHALTED_CORE_CYCLES_AVAILABLE))
75 return -1;
76 if (!((((eax >> 8)) & 0xff) > 0))
77 return -1;
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)
85 return -1;
86 else
87 watchdog = &amd_watchdog;
88 } else
89 return -1;
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);
100 return 0;
103 void arch_watchdog_stop(void)
107 void arch_watchdog_lockup(const struct nmi_frame * frame)
109 printf("KERNEL LOCK UP\n"
110 "eax 0x%08x\n"
111 "ecx 0x%08x\n"
112 "edx 0x%08x\n"
113 "ebx 0x%08x\n"
114 "ebp 0x%08x\n"
115 "esi 0x%08x\n"
116 "edi 0x%08x\n"
117 "gs 0x%08x\n"
118 "fs 0x%08x\n"
119 "es 0x%08x\n"
120 "ds 0x%08x\n"
121 "pc 0x%08x\n"
122 "cs 0x%08x\n"
123 "eflags 0x%08x\n",
124 frame->eax,
125 frame->ecx,
126 frame->edx,
127 frame->ebx,
128 frame->ebp,
129 frame->esi,
130 frame->edi,
131 frame->gs,
132 frame->fs,
133 frame->es,
134 frame->ds,
135 frame->pc,
136 frame->cs,
137 frame->eflags
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;
148 return -1;
150 else
151 BOOT_VERBOSE(printf("Watchdog enabled\n"););
153 return 0;
156 static int intel_arch_watchdog_profile_init(const unsigned freq)
158 u64_t cpuf;
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");
170 return EINVAL;
173 cpuf = make64(-ex64lo(cpuf), ex64hi(cpuf));
174 watchdog->profile_resetval = cpuf;
176 return OK;
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)
191 u64_t cpuf;
192 u32_t val;
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);
201 neg64(cpuf);
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)
223 u64_t cpuf;
225 /* FIXME works only if all CPUs have the same freq */
226 cpuf = cpu_get_freq(cpuid);
227 cpuf = div64u64(cpuf, freq);
229 neg64(cpuf);
230 watchdog->profile_resetval = cpuf;
232 return OK;
235 static struct arch_watchdog amd_watchdog = {
236 /*.init = */ amd_watchdog_init,
237 /*.reinit = */ amd_watchdog_reinit,
238 /*.profile_init = */ amd_watchdog_profile_init