* pm-x86: x86: tsc: Rework time_cpufreq_notifier() admin-guide: pm: intel_epb: Add SPDX license tag and copyright notice PM / arch: x86: MSR_IA32_ENERGY_PERF_BIAS sysfs interface PM / arch: x86: Rework the MSR_IA32_ENERGY_PERF_BIAS handling
Unified · Split
| @@ -518,3 +518,21 @@ Description: Control Symetric Multi Threading (SMT) · 517 unmodified lines | |||
| 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. | ||
| @@ -0,0 +1,41 @@ | |||
| 1 | .. SPDX-License-Identifier: GPL-2.0 | ||
| 2 | .. include:: <isonum.txt> | ||
| 3 | |||
| 4 | ====================================== | ||
| 5 | Intel Performance and Energy Bias Hint | ||
| 6 | ====================================== | ||
| 7 | |||
| 8 | :Copyright: |copy| 2019 Intel Corporation | ||
| 9 | |||
| 10 | :Author: Rafael J. Wysocki <rafael.j.wysocki@intel.com> | ||
| 11 | |||
| 12 | |||
| 13 | .. kernel-doc:: arch/x86/kernel/cpu/intel_epb.c | ||
| 14 | :doc: overview | ||
| 15 | |||
| 16 | Intel Performance and Energy Bias Attribute in ``sysfs`` | ||
| 17 | ======================================================== | ||
| 18 | |||
| 19 | The Intel Performance and Energy Bias Hint (EPB) value for a given (logical) CPU | ||
| 20 | can be checked or updated through a ``sysfs`` attribute (file) under | ||
| 21 | :file:`/sys/devices/system/cpu/cpu<N>/power/`, where the CPU number ``<N>`` | ||
| 22 | is allocated at the system initialization time: | ||
| 23 | |||
| 24 | ``energy_perf_bias`` | ||
| 25 | Shows the current EPB value for the CPU in a sliding scale 0 - 15, where | ||
| 26 | a value of 0 corresponds to a hint preference for highest performance | ||
| 27 | and a value of 15 corresponds to the maximum energy savings. | ||
| 28 | |||
| 29 | In order to update the EPB value for the CPU, this attribute can be | ||
| 30 | written to, either with a number in the 0 - 15 sliding scale above, or | ||
| 31 | with one of the strings: "performance", "balance-performance", "normal", | ||
| 32 | "balance-power", "power" that represent values reflected by their | ||
| 33 | meaning. | ||
| 34 | |||
| 35 | This attribute is present for all online CPUs supporting the EPB | ||
| 36 | feature. | ||
| 37 | |||
| 38 | Note that while the EPB interface to the processor is defined at the logical CPU | ||
| 39 | level, the physical register backing it may be shared by multiple CPUs (for | ||
| 40 | example, SMT siblings or cores in one package). For this reason, updating the | ||
| 41 | EPB value for one CPU may cause the EPB values for other CPUs to change. | ||
| @@ -8,3 +8,4 @@ Working-State Power Management · 7 unmodified lines | |||
| 8 | cpuidle | 8 | cpuidle |
| 9 | cpufreq | 9 | cpufreq |
| 10 | intel_pstate | 10 | intel_pstate |
| 11 | intel_epb | ||
| @@ -28,7 +28,7 @@ obj-y += cpuid-deps.o · 27 unmodified lines | |||
| 28 | obj-$(CONFIG_PROC_FS) += proc.o | 28 | obj-$(CONFIG_PROC_FS) += proc.o |
| 29 | obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o | 29 | obj-$(CONFIG_X86_FEATURE_NAMES) += capflags.o powerflags.o |
| 30 | 30 | ||
| 31 | obj-$(CONFIG_CPU_SUP_INTEL) += intel.o intel_pconfig.o | 31 | obj-$(CONFIG_CPU_SUP_INTEL) += intel.o intel_pconfig.o intel_epb.o |
| 32 | obj-$(CONFIG_CPU_SUP_AMD) += amd.o | 32 | obj-$(CONFIG_CPU_SUP_AMD) += amd.o |
| 33 | obj-$(CONFIG_CPU_SUP_HYGON) += hygon.o | 33 | obj-$(CONFIG_CPU_SUP_HYGON) += hygon.o |
| 34 | obj-$(CONFIG_CPU_SUP_CYRIX_32) += cyrix.o | 34 | obj-$(CONFIG_CPU_SUP_CYRIX_32) += cyrix.o |
| @@ -1864,23 +1864,6 @@ void cpu_init(void) · 1863 unmodified lines | |||
| 1864 | } | 1864 | } |
| 1865 | #endif | 1865 | #endif |
| 1866 | 1866 | ||
| 1867 | static void bsp_resume(void) | ||
| 1868 | { | ||
| 1869 | if (this_cpu->c_bsp_resume) | ||
| 1870 | this_cpu->c_bsp_resume(&boot_cpu_data); | ||
| 1871 | } | ||
| 1872 | |||
| 1873 | static struct syscore_ops cpu_syscore_ops = { | ||
| 1874 | .resume = bsp_resume, | ||
| 1875 | }; | ||
| 1876 | |||
| 1877 | static int __init init_cpu_syscore(void) | ||
| 1878 | { | ||
| 1879 | register_syscore_ops(&cpu_syscore_ops); | ||
| 1880 | return 0; | ||
| 1881 | } | ||
| 1882 | core_initcall(init_cpu_syscore); | ||
| 1883 | |||
| 1884 | /* | 1867 | /* |
| 1885 | * The microcode loader calls this upon late microcode load to recheck features, | 1868 | * The microcode loader calls this upon late microcode load to recheck features, |
| 1886 | * only when microcode has been updated. Caller holds microcode_mutex and CPU | 1869 | * only when microcode has been updated. Caller holds microcode_mutex and CPU |
| @@ -14,7 +14,6 @@ struct cpu_dev { · 13 unmodified lines | |||
| 14 | void (*c_init)(struct cpuinfo_x86 *); | 14 | void (*c_init)(struct cpuinfo_x86 *); |
| 15 | void (*c_identify)(struct cpuinfo_x86 *); | 15 | void (*c_identify)(struct cpuinfo_x86 *); |
| 16 | void (*c_detect_tlb)(struct cpuinfo_x86 *); | 16 | void (*c_detect_tlb)(struct cpuinfo_x86 *); |
| 17 | void (*c_bsp_resume)(struct cpuinfo_x86 *); | ||
| 18 | int c_x86_vendor; | 17 | int c_x86_vendor; |
| 19 | #ifdef CONFIG_X86_32 | 18 | #ifdef CONFIG_X86_32 |
| 20 | /* Optional vendor specific routine to obtain the cache size. */ | 19 | /* Optional vendor specific routine to obtain the cache size. */ |
| @@ -596,36 +596,6 @@ detect_keyid_bits: · 595 unmodified lines | |||
| 596 | c->x86_phys_bits -= keyid_bits; | 596 | c->x86_phys_bits -= keyid_bits; |
| 597 | } | 597 | } |
| 598 | 598 | ||
| 599 | static void init_intel_energy_perf(struct cpuinfo_x86 *c) | ||
| 600 | { | ||
| 601 | u64 epb; | ||
| 602 | |||
| 603 | /* | ||
| 604 | * Initialize MSR_IA32_ENERGY_PERF_BIAS if not already initialized. | ||
| 605 | * (x86_energy_perf_policy(8) is available to change it at run-time.) | ||
| 606 | */ | ||
| 607 | if (!cpu_has(c, X86_FEATURE_EPB)) | ||
| 608 | return; | ||
| 609 | |||
| 610 | rdmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb); | ||
| 611 | if ((epb & 0xF) != ENERGY_PERF_BIAS_PERFORMANCE) | ||
| 612 | return; | ||
| 613 | |||
| 614 | pr_info_once("ENERGY_PERF_BIAS: Set to 'normal', was 'performance'\n"); | ||
| 615 | pr_info_once("ENERGY_PERF_BIAS: View and update with x86_energy_perf_policy(8)\n"); | ||
| 616 | epb = (epb & ~0xF) | ENERGY_PERF_BIAS_NORMAL; | ||
| 617 | wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb); | ||
| 618 | } | ||
| 619 | |||
| 620 | static void intel_bsp_resume(struct cpuinfo_x86 *c) | ||
| 621 | { | ||
| 622 | /* | ||
| 623 | * MSR_IA32_ENERGY_PERF_BIAS is lost across suspend/resume, | ||
| 624 | * so reinitialize it properly like during bootup: | ||
| 625 | */ | ||
| 626 | init_intel_energy_perf(c); | ||
| 627 | } | ||
| 628 | |||
| 629 | static void init_cpuid_fault(struct cpuinfo_x86 *c) | 599 | static void init_cpuid_fault(struct cpuinfo_x86 *c) |
| 630 | { | 600 | { |
| 631 | u64 msr; | 601 | u64 msr; |
| @@ -763,8 +733,6 @@ static void init_intel(struct cpuinfo_x86 *c) · 131 unmodified lines | |||
| 763 | if (cpu_has(c, X86_FEATURE_TME)) | 733 | if (cpu_has(c, X86_FEATURE_TME)) |
| 764 | detect_tme(c); | 734 | detect_tme(c); |
| 765 | 735 | ||
| 766 | init_intel_energy_perf(c); | ||
| 767 | |||
| 768 | init_intel_misc_features(c); | 736 | init_intel_misc_features(c); |
| 769 | } | 737 | } |
| 770 | 738 | ||
| @@ -1023,9 +991,7 @@ static const struct cpu_dev intel_cpu_dev = { · 252 unmodified lines | |||
| 1023 | .c_detect_tlb = intel_detect_tlb, | 991 | .c_detect_tlb = intel_detect_tlb, |
| 1024 | .c_early_init = early_init_intel, | 992 | .c_early_init = early_init_intel, |
| 1025 | .c_init = init_intel, | 993 | .c_init = init_intel, |
| 1026 | .c_bsp_resume = intel_bsp_resume, | ||
| 1027 | .c_x86_vendor = X86_VENDOR_INTEL, | 994 | .c_x86_vendor = X86_VENDOR_INTEL, |
| 1028 | }; | 995 | }; |
| 1029 | 996 | ||
| 1030 | cpu_dev_register(intel_cpu_dev); | 997 | cpu_dev_register(intel_cpu_dev); |
| 1031 | |||
| @@ -0,0 +1,216 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* | ||
| 3 | * Intel Performance and Energy Bias Hint support. | ||
| 4 | * | ||
| 5 | * Copyright (C) 2019 Intel Corporation | ||
| 6 | * | ||
| 7 | * Author: | ||
| 8 | * Rafael J. Wysocki <rafael.j.wysocki@intel.com> | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/cpuhotplug.h> | ||
| 12 | #include <linux/cpu.h> | ||
| 13 | #include <linux/device.h> | ||
| 14 | #include <linux/kernel.h> | ||
| 15 | #include <linux/string.h> | ||
| 16 | #include <linux/syscore_ops.h> | ||
| 17 | #include <linux/pm.h> | ||
| 18 | |||
| 19 | #include <asm/cpufeature.h> | ||
| 20 | #include <asm/msr.h> | ||
| 21 | |||
| 22 | /** | ||
| 23 | * DOC: overview | ||
| 24 | * | ||
| 25 | * The Performance and Energy Bias Hint (EPB) allows software to specify its | ||
| 26 | * preference with respect to the power-performance tradeoffs present in the | ||
| 27 | * processor. Generally, the EPB is expected to be set by user space (directly | ||
| 28 | * via sysfs or with the help of the x86_energy_perf_policy tool), but there are | ||
| 29 | * two reasons for the kernel to update it. | ||
| 30 | * | ||
| 31 | * First, there are systems where the platform firmware resets the EPB during | ||
| 32 | * system-wide transitions from sleep states back into the working state | ||
| 33 | * effectively causing the previous EPB updates by user space to be lost. | ||
| 34 | * Thus the kernel needs to save the current EPB values for all CPUs during | ||
| 35 | * system-wide transitions to sleep states and restore them on the way back to | ||
| 36 | * the working state. That can be achieved by saving EPB for secondary CPUs | ||
| 37 | * when they are taken offline during transitions into system sleep states and | ||
| 38 | * for the boot CPU in a syscore suspend operation, so that it can be restored | ||
| 39 | * for the boot CPU in a syscore resume operation and for the other CPUs when | ||
| 40 | * they are brought back online. However, CPUs that are already offline when | ||
| 41 | * a system-wide PM transition is started are not taken offline again, but their | ||
| 42 | * EPB values may still be reset by the platform firmware during the transition, | ||
| 43 | * so in fact it is necessary to save the EPB of any CPU taken offline and to | ||
| 44 | * restore it when the given CPU goes back online at all times. | ||
| 45 | * | ||
| 46 | * Second, on many systems the initial EPB value coming from the platform | ||
| 47 | * firmware is 0 ('performance') and at least on some of them that is because | ||
| 48 | * the platform firmware does not initialize EPB at all with the assumption that | ||
| 49 | * the OS will do that anyway. That sometimes is problematic, as it may cause | ||
| 50 | * the system battery to drain too fast, for example, so it is better to adjust | ||
| 51 | * it on CPU bring-up and if the initial EPB value for a given CPU is 0, the | ||
| 52 | * kernel changes it to 6 ('normal'). | ||
| 53 | */ | ||
| 54 | |||
| 55 | static DEFINE_PER_CPU(u8, saved_epb); | ||
| 56 | |||
| 57 | #define EPB_MASK 0x0fULL | ||
| 58 | #define EPB_SAVED 0x10ULL | ||
| 59 | #define MAX_EPB EPB_MASK | ||
| 60 | |||
| 61 | static int intel_epb_save(void) | ||
| 62 | { | ||
| 63 | u64 epb; | ||
| 64 | |||
| 65 | rdmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb); | ||
| 66 | /* | ||
| 67 | * Ensure that saved_epb will always be nonzero after this write even if | ||
| 68 | * the EPB value read from the MSR is 0. | ||
| 69 | */ | ||
| 70 | this_cpu_write(saved_epb, (epb & EPB_MASK) | EPB_SAVED); | ||
| 71 | |||
| 72 | return 0; | ||
| 73 | } | ||
| 74 | |||
| 75 | static void intel_epb_restore(void) | ||
| 76 | { | ||
| 77 | u64 val = this_cpu_read(saved_epb); | ||
| 78 | u64 epb; | ||
| 79 | |||
| 80 | rdmsrl(MSR_IA32_ENERGY_PERF_BIAS, epb); | ||
| 81 | if (val) { | ||
| 82 | val &= EPB_MASK; | ||
| 83 | } else { | ||
| 84 | /* | ||
| 85 | * Because intel_epb_save() has not run for the current CPU yet, | ||
| 86 | * it is going online for the first time, so if its EPB value is | ||
| 87 | * 0 ('performance') at this point, assume that it has not been | ||
| 88 | * initialized by the platform firmware and set it to 6 | ||
| 89 | * ('normal'). | ||
| 90 | */ | ||
| 91 | val = epb & EPB_MASK; | ||
| 92 | if (val == ENERGY_PERF_BIAS_PERFORMANCE) { | ||
| 93 | val = ENERGY_PERF_BIAS_NORMAL; | ||
| 94 | pr_warn_once("ENERGY_PERF_BIAS: Set to 'normal', was 'performance'\n"); | ||
| 95 | } | ||
| 96 | } | ||
| 97 | wrmsrl(MSR_IA32_ENERGY_PERF_BIAS, (epb & ~EPB_MASK) | val); | ||
| 98 | } | ||
| 99 | |||
| 100 | static struct syscore_ops intel_epb_syscore_ops = { | ||
| 101 | .suspend = intel_epb_save, | ||
| 102 | .resume = intel_epb_restore, | ||
| 103 | }; | ||
| 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 | |||
| 174 | static int intel_epb_online(unsigned int cpu) | ||
| 175 | { | ||
| 176 | struct device *cpu_dev = get_cpu_device(cpu); | ||
| 177 | |||
| 178 | intel_epb_restore(); | ||
| 179 | if (!cpuhp_tasks_frozen) | ||
| 180 | sysfs_merge_group(&cpu_dev->kobj, &intel_epb_attr_group); | ||
| 181 | |||
| 182 | return 0; | ||
| 183 | } | ||
| 184 | |||
| 185 | static int intel_epb_offline(unsigned int cpu) | ||
| 186 | { | ||
| 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; | ||
| 194 | } | ||
| 195 | |||
| 196 | static __init int intel_epb_init(void) | ||
| 197 | { | ||
| 198 | int ret; | ||
| 199 | |||
| 200 | if (!boot_cpu_has(X86_FEATURE_EPB)) | ||
| 201 | return -ENODEV; | ||
| 202 | |||
| 203 | ret = cpuhp_setup_state(CPUHP_AP_X86_INTEL_EPB_ONLINE, | ||
| 204 | "x86/intel/epb:online", intel_epb_online, | ||
| 205 | intel_epb_offline); | ||
| 206 | if (ret < 0) | ||
| 207 | goto err_out_online; | ||
| 208 | |||
| 209 | register_syscore_ops(&intel_epb_syscore_ops); | ||
| 210 | return 0; | ||
| 211 | |||
| 212 | err_out_online: | ||
| 213 | cpuhp_remove_state(CPUHP_AP_X86_INTEL_EPB_ONLINE); | ||
| 214 | return ret; | ||
| 215 | } | ||
| 216 | subsys_initcall(intel_epb_init); | ||
| @@ -185,8 +185,7 @@ static void __init cyc2ns_init_boot_cpu(void) · 184 unmodified lines | |||
| 185 | /* | 185 | /* |
| 186 | * Secondary CPUs do not run through tsc_init(), so set up | 186 | * Secondary CPUs do not run through tsc_init(), so set up |
| 187 | * all the scale factors for all CPUs, assuming the same | 187 | * all the scale factors for all CPUs, assuming the same |
| 188 | * speed as the bootup CPU. (cpufreq notifiers will fix this | 188 | * speed as the bootup CPU. |
| 189 | * up if their speed diverges) | ||
| 190 | */ | 189 | */ |
| 191 | static void __init cyc2ns_init_secondary_cpus(void) | 190 | static void __init cyc2ns_init_secondary_cpus(void) |
| 192 | { | 191 | { |
| @@ -937,12 +936,12 @@ void tsc_restore_sched_clock_state(void) · 744 unmodified lines | |||
| 937 | } | 936 | } |
| 938 | 937 | ||
| 939 | #ifdef CONFIG_CPU_FREQ | 938 | #ifdef CONFIG_CPU_FREQ |
| 940 | /* Frequency scaling support. Adjust the TSC based timer when the cpu frequency | 939 | /* |
| 940 | * Frequency scaling support. Adjust the TSC based timer when the CPU frequency | ||
| 941 | * changes. | 941 | * changes. |
| 942 | * | 942 | * |
| 943 | * RED-PEN: On SMP we assume all CPUs run with the same frequency. It's | 943 | * NOTE: On SMP the situation is not fixable in general, so simply mark the TSC |
| 944 | * not that important because current Opteron setups do not support | 944 | * as unstable and give up in those cases. |
| 945 | * scaling on SMP anyroads. | ||
| 946 | * | 945 | * |
| 947 | * Should fix up last_tsc too. Currently gettimeofday in the | 946 | * Should fix up last_tsc too. Currently gettimeofday in the |
| 948 | * first tick after the change will be slightly wrong. | 947 | * first tick after the change will be slightly wrong. |
| @@ -956,22 +955,22 @@ static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val, · 7 unmodified lines | |||
| 956 | void *data) | 955 | void *data) |
| 957 | { | 956 | { |
| 958 | struct cpufreq_freqs *freq = data; | 957 | struct cpufreq_freqs *freq = data; |
| 959 | unsigned long *lpj; | ||
| 960 | 958 | ||
| 961 | lpj = &boot_cpu_data.loops_per_jiffy; | 959 | if (num_online_cpus() > 1) { |
| 962 | #ifdef CONFIG_SMP | 960 | mark_tsc_unstable("cpufreq changes on SMP"); |
| 963 | if (!(freq->flags & CPUFREQ_CONST_LOOPS)) | 961 | return 0; |
| 964 | lpj = &cpu_data(freq->cpu).loops_per_jiffy; | 962 | } |
| 965 | #endif | ||
| 966 | 963 | ||
| 967 | if (!ref_freq) { | 964 | if (!ref_freq) { |
| 968 | ref_freq = freq->old; | 965 | ref_freq = freq->old; |
| 969 | loops_per_jiffy_ref = *lpj; | 966 | loops_per_jiffy_ref = boot_cpu_data.loops_per_jiffy; |
| 970 | tsc_khz_ref = tsc_khz; | 967 | tsc_khz_ref = tsc_khz; |
| 971 | } | 968 | } |
| 969 | |||
| 972 | if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || | 970 | if ((val == CPUFREQ_PRECHANGE && freq->old < freq->new) || |
| 973 | (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { | 971 | (val == CPUFREQ_POSTCHANGE && freq->old > freq->new)) { |
| 974 | *lpj = cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new); | 972 | boot_cpu_data.loops_per_jiffy = |
| 973 | cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new); | ||
| 975 | 974 | ||
| 976 | tsc_khz = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new); | 975 | tsc_khz = cpufreq_scale(tsc_khz_ref, ref_freq, freq->new); |
| 977 | if (!(freq->flags & CPUFREQ_CONST_LOOPS)) | 976 | if (!(freq->flags & CPUFREQ_CONST_LOOPS)) |
| @@ -147,6 +147,7 @@ enum cpuhp_state { · 146 unmodified lines | |||
| 147 | CPUHP_AP_X86_VDSO_VMA_ONLINE, | 147 | CPUHP_AP_X86_VDSO_VMA_ONLINE, |
| 148 | CPUHP_AP_IRQ_AFFINITY_ONLINE, | 148 | CPUHP_AP_IRQ_AFFINITY_ONLINE, |
| 149 | CPUHP_AP_ARM_MVEBU_SYNC_CLOCKS, | 149 | CPUHP_AP_ARM_MVEBU_SYNC_CLOCKS, |
| 150 | CPUHP_AP_X86_INTEL_EPB_ONLINE, | ||
| 150 | CPUHP_AP_PERF_ONLINE, | 151 | CPUHP_AP_PERF_ONLINE, |
| 151 | CPUHP_AP_PERF_X86_ONLINE, | 152 | CPUHP_AP_PERF_X86_ONLINE, |
| 152 | CPUHP_AP_PERF_X86_UNCORE_ONLINE, | 153 | CPUHP_AP_PERF_X86_UNCORE_ONLINE, |