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 | |
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
-rw-r--r-- | arch/x86/include/asm/msr-index.h | 18 | ||||
-rw-r--r-- | drivers/cpufreq/intel_pstate.c | 34 | ||||
-rw-r--r-- | tools/power/x86/x86_energy_perf_policy/Makefile | 27 | ||||
-rw-r--r-- | tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.8 | 241 | ||||
-rw-r--r-- | tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c | 1504 |
5 files changed, 1527 insertions, 297 deletions
diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 673f9ac50f6d..d8638e2419cc 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h | |||
@@ -249,9 +249,13 @@ | |||
249 | #define HWP_MIN_PERF(x) (x & 0xff) | 249 | #define HWP_MIN_PERF(x) (x & 0xff) |
250 | #define HWP_MAX_PERF(x) ((x & 0xff) << 8) | 250 | #define HWP_MAX_PERF(x) ((x & 0xff) << 8) |
251 | #define HWP_DESIRED_PERF(x) ((x & 0xff) << 16) | 251 | #define HWP_DESIRED_PERF(x) ((x & 0xff) << 16) |
252 | #define HWP_ENERGY_PERF_PREFERENCE(x) ((x & 0xff) << 24) | 252 | #define HWP_ENERGY_PERF_PREFERENCE(x) (((unsigned long long) x & 0xff) << 24) |
253 | #define HWP_ACTIVITY_WINDOW(x) ((x & 0xff3) << 32) | 253 | #define HWP_EPP_PERFORMANCE 0x00 |
254 | #define HWP_PACKAGE_CONTROL(x) ((x & 0x1) << 42) | 254 | #define HWP_EPP_BALANCE_PERFORMANCE 0x80 |
255 | #define HWP_EPP_BALANCE_POWERSAVE 0xC0 | ||
256 | #define HWP_EPP_POWERSAVE 0xFF | ||
257 | #define HWP_ACTIVITY_WINDOW(x) ((unsigned long long)(x & 0xff3) << 32) | ||
258 | #define HWP_PACKAGE_CONTROL(x) ((unsigned long long)(x & 0x1) << 42) | ||
255 | 259 | ||
256 | /* IA32_HWP_STATUS */ | 260 | /* IA32_HWP_STATUS */ |
257 | #define HWP_GUARANTEED_CHANGE(x) (x & 0x1) | 261 | #define HWP_GUARANTEED_CHANGE(x) (x & 0x1) |
@@ -474,9 +478,11 @@ | |||
474 | #define MSR_MISC_PWR_MGMT 0x000001aa | 478 | #define MSR_MISC_PWR_MGMT 0x000001aa |
475 | 479 | ||
476 | #define MSR_IA32_ENERGY_PERF_BIAS 0x000001b0 | 480 | #define MSR_IA32_ENERGY_PERF_BIAS 0x000001b0 |
477 | #define ENERGY_PERF_BIAS_PERFORMANCE 0 | 481 | #define ENERGY_PERF_BIAS_PERFORMANCE 0 |
478 | #define ENERGY_PERF_BIAS_NORMAL 6 | 482 | #define ENERGY_PERF_BIAS_BALANCE_PERFORMANCE 4 |
479 | #define ENERGY_PERF_BIAS_POWERSAVE 15 | 483 | #define ENERGY_PERF_BIAS_NORMAL 6 |
484 | #define ENERGY_PERF_BIAS_BALANCE_POWERSAVE 8 | ||
485 | #define ENERGY_PERF_BIAS_POWERSAVE 15 | ||
480 | 486 | ||
481 | #define MSR_IA32_PACKAGE_THERM_STATUS 0x000001b1 | 487 | #define MSR_IA32_PACKAGE_THERM_STATUS 0x000001b1 |
482 | 488 | ||
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c index b7de5bd76a31..36ba6082d084 100644 --- a/drivers/cpufreq/intel_pstate.c +++ b/drivers/cpufreq/intel_pstate.c | |||
@@ -652,6 +652,12 @@ static const char * const energy_perf_strings[] = { | |||
652 | "power", | 652 | "power", |
653 | NULL | 653 | NULL |
654 | }; | 654 | }; |
655 | static const unsigned int epp_values[] = { | ||
656 | HWP_EPP_PERFORMANCE, | ||
657 | HWP_EPP_BALANCE_PERFORMANCE, | ||
658 | HWP_EPP_BALANCE_POWERSAVE, | ||
659 | HWP_EPP_POWERSAVE | ||
660 | }; | ||
655 | 661 | ||
656 | static int intel_pstate_get_energy_pref_index(struct cpudata *cpu_data) | 662 | static int intel_pstate_get_energy_pref_index(struct cpudata *cpu_data) |
657 | { | 663 | { |
@@ -663,17 +669,14 @@ static int intel_pstate_get_energy_pref_index(struct cpudata *cpu_data) | |||
663 | return epp; | 669 | return epp; |
664 | 670 | ||
665 | if (static_cpu_has(X86_FEATURE_HWP_EPP)) { | 671 | if (static_cpu_has(X86_FEATURE_HWP_EPP)) { |
666 | /* | 672 | if (epp == HWP_EPP_PERFORMANCE) |
667 | * Range: | 673 | return 1; |
668 | * 0x00-0x3F : Performance | 674 | if (epp <= HWP_EPP_BALANCE_PERFORMANCE) |
669 | * 0x40-0x7F : Balance performance | 675 | return 2; |
670 | * 0x80-0xBF : Balance power | 676 | if (epp <= HWP_EPP_BALANCE_POWERSAVE) |
671 | * 0xC0-0xFF : Power | 677 | return 3; |
672 | * The EPP is a 8 bit value, but our ranges restrict the | 678 | else |
673 | * value which can be set. Here only using top two bits | 679 | return 4; |
674 | * effectively. | ||
675 | */ | ||
676 | index = (epp >> 6) + 1; | ||
677 | } else if (static_cpu_has(X86_FEATURE_EPB)) { | 680 | } else if (static_cpu_has(X86_FEATURE_EPB)) { |
678 | /* | 681 | /* |
679 | * Range: | 682 | * Range: |
@@ -711,15 +714,8 @@ static int intel_pstate_set_energy_pref_index(struct cpudata *cpu_data, | |||
711 | 714 | ||
712 | value &= ~GENMASK_ULL(31, 24); | 715 | value &= ~GENMASK_ULL(31, 24); |
713 | 716 | ||
714 | /* | ||
715 | * If epp is not default, convert from index into | ||
716 | * energy_perf_strings to epp value, by shifting 6 | ||
717 | * bits left to use only top two bits in epp. | ||
718 | * The resultant epp need to shifted by 24 bits to | ||
719 | * epp position in MSR_HWP_REQUEST. | ||
720 | */ | ||
721 | if (epp == -EINVAL) | 717 | if (epp == -EINVAL) |
722 | epp = (pref_index - 1) << 6; | 718 | epp = epp_values[pref_index - 1]; |
723 | 719 | ||
724 | value |= (u64)epp << 24; | 720 | value |= (u64)epp << 24; |
725 | ret = wrmsrl_on_cpu(cpu_data->cpu, MSR_HWP_REQUEST, value); | 721 | ret = wrmsrl_on_cpu(cpu_data->cpu, MSR_HWP_REQUEST, value); |
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 | } |