| #include <arch/arch.h> |
| #include <arch/x86.h> |
| #include <arch/mmu.h> |
| #include <cpu_feat.h> |
| #include <arch/uaccess.h> |
| |
| static unsigned int x86_cstate; |
| |
| /* This atomically enables interrupts and halts. It returns with IRQs off. |
| * |
| * Note that sti does not take effect until after the *next* instruction */ |
| void cpu_halt(void) |
| { |
| if (cpu_has_feat(CPU_FEAT_X86_MWAIT)) { |
| /* TODO: since we're monitoring anyway, x86 could use |
| * monitor/mwait for KMSGs, instead of relying on IPIs. (Maybe |
| * only for ROUTINE). */ |
| asm volatile("monitor" : : "a"(KERNBASE), "c"(0), "d"(0)); |
| asm volatile("sti; mwait" : : "c"(0x0), "a"(x86_cstate) |
| : "memory"); |
| } else { |
| asm volatile("sti; hlt" : : : "memory"); |
| } |
| disable_irq(); |
| } |
| |
| /* Atomically enables interrupts and halts. It will wake if notif_pending was |
| * set (racy), and if we have mwait, it will wake if notif_pending gets set. |
| * It returns with IRQs off. */ |
| void cpu_halt_notif_pending(struct preempt_data *vcpd) |
| { |
| if (cpu_has_feat(CPU_FEAT_X86_MWAIT)) |
| asm volatile("monitor" : |
| : "a"(&vcpd->notif_pending), "c"(0), "d"(0)); |
| if (vcpd->notif_pending) |
| return; |
| /* Note we don't use the ecx=1 setting - we actually want to sti so that |
| * we handle the IRQ and not just wake from it. */ |
| if (cpu_has_feat(CPU_FEAT_X86_MWAIT)) |
| asm volatile("sti; mwait" : |
| : "c"(0x0), "a"(x86_cstate) : "memory"); |
| else |
| asm volatile("sti; hlt" : : : "memory"); |
| disable_irq(); |
| } |
| |
| void set_pstate(unsigned int pstate) |
| { |
| uint64_t perf_ctl; |
| |
| /* This MSR was introduced in 0f_03 (family/model), so checking cpuid |
| * should suffice. Though my Qemu says it is a later generation and |
| * still fails to support it (patches pending, I hear). */ |
| if (read_msr_safe(MSR_IA32_PERF_CTL, &perf_ctl)) |
| return; |
| /* The p-state ratio is actually at 15:8, AFAIK, for both PERF_CTL and |
| * PERF_STATUS. Not sure what the lower byte represents. It's probably |
| * processor specific. */ |
| perf_ctl &= ~0xff00ULL; |
| perf_ctl |= pstate << 8; |
| write_msr_safe(MSR_IA32_PERF_CTL, perf_ctl); |
| } |
| |
| void set_fastest_pstate(void) |
| { |
| uint64_t turbo_ratio_limit; |
| |
| /* Support for TURBO_RATIO_LIMIT varies from processor to processor. In |
| * lieu of a full per-model driver, we can just take a peak. */ |
| if (read_msr_safe(MSR_TURBO_RATIO_LIMIT, &turbo_ratio_limit)) |
| return; |
| /* The lowest byte is the max turbo ratio achievable by one active core. |
| */ |
| set_pstate(turbo_ratio_limit & 0xff); |
| } |
| |
| /* This returns the desired pstate, which might be less than desired if other |
| * cores are active. */ |
| unsigned int get_pstate(void) |
| { |
| uint64_t perf_ctl; |
| |
| if (read_msr_safe(MSR_IA32_PERF_CTL, &perf_ctl)) |
| return 0; |
| return (perf_ctl & 0xff00) >> 8; |
| } |
| |
| unsigned int get_actual_pstate(void) |
| { |
| uint64_t perf_status; |
| |
| if (read_msr_safe(MSR_IA32_PERF_STATUS, &perf_status)) |
| return 0; |
| return (perf_status & 0xff00) >> 8; |
| } |
| |
| void set_cstate(unsigned int cstate) |
| { |
| /* No real need to lock for an assignment. Any core can set this, and |
| * other cores will notice the next time they halt. */ |
| x86_cstate = cstate; |
| } |
| |
| unsigned int get_cstate(void) |
| { |
| /* We won't be able to use anything deeper than C1 without MWAIT */ |
| if (!cpu_has_feat(CPU_FEAT_X86_MWAIT)) |
| return X86_MWAIT_C1; |
| return x86_cstate; |
| } |