diff options
| -rw-r--r-- | Documentation/ABI/testing/sysfs-devices-system-cpu | 18 | ||||
| -rw-r--r-- | Documentation/admin-guide/pm/intel_epb.rst | 27 | ||||
| -rw-r--r-- | arch/x86/kernel/cpu/intel_epb.c | 93 |
3 files changed, 134 insertions, 4 deletions
diff --git a/Documentation/ABI/testing/sysfs-devices-system-cpu b/Documentation/ABI/testing/sysfs-devices-system-cpu index 9605dbd4b5b5..7f4af7da3fbc 100644 --- a/Documentation/ABI/testing/sysfs-devices-system-cpu +++ b/Documentation/ABI/testing/sysfs-devices-system-cpu | |||
| @@ -518,3 +518,21 @@ Description: Control Symetric Multi Threading (SMT) | |||
| 518 | 518 | ||
| 519 | If control status is "forceoff" or "notsupported" writes | 519 | If control status is "forceoff" or "notsupported" writes |
| 520 | are rejected. | 520 | are rejected. |
| 521 | |||
| 522 | What: /sys/devices/system/cpu/cpu#/power/energy_perf_bias | ||
| 523 | Date: March 2019 | ||
| 524 | Contact: linux-pm@vger.kernel.org | ||
| 525 | Description: Intel Energy and Performance Bias Hint (EPB) | ||
| 526 | |||
| 527 | EPB for the given CPU in a sliding scale 0 - 15, where a value | ||
| 528 | of 0 corresponds to a hint preference for highest performance | ||
| 529 | and a value of 15 corresponds to the maximum energy savings. | ||
| 530 | |||
| 531 | In order to change the EPB value for the CPU, write either | ||
| 532 | a number in the 0 - 15 sliding scale above, or one of the | ||
| 533 | strings: "performance", "balance-performance", "normal", | ||
| 534 | "balance-power", "power" (that represent values reflected by | ||
| 535 | their meaning), to this attribute. | ||
| 536 | |||
| 537 | This attribute is present for all online CPUs supporting the | ||
| 538 | Intel EPB feature. | ||
diff --git a/Documentation/admin-guide/pm/intel_epb.rst b/Documentation/admin-guide/pm/intel_epb.rst index e9cfa7ec5420..d100849edfc4 100644 --- a/Documentation/admin-guide/pm/intel_epb.rst +++ b/Documentation/admin-guide/pm/intel_epb.rst | |||
| @@ -4,3 +4,30 @@ Intel Performance and Energy Bias Hint | |||
| 4 | 4 | ||
| 5 | .. kernel-doc:: arch/x86/kernel/cpu/intel_epb.c | 5 | .. kernel-doc:: arch/x86/kernel/cpu/intel_epb.c |
| 6 | :doc: overview | 6 | :doc: overview |
| 7 | |||
| 8 | Intel Performance and Energy Bias Attribute in ``sysfs`` | ||
| 9 | ======================================================== | ||
| 10 | |||
| 11 | The Intel Performance and Energy Bias Hint (EPB) value for a given (logical) CPU | ||
| 12 | can be checked or updated through a ``sysfs`` attribute (file) under | ||
| 13 | :file:`/sys/devices/system/cpu/cpu<N>/power/`, where the CPU number ``<N>`` | ||
| 14 | is allocated at the system initialization time: | ||
| 15 | |||
| 16 | ``energy_perf_bias`` | ||
| 17 | Shows the current EPB value for the CPU in a sliding scale 0 - 15, where | ||
| 18 | a value of 0 corresponds to a hint preference for highest performance | ||
| 19 | and a value of 15 corresponds to the maximum energy savings. | ||
| 20 | |||
| 21 | In order to update the EPB value for the CPU, this attribute can be | ||
| 22 | written to, either with a number in the 0 - 15 sliding scale above, or | ||
| 23 | with one of the strings: "performance", "balance-performance", "normal", | ||
| 24 | "balance-power", "power" that represent values reflected by their | ||
| 25 | meaning. | ||
| 26 | |||
| 27 | This attribute is present for all online CPUs supporting the EPB | ||
| 28 | feature. | ||
| 29 | |||
| 30 | Note that while the EPB interface to the processor is defined at the logical CPU | ||
| 31 | level, the physical register backing it may be shared by multiple CPUs (for | ||
| 32 | example, SMT siblings or cores in one package). For this reason, updating the | ||
| 33 | EPB value for one CPU may cause the EPB values for other CPUs to change. | ||
diff --git a/arch/x86/kernel/cpu/intel_epb.c b/arch/x86/kernel/cpu/intel_epb.c index 8d53cc88bd22..f4dd73396f28 100644 --- a/arch/x86/kernel/cpu/intel_epb.c +++ b/arch/x86/kernel/cpu/intel_epb.c | |||
| @@ -9,8 +9,12 @@ | |||
| 9 | */ | 9 | */ |
| 10 | 10 | ||
| 11 | #include <linux/cpuhotplug.h> | 11 | #include <linux/cpuhotplug.h> |
| 12 | #include <linux/cpu.h> | ||
| 13 | #include <linux/device.h> | ||
| 12 | #include <linux/kernel.h> | 14 | #include <linux/kernel.h> |
| 15 | #include <linux/string.h> | ||
| 13 | #include <linux/syscore_ops.h> | 16 | #include <linux/syscore_ops.h> |
| 17 | #include <linux/pm.h> | ||
| 14 | 18 | ||
| 15 | #include <asm/cpufeature.h> | 19 | #include <asm/cpufeature.h> |
| 16 | #include <asm/msr.h> | 20 | #include <asm/msr.h> |
| @@ -20,9 +24,9 @@ | |||
| 20 | * | 24 | * |
| 21 | * The Performance and Energy Bias Hint (EPB) allows software to specify its | 25 | * The Performance and Energy Bias Hint (EPB) allows software to specify its |
| 22 | * preference with respect to the power-performance tradeoffs present in the | 26 | * preference with respect to the power-performance tradeoffs present in the |
| 23 | * processor. Generally, the EPB is expected to be set by user space through | 27 | * processor. Generally, the EPB is expected to be set by user space (directly |
| 24 | * the generic MSR interface (with the help of the x86_energy_perf_policy tool), | 28 | * via sysfs or with the help of the x86_energy_perf_policy tool), but there are |
| 25 | * but there are two reasons for the kernel to touch it. | 29 | * two reasons for the kernel to update it. |
| 26 | * | 30 | * |
| 27 | * First, there are systems where the platform firmware resets the EPB during | 31 | * First, there are systems where the platform firmware resets the EPB during |
| 28 | * system-wide transitions from sleep states back into the working state | 32 | * system-wide transitions from sleep states back into the working state |
| @@ -52,6 +56,7 @@ static DEFINE_PER_CPU(u8, saved_epb); | |||
| 52 | 56 | ||
| 53 | #define EPB_MASK 0x0fULL | 57 | #define EPB_MASK 0x0fULL |
| 54 | #define EPB_SAVED 0x10ULL | 58 | #define EPB_SAVED 0x10ULL |
| 59 | #define MAX_EPB EPB_MASK | ||
| 55 | 60 | ||
| 56 | static int intel_epb_save(void) | 61 | static int intel_epb_save(void) |
| 57 | { | 62 | { |
| @@ -97,15 +102,95 @@ static struct syscore_ops intel_epb_syscore_ops = { | |||
| 97 | .resume = intel_epb_restore, | 102 | .resume = intel_epb_restore, |
| 98 | }; | 103 | }; |
| 99 | 104 | ||
| 105 | static const char * const energy_perf_strings[] = { | ||
| 106 | "performance", | ||
| 107 | "balance-performance", | ||
| 108 | "normal", | ||
| 109 | "balance-power", | ||
| 110 | "power" | ||
| 111 | }; | ||
| 112 | static const u8 energ_perf_values[] = { | ||
| 113 | ENERGY_PERF_BIAS_PERFORMANCE, | ||
| 114 | ENERGY_PERF_BIAS_BALANCE_PERFORMANCE, | ||
| 115 | ENERGY_PERF_BIAS_NORMAL, | ||
| 116 | ENERGY_PERF_BIAS_BALANCE_POWERSAVE, | ||
| 117 | ENERGY_PERF_BIAS_POWERSAVE | ||
| 118 | }; | ||
| 119 | |||
| 120 | static ssize_t energy_perf_bias_show(struct device *dev, | ||
| 121 | struct device_attribute *attr, | ||
| 122 | char *buf) | ||
| 123 | { | ||
| 124 | unsigned int cpu = dev->id; | ||
| 125 | u64 epb; | ||
| 126 | int ret; | ||
| 127 | |||
| 128 | ret = rdmsrl_on_cpu(cpu, MSR_IA32_ENERGY_PERF_BIAS, &epb); | ||
| 129 | if (ret < 0) | ||
| 130 | return ret; | ||
| 131 | |||
| 132 | return sprintf(buf, "%llu\n", epb); | ||
| 133 | } | ||
| 134 | |||
| 135 | static ssize_t energy_perf_bias_store(struct device *dev, | ||
| 136 | struct device_attribute *attr, | ||
| 137 | const char *buf, size_t count) | ||
| 138 | { | ||
| 139 | unsigned int cpu = dev->id; | ||
| 140 | u64 epb, val; | ||
| 141 | int ret; | ||
| 142 | |||
| 143 | ret = __sysfs_match_string(energy_perf_strings, | ||
| 144 | ARRAY_SIZE(energy_perf_strings), buf); | ||
| 145 | if (ret >= 0) | ||
| 146 | val = energ_perf_values[ret]; | ||
| 147 | else if (kstrtou64(buf, 0, &val) || val > MAX_EPB) | ||
| 148 | return -EINVAL; | ||
| 149 | |||
| 150 | ret = rdmsrl_on_cpu(cpu, MSR_IA32_ENERGY_PERF_BIAS, &epb); | ||
| 151 | if (ret < 0) | ||
| 152 | return ret; | ||
| 153 | |||
| 154 | ret = wrmsrl_on_cpu(cpu, MSR_IA32_ENERGY_PERF_BIAS, | ||
| 155 | (epb & ~EPB_MASK) | val); | ||
| 156 | if (ret < 0) | ||
| 157 | return ret; | ||
| 158 | |||
| 159 | return count; | ||
| 160 | } | ||
| 161 | |||
| 162 | static DEVICE_ATTR_RW(energy_perf_bias); | ||
| 163 | |||
| 164 | static struct attribute *intel_epb_attrs[] = { | ||
| 165 | &dev_attr_energy_perf_bias.attr, | ||
| 166 | NULL | ||
| 167 | }; | ||
| 168 | |||
| 169 | static const struct attribute_group intel_epb_attr_group = { | ||
| 170 | .name = power_group_name, | ||
| 171 | .attrs = intel_epb_attrs | ||
| 172 | }; | ||
| 173 | |||
| 100 | static int intel_epb_online(unsigned int cpu) | 174 | static int intel_epb_online(unsigned int cpu) |
| 101 | { | 175 | { |
| 176 | struct device *cpu_dev = get_cpu_device(cpu); | ||
| 177 | |||
| 102 | intel_epb_restore(); | 178 | intel_epb_restore(); |
| 179 | if (!cpuhp_tasks_frozen) | ||
| 180 | sysfs_merge_group(&cpu_dev->kobj, &intel_epb_attr_group); | ||
| 181 | |||
| 103 | return 0; | 182 | return 0; |
| 104 | } | 183 | } |
| 105 | 184 | ||
| 106 | static int intel_epb_offline(unsigned int cpu) | 185 | static int intel_epb_offline(unsigned int cpu) |
| 107 | { | 186 | { |
| 108 | return intel_epb_save(); | 187 | struct device *cpu_dev = get_cpu_device(cpu); |
| 188 | |||
| 189 | if (!cpuhp_tasks_frozen) | ||
| 190 | sysfs_unmerge_group(&cpu_dev->kobj, &intel_epb_attr_group); | ||
| 191 | |||
| 192 | intel_epb_save(); | ||
| 193 | return 0; | ||
| 109 | } | 194 | } |
| 110 | 195 | ||
| 111 | static __init int intel_epb_init(void) | 196 | static __init int intel_epb_init(void) |
