diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2017-05-15 21:15:27 -0400 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2017-05-15 21:15:27 -0400 |
| commit | a32f80b30dae067357f96bc2a7f977e8a91b45ed (patch) | |
| tree | 3c06a476a1923683ce97991a0a535315efeddf31 /tools | |
| parent | 2ea659a9ef488125eb46da6eb571de5eae5c43f6 (diff) | |
| parent | 3cedbc5a6d7f7c5539e139f89ec9f6e1ed668418 (diff) | |
Merge branch 'utilities' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux
Pull power management utilities updates from Len Brown.
* 'utilities' of git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux:
intel_pstate: use updated msr-index.h HWP.EPP values
tools/power x86_energy_perf_policy: support HWP.EPP
x86: msr-index.h: fix shifts to ULL results in HWP macros.
x86: msr-index.h: define HWP.EPP values
x86: msr-index.h: define EPB mid-points
Diffstat (limited to 'tools')
3 files changed, 1500 insertions, 272 deletions
diff --git a/tools/power/x86/x86_energy_perf_policy/Makefile b/tools/power/x86/x86_energy_perf_policy/Makefile index 971c9ffdcb50..a711eec0c895 100644 --- a/tools/power/x86/x86_energy_perf_policy/Makefile +++ b/tools/power/x86/x86_energy_perf_policy/Makefile | |||
| @@ -1,10 +1,27 @@ | |||
| 1 | DESTDIR ?= | 1 | CC = $(CROSS_COMPILE)gcc |
| 2 | BUILD_OUTPUT := $(CURDIR) | ||
| 3 | PREFIX := /usr | ||
| 4 | DESTDIR := | ||
| 5 | |||
| 6 | ifeq ("$(origin O)", "command line") | ||
| 7 | BUILD_OUTPUT := $(O) | ||
| 8 | endif | ||
| 2 | 9 | ||
| 3 | x86_energy_perf_policy : x86_energy_perf_policy.c | 10 | x86_energy_perf_policy : x86_energy_perf_policy.c |
| 11 | CFLAGS += -Wall | ||
| 12 | CFLAGS += -DMSRHEADER='"../../../../arch/x86/include/asm/msr-index.h"' | ||
| 13 | |||
| 14 | %: %.c | ||
| 15 | @mkdir -p $(BUILD_OUTPUT) | ||
| 16 | $(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@ | ||
| 4 | 17 | ||
| 18 | .PHONY : clean | ||
| 5 | clean : | 19 | clean : |
| 6 | rm -f x86_energy_perf_policy | 20 | @rm -f $(BUILD_OUTPUT)/x86_energy_perf_policy |
| 21 | |||
| 22 | install : x86_energy_perf_policy | ||
| 23 | install -d $(DESTDIR)$(PREFIX)/bin | ||
| 24 | install $(BUILD_OUTPUT)/x86_energy_perf_policy $(DESTDIR)$(PREFIX)/bin/x86_energy_perf_policy | ||
| 25 | install -d $(DESTDIR)$(PREFIX)/share/man/man8 | ||
| 26 | install x86_energy_perf_policy.8 $(DESTDIR)$(PREFIX)/share/man/man8 | ||
| 7 | 27 | ||
| 8 | install : | ||
| 9 | install x86_energy_perf_policy ${DESTDIR}/usr/bin/ | ||
| 10 | install x86_energy_perf_policy.8 ${DESTDIR}/usr/share/man/man8/ | ||
diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 index 8eaaad648cdb..17db1c3af4d0 100644 --- a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 +++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 | |||
| @@ -1,104 +1,213 @@ | |||
| 1 | .\" This page Copyright (C) 2010 Len Brown <len.brown@intel.com> | 1 | .\" This page Copyright (C) 2010 - 2015 Len Brown <len.brown@intel.com> |
| 2 | .\" Distributed under the GPL, Copyleft 1994. | 2 | .\" Distributed under the GPL, Copyleft 1994. |
| 3 | .TH X86_ENERGY_PERF_POLICY 8 | 3 | .TH X86_ENERGY_PERF_POLICY 8 |
| 4 | .SH NAME | 4 | .SH NAME |
| 5 | x86_energy_perf_policy \- read or write MSR_IA32_ENERGY_PERF_BIAS | 5 | x86_energy_perf_policy \- Manage Energy vs. Performance Policy via x86 Model Specific Registers |
| 6 | .SH SYNOPSIS | 6 | .SH SYNOPSIS |
| 7 | .ft B | ||
| 8 | .B x86_energy_perf_policy | 7 | .B x86_energy_perf_policy |
| 9 | .RB [ "\-c cpu" ] | 8 | .RB "[ options ] [ scope ] [field \ value]" |
| 10 | .RB [ "\-v" ] | ||
| 11 | .RB "\-r" | ||
| 12 | .br | 9 | .br |
| 13 | .B x86_energy_perf_policy | 10 | .RB "scope: \-\-cpu\ cpu-list | \-\-pkg\ pkg-list" |
| 14 | .RB [ "\-c cpu" ] | ||
| 15 | .RB [ "\-v" ] | ||
| 16 | .RB 'performance' | ||
| 17 | .br | 11 | .br |
| 18 | .B x86_energy_perf_policy | 12 | .RB "cpu-list, pkg-list: # | #,# | #-# | all" |
| 19 | .RB [ "\-c cpu" ] | ||
| 20 | .RB [ "\-v" ] | ||
| 21 | .RB 'normal' | ||
| 22 | .br | 13 | .br |
| 23 | .B x86_energy_perf_policy | 14 | .RB "field: \-\-all | \-\-epb | \-\-hwp-epp | \-\-hwp-min | \-\-hwp-max | \-\-hwp-desired" |
| 24 | .RB [ "\-c cpu" ] | ||
| 25 | .RB [ "\-v" ] | ||
| 26 | .RB 'powersave' | ||
| 27 | .br | 15 | .br |
| 28 | .B x86_energy_perf_policy | 16 | .RB "other: (\-\-force | \-\-hwp-enable | \-\-turbo-enable) value)" |
| 29 | .RB [ "\-c cpu" ] | ||
| 30 | .RB [ "\-v" ] | ||
| 31 | .RB n | ||
| 32 | .br | 17 | .br |
| 18 | .RB "value: # | default | performance | balance-performance | balance-power | power" | ||
| 33 | .SH DESCRIPTION | 19 | .SH DESCRIPTION |
| 34 | \fBx86_energy_perf_policy\fP | 20 | \fBx86_energy_perf_policy\fP |
| 35 | allows software to convey | 21 | displays and updates energy-performance policy settings specific to |
| 36 | its policy for the relative importance of performance | 22 | Intel Architecture Processors. Settings are accessed via Model Specific Register (MSR) |
| 37 | versus energy savings to the processor. | 23 | updates, no matter if the Linux cpufreq sub-system is enabled or not. |
| 38 | 24 | ||
| 39 | The processor uses this information in model-specific ways | 25 | Policy in MSR_IA32_ENERGY_PERF_BIAS (EPB) |
| 40 | when it must select trade-offs between performance and | 26 | may affect a wide range of hardware decisions, |
| 41 | energy efficiency. | 27 | such as how aggressively the hardware enters and exits CPU idle states (C-states) |
| 28 | and Processor Performance States (P-states). | ||
| 29 | This policy hint does not replace explicit OS C-state and P-state selection. | ||
| 30 | Rather, it tells the hardware how aggressively to implement those selections. | ||
| 31 | Further, it allows the OS to influence energy/performance trade-offs where there | ||
| 32 | is no software interface, such as in the opportunistic "turbo-mode" P-state range. | ||
| 33 | Note that MSR_IA32_ENERGY_PERF_BIAS is defined per CPU, | ||
| 34 | but some implementations | ||
| 35 | share a single MSR among all CPUs in each processor package. | ||
| 36 | On those systems, a write to EPB on one processor will | ||
| 37 | be visible, and will have an effect, on all CPUs | ||
| 38 | in the same processor package. | ||
| 42 | 39 | ||
| 43 | This policy hint does not supersede Processor Performance states | 40 | Hardware P-States (HWP) are effectively an expansion of hardware |
| 44 | (P-states) or CPU Idle power states (C-states), but allows | 41 | P-state control from the opportunistic turbo-mode P-state range |
| 45 | software to have influence where it would otherwise be unable | 42 | to include the entire range of available P-states. |
| 46 | to express a preference. | 43 | On Broadwell Xeon, the initial HWP implementation, EBP influenced HWP. |
| 44 | That influence was removed in subsequent generations, | ||
| 45 | where it was moved to the | ||
| 46 | Energy_Performance_Preference (EPP) field in | ||
| 47 | a pair of dedicated MSRs -- MSR_IA32_HWP_REQUEST and MSR_IA32_HWP_REQUEST_PKG. | ||
| 47 | 48 | ||
| 48 | For example, this setting may tell the hardware how | 49 | EPP is the most commonly managed knob in HWP mode, |
| 49 | aggressively or conservatively to control frequency | 50 | but MSR_IA32_HWP_REQUEST also allows the user to specify |
| 50 | in the "turbo range" above the explicitly OS-controlled | 51 | minimum-frequency for Quality-of-Service, |
| 51 | P-state frequency range. It may also tell the hardware | 52 | and maximum-frequency for power-capping. |
| 52 | how aggressively is should enter the OS requested C-states. | 53 | MSR_IA32_HWP_REQUEST is defined per-CPU. |
| 53 | 54 | ||
| 54 | Support for this feature is indicated by CPUID.06H.ECX.bit3 | 55 | MSR_IA32_HWP_REQUEST_PKG has the same capability as MSR_IA32_HWP_REQUEST, |
| 55 | per the Intel Architectures Software Developer's Manual. | 56 | but it can simultaneously set the default policy for all CPUs within a package. |
| 57 | A bit in per-CPU MSR_IA32_HWP_REQUEST indicates whether it is | ||
| 58 | over-ruled-by or exempt-from MSR_IA32_HWP_REQUEST_PKG. | ||
| 56 | 59 | ||
| 57 | .SS Options | 60 | MSR_HWP_CAPABILITIES shows the default values for the fields |
| 58 | \fB-c\fP limits operation to a single CPU. | 61 | in MSR_IA32_HWP_REQUEST. It is displayed when no values |
| 59 | The default is to operate on all CPUs. | 62 | are being written. |
| 60 | Note that MSR_IA32_ENERGY_PERF_BIAS is defined per | 63 | |
| 61 | logical processor, but that the initial implementations | 64 | .SS SCOPE OPTIONS |
| 62 | of the MSR were shared among all processors in each package. | ||
| 63 | .PP | ||
| 64 | \fB-v\fP increases verbosity. By default | ||
| 65 | x86_energy_perf_policy is silent. | ||
| 66 | .PP | ||
| 67 | \fB-r\fP is for "read-only" mode - the unchanged state | ||
| 68 | is read and displayed. | ||
| 69 | .PP | 65 | .PP |
| 70 | .I performance | 66 | \fB-c, --cpu\fP Operate on the MSR_IA32_HWP_REQUEST for each CPU in a CPU-list. |
| 71 | Set a policy where performance is paramount. | 67 | The CPU-list may be comma-separated CPU numbers, with dash for range |
| 72 | The processor will be unwilling to sacrifice any performance | 68 | or the string "all". Eg. '--cpu 1,4,6-8' or '--cpu all'. |
| 73 | for the sake of energy saving. This is the hardware default. | 69 | When --cpu is used, \fB--hwp-use-pkg\fP is available, which specifies whether the per-cpu |
| 70 | MSR_IA32_HWP_REQUEST should be over-ruled by MSR_IA32_HWP_REQUEST_PKG (1), | ||
| 71 | or exempt from MSR_IA32_HWP_REQUEST_PKG (0). | ||
| 72 | |||
| 73 | \fB-p, --pkg\fP Operate on the MSR_IA32_HWP_REQUEST_PKG for each package in the package-list. | ||
| 74 | The list is a string of individual package numbers separated | ||
| 75 | by commas, and or ranges of package numbers separated by a dash, | ||
| 76 | or the string "all". | ||
| 77 | For example '--pkg 1,3' or '--pkg all' | ||
| 78 | |||
| 79 | .SS VALUE OPTIONS | ||
| 74 | .PP | 80 | .PP |
| 75 | .I normal | 81 | .I normal | default |
| 76 | Set a policy with a normal balance between performance and energy efficiency. | 82 | Set a policy with a normal balance between performance and energy efficiency. |
| 77 | The processor will tolerate minor performance compromise | 83 | The processor will tolerate minor performance compromise |
| 78 | for potentially significant energy savings. | 84 | for potentially significant energy savings. |
| 79 | This reasonable default for most desktops and servers. | 85 | This is a reasonable default for most desktops and servers. |
| 86 | "default" is a synonym for "normal". | ||
| 80 | .PP | 87 | .PP |
| 81 | .I powersave | 88 | .I performance |
| 89 | Set a policy for maximum performance, | ||
| 90 | accepting no performance sacrifice for the benefit of energy efficiency. | ||
| 91 | .PP | ||
| 92 | .I balance-performance | ||
| 93 | Set a policy with a high priority on performance, | ||
| 94 | but allowing some performance loss to benefit energy efficiency. | ||
| 95 | .PP | ||
| 96 | .I balance-power | ||
| 97 | Set a policy where the performance and power are balanced. | ||
| 98 | This is the default. | ||
| 99 | .PP | ||
| 100 | .I power | ||
| 82 | Set a policy where the processor can accept | 101 | Set a policy where the processor can accept |
| 83 | a measurable performance hit to maximize energy efficiency. | 102 | a measurable performance impact to maximize energy efficiency. |
| 103 | |||
| 84 | .PP | 104 | .PP |
| 85 | .I n | 105 | The following table shows the mapping from the value strings above to actual MSR values. |
| 86 | Set MSR_IA32_ENERGY_PERF_BIAS to the specified number. | 106 | This mapping is defined in the Linux-kernel header, msr-index.h. |
| 87 | The range of valid numbers is 0-15, where 0 is maximum | ||
| 88 | performance and 15 is maximum energy efficiency. | ||
| 89 | 107 | ||
| 108 | .nf | ||
| 109 | VALUE STRING EPB EPP | ||
| 110 | performance 0 0 | ||
| 111 | balance-performance 4 128 | ||
| 112 | normal, default 6 128 | ||
| 113 | balance-power 8 192 | ||
| 114 | power 15 255 | ||
| 115 | .fi | ||
| 116 | .PP | ||
| 117 | For MSR_IA32_HWP_REQUEST performance fields | ||
| 118 | (--hwp-min, --hwp-max, --hwp-desired), the value option | ||
| 119 | is in units of 100 MHz, Eg. 12 signifies 1200 MHz. | ||
| 120 | |||
| 121 | .SS FIELD OPTIONS | ||
| 122 | \fB-a, --all value-string\fP Sets all EPB and EPP and HWP limit fields to the value associated with | ||
| 123 | the value-string. In addition, enables turbo-mode and HWP-mode, if they were previous disabled. | ||
| 124 | Thus "--all normal" will set a system without cpufreq into a well known configuration. | ||
| 125 | .PP | ||
| 126 | \fB-B, --epb\fP set EPB per-core or per-package. | ||
| 127 | See value strings in the table above. | ||
| 128 | .PP | ||
| 129 | \fB-d, --debug\fP debug increases verbosity. By default | ||
| 130 | x86_energy_perf_policy is silent for updates, | ||
| 131 | and verbose for read-only mode. | ||
| 132 | .PP | ||
| 133 | \fB-P, --hwp-epp\fP set HWP.EPP per-core or per-package. | ||
| 134 | See value strings in the table above. | ||
| 135 | .PP | ||
| 136 | \fB-m, --hwp-min\fP request HWP to not go below the specified core/bus ratio. | ||
| 137 | The "default" is the value found in IA32_HWP_CAPABILITIES.min. | ||
| 138 | .PP | ||
| 139 | \fB-M, --hwp-max\fP request HWP not exceed a the specified core/bus ratio. | ||
| 140 | The "default" is the value found in IA32_HWP_CAPABILITIES.max. | ||
| 141 | .PP | ||
| 142 | \fB-D, --hwp-desired\fP request HWP 'desired' frequency. | ||
| 143 | The "normal" setting is 0, which | ||
| 144 | corresponds to 'full autonomous' HWP control. | ||
| 145 | Non-zero performance values request a specific performance | ||
| 146 | level on this processor, specified in multiples of 100 MHz. | ||
| 147 | .PP | ||
| 148 | \fB-w, --hwp-window\fP specify integer number of microsec | ||
| 149 | in the sliding window that HWP uses to maintain average frequency. | ||
| 150 | This parameter is meaningful only when the "desired" field above is non-zero. | ||
| 151 | Default is 0, allowing the HW to choose. | ||
| 152 | .SH OTHER OPTIONS | ||
| 153 | .PP | ||
| 154 | \fB-f, --force\fP writes the specified values without bounds checking. | ||
| 155 | .PP | ||
| 156 | \fB-U, --hwp-use-pkg\fP (0 | 1), when used in conjunction with --cpu, | ||
| 157 | indicates whether the per-CPU MSR_IA32_HWP_REQUEST should be overruled (1) | ||
| 158 | or exempt (0) from per-Package MSR_IA32_HWP_REQUEST_PKG settings. | ||
| 159 | The default is exempt. | ||
| 160 | .PP | ||
| 161 | \fB-H, --hwp-enable\fP enable HardWare-P-state (HWP) mode. Once enabled, system RESET is required to disable HWP mode. | ||
| 162 | .PP | ||
| 163 | \fB-t, --turbo-enable\fP enable (1) or disable (0) turbo mode. | ||
| 164 | .PP | ||
| 165 | \fB-v, --version\fP print version and exit. | ||
| 166 | .PP | ||
| 167 | If no request to change policy is made, | ||
| 168 | the default behavior is to read | ||
| 169 | and display the current system state, | ||
| 170 | including the default capabilities. | ||
| 171 | .SH WARNING | ||
| 172 | .PP | ||
| 173 | This utility writes directly to Model Specific Registers. | ||
| 174 | There is no locking or coordination should this utility | ||
| 175 | be used to modify HWP limit fields at the same time that | ||
| 176 | intel_pstate's sysfs attributes access the same MSRs. | ||
| 177 | .PP | ||
| 178 | Note that --hwp-desired and --hwp-window are considered experimental. | ||
| 179 | Future versions of Linux reserve the right to access these | ||
| 180 | fields internally -- potentially conflicting with user-space access. | ||
| 181 | .SH EXAMPLE | ||
| 182 | .nf | ||
| 183 | # sudo x86_energy_perf_policy | ||
| 184 | cpu0: EPB 6 | ||
| 185 | cpu0: HWP_REQ: min 6 max 35 des 0 epp 128 window 0x0 (0*10^0us) use_pkg 0 | ||
| 186 | cpu0: HWP_CAP: low 1 eff 8 guar 27 high 35 | ||
| 187 | cpu1: EPB 6 | ||
| 188 | cpu1: HWP_REQ: min 6 max 35 des 0 epp 128 window 0x0 (0*10^0us) use_pkg 0 | ||
| 189 | cpu1: HWP_CAP: low 1 eff 8 guar 27 high 35 | ||
| 190 | cpu2: EPB 6 | ||
| 191 | cpu2: HWP_REQ: min 6 max 35 des 0 epp 128 window 0x0 (0*10^0us) use_pkg 0 | ||
| 192 | cpu2: HWP_CAP: low 1 eff 8 guar 27 high 35 | ||
| 193 | cpu3: EPB 6 | ||
| 194 | cpu3: HWP_REQ: min 6 max 35 des 0 epp 128 window 0x0 (0*10^0us) use_pkg 0 | ||
| 195 | cpu3: HWP_CAP: low 1 eff 8 guar 27 high 35 | ||
| 196 | .fi | ||
| 90 | .SH NOTES | 197 | .SH NOTES |
| 91 | .B "x86_energy_perf_policy " | 198 | .B "x86_energy_perf_policy" |
| 92 | runs only as root. | 199 | runs only as root. |
| 93 | .SH FILES | 200 | .SH FILES |
| 94 | .ta | 201 | .ta |
| 95 | .nf | 202 | .nf |
| 96 | /dev/cpu/*/msr | 203 | /dev/cpu/*/msr |
| 97 | .fi | 204 | .fi |
| 98 | |||
| 99 | .SH "SEE ALSO" | 205 | .SH "SEE ALSO" |
| 206 | .nf | ||
| 100 | msr(4) | 207 | msr(4) |
| 208 | Intel(R) 64 and IA-32 Architectures Software Developer's Manual | ||
| 209 | .fi | ||
| 101 | .PP | 210 | .PP |
| 102 | .SH AUTHORS | 211 | .SH AUTHORS |
| 103 | .nf | 212 | .nf |
| 104 | Written by Len Brown <len.brown@intel.com> | 213 | Len Brown |
diff --git a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c index 40b3e5482f8a..65bbe627a425 100644 --- a/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c +++ b/tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c | |||
| @@ -3,322 +3,1424 @@ | |||
| 3 | * policy preference bias on recent X86 processors. | 3 | * policy preference bias on recent X86 processors. |
| 4 | */ | 4 | */ |
| 5 | /* | 5 | /* |
| 6 | * Copyright (c) 2010, Intel Corporation. | 6 | * Copyright (c) 2010 - 2017 Intel Corporation. |
| 7 | * Len Brown <len.brown@intel.com> | 7 | * Len Brown <len.brown@intel.com> |
| 8 | * | 8 | * |
| 9 | * This program is free software; you can redistribute it and/or modify it | 9 | * This program is released under GPL v2 |
| 10 | * under the terms and conditions of the GNU General Public License, | ||
| 11 | * version 2, as published by the Free Software Foundation. | ||
| 12 | * | ||
| 13 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 14 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 15 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 16 | * more details. | ||
| 17 | * | ||
| 18 | * You should have received a copy of the GNU General Public License along with | ||
| 19 | * this program; if not, write to the Free Software Foundation, Inc., | ||
| 20 | * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
| 21 | */ | 10 | */ |
| 22 | 11 | ||
| 12 | #define _GNU_SOURCE | ||
| 13 | #include MSRHEADER | ||
| 23 | #include <stdio.h> | 14 | #include <stdio.h> |
| 24 | #include <unistd.h> | 15 | #include <unistd.h> |
| 25 | #include <sys/types.h> | 16 | #include <sys/types.h> |
| 17 | #include <sched.h> | ||
| 26 | #include <sys/stat.h> | 18 | #include <sys/stat.h> |
| 27 | #include <sys/resource.h> | 19 | #include <sys/resource.h> |
| 20 | #include <getopt.h> | ||
| 21 | #include <err.h> | ||
| 28 | #include <fcntl.h> | 22 | #include <fcntl.h> |
| 29 | #include <signal.h> | 23 | #include <signal.h> |
| 30 | #include <sys/time.h> | 24 | #include <sys/time.h> |
| 25 | #include <limits.h> | ||
| 31 | #include <stdlib.h> | 26 | #include <stdlib.h> |
| 32 | #include <string.h> | 27 | #include <string.h> |
| 28 | #include <cpuid.h> | ||
| 29 | #include <errno.h> | ||
| 30 | |||
| 31 | #define OPTARG_NORMAL (INT_MAX - 1) | ||
| 32 | #define OPTARG_POWER (INT_MAX - 2) | ||
| 33 | #define OPTARG_BALANCE_POWER (INT_MAX - 3) | ||
| 34 | #define OPTARG_BALANCE_PERFORMANCE (INT_MAX - 4) | ||
| 35 | #define OPTARG_PERFORMANCE (INT_MAX - 5) | ||
| 36 | |||
| 37 | struct msr_hwp_cap { | ||
| 38 | unsigned char highest; | ||
| 39 | unsigned char guaranteed; | ||
| 40 | unsigned char efficient; | ||
| 41 | unsigned char lowest; | ||
| 42 | }; | ||
| 33 | 43 | ||
| 34 | unsigned int verbose; /* set with -v */ | 44 | struct msr_hwp_request { |
| 35 | unsigned int read_only; /* set with -r */ | 45 | unsigned char hwp_min; |
| 46 | unsigned char hwp_max; | ||
| 47 | unsigned char hwp_desired; | ||
| 48 | unsigned char hwp_epp; | ||
| 49 | unsigned int hwp_window; | ||
| 50 | unsigned char hwp_use_pkg; | ||
| 51 | } req_update; | ||
| 52 | |||
| 53 | unsigned int debug; | ||
| 54 | unsigned int verbose; | ||
| 55 | unsigned int force; | ||
| 36 | char *progname; | 56 | char *progname; |
| 37 | unsigned long long new_bias; | 57 | int base_cpu; |
| 38 | int cpu = -1; | 58 | unsigned char update_epb; |
| 59 | unsigned long long new_epb; | ||
| 60 | unsigned char turbo_is_enabled; | ||
| 61 | unsigned char update_turbo; | ||
| 62 | unsigned char turbo_update_value; | ||
| 63 | unsigned char update_hwp_epp; | ||
| 64 | unsigned char update_hwp_min; | ||
| 65 | unsigned char update_hwp_max; | ||
| 66 | unsigned char update_hwp_desired; | ||
| 67 | unsigned char update_hwp_window; | ||
| 68 | unsigned char update_hwp_use_pkg; | ||
| 69 | unsigned char update_hwp_enable; | ||
| 70 | #define hwp_update_enabled() (update_hwp_enable | update_hwp_epp | update_hwp_max | update_hwp_min | update_hwp_desired | update_hwp_window | update_hwp_use_pkg) | ||
| 71 | int max_cpu_num; | ||
| 72 | int max_pkg_num; | ||
| 73 | #define MAX_PACKAGES 64 | ||
| 74 | unsigned int first_cpu_in_pkg[MAX_PACKAGES]; | ||
| 75 | unsigned long long pkg_present_set; | ||
| 76 | unsigned long long pkg_selected_set; | ||
| 77 | cpu_set_t *cpu_present_set; | ||
| 78 | cpu_set_t *cpu_selected_set; | ||
| 79 | int genuine_intel; | ||
| 80 | |||
| 81 | size_t cpu_setsize; | ||
| 82 | |||
| 83 | char *proc_stat = "/proc/stat"; | ||
| 84 | |||
| 85 | unsigned int has_epb; /* MSR_IA32_ENERGY_PERF_BIAS */ | ||
| 86 | unsigned int has_hwp; /* IA32_PM_ENABLE, IA32_HWP_CAPABILITIES */ | ||
| 87 | /* IA32_HWP_REQUEST, IA32_HWP_STATUS */ | ||
| 88 | unsigned int has_hwp_notify; /* IA32_HWP_INTERRUPT */ | ||
| 89 | unsigned int has_hwp_activity_window; /* IA32_HWP_REQUEST[bits 41:32] */ | ||
| 90 | unsigned int has_hwp_epp; /* IA32_HWP_REQUEST[bits 31:24] */ | ||
| 91 | unsigned int has_hwp_request_pkg; /* IA32_HWP_REQUEST_PKG */ | ||
| 92 | |||
| 93 | unsigned int bdx_highest_ratio; | ||
| 39 | 94 | ||
| 40 | /* | 95 | /* |
| 41 | * Usage: | 96 | * maintain compatibility with original implementation, but don't document it: |
| 42 | * | ||
| 43 | * -c cpu: limit action to a single CPU (default is all CPUs) | ||
| 44 | * -v: verbose output (can invoke more than once) | ||
| 45 | * -r: read-only, don't change any settings | ||
| 46 | * | ||
| 47 | * performance | ||
| 48 | * Performance is paramount. | ||
| 49 | * Unwilling to sacrifice any performance | ||
| 50 | * for the sake of energy saving. (hardware default) | ||
| 51 | * | ||
| 52 | * normal | ||
| 53 | * Can tolerate minor performance compromise | ||
| 54 | * for potentially significant energy savings. | ||
| 55 | * (reasonable default for most desktops and servers) | ||
| 56 | * | ||
| 57 | * powersave | ||
| 58 | * Can tolerate significant performance hit | ||
| 59 | * to maximize energy savings. | ||
| 60 | * | ||
| 61 | * n | ||
| 62 | * a numerical value to write to the underlying MSR. | ||
| 63 | */ | 97 | */ |
| 64 | void usage(void) | 98 | void usage(void) |
| 65 | { | 99 | { |
| 66 | printf("%s: [-c cpu] [-v] " | 100 | fprintf(stderr, "%s [options] [scope][field value]\n", progname); |
| 67 | "(-r | 'performance' | 'normal' | 'powersave' | n)\n", | 101 | fprintf(stderr, "scope: --cpu cpu-list [--hwp-use-pkg #] | --pkg pkg-list\n"); |
| 68 | progname); | 102 | fprintf(stderr, "field: --all | --epb | --hwp-epp | --hwp-min | --hwp-max | --hwp-desired\n"); |
| 103 | fprintf(stderr, "other: --hwp-enable | --turbo-enable (0 | 1) | --help | --force\n"); | ||
| 104 | fprintf(stderr, | ||
| 105 | "value: ( # | \"normal\" | \"performance\" | \"balance-performance\" | \"balance-power\"| \"power\")\n"); | ||
| 106 | fprintf(stderr, "--hwp-window usec\n"); | ||
| 107 | |||
| 108 | fprintf(stderr, "Specify only Energy Performance BIAS (legacy usage):\n"); | ||
| 109 | fprintf(stderr, "%s: [-c cpu] [-v] (-r | policy-value )\n", progname); | ||
| 110 | |||
| 69 | exit(1); | 111 | exit(1); |
| 70 | } | 112 | } |
| 71 | 113 | ||
| 72 | #define MSR_IA32_ENERGY_PERF_BIAS 0x000001b0 | 114 | /* |
| 115 | * If bdx_highest_ratio is set, | ||
| 116 | * then we must translate between MSR format and simple ratio | ||
| 117 | * used on the cmdline. | ||
| 118 | */ | ||
| 119 | int ratio_2_msr_perf(int ratio) | ||
| 120 | { | ||
| 121 | int msr_perf; | ||
| 122 | |||
| 123 | if (!bdx_highest_ratio) | ||
| 124 | return ratio; | ||
| 125 | |||
| 126 | msr_perf = ratio * 255 / bdx_highest_ratio; | ||
| 127 | |||
| 128 | if (debug) | ||
| 129 | fprintf(stderr, "%d = ratio_to_msr_perf(%d)\n", msr_perf, ratio); | ||
| 130 | |||
| 131 | return msr_perf; | ||
| 132 | } | ||
| 133 | int msr_perf_2_ratio(int msr_perf) | ||
| 134 | { | ||
| 135 | int ratio; | ||
| 136 | double d; | ||
| 137 | |||
| 138 | if (!bdx_highest_ratio) | ||
| 139 | return msr_perf; | ||
| 140 | |||
| 141 | d = (double)msr_perf * (double) bdx_highest_ratio / 255.0; | ||
| 142 | d = d + 0.5; /* round */ | ||
| 143 | ratio = (int)d; | ||
| 144 | |||
| 145 | if (debug) | ||
| 146 | fprintf(stderr, "%d = msr_perf_ratio(%d) {%f}\n", ratio, msr_perf, d); | ||
| 147 | |||
| 148 | return ratio; | ||
| 149 | } | ||
| 150 | int parse_cmdline_epb(int i) | ||
| 151 | { | ||
| 152 | if (!has_epb) | ||
| 153 | errx(1, "EPB not enabled on this platform"); | ||
| 154 | |||
| 155 | update_epb = 1; | ||
| 156 | |||
| 157 | switch (i) { | ||
| 158 | case OPTARG_POWER: | ||
| 159 | return ENERGY_PERF_BIAS_POWERSAVE; | ||
| 160 | case OPTARG_BALANCE_POWER: | ||
| 161 | return ENERGY_PERF_BIAS_BALANCE_POWERSAVE; | ||
| 162 | case OPTARG_NORMAL: | ||
| 163 | return ENERGY_PERF_BIAS_NORMAL; | ||
| 164 | case OPTARG_BALANCE_PERFORMANCE: | ||
| 165 | return ENERGY_PERF_BIAS_BALANCE_PERFORMANCE; | ||
| 166 | case OPTARG_PERFORMANCE: | ||
| 167 | return ENERGY_PERF_BIAS_PERFORMANCE; | ||
| 168 | } | ||
| 169 | if (i < 0 || i > ENERGY_PERF_BIAS_POWERSAVE) | ||
| 170 | errx(1, "--epb must be from 0 to 15"); | ||
| 171 | return i; | ||
| 172 | } | ||
| 173 | |||
| 174 | #define HWP_CAP_LOWEST 0 | ||
| 175 | #define HWP_CAP_HIGHEST 255 | ||
| 176 | |||
| 177 | /* | ||
| 178 | * "performance" changes hwp_min to cap.highest | ||
| 179 | * All others leave it at cap.lowest | ||
| 180 | */ | ||
| 181 | int parse_cmdline_hwp_min(int i) | ||
| 182 | { | ||
| 183 | update_hwp_min = 1; | ||
| 184 | |||
| 185 | switch (i) { | ||
| 186 | case OPTARG_POWER: | ||
| 187 | case OPTARG_BALANCE_POWER: | ||
| 188 | case OPTARG_NORMAL: | ||
| 189 | case OPTARG_BALANCE_PERFORMANCE: | ||
| 190 | return HWP_CAP_LOWEST; | ||
| 191 | case OPTARG_PERFORMANCE: | ||
| 192 | return HWP_CAP_HIGHEST; | ||
| 193 | } | ||
| 194 | return i; | ||
| 195 | } | ||
| 196 | /* | ||
| 197 | * "power" changes hwp_max to cap.lowest | ||
| 198 | * All others leave it at cap.highest | ||
| 199 | */ | ||
| 200 | int parse_cmdline_hwp_max(int i) | ||
| 201 | { | ||
| 202 | update_hwp_max = 1; | ||
| 203 | |||
| 204 | switch (i) { | ||
| 205 | case OPTARG_POWER: | ||
| 206 | return HWP_CAP_LOWEST; | ||
| 207 | case OPTARG_NORMAL: | ||
| 208 | case OPTARG_BALANCE_POWER: | ||
| 209 | case OPTARG_BALANCE_PERFORMANCE: | ||
| 210 | case OPTARG_PERFORMANCE: | ||
| 211 | return HWP_CAP_HIGHEST; | ||
| 212 | } | ||
| 213 | return i; | ||
| 214 | } | ||
| 215 | /* | ||
| 216 | * for --hwp-des, all strings leave it in autonomous mode | ||
| 217 | * If you want to change it, you need to explicitly pick a value | ||
| 218 | */ | ||
| 219 | int parse_cmdline_hwp_desired(int i) | ||
| 220 | { | ||
| 221 | update_hwp_desired = 1; | ||
| 222 | |||
| 223 | switch (i) { | ||
| 224 | case OPTARG_POWER: | ||
| 225 | case OPTARG_BALANCE_POWER: | ||
| 226 | case OPTARG_BALANCE_PERFORMANCE: | ||
| 227 | case OPTARG_NORMAL: | ||
| 228 | case OPTARG_PERFORMANCE: | ||
| 229 | return 0; /* autonomous */ | ||
| 230 | } | ||
| 231 | return i; | ||
| 232 | } | ||
| 233 | |||
| 234 | int parse_cmdline_hwp_window(int i) | ||
| 235 | { | ||
| 236 | unsigned int exponent; | ||
| 237 | |||
| 238 | update_hwp_window = 1; | ||
| 239 | |||
| 240 | switch (i) { | ||
| 241 | case OPTARG_POWER: | ||
| 242 | case OPTARG_BALANCE_POWER: | ||
| 243 | case OPTARG_NORMAL: | ||
| 244 | case OPTARG_BALANCE_PERFORMANCE: | ||
| 245 | case OPTARG_PERFORMANCE: | ||
| 246 | return 0; | ||
| 247 | } | ||
| 248 | if (i < 0 || i > 1270000000) { | ||
| 249 | fprintf(stderr, "--hwp-window: 0 for auto; 1 - 1270000000 usec for window duration\n"); | ||
| 250 | usage(); | ||
| 251 | } | ||
| 252 | for (exponent = 0; ; ++exponent) { | ||
| 253 | if (debug) | ||
| 254 | printf("%d 10^%d\n", i, exponent); | ||
| 255 | |||
| 256 | if (i <= 127) | ||
| 257 | break; | ||
| 258 | |||
| 259 | i = i / 10; | ||
| 260 | } | ||
| 261 | if (debug) | ||
| 262 | fprintf(stderr, "%d*10^%d: 0x%x\n", i, exponent, (exponent << 7) | i); | ||
| 263 | |||
| 264 | return (exponent << 7) | i; | ||
| 265 | } | ||
| 266 | int parse_cmdline_hwp_epp(int i) | ||
| 267 | { | ||
| 268 | update_hwp_epp = 1; | ||
| 269 | |||
| 270 | switch (i) { | ||
| 271 | case OPTARG_POWER: | ||
| 272 | return HWP_EPP_POWERSAVE; | ||
| 273 | case OPTARG_BALANCE_POWER: | ||
| 274 | return HWP_EPP_BALANCE_POWERSAVE; | ||
| 275 | case OPTARG_NORMAL: | ||
| 276 | case OPTARG_BALANCE_PERFORMANCE: | ||
| 277 | return HWP_EPP_BALANCE_PERFORMANCE; | ||
| 278 | case OPTARG_PERFORMANCE: | ||
| 279 | return HWP_EPP_PERFORMANCE; | ||
| 280 | } | ||
| 281 | if (i < 0 || i > 0xff) { | ||
| 282 | fprintf(stderr, "--hwp-epp must be from 0 to 0xff\n"); | ||
| 283 | usage(); | ||
| 284 | } | ||
| 285 | return i; | ||
| 286 | } | ||
| 287 | int parse_cmdline_turbo(int i) | ||
| 288 | { | ||
| 289 | update_turbo = 1; | ||
| 290 | |||
| 291 | switch (i) { | ||
| 292 | case OPTARG_POWER: | ||
| 293 | return 0; | ||
| 294 | case OPTARG_NORMAL: | ||
| 295 | case OPTARG_BALANCE_POWER: | ||
| 296 | case OPTARG_BALANCE_PERFORMANCE: | ||
| 297 | case OPTARG_PERFORMANCE: | ||
| 298 | return 1; | ||
| 299 | } | ||
| 300 | if (i < 0 || i > 1) { | ||
| 301 | fprintf(stderr, "--turbo-enable: 1 to enable, 0 to disable\n"); | ||
| 302 | usage(); | ||
| 303 | } | ||
| 304 | return i; | ||
| 305 | } | ||
| 306 | |||
| 307 | int parse_optarg_string(char *s) | ||
| 308 | { | ||
| 309 | int i; | ||
| 310 | char *endptr; | ||
| 311 | |||
| 312 | if (!strncmp(s, "default", 7)) | ||
| 313 | return OPTARG_NORMAL; | ||
| 314 | |||
| 315 | if (!strncmp(s, "normal", 6)) | ||
| 316 | return OPTARG_NORMAL; | ||
| 317 | |||
| 318 | if (!strncmp(s, "power", 9)) | ||
| 319 | return OPTARG_POWER; | ||
| 320 | |||
| 321 | if (!strncmp(s, "balance-power", 17)) | ||
| 322 | return OPTARG_BALANCE_POWER; | ||
| 323 | |||
| 324 | if (!strncmp(s, "balance-performance", 19)) | ||
| 325 | return OPTARG_BALANCE_PERFORMANCE; | ||
| 326 | |||
| 327 | if (!strncmp(s, "performance", 11)) | ||
| 328 | return OPTARG_PERFORMANCE; | ||
| 329 | |||
| 330 | i = strtol(s, &endptr, 0); | ||
| 331 | if (s == endptr) { | ||
| 332 | fprintf(stderr, "no digits in \"%s\"\n", s); | ||
| 333 | usage(); | ||
| 334 | } | ||
| 335 | if (i == LONG_MIN || i == LONG_MAX) | ||
| 336 | errx(-1, "%s", s); | ||
| 337 | |||
| 338 | if (i > 0xFF) | ||
| 339 | errx(-1, "%d (0x%x) must be < 256", i, i); | ||
| 340 | |||
| 341 | if (i < 0) | ||
| 342 | errx(-1, "%d (0x%x) must be >= 0", i, i); | ||
| 343 | return i; | ||
| 344 | } | ||
| 345 | |||
| 346 | void parse_cmdline_all(char *s) | ||
| 347 | { | ||
| 348 | force++; | ||
| 349 | update_hwp_enable = 1; | ||
| 350 | req_update.hwp_min = parse_cmdline_hwp_min(parse_optarg_string(s)); | ||
| 351 | req_update.hwp_max = parse_cmdline_hwp_max(parse_optarg_string(s)); | ||
| 352 | req_update.hwp_epp = parse_cmdline_hwp_epp(parse_optarg_string(s)); | ||
| 353 | if (has_epb) | ||
| 354 | new_epb = parse_cmdline_epb(parse_optarg_string(s)); | ||
| 355 | turbo_update_value = parse_cmdline_turbo(parse_optarg_string(s)); | ||
| 356 | req_update.hwp_desired = parse_cmdline_hwp_desired(parse_optarg_string(s)); | ||
| 357 | req_update.hwp_window = parse_cmdline_hwp_window(parse_optarg_string(s)); | ||
| 358 | } | ||
| 359 | |||
| 360 | void validate_cpu_selected_set(void) | ||
| 361 | { | ||
| 362 | int cpu; | ||
| 363 | |||
| 364 | if (CPU_COUNT_S(cpu_setsize, cpu_selected_set) == 0) | ||
| 365 | errx(0, "no CPUs requested"); | ||
| 366 | |||
| 367 | for (cpu = 0; cpu <= max_cpu_num; ++cpu) { | ||
| 368 | if (CPU_ISSET_S(cpu, cpu_setsize, cpu_selected_set)) | ||
| 369 | if (!CPU_ISSET_S(cpu, cpu_setsize, cpu_present_set)) | ||
| 370 | errx(1, "Requested cpu% is not present", cpu); | ||
| 371 | } | ||
| 372 | } | ||
| 373 | |||
| 374 | void parse_cmdline_cpu(char *s) | ||
| 375 | { | ||
| 376 | char *startp, *endp; | ||
| 377 | int cpu = 0; | ||
| 378 | |||
| 379 | if (pkg_selected_set) { | ||
| 380 | usage(); | ||
| 381 | errx(1, "--cpu | --pkg"); | ||
| 382 | } | ||
| 383 | cpu_selected_set = CPU_ALLOC((max_cpu_num + 1)); | ||
| 384 | if (cpu_selected_set == NULL) | ||
| 385 | err(1, "cpu_selected_set"); | ||
| 386 | CPU_ZERO_S(cpu_setsize, cpu_selected_set); | ||
| 387 | |||
| 388 | for (startp = s; startp && *startp;) { | ||
| 389 | |||
| 390 | if (*startp == ',') { | ||
| 391 | startp++; | ||
| 392 | continue; | ||
| 393 | } | ||
| 394 | |||
| 395 | if (*startp == '-') { | ||
| 396 | int end_cpu; | ||
| 73 | 397 | ||
| 74 | #define BIAS_PERFORMANCE 0 | 398 | startp++; |
| 75 | #define BIAS_BALANCE 6 | 399 | end_cpu = strtol(startp, &endp, 10); |
| 76 | #define BIAS_POWERSAVE 15 | 400 | if (startp == endp) |
| 401 | continue; | ||
| 402 | |||
| 403 | while (cpu <= end_cpu) { | ||
| 404 | if (cpu > max_cpu_num) | ||
| 405 | errx(1, "Requested cpu%d exceeds max cpu%d", cpu, max_cpu_num); | ||
| 406 | CPU_SET_S(cpu, cpu_setsize, cpu_selected_set); | ||
| 407 | cpu++; | ||
| 408 | } | ||
| 409 | startp = endp; | ||
| 410 | continue; | ||
| 411 | } | ||
| 412 | |||
| 413 | if (strncmp(startp, "all", 3) == 0) { | ||
| 414 | for (cpu = 0; cpu <= max_cpu_num; cpu += 1) { | ||
| 415 | if (CPU_ISSET_S(cpu, cpu_setsize, cpu_present_set)) | ||
| 416 | CPU_SET_S(cpu, cpu_setsize, cpu_selected_set); | ||
| 417 | } | ||
| 418 | startp += 3; | ||
| 419 | if (*startp == 0) | ||
| 420 | break; | ||
| 421 | } | ||
| 422 | /* "--cpu even" is not documented */ | ||
| 423 | if (strncmp(startp, "even", 4) == 0) { | ||
| 424 | for (cpu = 0; cpu <= max_cpu_num; cpu += 2) { | ||
| 425 | if (CPU_ISSET_S(cpu, cpu_setsize, cpu_present_set)) | ||
| 426 | CPU_SET_S(cpu, cpu_setsize, cpu_selected_set); | ||
| 427 | } | ||
| 428 | startp += 4; | ||
| 429 | if (*startp == 0) | ||
| 430 | break; | ||
| 431 | } | ||
| 432 | |||
| 433 | /* "--cpu odd" is not documented */ | ||
| 434 | if (strncmp(startp, "odd", 3) == 0) { | ||
| 435 | for (cpu = 1; cpu <= max_cpu_num; cpu += 2) { | ||
| 436 | if (CPU_ISSET_S(cpu, cpu_setsize, cpu_present_set)) | ||
| 437 | CPU_SET_S(cpu, cpu_setsize, cpu_selected_set); | ||
| 438 | } | ||
| 439 | startp += 3; | ||
| 440 | if (*startp == 0) | ||
| 441 | break; | ||
| 442 | } | ||
| 443 | |||
| 444 | cpu = strtol(startp, &endp, 10); | ||
| 445 | if (startp == endp) | ||
| 446 | errx(1, "--cpu cpu-set: confused by '%s'", startp); | ||
| 447 | if (cpu > max_cpu_num) | ||
| 448 | errx(1, "Requested cpu%d exceeds max cpu%d", cpu, max_cpu_num); | ||
| 449 | CPU_SET_S(cpu, cpu_setsize, cpu_selected_set); | ||
| 450 | startp = endp; | ||
| 451 | } | ||
| 452 | |||
| 453 | validate_cpu_selected_set(); | ||
| 454 | |||
| 455 | } | ||
| 456 | |||
| 457 | void parse_cmdline_pkg(char *s) | ||
| 458 | { | ||
| 459 | char *startp, *endp; | ||
| 460 | int pkg = 0; | ||
| 461 | |||
| 462 | if (cpu_selected_set) { | ||
| 463 | usage(); | ||
| 464 | errx(1, "--pkg | --cpu"); | ||
| 465 | } | ||
| 466 | pkg_selected_set = 0; | ||
| 467 | |||
| 468 | for (startp = s; startp && *startp;) { | ||
| 469 | |||
| 470 | if (*startp == ',') { | ||
| 471 | startp++; | ||
| 472 | continue; | ||
| 473 | } | ||
| 474 | |||
| 475 | if (*startp == '-') { | ||
| 476 | int end_pkg; | ||
| 477 | |||
| 478 | startp++; | ||
| 479 | end_pkg = strtol(startp, &endp, 10); | ||
| 480 | if (startp == endp) | ||
| 481 | continue; | ||
| 482 | |||
| 483 | while (pkg <= end_pkg) { | ||
| 484 | if (pkg > max_pkg_num) | ||
| 485 | errx(1, "Requested pkg%d exceeds max pkg%d", pkg, max_pkg_num); | ||
| 486 | pkg_selected_set |= 1 << pkg; | ||
| 487 | pkg++; | ||
| 488 | } | ||
| 489 | startp = endp; | ||
| 490 | continue; | ||
| 491 | } | ||
| 492 | |||
| 493 | if (strncmp(startp, "all", 3) == 0) { | ||
| 494 | pkg_selected_set = pkg_present_set; | ||
| 495 | return; | ||
| 496 | } | ||
| 497 | |||
| 498 | pkg = strtol(startp, &endp, 10); | ||
| 499 | if (pkg > max_pkg_num) | ||
| 500 | errx(1, "Requested pkg%d Exceeds max pkg%d", pkg, max_pkg_num); | ||
| 501 | pkg_selected_set |= 1 << pkg; | ||
| 502 | startp = endp; | ||
| 503 | } | ||
| 504 | } | ||
| 505 | |||
| 506 | void for_packages(unsigned long long pkg_set, int (func)(int)) | ||
| 507 | { | ||
| 508 | int pkg_num; | ||
| 509 | |||
| 510 | for (pkg_num = 0; pkg_num <= max_pkg_num; ++pkg_num) { | ||
| 511 | if (pkg_set & (1UL << pkg_num)) | ||
| 512 | func(pkg_num); | ||
| 513 | } | ||
| 514 | } | ||
| 515 | |||
| 516 | void print_version(void) | ||
| 517 | { | ||
| 518 | printf("x86_energy_perf_policy 17.05.11 (C) Len Brown <len.brown@intel.com>\n"); | ||
| 519 | } | ||
| 77 | 520 | ||
| 78 | void cmdline(int argc, char **argv) | 521 | void cmdline(int argc, char **argv) |
| 79 | { | 522 | { |
| 80 | int opt; | 523 | int opt; |
| 524 | int option_index = 0; | ||
| 525 | |||
| 526 | static struct option long_options[] = { | ||
| 527 | {"all", required_argument, 0, 'a'}, | ||
| 528 | {"cpu", required_argument, 0, 'c'}, | ||
| 529 | {"pkg", required_argument, 0, 'p'}, | ||
| 530 | {"debug", no_argument, 0, 'd'}, | ||
| 531 | {"hwp-desired", required_argument, 0, 'D'}, | ||
| 532 | {"epb", required_argument, 0, 'B'}, | ||
| 533 | {"force", no_argument, 0, 'f'}, | ||
| 534 | {"hwp-enable", no_argument, 0, 'e'}, | ||
| 535 | {"help", no_argument, 0, 'h'}, | ||
| 536 | {"hwp-epp", required_argument, 0, 'P'}, | ||
| 537 | {"hwp-min", required_argument, 0, 'm'}, | ||
| 538 | {"hwp-max", required_argument, 0, 'M'}, | ||
| 539 | {"read", no_argument, 0, 'r'}, | ||
| 540 | {"turbo-enable", required_argument, 0, 't'}, | ||
| 541 | {"hwp-use-pkg", required_argument, 0, 'u'}, | ||
| 542 | {"version", no_argument, 0, 'v'}, | ||
| 543 | {"hwp-window", required_argument, 0, 'w'}, | ||
| 544 | {0, 0, 0, 0 } | ||
| 545 | }; | ||
| 81 | 546 | ||
| 82 | progname = argv[0]; | 547 | progname = argv[0]; |
| 83 | 548 | ||
| 84 | while ((opt = getopt(argc, argv, "+rvc:")) != -1) { | 549 | while ((opt = getopt_long_only(argc, argv, "+a:c:dD:E:e:f:m:M:rt:u:vw", |
| 550 | long_options, &option_index)) != -1) { | ||
| 85 | switch (opt) { | 551 | switch (opt) { |
| 552 | case 'a': | ||
| 553 | parse_cmdline_all(optarg); | ||
| 554 | break; | ||
| 555 | case 'B': | ||
| 556 | new_epb = parse_cmdline_epb(parse_optarg_string(optarg)); | ||
| 557 | break; | ||
| 86 | case 'c': | 558 | case 'c': |
| 87 | cpu = atoi(optarg); | 559 | parse_cmdline_cpu(optarg); |
| 560 | break; | ||
| 561 | case 'e': | ||
| 562 | update_hwp_enable = 1; | ||
| 563 | break; | ||
| 564 | case 'h': | ||
| 565 | usage(); | ||
| 566 | break; | ||
| 567 | case 'd': | ||
| 568 | debug++; | ||
| 569 | verbose++; | ||
| 570 | break; | ||
| 571 | case 'f': | ||
| 572 | force++; | ||
| 573 | break; | ||
| 574 | case 'D': | ||
| 575 | req_update.hwp_desired = parse_cmdline_hwp_desired(parse_optarg_string(optarg)); | ||
| 576 | break; | ||
| 577 | case 'm': | ||
| 578 | req_update.hwp_min = parse_cmdline_hwp_min(parse_optarg_string(optarg)); | ||
| 579 | break; | ||
| 580 | case 'M': | ||
| 581 | req_update.hwp_max = parse_cmdline_hwp_max(parse_optarg_string(optarg)); | ||
| 582 | break; | ||
| 583 | case 'p': | ||
| 584 | parse_cmdline_pkg(optarg); | ||
| 585 | break; | ||
| 586 | case 'P': | ||
| 587 | req_update.hwp_epp = parse_cmdline_hwp_epp(parse_optarg_string(optarg)); | ||
| 88 | break; | 588 | break; |
| 89 | case 'r': | 589 | case 'r': |
| 90 | read_only = 1; | 590 | /* v1 used -r to specify read-only mode, now the default */ |
| 591 | break; | ||
| 592 | case 't': | ||
| 593 | turbo_update_value = parse_cmdline_turbo(parse_optarg_string(optarg)); | ||
| 594 | break; | ||
| 595 | case 'u': | ||
| 596 | update_hwp_use_pkg++; | ||
| 597 | if (atoi(optarg) == 0) | ||
| 598 | req_update.hwp_use_pkg = 0; | ||
| 599 | else | ||
| 600 | req_update.hwp_use_pkg = 1; | ||
| 91 | break; | 601 | break; |
| 92 | case 'v': | 602 | case 'v': |
| 93 | verbose++; | 603 | print_version(); |
| 604 | exit(0); | ||
| 605 | break; | ||
| 606 | case 'w': | ||
| 607 | req_update.hwp_window = parse_cmdline_hwp_window(parse_optarg_string(optarg)); | ||
| 94 | break; | 608 | break; |
| 95 | default: | 609 | default: |
| 96 | usage(); | 610 | usage(); |
| 97 | } | 611 | } |
| 98 | } | 612 | } |
| 99 | /* if -r, then should be no additional optind */ | ||
| 100 | if (read_only && (argc > optind)) | ||
| 101 | usage(); | ||
| 102 | |||
| 103 | /* | 613 | /* |
| 104 | * if no -r , then must be one additional optind | 614 | * v1 allowed "performance"|"normal"|"power" with no policy specifier |
| 615 | * to update BIAS. Continue to support that, even though no longer documented. | ||
| 105 | */ | 616 | */ |
| 106 | if (!read_only) { | 617 | if (argc == optind + 1) |
| 618 | new_epb = parse_cmdline_epb(parse_optarg_string(argv[optind])); | ||
| 107 | 619 | ||
| 108 | if (argc != optind + 1) { | 620 | if (argc > optind + 1) { |
| 109 | printf("must supply -r or policy param\n"); | 621 | fprintf(stderr, "stray parameter '%s'\n", argv[optind + 1]); |
| 110 | usage(); | 622 | usage(); |
| 111 | } | 623 | } |
| 624 | } | ||
| 112 | 625 | ||
| 113 | if (!strcmp("performance", argv[optind])) { | 626 | |
| 114 | new_bias = BIAS_PERFORMANCE; | 627 | int get_msr(int cpu, int offset, unsigned long long *msr) |
| 115 | } else if (!strcmp("normal", argv[optind])) { | 628 | { |
| 116 | new_bias = BIAS_BALANCE; | 629 | int retval; |
| 117 | } else if (!strcmp("powersave", argv[optind])) { | 630 | char pathname[32]; |
| 118 | new_bias = BIAS_POWERSAVE; | 631 | int fd; |
| 119 | } else { | 632 | |
| 120 | char *endptr; | 633 | sprintf(pathname, "/dev/cpu/%d/msr", cpu); |
| 121 | 634 | fd = open(pathname, O_RDONLY); | |
| 122 | new_bias = strtoull(argv[optind], &endptr, 0); | 635 | if (fd < 0) |
| 123 | if (endptr == argv[optind] || | 636 | err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, or run as root", pathname); |
| 124 | new_bias > BIAS_POWERSAVE) { | 637 | |
| 125 | fprintf(stderr, "invalid value: %s\n", | 638 | retval = pread(fd, msr, sizeof(*msr), offset); |
| 126 | argv[optind]); | 639 | if (retval != sizeof(*msr)) |
| 127 | usage(); | 640 | err(-1, "%s offset 0x%llx read failed", pathname, (unsigned long long)offset); |
| 128 | } | 641 | |
| 129 | } | 642 | if (debug > 1) |
| 643 | fprintf(stderr, "get_msr(cpu%d, 0x%X, 0x%llX)\n", cpu, offset, *msr); | ||
| 644 | |||
| 645 | close(fd); | ||
| 646 | return 0; | ||
| 647 | } | ||
| 648 | |||
| 649 | int put_msr(int cpu, int offset, unsigned long long new_msr) | ||
| 650 | { | ||
| 651 | char pathname[32]; | ||
| 652 | int retval; | ||
| 653 | int fd; | ||
| 654 | |||
| 655 | sprintf(pathname, "/dev/cpu/%d/msr", cpu); | ||
| 656 | fd = open(pathname, O_RDWR); | ||
| 657 | if (fd < 0) | ||
| 658 | err(-1, "%s open failed, try chown or chmod +r /dev/cpu/*/msr, or run as root", pathname); | ||
| 659 | |||
| 660 | retval = pwrite(fd, &new_msr, sizeof(new_msr), offset); | ||
| 661 | if (retval != sizeof(new_msr)) | ||
| 662 | err(-2, "pwrite(cpu%d, offset 0x%x, 0x%llx) = %d", cpu, offset, new_msr, retval); | ||
| 663 | |||
| 664 | close(fd); | ||
| 665 | |||
| 666 | if (debug > 1) | ||
| 667 | fprintf(stderr, "put_msr(cpu%d, 0x%X, 0x%llX)\n", cpu, offset, new_msr); | ||
| 668 | |||
| 669 | return 0; | ||
| 670 | } | ||
| 671 | |||
| 672 | void print_hwp_cap(int cpu, struct msr_hwp_cap *cap, char *str) | ||
| 673 | { | ||
| 674 | if (cpu != -1) | ||
| 675 | printf("cpu%d: ", cpu); | ||
| 676 | |||
| 677 | printf("HWP_CAP: low %d eff %d guar %d high %d\n", | ||
| 678 | cap->lowest, cap->efficient, cap->guaranteed, cap->highest); | ||
| 679 | } | ||
| 680 | void read_hwp_cap(int cpu, struct msr_hwp_cap *cap, unsigned int msr_offset) | ||
| 681 | { | ||
| 682 | unsigned long long msr; | ||
| 683 | |||
| 684 | get_msr(cpu, msr_offset, &msr); | ||
| 685 | |||
| 686 | cap->highest = msr_perf_2_ratio(HWP_HIGHEST_PERF(msr)); | ||
| 687 | cap->guaranteed = msr_perf_2_ratio(HWP_GUARANTEED_PERF(msr)); | ||
| 688 | cap->efficient = msr_perf_2_ratio(HWP_MOSTEFFICIENT_PERF(msr)); | ||
| 689 | cap->lowest = msr_perf_2_ratio(HWP_LOWEST_PERF(msr)); | ||
| 690 | } | ||
| 691 | |||
| 692 | void print_hwp_request(int cpu, struct msr_hwp_request *h, char *str) | ||
| 693 | { | ||
| 694 | if (cpu != -1) | ||
| 695 | printf("cpu%d: ", cpu); | ||
| 696 | |||
| 697 | if (str) | ||
| 698 | printf("%s", str); | ||
| 699 | |||
| 700 | printf("HWP_REQ: min %d max %d des %d epp %d window 0x%x (%d*10^%dus) use_pkg %d\n", | ||
| 701 | h->hwp_min, h->hwp_max, h->hwp_desired, h->hwp_epp, | ||
| 702 | h->hwp_window, h->hwp_window & 0x7F, (h->hwp_window >> 7) & 0x7, h->hwp_use_pkg); | ||
| 703 | } | ||
| 704 | void print_hwp_request_pkg(int pkg, struct msr_hwp_request *h, char *str) | ||
| 705 | { | ||
| 706 | printf("pkg%d: ", pkg); | ||
| 707 | |||
| 708 | if (str) | ||
| 709 | printf("%s", str); | ||
| 710 | |||
| 711 | printf("HWP_REQ_PKG: min %d max %d des %d epp %d window 0x%x (%d*10^%dus)\n", | ||
| 712 | h->hwp_min, h->hwp_max, h->hwp_desired, h->hwp_epp, | ||
| 713 | h->hwp_window, h->hwp_window & 0x7F, (h->hwp_window >> 7) & 0x7); | ||
| 714 | } | ||
| 715 | void read_hwp_request(int cpu, struct msr_hwp_request *hwp_req, unsigned int msr_offset) | ||
| 716 | { | ||
| 717 | unsigned long long msr; | ||
| 718 | |||
| 719 | get_msr(cpu, msr_offset, &msr); | ||
| 720 | |||
| 721 | hwp_req->hwp_min = msr_perf_2_ratio((((msr) >> 0) & 0xff)); | ||
| 722 | hwp_req->hwp_max = msr_perf_2_ratio((((msr) >> 8) & 0xff)); | ||
| 723 | hwp_req->hwp_desired = msr_perf_2_ratio((((msr) >> 16) & 0xff)); | ||
| 724 | hwp_req->hwp_epp = (((msr) >> 24) & 0xff); | ||
| 725 | hwp_req->hwp_window = (((msr) >> 32) & 0x3ff); | ||
| 726 | hwp_req->hwp_use_pkg = (((msr) >> 42) & 0x1); | ||
| 727 | } | ||
| 728 | |||
| 729 | void write_hwp_request(int cpu, struct msr_hwp_request *hwp_req, unsigned int msr_offset) | ||
| 730 | { | ||
| 731 | unsigned long long msr = 0; | ||
| 732 | |||
| 733 | if (debug > 1) | ||
| 734 | printf("cpu%d: requesting min %d max %d des %d epp %d window 0x%0x use_pkg %d\n", | ||
| 735 | cpu, hwp_req->hwp_min, hwp_req->hwp_max, | ||
| 736 | hwp_req->hwp_desired, hwp_req->hwp_epp, | ||
| 737 | hwp_req->hwp_window, hwp_req->hwp_use_pkg); | ||
| 738 | |||
| 739 | msr |= HWP_MIN_PERF(ratio_2_msr_perf(hwp_req->hwp_min)); | ||
| 740 | msr |= HWP_MAX_PERF(ratio_2_msr_perf(hwp_req->hwp_max)); | ||
| 741 | msr |= HWP_DESIRED_PERF(ratio_2_msr_perf(hwp_req->hwp_desired)); | ||
| 742 | msr |= HWP_ENERGY_PERF_PREFERENCE(hwp_req->hwp_epp); | ||
| 743 | msr |= HWP_ACTIVITY_WINDOW(hwp_req->hwp_window); | ||
| 744 | msr |= HWP_PACKAGE_CONTROL(hwp_req->hwp_use_pkg); | ||
| 745 | |||
| 746 | put_msr(cpu, msr_offset, msr); | ||
| 747 | } | ||
| 748 | |||
| 749 | int print_cpu_msrs(int cpu) | ||
| 750 | { | ||
| 751 | unsigned long long msr; | ||
| 752 | struct msr_hwp_request req; | ||
| 753 | struct msr_hwp_cap cap; | ||
| 754 | |||
| 755 | if (has_epb) { | ||
| 756 | get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &msr); | ||
| 757 | |||
| 758 | printf("cpu%d: EPB %u\n", cpu, (unsigned int) msr); | ||
| 130 | } | 759 | } |
| 760 | |||
| 761 | if (!has_hwp) | ||
| 762 | return 0; | ||
| 763 | |||
| 764 | read_hwp_request(cpu, &req, MSR_HWP_REQUEST); | ||
| 765 | print_hwp_request(cpu, &req, ""); | ||
| 766 | |||
| 767 | read_hwp_cap(cpu, &cap, MSR_HWP_CAPABILITIES); | ||
| 768 | print_hwp_cap(cpu, &cap, ""); | ||
| 769 | |||
| 770 | return 0; | ||
| 771 | } | ||
| 772 | |||
| 773 | int print_pkg_msrs(int pkg) | ||
| 774 | { | ||
| 775 | struct msr_hwp_request req; | ||
| 776 | unsigned long long msr; | ||
| 777 | |||
| 778 | if (!has_hwp) | ||
| 779 | return 0; | ||
| 780 | |||
| 781 | read_hwp_request(first_cpu_in_pkg[pkg], &req, MSR_HWP_REQUEST_PKG); | ||
| 782 | print_hwp_request_pkg(pkg, &req, ""); | ||
| 783 | |||
| 784 | if (has_hwp_notify) { | ||
| 785 | get_msr(first_cpu_in_pkg[pkg], MSR_HWP_INTERRUPT, &msr); | ||
| 786 | fprintf(stderr, | ||
| 787 | "pkg%d: MSR_HWP_INTERRUPT: 0x%08llx (Excursion_Min-%sabled, Guaranteed_Perf_Change-%sabled)\n", | ||
| 788 | pkg, msr, | ||
| 789 | ((msr) & 0x2) ? "EN" : "Dis", | ||
| 790 | ((msr) & 0x1) ? "EN" : "Dis"); | ||
| 791 | } | ||
| 792 | get_msr(first_cpu_in_pkg[pkg], MSR_HWP_STATUS, &msr); | ||
| 793 | fprintf(stderr, | ||
| 794 | "pkg%d: MSR_HWP_STATUS: 0x%08llx (%sExcursion_Min, %sGuaranteed_Perf_Change)\n", | ||
| 795 | pkg, msr, | ||
| 796 | ((msr) & 0x4) ? "" : "No-", | ||
| 797 | ((msr) & 0x1) ? "" : "No-"); | ||
| 798 | |||
| 799 | return 0; | ||
| 131 | } | 800 | } |
| 132 | 801 | ||
| 133 | /* | 802 | /* |
| 134 | * validate_cpuid() | 803 | * Assumption: All HWP systems have 100 MHz bus clock |
| 135 | * returns on success, quietly exits on failure (make verbose with -v) | ||
| 136 | */ | 804 | */ |
| 137 | void validate_cpuid(void) | 805 | int ratio_2_sysfs_khz(int ratio) |
| 138 | { | 806 | { |
| 139 | unsigned int eax, ebx, ecx, edx, max_level; | 807 | int bclk_khz = 100 * 1000; /* 100,000 KHz = 100 MHz */ |
| 140 | unsigned int fms, family, model, stepping; | ||
| 141 | 808 | ||
| 142 | eax = ebx = ecx = edx = 0; | 809 | return ratio * bclk_khz; |
| 810 | } | ||
| 811 | /* | ||
| 812 | * If HWP is enabled and cpufreq sysfs attribtes are present, | ||
| 813 | * then update sysfs, so that it will not become | ||
| 814 | * stale when we write to MSRs. | ||
| 815 | * (intel_pstate's max_perf_pct and min_perf_pct will follow cpufreq, | ||
| 816 | * so we don't have to touch that.) | ||
| 817 | */ | ||
| 818 | void update_cpufreq_scaling_freq(int is_max, int cpu, unsigned int ratio) | ||
| 819 | { | ||
| 820 | char pathname[64]; | ||
| 821 | FILE *fp; | ||
| 822 | int retval; | ||
| 823 | int khz; | ||
| 143 | 824 | ||
| 144 | asm("cpuid" : "=a" (max_level), "=b" (ebx), "=c" (ecx), | 825 | sprintf(pathname, "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_%s_freq", |
| 145 | "=d" (edx) : "a" (0)); | 826 | cpu, is_max ? "max" : "min"); |
| 146 | 827 | ||
| 147 | if (ebx != 0x756e6547 || edx != 0x49656e69 || ecx != 0x6c65746e) { | 828 | fp = fopen(pathname, "w"); |
| 148 | if (verbose) | 829 | if (!fp) { |
| 149 | fprintf(stderr, "%.4s%.4s%.4s != GenuineIntel", | 830 | if (debug) |
| 150 | (char *)&ebx, (char *)&edx, (char *)&ecx); | 831 | perror(pathname); |
| 151 | exit(1); | 832 | return; |
| 152 | } | 833 | } |
| 153 | 834 | ||
| 154 | asm("cpuid" : "=a" (fms), "=c" (ecx), "=d" (edx) : "a" (1) : "ebx"); | 835 | khz = ratio_2_sysfs_khz(ratio); |
| 155 | family = (fms >> 8) & 0xf; | 836 | retval = fprintf(fp, "%d", khz); |
| 156 | model = (fms >> 4) & 0xf; | 837 | if (retval < 0) |
| 157 | stepping = fms & 0xf; | 838 | if (debug) |
| 158 | if (family == 6 || family == 0xf) | 839 | perror("fprintf"); |
| 159 | model += ((fms >> 16) & 0xf) << 4; | 840 | if (debug) |
| 841 | printf("echo %d > %s\n", khz, pathname); | ||
| 160 | 842 | ||
| 161 | if (verbose > 1) | 843 | fclose(fp); |
| 162 | printf("CPUID %d levels family:model:stepping " | 844 | } |
| 163 | "0x%x:%x:%x (%d:%d:%d)\n", max_level, | ||
| 164 | family, model, stepping, family, model, stepping); | ||
| 165 | 845 | ||
| 166 | if (!(edx & (1 << 5))) { | 846 | /* |
| 167 | if (verbose) | 847 | * We update all sysfs before updating any MSRs because of |
| 168 | printf("CPUID: no MSR\n"); | 848 | * bugs in cpufreq/intel_pstate where the sysfs writes |
| 169 | exit(1); | 849 | * for a CPU may change the min/max values on other CPUS. |
| 850 | */ | ||
| 851 | |||
| 852 | int update_sysfs(int cpu) | ||
| 853 | { | ||
| 854 | if (!has_hwp) | ||
| 855 | return 0; | ||
| 856 | |||
| 857 | if (!hwp_update_enabled()) | ||
| 858 | return 0; | ||
| 859 | |||
| 860 | if (access("/sys/devices/system/cpu/cpu0/cpufreq", F_OK)) | ||
| 861 | return 0; | ||
| 862 | |||
| 863 | if (update_hwp_min) | ||
| 864 | update_cpufreq_scaling_freq(0, cpu, req_update.hwp_min); | ||
| 865 | |||
| 866 | if (update_hwp_max) | ||
| 867 | update_cpufreq_scaling_freq(1, cpu, req_update.hwp_max); | ||
| 868 | |||
| 869 | return 0; | ||
| 870 | } | ||
| 871 | |||
| 872 | int verify_hwp_req_self_consistency(int cpu, struct msr_hwp_request *req) | ||
| 873 | { | ||
| 874 | /* fail if min > max requested */ | ||
| 875 | if (req->hwp_min > req->hwp_max) { | ||
| 876 | errx(1, "cpu%d: requested hwp-min %d > hwp_max %d", | ||
| 877 | cpu, req->hwp_min, req->hwp_max); | ||
| 170 | } | 878 | } |
| 171 | 879 | ||
| 172 | /* | 880 | /* fail if desired > max requestd */ |
| 173 | * Support for MSR_IA32_ENERGY_PERF_BIAS | 881 | if (req->hwp_desired && (req->hwp_desired > req->hwp_max)) { |
| 174 | * is indicated by CPUID.06H.ECX.bit3 | 882 | errx(1, "cpu%d: requested hwp-desired %d > hwp_max %d", |
| 175 | */ | 883 | cpu, req->hwp_desired, req->hwp_max); |
| 176 | asm("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (6)); | ||
| 177 | if (verbose) | ||
| 178 | printf("CPUID.06H.ECX: 0x%x\n", ecx); | ||
| 179 | if (!(ecx & (1 << 3))) { | ||
| 180 | if (verbose) | ||
| 181 | printf("CPUID: No MSR_IA32_ENERGY_PERF_BIAS\n"); | ||
| 182 | exit(1); | ||
| 183 | } | 884 | } |
| 184 | return; /* success */ | 885 | /* fail if desired < min requestd */ |
| 886 | if (req->hwp_desired && (req->hwp_desired < req->hwp_min)) { | ||
| 887 | errx(1, "cpu%d: requested hwp-desired %d < requested hwp_min %d", | ||
| 888 | cpu, req->hwp_desired, req->hwp_min); | ||
| 889 | } | ||
| 890 | |||
| 891 | return 0; | ||
| 185 | } | 892 | } |
| 186 | 893 | ||
| 187 | unsigned long long get_msr(int cpu, int offset) | 894 | int check_hwp_request_v_hwp_capabilities(int cpu, struct msr_hwp_request *req, struct msr_hwp_cap *cap) |
| 188 | { | 895 | { |
| 189 | unsigned long long msr; | 896 | if (update_hwp_max) { |
| 190 | char msr_path[32]; | 897 | if (req->hwp_max > cap->highest) |
| 191 | int retval; | 898 | errx(1, "cpu%d: requested max %d > capabilities highest %d, use --force?", |
| 192 | int fd; | 899 | cpu, req->hwp_max, cap->highest); |
| 900 | if (req->hwp_max < cap->lowest) | ||
| 901 | errx(1, "cpu%d: requested max %d < capabilities lowest %d, use --force?", | ||
| 902 | cpu, req->hwp_max, cap->lowest); | ||
| 903 | } | ||
| 193 | 904 | ||
| 194 | sprintf(msr_path, "/dev/cpu/%d/msr", cpu); | 905 | if (update_hwp_min) { |
| 195 | fd = open(msr_path, O_RDONLY); | 906 | if (req->hwp_min > cap->highest) |
| 196 | if (fd < 0) { | 907 | errx(1, "cpu%d: requested min %d > capabilities highest %d, use --force?", |
| 197 | printf("Try \"# modprobe msr\"\n"); | 908 | cpu, req->hwp_min, cap->highest); |
| 198 | perror(msr_path); | 909 | if (req->hwp_min < cap->lowest) |
| 199 | exit(1); | 910 | errx(1, "cpu%d: requested min %d < capabilities lowest %d, use --force?", |
| 911 | cpu, req->hwp_min, cap->lowest); | ||
| 200 | } | 912 | } |
| 201 | 913 | ||
| 202 | retval = pread(fd, &msr, sizeof msr, offset); | 914 | if (update_hwp_min && update_hwp_max && (req->hwp_min > req->hwp_max)) |
| 915 | errx(1, "cpu%d: requested min %d > requested max %d", | ||
| 916 | cpu, req->hwp_min, req->hwp_max); | ||
| 203 | 917 | ||
| 204 | if (retval != sizeof msr) { | 918 | if (update_hwp_desired && req->hwp_desired) { |
| 205 | printf("pread cpu%d 0x%x = %d\n", cpu, offset, retval); | 919 | if (req->hwp_desired > req->hwp_max) |
| 206 | exit(-2); | 920 | errx(1, "cpu%d: requested desired %d > requested max %d, use --force?", |
| 921 | cpu, req->hwp_desired, req->hwp_max); | ||
| 922 | if (req->hwp_desired < req->hwp_min) | ||
| 923 | errx(1, "cpu%d: requested desired %d < requested min %d, use --force?", | ||
| 924 | cpu, req->hwp_desired, req->hwp_min); | ||
| 925 | if (req->hwp_desired < cap->lowest) | ||
| 926 | errx(1, "cpu%d: requested desired %d < capabilities lowest %d, use --force?", | ||
| 927 | cpu, req->hwp_desired, cap->lowest); | ||
| 928 | if (req->hwp_desired > cap->highest) | ||
| 929 | errx(1, "cpu%d: requested desired %d > capabilities highest %d, use --force?", | ||
| 930 | cpu, req->hwp_desired, cap->highest); | ||
| 207 | } | 931 | } |
| 208 | close(fd); | 932 | |
| 209 | return msr; | 933 | return 0; |
| 210 | } | 934 | } |
| 211 | 935 | ||
| 212 | unsigned long long put_msr(int cpu, unsigned long long new_msr, int offset) | 936 | int update_hwp_request(int cpu) |
| 213 | { | 937 | { |
| 214 | unsigned long long old_msr; | 938 | struct msr_hwp_request req; |
| 215 | char msr_path[32]; | 939 | struct msr_hwp_cap cap; |
| 216 | int retval; | 940 | |
| 217 | int fd; | 941 | int msr_offset = MSR_HWP_REQUEST; |
| 942 | |||
| 943 | read_hwp_request(cpu, &req, msr_offset); | ||
| 944 | if (debug) | ||
| 945 | print_hwp_request(cpu, &req, "old: "); | ||
| 946 | |||
| 947 | if (update_hwp_min) | ||
| 948 | req.hwp_min = req_update.hwp_min; | ||
| 949 | |||
| 950 | if (update_hwp_max) | ||
| 951 | req.hwp_max = req_update.hwp_max; | ||
| 952 | |||
| 953 | if (update_hwp_desired) | ||
| 954 | req.hwp_desired = req_update.hwp_desired; | ||
| 955 | |||
| 956 | if (update_hwp_window) | ||
| 957 | req.hwp_window = req_update.hwp_window; | ||
| 958 | |||
| 959 | if (update_hwp_epp) | ||
| 960 | req.hwp_epp = req_update.hwp_epp; | ||
| 961 | |||
| 962 | req.hwp_use_pkg = req_update.hwp_use_pkg; | ||
| 963 | |||
| 964 | read_hwp_cap(cpu, &cap, MSR_HWP_CAPABILITIES); | ||
| 965 | if (debug) | ||
| 966 | print_hwp_cap(cpu, &cap, ""); | ||
| 967 | |||
| 968 | if (!force) | ||
| 969 | check_hwp_request_v_hwp_capabilities(cpu, &req, &cap); | ||
| 970 | |||
| 971 | verify_hwp_req_self_consistency(cpu, &req); | ||
| 218 | 972 | ||
| 219 | sprintf(msr_path, "/dev/cpu/%d/msr", cpu); | 973 | write_hwp_request(cpu, &req, msr_offset); |
| 220 | fd = open(msr_path, O_RDWR); | 974 | |
| 221 | if (fd < 0) { | 975 | if (debug) { |
| 222 | perror(msr_path); | 976 | read_hwp_request(cpu, &req, msr_offset); |
| 223 | exit(1); | 977 | print_hwp_request(cpu, &req, "new: "); |
| 224 | } | 978 | } |
| 979 | return 0; | ||
| 980 | } | ||
| 981 | int update_hwp_request_pkg(int pkg) | ||
| 982 | { | ||
| 983 | struct msr_hwp_request req; | ||
| 984 | struct msr_hwp_cap cap; | ||
| 985 | int cpu = first_cpu_in_pkg[pkg]; | ||
| 986 | |||
| 987 | int msr_offset = MSR_HWP_REQUEST_PKG; | ||
| 988 | |||
| 989 | read_hwp_request(cpu, &req, msr_offset); | ||
| 990 | if (debug) | ||
| 991 | print_hwp_request_pkg(pkg, &req, "old: "); | ||
| 992 | |||
| 993 | if (update_hwp_min) | ||
| 994 | req.hwp_min = req_update.hwp_min; | ||
| 995 | |||
| 996 | if (update_hwp_max) | ||
| 997 | req.hwp_max = req_update.hwp_max; | ||
| 998 | |||
| 999 | if (update_hwp_desired) | ||
| 1000 | req.hwp_desired = req_update.hwp_desired; | ||
| 1001 | |||
| 1002 | if (update_hwp_window) | ||
| 1003 | req.hwp_window = req_update.hwp_window; | ||
| 1004 | |||
| 1005 | if (update_hwp_epp) | ||
| 1006 | req.hwp_epp = req_update.hwp_epp; | ||
| 1007 | |||
| 1008 | read_hwp_cap(cpu, &cap, MSR_HWP_CAPABILITIES); | ||
| 1009 | if (debug) | ||
| 1010 | print_hwp_cap(cpu, &cap, ""); | ||
| 1011 | |||
| 1012 | if (!force) | ||
| 1013 | check_hwp_request_v_hwp_capabilities(cpu, &req, &cap); | ||
| 1014 | |||
| 1015 | verify_hwp_req_self_consistency(cpu, &req); | ||
| 1016 | |||
| 1017 | write_hwp_request(cpu, &req, msr_offset); | ||
| 225 | 1018 | ||
| 226 | retval = pread(fd, &old_msr, sizeof old_msr, offset); | 1019 | if (debug) { |
| 227 | if (retval != sizeof old_msr) { | 1020 | read_hwp_request(cpu, &req, msr_offset); |
| 228 | perror("pwrite"); | 1021 | print_hwp_request_pkg(pkg, &req, "new: "); |
| 229 | printf("pread cpu%d 0x%x = %d\n", cpu, offset, retval); | ||
| 230 | exit(-2); | ||
| 231 | } | 1022 | } |
| 1023 | return 0; | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | int enable_hwp_on_cpu(int cpu) | ||
| 1027 | { | ||
| 1028 | unsigned long long msr; | ||
| 1029 | |||
| 1030 | get_msr(cpu, MSR_PM_ENABLE, &msr); | ||
| 1031 | put_msr(cpu, MSR_PM_ENABLE, 1); | ||
| 1032 | |||
| 1033 | if (verbose) | ||
| 1034 | printf("cpu%d: MSR_PM_ENABLE old: %d new: %d\n", cpu, (unsigned int) msr, 1); | ||
| 1035 | |||
| 1036 | return 0; | ||
| 1037 | } | ||
| 1038 | |||
| 1039 | int update_cpu_msrs(int cpu) | ||
| 1040 | { | ||
| 1041 | unsigned long long msr; | ||
| 1042 | |||
| 232 | 1043 | ||
| 233 | retval = pwrite(fd, &new_msr, sizeof new_msr, offset); | 1044 | if (update_epb) { |
| 234 | if (retval != sizeof new_msr) { | 1045 | get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, &msr); |
| 235 | perror("pwrite"); | 1046 | put_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS, new_epb); |
| 236 | printf("pwrite cpu%d 0x%x = %d\n", cpu, offset, retval); | 1047 | |
| 237 | exit(-2); | 1048 | if (verbose) |
| 1049 | printf("cpu%d: ENERGY_PERF_BIAS old: %d new: %d\n", | ||
| 1050 | cpu, (unsigned int) msr, (unsigned int) new_epb); | ||
| 238 | } | 1051 | } |
| 239 | 1052 | ||
| 240 | close(fd); | 1053 | if (update_turbo) { |
| 1054 | int turbo_is_present_and_disabled; | ||
| 1055 | |||
| 1056 | get_msr(cpu, MSR_IA32_MISC_ENABLE, &msr); | ||
| 1057 | |||
| 1058 | turbo_is_present_and_disabled = ((msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE) != 0); | ||
| 1059 | |||
| 1060 | if (turbo_update_value == 1) { | ||
| 1061 | if (turbo_is_present_and_disabled) { | ||
| 1062 | msr &= ~MSR_IA32_MISC_ENABLE_TURBO_DISABLE; | ||
| 1063 | put_msr(cpu, MSR_IA32_MISC_ENABLE, msr); | ||
| 1064 | if (verbose) | ||
| 1065 | printf("cpu%d: turbo ENABLE\n", cpu); | ||
| 1066 | } | ||
| 1067 | } else { | ||
| 1068 | /* | ||
| 1069 | * if "turbo_is_enabled" were known to be describe this cpu | ||
| 1070 | * then we could use it here to skip redundant disable requests. | ||
| 1071 | * but cpu may be in a different package, so we always write. | ||
| 1072 | */ | ||
| 1073 | msr |= MSR_IA32_MISC_ENABLE_TURBO_DISABLE; | ||
| 1074 | put_msr(cpu, MSR_IA32_MISC_ENABLE, msr); | ||
| 1075 | if (verbose) | ||
| 1076 | printf("cpu%d: turbo DISABLE\n", cpu); | ||
| 1077 | } | ||
| 1078 | } | ||
| 1079 | |||
| 1080 | if (!has_hwp) | ||
| 1081 | return 0; | ||
| 1082 | |||
| 1083 | if (!hwp_update_enabled()) | ||
| 1084 | return 0; | ||
| 1085 | |||
| 1086 | update_hwp_request(cpu); | ||
| 1087 | return 0; | ||
| 1088 | } | ||
| 1089 | |||
| 1090 | /* | ||
| 1091 | * Open a file, and exit on failure | ||
| 1092 | */ | ||
| 1093 | FILE *fopen_or_die(const char *path, const char *mode) | ||
| 1094 | { | ||
| 1095 | FILE *filep = fopen(path, "r"); | ||
| 241 | 1096 | ||
| 242 | return old_msr; | 1097 | if (!filep) |
| 1098 | err(1, "%s: open failed", path); | ||
| 1099 | return filep; | ||
| 243 | } | 1100 | } |
| 244 | 1101 | ||
| 245 | void print_msr(int cpu) | 1102 | unsigned int get_pkg_num(int cpu) |
| 246 | { | 1103 | { |
| 247 | printf("cpu%d: 0x%016llx\n", | 1104 | FILE *fp; |
| 248 | cpu, get_msr(cpu, MSR_IA32_ENERGY_PERF_BIAS)); | 1105 | char pathname[128]; |
| 1106 | unsigned int pkg; | ||
| 1107 | int retval; | ||
| 1108 | |||
| 1109 | sprintf(pathname, "/sys/devices/system/cpu/cpu%d/topology/physical_package_id", cpu); | ||
| 1110 | |||
| 1111 | fp = fopen_or_die(pathname, "r"); | ||
| 1112 | retval = fscanf(fp, "%d\n", &pkg); | ||
| 1113 | if (retval != 1) | ||
| 1114 | errx(1, "%s: failed to parse", pathname); | ||
| 1115 | return pkg; | ||
| 249 | } | 1116 | } |
| 250 | 1117 | ||
| 251 | void update_msr(int cpu) | 1118 | int set_max_cpu_pkg_num(int cpu) |
| 252 | { | 1119 | { |
| 253 | unsigned long long previous_msr; | 1120 | unsigned int pkg; |
| 254 | 1121 | ||
| 255 | previous_msr = put_msr(cpu, new_bias, MSR_IA32_ENERGY_PERF_BIAS); | 1122 | if (max_cpu_num < cpu) |
| 1123 | max_cpu_num = cpu; | ||
| 256 | 1124 | ||
| 257 | if (verbose) | 1125 | pkg = get_pkg_num(cpu); |
| 258 | printf("cpu%d msr0x%x 0x%016llx -> 0x%016llx\n", | 1126 | |
| 259 | cpu, MSR_IA32_ENERGY_PERF_BIAS, previous_msr, new_bias); | 1127 | if (pkg >= MAX_PACKAGES) |
| 1128 | errx(1, "cpu%d: %d >= MAX_PACKAGES (%d)", cpu, pkg, MAX_PACKAGES); | ||
| 1129 | |||
| 1130 | if (pkg > max_pkg_num) | ||
| 1131 | max_pkg_num = pkg; | ||
| 260 | 1132 | ||
| 261 | return; | 1133 | if ((pkg_present_set & (1ULL << pkg)) == 0) { |
| 1134 | pkg_present_set |= (1ULL << pkg); | ||
| 1135 | first_cpu_in_pkg[pkg] = cpu; | ||
| 1136 | } | ||
| 1137 | |||
| 1138 | return 0; | ||
| 1139 | } | ||
| 1140 | int mark_cpu_present(int cpu) | ||
| 1141 | { | ||
| 1142 | CPU_SET_S(cpu, cpu_setsize, cpu_present_set); | ||
| 1143 | return 0; | ||
| 262 | } | 1144 | } |
| 263 | 1145 | ||
| 264 | char *proc_stat = "/proc/stat"; | ||
| 265 | /* | 1146 | /* |
| 266 | * run func() on every cpu in /dev/cpu | 1147 | * run func(cpu) on every cpu in /proc/stat |
| 1148 | * return max_cpu number | ||
| 267 | */ | 1149 | */ |
| 268 | void for_every_cpu(void (func)(int)) | 1150 | int for_all_proc_cpus(int (func)(int)) |
| 269 | { | 1151 | { |
| 270 | FILE *fp; | 1152 | FILE *fp; |
| 1153 | int cpu_num; | ||
| 271 | int retval; | 1154 | int retval; |
| 272 | 1155 | ||
| 273 | fp = fopen(proc_stat, "r"); | 1156 | fp = fopen_or_die(proc_stat, "r"); |
| 274 | if (fp == NULL) { | ||
| 275 | perror(proc_stat); | ||
| 276 | exit(1); | ||
| 277 | } | ||
| 278 | 1157 | ||
| 279 | retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n"); | 1158 | retval = fscanf(fp, "cpu %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n"); |
| 280 | if (retval != 0) { | 1159 | if (retval != 0) |
| 281 | perror("/proc/stat format"); | 1160 | err(1, "%s: failed to parse format", proc_stat); |
| 282 | exit(1); | ||
| 283 | } | ||
| 284 | 1161 | ||
| 285 | while (1) { | 1162 | while (1) { |
| 286 | int cpu; | 1163 | retval = fscanf(fp, "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", &cpu_num); |
| 287 | |||
| 288 | retval = fscanf(fp, | ||
| 289 | "cpu%u %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d\n", | ||
| 290 | &cpu); | ||
| 291 | if (retval != 1) | 1164 | if (retval != 1) |
| 292 | break; | 1165 | break; |
| 293 | 1166 | ||
| 294 | func(cpu); | 1167 | retval = func(cpu_num); |
| 1168 | if (retval) { | ||
| 1169 | fclose(fp); | ||
| 1170 | return retval; | ||
| 1171 | } | ||
| 295 | } | 1172 | } |
| 296 | fclose(fp); | 1173 | fclose(fp); |
| 1174 | return 0; | ||
| 1175 | } | ||
| 1176 | |||
| 1177 | void for_all_cpus_in_set(size_t set_size, cpu_set_t *cpu_set, int (func)(int)) | ||
| 1178 | { | ||
| 1179 | int cpu_num; | ||
| 1180 | |||
| 1181 | for (cpu_num = 0; cpu_num <= max_cpu_num; ++cpu_num) | ||
| 1182 | if (CPU_ISSET_S(cpu_num, set_size, cpu_set)) | ||
| 1183 | func(cpu_num); | ||
| 1184 | } | ||
| 1185 | |||
| 1186 | void init_data_structures(void) | ||
| 1187 | { | ||
| 1188 | for_all_proc_cpus(set_max_cpu_pkg_num); | ||
| 1189 | |||
| 1190 | cpu_setsize = CPU_ALLOC_SIZE((max_cpu_num + 1)); | ||
| 1191 | |||
| 1192 | cpu_present_set = CPU_ALLOC((max_cpu_num + 1)); | ||
| 1193 | if (cpu_present_set == NULL) | ||
| 1194 | err(3, "CPU_ALLOC"); | ||
| 1195 | CPU_ZERO_S(cpu_setsize, cpu_present_set); | ||
| 1196 | for_all_proc_cpus(mark_cpu_present); | ||
| 1197 | } | ||
| 1198 | |||
| 1199 | /* clear has_hwp if it is not enable (or being enabled) */ | ||
| 1200 | |||
| 1201 | void verify_hwp_is_enabled(void) | ||
| 1202 | { | ||
| 1203 | unsigned long long msr; | ||
| 1204 | |||
| 1205 | if (!has_hwp) /* set in early_cpuid() */ | ||
| 1206 | return; | ||
| 1207 | |||
| 1208 | /* MSR_PM_ENABLE[1] == 1 if HWP is enabled and MSRs visible */ | ||
| 1209 | get_msr(base_cpu, MSR_PM_ENABLE, &msr); | ||
| 1210 | if ((msr & 1) == 0) { | ||
| 1211 | fprintf(stderr, "HWP can be enabled using '--hwp-enable'\n"); | ||
| 1212 | has_hwp = 0; | ||
| 1213 | return; | ||
| 1214 | } | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | int req_update_bounds_check(void) | ||
| 1218 | { | ||
| 1219 | if (!hwp_update_enabled()) | ||
| 1220 | return 0; | ||
| 1221 | |||
| 1222 | /* fail if min > max requested */ | ||
| 1223 | if ((update_hwp_max && update_hwp_min) && | ||
| 1224 | (req_update.hwp_min > req_update.hwp_max)) { | ||
| 1225 | printf("hwp-min %d > hwp_max %d\n", req_update.hwp_min, req_update.hwp_max); | ||
| 1226 | return -EINVAL; | ||
| 1227 | } | ||
| 1228 | |||
| 1229 | /* fail if desired > max requestd */ | ||
| 1230 | if (req_update.hwp_desired && update_hwp_max && | ||
| 1231 | (req_update.hwp_desired > req_update.hwp_max)) { | ||
| 1232 | printf("hwp-desired cannot be greater than hwp_max\n"); | ||
| 1233 | return -EINVAL; | ||
| 1234 | } | ||
| 1235 | /* fail if desired < min requestd */ | ||
| 1236 | if (req_update.hwp_desired && update_hwp_min && | ||
| 1237 | (req_update.hwp_desired < req_update.hwp_min)) { | ||
| 1238 | printf("hwp-desired cannot be less than hwp_min\n"); | ||
| 1239 | return -EINVAL; | ||
| 1240 | } | ||
| 1241 | |||
| 1242 | return 0; | ||
| 1243 | } | ||
| 1244 | |||
| 1245 | void set_base_cpu(void) | ||
| 1246 | { | ||
| 1247 | base_cpu = sched_getcpu(); | ||
| 1248 | if (base_cpu < 0) | ||
| 1249 | err(-ENODEV, "No valid cpus found"); | ||
| 1250 | } | ||
| 1251 | |||
| 1252 | |||
| 1253 | void probe_dev_msr(void) | ||
| 1254 | { | ||
| 1255 | struct stat sb; | ||
| 1256 | char pathname[32]; | ||
| 1257 | |||
| 1258 | sprintf(pathname, "/dev/cpu/%d/msr", base_cpu); | ||
| 1259 | if (stat(pathname, &sb)) | ||
| 1260 | if (system("/sbin/modprobe msr > /dev/null 2>&1")) | ||
| 1261 | err(-5, "no /dev/cpu/0/msr, Try \"# modprobe msr\" "); | ||
| 1262 | } | ||
| 1263 | /* | ||
| 1264 | * early_cpuid() | ||
| 1265 | * initialize turbo_is_enabled, has_hwp, has_epb | ||
| 1266 | * before cmdline is parsed | ||
| 1267 | */ | ||
| 1268 | void early_cpuid(void) | ||
| 1269 | { | ||
| 1270 | unsigned int eax, ebx, ecx, edx, max_level; | ||
| 1271 | unsigned int fms, family, model; | ||
| 1272 | |||
| 1273 | __get_cpuid(0, &max_level, &ebx, &ecx, &edx); | ||
| 1274 | |||
| 1275 | if (max_level < 6) | ||
| 1276 | errx(1, "Processor not supported\n"); | ||
| 1277 | |||
| 1278 | __get_cpuid(1, &fms, &ebx, &ecx, &edx); | ||
| 1279 | family = (fms >> 8) & 0xf; | ||
| 1280 | model = (fms >> 4) & 0xf; | ||
| 1281 | if (family == 6 || family == 0xf) | ||
| 1282 | model += ((fms >> 16) & 0xf) << 4; | ||
| 1283 | |||
| 1284 | if (model == 0x4F) { | ||
| 1285 | unsigned long long msr; | ||
| 1286 | |||
| 1287 | get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT, &msr); | ||
| 1288 | |||
| 1289 | bdx_highest_ratio = msr & 0xFF; | ||
| 1290 | } | ||
| 1291 | |||
| 1292 | __get_cpuid(0x6, &eax, &ebx, &ecx, &edx); | ||
| 1293 | turbo_is_enabled = (eax >> 1) & 1; | ||
| 1294 | has_hwp = (eax >> 7) & 1; | ||
| 1295 | has_epb = (ecx >> 3) & 1; | ||
| 1296 | } | ||
| 1297 | |||
| 1298 | /* | ||
| 1299 | * parse_cpuid() | ||
| 1300 | * set | ||
| 1301 | * has_hwp, has_hwp_notify, has_hwp_activity_window, has_hwp_epp, has_hwp_request_pkg, has_epb | ||
| 1302 | */ | ||
| 1303 | void parse_cpuid(void) | ||
| 1304 | { | ||
| 1305 | unsigned int eax, ebx, ecx, edx, max_level; | ||
| 1306 | unsigned int fms, family, model, stepping; | ||
| 1307 | |||
| 1308 | eax = ebx = ecx = edx = 0; | ||
| 1309 | |||
| 1310 | __get_cpuid(0, &max_level, &ebx, &ecx, &edx); | ||
| 1311 | |||
| 1312 | if (ebx == 0x756e6547 && edx == 0x49656e69 && ecx == 0x6c65746e) | ||
| 1313 | genuine_intel = 1; | ||
| 1314 | |||
| 1315 | if (debug) | ||
| 1316 | fprintf(stderr, "CPUID(0): %.4s%.4s%.4s ", | ||
| 1317 | (char *)&ebx, (char *)&edx, (char *)&ecx); | ||
| 1318 | |||
| 1319 | __get_cpuid(1, &fms, &ebx, &ecx, &edx); | ||
| 1320 | family = (fms >> 8) & 0xf; | ||
| 1321 | model = (fms >> 4) & 0xf; | ||
| 1322 | stepping = fms & 0xf; | ||
| 1323 | if (family == 6 || family == 0xf) | ||
| 1324 | model += ((fms >> 16) & 0xf) << 4; | ||
| 1325 | |||
| 1326 | if (debug) { | ||
| 1327 | fprintf(stderr, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n", | ||
| 1328 | max_level, family, model, stepping, family, model, stepping); | ||
| 1329 | fprintf(stderr, "CPUID(1): %s %s %s %s %s %s %s %s\n", | ||
| 1330 | ecx & (1 << 0) ? "SSE3" : "-", | ||
| 1331 | ecx & (1 << 3) ? "MONITOR" : "-", | ||
| 1332 | ecx & (1 << 7) ? "EIST" : "-", | ||
| 1333 | ecx & (1 << 8) ? "TM2" : "-", | ||
| 1334 | edx & (1 << 4) ? "TSC" : "-", | ||
| 1335 | edx & (1 << 5) ? "MSR" : "-", | ||
| 1336 | edx & (1 << 22) ? "ACPI-TM" : "-", | ||
| 1337 | edx & (1 << 29) ? "TM" : "-"); | ||
| 1338 | } | ||
| 1339 | |||
| 1340 | if (!(edx & (1 << 5))) | ||
| 1341 | errx(1, "CPUID: no MSR"); | ||
| 1342 | |||
| 1343 | |||
| 1344 | __get_cpuid(0x6, &eax, &ebx, &ecx, &edx); | ||
| 1345 | /* turbo_is_enabled already set */ | ||
| 1346 | /* has_hwp already set */ | ||
| 1347 | has_hwp_notify = eax & (1 << 8); | ||
| 1348 | has_hwp_activity_window = eax & (1 << 9); | ||
| 1349 | has_hwp_epp = eax & (1 << 10); | ||
| 1350 | has_hwp_request_pkg = eax & (1 << 11); | ||
| 1351 | |||
| 1352 | if (!has_hwp_request_pkg && update_hwp_use_pkg) | ||
| 1353 | errx(1, "--hwp-use-pkg is not available on this hardware"); | ||
| 1354 | |||
| 1355 | /* has_epb already set */ | ||
| 1356 | |||
| 1357 | if (debug) | ||
| 1358 | fprintf(stderr, | ||
| 1359 | "CPUID(6): %sTURBO, %sHWP, %sHWPnotify, %sHWPwindow, %sHWPepp, %sHWPpkg, %sEPB\n", | ||
| 1360 | turbo_is_enabled ? "" : "No-", | ||
| 1361 | has_hwp ? "" : "No-", | ||
| 1362 | has_hwp_notify ? "" : "No-", | ||
| 1363 | has_hwp_activity_window ? "" : "No-", | ||
| 1364 | has_hwp_epp ? "" : "No-", | ||
| 1365 | has_hwp_request_pkg ? "" : "No-", | ||
| 1366 | has_epb ? "" : "No-"); | ||
| 1367 | |||
| 1368 | return; /* success */ | ||
| 297 | } | 1369 | } |
| 298 | 1370 | ||
| 299 | int main(int argc, char **argv) | 1371 | int main(int argc, char **argv) |
| 300 | { | 1372 | { |
| 1373 | set_base_cpu(); | ||
| 1374 | probe_dev_msr(); | ||
| 1375 | init_data_structures(); | ||
| 1376 | |||
| 1377 | early_cpuid(); /* initial cpuid parse before cmdline */ | ||
| 1378 | |||
| 301 | cmdline(argc, argv); | 1379 | cmdline(argc, argv); |
| 302 | 1380 | ||
| 303 | if (verbose > 1) | 1381 | if (debug) |
| 304 | printf("x86_energy_perf_policy Nov 24, 2010" | 1382 | print_version(); |
| 305 | " - Len Brown <lenb@kernel.org>\n"); | 1383 | |
| 306 | if (verbose > 1 && !read_only) | 1384 | parse_cpuid(); |
| 307 | printf("new_bias %lld\n", new_bias); | 1385 | |
| 308 | 1386 | /* If CPU-set and PKG-set are not initialized, default to all CPUs */ | |
| 309 | validate_cpuid(); | 1387 | if ((cpu_selected_set == 0) && (pkg_selected_set == 0)) |
| 310 | 1388 | cpu_selected_set = cpu_present_set; | |
| 311 | if (cpu != -1) { | 1389 | |
| 312 | if (read_only) | 1390 | /* |
| 313 | print_msr(cpu); | 1391 | * If HWP is being enabled, do it now, so that subsequent operations |
| 314 | else | 1392 | * that access HWP registers can work. |
| 315 | update_msr(cpu); | 1393 | */ |
| 316 | } else { | 1394 | if (update_hwp_enable) |
| 317 | if (read_only) | 1395 | for_all_cpus_in_set(cpu_setsize, cpu_selected_set, enable_hwp_on_cpu); |
| 318 | for_every_cpu(print_msr); | 1396 | |
| 319 | else | 1397 | /* If HWP present, but disabled, warn and ignore from here forward */ |
| 320 | for_every_cpu(update_msr); | 1398 | verify_hwp_is_enabled(); |
| 1399 | |||
| 1400 | if (req_update_bounds_check()) | ||
| 1401 | return -EINVAL; | ||
| 1402 | |||
| 1403 | /* display information only, no updates to settings */ | ||
| 1404 | if (!update_epb && !update_turbo && !hwp_update_enabled()) { | ||
| 1405 | if (cpu_selected_set) | ||
| 1406 | for_all_cpus_in_set(cpu_setsize, cpu_selected_set, print_cpu_msrs); | ||
| 1407 | |||
| 1408 | if (has_hwp_request_pkg) { | ||
| 1409 | if (pkg_selected_set == 0) | ||
| 1410 | pkg_selected_set = pkg_present_set; | ||
| 1411 | |||
| 1412 | for_packages(pkg_selected_set, print_pkg_msrs); | ||
| 1413 | } | ||
| 1414 | |||
| 1415 | return 0; | ||
| 321 | } | 1416 | } |
| 322 | 1417 | ||
| 1418 | /* update CPU set */ | ||
| 1419 | if (cpu_selected_set) { | ||
| 1420 | for_all_cpus_in_set(cpu_setsize, cpu_selected_set, update_sysfs); | ||
| 1421 | for_all_cpus_in_set(cpu_setsize, cpu_selected_set, update_cpu_msrs); | ||
| 1422 | } else if (pkg_selected_set) | ||
| 1423 | for_packages(pkg_selected_set, update_hwp_request_pkg); | ||
| 1424 | |||
| 323 | return 0; | 1425 | return 0; |
| 324 | } | 1426 | } |
