Index: src/sys/amd64/amd64/local_apic.c =================================================================== RCS file: /home/ncvs/src/sys/amd64/amd64/local_apic.c,v retrieving revision 1.17.2.15 diff -u -r1.17.2.15 local_apic.c --- src/sys/amd64/amd64/local_apic.c 8 Nov 2007 20:09:45 -0000 1.17.2.15 +++ src/sys/amd64/amd64/local_apic.c 25 May 2008 12:00:46 -0000 @@ -318,29 +318,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.638.2.16 diff -u -r1.638.2.16 machdep.c --- src/sys/amd64/amd64/machdep.c 27 Mar 2008 13:53:50 -0000 1.638.2.16 +++ src/sys/amd64/amd64/machdep.c 25 May 2008 12:00:47 -0000 @@ -559,6 +559,56 @@ SYSCTL_INT(_machdep, OID_AUTO, cpu_idle_hlt, CTLFLAG_RW, &cpu_idle_hlt, 0, "Idle loop HLT enable"); +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) + 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_fn_k8c1e(void) +{ + uint64_t msr; + + msr = rdmsr(MSR_AMDK8_IPM); + if (msr & AMDK8_CMPHALT) + wrmsr(MSR_AMDK8_IPM, msr & ~AMDK8_CMPHALT); + + (*cpu_idle_hook)(); +} + +static void +cpu_idle_fn_default(void) +{ + + (*cpu_idle_hook)(); +} + +static void (*cpu_idle_fn)(void) = cpu_idle_fn_default; + static void cpu_idle_default(void) { @@ -589,7 +639,7 @@ if (sched_runnable()) enable_intr(); else - (*cpu_idle_hook)(); + (*cpu_idle_fn)(); } } @@ -1352,6 +1402,9 @@ if (env != NULL) strlcpy(kernelname, env, sizeof(kernelname)); + if (cpu_probe_k8c1e()) + cpu_idle_fn = cpu_idle_fn_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.17.2.14 diff -u -r1.17.2.14 local_apic.c --- src/sys/i386/i386/local_apic.c 5 Oct 2007 15:22:36 -0000 1.17.2.14 +++ src/sys/i386/i386/local_apic.c 25 May 2008 12:00:47 -0000 @@ -319,29 +319,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.616.2.13 diff -u -r1.616.2.13 machdep.c --- src/sys/i386/i386/machdep.c 27 Mar 2008 13:53:51 -0000 1.616.2.13 +++ src/sys/i386/i386/machdep.c 25 May 2008 12:00:48 -0000 @@ -1136,6 +1136,56 @@ SYSCTL_INT(_machdep, OID_AUTO, cpu_idle_hlt, CTLFLAG_RW, &cpu_idle_hlt, 0, "Idle loop HLT enable"); +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) + 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_fn_k8c1e(void) +{ + uint64_t msr; + + msr = rdmsr(MSR_AMDK8_IPM); + if (msr & AMDK8_CMPHALT) + wrmsr(MSR_AMDK8_IPM, msr & ~AMDK8_CMPHALT); + + (*cpu_idle_hook)(); +} + +static void +cpu_idle_fn_default(void) +{ + + (*cpu_idle_hook)(); +} + +static void (*cpu_idle_fn)(void) = cpu_idle_fn_default; + static void cpu_idle_default(void) { @@ -1167,7 +1217,7 @@ if (sched_runnable()) enable_intr(); else - (*cpu_idle_hook)(); + (*cpu_idle_fn)(); } } @@ -2391,6 +2441,9 @@ #endif thread0.td_pcb->pcb_ext = 0; thread0.td_frame = &proc0_tf; + + if (cpu_probe_k8c1e()) + cpu_idle_fn = cpu_idle_fn_k8c1e; } void