Changeset View
Changeset View
Standalone View
Standalone View
head/sys/x86/x86/cpu_machdep.c
Show First 20 Lines • Show All 480 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
return ((cpu_feature2 & CPUID2_MON) != 0 && ((cpu_mon_mwait_flags & | return ((cpu_feature2 & CPUID2_MON) != 0 && ((cpu_mon_mwait_flags & | ||||
(CPUID5_MON_MWAIT_EXT | CPUID5_MWAIT_INTRBREAK)) == | (CPUID5_MON_MWAIT_EXT | CPUID5_MWAIT_INTRBREAK)) == | ||||
(CPUID5_MON_MWAIT_EXT | CPUID5_MWAIT_INTRBREAK))); | (CPUID5_MON_MWAIT_EXT | CPUID5_MWAIT_INTRBREAK))); | ||||
} | } | ||||
void (*cpu_idle_hook)(sbintime_t) = NULL; /* ACPI idle hook. */ | void (*cpu_idle_hook)(sbintime_t) = NULL; /* ACPI idle hook. */ | ||||
static int cpu_ident_amdc1e = 0; /* AMD C1E supported. */ | |||||
int cpu_amdc1e_bug = 0; /* AMD C1E APIC workaround required. */ | |||||
static int idle_mwait = 1; /* Use MONITOR/MWAIT for short idle. */ | static int idle_mwait = 1; /* Use MONITOR/MWAIT for short idle. */ | ||||
SYSCTL_INT(_machdep, OID_AUTO, idle_mwait, CTLFLAG_RWTUN, &idle_mwait, | SYSCTL_INT(_machdep, OID_AUTO, idle_mwait, CTLFLAG_RWTUN, &idle_mwait, | ||||
0, "Use MONITOR/MWAIT for short idle"); | 0, "Use MONITOR/MWAIT for short idle"); | ||||
static void | static void | ||||
cpu_idle_acpi(sbintime_t sbt) | cpu_idle_acpi(sbintime_t sbt) | ||||
{ | { | ||||
int *state; | int *state; | ||||
▲ Show 20 Lines • Show All 84 Lines • ▼ Show 20 Lines | cpu_idle_spin(sbintime_t sbt) | ||||
*/ | */ | ||||
for (i = 0; i < 1000; i++) { | for (i = 0; i < 1000; i++) { | ||||
if (sched_runnable()) | if (sched_runnable()) | ||||
return; | return; | ||||
cpu_spinwait(); | cpu_spinwait(); | ||||
} | } | ||||
} | } | ||||
/* | |||||
* C1E renders the local APIC timer dead, so we disable it by | |||||
* reading the Interrupt Pending Message register and clearing | |||||
* both C1eOnCmpHalt (bit 28) and SmiOnCmpHalt (bit 27). | |||||
* | |||||
* Reference: | |||||
* "BIOS and Kernel Developer's Guide for AMD NPT Family 0Fh Processors" | |||||
* #32559 revision 3.00+ | |||||
*/ | |||||
#define MSR_AMDK8_IPM 0xc0010055 | |||||
#define AMDK8_SMIONCMPHALT (1ULL << 27) | |||||
#define AMDK8_C1EONCMPHALT (1ULL << 28) | |||||
#define AMDK8_CMPHALT (AMDK8_SMIONCMPHALT | AMDK8_C1EONCMPHALT) | |||||
void | |||||
cpu_probe_amdc1e(void) | |||||
{ | |||||
/* | |||||
* Detect the presence of C1E capability mostly on latest | |||||
* dual-cores (or future) k8 family. | |||||
*/ | |||||
if (cpu_vendor_id == CPU_VENDOR_AMD && | |||||
(cpu_id & 0x00000f00) == 0x00000f00 && | |||||
(cpu_id & 0x0fff0000) >= 0x00040000) { | |||||
cpu_ident_amdc1e = 1; | |||||
} | |||||
} | |||||
void (*cpu_idle_fn)(sbintime_t) = cpu_idle_acpi; | void (*cpu_idle_fn)(sbintime_t) = cpu_idle_acpi; | ||||
void | void | ||||
cpu_idle(int busy) | cpu_idle(int busy) | ||||
{ | { | ||||
uint64_t msr; | uint64_t msr; | ||||
sbintime_t sbt = -1; | sbintime_t sbt = -1; | ||||
Show All 13 Lines | #endif | ||||
/* If we have time - switch timers into idle mode. */ | /* If we have time - switch timers into idle mode. */ | ||||
if (!busy) { | if (!busy) { | ||||
critical_enter(); | critical_enter(); | ||||
sbt = cpu_idleclock(); | sbt = cpu_idleclock(); | ||||
} | } | ||||
/* Apply AMD APIC timer C1E workaround. */ | /* Apply AMD APIC timer C1E workaround. */ | ||||
if (cpu_ident_amdc1e && cpu_disable_c3_sleep) { | if (cpu_amdc1e_bug && cpu_disable_c3_sleep) { | ||||
msr = rdmsr(MSR_AMDK8_IPM); | msr = rdmsr(MSR_AMDK8_IPM); | ||||
if (msr & AMDK8_CMPHALT) | if ((msr & (AMDK8_SMIONCMPHALT | AMDK8_C1EONCMPHALT)) != 0) | ||||
wrmsr(MSR_AMDK8_IPM, msr & ~AMDK8_CMPHALT); | wrmsr(MSR_AMDK8_IPM, msr & ~(AMDK8_SMIONCMPHALT | | ||||
AMDK8_C1EONCMPHALT)); | |||||
} | } | ||||
/* Call main idle method. */ | /* Call main idle method. */ | ||||
cpu_idle_fn(sbt); | cpu_idle_fn(sbt); | ||||
/* Switch timers back into active mode. */ | /* Switch timers back into active mode. */ | ||||
if (!busy) { | if (!busy) { | ||||
cpu_activeclock(); | cpu_activeclock(); | ||||
▲ Show 20 Lines • Show All 838 Lines • Show Last 20 Lines |