Index: sys/conf/files.amd64 =================================================================== --- sys/conf/files.amd64 +++ sys/conf/files.amd64 @@ -701,6 +701,7 @@ x86/cpufreq/powernow.c optional cpufreq x86/cpufreq/est.c optional cpufreq x86/cpufreq/hwpstate_amd.c optional cpufreq +x86/cpufreq/hwpstate_intel.c optional cpufreq x86/cpufreq/p4tcc.c optional cpufreq x86/iommu/busdma_dmar.c optional acpi acpi_dmar pci x86/iommu/intel_ctx.c optional acpi acpi_dmar pci Index: sys/conf/files.i386 =================================================================== --- sys/conf/files.i386 +++ sys/conf/files.i386 @@ -573,6 +573,7 @@ x86/bios/vpd.c optional vpd x86/cpufreq/est.c optional cpufreq x86/cpufreq/hwpstate_amd.c optional cpufreq +x86/cpufreq/hwpstate_intel.c optional cpufreq x86/cpufreq/p4tcc.c optional cpufreq x86/cpufreq/powernow.c optional cpufreq x86/cpufreq/smist.c optional cpufreq Index: sys/modules/cpufreq/Makefile =================================================================== --- sys/modules/cpufreq/Makefile +++ sys/modules/cpufreq/Makefile @@ -11,7 +11,7 @@ .PATH: ${SRCTOP}/sys/x86/cpufreq SRCS+= acpi_if.h opt_acpi.h -SRCS+= est.c hwpstate_amd.c p4tcc.c powernow.c +SRCS+= est.c hwpstate_amd.c p4tcc.c powernow.c hwpstate_intel.c .endif .if ${MACHINE} == "i386" Index: sys/x86/cpufreq/est.c =================================================================== --- sys/x86/cpufreq/est.c +++ sys/x86/cpufreq/est.c @@ -50,6 +50,8 @@ #include #include "acpi_if.h" +extern uint32_t intel_speed_shift; + /* Status/control registers (from the IA-32 System Programming Guide). */ #define MSR_PERF_STATUS 0x198 #define MSR_PERF_CTL 0x199 @@ -916,6 +918,10 @@ { device_t child; + /* If the Intel driver is handling this */ + if (intel_speed_shift == true) + return; + /* Make sure we're not being doubly invoked. */ if (device_find_child(parent, "est", -1) != NULL) return; Index: sys/x86/cpufreq/hwpstate_intel.c =================================================================== --- /dev/null +++ sys/x86/cpufreq/hwpstate_intel.c @@ -0,0 +1,247 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2018 Intel Corporation + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted providing that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include + +#include "acpi_if.h" +#include "cpufreq_if.h" + +bool intel_speed_shift=true; +SYSCTL_BOOL(_machdep, OID_AUTO, intel_speed_shift, CTLFLAG_RDTUN, &intel_speed_shift, + 0, "Enable Intel Speed Shift (HWP)"); + +static void intel_hwpstate_identify(driver_t *driver, device_t parent); +static int intel_hwpstate_probe(device_t dev); +static int intel_hwpstate_attach(device_t dev); +static int intel_hwpstate_detach(device_t dev); + +#if 0 +static int intel_hwpstate_get(device_t dev, struct cf_setting *cf); +static int intel_hwpstate_set(device_t dev, const struct cf_setting *cf); +static int intel_hwpstate_settings(device_t dev, struct cf_setting *sets, int *count); +static int intel_hwpstate_type(device_t dev, int *type); +#endif + +static device_method_t intel_hwpstate_methods[] = { + /* Device interface */ + DEVMETHOD(device_identify, intel_hwpstate_identify), + DEVMETHOD(device_probe, intel_hwpstate_probe), + DEVMETHOD(device_attach, intel_hwpstate_attach), + DEVMETHOD(device_detach, intel_hwpstate_detach), + +#if 0 + /* cpufreq interface */ + DEVMETHOD(cpufreq_drv_get, intel_hwpstate_get), + DEVMETHOD(cpufreq_drv_set, intel_hwpstate_set), + DEVMETHOD(cpufreq_drv_settings, intel_hwpstate_settings), + DEVMETHOD(cpufreq_drv_type, intel_hwpstate_type), +#endif + {0, 0} +}; + +struct hwp_softc { + device_t dev; + bool hwp_notifications; + bool hwp_activity_window; + bool hwp_pref_ctrl; + bool hwp_pkg_ctrl; +}; + +static devclass_t hwpstate_intel_devclass; +static driver_t hwpstate_intel_driver = { + "hwpstate_intel", + intel_hwpstate_methods, + sizeof(struct hwp_softc), +}; + +/* NB: This must run before the est module!!!! */ +DRIVER_MODULE_ORDERED(hwpstate_intel, cpu, hwpstate_intel_driver, + hwpstate_intel_devclass, 0, 0, SI_ORDER_FIRST); + +static void +intel_hwpstate_identify(driver_t *driver, device_t parent) +{ + uint32_t regs[4]; + + if (intel_speed_shift == false) + return; + + if (device_find_child(parent, "hwpstate_intel", -1) != NULL) + return; + + if (cpu_vendor_id != CPU_VENDOR_INTEL) + return; + + if (resource_disabled("hwpstate_intel", 0)) + return; + /* + * Intel SDM 14.4.1 (HWP Programming Interfaces): + * The CPUID instruction allows software to discover the presence of + * HWP support in an Intel processor. Specifically, execute CPUID + * instruction with EAX=06H as input will return 5 bit flags covering + * the following aspects in bits 7 through 11 of CPUID.06H:EAX. + */ + if (cpu_high < 6) + goto err; + /* + * Intel SDM 14.4.1 (HWP Programming Interfaces): + * Availability of HWP baseline resource and capability, + * CPUID.06H:EAX[bit 7]: If this bit is set, HWP provides several new + * architectural MSRs: IA32_PM_ENABLE, IA32_HWP_CAPABILITIES, + * IA32_HWP_REQUEST, IA32_HWP_STATUS. + */ + do_cpuid(6, regs); + if ((regs[0] & CPUTPM1_HWP) == 0) + goto err; + + if (BUS_ADD_CHILD(parent, 10, "hwpstate_intel", -1) == NULL) + goto err; + + device_printf(parent, "hwpstate registered (0x%x)\n", (regs[0] >> 7) & 0x1f); + return; + +err: + device_printf(parent, "Speed Shift unavailable. Falling back to est\n"); + intel_speed_shift = false; +} + +static int +intel_hwpstate_probe(device_t dev) +{ + device_t perf_dev; + int error, type; + + perf_dev = device_find_child(device_get_parent(dev), "acpi_perf", -1); + if (perf_dev && device_is_attached(perf_dev)) { + error = CPUFREQ_DRV_TYPE(perf_dev, &type); + if (error == 0) { + if ((type & CPUFREQ_FLAG_INFO_ONLY) != 0) { + /* We don't handle collision with acpi_perf */ + device_printf(dev, + "Passive-aggressively avoiding acpi_perf\n"); + return (ENXIO); + } + } + } + + device_set_desc(dev, "Intel Speed Shift"); + return (BUS_PROBE_DEFAULT); +} + + +static void +set_autonomous_hwp(void) +{ + uint64_t caps, req; + + wrmsr_safe(MSR_IA32_PM_ENABLE, 1); + + /* Set up the defaults from SDM 14.4.10 */ + rdmsr_safe(MSR_IA32_HWP_REQUEST, &req); + rdmsr_safe(MSR_IA32_HWP_CAPABILITIES, &caps); + + /* hardware autonomous selection determines the performance target */ + req &= ~IA32_HWP_DESIRED_PERFORMANCE; + + /* enable HW dynamic selection of window size */ + req &= ~IA32_HWP_ACTIVITY_WINDOW; + + /* IA32_HWP_REQUEST.Minimum_Performance = IA32_HWP_CAPABILITIES.Lowest_Performance */ + req |= IA32_HWP_CAPABILITIES_LOWEST_PERFORMANCE(caps); + + /* IA32_HWP_REQUEST.Maximum_Performance = IA32_HWP_CAPABILITIES.Highest_Performance. */ + req |= IA32_HWP_CAPABILITIES_HIGHEST_PERFORMANCE(caps) << 8; + + wrmsr_safe(MSR_IA32_HWP_REQUEST, req); +} + +static int +intel_hwpstate_attach(device_t dev) +{ + struct hwp_softc *sc; + uint32_t regs[4]; + int i; + + KASSERT(device_find_child(device_get_parent(dev), "est", -1) == NULL, + ("EST driver already loaded")); + + sc = device_get_softc(dev); + sc->dev = dev; + + do_cpuid(6, regs); + if (regs[0] & CPUTPM1_HWP_NOTIFICATION) + sc->hwp_notifications = true; + if (regs[0] & CPUTPM1_HWP_ACTIVITY_WINDOW) + sc->hwp_activity_window = true; + if (regs[0] & CPUTPM1_HWP_PERF_PREF) + sc->hwp_pref_ctrl = true; + if (regs[0] & CPUTPM1_HWP_PKG) + sc->hwp_pkg_ctrl = true; + + CPU_FOREACH(i) { + thread_lock(curthread); + sched_bind(curthread, i); + thread_unlock(curthread); + + set_autonomous_hwp(); + + thread_lock(curthread); + sched_unbind(curthread); + thread_unlock(curthread); + } + + return (cpufreq_register(dev)); +} + +static int +intel_hwpstate_detach(device_t dev) +{ + + return (cpufreq_unregister(dev)); +}