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