Changeset View
Changeset View
Standalone View
Standalone View
sys/x86/cpufreq/hwpstate_amd.c
| Show First 20 Lines • Show All 255 Lines • ▼ Show 20 Lines | print_cppc_caps_1(struct sbuf *const sb, const uint64_t caps) | ||||
| print_msr_bits(sb, "Guaranteed Performance", | print_msr_bits(sb, "Guaranteed Performance", | ||||
| AMD_CPPC_CAPS_1_NOMINAL_PERF_BITS, caps); | AMD_CPPC_CAPS_1_NOMINAL_PERF_BITS, caps); | ||||
| print_msr_bits(sb, "Efficient Performance", | print_msr_bits(sb, "Efficient Performance", | ||||
| AMD_CPPC_CAPS_1_EFFICIENT_PERF_BITS, caps); | AMD_CPPC_CAPS_1_EFFICIENT_PERF_BITS, caps); | ||||
| print_msr_bits(sb, "Lowest Performance", | print_msr_bits(sb, "Lowest Performance", | ||||
| AMD_CPPC_CAPS_1_LOWEST_PERF_BITS, caps); | 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 | static void | ||||
| print_cppc_no_caps_1(struct sbuf *const sb) | print_cppc_no_caps_1(struct sbuf *const sb) | ||||
| { | { | ||||
| sbuf_printf(sb, MSR_AMD_CPPC_CAPS_1_NAME ": " MSR_NOT_READ_MSG "\n"); | sbuf_printf(sb, MSR_AMD_CPPC_CAPS_1_NAME ": " MSR_NOT_READ_MSG "\n"); | ||||
| } | } | ||||
| static void | static void | ||||
| ▲ Show 20 Lines • Show All 366 Lines • ▼ Show 20 Lines | hwpstate_identify(driver_t *driver, device_t parent) | ||||
| if (resource_disabled(HWP_AMD_CLASSNAME, 0)) | if (resource_disabled(HWP_AMD_CLASSNAME, 0)) | ||||
| return; | return; | ||||
| if (BUS_ADD_CHILD(parent, 10, HWP_AMD_CLASSNAME, | if (BUS_ADD_CHILD(parent, 10, HWP_AMD_CLASSNAME, | ||||
| device_get_unit(parent)) == NULL) | device_get_unit(parent)) == NULL) | ||||
| device_printf(parent, "hwpstate: add child failed\n"); | device_printf(parent, "hwpstate: add child failed\n"); | ||||
| } | } | ||||
| struct amd_set_autonomous_hwp_request { | struct set_autonomous_hwp_data { | ||||
| device_t dev; | /* Inputs */ | ||||
| int res; | 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 | static void | ||||
| amd_set_autonomous_hwp_cb(void *args) | amd_set_autonomous_hwp_cb(void *args) | ||||
| { | { | ||||
| struct hwpstate_softc *sc; | struct set_autonomous_hwp_data *const data = args; | ||||
| struct amd_set_autonomous_hwp_request *req = | struct hwpstate_softc *const sc = data->sc; | ||||
| (struct amd_set_autonomous_hwp_request *)args; | int error; | ||||
| device_t dev; | |||||
| uint64_t caps; | |||||
| int ret; | |||||
| dev = req->dev; | /* We proceed sequentially, so we'll clear out errors on progress. */ | ||||
| sc = device_get_softc(dev); | data->res = HWP_ERROR_CPPC_ENABLE | HWP_ERROR_CPPC_CAPS | | ||||
| ret = wrmsr_safe(MSR_AMD_CPPC_ENABLE, 1); | HWP_ERROR_CPPC_REQUEST | HWP_ERROR_CPPC_REQUEST_WRITE; | ||||
| if (ret != 0) { | |||||
| device_printf(dev, "Failed to enable cppc for cpu%d (%d)\n", | |||||
| curcpu, ret); | |||||
| req->res = ret; | |||||
| } | |||||
| ret = rdmsr_safe(MSR_AMD_CPPC_REQUEST, &sc->cppc.request); | error = wrmsr_safe(MSR_AMD_CPPC_ENABLE, 1); | ||||
| if (ret != 0) { | if (error != 0) | ||||
| device_printf(dev, | return; | ||||
| "Failed to read CPPC request MSR for cpu%d (%d)\n", curcpu, | data->res &= ~HWP_ERROR_CPPC_ENABLE; | ||||
| ret); | |||||
| req->res = ret; | |||||
| } | |||||
| ret = rdmsr_safe(MSR_AMD_CPPC_CAPS_1, &caps); | error = rdmsr_safe(MSR_AMD_CPPC_CAPS_1, &data->caps); | ||||
| if (ret != 0) { | if (error != 0) | ||||
| device_printf(dev, | |||||
| "Failed to read HWP capabilities MSR for cpu%d (%d)\n", | |||||
| curcpu, ret); | |||||
| req->res = ret; | |||||
| return; | 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 | * In Intel's reference manual, the default value of EPP is 0x80u which | ||||
| * is the balanced mode. For consistency, we set the same value in AMD's | * is the balanced mode. For consistency, we set the same value in AMD's | ||||
| * CPPC driver. | * CPPC driver. | ||||
| */ | */ | ||||
| SET_BITS_VALUE(sc->cppc.request, AMD_CPPC_REQUEST_EPP_BITS, 0x80); | SET_BITS_VALUE(sc->cppc.request, AMD_CPPC_REQUEST_EPP_BITS, 0x80); | ||||
| SET_BITS_VALUE(sc->cppc.request, AMD_CPPC_REQUEST_MIN_PERF_BITS, | 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, | 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 */ | /* enable autonomous mode by setting desired performance to 0 */ | ||||
| SET_BITS_VALUE(sc->cppc.request, AMD_CPPC_REQUEST_DES_PERF_BITS, 0); | SET_BITS_VALUE(sc->cppc.request, AMD_CPPC_REQUEST_DES_PERF_BITS, 0); | ||||
| ret = wrmsr_safe(MSR_AMD_CPPC_REQUEST, sc->cppc.request); | error = wrmsr_safe(MSR_AMD_CPPC_REQUEST, sc->cppc.request); | ||||
| if (ret) { | if (error != 0) | ||||
| device_printf(dev, "Failed to setup autonomous HWP for cpu%d\n", | |||||
| curcpu); | |||||
| req->res = ret; | |||||
| return; | return; | ||||
| data->res &= ~HWP_ERROR_CPPC_REQUEST_WRITE; | |||||
| data->request = sc->cppc.request; | |||||
| } | } | ||||
| req->res = 0; | |||||
| } | |||||
| static int | static int | ||||
| amd_set_autonomous_hwp(struct hwpstate_softc *sc) | amd_set_autonomous_hwp(struct hwpstate_softc *sc) | ||||
| { | { | ||||
| struct amd_set_autonomous_hwp_request req; | const device_t dev = sc->dev; | ||||
| device_t dev; | const u_int cpuid = cpu_get_pcpu(dev)->pc_cpuid; | ||||
| struct set_autonomous_hwp_data data; | |||||
| struct sbuf sbs; | |||||
| struct sbuf *sb; | |||||
| dev = sc->dev; | data.sc = sc; | ||||
| req.dev = dev; | smp_rendezvous_cpu(cpuid, smp_no_rendezvous_barrier, | ||||
| smp_rendezvous_cpu(cpu_get_pcpu(dev)->pc_cpuid, | amd_set_autonomous_hwp_cb, smp_no_rendezvous_barrier, &data); | ||||
| smp_no_rendezvous_barrier, amd_set_autonomous_hwp_cb, | |||||
| smp_no_rendezvous_barrier, &req); | |||||
| return (req.res); | 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. | |||||
| */ | |||||
| sb = sbuf_new(&sbs, NULL, 0, SBUF_AUTOEXTEND); | |||||
| 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 | static int | ||||
| hwpstate_probe(device_t dev) | hwpstate_probe(device_t dev) | ||||
| { | { | ||||
| struct hwpstate_softc *sc; | struct hwpstate_softc *sc; | ||||
| device_t perf_dev; | device_t perf_dev; | ||||
| uint64_t msr; | uint64_t msr; | ||||
| ▲ Show 20 Lines • Show All 266 Lines • Show Last 20 Lines | |||||