tests/linux: use Akaros's CFLAGS
[akaros.git] / kern / arch / x86 / idle.c
1 #include <arch/arch.h>
2 #include <arch/x86.h>
3 #include <arch/mmu.h>
4 #include <cpu_feat.h>
5 #include <arch/uaccess.h>
6
7 static unsigned int x86_cstate;
8
9 /* This atomically enables interrupts and halts.  It returns with IRQs off.
10  *
11  * Note that sti does not take effect until after the *next* instruction */
12 void cpu_halt(void)
13 {
14         if (cpu_has_feat(CPU_FEAT_X86_MWAIT)) {
15                 /* TODO: since we're monitoring anyway, x86 could use
16                  * monitor/mwait for KMSGs, instead of relying on IPIs.  (Maybe
17                  * only for ROUTINE). */
18                 asm volatile("monitor" : : "a"(KERNBASE), "c"(0), "d"(0));
19                 asm volatile("sti; mwait" : : "c"(0x0), "a"(x86_cstate)
20                              : "memory");
21         } else {
22                 asm volatile("sti; hlt" : : : "memory");
23         }
24         disable_irq();
25 }
26
27 /* Atomically enables interrupts and halts.  It will wake if notif_pending was
28  * set (racy), and if we have mwait, it will wake if notif_pending gets set.
29  * It returns with IRQs off. */
30 void cpu_halt_notif_pending(struct preempt_data *vcpd)
31 {
32         if (cpu_has_feat(CPU_FEAT_X86_MWAIT))
33                 asm volatile("monitor" :
34                              : "a"(&vcpd->notif_pending), "c"(0), "d"(0));
35         if (vcpd->notif_pending)
36                 return;
37         /* Note we don't use the ecx=1 setting - we actually want to sti so that
38          * we handle the IRQ and not just wake from it. */
39         if (cpu_has_feat(CPU_FEAT_X86_MWAIT))
40                 asm volatile("sti; mwait" :
41                              : "c"(0x0), "a"(x86_cstate) : "memory");
42         else
43                 asm volatile("sti; hlt" : : : "memory");
44         disable_irq();
45 }
46
47 void set_pstate(unsigned int pstate)
48 {
49         uint64_t perf_ctl;
50
51         /* This MSR was introduced in 0f_03 (family/model), so checking cpuid
52          * should suffice.  Though my Qemu says it is a later generation and
53          * still fails to support it (patches pending, I hear). */
54         if (read_msr_safe(MSR_IA32_PERF_CTL, &perf_ctl))
55                 return;
56         /* The p-state ratio is actually at 15:8, AFAIK, for both PERF_CTL and
57          * PERF_STATUS.  Not sure what the lower byte represents.  It's probably
58          * processor specific. */
59         perf_ctl &= ~0xff00ULL;
60         perf_ctl |= pstate << 8;
61         write_msr_safe(MSR_IA32_PERF_CTL, perf_ctl);
62 }
63
64 void set_fastest_pstate(void)
65 {
66         uint64_t turbo_ratio_limit;
67
68         /* Support for TURBO_RATIO_LIMIT varies from processor to processor.  In
69          * lieu of a full per-model driver, we can just take a peak. */
70         if (read_msr_safe(MSR_TURBO_RATIO_LIMIT, &turbo_ratio_limit))
71                 return;
72         /* The lowest byte is the max turbo ratio achievable by one active core.
73          */
74         set_pstate(turbo_ratio_limit & 0xff);
75 }
76
77 /* This returns the desired pstate, which might be less than desired if other
78  * cores are active. */
79 unsigned int get_pstate(void)
80 {
81         uint64_t perf_ctl;
82
83         if (read_msr_safe(MSR_IA32_PERF_CTL, &perf_ctl))
84                 return 0;
85         return (perf_ctl & 0xff00) >> 8;
86 }
87
88 unsigned int get_actual_pstate(void)
89 {
90         uint64_t perf_status;
91
92         if (read_msr_safe(MSR_IA32_PERF_STATUS, &perf_status))
93                 return 0;
94         return (perf_status & 0xff00) >> 8;
95 }
96
97 void set_cstate(unsigned int cstate)
98 {
99         /* No real need to lock for an assignment.  Any core can set this, and
100          * other cores will notice the next time they halt. */
101         x86_cstate = cstate;
102 }
103
104 unsigned int get_cstate(void)
105 {
106         /* We won't be able to use anything deeper than C1 without MWAIT */
107         if (!cpu_has_feat(CPU_FEAT_X86_MWAIT))
108                 return X86_MWAIT_C1;
109         return x86_cstate;
110 }