The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/x86/cpufreq/hwpstate_intel.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2018 Intel Corporation
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted providing that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
   19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   23  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
   24  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   25  * POSSIBILITY OF SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include <sys/types.h>
   32 #include <sys/sbuf.h>
   33 #include <sys/module.h>
   34 #include <sys/systm.h>
   35 #include <sys/errno.h>
   36 #include <sys/param.h>
   37 #include <sys/kernel.h>
   38 #include <sys/bus.h>
   39 #include <sys/cpu.h>
   40 #include <sys/smp.h>
   41 #include <sys/proc.h>
   42 #include <sys/sched.h>
   43 
   44 #include <machine/cpu.h>
   45 #include <machine/md_var.h>
   46 #include <machine/cputypes.h>
   47 #include <machine/specialreg.h>
   48 
   49 #include <contrib/dev/acpica/include/acpi.h>
   50 
   51 #include <dev/acpica/acpivar.h>
   52 
   53 #include <x86/cpufreq/hwpstate_intel_internal.h>
   54 
   55 #include "acpi_if.h"
   56 #include "cpufreq_if.h"
   57 
   58 extern uint64_t tsc_freq;
   59 
   60 static int      intel_hwpstate_probe(device_t dev);
   61 static int      intel_hwpstate_attach(device_t dev);
   62 static int      intel_hwpstate_detach(device_t dev);
   63 static int      intel_hwpstate_suspend(device_t dev);
   64 static int      intel_hwpstate_resume(device_t dev);
   65 
   66 static int      intel_hwpstate_get(device_t dev, struct cf_setting *cf);
   67 static int      intel_hwpstate_type(device_t dev, int *type);
   68 
   69 static device_method_t intel_hwpstate_methods[] = {
   70         /* Device interface */
   71         DEVMETHOD(device_identify,      intel_hwpstate_identify),
   72         DEVMETHOD(device_probe,         intel_hwpstate_probe),
   73         DEVMETHOD(device_attach,        intel_hwpstate_attach),
   74         DEVMETHOD(device_detach,        intel_hwpstate_detach),
   75         DEVMETHOD(device_suspend,       intel_hwpstate_suspend),
   76         DEVMETHOD(device_resume,        intel_hwpstate_resume),
   77 
   78         /* cpufreq interface */
   79         DEVMETHOD(cpufreq_drv_get,      intel_hwpstate_get),
   80         DEVMETHOD(cpufreq_drv_type,     intel_hwpstate_type),
   81 
   82         DEVMETHOD_END
   83 };
   84 
   85 struct hwp_softc {
   86         device_t                dev;
   87         bool                    hwp_notifications;
   88         bool                    hwp_activity_window;
   89         bool                    hwp_pref_ctrl;
   90         bool                    hwp_pkg_ctrl;
   91         bool                    hwp_pkg_ctrl_en;
   92         bool                    hwp_perf_bias;
   93         bool                    hwp_perf_bias_cached;
   94 
   95         uint64_t                req; /* Cached copy of HWP_REQUEST */
   96         uint64_t                hwp_energy_perf_bias;   /* Cache PERF_BIAS */
   97 
   98         uint8_t                 high;
   99         uint8_t                 guaranteed;
  100         uint8_t                 efficient;
  101         uint8_t                 low;
  102 };
  103 
  104 static devclass_t hwpstate_intel_devclass;
  105 static driver_t hwpstate_intel_driver = {
  106         "hwpstate_intel",
  107         intel_hwpstate_methods,
  108         sizeof(struct hwp_softc),
  109 };
  110 
  111 DRIVER_MODULE(hwpstate_intel, cpu, hwpstate_intel_driver,
  112     hwpstate_intel_devclass, NULL, NULL);
  113 MODULE_VERSION(hwpstate_intel, 1);
  114 
  115 static bool hwpstate_pkg_ctrl_enable = true;
  116 SYSCTL_BOOL(_machdep, OID_AUTO, hwpstate_pkg_ctrl, CTLFLAG_RDTUN,
  117     &hwpstate_pkg_ctrl_enable, 0,
  118     "Set 1 (default) to enable package-level control, 0 to disable");
  119 
  120 static int
  121 intel_hwp_dump_sysctl_handler(SYSCTL_HANDLER_ARGS)
  122 {
  123         device_t dev;
  124         struct pcpu *pc;
  125         struct sbuf *sb;
  126         struct hwp_softc *sc;
  127         uint64_t data, data2;
  128         int ret;
  129 
  130         sc = (struct hwp_softc *)arg1;
  131         dev = sc->dev;
  132 
  133         pc = cpu_get_pcpu(dev);
  134         if (pc == NULL)
  135                 return (ENXIO);
  136 
  137         sb = sbuf_new(NULL, NULL, 1024, SBUF_FIXEDLEN | SBUF_INCLUDENUL);
  138         sbuf_putc(sb, '\n');
  139         thread_lock(curthread);
  140         sched_bind(curthread, pc->pc_cpuid);
  141         thread_unlock(curthread);
  142 
  143         rdmsr_safe(MSR_IA32_PM_ENABLE, &data);
  144         sbuf_printf(sb, "CPU%d: HWP %sabled\n", pc->pc_cpuid,
  145             ((data & 1) ? "En" : "Dis"));
  146 
  147         if (data == 0) {
  148                 ret = 0;
  149                 goto out;
  150         }
  151 
  152         rdmsr_safe(MSR_IA32_HWP_CAPABILITIES, &data);
  153         sbuf_printf(sb, "\tHighest Performance: %03ju\n", data & 0xff);
  154         sbuf_printf(sb, "\tGuaranteed Performance: %03ju\n", (data >> 8) & 0xff);
  155         sbuf_printf(sb, "\tEfficient Performance: %03ju\n", (data >> 16) & 0xff);
  156         sbuf_printf(sb, "\tLowest Performance: %03ju\n", (data >> 24) & 0xff);
  157 
  158         rdmsr_safe(MSR_IA32_HWP_REQUEST, &data);
  159         data2 = 0;
  160         if (sc->hwp_pkg_ctrl && (data & IA32_HWP_REQUEST_PACKAGE_CONTROL))
  161                 rdmsr_safe(MSR_IA32_HWP_REQUEST_PKG, &data2);
  162 
  163         sbuf_putc(sb, '\n');
  164 
  165 #define pkg_print(x, name, offset) do {                                 \
  166         if (!sc->hwp_pkg_ctrl || (data & x) != 0)                       \
  167                 sbuf_printf(sb, "\t%s: %03u\n", name,                   \
  168                     (unsigned)(data >> offset) & 0xff);                 \
  169         else                                                            \
  170                 sbuf_printf(sb, "\t%s: %03u\n", name,                   \
  171                     (unsigned)(data2 >> offset) & 0xff);                \
  172 } while (0)
  173 
  174         pkg_print(IA32_HWP_REQUEST_EPP_VALID,
  175             "Requested Efficiency Performance Preference", 24);
  176         pkg_print(IA32_HWP_REQUEST_DESIRED_VALID,
  177             "Requested Desired Performance", 16);
  178         pkg_print(IA32_HWP_REQUEST_MAXIMUM_VALID,
  179             "Requested Maximum Performance", 8);
  180         pkg_print(IA32_HWP_REQUEST_MINIMUM_VALID,
  181             "Requested Minimum Performance", 0);
  182 #undef pkg_print
  183 
  184         sbuf_putc(sb, '\n');
  185 
  186 out:
  187         thread_lock(curthread);
  188         sched_unbind(curthread);
  189         thread_unlock(curthread);
  190 
  191         ret = sbuf_finish(sb);
  192         if (ret == 0)
  193                 ret = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb));
  194         sbuf_delete(sb);
  195 
  196         return (ret);
  197 }
  198 
  199 static inline int
  200 percent_to_raw(int x)
  201 {
  202 
  203         MPASS(x <= 100 && x >= 0);
  204         return (0xff * x / 100);
  205 }
  206 
  207 /*
  208  * Given x * 10 in [0, 1000], round to the integer nearest x.
  209  *
  210  * This allows round-tripping nice human readable numbers through this
  211  * interface.  Otherwise, user-provided percentages such as 25, 50, 75 get
  212  * rounded down to 24, 49, and 74, which is a bit ugly.
  213  */
  214 static inline int
  215 round10(int xtimes10)
  216 {
  217         return ((xtimes10 + 5) / 10);
  218 }
  219 
  220 static inline int
  221 raw_to_percent(int x)
  222 {
  223         MPASS(x <= 0xff && x >= 0);
  224         return (round10(x * 1000 / 0xff));
  225 }
  226 
  227 /* Range of MSR_IA32_ENERGY_PERF_BIAS is more limited: 0-0xf. */
  228 static inline int
  229 percent_to_raw_perf_bias(int x)
  230 {
  231         /*
  232          * Round up so that raw values present as nice round human numbers and
  233          * also round-trip to the same raw value.
  234          */
  235         MPASS(x <= 100 && x >= 0);
  236         return (((0xf * x) + 50) / 100);
  237 }
  238 
  239 static inline int
  240 raw_to_percent_perf_bias(int x)
  241 {
  242         /* Rounding to nice human numbers despite a step interval of 6.67%. */
  243         MPASS(x <= 0xf && x >= 0);
  244         return (((x * 20) / 0xf) * 5);
  245 }
  246 
  247 static int
  248 sysctl_epp_select(SYSCTL_HANDLER_ARGS)
  249 {
  250         struct hwp_softc *sc;
  251         device_t dev;
  252         struct pcpu *pc;
  253         uint64_t epb;
  254         uint32_t val;
  255         int ret;
  256 
  257         dev = oidp->oid_arg1;
  258         sc = device_get_softc(dev);
  259         if (!sc->hwp_pref_ctrl && !sc->hwp_perf_bias)
  260                 return (ENODEV);
  261 
  262         pc = cpu_get_pcpu(dev);
  263         if (pc == NULL)
  264                 return (ENXIO);
  265 
  266         thread_lock(curthread);
  267         sched_bind(curthread, pc->pc_cpuid);
  268         thread_unlock(curthread);
  269 
  270         if (sc->hwp_pref_ctrl) {
  271                 val = (sc->req & IA32_HWP_REQUEST_ENERGY_PERFORMANCE_PREFERENCE) >> 24;
  272                 val = raw_to_percent(val);
  273         } else {
  274                 /*
  275                  * If cpuid indicates EPP is not supported, the HWP controller
  276                  * uses MSR_IA32_ENERGY_PERF_BIAS instead (Intel SDM §14.4.4).
  277                  * This register is per-core (but not HT).
  278                  */
  279                 if (!sc->hwp_perf_bias_cached) {
  280                         ret = rdmsr_safe(MSR_IA32_ENERGY_PERF_BIAS, &epb);
  281                         if (ret)
  282                                 goto out;
  283                         sc->hwp_energy_perf_bias = epb;
  284                         sc->hwp_perf_bias_cached = true;
  285                 }
  286                 val = sc->hwp_energy_perf_bias &
  287                     IA32_ENERGY_PERF_BIAS_POLICY_HINT_MASK;
  288                 val = raw_to_percent_perf_bias(val);
  289         }
  290 
  291         MPASS(val >= 0 && val <= 100);
  292 
  293         ret = sysctl_handle_int(oidp, &val, 0, req);
  294         if (ret || req->newptr == NULL)
  295                 goto out;
  296 
  297         if (val > 100) {
  298                 ret = EINVAL;
  299                 goto out;
  300         }
  301 
  302         if (sc->hwp_pref_ctrl) {
  303                 val = percent_to_raw(val);
  304 
  305                 sc->req =
  306                     ((sc->req & ~IA32_HWP_REQUEST_ENERGY_PERFORMANCE_PREFERENCE)
  307                     | (val << 24u));
  308 
  309                 if (sc->hwp_pkg_ctrl_en)
  310                         ret = wrmsr_safe(MSR_IA32_HWP_REQUEST_PKG, sc->req);
  311                 else
  312                         ret = wrmsr_safe(MSR_IA32_HWP_REQUEST, sc->req);
  313         } else {
  314                 val = percent_to_raw_perf_bias(val);
  315                 MPASS((val & ~IA32_ENERGY_PERF_BIAS_POLICY_HINT_MASK) == 0);
  316 
  317                 sc->hwp_energy_perf_bias =
  318                     ((sc->hwp_energy_perf_bias &
  319                     ~IA32_ENERGY_PERF_BIAS_POLICY_HINT_MASK) | val);
  320                 ret = wrmsr_safe(MSR_IA32_ENERGY_PERF_BIAS,
  321                     sc->hwp_energy_perf_bias);
  322         }
  323 
  324 out:
  325         thread_lock(curthread);
  326         sched_unbind(curthread);
  327         thread_unlock(curthread);
  328 
  329         return (ret);
  330 }
  331 
  332 void
  333 intel_hwpstate_identify(driver_t *driver, device_t parent)
  334 {
  335         if (device_find_child(parent, "hwpstate_intel", -1) != NULL)
  336                 return;
  337 
  338         if (cpu_vendor_id != CPU_VENDOR_INTEL)
  339                 return;
  340 
  341         if (resource_disabled("hwpstate_intel", 0))
  342                 return;
  343 
  344         /*
  345          * Intel SDM 14.4.1 (HWP Programming Interfaces):
  346          *   Availability of HWP baseline resource and capability,
  347          *   CPUID.06H:EAX[bit 7]: If this bit is set, HWP provides several new
  348          *   architectural MSRs: IA32_PM_ENABLE, IA32_HWP_CAPABILITIES,
  349          *   IA32_HWP_REQUEST, IA32_HWP_STATUS.
  350          */
  351         if ((cpu_power_eax & CPUTPM1_HWP) == 0)
  352                 return;
  353 
  354         if (BUS_ADD_CHILD(parent, 10, "hwpstate_intel", -1) == NULL)
  355                 return;
  356 
  357         if (bootverbose)
  358                 device_printf(parent, "hwpstate registered\n");
  359 }
  360 
  361 static int
  362 intel_hwpstate_probe(device_t dev)
  363 {
  364 
  365         device_set_desc(dev, "Intel Speed Shift");
  366         return (BUS_PROBE_NOWILDCARD);
  367 }
  368 
  369 static int
  370 set_autonomous_hwp(struct hwp_softc *sc)
  371 {
  372         struct pcpu *pc;
  373         device_t dev;
  374         uint64_t caps;
  375         int ret;
  376 
  377         dev = sc->dev;
  378 
  379         pc = cpu_get_pcpu(dev);
  380         if (pc == NULL)
  381                 return (ENXIO);
  382 
  383         thread_lock(curthread);
  384         sched_bind(curthread, pc->pc_cpuid);
  385         thread_unlock(curthread);
  386 
  387         /* XXX: Many MSRs aren't readable until feature is enabled */
  388         ret = wrmsr_safe(MSR_IA32_PM_ENABLE, 1);
  389         if (ret) {
  390                 /*
  391                  * This is actually a package-level MSR, and only the first
  392                  * write is not ignored.  So it is harmless to enable it across
  393                  * all devices, and this allows us not to care especially in
  394                  * which order cores (and packages) are probed.  This error
  395                  * condition should not happen given we gate on the HWP CPUID
  396                  * feature flag, if the Intel SDM is correct.
  397                  */
  398                 device_printf(dev, "Failed to enable HWP for cpu%d (%d)\n",
  399                     pc->pc_cpuid, ret);
  400                 goto out;
  401         }
  402 
  403         ret = rdmsr_safe(MSR_IA32_HWP_REQUEST, &sc->req);
  404         if (ret) {
  405                 device_printf(dev,
  406                     "Failed to read HWP request MSR for cpu%d (%d)\n",
  407                     pc->pc_cpuid, ret);
  408                 goto out;
  409         }
  410 
  411         ret = rdmsr_safe(MSR_IA32_HWP_CAPABILITIES, &caps);
  412         if (ret) {
  413                 device_printf(dev,
  414                     "Failed to read HWP capabilities MSR for cpu%d (%d)\n",
  415                     pc->pc_cpuid, ret);
  416                 goto out;
  417         }
  418 
  419         /*
  420          * High and low are static; "guaranteed" is dynamic; and efficient is
  421          * also dynamic.
  422          */
  423         sc->high = IA32_HWP_CAPABILITIES_HIGHEST_PERFORMANCE(caps);
  424         sc->guaranteed = IA32_HWP_CAPABILITIES_GUARANTEED_PERFORMANCE(caps);
  425         sc->efficient = IA32_HWP_CAPABILITIES_EFFICIENT_PERFORMANCE(caps);
  426         sc->low = IA32_HWP_CAPABILITIES_LOWEST_PERFORMANCE(caps);
  427 
  428         /* hardware autonomous selection determines the performance target */
  429         sc->req &= ~IA32_HWP_DESIRED_PERFORMANCE;
  430 
  431         /* enable HW dynamic selection of window size */
  432         sc->req &= ~IA32_HWP_ACTIVITY_WINDOW;
  433 
  434         /* IA32_HWP_REQUEST.Minimum_Performance = IA32_HWP_CAPABILITIES.Lowest_Performance */
  435         sc->req &= ~IA32_HWP_MINIMUM_PERFORMANCE;
  436         sc->req |= sc->low;
  437 
  438         /* IA32_HWP_REQUEST.Maximum_Performance = IA32_HWP_CAPABILITIES.Highest_Performance. */
  439         sc->req &= ~IA32_HWP_REQUEST_MAXIMUM_PERFORMANCE;
  440         sc->req |= sc->high << 8;
  441 
  442         /* If supported, request package-level control for this CPU. */
  443         if (sc->hwp_pkg_ctrl_en)
  444                 ret = wrmsr_safe(MSR_IA32_HWP_REQUEST, sc->req |
  445                     IA32_HWP_REQUEST_PACKAGE_CONTROL);
  446         else
  447                 ret = wrmsr_safe(MSR_IA32_HWP_REQUEST, sc->req);
  448         if (ret) {
  449                 device_printf(dev,
  450                     "Failed to setup%s autonomous HWP for cpu%d\n",
  451                     sc->hwp_pkg_ctrl_en ? " PKG" : "", pc->pc_cpuid);
  452                 goto out;
  453         }
  454 
  455         /* If supported, write the PKG-wide control MSR. */
  456         if (sc->hwp_pkg_ctrl_en) {
  457                 /*
  458                  * "The structure of the IA32_HWP_REQUEST_PKG MSR
  459                  * (package-level) is identical to the IA32_HWP_REQUEST MSR
  460                  * with the exception of the Package Control field, which does
  461                  * not exist." (Intel SDM §14.4.4)
  462                  */
  463                 ret = wrmsr_safe(MSR_IA32_HWP_REQUEST_PKG, sc->req);
  464                 if (ret) {
  465                         device_printf(dev,
  466                             "Failed to set autonomous HWP for package\n");
  467                 }
  468         }
  469 
  470 out:
  471         thread_lock(curthread);
  472         sched_unbind(curthread);
  473         thread_unlock(curthread);
  474 
  475         return (ret);
  476 }
  477 
  478 static int
  479 intel_hwpstate_attach(device_t dev)
  480 {
  481         struct hwp_softc *sc;
  482         int ret;
  483 
  484         sc = device_get_softc(dev);
  485         sc->dev = dev;
  486 
  487         /* eax */
  488         if (cpu_power_eax & CPUTPM1_HWP_NOTIFICATION)
  489                 sc->hwp_notifications = true;
  490         if (cpu_power_eax & CPUTPM1_HWP_ACTIVITY_WINDOW)
  491                 sc->hwp_activity_window = true;
  492         if (cpu_power_eax & CPUTPM1_HWP_PERF_PREF)
  493                 sc->hwp_pref_ctrl = true;
  494         if (cpu_power_eax & CPUTPM1_HWP_PKG)
  495                 sc->hwp_pkg_ctrl = true;
  496 
  497         /* Allow administrators to disable pkg-level control. */
  498         sc->hwp_pkg_ctrl_en = (sc->hwp_pkg_ctrl && hwpstate_pkg_ctrl_enable);
  499 
  500         /* ecx */
  501         if (cpu_power_ecx & CPUID_PERF_BIAS)
  502                 sc->hwp_perf_bias = true;
  503 
  504         ret = set_autonomous_hwp(sc);
  505         if (ret)
  506                 return (ret);
  507 
  508         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
  509             SYSCTL_STATIC_CHILDREN(_debug), OID_AUTO, device_get_nameunit(dev),
  510             CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_SKIP | CTLFLAG_NEEDGIANT,
  511             sc, 0, intel_hwp_dump_sysctl_handler, "A", "");
  512 
  513         SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
  514             SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
  515             "epp", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, dev, 0,
  516             sysctl_epp_select, "I",
  517             "Efficiency/Performance Preference "
  518             "(range from 0, most performant, through 100, most efficient)");
  519 
  520         return (cpufreq_register(dev));
  521 }
  522 
  523 static int
  524 intel_hwpstate_detach(device_t dev)
  525 {
  526 
  527         return (cpufreq_unregister(dev));
  528 }
  529 
  530 static int
  531 intel_hwpstate_get(device_t dev, struct cf_setting *set)
  532 {
  533         struct pcpu *pc;
  534         uint64_t rate;
  535         int ret;
  536 
  537         if (set == NULL)
  538                 return (EINVAL);
  539 
  540         pc = cpu_get_pcpu(dev);
  541         if (pc == NULL)
  542                 return (ENXIO);
  543 
  544         memset(set, CPUFREQ_VAL_UNKNOWN, sizeof(*set));
  545         set->dev = dev;
  546 
  547         ret = cpu_est_clockrate(pc->pc_cpuid, &rate);
  548         if (ret == 0)
  549                 set->freq = rate / 1000000;
  550 
  551         set->volts = CPUFREQ_VAL_UNKNOWN;
  552         set->power = CPUFREQ_VAL_UNKNOWN;
  553         set->lat = CPUFREQ_VAL_UNKNOWN;
  554 
  555         return (0);
  556 }
  557 
  558 static int
  559 intel_hwpstate_type(device_t dev, int *type)
  560 {
  561         if (type == NULL)
  562                 return (EINVAL);
  563         *type = CPUFREQ_TYPE_ABSOLUTE | CPUFREQ_FLAG_INFO_ONLY | CPUFREQ_FLAG_UNCACHED;
  564 
  565         return (0);
  566 }
  567 
  568 static int
  569 intel_hwpstate_suspend(device_t dev)
  570 {
  571         return (0);
  572 }
  573 
  574 /*
  575  * Redo a subset of set_autonomous_hwp on resume; untested.  Without this,
  576  * testers observed that on resume MSR_IA32_HWP_REQUEST was bogus.
  577  */
  578 static int
  579 intel_hwpstate_resume(device_t dev)
  580 {
  581         struct hwp_softc *sc;
  582         struct pcpu *pc;
  583         int ret;
  584 
  585         sc = device_get_softc(dev);
  586 
  587         pc = cpu_get_pcpu(dev);
  588         if (pc == NULL)
  589                 return (ENXIO);
  590 
  591         thread_lock(curthread);
  592         sched_bind(curthread, pc->pc_cpuid);
  593         thread_unlock(curthread);
  594 
  595         ret = wrmsr_safe(MSR_IA32_PM_ENABLE, 1);
  596         if (ret) {
  597                 device_printf(dev,
  598                     "Failed to enable HWP for cpu%d after suspend (%d)\n",
  599                     pc->pc_cpuid, ret);
  600                 goto out;
  601         }
  602 
  603         if (sc->hwp_pkg_ctrl_en)
  604                 ret = wrmsr_safe(MSR_IA32_HWP_REQUEST, sc->req |
  605                     IA32_HWP_REQUEST_PACKAGE_CONTROL);
  606         else
  607                 ret = wrmsr_safe(MSR_IA32_HWP_REQUEST, sc->req);
  608         if (ret) {
  609                 device_printf(dev,
  610                     "Failed to set%s autonomous HWP for cpu%d after suspend\n",
  611                     sc->hwp_pkg_ctrl_en ? " PKG" : "", pc->pc_cpuid);
  612                 goto out;
  613         }
  614         if (sc->hwp_pkg_ctrl_en) {
  615                 ret = wrmsr_safe(MSR_IA32_HWP_REQUEST_PKG, sc->req);
  616                 if (ret) {
  617                         device_printf(dev,
  618                             "Failed to set autonomous HWP for package after "
  619                             "suspend\n");
  620                         goto out;
  621                 }
  622         }
  623         if (!sc->hwp_pref_ctrl && sc->hwp_perf_bias_cached) {
  624                 ret = wrmsr_safe(MSR_IA32_ENERGY_PERF_BIAS,
  625                     sc->hwp_energy_perf_bias);
  626                 if (ret) {
  627                         device_printf(dev,
  628                             "Failed to set energy perf bias for cpu%d after "
  629                             "suspend\n", pc->pc_cpuid);
  630                 }
  631         }
  632 
  633 out:
  634         thread_lock(curthread);
  635         sched_unbind(curthread);
  636         thread_unlock(curthread);
  637 
  638         return (ret);
  639 }

Cache object: c3d90056359272c29b49cb32cbf0f8c5


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.