diff --git a/sys/x86/cpufreq/hwpstate_amd.c b/sys/x86/cpufreq/hwpstate_amd.c --- a/sys/x86/cpufreq/hwpstate_amd.c +++ b/sys/x86/cpufreq/hwpstate_amd.c @@ -261,7 +261,7 @@ AMD_CPPC_CAPS_1_LOWEST_PERF_BITS, caps); } -#define MSR_NOT_READ_MSG "Fault on read" +#define MSR_NOT_READ_MSG "Not read (fault or previous errors)" static void print_cppc_no_caps_1(struct sbuf *const sb) @@ -644,46 +644,45 @@ device_printf(parent, "hwpstate: add child failed\n"); } -struct amd_set_autonomous_hwp_request { - device_t dev; - int res; +struct set_autonomous_hwp_data { + /* Inputs */ + struct hwpstate_softc *sc; + /* Outputs */ + /* HWP_ERROR_CPPC_* */ + u_int res; + /* Below fields filled depending on 'res'. */ + uint64_t caps; + uint64_t init_request; + uint64_t request; }; static void amd_set_autonomous_hwp_cb(void *args) { - struct hwpstate_softc *sc; - struct amd_set_autonomous_hwp_request *req = - (struct amd_set_autonomous_hwp_request *)args; - device_t dev; - uint64_t caps; - int ret; + struct set_autonomous_hwp_data *const data = args; + struct hwpstate_softc *const sc = data->sc; + int error; - dev = req->dev; - sc = device_get_softc(dev); - ret = wrmsr_safe(MSR_AMD_CPPC_ENABLE, 1); - if (ret != 0) { - device_printf(dev, "Failed to enable cppc for cpu%d (%d)\n", - curcpu, ret); - req->res = ret; - } + /* We proceed sequentially, so we'll clear out errors on progress. */ + data->res = HWP_ERROR_CPPC_ENABLE | HWP_ERROR_CPPC_CAPS | + HWP_ERROR_CPPC_REQUEST | HWP_ERROR_CPPC_REQUEST_WRITE; - ret = rdmsr_safe(MSR_AMD_CPPC_REQUEST, &sc->cppc.request); - if (ret != 0) { - device_printf(dev, - "Failed to read CPPC request MSR for cpu%d (%d)\n", curcpu, - ret); - req->res = ret; - } + error = wrmsr_safe(MSR_AMD_CPPC_ENABLE, 1); + if (error != 0) + return; + data->res &= ~HWP_ERROR_CPPC_ENABLE; - ret = rdmsr_safe(MSR_AMD_CPPC_CAPS_1, &caps); - if (ret != 0) { - device_printf(dev, - "Failed to read HWP capabilities MSR for cpu%d (%d)\n", - curcpu, ret); - req->res = ret; + error = rdmsr_safe(MSR_AMD_CPPC_CAPS_1, &data->caps); + if (error != 0) return; - } + data->res &= ~HWP_ERROR_CPPC_CAPS; + + error = rdmsr_safe(MSR_AMD_CPPC_REQUEST, &sc->cppc.request); + if (error != 0) + return; + data->res &= ~HWP_ERROR_CPPC_REQUEST; + /* The CPPC_REQUEST value before we tweak it. */ + data->init_request = sc->cppc.request; /* * In Intel's reference manual, the default value of EPP is 0x80u which @@ -692,35 +691,71 @@ */ SET_BITS_VALUE(sc->cppc.request, AMD_CPPC_REQUEST_EPP_BITS, 0x80); SET_BITS_VALUE(sc->cppc.request, AMD_CPPC_REQUEST_MIN_PERF_BITS, - BITS_VALUE(AMD_CPPC_CAPS_1_LOWEST_PERF_BITS, caps)); + BITS_VALUE(AMD_CPPC_CAPS_1_LOWEST_PERF_BITS, data->caps)); SET_BITS_VALUE(sc->cppc.request, AMD_CPPC_REQUEST_MAX_PERF_BITS, - BITS_VALUE(AMD_CPPC_CAPS_1_HIGHEST_PERF_BITS, caps)); + BITS_VALUE(AMD_CPPC_CAPS_1_HIGHEST_PERF_BITS, data->caps)); /* enable autonomous mode by setting desired performance to 0 */ SET_BITS_VALUE(sc->cppc.request, AMD_CPPC_REQUEST_DES_PERF_BITS, 0); - ret = wrmsr_safe(MSR_AMD_CPPC_REQUEST, sc->cppc.request); - if (ret) { - device_printf(dev, "Failed to setup autonomous HWP for cpu%d\n", - curcpu); - req->res = ret; + error = wrmsr_safe(MSR_AMD_CPPC_REQUEST, sc->cppc.request); + if (error != 0) return; - } - req->res = 0; + data->res &= ~HWP_ERROR_CPPC_REQUEST_WRITE; + data->request = sc->cppc.request; } static int amd_set_autonomous_hwp(struct hwpstate_softc *sc) { - struct amd_set_autonomous_hwp_request req; - device_t dev; + const device_t dev = sc->dev; + const u_int cpuid = cpu_get_pcpu(dev)->pc_cpuid; + struct set_autonomous_hwp_data data; + struct sbuf sbs; + struct sbuf *sb; + + data.sc = sc; + smp_rendezvous_cpu(cpuid, smp_no_rendezvous_barrier, + amd_set_autonomous_hwp_cb, smp_no_rendezvous_barrier, &data); + + if (hwp_has_error(data.res, HWP_ERROR_CPPC_ENABLE)) { + device_printf(dev, "CPU%u: Failed to enable CPPC!\n", cpuid); + return (ENXIO); + } + device_printf(dev, "CPU%u: CPPC enabled.\n", cpuid); + + /* + * Now that we have enabled CPPC, we can't go back, so we'll attach even + * in case of further malfunction, allowing the user to retry setting + * CPPC_REQUEST via the sysctl knobs. + */ - dev = sc->dev; - req.dev = dev; - smp_rendezvous_cpu(cpu_get_pcpu(dev)->pc_cpuid, - smp_no_rendezvous_barrier, amd_set_autonomous_hwp_cb, - smp_no_rendezvous_barrier, &req); + sb = sbuf_new(&sbs, NULL, 0, SBUF_AUTOEXTEND); - return (req.res); + if (hwpstate_verbose) + sbuf_printf(sb, + "CPU%u: Initial MSR values after CPPC enable:\n", cpuid); + if (hwp_has_error(data.res, HWP_ERROR_CPPC_CAPS)) + print_cppc_no_caps_1(sb); + else if (hwpstate_verbose) + print_cppc_caps_1(sb, data.caps); + if (hwp_has_error(data.res, HWP_ERROR_CPPC_REQUEST)) + print_cppc_no_request(sb); + else if (hwpstate_verbose) + print_cppc_request(sb, data.init_request); + if (hwp_has_error(data.res, HWP_ERROR_CPPC_REQUEST_WRITE)) + device_printf(dev, "CPU%u: Could not write into " + MSR_AMD_CPPC_REQUEST_NAME "!\n", + cpuid); + else if (hwpstate_verbose) { + sbuf_printf(sb, "CPU%u: Tweaked MSR values:\n", cpuid); + print_cppc_request(sb, data.request); + } + + sbuf_finish(sb); + sbuf_putbuf(sb); + sbuf_delete(sb); + + return (0); } static int