Index: src/sys/amd64/amd64/local_apic.c =================================================================== RCS file: /home/ncvs/src/sys/amd64/amd64/local_apic.c,v retrieving revision 1.45 diff -u -r1.45 local_apic.c --- src/sys/amd64/amd64/local_apic.c 24 May 2008 06:32:26 -0000 1.45 +++ src/sys/amd64/amd64/local_apic.c 25 May 2008 11:51:50 -0000 @@ -327,29 +327,6 @@ /* XXX: Error and thermal LVTs */ - if (strcmp(cpu_vendor, "AuthenticAMD") == 0) { - /* - * Detect the presence of C1E capability mostly on latest - * dual-cores (or future) k8 family. This feature 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 - */ - if ((cpu_id & 0x00000f00) == 0x00000f00 && - (cpu_id & 0x0fff0000) >= 0x00040000) { - uint64_t msr; - - msr = rdmsr(0xc0010055); - if (msr & 0x18000000) - wrmsr(0xc0010055, msr & ~0x18000000ULL); - } - } - intr_restore(eflags); } Index: src/sys/amd64/amd64/machdep.c =================================================================== RCS file: /home/ncvs/src/sys/amd64/amd64/machdep.c,v retrieving revision 1.686 diff -u -r1.686 machdep.c --- src/sys/amd64/amd64/machdep.c 25 Apr 2008 05:18:47 -0000 1.686 +++ src/sys/amd64/amd64/machdep.c 25 May 2008 11:51:51 -0000 @@ -556,6 +556,60 @@ __asm __volatile("sti; hlt"); } +static int cpu_ident_k8c1e = 0; + +static int +cpu_probe_k8c1e(void) +{ + /* + * Detect the presence of C1E capability mostly on latest + * dual-cores (or future) k8 family. + */ + if (strcmp(cpu_vendor, "AuthenticAMD") == 0 && + (cpu_id & 0x00000f00) == 0x00000f00 && + (cpu_id & 0x0fff0000) >= 0x00040000) { + cpu_ident_k8c1e = 1; + return (1); + } + + return (0); +} + +/* + * 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) + +static void +cpu_idle_k8c1e(int busy) +{ + + disable_intr(); + if (sched_runnable()) + enable_intr(); + else { + uint64_t msr; + + msr = rdmsr(MSR_AMDK8_IPM); + if (msr & AMDK8_CMPHALT) + wrmsr(MSR_AMDK8_IPM, msr & ~AMDK8_CMPHALT); + + if (cpu_idle_hook) + cpu_idle_hook(); + else + __asm __volatile("sti; hlt"); + } +} + static void cpu_idle_spin(int busy) { @@ -653,6 +707,7 @@ { cpu_idle_spin, "spin" }, { cpu_idle_mwait, "mwait" }, { cpu_idle_mwait_hlt, "mwait_hlt" }, + { cpu_idle_k8c1e, "k8c1e" }, { cpu_idle_hlt, "hlt" }, { cpu_idle_acpi, "acpi" }, { NULL, NULL } @@ -671,6 +726,9 @@ if (strstr(idle_tbl[i].id_name, "mwait") && (cpu_feature2 & CPUID2_MON) == 0) continue; + if (strcmp(idle_tbl[i].id_name, "k8c1e") == 0 && + cpu_ident_k8c1e == 0) + continue; p += sprintf(p, "%s, ", idle_tbl[i].id_name); } error = sysctl_handle_string(oidp, avail, 0, req); @@ -701,6 +759,9 @@ if (strstr(idle_tbl[i].id_name, "mwait") && (cpu_feature2 & CPUID2_MON) == 0) continue; + if (strcmp(idle_tbl[i].id_name, "k8c1e") == 0 && + cpu_ident_k8c1e == 0) + continue; if (strcmp(idle_tbl[i].id_name, buf)) continue; cpu_idle_fn = idle_tbl[i].id_fn; @@ -1475,6 +1536,9 @@ if (env != NULL) strlcpy(kernelname, env, sizeof(kernelname)); + if (cpu_probe_k8c1e()) + cpu_idle_fn = cpu_idle_k8c1e; + /* Location of kernel stack for locore */ return ((u_int64_t)thread0.td_pcb); } Index: src/sys/i386/i386/local_apic.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/local_apic.c,v retrieving revision 1.46 diff -u -r1.46 local_apic.c --- src/sys/i386/i386/local_apic.c 24 May 2008 06:27:02 -0000 1.46 +++ src/sys/i386/i386/local_apic.c 25 May 2008 11:51:52 -0000 @@ -329,29 +329,6 @@ /* XXX: Error and thermal LVTs */ - if (strcmp(cpu_vendor, "AuthenticAMD") == 0) { - /* - * Detect the presence of C1E capability mostly on latest - * dual-cores (or future) k8 family. This feature 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 - */ - if ((cpu_id & 0x00000f00) == 0x00000f00 && - (cpu_id & 0x0fff0000) >= 0x00040000) { - uint64_t msr; - - msr = rdmsr(0xc0010055); - if (msr & 0x18000000) - wrmsr(0xc0010055, msr & ~0x18000000ULL); - } - } - intr_restore(eflags); } Index: src/sys/i386/i386/machdep.c =================================================================== RCS file: /home/ncvs/src/sys/i386/i386/machdep.c,v retrieving revision 1.670 diff -u -r1.670 machdep.c --- src/sys/i386/i386/machdep.c 25 Apr 2008 05:18:48 -0000 1.670 +++ src/sys/i386/i386/machdep.c 25 May 2008 11:51:52 -0000 @@ -1156,6 +1156,60 @@ __asm __volatile("sti; hlt"); } +static int cpu_ident_k8c1e = 0; + +static int +cpu_probe_k8c1e(void) +{ + /* + * Detect the presence of C1E capability mostly on latest + * dual-cores (or future) k8 family. + */ + if (strcmp(cpu_vendor, "AuthenticAMD") == 0 && + (cpu_id & 0x00000f00) == 0x00000f00 && + (cpu_id & 0x0fff0000) >= 0x00040000) { + cpu_ident_k8c1e = 1; + return (1); + } + + return (0); +} + +/* + * 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) + +static void +cpu_idle_k8c1e(int busy) +{ + + disable_intr(); + if (sched_runnable()) + enable_intr(); + else { + uint64_t msr; + + msr = rdmsr(MSR_AMDK8_IPM); + if (msr & AMDK8_CMPHALT) + wrmsr(MSR_AMDK8_IPM, msr & ~AMDK8_CMPHALT); + + if (cpu_idle_hook) + cpu_idle_hook(); + else + __asm __volatile("sti; hlt"); + } +} + static void cpu_idle_spin(int busy) { @@ -1253,6 +1307,7 @@ { cpu_idle_spin, "spin" }, { cpu_idle_mwait, "mwait" }, { cpu_idle_mwait_hlt, "mwait_hlt" }, + { cpu_idle_k8c1e, "k8c1e" }, { cpu_idle_hlt, "hlt" }, { cpu_idle_acpi, "acpi" }, { NULL, NULL } @@ -1271,6 +1326,9 @@ if (strstr(idle_tbl[i].id_name, "mwait") && (cpu_feature2 & CPUID2_MON) == 0) continue; + if (strcmp(idle_tbl[i].id_name, "k8c1e") == 0 && + cpu_ident_k8c1e == 0) + continue; p += sprintf(p, "%s, ", idle_tbl[i].id_name); } error = sysctl_handle_string(oidp, avail, 0, req); @@ -1301,6 +1359,9 @@ if (strstr(idle_tbl[i].id_name, "mwait") && (cpu_feature2 & CPUID2_MON) == 0) continue; + if (strcmp(idle_tbl[i].id_name, "k8c1e") == 0 && + cpu_ident_k8c1e == 0) + continue; if (strcmp(idle_tbl[i].id_name, buf)) continue; cpu_idle_fn = idle_tbl[i].id_fn; @@ -2526,6 +2587,9 @@ #endif thread0.td_pcb->pcb_ext = 0; thread0.td_frame = &proc0_tf; + + if (cpu_probe_k8c1e()) + cpu_idle_fn = cpu_idle_k8c1e; } void