akaros/kern/arch/x86/idle.c
<<
>>
Prefs
   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
   7static 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 */
  12void 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. */
  30void 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
  47void 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
  64void 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. */
  79unsigned 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
  88unsigned 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
  97void 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
 104unsigned 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}
 111