diff options
Diffstat (limited to 'usr/src/uts/i86pc/os')
-rw-r--r-- | usr/src/uts/i86pc/os/cpuid.c | 189 | ||||
-rw-r--r-- | usr/src/uts/i86pc/os/cpupm/pwrnow.c | 45 | ||||
-rw-r--r-- | usr/src/uts/i86pc/os/cpupm/speedstep.c | 204 | ||||
-rw-r--r-- | usr/src/uts/i86pc/os/cpupm/turbo.c | 208 | ||||
-rw-r--r-- | usr/src/uts/i86pc/os/microcode.c | 31 | ||||
-rw-r--r-- | usr/src/uts/i86pc/os/mlsetup.c | 5 | ||||
-rw-r--r-- | usr/src/uts/i86pc/os/mp_machdep.c | 13 | ||||
-rw-r--r-- | usr/src/uts/i86pc/os/mp_startup.c | 18 |
8 files changed, 441 insertions, 272 deletions
diff --git a/usr/src/uts/i86pc/os/cpuid.c b/usr/src/uts/i86pc/os/cpuid.c index 0a389e0063..10946474dd 100644 --- a/usr/src/uts/i86pc/os/cpuid.c +++ b/usr/src/uts/i86pc/os/cpuid.c @@ -30,7 +30,7 @@ * Portions Copyright 2009 Advanced Micro Devices, Inc. */ /* - * Copyright (c) 2011, Joyent, Inc. All rights reserved. + * Copyright (c) 2012, Joyent, Inc. All rights reserved. */ /* * Various routines to handle identification @@ -160,7 +160,8 @@ static char *x86_feature_names[NUM_X86_FEATURES] = { "xsave", "avx", "vmx", - "svm" + "svm", + "topoext" }; boolean_t @@ -269,7 +270,7 @@ struct xsave_info { */ #define NMAX_CPI_STD 6 /* eax = 0 .. 5 */ -#define NMAX_CPI_EXTD 0x1c /* eax = 0x80000000 .. 0x8000001b */ +#define NMAX_CPI_EXTD 0x1f /* eax = 0x80000000 .. 0x8000001e */ /* * Some terminology needs to be explained: @@ -283,6 +284,8 @@ struct xsave_info { * memory controllers, PCI configuration spaces. They are connected * inside the package with Hypertransport links. On single-node * processors, processor node is equivalent to chip/socket/package. + * - Compute Unit: Some AMD processors pair cores in "compute units" that + * share the FPU and the I$ and L2 caches. */ struct cpuid_info { @@ -343,6 +346,8 @@ struct cpuid_info { uint_t cpi_procnodeid; /* AMD: nodeID on HT, Intel: chipid */ uint_t cpi_procnodes_per_pkg; /* AMD: # of nodes in the package */ /* Intel: 1 */ + uint_t cpi_compunitid; /* AMD: ComputeUnit ID, Intel: coreid */ + uint_t cpi_cores_per_compunit; /* AMD: # of cores in the ComputeUnit */ struct xsave_info cpi_xsave; /* fn D: xsave/xrestor info */ }; @@ -727,6 +732,7 @@ cpuid_intel_getids(cpu_t *cpu, void *feature) cpi->cpi_pkgcoreid = 0; } cpi->cpi_procnodeid = cpi->cpi_chipid; + cpi->cpi_compunitid = cpi->cpi_coreid; } static void @@ -736,6 +742,7 @@ cpuid_amd_getids(cpu_t *cpu) uint32_t nb_caps_reg; uint_t node2_1; struct cpuid_info *cpi = cpu->cpu_m.mcpu_cpi; + struct cpuid_regs *cp; /* * AMD CMP chips currently have a single thread per core. @@ -753,9 +760,15 @@ cpuid_amd_getids(cpu_t *cpu) * from 0 regardless of how many or which are disabled, and there * is no way for operating system to discover the real core id when some * are disabled. + * + * In family 0x15, the cores come in pairs called compute units. They + * share I$ and L2 caches and the FPU. Enumeration of this feature is + * simplified by the new topology extensions CPUID leaf, indicated by + * the X86 feature X86FSET_TOPOEXT. */ cpi->cpi_coreid = cpu->cpu_id; + cpi->cpi_compunitid = cpu->cpu_id; if (cpi->cpi_xmaxeax >= 0x80000008) { @@ -784,10 +797,21 @@ cpuid_amd_getids(cpu_t *cpu) cpi->cpi_apicid & ((1<<coreidsz) - 1); cpi->cpi_ncpu_per_chip = cpi->cpi_ncore_per_chip; - /* Get nodeID */ - if (cpi->cpi_family == 0xf) { + /* Get node ID, compute unit ID */ + if (is_x86_feature(x86_featureset, X86FSET_TOPOEXT) && + cpi->cpi_xmaxeax >= 0x8000001e) { + cp = &cpi->cpi_extd[0x1e]; + cp->cp_eax = 0x8000001e; + (void) __cpuid_insn(cp); + + cpi->cpi_procnodes_per_pkg = BITX(cp->cp_ecx, 10, 8) + 1; + cpi->cpi_procnodeid = BITX(cp->cp_ecx, 7, 0); + cpi->cpi_cores_per_compunit = BITX(cp->cp_ebx, 15, 8) + 1; + cpi->cpi_compunitid = BITX(cp->cp_ebx, 7, 0) + + (cpi->cpi_ncore_per_chip / cpi->cpi_cores_per_compunit) + * (cpi->cpi_procnodeid / cpi->cpi_procnodes_per_pkg); + } else if (cpi->cpi_family == 0xf || cpi->cpi_family >= 0x11) { cpi->cpi_procnodeid = (cpi->cpi_apicid >> coreidsz) & 7; - cpi->cpi_chipid = cpi->cpi_procnodeid; } else if (cpi->cpi_family == 0x10) { /* * See if we are a multi-node processor. @@ -798,7 +822,6 @@ cpuid_amd_getids(cpu_t *cpu) /* Single-node */ cpi->cpi_procnodeid = BITX(cpi->cpi_apicid, 5, coreidsz); - cpi->cpi_chipid = cpi->cpi_procnodeid; } else { /* @@ -813,7 +836,6 @@ cpuid_amd_getids(cpu_t *cpu) if (cpi->cpi_apicid == cpi->cpi_pkgcoreid) { /* We are BSP */ cpi->cpi_procnodeid = (first_half ? 0 : 1); - cpi->cpi_chipid = cpi->cpi_procnodeid >> 1; } else { /* We are AP */ @@ -833,17 +855,14 @@ cpuid_amd_getids(cpu_t *cpu) else cpi->cpi_procnodeid = node2_1 + first_half; - - cpi->cpi_chipid = cpi->cpi_procnodeid >> 1; } } - } else if (cpi->cpi_family >= 0x11) { - cpi->cpi_procnodeid = (cpi->cpi_apicid >> coreidsz) & 7; - cpi->cpi_chipid = cpi->cpi_procnodeid; } else { cpi->cpi_procnodeid = 0; - cpi->cpi_chipid = cpi->cpi_procnodeid; } + + cpi->cpi_chipid = + cpi->cpi_procnodeid / cpi->cpi_procnodes_per_pkg; } /* @@ -1218,30 +1237,28 @@ cpuid_pass1(cpu_t *cpu, uchar_t *featureset) if (cp->cp_ecx & CPUID_INTC_ECX_SSE3) { add_x86_feature(featureset, X86FSET_SSE3); } - if (cpi->cpi_vendor == X86_VENDOR_Intel) { - if (cp->cp_ecx & CPUID_INTC_ECX_SSSE3) { - add_x86_feature(featureset, X86FSET_SSSE3); - } - if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_1) { - add_x86_feature(featureset, X86FSET_SSE4_1); - } - if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_2) { - add_x86_feature(featureset, X86FSET_SSE4_2); - } - if (cp->cp_ecx & CPUID_INTC_ECX_AES) { - add_x86_feature(featureset, X86FSET_AES); - } - if (cp->cp_ecx & CPUID_INTC_ECX_PCLMULQDQ) { - add_x86_feature(featureset, X86FSET_PCLMULQDQ); - } + if (cp->cp_ecx & CPUID_INTC_ECX_SSSE3) { + add_x86_feature(featureset, X86FSET_SSSE3); + } + if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_1) { + add_x86_feature(featureset, X86FSET_SSE4_1); + } + if (cp->cp_ecx & CPUID_INTC_ECX_SSE4_2) { + add_x86_feature(featureset, X86FSET_SSE4_2); + } + if (cp->cp_ecx & CPUID_INTC_ECX_AES) { + add_x86_feature(featureset, X86FSET_AES); + } + if (cp->cp_ecx & CPUID_INTC_ECX_PCLMULQDQ) { + add_x86_feature(featureset, X86FSET_PCLMULQDQ); + } - if (cp->cp_ecx & CPUID_INTC_ECX_XSAVE) { - add_x86_feature(featureset, X86FSET_XSAVE); - /* We only test AVX when there is XSAVE */ - if (cp->cp_ecx & CPUID_INTC_ECX_AVX) { - add_x86_feature(featureset, - X86FSET_AVX); - } + if (cp->cp_ecx & CPUID_INTC_ECX_XSAVE) { + add_x86_feature(featureset, X86FSET_XSAVE); + /* We only test AVX when there is XSAVE */ + if (cp->cp_ecx & CPUID_INTC_ECX_AVX) { + add_x86_feature(featureset, + X86FSET_AVX); } } } @@ -1439,6 +1456,10 @@ cpuid_pass1(cpu_t *cpu, uchar_t *featureset) if (cp->cp_ecx & CPUID_AMD_ECX_SVM) { add_x86_feature(featureset, X86FSET_SVM); } + + if (cp->cp_ecx & CPUID_AMD_ECX_TOPOEXT) { + add_x86_feature(featureset, X86FSET_TOPOEXT); + } break; default: break; @@ -1547,6 +1568,7 @@ cpuid_pass1(cpu_t *cpu, uchar_t *featureset) cpi->cpi_apicid = CPI_APIC_ID(cpi); cpi->cpi_procnodes_per_pkg = 1; + cpi->cpi_cores_per_compunit = 1; if (is_x86_feature(featureset, X86FSET_HTT) == B_FALSE && is_x86_feature(featureset, X86FSET_CMP) == B_FALSE) { /* @@ -1573,6 +1595,7 @@ cpuid_pass1(cpu_t *cpu, uchar_t *featureset) cpi->cpi_coreid = cpi->cpi_chipid; cpi->cpi_pkgcoreid = 0; cpi->cpi_procnodeid = cpi->cpi_chipid; + cpi->cpi_compunitid = cpi->cpi_chipid; } } @@ -1797,7 +1820,7 @@ cpuid_pass2(cpu_t *cpu) /* * XSAVE enumeration */ - if (cpi->cpi_maxeax >= 0xD && cpi->cpi_vendor == X86_VENDOR_Intel) { + if (cpi->cpi_maxeax >= 0xD) { struct cpuid_regs regs; boolean_t cpuid_d_valid = B_TRUE; @@ -2531,23 +2554,21 @@ cpuid_pass4(cpu_t *cpu) if (!is_x86_feature(x86_featureset, X86FSET_SSE3)) *ecx &= ~CPUID_INTC_ECX_SSE3; - if (cpi->cpi_vendor == X86_VENDOR_Intel) { - if (!is_x86_feature(x86_featureset, X86FSET_SSSE3)) - *ecx &= ~CPUID_INTC_ECX_SSSE3; - if (!is_x86_feature(x86_featureset, X86FSET_SSE4_1)) - *ecx &= ~CPUID_INTC_ECX_SSE4_1; - if (!is_x86_feature(x86_featureset, X86FSET_SSE4_2)) - *ecx &= ~CPUID_INTC_ECX_SSE4_2; - if (!is_x86_feature(x86_featureset, X86FSET_AES)) - *ecx &= ~CPUID_INTC_ECX_AES; - if (!is_x86_feature(x86_featureset, X86FSET_PCLMULQDQ)) - *ecx &= ~CPUID_INTC_ECX_PCLMULQDQ; - if (!is_x86_feature(x86_featureset, X86FSET_XSAVE)) - *ecx &= ~(CPUID_INTC_ECX_XSAVE | - CPUID_INTC_ECX_OSXSAVE); - if (!is_x86_feature(x86_featureset, X86FSET_AVX)) - *ecx &= ~CPUID_INTC_ECX_AVX; - } + if (!is_x86_feature(x86_featureset, X86FSET_SSSE3)) + *ecx &= ~CPUID_INTC_ECX_SSSE3; + if (!is_x86_feature(x86_featureset, X86FSET_SSE4_1)) + *ecx &= ~CPUID_INTC_ECX_SSE4_1; + if (!is_x86_feature(x86_featureset, X86FSET_SSE4_2)) + *ecx &= ~CPUID_INTC_ECX_SSE4_2; + if (!is_x86_feature(x86_featureset, X86FSET_AES)) + *ecx &= ~CPUID_INTC_ECX_AES; + if (!is_x86_feature(x86_featureset, X86FSET_PCLMULQDQ)) + *ecx &= ~CPUID_INTC_ECX_PCLMULQDQ; + if (!is_x86_feature(x86_featureset, X86FSET_XSAVE)) + *ecx &= ~(CPUID_INTC_ECX_XSAVE | + CPUID_INTC_ECX_OSXSAVE); + if (!is_x86_feature(x86_featureset, X86FSET_AVX)) + *ecx &= ~CPUID_INTC_ECX_AVX; /* * [no explicit support required beyond x87 fp context] @@ -2567,22 +2588,24 @@ cpuid_pass4(cpu_t *cpu) hwcap_flags |= AV_386_SSE2; if (*ecx & CPUID_INTC_ECX_SSE3) hwcap_flags |= AV_386_SSE3; - if (cpi->cpi_vendor == X86_VENDOR_Intel) { - if (*ecx & CPUID_INTC_ECX_SSSE3) - hwcap_flags |= AV_386_SSSE3; - if (*ecx & CPUID_INTC_ECX_SSE4_1) - hwcap_flags |= AV_386_SSE4_1; - if (*ecx & CPUID_INTC_ECX_SSE4_2) - hwcap_flags |= AV_386_SSE4_2; - if (*ecx & CPUID_INTC_ECX_MOVBE) - hwcap_flags |= AV_386_MOVBE; - if (*ecx & CPUID_INTC_ECX_AES) - hwcap_flags |= AV_386_AES; - if (*ecx & CPUID_INTC_ECX_PCLMULQDQ) - hwcap_flags |= AV_386_PCLMULQDQ; - if ((*ecx & CPUID_INTC_ECX_XSAVE) && - (*ecx & CPUID_INTC_ECX_OSXSAVE)) - hwcap_flags |= AV_386_XSAVE; + if (*ecx & CPUID_INTC_ECX_SSSE3) + hwcap_flags |= AV_386_SSSE3; + if (*ecx & CPUID_INTC_ECX_SSE4_1) + hwcap_flags |= AV_386_SSE4_1; + if (*ecx & CPUID_INTC_ECX_SSE4_2) + hwcap_flags |= AV_386_SSE4_2; + if (*ecx & CPUID_INTC_ECX_MOVBE) + hwcap_flags |= AV_386_MOVBE; + if (*ecx & CPUID_INTC_ECX_AES) + hwcap_flags |= AV_386_AES; + if (*ecx & CPUID_INTC_ECX_PCLMULQDQ) + hwcap_flags |= AV_386_PCLMULQDQ; + if ((*ecx & CPUID_INTC_ECX_XSAVE) && + (*ecx & CPUID_INTC_ECX_OSXSAVE)) { + hwcap_flags |= AV_386_XSAVE; + + if (*ecx & CPUID_INTC_ECX_AVX) + hwcap_flags |= AV_386_AVX; } if (*ecx & CPUID_INTC_ECX_VMX) hwcap_flags |= AV_386_VMX; @@ -3006,6 +3029,20 @@ cpuid_get_procnodes_per_pkg(cpu_t *cpu) return (cpu->cpu_m.mcpu_cpi->cpi_procnodes_per_pkg); } +uint_t +cpuid_get_compunitid(cpu_t *cpu) +{ + ASSERT(cpuid_checkpass(cpu, 1)); + return (cpu->cpu_m.mcpu_cpi->cpi_compunitid); +} + +uint_t +cpuid_get_cores_per_compunit(cpu_t *cpu) +{ + ASSERT(cpuid_checkpass(cpu, 1)); + return (cpu->cpu_m.mcpu_cpi->cpi_cores_per_compunit); +} + /*ARGSUSED*/ int cpuid_have_cr8access(cpu_t *cpu) @@ -3336,6 +3373,13 @@ cpuid_opteron_erratum(cpu_t *cpu, uint_t erratum) return (DR_AX(eax) || DR_B0(eax) || DR_B1(eax) || DR_BA(eax) || DR_B2(eax) || RB_C0(eax)); + case 721: +#if defined(__amd64) + return (cpi->cpi_family == 0x10 || cpi->cpi_family == 0x12); +#else + return (0); +#endif + default: return (-1); @@ -4135,6 +4179,9 @@ cpuid_set_cpu_properties(void *dip, processorid_t cpu_id, case X86_VENDOR_Intel: create = IS_NEW_F6(cpi) || cpi->cpi_family >= 0xf; break; + case X86_VENDOR_AMD: + create = cpi->cpi_family >= 0xf; + break; default: create = 0; break; diff --git a/usr/src/uts/i86pc/os/cpupm/pwrnow.c b/usr/src/uts/i86pc/os/cpupm/pwrnow.c index d403c69e34..0116fe9157 100644 --- a/usr/src/uts/i86pc/os/cpupm/pwrnow.c +++ b/usr/src/uts/i86pc/os/cpupm/pwrnow.c @@ -38,6 +38,8 @@ static void pwrnow_fini(cpu_t *); static void pwrnow_power(cpuset_t, uint32_t); static void pwrnow_stop(cpu_t *); +static boolean_t pwrnow_cpb_supported(void); + /* * Interfaces for modules implementing AMD's PowerNow!. */ @@ -67,6 +69,7 @@ cpupm_state_ops_t pwrnow_ops = { #define AMD_CPUID_PSTATE_HARDWARE (1<<7) #define AMD_CPUID_TSC_CONSTANT (1<<8) +#define AMD_CPUID_CPB (1<<9) /* * Debugging support @@ -128,6 +131,10 @@ pwrnow_pstate_transition(uint32_t req_state) ctrl = CPU_ACPI_PSTATE_CTRL(req_pstate); write_ctrl(handle, ctrl); + if (mach_state->ms_turbo != NULL) + cpupm_record_turbo_info(mach_state->ms_turbo, + mach_state->ms_pstate.cma_state.pstate, req_state); + mach_state->ms_pstate.cma_state.pstate = req_state; cpu_set_curr_clock((uint64_t)CPU_ACPI_FREQ(req_pstate) * 1000000); } @@ -192,6 +199,12 @@ pwrnow_init(cpu_t *cp) cpupm_alloc_domains(cp, CPUPM_P_STATES); + /* + * Check for Core Performance Boost support + */ + if (pwrnow_cpb_supported()) + mach_state->ms_turbo = cpupm_turbo_init(cp); + PWRNOW_DEBUG(("Processor %d succeeded.\n", cp->cpu_id)) return (PWRNOW_RET_SUCCESS); } @@ -208,6 +221,10 @@ pwrnow_fini(cpu_t *cp) cpupm_free_domains(&cpupm_pstate_domains); cpu_acpi_free_pstate_data(handle); + + if (mach_state->ms_turbo != NULL) + cpupm_turbo_fini(mach_state->ms_turbo); + mach_state->ms_turbo = NULL; } boolean_t @@ -249,6 +266,30 @@ pwrnow_supported() return (B_TRUE); } +static boolean_t +pwrnow_cpb_supported(void) +{ + struct cpuid_regs cpu_regs; + + /* Required features */ + if (!is_x86_feature(x86_featureset, X86FSET_CPUID) || + !is_x86_feature(x86_featureset, X86FSET_MSR)) { + PWRNOW_DEBUG(("No CPUID or MSR support.")); + return (B_FALSE); + } + + /* + * Get the Advanced Power Management Information. + */ + cpu_regs.cp_eax = 0x80000007; + (void) __cpuid_insn(&cpu_regs); + + if (!(cpu_regs.cp_edx & AMD_CPUID_CPB)) + return (B_FALSE); + + return (B_TRUE); +} + static void pwrnow_stop(cpu_t *cp) { @@ -258,4 +299,8 @@ pwrnow_stop(cpu_t *cp) cpupm_remove_domains(cp, CPUPM_P_STATES, &cpupm_pstate_domains); cpu_acpi_free_pstate_data(handle); + + if (mach_state->ms_turbo != NULL) + cpupm_turbo_fini(mach_state->ms_turbo); + mach_state->ms_turbo = NULL; } diff --git a/usr/src/uts/i86pc/os/cpupm/speedstep.c b/usr/src/uts/i86pc/os/cpupm/speedstep.c index 2be4529a83..27df5c022d 100644 --- a/usr/src/uts/i86pc/os/cpupm/speedstep.c +++ b/usr/src/uts/i86pc/os/cpupm/speedstep.c @@ -38,33 +38,11 @@ #include <sys/dtrace.h> #include <sys/sdt.h> -/* - * turbo related structure definitions - */ -typedef struct cpupm_turbo_info { - kstat_t *turbo_ksp; /* turbo kstat */ - int in_turbo; /* in turbo? */ - int turbo_supported; /* turbo flag */ - uint64_t t_mcnt; /* turbo mcnt */ - uint64_t t_acnt; /* turbo acnt */ -} cpupm_turbo_info_t; - -typedef struct turbo_kstat_s { - struct kstat_named turbo_supported; /* turbo flag */ - struct kstat_named t_mcnt; /* IA32_MPERF_MSR */ - struct kstat_named t_acnt; /* IA32_APERF_MSR */ -} turbo_kstat_t; - static int speedstep_init(cpu_t *); static void speedstep_fini(cpu_t *); static void speedstep_power(cpuset_t, uint32_t); static void speedstep_stop(cpu_t *); -static boolean_t turbo_supported(void); -static int turbo_kstat_update(kstat_t *, int); -static void get_turbo_info(cpupm_turbo_info_t *); -static void reset_turbo_info(void); -static void record_turbo_info(cpupm_turbo_info_t *, uint32_t, uint32_t); -static void update_turbo_info(cpupm_turbo_info_t *); +static boolean_t speedstep_turbo_supported(void); /* * Interfaces for modules implementing Intel's Enhanced SpeedStep. @@ -96,16 +74,6 @@ cpupm_state_ops_t speedstep_ops = { #define IA32_MISC_ENABLE_CXE (1<<25) #define CPUID_TURBO_SUPPORT (1 << 1) -#define CPU_ACPI_P0 0 -#define CPU_IN_TURBO 1 - -/* - * MSR for hardware coordination feedback mechanism - * - IA32_MPERF: increments in proportion to a fixed frequency - * - IA32_APERF: increments in proportion to actual performance - */ -#define IA32_MPERF_MSR 0xE7 -#define IA32_APERF_MSR 0xE8 /* * Debugging support @@ -117,116 +85,6 @@ volatile int ess_debug = 0; #define ESSDEBUG(arglist) #endif -static kmutex_t turbo_mutex; - -turbo_kstat_t turbo_kstat = { - { "turbo_supported", KSTAT_DATA_UINT32 }, - { "turbo_mcnt", KSTAT_DATA_UINT64 }, - { "turbo_acnt", KSTAT_DATA_UINT64 }, -}; - -/* - * kstat update function of the turbo mode info - */ -static int -turbo_kstat_update(kstat_t *ksp, int flag) -{ - cpupm_turbo_info_t *turbo_info = ksp->ks_private; - - if (flag == KSTAT_WRITE) { - return (EACCES); - } - - /* - * update the count in case CPU is in the turbo - * mode for a long time - */ - if (turbo_info->in_turbo == CPU_IN_TURBO) - update_turbo_info(turbo_info); - - turbo_kstat.turbo_supported.value.ui32 = - turbo_info->turbo_supported; - turbo_kstat.t_mcnt.value.ui64 = turbo_info->t_mcnt; - turbo_kstat.t_acnt.value.ui64 = turbo_info->t_acnt; - - return (0); -} - -/* - * Get count of MPERF/APERF MSR - */ -static void -get_turbo_info(cpupm_turbo_info_t *turbo_info) -{ - ulong_t iflag; - uint64_t mcnt, acnt; - - iflag = intr_clear(); - mcnt = rdmsr(IA32_MPERF_MSR); - acnt = rdmsr(IA32_APERF_MSR); - turbo_info->t_mcnt += mcnt; - turbo_info->t_acnt += acnt; - intr_restore(iflag); -} - -/* - * Clear MPERF/APERF MSR - */ -static void -reset_turbo_info(void) -{ - ulong_t iflag; - - iflag = intr_clear(); - wrmsr(IA32_MPERF_MSR, 0); - wrmsr(IA32_APERF_MSR, 0); - intr_restore(iflag); -} - -/* - * sum up the count of one CPU_ACPI_P0 transition - */ -static void -record_turbo_info(cpupm_turbo_info_t *turbo_info, - uint32_t cur_state, uint32_t req_state) -{ - if (!turbo_info->turbo_supported) - return; - /* - * enter P0 state - */ - if (req_state == CPU_ACPI_P0) { - reset_turbo_info(); - turbo_info->in_turbo = CPU_IN_TURBO; - } - /* - * Leave P0 state - */ - else if (cur_state == CPU_ACPI_P0) { - turbo_info->in_turbo = 0; - get_turbo_info(turbo_info); - } -} - -/* - * update the sum of counts and clear MSRs - */ -static void -update_turbo_info(cpupm_turbo_info_t *turbo_info) -{ - ulong_t iflag; - uint64_t mcnt, acnt; - - iflag = intr_clear(); - mcnt = rdmsr(IA32_MPERF_MSR); - acnt = rdmsr(IA32_APERF_MSR); - wrmsr(IA32_MPERF_MSR, 0); - wrmsr(IA32_APERF_MSR, 0); - turbo_info->t_mcnt += mcnt; - turbo_info->t_acnt += acnt; - intr_restore(iflag); -} - /* * Write the ctrl register. How it is written, depends upon the _PCT * APCI object value. @@ -276,8 +134,6 @@ speedstep_pstate_transition(uint32_t req_state) cpu_acpi_handle_t handle = mach_state->ms_acpi_handle; cpu_acpi_pstate_t *req_pstate; uint32_t ctrl; - cpupm_turbo_info_t *turbo_info = - (cpupm_turbo_info_t *)(mach_state->ms_vendor); req_pstate = (cpu_acpi_pstate_t *)CPU_ACPI_PSTATES(handle); req_pstate += req_state; @@ -290,11 +146,10 @@ speedstep_pstate_transition(uint32_t req_state) ctrl = CPU_ACPI_PSTATE_CTRL(req_pstate); write_ctrl(handle, ctrl); - if (turbo_info) - record_turbo_info(turbo_info, + if (mach_state->ms_turbo != NULL) + cpupm_record_turbo_info(mach_state->ms_turbo, mach_state->ms_pstate.cma_state.pstate, req_state); - mach_state->ms_pstate.cma_state.pstate = req_state; cpu_set_curr_clock(((uint64_t)CPU_ACPI_FREQ(req_pstate) * 1000000)); } @@ -330,7 +185,6 @@ speedstep_init(cpu_t *cp) (cpupm_mach_state_t *)cp->cpu_m.mcpu_pm_mach_state; cpu_acpi_handle_t handle = mach_state->ms_acpi_handle; cpu_acpi_pct_t *pct_stat; - cpupm_turbo_info_t *turbo_info; ESSDEBUG(("speedstep_init: processor %d\n", cp->cpu_id)); @@ -363,34 +217,8 @@ speedstep_init(cpu_t *cp) cpupm_alloc_domains(cp, CPUPM_P_STATES); - if (!turbo_supported()) { - mach_state->ms_vendor = NULL; - goto ess_ret_success; - } - /* - * turbo mode supported - */ - turbo_info = mach_state->ms_vendor = - kmem_zalloc(sizeof (cpupm_turbo_info_t), KM_SLEEP); - turbo_info->turbo_supported = 1; - turbo_info->turbo_ksp = kstat_create("turbo", cp->cpu_id, - "turbo", "misc", KSTAT_TYPE_NAMED, - sizeof (turbo_kstat) / sizeof (kstat_named_t), - KSTAT_FLAG_VIRTUAL); - - if (turbo_info->turbo_ksp == NULL) { - cmn_err(CE_NOTE, "kstat_create(turbo) fail"); - } else { - turbo_info->turbo_ksp->ks_data = &turbo_kstat; - turbo_info->turbo_ksp->ks_lock = &turbo_mutex; - turbo_info->turbo_ksp->ks_update = turbo_kstat_update; - turbo_info->turbo_ksp->ks_data_size += MAXNAMELEN; - turbo_info->turbo_ksp->ks_private = turbo_info; - - kstat_install(turbo_info->turbo_ksp); - } - -ess_ret_success: + if (speedstep_turbo_supported()) + mach_state->ms_turbo = cpupm_turbo_init(cp); ESSDEBUG(("Processor %d succeeded.\n", cp->cpu_id)) return (ESS_RET_SUCCESS); @@ -405,17 +233,13 @@ speedstep_fini(cpu_t *cp) cpupm_mach_state_t *mach_state = (cpupm_mach_state_t *)(cp->cpu_m.mcpu_pm_mach_state); cpu_acpi_handle_t handle = mach_state->ms_acpi_handle; - cpupm_turbo_info_t *turbo_info = - (cpupm_turbo_info_t *)(mach_state->ms_vendor); cpupm_free_domains(&cpupm_pstate_domains); cpu_acpi_free_pstate_data(handle); - if (turbo_info) { - if (turbo_info->turbo_ksp != NULL) - kstat_delete(turbo_info->turbo_ksp); - kmem_free(turbo_info, sizeof (cpupm_turbo_info_t)); - } + if (mach_state->ms_turbo != NULL) + cpupm_turbo_fini(mach_state->ms_turbo); + mach_state->ms_turbo = NULL; } static void @@ -424,17 +248,13 @@ speedstep_stop(cpu_t *cp) cpupm_mach_state_t *mach_state = (cpupm_mach_state_t *)(cp->cpu_m.mcpu_pm_mach_state); cpu_acpi_handle_t handle = mach_state->ms_acpi_handle; - cpupm_turbo_info_t *turbo_info = - (cpupm_turbo_info_t *)(mach_state->ms_vendor); cpupm_remove_domains(cp, CPUPM_P_STATES, &cpupm_pstate_domains); cpu_acpi_free_pstate_data(handle); - if (turbo_info) { - if (turbo_info->turbo_ksp != NULL) - kstat_delete(turbo_info->turbo_ksp); - kmem_free(turbo_info, sizeof (cpupm_turbo_info_t)); - } + if (mach_state->ms_turbo != NULL) + cpupm_turbo_fini(mach_state->ms_turbo); + mach_state->ms_turbo = NULL; } boolean_t @@ -470,7 +290,7 @@ speedstep_supported(uint_t family, uint_t model) } boolean_t -turbo_supported(void) +speedstep_turbo_supported(void) { struct cpuid_regs cpu_regs; diff --git a/usr/src/uts/i86pc/os/cpupm/turbo.c b/usr/src/uts/i86pc/os/cpupm/turbo.c new file mode 100644 index 0000000000..7844ce2247 --- /dev/null +++ b/usr/src/uts/i86pc/os/cpupm/turbo.c @@ -0,0 +1,208 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ +/* + * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. + */ +/* + * Copyright (c) 2009, Intel Corporation. + * All Rights Reserved. + */ + +#include <sys/x86_archext.h> +#include <sys/machsystm.h> +#include <sys/archsystm.h> +#include <sys/x_call.h> +#include <sys/acpi/acpi.h> +#include <sys/acpica.h> +#include <sys/speedstep.h> +#include <sys/cpu_acpi.h> +#include <sys/cpupm.h> +#include <sys/dtrace.h> +#include <sys/sdt.h> + +typedef struct turbo_kstat_s { + struct kstat_named turbo_supported; /* turbo flag */ + struct kstat_named t_mcnt; /* IA32_MPERF_MSR */ + struct kstat_named t_acnt; /* IA32_APERF_MSR */ +} turbo_kstat_t; + +static int turbo_kstat_update(kstat_t *, int); +static void get_turbo_info(cpupm_mach_turbo_info_t *); +static void reset_turbo_info(void); +static void record_turbo_info(cpupm_mach_turbo_info_t *, uint32_t, uint32_t); +static void update_turbo_info(cpupm_mach_turbo_info_t *); + +static kmutex_t turbo_mutex; + +turbo_kstat_t turbo_kstat = { + { "turbo_supported", KSTAT_DATA_UINT32 }, + { "turbo_mcnt", KSTAT_DATA_UINT64 }, + { "turbo_acnt", KSTAT_DATA_UINT64 }, +}; + +#define CPU_ACPI_P0 0 +#define CPU_IN_TURBO 1 + +/* + * MSR for hardware coordination feedback mechanism + * - IA32_MPERF: increments in proportion to a fixed frequency + * - IA32_APERF: increments in proportion to actual performance + */ +#define IA32_MPERF_MSR 0xE7 +#define IA32_APERF_MSR 0xE8 + +/* + * kstat update function of the turbo mode info + */ +static int +turbo_kstat_update(kstat_t *ksp, int flag) +{ + cpupm_mach_turbo_info_t *turbo_info = ksp->ks_private; + + if (flag == KSTAT_WRITE) { + return (EACCES); + } + + /* + * update the count in case CPU is in the turbo + * mode for a long time + */ + if (turbo_info->in_turbo == CPU_IN_TURBO) + update_turbo_info(turbo_info); + + turbo_kstat.turbo_supported.value.ui32 = + turbo_info->turbo_supported; + turbo_kstat.t_mcnt.value.ui64 = turbo_info->t_mcnt; + turbo_kstat.t_acnt.value.ui64 = turbo_info->t_acnt; + + return (0); +} + +/* + * update the sum of counts and clear MSRs + */ +static void +update_turbo_info(cpupm_mach_turbo_info_t *turbo_info) +{ + ulong_t iflag; + uint64_t mcnt, acnt; + + iflag = intr_clear(); + mcnt = rdmsr(IA32_MPERF_MSR); + acnt = rdmsr(IA32_APERF_MSR); + wrmsr(IA32_MPERF_MSR, 0); + wrmsr(IA32_APERF_MSR, 0); + turbo_info->t_mcnt += mcnt; + turbo_info->t_acnt += acnt; + intr_restore(iflag); +} + +/* + * Get count of MPERF/APERF MSR + */ +static void +get_turbo_info(cpupm_mach_turbo_info_t *turbo_info) +{ + ulong_t iflag; + uint64_t mcnt, acnt; + + iflag = intr_clear(); + mcnt = rdmsr(IA32_MPERF_MSR); + acnt = rdmsr(IA32_APERF_MSR); + turbo_info->t_mcnt += mcnt; + turbo_info->t_acnt += acnt; + intr_restore(iflag); +} + +/* + * Clear MPERF/APERF MSR + */ +static void +reset_turbo_info(void) +{ + ulong_t iflag; + + iflag = intr_clear(); + wrmsr(IA32_MPERF_MSR, 0); + wrmsr(IA32_APERF_MSR, 0); + intr_restore(iflag); +} + +/* + * sum up the count of one CPU_ACPI_P0 transition + */ +void +cpupm_record_turbo_info(cpupm_mach_turbo_info_t *turbo_info, + uint32_t cur_state, uint32_t req_state) +{ + if (!turbo_info->turbo_supported) + return; + /* + * enter P0 state + */ + if (req_state == CPU_ACPI_P0) { + reset_turbo_info(); + turbo_info->in_turbo = CPU_IN_TURBO; + } + /* + * Leave P0 state + */ + else if (cur_state == CPU_ACPI_P0) { + turbo_info->in_turbo = 0; + get_turbo_info(turbo_info); + } +} + +cpupm_mach_turbo_info_t * +cpupm_turbo_init(cpu_t *cp) +{ + cpupm_mach_turbo_info_t *turbo_info; + + turbo_info = kmem_zalloc(sizeof (cpupm_mach_turbo_info_t), KM_SLEEP); + + turbo_info->turbo_supported = 1; + turbo_info->turbo_ksp = kstat_create("turbo", cp->cpu_id, + "turbo", "misc", KSTAT_TYPE_NAMED, + sizeof (turbo_kstat) / sizeof (kstat_named_t), + KSTAT_FLAG_VIRTUAL); + + if (turbo_info->turbo_ksp == NULL) { + cmn_err(CE_NOTE, "kstat_create(turbo) fail"); + } else { + turbo_info->turbo_ksp->ks_data = &turbo_kstat; + turbo_info->turbo_ksp->ks_lock = &turbo_mutex; + turbo_info->turbo_ksp->ks_update = turbo_kstat_update; + turbo_info->turbo_ksp->ks_data_size += MAXNAMELEN; + turbo_info->turbo_ksp->ks_private = turbo_info; + + kstat_install(turbo_info->turbo_ksp); + } + + return (turbo_info); +} + +void +cpupm_turbo_fini(cpupm_mach_turbo_info_t *turbo_info) +{ + if (turbo_info->turbo_ksp != NULL) + kstat_delete(turbo_info->turbo_ksp); + kmem_free(turbo_info, sizeof (cpupm_mach_turbo_info_t)); +} diff --git a/usr/src/uts/i86pc/os/microcode.c b/usr/src/uts/i86pc/os/microcode.c index 90d9585640..c5c6a16790 100644 --- a/usr/src/uts/i86pc/os/microcode.c +++ b/usr/src/uts/i86pc/os/microcode.c @@ -33,6 +33,7 @@ #include <sys/kobj.h> #include <sys/kobj_impl.h> #include <sys/machsystm.h> +#include <sys/ontrap.h> #include <sys/param.h> #include <sys/machparam.h> #include <sys/promif.h> @@ -646,16 +647,17 @@ ucode_match_amd(uint16_t eq_sig, cpu_ucode_info_t *uinfop, if (ucodefp == NULL || size < sizeof (ucode_header_amd_t)) return (EM_NOMATCH); + uh = &ucodefp->uf_header; + /* * Don't even think about loading patches that would require code - * execution. + * execution. Does not apply to patches for family 0x14 and beyond. */ - if (size > offsetof(ucode_file_amd_t, uf_code_present) && + if (uh->uh_cpu_rev < 0x5000 && + size > offsetof(ucode_file_amd_t, uf_code_present) && ucodefp->uf_code_present) return (EM_NOMATCH); - uh = &ucodefp->uf_header; - if (eq_sig != uh->uh_cpu_rev) return (EM_NOMATCH); @@ -671,7 +673,7 @@ ucode_match_amd(uint16_t eq_sig, cpu_ucode_info_t *uinfop, return (EM_NOMATCH); } - if (uh->uh_patch_id <= uinfop->cui_rev) + if (uh->uh_patch_id <= uinfop->cui_rev && !ucode_force_update) return (EM_HIGHERREV); return (EM_OK); @@ -726,6 +728,9 @@ ucode_write(xc_arg_t arg1, xc_arg_t unused2, xc_arg_t unused3) { ucode_update_t *uusp = (ucode_update_t *)arg1; cpu_ucode_info_t *uinfop = CPU->cpu_m.mcpu_ucode_info; +#ifndef __xpv + on_trap_data_t otd; +#endif ASSERT(ucode); ASSERT(uusp->ucodep); @@ -743,7 +748,10 @@ ucode_write(xc_arg_t arg1, xc_arg_t unused2, xc_arg_t unused3) return (0); } - wrmsr(ucode->write_msr, (uintptr_t)uusp->ucodep); + if (!on_trap(&otd, OT_DATA_ACCESS)) + wrmsr(ucode->write_msr, (uintptr_t)uusp->ucodep); + + no_trap(); #endif ucode->read_rev(uinfop); uusp->new_rev = uinfop->cui_rev; @@ -758,6 +766,8 @@ ucode_load_amd(ucode_file_t *ufp, cpu_ucode_info_t *uinfop, cpu_t *cp) ucode_file_amd_t *ucodefp = ufp->amd; #ifdef __xpv ucode_update_t uus; +#else + on_trap_data_t otd; #endif ASSERT(ucode); @@ -765,7 +775,13 @@ ucode_load_amd(ucode_file_t *ufp, cpu_ucode_info_t *uinfop, cpu_t *cp) #ifndef __xpv kpreempt_disable(); + if (on_trap(&otd, OT_DATA_ACCESS)) { + no_trap(); + kpreempt_enable(); + return (0); + } wrmsr(ucode->write_msr, (uintptr_t)ucodefp); + no_trap(); ucode->read_rev(uinfop); kpreempt_enable(); @@ -1093,7 +1109,8 @@ ucode_update(uint8_t *ucodep, int size) kpreempt_enable(); CPUSET_DEL(cpuset, id); - if (uusp->new_rev != 0 && uusp->info.cui_rev == uusp->new_rev) { + if (uusp->new_rev != 0 && uusp->info.cui_rev == uusp->new_rev && + !ucode_force_update) { rc = EM_HIGHERREV; } else if ((uusp->new_rev == 0) || (uusp->expected_rev != 0 && uusp->expected_rev != uusp->new_rev)) { diff --git a/usr/src/uts/i86pc/os/mlsetup.c b/usr/src/uts/i86pc/os/mlsetup.c index 63b858f978..dc79a04af2 100644 --- a/usr/src/uts/i86pc/os/mlsetup.c +++ b/usr/src/uts/i86pc/os/mlsetup.c @@ -19,6 +19,8 @@ * CDDL HEADER END */ /* + * Copyright (c) 2012 Gary Mills + * * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011 by Delphix. All rights reserved. */ @@ -110,7 +112,6 @@ mlsetup(struct regs *rp) extern disp_t cpu0_disp; extern char t0stack[]; extern int post_fastreboot; - extern int console; extern uint64_t plat_dr_options; ASSERT_STACK_ALIGNED(); @@ -348,7 +349,7 @@ mlsetup(struct regs *rp) * Explicitly set console to text mode (0x3) if this is a boot * post Fast Reboot, and the console is set to CONS_SCREEN_TEXT. */ - if (post_fastreboot && console == CONS_SCREEN_TEXT) + if (post_fastreboot && boot_console_type(NULL) == CONS_SCREEN_TEXT) set_console_mode(0x3); /* diff --git a/usr/src/uts/i86pc/os/mp_machdep.c b/usr/src/uts/i86pc/os/mp_machdep.c index d7aab080a6..7062df90ff 100644 --- a/usr/src/uts/i86pc/os/mp_machdep.c +++ b/usr/src/uts/i86pc/os/mp_machdep.c @@ -245,6 +245,11 @@ pg_plat_hw_shared(cpu_t *cp, pghw_type_t hw) } else { return (0); } + case PGHW_FPU: + if (cpuid_get_cores_per_compunit(cp) > 1) + return (1); + else + return (0); case PGHW_PROCNODE: if (cpuid_get_procnodes_per_pkg(cp) > 1) return (1); @@ -306,6 +311,8 @@ pg_plat_hw_instance_id(cpu_t *cpu, pghw_type_t hw) return (cpuid_get_coreid(cpu)); case PGHW_CACHE: return (cpuid_get_last_lvl_cacheid(cpu)); + case PGHW_FPU: + return (cpuid_get_compunitid(cpu)); case PGHW_PROCNODE: return (cpuid_get_procnodeid(cpu)); case PGHW_CHIP: @@ -331,6 +338,7 @@ pg_plat_hw_rank(pghw_type_t hw1, pghw_type_t hw2) static pghw_type_t hw_hier[] = { PGHW_IPIPE, PGHW_CACHE, + PGHW_FPU, PGHW_PROCNODE, PGHW_CHIP, PGHW_POW_IDLE, @@ -361,8 +369,13 @@ pg_plat_cmt_policy(pghw_type_t hw) /* * For shared caches, also load balance across them to * maximize aggregate cache capacity + * + * On AMD family 0x15 CPUs, cores come in pairs called + * compute units, sharing the FPU and the I$ and L2 + * caches. Use balancing and cache affinity. */ switch (hw) { + case PGHW_FPU: case PGHW_CACHE: return (CMT_BALANCE|CMT_AFFINITY); default: diff --git a/usr/src/uts/i86pc/os/mp_startup.c b/usr/src/uts/i86pc/os/mp_startup.c index 843c5ae73a..588d38bb7a 100644 --- a/usr/src/uts/i86pc/os/mp_startup.c +++ b/usr/src/uts/i86pc/os/mp_startup.c @@ -649,6 +649,10 @@ int opteron_workaround_6323525; /* if non-zero -> at least one cpu has it */ int opteron_erratum_298; #endif +#if defined(OPTERON_ERRATUM_721) +int opteron_erratum_721; +#endif + static void workaround_warning(cpu_t *cp, uint_t erratum) { @@ -1177,6 +1181,16 @@ workaround_errata(struct cpu *cpu) missing += do_erratum_298(cpu); + if (cpuid_opteron_erratum(cpu, 721) > 0) { +#if defined(OPTERON_ERRATUM_721) + wrmsr(MSR_AMD_DE_CFG, rdmsr(MSR_AMD_DE_CFG) | AMD_DE_CFG_E721); + opteron_erratum_721++; +#else + workaround_warning(cpu, 721); + missing++; +#endif + } + #ifdef __xpv return (0); #else @@ -1267,6 +1281,10 @@ workaround_errata_end() " system\noperation may occur.\n"); } #endif +#if defined(OPTERON_ERRATUM_721) + if (opteron_erratum_721) + workaround_applied(721); +#endif } /* |