mirror of
https://github.com/torvalds/linux.git
synced 2024-10-22 21:20:52 +00:00
Power management updates for 6.12-rc1
- Remove LATENCY_MULTIPLIER from cpufreq (Qais Yousef). - Add support for Granite Rapids and Sierra Forest in OOB mode to the intel_pstate cpufreq driver (Srinivas Pandruvada). - Add basic support for CPU capacity scaling on x86 and make the intel_pstate driver set asymmetric CPU capacity on hybrid systems without SMT (Rafael Wysocki). - Add missing MODULE_DESCRIPTION() macros to the powerpc cpufreq driver (Jeff Johnson). - Several OF related cleanups in cpufreq drivers (Rob Herring). - Enable COMPILE_TEST for ARM drivers (Rob Herrring). - Introduce quirks for syscon failures and use socinfo to get revision for TI cpufreq driver (Dhruva Gole, Nishanth Menon). - Minor cleanups in amd-pstate driver (Anastasia Belova, Dhananjay Ugwekar). - Minor cleanups for loongson, cpufreq-dt and powernv cpufreq drivers (Danila Tikhonov, Huacai Chen, and Liu Jing). - Make amd-pstate validate return of any attempt to update EPP limits, which fixes the masking hardware problems (Mario Limonciello). - Move the calculation of the AMD boost numerator outside of amd-pstate, correcting acpi-cpufreq on systems with preferred cores (Mario Limonciello). - Harden preferred core detection in amd-pstate to avoid potential false positives (Mario Limonciello). - Add extra unit test coverage for mode state machine (Mario Limonciello). - Fix an "Uninitialized variables" issue in amd-pstste (Qianqiang Liu). - Add Granite Rapids Xeon support to intel_idle (Artem Bityutskiy). - Disable promotion to C1E on Jasper Lake and Elkhart Lake in intel_idle (Kai-Heng Feng). - Use scoped device node handling to fix missing of_node_put() and simplify walking OF children in the riscv-sbi cpuidle driver (Krzysztof Kozlowski). - Remove dead code from cpuidle_enter_state() (Dhruva Gole). - Change an error pointer to NULL to fix error handling in the intel_rapl power capping driver (Dan Carpenter). - Fix off by one in get_rpi() in the intel_rapl power capping driver (Dan Carpenter). - Add support for ArrowLake-U to the intel_rapl power capping driver (Sumeet Pawnikar). - Fix the energy-pkg event for AMD CPUs in the intel_rapl power capping driver (Dhananjay Ugwekar). - Add support for AMD family 1Ah processors to the intel_rapl power capping driver (Dhananjay Ugwekar). - Remove unused stub for saveable_highmem_page() and remove deprecated macros from power management documentation (Andy Shevchenko). - Use ysfs_emit() and sysfs_emit_at() in "show" functions in the PM sysfs interface (Xueqin Luo). - Update the maintainers information for the operating-points-v2-ti-cpu DT binding (Dhruva Gole). - Drop unnecessary of_match_ptr() from ti-opp-supply (Rob Herring). - Add missing MODULE_DESCRIPTION() macros to devfreq governors (Jeff Johnson). - Use devm_clk_get_enabled() in the exynos-bus devfreq driver (Anand Moon). - Use of_property_present() instead of of_get_property() in the imx-bus devfreq driver (Rob Herring). - Update directory handling and installation process in the pm-graph Makefile and add .gitignore to ignore sleepgraph.py artifacts to pm-graph (Amit Vadhavana, Yo-Jung Lin). - Make cpupower display residency value in idle-info (Aboorva Devarajan). - Add missing powercap_set_enabled() stub function to cpupower (John B. Wyatt IV). - Add SWIG support to cpupower (John B. Wyatt IV). -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEE4fcc61cGeeHD/fCwgsRv/nhiVHEFAmbjKEQSHHJqd0Byand5 c29ja2kubmV0AAoJEILEb/54YlRx8g8P/1RqL6NuCxH4eobwZigeyBS6/sLHPmKo wqHcerZsU7EH8DOlmBU0SH1Br2WBQAbaP8d1ukT5qkGBrZ+IM/A2ipZct0yAHH2D aBKwg7V3LvXo2mPuLve0knpM6W7zibPHJJlcjh8DmGQJabhWO7jr+p/0eS4JE2ek iE5FCXTxhvbcNJ9yWSt7+3HHmvj74P81As7txysLSzhWSZDcqXb0XJRgVJnWDt+x OyTAMEEAY2BuqmijHzqxxHcA1fxOBK/pa9yfPdKP7ePynLnpP7xd9A5oLbXQ4BL9 PHqpD06ZBdSMQzKkyCODypZt8PL+FcEALE4u9chV/nzVwp7TrtDneXWA7RA0GXgq mp9hm51GmdptRayePR3s4TCA6a2BUw3Ue4fgs6XF/bexNpc3nx0wtP8HEevcuy8q Z7XQkpqW942vOohfoN42JwTjfDJhYTwSH3dcIY8UghHtzwZ5YKV1M4f97kNR7V2i QLJvaGJ5yTTcaHndkpc4EKknPyLRaWPh8h/yVmMRBcAaGBWaImul3a5NI07f0wLM LTenlpEcls7WSu9n3uvFXvT7nSS2CBV0huTbg449X4T2J0T6EooYsVuHNsFMNFLy Xm3lUtdm5QjAXFf+azOCO+26XQt8wObC0ttZtCC2j1b8D+9Riuwh5QHLr99rRTzn 7Ic4U5Lkimzx =JM+K -----END PGP SIGNATURE----- Merge tag 'pm-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull power management updates from Rafael Wysocki: "By the number of new lines of code, the most visible change here is the addition of hybrid CPU capacity scaling support to the intel_pstate driver. Next are the amd-pstate driver changes related to the calculation of the AMD boost numerator and preferred core detection. As far as new hardware support is concerned, the intel_idle driver will now handle Granite Rapids Xeon processors natively, the intel_rapl power capping driver will recognize family 1Ah of AMD processors and Intel ArrowLake-U chipos, and intel_pstate will handle Granite Rapids and Sierra Forest chips in the out-of-band (OOB) mode. Apart from the above, there is a usual collection of assorted fixes and code cleanups in many places and there are tooling updates. Specifics: - Remove LATENCY_MULTIPLIER from cpufreq (Qais Yousef) - Add support for Granite Rapids and Sierra Forest in OOB mode to the intel_pstate cpufreq driver (Srinivas Pandruvada) - Add basic support for CPU capacity scaling on x86 and make the intel_pstate driver set asymmetric CPU capacity on hybrid systems without SMT (Rafael Wysocki) - Add missing MODULE_DESCRIPTION() macros to the powerpc cpufreq driver (Jeff Johnson) - Several OF related cleanups in cpufreq drivers (Rob Herring) - Enable COMPILE_TEST for ARM drivers (Rob Herrring) - Introduce quirks for syscon failures and use socinfo to get revision for TI cpufreq driver (Dhruva Gole, Nishanth Menon) - Minor cleanups in amd-pstate driver (Anastasia Belova, Dhananjay Ugwekar) - Minor cleanups for loongson, cpufreq-dt and powernv cpufreq drivers (Danila Tikhonov, Huacai Chen, and Liu Jing) - Make amd-pstate validate return of any attempt to update EPP limits, which fixes the masking hardware problems (Mario Limonciello) - Move the calculation of the AMD boost numerator outside of amd-pstate, correcting acpi-cpufreq on systems with preferred cores (Mario Limonciello) - Harden preferred core detection in amd-pstate to avoid potential false positives (Mario Limonciello) - Add extra unit test coverage for mode state machine (Mario Limonciello) - Fix an "Uninitialized variables" issue in amd-pstste (Qianqiang Liu) - Add Granite Rapids Xeon support to intel_idle (Artem Bityutskiy) - Disable promotion to C1E on Jasper Lake and Elkhart Lake in intel_idle (Kai-Heng Feng) - Use scoped device node handling to fix missing of_node_put() and simplify walking OF children in the riscv-sbi cpuidle driver (Krzysztof Kozlowski) - Remove dead code from cpuidle_enter_state() (Dhruva Gole) - Change an error pointer to NULL to fix error handling in the intel_rapl power capping driver (Dan Carpenter) - Fix off by one in get_rpi() in the intel_rapl power capping driver (Dan Carpenter) - Add support for ArrowLake-U to the intel_rapl power capping driver (Sumeet Pawnikar) - Fix the energy-pkg event for AMD CPUs in the intel_rapl power capping driver (Dhananjay Ugwekar) - Add support for AMD family 1Ah processors to the intel_rapl power capping driver (Dhananjay Ugwekar) - Remove unused stub for saveable_highmem_page() and remove deprecated macros from power management documentation (Andy Shevchenko) - Use ysfs_emit() and sysfs_emit_at() in "show" functions in the PM sysfs interface (Xueqin Luo) - Update the maintainers information for the operating-points-v2-ti-cpu DT binding (Dhruva Gole) - Drop unnecessary of_match_ptr() from ti-opp-supply (Rob Herring) - Add missing MODULE_DESCRIPTION() macros to devfreq governors (Jeff Johnson) - Use devm_clk_get_enabled() in the exynos-bus devfreq driver (Anand Moon) - Use of_property_present() instead of of_get_property() in the imx-bus devfreq driver (Rob Herring) - Update directory handling and installation process in the pm-graph Makefile and add .gitignore to ignore sleepgraph.py artifacts to pm-graph (Amit Vadhavana, Yo-Jung Lin) - Make cpupower display residency value in idle-info (Aboorva Devarajan) - Add missing powercap_set_enabled() stub function to cpupower (John B. Wyatt IV) - Add SWIG support to cpupower (John B. Wyatt IV)" * tag 'pm-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (62 commits) cpufreq/amd-pstate-ut: Fix an "Uninitialized variables" issue cpufreq/amd-pstate-ut: Add test case for mode switches cpufreq/amd-pstate: Export symbols for changing modes amd-pstate: Add missing documentation for `amd_pstate_prefcore_ranking` cpufreq: amd-pstate: Add documentation for `amd_pstate_hw_prefcore` cpufreq: amd-pstate: Optimize amd_pstate_update_limits() cpufreq: amd-pstate: Merge amd_pstate_highest_perf_set() into amd_get_boost_ratio_numerator() x86/amd: Detect preferred cores in amd_get_boost_ratio_numerator() x86/amd: Move amd_get_highest_perf() out of amd-pstate ACPI: CPPC: Adjust debug messages in amd_set_max_freq_ratio() to warn ACPI: CPPC: Drop check for non zero perf ratio x86/amd: Rename amd_get_highest_perf() to amd_get_boost_ratio_numerator() ACPI: CPPC: Adjust return code for inline functions in !CONFIG_ACPI_CPPC_LIB x86/amd: Move amd_get_highest_perf() from amd.c to cppc.c PM: hibernate: Remove unused stub for saveable_highmem_page() pm:cpupower: Add error warning when SWIG is not installed MAINTAINERS: Add Maintainers for SWIG Python bindings pm:cpupower: Include test_raw_pylibcpupower.py pm:cpupower: Add SWIG bindings files for libcpupower pm:cpupower: Add missing powercap_set_enabled() stub function ...
This commit is contained in:
commit
02824a5fd1
|
@ -251,7 +251,9 @@ performance supported in `AMD CPPC Performance Capability <perf_cap_>`_).
|
||||||
In some ASICs, the highest CPPC performance is not the one in the ``_CPC``
|
In some ASICs, the highest CPPC performance is not the one in the ``_CPC``
|
||||||
table, so we need to expose it to sysfs. If boost is not active, but
|
table, so we need to expose it to sysfs. If boost is not active, but
|
||||||
still supported, this maximum frequency will be larger than the one in
|
still supported, this maximum frequency will be larger than the one in
|
||||||
``cpuinfo``.
|
``cpuinfo``. On systems that support preferred core, the driver will have
|
||||||
|
different values for some cores than others and this will reflect the values
|
||||||
|
advertised by the platform at bootup.
|
||||||
This attribute is read-only.
|
This attribute is read-only.
|
||||||
|
|
||||||
``amd_pstate_lowest_nonlinear_freq``
|
``amd_pstate_lowest_nonlinear_freq``
|
||||||
|
@ -262,6 +264,17 @@ lowest non-linear performance in `AMD CPPC Performance Capability
|
||||||
<perf_cap_>`_.)
|
<perf_cap_>`_.)
|
||||||
This attribute is read-only.
|
This attribute is read-only.
|
||||||
|
|
||||||
|
``amd_pstate_hw_prefcore``
|
||||||
|
|
||||||
|
Whether the platform supports the preferred core feature and it has been
|
||||||
|
enabled. This attribute is read-only.
|
||||||
|
|
||||||
|
``amd_pstate_prefcore_ranking``
|
||||||
|
|
||||||
|
The performance ranking of the core. This number doesn't have any unit, but
|
||||||
|
larger numbers are preferred at the time of reading. This can change at
|
||||||
|
runtime based on platform conditions. This attribute is read-only.
|
||||||
|
|
||||||
``energy_performance_available_preferences``
|
``energy_performance_available_preferences``
|
||||||
|
|
||||||
A list of all the supported EPP preferences that could be used for
|
A list of all the supported EPP preferences that could be used for
|
||||||
|
|
|
@ -19,7 +19,7 @@ description:
|
||||||
the hardware description for the scheme mentioned above.
|
the hardware description for the scheme mentioned above.
|
||||||
|
|
||||||
maintainers:
|
maintainers:
|
||||||
- Nishanth Menon <nm@ti.com>
|
- Dhruva Gole <d-gole@ti.com>
|
||||||
|
|
||||||
allOf:
|
allOf:
|
||||||
- $ref: opp-v2-base.yaml#
|
- $ref: opp-v2-base.yaml#
|
||||||
|
|
|
@ -979,18 +979,17 @@ subsections can be defined as a separate function, it often is convenient to
|
||||||
point two or more members of struct dev_pm_ops to the same routine. There are
|
point two or more members of struct dev_pm_ops to the same routine. There are
|
||||||
a few convenience macros that can be used for this purpose.
|
a few convenience macros that can be used for this purpose.
|
||||||
|
|
||||||
The SIMPLE_DEV_PM_OPS macro declares a struct dev_pm_ops object with one
|
The DEFINE_SIMPLE_DEV_PM_OPS() declares a struct dev_pm_ops object with one
|
||||||
suspend routine pointed to by the .suspend(), .freeze(), and .poweroff()
|
suspend routine pointed to by the .suspend(), .freeze(), and .poweroff()
|
||||||
members and one resume routine pointed to by the .resume(), .thaw(), and
|
members and one resume routine pointed to by the .resume(), .thaw(), and
|
||||||
.restore() members. The other function pointers in this struct dev_pm_ops are
|
.restore() members. The other function pointers in this struct dev_pm_ops are
|
||||||
unset.
|
unset.
|
||||||
|
|
||||||
The UNIVERSAL_DEV_PM_OPS macro is similar to SIMPLE_DEV_PM_OPS, but it
|
The DEFINE_RUNTIME_DEV_PM_OPS() is similar to DEFINE_SIMPLE_DEV_PM_OPS(), but it
|
||||||
additionally sets the .runtime_resume() pointer to the same value as
|
additionally sets the .runtime_resume() pointer to pm_runtime_force_resume()
|
||||||
.resume() (and .thaw(), and .restore()) and the .runtime_suspend() pointer to
|
and the .runtime_suspend() pointer to pm_runtime_force_suspend().
|
||||||
the same value as .suspend() (and .freeze() and .poweroff()).
|
|
||||||
|
|
||||||
The SET_SYSTEM_SLEEP_PM_OPS can be used inside of a declaration of struct
|
The SYSTEM_SLEEP_PM_OPS() can be used inside of a declaration of struct
|
||||||
dev_pm_ops to indicate that one suspend routine is to be pointed to by the
|
dev_pm_ops to indicate that one suspend routine is to be pointed to by the
|
||||||
.suspend(), .freeze(), and .poweroff() members and one resume routine is to
|
.suspend(), .freeze(), and .poweroff() members and one resume routine is to
|
||||||
be pointed to by the .resume(), .thaw(), and .restore() members.
|
be pointed to by the .resume(), .thaw(), and .restore() members.
|
||||||
|
|
|
@ -811,8 +811,8 @@ subsystem-level dev_pm_ops structure.
|
||||||
|
|
||||||
Device drivers that wish to use the same function as a system suspend, freeze,
|
Device drivers that wish to use the same function as a system suspend, freeze,
|
||||||
poweroff and runtime suspend callback, and similarly for system resume, thaw,
|
poweroff and runtime suspend callback, and similarly for system resume, thaw,
|
||||||
restore, and runtime resume, can achieve this with the help of the
|
restore, and runtime resume, can achieve similar behaviour with the help of the
|
||||||
UNIVERSAL_DEV_PM_OPS macro defined in include/linux/pm.h (possibly setting its
|
DEFINE_RUNTIME_DEV_PM_OPS() defined in include/linux/pm_runtime.h (possibly setting its
|
||||||
last argument to NULL).
|
last argument to NULL).
|
||||||
|
|
||||||
8. "No-Callback" Devices
|
8. "No-Callback" Devices
|
||||||
|
|
|
@ -5851,6 +5851,9 @@ CPU POWER MONITORING SUBSYSTEM
|
||||||
M: Thomas Renninger <trenn@suse.com>
|
M: Thomas Renninger <trenn@suse.com>
|
||||||
M: Shuah Khan <shuah@kernel.org>
|
M: Shuah Khan <shuah@kernel.org>
|
||||||
M: Shuah Khan <skhan@linuxfoundation.org>
|
M: Shuah Khan <skhan@linuxfoundation.org>
|
||||||
|
M: John B. Wyatt IV <jwyatt@redhat.com>
|
||||||
|
M: John B. Wyatt IV <sageofredondo@gmail.com>
|
||||||
|
M: John Kacur <jkacur@redhat.com>
|
||||||
L: linux-pm@vger.kernel.org
|
L: linux-pm@vger.kernel.org
|
||||||
S: Maintained
|
S: Maintained
|
||||||
F: tools/power/cpupower/
|
F: tools/power/cpupower/
|
||||||
|
|
|
@ -691,8 +691,6 @@ static inline u32 per_cpu_l2c_id(unsigned int cpu)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_CPU_SUP_AMD
|
#ifdef CONFIG_CPU_SUP_AMD
|
||||||
extern u32 amd_get_highest_perf(void);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Issue a DIV 0/1 insn to clear any division data from previous DIV
|
* Issue a DIV 0/1 insn to clear any division data from previous DIV
|
||||||
* operations.
|
* operations.
|
||||||
|
@ -705,7 +703,6 @@ static __always_inline void amd_clear_divider(void)
|
||||||
|
|
||||||
extern void amd_check_microcode(void);
|
extern void amd_check_microcode(void);
|
||||||
#else
|
#else
|
||||||
static inline u32 amd_get_highest_perf(void) { return 0; }
|
|
||||||
static inline void amd_clear_divider(void) { }
|
static inline void amd_clear_divider(void) { }
|
||||||
static inline void amd_check_microcode(void) { }
|
static inline void amd_check_microcode(void) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -282,9 +282,22 @@ static inline long arch_scale_freq_capacity(int cpu)
|
||||||
}
|
}
|
||||||
#define arch_scale_freq_capacity arch_scale_freq_capacity
|
#define arch_scale_freq_capacity arch_scale_freq_capacity
|
||||||
|
|
||||||
|
bool arch_enable_hybrid_capacity_scale(void);
|
||||||
|
void arch_set_cpu_capacity(int cpu, unsigned long cap, unsigned long max_cap,
|
||||||
|
unsigned long cap_freq, unsigned long base_freq);
|
||||||
|
|
||||||
|
unsigned long arch_scale_cpu_capacity(int cpu);
|
||||||
|
#define arch_scale_cpu_capacity arch_scale_cpu_capacity
|
||||||
|
|
||||||
extern void arch_set_max_freq_ratio(bool turbo_disabled);
|
extern void arch_set_max_freq_ratio(bool turbo_disabled);
|
||||||
extern void freq_invariance_set_perf_ratio(u64 ratio, bool turbo_disabled);
|
extern void freq_invariance_set_perf_ratio(u64 ratio, bool turbo_disabled);
|
||||||
#else
|
#else
|
||||||
|
static inline bool arch_enable_hybrid_capacity_scale(void) { return false; }
|
||||||
|
static inline void arch_set_cpu_capacity(int cpu, unsigned long cap,
|
||||||
|
unsigned long max_cap,
|
||||||
|
unsigned long cap_freq,
|
||||||
|
unsigned long base_freq) { }
|
||||||
|
|
||||||
static inline void arch_set_max_freq_ratio(bool turbo_disabled) { }
|
static inline void arch_set_max_freq_ratio(bool turbo_disabled) { }
|
||||||
static inline void freq_invariance_set_perf_ratio(u64 ratio, bool turbo_disabled) { }
|
static inline void freq_invariance_set_perf_ratio(u64 ratio, bool turbo_disabled) { }
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -9,6 +9,17 @@
|
||||||
#include <asm/processor.h>
|
#include <asm/processor.h>
|
||||||
#include <asm/topology.h>
|
#include <asm/topology.h>
|
||||||
|
|
||||||
|
#define CPPC_HIGHEST_PERF_PERFORMANCE 196
|
||||||
|
#define CPPC_HIGHEST_PERF_PREFCORE 166
|
||||||
|
|
||||||
|
enum amd_pref_core {
|
||||||
|
AMD_PREF_CORE_UNKNOWN = 0,
|
||||||
|
AMD_PREF_CORE_SUPPORTED,
|
||||||
|
AMD_PREF_CORE_UNSUPPORTED,
|
||||||
|
};
|
||||||
|
static enum amd_pref_core amd_pref_core_detected;
|
||||||
|
static u64 boost_numerator;
|
||||||
|
|
||||||
/* Refer to drivers/acpi/cppc_acpi.c for the description of functions */
|
/* Refer to drivers/acpi/cppc_acpi.c for the description of functions */
|
||||||
|
|
||||||
bool cpc_supported_by_cpu(void)
|
bool cpc_supported_by_cpu(void)
|
||||||
|
@ -69,31 +80,30 @@ int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val)
|
||||||
static void amd_set_max_freq_ratio(void)
|
static void amd_set_max_freq_ratio(void)
|
||||||
{
|
{
|
||||||
struct cppc_perf_caps perf_caps;
|
struct cppc_perf_caps perf_caps;
|
||||||
u64 highest_perf, nominal_perf;
|
u64 numerator, nominal_perf;
|
||||||
u64 perf_ratio;
|
u64 perf_ratio;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
rc = cppc_get_perf_caps(0, &perf_caps);
|
rc = cppc_get_perf_caps(0, &perf_caps);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
pr_debug("Could not retrieve perf counters (%d)\n", rc);
|
pr_warn("Could not retrieve perf counters (%d)\n", rc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
highest_perf = amd_get_highest_perf();
|
rc = amd_get_boost_ratio_numerator(0, &numerator);
|
||||||
|
if (rc) {
|
||||||
|
pr_warn("Could not retrieve highest performance (%d)\n", rc);
|
||||||
|
return;
|
||||||
|
}
|
||||||
nominal_perf = perf_caps.nominal_perf;
|
nominal_perf = perf_caps.nominal_perf;
|
||||||
|
|
||||||
if (!highest_perf || !nominal_perf) {
|
if (!nominal_perf) {
|
||||||
pr_debug("Could not retrieve highest or nominal performance\n");
|
pr_warn("Could not retrieve nominal performance\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
perf_ratio = div_u64(highest_perf * SCHED_CAPACITY_SCALE, nominal_perf);
|
|
||||||
/* midpoint between max_boost and max_P */
|
/* midpoint between max_boost and max_P */
|
||||||
perf_ratio = (perf_ratio + SCHED_CAPACITY_SCALE) >> 1;
|
perf_ratio = (div_u64(numerator * SCHED_CAPACITY_SCALE, nominal_perf) + SCHED_CAPACITY_SCALE) >> 1;
|
||||||
if (!perf_ratio) {
|
|
||||||
pr_debug("Non-zero highest/nominal perf values led to a 0 ratio\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
freq_invariance_set_perf_ratio(perf_ratio, false);
|
freq_invariance_set_perf_ratio(perf_ratio, false);
|
||||||
}
|
}
|
||||||
|
@ -116,3 +126,143 @@ void init_freq_invariance_cppc(void)
|
||||||
init_done = true;
|
init_done = true;
|
||||||
mutex_unlock(&freq_invariance_lock);
|
mutex_unlock(&freq_invariance_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the highest performance register value.
|
||||||
|
* @cpu: CPU from which to get highest performance.
|
||||||
|
* @highest_perf: Return address for highest performance value.
|
||||||
|
*
|
||||||
|
* Return: 0 for success, negative error code otherwise.
|
||||||
|
*/
|
||||||
|
int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf)
|
||||||
|
{
|
||||||
|
u64 val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (cpu_feature_enabled(X86_FEATURE_CPPC)) {
|
||||||
|
ret = rdmsrl_safe_on_cpu(cpu, MSR_AMD_CPPC_CAP1, &val);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
val = AMD_CPPC_HIGHEST_PERF(val);
|
||||||
|
} else {
|
||||||
|
ret = cppc_get_highest_perf(cpu, &val);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE_ONCE(*highest_perf, (u32)val);
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(amd_get_highest_perf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* amd_detect_prefcore: Detect if CPUs in the system support preferred cores
|
||||||
|
* @detected: Output variable for the result of the detection.
|
||||||
|
*
|
||||||
|
* Determine whether CPUs in the system support preferred cores. On systems
|
||||||
|
* that support preferred cores, different highest perf values will be found
|
||||||
|
* on different cores. On other systems, the highest perf value will be the
|
||||||
|
* same on all cores.
|
||||||
|
*
|
||||||
|
* The result of the detection will be stored in the 'detected' parameter.
|
||||||
|
*
|
||||||
|
* Return: 0 for success, negative error code otherwise
|
||||||
|
*/
|
||||||
|
int amd_detect_prefcore(bool *detected)
|
||||||
|
{
|
||||||
|
int cpu, count = 0;
|
||||||
|
u64 highest_perf[2] = {0};
|
||||||
|
|
||||||
|
if (WARN_ON(!detected))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
switch (amd_pref_core_detected) {
|
||||||
|
case AMD_PREF_CORE_SUPPORTED:
|
||||||
|
*detected = true;
|
||||||
|
return 0;
|
||||||
|
case AMD_PREF_CORE_UNSUPPORTED:
|
||||||
|
*detected = false;
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for_each_present_cpu(cpu) {
|
||||||
|
u32 tmp;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = amd_get_highest_perf(cpu, &tmp);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
if (!count || (count == 1 && tmp != highest_perf[0]))
|
||||||
|
highest_perf[count++] = tmp;
|
||||||
|
|
||||||
|
if (count == 2)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*detected = (count == 2);
|
||||||
|
boost_numerator = highest_perf[0];
|
||||||
|
|
||||||
|
amd_pref_core_detected = *detected ? AMD_PREF_CORE_SUPPORTED :
|
||||||
|
AMD_PREF_CORE_UNSUPPORTED;
|
||||||
|
|
||||||
|
pr_debug("AMD CPPC preferred core is %ssupported (highest perf: 0x%llx)\n",
|
||||||
|
*detected ? "" : "un", highest_perf[0]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(amd_detect_prefcore);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* amd_get_boost_ratio_numerator: Get the numerator to use for boost ratio calculation
|
||||||
|
* @cpu: CPU to get numerator for.
|
||||||
|
* @numerator: Output variable for numerator.
|
||||||
|
*
|
||||||
|
* Determine the numerator to use for calculating the boost ratio on
|
||||||
|
* a CPU. On systems that support preferred cores, this will be a hardcoded
|
||||||
|
* value. On other systems this will the highest performance register value.
|
||||||
|
*
|
||||||
|
* If booting the system with amd-pstate enabled but preferred cores disabled then
|
||||||
|
* the correct boost numerator will be returned to match hardware capabilities
|
||||||
|
* even if the preferred cores scheduling hints are not enabled.
|
||||||
|
*
|
||||||
|
* Return: 0 for success, negative error code otherwise.
|
||||||
|
*/
|
||||||
|
int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator)
|
||||||
|
{
|
||||||
|
bool prefcore;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = amd_detect_prefcore(&prefcore);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
/* without preferred cores, return the highest perf register value */
|
||||||
|
if (!prefcore) {
|
||||||
|
*numerator = boost_numerator;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For AMD CPUs with Family ID 19H and Model ID range 0x70 to 0x7f,
|
||||||
|
* the highest performance level is set to 196.
|
||||||
|
* https://bugzilla.kernel.org/show_bug.cgi?id=218759
|
||||||
|
*/
|
||||||
|
if (cpu_feature_enabled(X86_FEATURE_ZEN4)) {
|
||||||
|
switch (boot_cpu_data.x86_model) {
|
||||||
|
case 0x70 ... 0x7f:
|
||||||
|
*numerator = CPPC_HIGHEST_PERF_PERFORMANCE;
|
||||||
|
return 0;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*numerator = CPPC_HIGHEST_PERF_PREFCORE;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(amd_get_boost_ratio_numerator);
|
||||||
|
|
|
@ -1190,22 +1190,6 @@ unsigned long amd_get_dr_addr_mask(unsigned int dr)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(amd_get_dr_addr_mask);
|
EXPORT_SYMBOL_GPL(amd_get_dr_addr_mask);
|
||||||
|
|
||||||
u32 amd_get_highest_perf(void)
|
|
||||||
{
|
|
||||||
struct cpuinfo_x86 *c = &boot_cpu_data;
|
|
||||||
|
|
||||||
if (c->x86 == 0x17 && ((c->x86_model >= 0x30 && c->x86_model < 0x40) ||
|
|
||||||
(c->x86_model >= 0x70 && c->x86_model < 0x80)))
|
|
||||||
return 166;
|
|
||||||
|
|
||||||
if (c->x86 == 0x19 && ((c->x86_model >= 0x20 && c->x86_model < 0x30) ||
|
|
||||||
(c->x86_model >= 0x40 && c->x86_model < 0x70)))
|
|
||||||
return 166;
|
|
||||||
|
|
||||||
return 255;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(amd_get_highest_perf);
|
|
||||||
|
|
||||||
static void zenbleed_check_cpu(void *unused)
|
static void zenbleed_check_cpu(void *unused)
|
||||||
{
|
{
|
||||||
struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
|
struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
|
||||||
|
|
|
@ -349,9 +349,89 @@ static DECLARE_WORK(disable_freq_invariance_work,
|
||||||
DEFINE_PER_CPU(unsigned long, arch_freq_scale) = SCHED_CAPACITY_SCALE;
|
DEFINE_PER_CPU(unsigned long, arch_freq_scale) = SCHED_CAPACITY_SCALE;
|
||||||
EXPORT_PER_CPU_SYMBOL_GPL(arch_freq_scale);
|
EXPORT_PER_CPU_SYMBOL_GPL(arch_freq_scale);
|
||||||
|
|
||||||
|
static DEFINE_STATIC_KEY_FALSE(arch_hybrid_cap_scale_key);
|
||||||
|
|
||||||
|
struct arch_hybrid_cpu_scale {
|
||||||
|
unsigned long capacity;
|
||||||
|
unsigned long freq_ratio;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct arch_hybrid_cpu_scale __percpu *arch_cpu_scale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* arch_enable_hybrid_capacity_scale() - Enable hybrid CPU capacity scaling
|
||||||
|
*
|
||||||
|
* Allocate memory for per-CPU data used by hybrid CPU capacity scaling,
|
||||||
|
* initialize it and set the static key controlling its code paths.
|
||||||
|
*
|
||||||
|
* Must be called before arch_set_cpu_capacity().
|
||||||
|
*/
|
||||||
|
bool arch_enable_hybrid_capacity_scale(void)
|
||||||
|
{
|
||||||
|
int cpu;
|
||||||
|
|
||||||
|
if (static_branch_unlikely(&arch_hybrid_cap_scale_key)) {
|
||||||
|
WARN_ONCE(1, "Hybrid CPU capacity scaling already enabled");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
arch_cpu_scale = alloc_percpu(struct arch_hybrid_cpu_scale);
|
||||||
|
if (!arch_cpu_scale)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for_each_possible_cpu(cpu) {
|
||||||
|
per_cpu_ptr(arch_cpu_scale, cpu)->capacity = SCHED_CAPACITY_SCALE;
|
||||||
|
per_cpu_ptr(arch_cpu_scale, cpu)->freq_ratio = arch_max_freq_ratio;
|
||||||
|
}
|
||||||
|
|
||||||
|
static_branch_enable(&arch_hybrid_cap_scale_key);
|
||||||
|
|
||||||
|
pr_info("Hybrid CPU capacity scaling enabled\n");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* arch_set_cpu_capacity() - Set scale-invariance parameters for a CPU
|
||||||
|
* @cpu: Target CPU.
|
||||||
|
* @cap: Capacity of @cpu at its maximum frequency, relative to @max_cap.
|
||||||
|
* @max_cap: System-wide maximum CPU capacity.
|
||||||
|
* @cap_freq: Frequency of @cpu corresponding to @cap.
|
||||||
|
* @base_freq: Frequency of @cpu at which MPERF counts.
|
||||||
|
*
|
||||||
|
* The units in which @cap and @max_cap are expressed do not matter, so long
|
||||||
|
* as they are consistent, because the former is effectively divided by the
|
||||||
|
* latter. Analogously for @cap_freq and @base_freq.
|
||||||
|
*
|
||||||
|
* After calling this function for all CPUs, call arch_rebuild_sched_domains()
|
||||||
|
* to let the scheduler know that capacity-aware scheduling can be used going
|
||||||
|
* forward.
|
||||||
|
*/
|
||||||
|
void arch_set_cpu_capacity(int cpu, unsigned long cap, unsigned long max_cap,
|
||||||
|
unsigned long cap_freq, unsigned long base_freq)
|
||||||
|
{
|
||||||
|
if (static_branch_likely(&arch_hybrid_cap_scale_key)) {
|
||||||
|
WRITE_ONCE(per_cpu_ptr(arch_cpu_scale, cpu)->capacity,
|
||||||
|
div_u64(cap << SCHED_CAPACITY_SHIFT, max_cap));
|
||||||
|
WRITE_ONCE(per_cpu_ptr(arch_cpu_scale, cpu)->freq_ratio,
|
||||||
|
div_u64(cap_freq << SCHED_CAPACITY_SHIFT, base_freq));
|
||||||
|
} else {
|
||||||
|
WARN_ONCE(1, "Hybrid CPU capacity scaling not enabled");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long arch_scale_cpu_capacity(int cpu)
|
||||||
|
{
|
||||||
|
if (static_branch_unlikely(&arch_hybrid_cap_scale_key))
|
||||||
|
return READ_ONCE(per_cpu_ptr(arch_cpu_scale, cpu)->capacity);
|
||||||
|
|
||||||
|
return SCHED_CAPACITY_SCALE;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(arch_scale_cpu_capacity);
|
||||||
|
|
||||||
static void scale_freq_tick(u64 acnt, u64 mcnt)
|
static void scale_freq_tick(u64 acnt, u64 mcnt)
|
||||||
{
|
{
|
||||||
u64 freq_scale;
|
u64 freq_scale, freq_ratio;
|
||||||
|
|
||||||
if (!arch_scale_freq_invariant())
|
if (!arch_scale_freq_invariant())
|
||||||
return;
|
return;
|
||||||
|
@ -359,7 +439,12 @@ static void scale_freq_tick(u64 acnt, u64 mcnt)
|
||||||
if (check_shl_overflow(acnt, 2*SCHED_CAPACITY_SHIFT, &acnt))
|
if (check_shl_overflow(acnt, 2*SCHED_CAPACITY_SHIFT, &acnt))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (check_mul_overflow(mcnt, arch_max_freq_ratio, &mcnt) || !mcnt)
|
if (static_branch_unlikely(&arch_hybrid_cap_scale_key))
|
||||||
|
freq_ratio = READ_ONCE(this_cpu_ptr(arch_cpu_scale)->freq_ratio);
|
||||||
|
else
|
||||||
|
freq_ratio = arch_max_freq_ratio;
|
||||||
|
|
||||||
|
if (check_mul_overflow(mcnt, freq_ratio, &mcnt) || !mcnt)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
freq_scale = div64_u64(acnt, mcnt);
|
freq_scale = div64_u64(acnt, mcnt);
|
||||||
|
|
|
@ -231,9 +231,7 @@ if X86
|
||||||
source "drivers/cpufreq/Kconfig.x86"
|
source "drivers/cpufreq/Kconfig.x86"
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if ARM || ARM64
|
|
||||||
source "drivers/cpufreq/Kconfig.arm"
|
source "drivers/cpufreq/Kconfig.arm"
|
||||||
endif
|
|
||||||
|
|
||||||
if PPC32 || PPC64
|
if PPC32 || PPC64
|
||||||
source "drivers/cpufreq/Kconfig.powerpc"
|
source "drivers/cpufreq/Kconfig.powerpc"
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
|
|
||||||
config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM
|
config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM
|
||||||
tristate "Allwinner nvmem based SUN50I CPUFreq driver"
|
tristate "Allwinner nvmem based SUN50I CPUFreq driver"
|
||||||
depends on ARCH_SUNXI
|
depends on ARCH_SUNXI || COMPILE_TEST
|
||||||
depends on NVMEM_SUNXI_SID
|
depends on NVMEM_SUNXI_SID
|
||||||
select PM_OPP
|
select PM_OPP
|
||||||
help
|
help
|
||||||
|
@ -26,15 +26,17 @@ config ARM_APPLE_SOC_CPUFREQ
|
||||||
|
|
||||||
config ARM_ARMADA_37XX_CPUFREQ
|
config ARM_ARMADA_37XX_CPUFREQ
|
||||||
tristate "Armada 37xx CPUFreq support"
|
tristate "Armada 37xx CPUFreq support"
|
||||||
depends on ARCH_MVEBU && CPUFREQ_DT
|
depends on ARCH_MVEBU || COMPILE_TEST
|
||||||
|
depends on CPUFREQ_DT
|
||||||
help
|
help
|
||||||
This adds the CPUFreq driver support for Marvell Armada 37xx SoCs.
|
This adds the CPUFreq driver support for Marvell Armada 37xx SoCs.
|
||||||
The Armada 37xx PMU supports 4 frequency and VDD levels.
|
The Armada 37xx PMU supports 4 frequency and VDD levels.
|
||||||
|
|
||||||
config ARM_ARMADA_8K_CPUFREQ
|
config ARM_ARMADA_8K_CPUFREQ
|
||||||
tristate "Armada 8K CPUFreq driver"
|
tristate "Armada 8K CPUFreq driver"
|
||||||
depends on ARCH_MVEBU && CPUFREQ_DT
|
depends on ARCH_MVEBU || COMPILE_TEST
|
||||||
select ARMADA_AP_CPU_CLK
|
depends on CPUFREQ_DT
|
||||||
|
select ARMADA_AP_CPU_CLK if COMMON_CLK
|
||||||
help
|
help
|
||||||
This enables the CPUFreq driver support for Marvell
|
This enables the CPUFreq driver support for Marvell
|
||||||
Armada8k SOCs.
|
Armada8k SOCs.
|
||||||
|
@ -56,7 +58,7 @@ config ARM_SCPI_CPUFREQ
|
||||||
config ARM_VEXPRESS_SPC_CPUFREQ
|
config ARM_VEXPRESS_SPC_CPUFREQ
|
||||||
tristate "Versatile Express SPC based CPUfreq driver"
|
tristate "Versatile Express SPC based CPUfreq driver"
|
||||||
depends on ARM_CPU_TOPOLOGY && HAVE_CLK
|
depends on ARM_CPU_TOPOLOGY && HAVE_CLK
|
||||||
depends on ARCH_VEXPRESS_SPC
|
depends on ARCH_VEXPRESS_SPC || COMPILE_TEST
|
||||||
select PM_OPP
|
select PM_OPP
|
||||||
help
|
help
|
||||||
This add the CPUfreq driver support for Versatile Express
|
This add the CPUfreq driver support for Versatile Express
|
||||||
|
@ -75,7 +77,8 @@ config ARM_BRCMSTB_AVS_CPUFREQ
|
||||||
|
|
||||||
config ARM_HIGHBANK_CPUFREQ
|
config ARM_HIGHBANK_CPUFREQ
|
||||||
tristate "Calxeda Highbank-based"
|
tristate "Calxeda Highbank-based"
|
||||||
depends on ARCH_HIGHBANK && CPUFREQ_DT && REGULATOR
|
depends on ARCH_HIGHBANK || COMPILE_TEST
|
||||||
|
depends on CPUFREQ_DT && REGULATOR && PL320_MBOX
|
||||||
default m
|
default m
|
||||||
help
|
help
|
||||||
This adds the CPUFreq driver for Calxeda Highbank SoC
|
This adds the CPUFreq driver for Calxeda Highbank SoC
|
||||||
|
@ -96,7 +99,8 @@ config ARM_IMX6Q_CPUFREQ
|
||||||
|
|
||||||
config ARM_IMX_CPUFREQ_DT
|
config ARM_IMX_CPUFREQ_DT
|
||||||
tristate "Freescale i.MX8M cpufreq support"
|
tristate "Freescale i.MX8M cpufreq support"
|
||||||
depends on ARCH_MXC && CPUFREQ_DT
|
depends on CPUFREQ_DT
|
||||||
|
depends on ARCH_MXC || COMPILE_TEST
|
||||||
help
|
help
|
||||||
This adds cpufreq driver support for Freescale i.MX7/i.MX8M
|
This adds cpufreq driver support for Freescale i.MX7/i.MX8M
|
||||||
series SoCs, based on cpufreq-dt.
|
series SoCs, based on cpufreq-dt.
|
||||||
|
@ -111,7 +115,8 @@ config ARM_KIRKWOOD_CPUFREQ
|
||||||
|
|
||||||
config ARM_MEDIATEK_CPUFREQ
|
config ARM_MEDIATEK_CPUFREQ
|
||||||
tristate "CPU Frequency scaling support for MediaTek SoCs"
|
tristate "CPU Frequency scaling support for MediaTek SoCs"
|
||||||
depends on ARCH_MEDIATEK && REGULATOR
|
depends on ARCH_MEDIATEK || COMPILE_TEST
|
||||||
|
depends on REGULATOR
|
||||||
select PM_OPP
|
select PM_OPP
|
||||||
help
|
help
|
||||||
This adds the CPUFreq driver support for MediaTek SoCs.
|
This adds the CPUFreq driver support for MediaTek SoCs.
|
||||||
|
@ -130,12 +135,12 @@ config ARM_MEDIATEK_CPUFREQ_HW
|
||||||
|
|
||||||
config ARM_OMAP2PLUS_CPUFREQ
|
config ARM_OMAP2PLUS_CPUFREQ
|
||||||
bool "TI OMAP2+"
|
bool "TI OMAP2+"
|
||||||
depends on ARCH_OMAP2PLUS
|
depends on ARCH_OMAP2PLUS || COMPILE_TEST
|
||||||
default ARCH_OMAP2PLUS
|
default ARCH_OMAP2PLUS
|
||||||
|
|
||||||
config ARM_QCOM_CPUFREQ_NVMEM
|
config ARM_QCOM_CPUFREQ_NVMEM
|
||||||
tristate "Qualcomm nvmem based CPUFreq"
|
tristate "Qualcomm nvmem based CPUFreq"
|
||||||
depends on ARCH_QCOM
|
depends on ARCH_QCOM || COMPILE_TEST
|
||||||
depends on NVMEM_QCOM_QFPROM
|
depends on NVMEM_QCOM_QFPROM
|
||||||
depends on QCOM_SMEM
|
depends on QCOM_SMEM
|
||||||
select PM_OPP
|
select PM_OPP
|
||||||
|
@ -166,7 +171,7 @@ config ARM_RASPBERRYPI_CPUFREQ
|
||||||
|
|
||||||
config ARM_S3C64XX_CPUFREQ
|
config ARM_S3C64XX_CPUFREQ
|
||||||
bool "Samsung S3C64XX"
|
bool "Samsung S3C64XX"
|
||||||
depends on CPU_S3C6410
|
depends on CPU_S3C6410 || COMPILE_TEST
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
This adds the CPUFreq driver for Samsung S3C6410 SoC.
|
This adds the CPUFreq driver for Samsung S3C6410 SoC.
|
||||||
|
@ -175,7 +180,7 @@ config ARM_S3C64XX_CPUFREQ
|
||||||
|
|
||||||
config ARM_S5PV210_CPUFREQ
|
config ARM_S5PV210_CPUFREQ
|
||||||
bool "Samsung S5PV210 and S5PC110"
|
bool "Samsung S5PV210 and S5PC110"
|
||||||
depends on CPU_S5PV210
|
depends on CPU_S5PV210 || COMPILE_TEST
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
This adds the CPUFreq driver for Samsung S5PV210 and
|
This adds the CPUFreq driver for Samsung S5PV210 and
|
||||||
|
@ -199,14 +204,15 @@ config ARM_SCMI_CPUFREQ
|
||||||
|
|
||||||
config ARM_SPEAR_CPUFREQ
|
config ARM_SPEAR_CPUFREQ
|
||||||
bool "SPEAr CPUFreq support"
|
bool "SPEAr CPUFreq support"
|
||||||
depends on PLAT_SPEAR
|
depends on PLAT_SPEAR || COMPILE_TEST
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
This adds the CPUFreq driver support for SPEAr SOCs.
|
This adds the CPUFreq driver support for SPEAr SOCs.
|
||||||
|
|
||||||
config ARM_STI_CPUFREQ
|
config ARM_STI_CPUFREQ
|
||||||
tristate "STi CPUFreq support"
|
tristate "STi CPUFreq support"
|
||||||
depends on CPUFREQ_DT && SOC_STIH407
|
depends on CPUFREQ_DT
|
||||||
|
depends on SOC_STIH407 || COMPILE_TEST
|
||||||
help
|
help
|
||||||
This driver uses the generic OPP framework to match the running
|
This driver uses the generic OPP framework to match the running
|
||||||
platform with a predefined set of suitable values. If not provided
|
platform with a predefined set of suitable values. If not provided
|
||||||
|
@ -216,34 +222,38 @@ config ARM_STI_CPUFREQ
|
||||||
|
|
||||||
config ARM_TEGRA20_CPUFREQ
|
config ARM_TEGRA20_CPUFREQ
|
||||||
tristate "Tegra20/30 CPUFreq support"
|
tristate "Tegra20/30 CPUFreq support"
|
||||||
depends on ARCH_TEGRA && CPUFREQ_DT
|
depends on ARCH_TEGRA || COMPILE_TEST
|
||||||
|
depends on CPUFREQ_DT
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
This adds the CPUFreq driver support for Tegra20/30 SOCs.
|
This adds the CPUFreq driver support for Tegra20/30 SOCs.
|
||||||
|
|
||||||
config ARM_TEGRA124_CPUFREQ
|
config ARM_TEGRA124_CPUFREQ
|
||||||
bool "Tegra124 CPUFreq support"
|
bool "Tegra124 CPUFreq support"
|
||||||
depends on ARCH_TEGRA && CPUFREQ_DT
|
depends on ARCH_TEGRA || COMPILE_TEST
|
||||||
|
depends on CPUFREQ_DT
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
This adds the CPUFreq driver support for Tegra124 SOCs.
|
This adds the CPUFreq driver support for Tegra124 SOCs.
|
||||||
|
|
||||||
config ARM_TEGRA186_CPUFREQ
|
config ARM_TEGRA186_CPUFREQ
|
||||||
tristate "Tegra186 CPUFreq support"
|
tristate "Tegra186 CPUFreq support"
|
||||||
depends on ARCH_TEGRA && TEGRA_BPMP
|
depends on ARCH_TEGRA || COMPILE_TEST
|
||||||
|
depends on TEGRA_BPMP
|
||||||
help
|
help
|
||||||
This adds the CPUFreq driver support for Tegra186 SOCs.
|
This adds the CPUFreq driver support for Tegra186 SOCs.
|
||||||
|
|
||||||
config ARM_TEGRA194_CPUFREQ
|
config ARM_TEGRA194_CPUFREQ
|
||||||
tristate "Tegra194 CPUFreq support"
|
tristate "Tegra194 CPUFreq support"
|
||||||
depends on ARCH_TEGRA_194_SOC && TEGRA_BPMP
|
depends on ARCH_TEGRA_194_SOC || (64BIT && COMPILE_TEST)
|
||||||
|
depends on TEGRA_BPMP
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
This adds CPU frequency driver support for Tegra194 SOCs.
|
This adds CPU frequency driver support for Tegra194 SOCs.
|
||||||
|
|
||||||
config ARM_TI_CPUFREQ
|
config ARM_TI_CPUFREQ
|
||||||
bool "Texas Instruments CPUFreq support"
|
bool "Texas Instruments CPUFreq support"
|
||||||
depends on ARCH_OMAP2PLUS || ARCH_K3
|
depends on ARCH_OMAP2PLUS || ARCH_K3 || COMPILE_TEST
|
||||||
default y
|
default y
|
||||||
help
|
help
|
||||||
This driver enables valid OPPs on the running platform based on
|
This driver enables valid OPPs on the running platform based on
|
||||||
|
@ -255,7 +265,7 @@ config ARM_TI_CPUFREQ
|
||||||
|
|
||||||
config ARM_PXA2xx_CPUFREQ
|
config ARM_PXA2xx_CPUFREQ
|
||||||
tristate "Intel PXA2xx CPUfreq driver"
|
tristate "Intel PXA2xx CPUfreq driver"
|
||||||
depends on PXA27x || PXA25x
|
depends on PXA27x || PXA25x || COMPILE_TEST
|
||||||
help
|
help
|
||||||
This add the CPUFreq driver support for Intel PXA2xx SOCs.
|
This add the CPUFreq driver support for Intel PXA2xx SOCs.
|
||||||
|
|
||||||
|
|
|
@ -642,10 +642,16 @@ static u64 get_max_boost_ratio(unsigned int cpu)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
|
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
|
||||||
highest_perf = amd_get_highest_perf();
|
ret = amd_get_boost_ratio_numerator(cpu, &highest_perf);
|
||||||
else
|
if (ret) {
|
||||||
|
pr_debug("CPU%d: Unable to get boost ratio numerator (%d)\n",
|
||||||
|
cpu, ret);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
highest_perf = perf_caps.highest_perf;
|
highest_perf = perf_caps.highest_perf;
|
||||||
|
}
|
||||||
|
|
||||||
nominal_perf = perf_caps.nominal_perf;
|
nominal_perf = perf_caps.nominal_perf;
|
||||||
|
|
||||||
|
|
|
@ -54,12 +54,14 @@ static void amd_pstate_ut_acpi_cpc_valid(u32 index);
|
||||||
static void amd_pstate_ut_check_enabled(u32 index);
|
static void amd_pstate_ut_check_enabled(u32 index);
|
||||||
static void amd_pstate_ut_check_perf(u32 index);
|
static void amd_pstate_ut_check_perf(u32 index);
|
||||||
static void amd_pstate_ut_check_freq(u32 index);
|
static void amd_pstate_ut_check_freq(u32 index);
|
||||||
|
static void amd_pstate_ut_check_driver(u32 index);
|
||||||
|
|
||||||
static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = {
|
static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = {
|
||||||
{"amd_pstate_ut_acpi_cpc_valid", amd_pstate_ut_acpi_cpc_valid },
|
{"amd_pstate_ut_acpi_cpc_valid", amd_pstate_ut_acpi_cpc_valid },
|
||||||
{"amd_pstate_ut_check_enabled", amd_pstate_ut_check_enabled },
|
{"amd_pstate_ut_check_enabled", amd_pstate_ut_check_enabled },
|
||||||
{"amd_pstate_ut_check_perf", amd_pstate_ut_check_perf },
|
{"amd_pstate_ut_check_perf", amd_pstate_ut_check_perf },
|
||||||
{"amd_pstate_ut_check_freq", amd_pstate_ut_check_freq }
|
{"amd_pstate_ut_check_freq", amd_pstate_ut_check_freq },
|
||||||
|
{"amd_pstate_ut_check_driver", amd_pstate_ut_check_driver }
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool get_shared_mem(void)
|
static bool get_shared_mem(void)
|
||||||
|
@ -257,6 +259,43 @@ skip_test:
|
||||||
cpufreq_cpu_put(policy);
|
cpufreq_cpu_put(policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int amd_pstate_set_mode(enum amd_pstate_mode mode)
|
||||||
|
{
|
||||||
|
const char *mode_str = amd_pstate_get_mode_string(mode);
|
||||||
|
|
||||||
|
pr_debug("->setting mode to %s\n", mode_str);
|
||||||
|
|
||||||
|
return amd_pstate_update_status(mode_str, strlen(mode_str));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void amd_pstate_ut_check_driver(u32 index)
|
||||||
|
{
|
||||||
|
enum amd_pstate_mode mode1, mode2 = AMD_PSTATE_DISABLE;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
for (mode1 = AMD_PSTATE_DISABLE; mode1 < AMD_PSTATE_MAX; mode1++) {
|
||||||
|
ret = amd_pstate_set_mode(mode1);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
for (mode2 = AMD_PSTATE_DISABLE; mode2 < AMD_PSTATE_MAX; mode2++) {
|
||||||
|
if (mode1 == mode2)
|
||||||
|
continue;
|
||||||
|
ret = amd_pstate_set_mode(mode2);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
if (ret)
|
||||||
|
pr_warn("%s: failed to update status for %s->%s: %d\n", __func__,
|
||||||
|
amd_pstate_get_mode_string(mode1),
|
||||||
|
amd_pstate_get_mode_string(mode2), ret);
|
||||||
|
|
||||||
|
amd_pstate_ut_cases[index].result = ret ?
|
||||||
|
AMD_PSTATE_UT_RESULT_FAIL :
|
||||||
|
AMD_PSTATE_UT_RESULT_PASS;
|
||||||
|
}
|
||||||
|
|
||||||
static int __init amd_pstate_ut_init(void)
|
static int __init amd_pstate_ut_init(void)
|
||||||
{
|
{
|
||||||
u32 i = 0, arr_size = ARRAY_SIZE(amd_pstate_ut_cases);
|
u32 i = 0, arr_size = ARRAY_SIZE(amd_pstate_ut_cases);
|
||||||
|
|
|
@ -52,26 +52,12 @@
|
||||||
#define AMD_PSTATE_TRANSITION_LATENCY 20000
|
#define AMD_PSTATE_TRANSITION_LATENCY 20000
|
||||||
#define AMD_PSTATE_TRANSITION_DELAY 1000
|
#define AMD_PSTATE_TRANSITION_DELAY 1000
|
||||||
#define AMD_PSTATE_FAST_CPPC_TRANSITION_DELAY 600
|
#define AMD_PSTATE_FAST_CPPC_TRANSITION_DELAY 600
|
||||||
#define CPPC_HIGHEST_PERF_PERFORMANCE 196
|
|
||||||
#define CPPC_HIGHEST_PERF_DEFAULT 166
|
|
||||||
|
|
||||||
#define AMD_CPPC_EPP_PERFORMANCE 0x00
|
#define AMD_CPPC_EPP_PERFORMANCE 0x00
|
||||||
#define AMD_CPPC_EPP_BALANCE_PERFORMANCE 0x80
|
#define AMD_CPPC_EPP_BALANCE_PERFORMANCE 0x80
|
||||||
#define AMD_CPPC_EPP_BALANCE_POWERSAVE 0xBF
|
#define AMD_CPPC_EPP_BALANCE_POWERSAVE 0xBF
|
||||||
#define AMD_CPPC_EPP_POWERSAVE 0xFF
|
#define AMD_CPPC_EPP_POWERSAVE 0xFF
|
||||||
|
|
||||||
/*
|
|
||||||
* enum amd_pstate_mode - driver working mode of amd pstate
|
|
||||||
*/
|
|
||||||
enum amd_pstate_mode {
|
|
||||||
AMD_PSTATE_UNDEFINED = 0,
|
|
||||||
AMD_PSTATE_DISABLE,
|
|
||||||
AMD_PSTATE_PASSIVE,
|
|
||||||
AMD_PSTATE_ACTIVE,
|
|
||||||
AMD_PSTATE_GUIDED,
|
|
||||||
AMD_PSTATE_MAX,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const char * const amd_pstate_mode_string[] = {
|
static const char * const amd_pstate_mode_string[] = {
|
||||||
[AMD_PSTATE_UNDEFINED] = "undefined",
|
[AMD_PSTATE_UNDEFINED] = "undefined",
|
||||||
[AMD_PSTATE_DISABLE] = "disable",
|
[AMD_PSTATE_DISABLE] = "disable",
|
||||||
|
@ -81,6 +67,14 @@ static const char * const amd_pstate_mode_string[] = {
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const char *amd_pstate_get_mode_string(enum amd_pstate_mode mode)
|
||||||
|
{
|
||||||
|
if (mode < 0 || mode >= AMD_PSTATE_MAX)
|
||||||
|
return NULL;
|
||||||
|
return amd_pstate_mode_string[mode];
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(amd_pstate_get_mode_string);
|
||||||
|
|
||||||
struct quirk_entry {
|
struct quirk_entry {
|
||||||
u32 nominal_freq;
|
u32 nominal_freq;
|
||||||
u32 lowest_freq;
|
u32 lowest_freq;
|
||||||
|
@ -372,43 +366,17 @@ static inline int amd_pstate_enable(bool enable)
|
||||||
return static_call(amd_pstate_enable)(enable);
|
return static_call(amd_pstate_enable)(enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
static u32 amd_pstate_highest_perf_set(struct amd_cpudata *cpudata)
|
|
||||||
{
|
|
||||||
struct cpuinfo_x86 *c = &cpu_data(0);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For AMD CPUs with Family ID 19H and Model ID range 0x70 to 0x7f,
|
|
||||||
* the highest performance level is set to 196.
|
|
||||||
* https://bugzilla.kernel.org/show_bug.cgi?id=218759
|
|
||||||
*/
|
|
||||||
if (c->x86 == 0x19 && (c->x86_model >= 0x70 && c->x86_model <= 0x7f))
|
|
||||||
return CPPC_HIGHEST_PERF_PERFORMANCE;
|
|
||||||
|
|
||||||
return CPPC_HIGHEST_PERF_DEFAULT;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int pstate_init_perf(struct amd_cpudata *cpudata)
|
static int pstate_init_perf(struct amd_cpudata *cpudata)
|
||||||
{
|
{
|
||||||
u64 cap1;
|
u64 cap1;
|
||||||
u32 highest_perf;
|
|
||||||
|
|
||||||
int ret = rdmsrl_safe_on_cpu(cpudata->cpu, MSR_AMD_CPPC_CAP1,
|
int ret = rdmsrl_safe_on_cpu(cpudata->cpu, MSR_AMD_CPPC_CAP1,
|
||||||
&cap1);
|
&cap1);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
/* For platforms that do not support the preferred core feature, the
|
WRITE_ONCE(cpudata->highest_perf, AMD_CPPC_HIGHEST_PERF(cap1));
|
||||||
* highest_pef may be configured with 166 or 255, to avoid max frequency
|
WRITE_ONCE(cpudata->max_limit_perf, AMD_CPPC_HIGHEST_PERF(cap1));
|
||||||
* calculated wrongly. we take the AMD_CPPC_HIGHEST_PERF(cap1) value as
|
|
||||||
* the default max perf.
|
|
||||||
*/
|
|
||||||
if (cpudata->hw_prefcore)
|
|
||||||
highest_perf = amd_pstate_highest_perf_set(cpudata);
|
|
||||||
else
|
|
||||||
highest_perf = AMD_CPPC_HIGHEST_PERF(cap1);
|
|
||||||
|
|
||||||
WRITE_ONCE(cpudata->highest_perf, highest_perf);
|
|
||||||
WRITE_ONCE(cpudata->max_limit_perf, highest_perf);
|
|
||||||
WRITE_ONCE(cpudata->nominal_perf, AMD_CPPC_NOMINAL_PERF(cap1));
|
WRITE_ONCE(cpudata->nominal_perf, AMD_CPPC_NOMINAL_PERF(cap1));
|
||||||
WRITE_ONCE(cpudata->lowest_nonlinear_perf, AMD_CPPC_LOWNONLIN_PERF(cap1));
|
WRITE_ONCE(cpudata->lowest_nonlinear_perf, AMD_CPPC_LOWNONLIN_PERF(cap1));
|
||||||
WRITE_ONCE(cpudata->lowest_perf, AMD_CPPC_LOWEST_PERF(cap1));
|
WRITE_ONCE(cpudata->lowest_perf, AMD_CPPC_LOWEST_PERF(cap1));
|
||||||
|
@ -420,19 +388,13 @@ static int pstate_init_perf(struct amd_cpudata *cpudata)
|
||||||
static int cppc_init_perf(struct amd_cpudata *cpudata)
|
static int cppc_init_perf(struct amd_cpudata *cpudata)
|
||||||
{
|
{
|
||||||
struct cppc_perf_caps cppc_perf;
|
struct cppc_perf_caps cppc_perf;
|
||||||
u32 highest_perf;
|
|
||||||
|
|
||||||
int ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf);
|
int ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf);
|
||||||
if (ret)
|
if (ret)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (cpudata->hw_prefcore)
|
WRITE_ONCE(cpudata->highest_perf, cppc_perf.highest_perf);
|
||||||
highest_perf = amd_pstate_highest_perf_set(cpudata);
|
WRITE_ONCE(cpudata->max_limit_perf, cppc_perf.highest_perf);
|
||||||
else
|
|
||||||
highest_perf = cppc_perf.highest_perf;
|
|
||||||
|
|
||||||
WRITE_ONCE(cpudata->highest_perf, highest_perf);
|
|
||||||
WRITE_ONCE(cpudata->max_limit_perf, highest_perf);
|
|
||||||
WRITE_ONCE(cpudata->nominal_perf, cppc_perf.nominal_perf);
|
WRITE_ONCE(cpudata->nominal_perf, cppc_perf.nominal_perf);
|
||||||
WRITE_ONCE(cpudata->lowest_nonlinear_perf,
|
WRITE_ONCE(cpudata->lowest_nonlinear_perf,
|
||||||
cppc_perf.lowest_nonlinear_perf);
|
cppc_perf.lowest_nonlinear_perf);
|
||||||
|
@ -554,12 +516,15 @@ static void amd_pstate_update(struct amd_cpudata *cpudata, u32 min_perf,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value == prev)
|
if (value == prev)
|
||||||
return;
|
goto cpufreq_policy_put;
|
||||||
|
|
||||||
WRITE_ONCE(cpudata->cppc_req_cached, value);
|
WRITE_ONCE(cpudata->cppc_req_cached, value);
|
||||||
|
|
||||||
amd_pstate_update_perf(cpudata, min_perf, des_perf,
|
amd_pstate_update_perf(cpudata, min_perf, des_perf,
|
||||||
max_perf, fast_switch);
|
max_perf, fast_switch);
|
||||||
|
|
||||||
|
cpufreq_policy_put:
|
||||||
|
cpufreq_cpu_put(policy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int amd_pstate_verify(struct cpufreq_policy_data *policy)
|
static int amd_pstate_verify(struct cpufreq_policy_data *policy)
|
||||||
|
@ -656,7 +621,12 @@ static void amd_pstate_adjust_perf(unsigned int cpu,
|
||||||
unsigned long max_perf, min_perf, des_perf,
|
unsigned long max_perf, min_perf, des_perf,
|
||||||
cap_perf, lowest_nonlinear_perf;
|
cap_perf, lowest_nonlinear_perf;
|
||||||
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
|
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
|
||||||
struct amd_cpudata *cpudata = policy->driver_data;
|
struct amd_cpudata *cpudata;
|
||||||
|
|
||||||
|
if (!policy)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cpudata = policy->driver_data;
|
||||||
|
|
||||||
if (policy->min != cpudata->min_limit_freq || policy->max != cpudata->max_limit_freq)
|
if (policy->min != cpudata->min_limit_freq || policy->max != cpudata->max_limit_freq)
|
||||||
amd_pstate_update_min_max_limit(policy);
|
amd_pstate_update_min_max_limit(policy);
|
||||||
|
@ -803,66 +773,22 @@ static void amd_pstste_sched_prefcore_workfn(struct work_struct *work)
|
||||||
}
|
}
|
||||||
static DECLARE_WORK(sched_prefcore_work, amd_pstste_sched_prefcore_workfn);
|
static DECLARE_WORK(sched_prefcore_work, amd_pstste_sched_prefcore_workfn);
|
||||||
|
|
||||||
/*
|
|
||||||
* Get the highest performance register value.
|
|
||||||
* @cpu: CPU from which to get highest performance.
|
|
||||||
* @highest_perf: Return address.
|
|
||||||
*
|
|
||||||
* Return: 0 for success, -EIO otherwise.
|
|
||||||
*/
|
|
||||||
static int amd_pstate_get_highest_perf(int cpu, u32 *highest_perf)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (cpu_feature_enabled(X86_FEATURE_CPPC)) {
|
|
||||||
u64 cap1;
|
|
||||||
|
|
||||||
ret = rdmsrl_safe_on_cpu(cpu, MSR_AMD_CPPC_CAP1, &cap1);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
WRITE_ONCE(*highest_perf, AMD_CPPC_HIGHEST_PERF(cap1));
|
|
||||||
} else {
|
|
||||||
u64 cppc_highest_perf;
|
|
||||||
|
|
||||||
ret = cppc_get_highest_perf(cpu, &cppc_highest_perf);
|
|
||||||
if (ret)
|
|
||||||
return ret;
|
|
||||||
WRITE_ONCE(*highest_perf, cppc_highest_perf);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define CPPC_MAX_PERF U8_MAX
|
#define CPPC_MAX_PERF U8_MAX
|
||||||
|
|
||||||
static void amd_pstate_init_prefcore(struct amd_cpudata *cpudata)
|
static void amd_pstate_init_prefcore(struct amd_cpudata *cpudata)
|
||||||
{
|
{
|
||||||
int ret, prio;
|
/* user disabled or not detected */
|
||||||
u32 highest_perf;
|
if (!amd_pstate_prefcore)
|
||||||
|
|
||||||
ret = amd_pstate_get_highest_perf(cpudata->cpu, &highest_perf);
|
|
||||||
if (ret)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cpudata->hw_prefcore = true;
|
cpudata->hw_prefcore = true;
|
||||||
/* check if CPPC preferred core feature is enabled*/
|
|
||||||
if (highest_perf < CPPC_MAX_PERF)
|
|
||||||
prio = (int)highest_perf;
|
|
||||||
else {
|
|
||||||
pr_debug("AMD CPPC preferred core is unsupported!\n");
|
|
||||||
cpudata->hw_prefcore = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!amd_pstate_prefcore)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The priorities can be set regardless of whether or not
|
* The priorities can be set regardless of whether or not
|
||||||
* sched_set_itmt_support(true) has been called and it is valid to
|
* sched_set_itmt_support(true) has been called and it is valid to
|
||||||
* update them at any time after it has been called.
|
* update them at any time after it has been called.
|
||||||
*/
|
*/
|
||||||
sched_set_itmt_core_prio(prio, cpudata->cpu);
|
sched_set_itmt_core_prio((int)READ_ONCE(cpudata->highest_perf), cpudata->cpu);
|
||||||
|
|
||||||
schedule_work(&sched_prefcore_work);
|
schedule_work(&sched_prefcore_work);
|
||||||
}
|
}
|
||||||
|
@ -870,22 +796,27 @@ static void amd_pstate_init_prefcore(struct amd_cpudata *cpudata)
|
||||||
static void amd_pstate_update_limits(unsigned int cpu)
|
static void amd_pstate_update_limits(unsigned int cpu)
|
||||||
{
|
{
|
||||||
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
|
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
|
||||||
struct amd_cpudata *cpudata = policy->driver_data;
|
struct amd_cpudata *cpudata;
|
||||||
u32 prev_high = 0, cur_high = 0;
|
u32 prev_high = 0, cur_high = 0;
|
||||||
int ret;
|
int ret;
|
||||||
bool highest_perf_changed = false;
|
bool highest_perf_changed = false;
|
||||||
|
|
||||||
mutex_lock(&amd_pstate_driver_lock);
|
if (!policy)
|
||||||
if ((!amd_pstate_prefcore) || (!cpudata->hw_prefcore))
|
return;
|
||||||
goto free_cpufreq_put;
|
|
||||||
|
|
||||||
ret = amd_pstate_get_highest_perf(cpu, &cur_high);
|
cpudata = policy->driver_data;
|
||||||
|
|
||||||
|
if (!amd_pstate_prefcore)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mutex_lock(&amd_pstate_driver_lock);
|
||||||
|
ret = amd_get_highest_perf(cpu, &cur_high);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto free_cpufreq_put;
|
goto free_cpufreq_put;
|
||||||
|
|
||||||
prev_high = READ_ONCE(cpudata->prefcore_ranking);
|
prev_high = READ_ONCE(cpudata->prefcore_ranking);
|
||||||
if (prev_high != cur_high) {
|
highest_perf_changed = (prev_high != cur_high);
|
||||||
highest_perf_changed = true;
|
if (highest_perf_changed) {
|
||||||
WRITE_ONCE(cpudata->prefcore_ranking, cur_high);
|
WRITE_ONCE(cpudata->prefcore_ranking, cur_high);
|
||||||
|
|
||||||
if (cur_high < CPPC_MAX_PERF)
|
if (cur_high < CPPC_MAX_PERF)
|
||||||
|
@ -949,8 +880,8 @@ static u32 amd_pstate_get_transition_latency(unsigned int cpu)
|
||||||
static int amd_pstate_init_freq(struct amd_cpudata *cpudata)
|
static int amd_pstate_init_freq(struct amd_cpudata *cpudata)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
u32 min_freq;
|
u32 min_freq, max_freq;
|
||||||
u32 highest_perf, max_freq;
|
u64 numerator;
|
||||||
u32 nominal_perf, nominal_freq;
|
u32 nominal_perf, nominal_freq;
|
||||||
u32 lowest_nonlinear_perf, lowest_nonlinear_freq;
|
u32 lowest_nonlinear_perf, lowest_nonlinear_freq;
|
||||||
u32 boost_ratio, lowest_nonlinear_ratio;
|
u32 boost_ratio, lowest_nonlinear_ratio;
|
||||||
|
@ -972,8 +903,10 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata)
|
||||||
|
|
||||||
nominal_perf = READ_ONCE(cpudata->nominal_perf);
|
nominal_perf = READ_ONCE(cpudata->nominal_perf);
|
||||||
|
|
||||||
highest_perf = READ_ONCE(cpudata->highest_perf);
|
ret = amd_get_boost_ratio_numerator(cpudata->cpu, &numerator);
|
||||||
boost_ratio = div_u64(highest_perf << SCHED_CAPACITY_SHIFT, nominal_perf);
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
boost_ratio = div_u64(numerator << SCHED_CAPACITY_SHIFT, nominal_perf);
|
||||||
max_freq = (nominal_freq * boost_ratio >> SCHED_CAPACITY_SHIFT) * 1000;
|
max_freq = (nominal_freq * boost_ratio >> SCHED_CAPACITY_SHIFT) * 1000;
|
||||||
|
|
||||||
lowest_nonlinear_perf = READ_ONCE(cpudata->lowest_nonlinear_perf);
|
lowest_nonlinear_perf = READ_ONCE(cpudata->lowest_nonlinear_perf);
|
||||||
|
@ -1028,12 +961,12 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
|
||||||
|
|
||||||
cpudata->cpu = policy->cpu;
|
cpudata->cpu = policy->cpu;
|
||||||
|
|
||||||
amd_pstate_init_prefcore(cpudata);
|
|
||||||
|
|
||||||
ret = amd_pstate_init_perf(cpudata);
|
ret = amd_pstate_init_perf(cpudata);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto free_cpudata1;
|
goto free_cpudata1;
|
||||||
|
|
||||||
|
amd_pstate_init_prefcore(cpudata);
|
||||||
|
|
||||||
ret = amd_pstate_init_freq(cpudata);
|
ret = amd_pstate_init_freq(cpudata);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto free_cpudata1;
|
goto free_cpudata1;
|
||||||
|
@ -1349,7 +1282,7 @@ static ssize_t amd_pstate_show_status(char *buf)
|
||||||
return sysfs_emit(buf, "%s\n", amd_pstate_mode_string[cppc_state]);
|
return sysfs_emit(buf, "%s\n", amd_pstate_mode_string[cppc_state]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int amd_pstate_update_status(const char *buf, size_t size)
|
int amd_pstate_update_status(const char *buf, size_t size)
|
||||||
{
|
{
|
||||||
int mode_idx;
|
int mode_idx;
|
||||||
|
|
||||||
|
@ -1366,6 +1299,7 @@ static int amd_pstate_update_status(const char *buf, size_t size)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(amd_pstate_update_status);
|
||||||
|
|
||||||
static ssize_t status_show(struct device *dev,
|
static ssize_t status_show(struct device *dev,
|
||||||
struct device_attribute *attr, char *buf)
|
struct device_attribute *attr, char *buf)
|
||||||
|
@ -1483,12 +1417,12 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
|
||||||
cpudata->cpu = policy->cpu;
|
cpudata->cpu = policy->cpu;
|
||||||
cpudata->epp_policy = 0;
|
cpudata->epp_policy = 0;
|
||||||
|
|
||||||
amd_pstate_init_prefcore(cpudata);
|
|
||||||
|
|
||||||
ret = amd_pstate_init_perf(cpudata);
|
ret = amd_pstate_init_perf(cpudata);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto free_cpudata1;
|
goto free_cpudata1;
|
||||||
|
|
||||||
|
amd_pstate_init_prefcore(cpudata);
|
||||||
|
|
||||||
ret = amd_pstate_init_freq(cpudata);
|
ret = amd_pstate_init_freq(cpudata);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto free_cpudata1;
|
goto free_cpudata1;
|
||||||
|
@ -1555,7 +1489,7 @@ static void amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy)
|
||||||
pr_debug("CPU %d exiting\n", policy->cpu);
|
pr_debug("CPU %d exiting\n", policy->cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void amd_pstate_epp_update_limit(struct cpufreq_policy *policy)
|
static int amd_pstate_epp_update_limit(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
struct amd_cpudata *cpudata = policy->driver_data;
|
struct amd_cpudata *cpudata = policy->driver_data;
|
||||||
u32 max_perf, min_perf, min_limit_perf, max_limit_perf;
|
u32 max_perf, min_perf, min_limit_perf, max_limit_perf;
|
||||||
|
@ -1605,7 +1539,7 @@ static void amd_pstate_epp_update_limit(struct cpufreq_policy *policy)
|
||||||
* This return value can only be negative for shared_memory
|
* This return value can only be negative for shared_memory
|
||||||
* systems where EPP register read/write not supported.
|
* systems where EPP register read/write not supported.
|
||||||
*/
|
*/
|
||||||
return;
|
return epp;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE)
|
if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE)
|
||||||
|
@ -1618,12 +1552,13 @@ static void amd_pstate_epp_update_limit(struct cpufreq_policy *policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
WRITE_ONCE(cpudata->cppc_req_cached, value);
|
WRITE_ONCE(cpudata->cppc_req_cached, value);
|
||||||
amd_pstate_set_epp(cpudata, epp);
|
return amd_pstate_set_epp(cpudata, epp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
|
static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
|
||||||
{
|
{
|
||||||
struct amd_cpudata *cpudata = policy->driver_data;
|
struct amd_cpudata *cpudata = policy->driver_data;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (!policy->cpuinfo.max_freq)
|
if (!policy->cpuinfo.max_freq)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
@ -1633,7 +1568,9 @@ static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
|
||||||
|
|
||||||
cpudata->policy = policy->policy;
|
cpudata->policy = policy->policy;
|
||||||
|
|
||||||
amd_pstate_epp_update_limit(policy);
|
ret = amd_pstate_epp_update_limit(policy);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* policy->cur is never updated with the amd_pstate_epp driver, but it
|
* policy->cur is never updated with the amd_pstate_epp driver, but it
|
||||||
|
@ -1947,6 +1884,12 @@ static int __init amd_pstate_init(void)
|
||||||
static_call_update(amd_pstate_update_perf, cppc_update_perf);
|
static_call_update(amd_pstate_update_perf, cppc_update_perf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (amd_pstate_prefcore) {
|
||||||
|
ret = amd_detect_prefcore(&amd_pstate_prefcore);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* enable amd pstate feature */
|
/* enable amd pstate feature */
|
||||||
ret = amd_pstate_enable(true);
|
ret = amd_pstate_enable(true);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
|
|
@ -103,4 +103,18 @@ struct amd_cpudata {
|
||||||
bool boost_state;
|
bool boost_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* enum amd_pstate_mode - driver working mode of amd pstate
|
||||||
|
*/
|
||||||
|
enum amd_pstate_mode {
|
||||||
|
AMD_PSTATE_UNDEFINED = 0,
|
||||||
|
AMD_PSTATE_DISABLE,
|
||||||
|
AMD_PSTATE_PASSIVE,
|
||||||
|
AMD_PSTATE_ACTIVE,
|
||||||
|
AMD_PSTATE_GUIDED,
|
||||||
|
AMD_PSTATE_MAX,
|
||||||
|
};
|
||||||
|
const char *amd_pstate_get_mode_string(enum amd_pstate_mode mode);
|
||||||
|
int amd_pstate_update_status(const char *buf, size_t size);
|
||||||
|
|
||||||
#endif /* _LINUX_AMD_PSTATE_H */
|
#endif /* _LINUX_AMD_PSTATE_H */
|
||||||
|
|
|
@ -85,7 +85,7 @@ static const struct apple_soc_cpufreq_info soc_default_info = {
|
||||||
.cur_pstate_mask = 0, /* fallback */
|
.cur_pstate_mask = 0, /* fallback */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id apple_soc_cpufreq_of_match[] = {
|
static const struct of_device_id apple_soc_cpufreq_of_match[] __maybe_unused = {
|
||||||
{
|
{
|
||||||
.compatible = "apple,t8103-cluster-cpufreq",
|
.compatible = "apple,t8103-cluster-cpufreq",
|
||||||
.data = &soc_t8103_info,
|
.data = &soc_t8103_info,
|
||||||
|
|
|
@ -132,7 +132,7 @@ static int __init armada_8k_cpufreq_init(void)
|
||||||
int ret = 0, opps_index = 0, cpu, nb_cpus;
|
int ret = 0, opps_index = 0, cpu, nb_cpus;
|
||||||
struct freq_table *freq_tables;
|
struct freq_table *freq_tables;
|
||||||
struct device_node *node;
|
struct device_node *node;
|
||||||
struct cpumask cpus;
|
static struct cpumask cpus;
|
||||||
|
|
||||||
node = of_find_matching_node_and_match(NULL, armada_8k_cpufreq_of_match,
|
node = of_find_matching_node_and_match(NULL, armada_8k_cpufreq_of_match,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
|
@ -166,6 +166,7 @@ static const struct of_device_id blocklist[] __initconst = {
|
||||||
{ .compatible = "qcom,sm6350", },
|
{ .compatible = "qcom,sm6350", },
|
||||||
{ .compatible = "qcom,sm6375", },
|
{ .compatible = "qcom,sm6375", },
|
||||||
{ .compatible = "qcom,sm7225", },
|
{ .compatible = "qcom,sm7225", },
|
||||||
|
{ .compatible = "qcom,sm7325", },
|
||||||
{ .compatible = "qcom,sm8150", },
|
{ .compatible = "qcom,sm8150", },
|
||||||
{ .compatible = "qcom,sm8250", },
|
{ .compatible = "qcom,sm8250", },
|
||||||
{ .compatible = "qcom,sm8350", },
|
{ .compatible = "qcom,sm8350", },
|
||||||
|
|
|
@ -69,7 +69,6 @@ static int set_target(struct cpufreq_policy *policy, unsigned int index)
|
||||||
static const char *find_supply_name(struct device *dev)
|
static const char *find_supply_name(struct device *dev)
|
||||||
{
|
{
|
||||||
struct device_node *np __free(device_node) = of_node_get(dev->of_node);
|
struct device_node *np __free(device_node) = of_node_get(dev->of_node);
|
||||||
struct property *pp;
|
|
||||||
int cpu = dev->id;
|
int cpu = dev->id;
|
||||||
|
|
||||||
/* This must be valid for sure */
|
/* This must be valid for sure */
|
||||||
|
@ -77,14 +76,10 @@ static const char *find_supply_name(struct device *dev)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
/* Try "cpu0" for older DTs */
|
/* Try "cpu0" for older DTs */
|
||||||
if (!cpu) {
|
if (!cpu && of_property_present(np, "cpu0-supply"))
|
||||||
pp = of_find_property(np, "cpu0-supply", NULL);
|
return "cpu0";
|
||||||
if (pp)
|
|
||||||
return "cpu0";
|
|
||||||
}
|
|
||||||
|
|
||||||
pp = of_find_property(np, "cpu-supply", NULL);
|
if (of_property_present(np, "cpu-supply"))
|
||||||
if (pp)
|
|
||||||
return "cpu";
|
return "cpu";
|
||||||
|
|
||||||
dev_dbg(dev, "no regulator for cpu%d\n", cpu);
|
dev_dbg(dev, "no regulator for cpu%d\n", cpu);
|
||||||
|
|
|
@ -575,30 +575,11 @@ unsigned int cpufreq_policy_transition_delay_us(struct cpufreq_policy *policy)
|
||||||
return policy->transition_delay_us;
|
return policy->transition_delay_us;
|
||||||
|
|
||||||
latency = policy->cpuinfo.transition_latency / NSEC_PER_USEC;
|
latency = policy->cpuinfo.transition_latency / NSEC_PER_USEC;
|
||||||
if (latency) {
|
if (latency)
|
||||||
unsigned int max_delay_us = 2 * MSEC_PER_SEC;
|
/* Give a 50% breathing room between updates */
|
||||||
|
return latency + (latency >> 1);
|
||||||
|
|
||||||
/*
|
return USEC_PER_MSEC;
|
||||||
* If the platform already has high transition_latency, use it
|
|
||||||
* as-is.
|
|
||||||
*/
|
|
||||||
if (latency > max_delay_us)
|
|
||||||
return latency;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For platforms that can change the frequency very fast (< 2
|
|
||||||
* us), the above formula gives a decent transition delay. But
|
|
||||||
* for platforms where transition_latency is in milliseconds, it
|
|
||||||
* ends up giving unrealistic values.
|
|
||||||
*
|
|
||||||
* Cap the default transition delay to 2 ms, which seems to be
|
|
||||||
* a reasonable amount of time after which we should reevaluate
|
|
||||||
* the frequency.
|
|
||||||
*/
|
|
||||||
return min(latency * LATENCY_MULTIPLIER, max_delay_us);
|
|
||||||
}
|
|
||||||
|
|
||||||
return LATENCY_MULTIPLIER;
|
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(cpufreq_policy_transition_delay_us);
|
EXPORT_SYMBOL_GPL(cpufreq_policy_transition_delay_us);
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <linux/tick.h>
|
#include <linux/tick.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/sched/cpufreq.h>
|
#include <linux/sched/cpufreq.h>
|
||||||
|
#include <linux/sched/smt.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/cpu.h>
|
#include <linux/cpu.h>
|
||||||
#include <linux/cpufreq.h>
|
#include <linux/cpufreq.h>
|
||||||
|
@ -215,6 +216,7 @@ struct global_params {
|
||||||
* @hwp_req_cached: Cached value of the last HWP Request MSR
|
* @hwp_req_cached: Cached value of the last HWP Request MSR
|
||||||
* @hwp_cap_cached: Cached value of the last HWP Capabilities MSR
|
* @hwp_cap_cached: Cached value of the last HWP Capabilities MSR
|
||||||
* @last_io_update: Last time when IO wake flag was set
|
* @last_io_update: Last time when IO wake flag was set
|
||||||
|
* @capacity_perf: Highest perf used for scale invariance
|
||||||
* @sched_flags: Store scheduler flags for possible cross CPU update
|
* @sched_flags: Store scheduler flags for possible cross CPU update
|
||||||
* @hwp_boost_min: Last HWP boosted min performance
|
* @hwp_boost_min: Last HWP boosted min performance
|
||||||
* @suspended: Whether or not the driver has been suspended.
|
* @suspended: Whether or not the driver has been suspended.
|
||||||
|
@ -253,6 +255,7 @@ struct cpudata {
|
||||||
u64 hwp_req_cached;
|
u64 hwp_req_cached;
|
||||||
u64 hwp_cap_cached;
|
u64 hwp_cap_cached;
|
||||||
u64 last_io_update;
|
u64 last_io_update;
|
||||||
|
unsigned int capacity_perf;
|
||||||
unsigned int sched_flags;
|
unsigned int sched_flags;
|
||||||
u32 hwp_boost_min;
|
u32 hwp_boost_min;
|
||||||
bool suspended;
|
bool suspended;
|
||||||
|
@ -295,6 +298,7 @@ static int hwp_mode_bdw __ro_after_init;
|
||||||
static bool per_cpu_limits __ro_after_init;
|
static bool per_cpu_limits __ro_after_init;
|
||||||
static bool hwp_forced __ro_after_init;
|
static bool hwp_forced __ro_after_init;
|
||||||
static bool hwp_boost __read_mostly;
|
static bool hwp_boost __read_mostly;
|
||||||
|
static bool hwp_is_hybrid;
|
||||||
|
|
||||||
static struct cpufreq_driver *intel_pstate_driver __read_mostly;
|
static struct cpufreq_driver *intel_pstate_driver __read_mostly;
|
||||||
|
|
||||||
|
@ -934,6 +938,139 @@ static struct freq_attr *hwp_cpufreq_attrs[] = {
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct cpudata *hybrid_max_perf_cpu __read_mostly;
|
||||||
|
/*
|
||||||
|
* Protects hybrid_max_perf_cpu, the capacity_perf fields in struct cpudata,
|
||||||
|
* and the x86 arch scale-invariance information from concurrent updates.
|
||||||
|
*/
|
||||||
|
static DEFINE_MUTEX(hybrid_capacity_lock);
|
||||||
|
|
||||||
|
static void hybrid_set_cpu_capacity(struct cpudata *cpu)
|
||||||
|
{
|
||||||
|
arch_set_cpu_capacity(cpu->cpu, cpu->capacity_perf,
|
||||||
|
hybrid_max_perf_cpu->capacity_perf,
|
||||||
|
cpu->capacity_perf,
|
||||||
|
cpu->pstate.max_pstate_physical);
|
||||||
|
|
||||||
|
pr_debug("CPU%d: perf = %u, max. perf = %u, base perf = %d\n", cpu->cpu,
|
||||||
|
cpu->capacity_perf, hybrid_max_perf_cpu->capacity_perf,
|
||||||
|
cpu->pstate.max_pstate_physical);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hybrid_clear_cpu_capacity(unsigned int cpunum)
|
||||||
|
{
|
||||||
|
arch_set_cpu_capacity(cpunum, 1, 1, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hybrid_get_capacity_perf(struct cpudata *cpu)
|
||||||
|
{
|
||||||
|
if (READ_ONCE(global.no_turbo)) {
|
||||||
|
cpu->capacity_perf = cpu->pstate.max_pstate_physical;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpu->capacity_perf = HWP_HIGHEST_PERF(READ_ONCE(cpu->hwp_cap_cached));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hybrid_set_capacity_of_cpus(void)
|
||||||
|
{
|
||||||
|
int cpunum;
|
||||||
|
|
||||||
|
for_each_online_cpu(cpunum) {
|
||||||
|
struct cpudata *cpu = all_cpu_data[cpunum];
|
||||||
|
|
||||||
|
if (cpu)
|
||||||
|
hybrid_set_cpu_capacity(cpu);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hybrid_update_cpu_capacity_scaling(void)
|
||||||
|
{
|
||||||
|
struct cpudata *max_perf_cpu = NULL;
|
||||||
|
unsigned int max_cap_perf = 0;
|
||||||
|
int cpunum;
|
||||||
|
|
||||||
|
for_each_online_cpu(cpunum) {
|
||||||
|
struct cpudata *cpu = all_cpu_data[cpunum];
|
||||||
|
|
||||||
|
if (!cpu)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* During initialization, CPU performance at full capacity needs
|
||||||
|
* to be determined.
|
||||||
|
*/
|
||||||
|
if (!hybrid_max_perf_cpu)
|
||||||
|
hybrid_get_capacity_perf(cpu);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If hybrid_max_perf_cpu is not NULL at this point, it is
|
||||||
|
* being replaced, so don't take it into account when looking
|
||||||
|
* for the new one.
|
||||||
|
*/
|
||||||
|
if (cpu == hybrid_max_perf_cpu)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (cpu->capacity_perf > max_cap_perf) {
|
||||||
|
max_cap_perf = cpu->capacity_perf;
|
||||||
|
max_perf_cpu = cpu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (max_perf_cpu) {
|
||||||
|
hybrid_max_perf_cpu = max_perf_cpu;
|
||||||
|
hybrid_set_capacity_of_cpus();
|
||||||
|
} else {
|
||||||
|
pr_info("Found no CPUs with nonzero maximum performance\n");
|
||||||
|
/* Revert to the flat CPU capacity structure. */
|
||||||
|
for_each_online_cpu(cpunum)
|
||||||
|
hybrid_clear_cpu_capacity(cpunum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __hybrid_init_cpu_capacity_scaling(void)
|
||||||
|
{
|
||||||
|
hybrid_max_perf_cpu = NULL;
|
||||||
|
hybrid_update_cpu_capacity_scaling();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hybrid_init_cpu_capacity_scaling(void)
|
||||||
|
{
|
||||||
|
bool disable_itmt = false;
|
||||||
|
|
||||||
|
mutex_lock(&hybrid_capacity_lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If hybrid_max_perf_cpu is set at this point, the hybrid CPU capacity
|
||||||
|
* scaling has been enabled already and the driver is just changing the
|
||||||
|
* operation mode.
|
||||||
|
*/
|
||||||
|
if (hybrid_max_perf_cpu) {
|
||||||
|
__hybrid_init_cpu_capacity_scaling();
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On hybrid systems, use asym capacity instead of ITMT, but because
|
||||||
|
* the capacity of SMT threads is not deterministic even approximately,
|
||||||
|
* do not do that when SMT is in use.
|
||||||
|
*/
|
||||||
|
if (hwp_is_hybrid && !sched_smt_active() && arch_enable_hybrid_capacity_scale()) {
|
||||||
|
__hybrid_init_cpu_capacity_scaling();
|
||||||
|
disable_itmt = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
unlock:
|
||||||
|
mutex_unlock(&hybrid_capacity_lock);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Disabling ITMT causes sched domains to be rebuilt to disable asym
|
||||||
|
* packing and enable asym capacity.
|
||||||
|
*/
|
||||||
|
if (disable_itmt)
|
||||||
|
sched_clear_itmt_support();
|
||||||
|
}
|
||||||
|
|
||||||
static void __intel_pstate_get_hwp_cap(struct cpudata *cpu)
|
static void __intel_pstate_get_hwp_cap(struct cpudata *cpu)
|
||||||
{
|
{
|
||||||
u64 cap;
|
u64 cap;
|
||||||
|
@ -962,6 +1099,43 @@ static void intel_pstate_get_hwp_cap(struct cpudata *cpu)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hybrid_update_capacity(struct cpudata *cpu)
|
||||||
|
{
|
||||||
|
unsigned int max_cap_perf;
|
||||||
|
|
||||||
|
mutex_lock(&hybrid_capacity_lock);
|
||||||
|
|
||||||
|
if (!hybrid_max_perf_cpu)
|
||||||
|
goto unlock;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The maximum performance of the CPU may have changed, but assume
|
||||||
|
* that the performance of the other CPUs has not changed.
|
||||||
|
*/
|
||||||
|
max_cap_perf = hybrid_max_perf_cpu->capacity_perf;
|
||||||
|
|
||||||
|
intel_pstate_get_hwp_cap(cpu);
|
||||||
|
|
||||||
|
hybrid_get_capacity_perf(cpu);
|
||||||
|
/* Should hybrid_max_perf_cpu be replaced by this CPU? */
|
||||||
|
if (cpu->capacity_perf > max_cap_perf) {
|
||||||
|
hybrid_max_perf_cpu = cpu;
|
||||||
|
hybrid_set_capacity_of_cpus();
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this CPU is hybrid_max_perf_cpu, should it be replaced? */
|
||||||
|
if (cpu == hybrid_max_perf_cpu && cpu->capacity_perf < max_cap_perf) {
|
||||||
|
hybrid_update_cpu_capacity_scaling();
|
||||||
|
goto unlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
hybrid_set_cpu_capacity(cpu);
|
||||||
|
|
||||||
|
unlock:
|
||||||
|
mutex_unlock(&hybrid_capacity_lock);
|
||||||
|
}
|
||||||
|
|
||||||
static void intel_pstate_hwp_set(unsigned int cpu)
|
static void intel_pstate_hwp_set(unsigned int cpu)
|
||||||
{
|
{
|
||||||
struct cpudata *cpu_data = all_cpu_data[cpu];
|
struct cpudata *cpu_data = all_cpu_data[cpu];
|
||||||
|
@ -1070,6 +1244,22 @@ static void intel_pstate_hwp_offline(struct cpudata *cpu)
|
||||||
value |= HWP_ENERGY_PERF_PREFERENCE(HWP_EPP_POWERSAVE);
|
value |= HWP_ENERGY_PERF_PREFERENCE(HWP_EPP_POWERSAVE);
|
||||||
|
|
||||||
wrmsrl_on_cpu(cpu->cpu, MSR_HWP_REQUEST, value);
|
wrmsrl_on_cpu(cpu->cpu, MSR_HWP_REQUEST, value);
|
||||||
|
|
||||||
|
mutex_lock(&hybrid_capacity_lock);
|
||||||
|
|
||||||
|
if (!hybrid_max_perf_cpu) {
|
||||||
|
mutex_unlock(&hybrid_capacity_lock);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hybrid_max_perf_cpu == cpu)
|
||||||
|
hybrid_update_cpu_capacity_scaling();
|
||||||
|
|
||||||
|
mutex_unlock(&hybrid_capacity_lock);
|
||||||
|
|
||||||
|
/* Reset the capacity of the CPU going offline to the initial value. */
|
||||||
|
hybrid_clear_cpu_capacity(cpu->cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define POWER_CTL_EE_ENABLE 1
|
#define POWER_CTL_EE_ENABLE 1
|
||||||
|
@ -1165,21 +1355,46 @@ static void __intel_pstate_update_max_freq(struct cpudata *cpudata,
|
||||||
static void intel_pstate_update_limits(unsigned int cpu)
|
static void intel_pstate_update_limits(unsigned int cpu)
|
||||||
{
|
{
|
||||||
struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpu);
|
struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpu);
|
||||||
|
struct cpudata *cpudata;
|
||||||
|
|
||||||
if (!policy)
|
if (!policy)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
__intel_pstate_update_max_freq(all_cpu_data[cpu], policy);
|
cpudata = all_cpu_data[cpu];
|
||||||
|
|
||||||
|
__intel_pstate_update_max_freq(cpudata, policy);
|
||||||
|
|
||||||
|
/* Prevent the driver from being unregistered now. */
|
||||||
|
mutex_lock(&intel_pstate_driver_lock);
|
||||||
|
|
||||||
cpufreq_cpu_release(policy);
|
cpufreq_cpu_release(policy);
|
||||||
|
|
||||||
|
hybrid_update_capacity(cpudata);
|
||||||
|
|
||||||
|
mutex_unlock(&intel_pstate_driver_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void intel_pstate_update_limits_for_all(void)
|
static void intel_pstate_update_limits_for_all(void)
|
||||||
{
|
{
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
for_each_possible_cpu(cpu)
|
for_each_possible_cpu(cpu) {
|
||||||
intel_pstate_update_limits(cpu);
|
struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpu);
|
||||||
|
|
||||||
|
if (!policy)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
__intel_pstate_update_max_freq(all_cpu_data[cpu], policy);
|
||||||
|
|
||||||
|
cpufreq_cpu_release(policy);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(&hybrid_capacity_lock);
|
||||||
|
|
||||||
|
if (hybrid_max_perf_cpu)
|
||||||
|
__hybrid_init_cpu_capacity_scaling();
|
||||||
|
|
||||||
|
mutex_unlock(&hybrid_capacity_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************** sysfs begin ************************/
|
/************************** sysfs begin ************************/
|
||||||
|
@ -1618,6 +1833,13 @@ static void intel_pstate_notify_work(struct work_struct *work)
|
||||||
__intel_pstate_update_max_freq(cpudata, policy);
|
__intel_pstate_update_max_freq(cpudata, policy);
|
||||||
|
|
||||||
cpufreq_cpu_release(policy);
|
cpufreq_cpu_release(policy);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The driver will not be unregistered while this function is
|
||||||
|
* running, so update the capacity without acquiring the driver
|
||||||
|
* lock.
|
||||||
|
*/
|
||||||
|
hybrid_update_capacity(cpudata);
|
||||||
}
|
}
|
||||||
|
|
||||||
wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_STATUS, 0);
|
wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_STATUS, 0);
|
||||||
|
@ -2034,8 +2256,10 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
|
||||||
|
|
||||||
if (pstate_funcs.get_cpu_scaling) {
|
if (pstate_funcs.get_cpu_scaling) {
|
||||||
cpu->pstate.scaling = pstate_funcs.get_cpu_scaling(cpu->cpu);
|
cpu->pstate.scaling = pstate_funcs.get_cpu_scaling(cpu->cpu);
|
||||||
if (cpu->pstate.scaling != perf_ctl_scaling)
|
if (cpu->pstate.scaling != perf_ctl_scaling) {
|
||||||
intel_pstate_hybrid_hwp_adjust(cpu);
|
intel_pstate_hybrid_hwp_adjust(cpu);
|
||||||
|
hwp_is_hybrid = true;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
cpu->pstate.scaling = perf_ctl_scaling;
|
cpu->pstate.scaling = perf_ctl_scaling;
|
||||||
}
|
}
|
||||||
|
@ -2425,6 +2649,10 @@ static const struct x86_cpu_id intel_pstate_cpu_oob_ids[] __initconst = {
|
||||||
X86_MATCH(INTEL_ICELAKE_X, core_funcs),
|
X86_MATCH(INTEL_ICELAKE_X, core_funcs),
|
||||||
X86_MATCH(INTEL_SAPPHIRERAPIDS_X, core_funcs),
|
X86_MATCH(INTEL_SAPPHIRERAPIDS_X, core_funcs),
|
||||||
X86_MATCH(INTEL_EMERALDRAPIDS_X, core_funcs),
|
X86_MATCH(INTEL_EMERALDRAPIDS_X, core_funcs),
|
||||||
|
X86_MATCH(INTEL_GRANITERAPIDS_D, core_funcs),
|
||||||
|
X86_MATCH(INTEL_GRANITERAPIDS_X, core_funcs),
|
||||||
|
X86_MATCH(INTEL_ATOM_CRESTMONT, core_funcs),
|
||||||
|
X86_MATCH(INTEL_ATOM_CRESTMONT_X, core_funcs),
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
@ -2703,6 +2931,8 @@ static int intel_pstate_cpu_online(struct cpufreq_policy *policy)
|
||||||
*/
|
*/
|
||||||
intel_pstate_hwp_reenable(cpu);
|
intel_pstate_hwp_reenable(cpu);
|
||||||
cpu->suspended = false;
|
cpu->suspended = false;
|
||||||
|
|
||||||
|
hybrid_update_capacity(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3143,6 +3373,8 @@ static int intel_pstate_register_driver(struct cpufreq_driver *driver)
|
||||||
|
|
||||||
global.min_perf_pct = min_perf_pct_min();
|
global.min_perf_pct = min_perf_pct_min();
|
||||||
|
|
||||||
|
hybrid_init_cpu_capacity_scaling();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -176,7 +176,7 @@ static DEFINE_PER_CPU(struct loongson3_freq_data *, freq_data);
|
||||||
static inline int do_service_request(u32 id, u32 info, u32 cmd, u32 val, u32 extra)
|
static inline int do_service_request(u32 id, u32 info, u32 cmd, u32 val, u32 extra)
|
||||||
{
|
{
|
||||||
int retries;
|
int retries;
|
||||||
unsigned int cpu = smp_processor_id();
|
unsigned int cpu = raw_smp_processor_id();
|
||||||
unsigned int package = cpu_data[cpu].package;
|
unsigned int package = cpu_data[cpu].package;
|
||||||
union smc_message msg, last;
|
union smc_message msg, last;
|
||||||
|
|
||||||
|
|
|
@ -238,4 +238,5 @@ bail_noprops:
|
||||||
module_init(maple_cpufreq_init);
|
module_init(maple_cpufreq_init);
|
||||||
|
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("cpufreq driver for Maple 970FX/970MP boards");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -738,7 +738,7 @@ static const struct mtk_cpufreq_platform_data mt8516_platform_data = {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* List of machines supported by this driver */
|
/* List of machines supported by this driver */
|
||||||
static const struct of_device_id mtk_cpufreq_machines[] __initconst = {
|
static const struct of_device_id mtk_cpufreq_machines[] __initconst __maybe_unused = {
|
||||||
{ .compatible = "mediatek,mt2701", .data = &mt2701_platform_data },
|
{ .compatible = "mediatek,mt2701", .data = &mt2701_platform_data },
|
||||||
{ .compatible = "mediatek,mt2712", .data = &mt2701_platform_data },
|
{ .compatible = "mediatek,mt2712", .data = &mt2701_platform_data },
|
||||||
{ .compatible = "mediatek,mt7622", .data = &mt7622_platform_data },
|
{ .compatible = "mediatek,mt7622", .data = &mt7622_platform_data },
|
||||||
|
|
|
@ -28,9 +28,6 @@
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/regulator/consumer.h>
|
#include <linux/regulator/consumer.h>
|
||||||
|
|
||||||
#include <asm/smp_plat.h>
|
|
||||||
#include <asm/cpu.h>
|
|
||||||
|
|
||||||
/* OPP tolerance in percentage */
|
/* OPP tolerance in percentage */
|
||||||
#define OPP_TOLERANCE 4
|
#define OPP_TOLERANCE 4
|
||||||
|
|
||||||
|
|
|
@ -269,5 +269,6 @@ static void __exit pas_cpufreq_exit(void)
|
||||||
module_init(pas_cpufreq_init);
|
module_init(pas_cpufreq_init);
|
||||||
module_exit(pas_cpufreq_exit);
|
module_exit(pas_cpufreq_exit);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("cpufreq driver for PA Semi PWRficient");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>, Olof Johansson <olof@lixom.net>");
|
MODULE_AUTHOR("Egor Martovetsky <egor@pasemi.com>, Olof Johansson <olof@lixom.net>");
|
||||||
|
|
|
@ -505,7 +505,7 @@ static int __init g5_pm72_cpufreq_init(struct device_node *cpunode)
|
||||||
continue;
|
continue;
|
||||||
if (strcmp(loc, "CPU CLOCK"))
|
if (strcmp(loc, "CPU CLOCK"))
|
||||||
continue;
|
continue;
|
||||||
if (!of_get_property(hwclock, "platform-get-frequency", NULL))
|
if (!of_property_present(hwclock, "platform-get-frequency"))
|
||||||
continue;
|
continue;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -671,4 +671,5 @@ static int __init g5_cpufreq_init(void)
|
||||||
module_init(g5_cpufreq_init);
|
module_init(g5_cpufreq_init);
|
||||||
|
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("cpufreq driver for SMU & 970FX based G5 Macs");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -692,7 +692,7 @@ static void gpstate_timer_handler(struct timer_list *t)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If PMCR was last updated was using fast_swtich then
|
* If PMCR was last updated was using fast_switch then
|
||||||
* We may have wrong in gpstate->last_lpstate_idx
|
* We may have wrong in gpstate->last_lpstate_idx
|
||||||
* value. Hence, read from PMCR to get correct data.
|
* value. Hence, read from PMCR to get correct data.
|
||||||
*/
|
*/
|
||||||
|
@ -1160,5 +1160,6 @@ static void __exit powernv_cpufreq_exit(void)
|
||||||
}
|
}
|
||||||
module_exit(powernv_cpufreq_exit);
|
module_exit(powernv_cpufreq_exit);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("cpufreq driver for IBM/OpenPOWER powernv systems");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Vaidyanathan Srinivasan <svaidy at linux.vnet.ibm.com>");
|
MODULE_AUTHOR("Vaidyanathan Srinivasan <svaidy at linux.vnet.ibm.com>");
|
||||||
|
|
|
@ -168,5 +168,6 @@ static void __exit cbe_cpufreq_exit(void)
|
||||||
module_init(cbe_cpufreq_init);
|
module_init(cbe_cpufreq_init);
|
||||||
module_exit(cbe_cpufreq_exit);
|
module_exit(cbe_cpufreq_exit);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("cpufreq driver for Cell BE processors");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
|
MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/interconnect.h>
|
#include <linux/interconnect.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/io.h>
|
||||||
#include <linux/kernel.h>
|
#include <linux/kernel.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
|
|
|
@ -611,7 +611,7 @@ static struct platform_driver qcom_cpufreq_driver = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct of_device_id qcom_cpufreq_match_list[] __initconst = {
|
static const struct of_device_id qcom_cpufreq_match_list[] __initconst __maybe_unused = {
|
||||||
{ .compatible = "qcom,apq8096", .data = &match_data_kryo },
|
{ .compatible = "qcom,apq8096", .data = &match_data_kryo },
|
||||||
{ .compatible = "qcom,msm8909", .data = &match_data_msm8909 },
|
{ .compatible = "qcom,msm8909", .data = &match_data_msm8909 },
|
||||||
{ .compatible = "qcom,msm8996", .data = &match_data_kryo },
|
{ .compatible = "qcom,msm8996", .data = &match_data_kryo },
|
||||||
|
|
|
@ -171,10 +171,9 @@ static struct cpufreq_driver spear_cpufreq_driver = {
|
||||||
static int spear_cpufreq_probe(struct platform_device *pdev)
|
static int spear_cpufreq_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct device_node *np;
|
struct device_node *np;
|
||||||
const struct property *prop;
|
|
||||||
struct cpufreq_frequency_table *freq_tbl;
|
struct cpufreq_frequency_table *freq_tbl;
|
||||||
const __be32 *val;
|
u32 val;
|
||||||
int cnt, i, ret;
|
int cnt, ret, i = 0;
|
||||||
|
|
||||||
np = of_cpu_device_node_get(0);
|
np = of_cpu_device_node_get(0);
|
||||||
if (!np) {
|
if (!np) {
|
||||||
|
@ -186,26 +185,23 @@ static int spear_cpufreq_probe(struct platform_device *pdev)
|
||||||
&spear_cpufreq.transition_latency))
|
&spear_cpufreq.transition_latency))
|
||||||
spear_cpufreq.transition_latency = CPUFREQ_ETERNAL;
|
spear_cpufreq.transition_latency = CPUFREQ_ETERNAL;
|
||||||
|
|
||||||
prop = of_find_property(np, "cpufreq_tbl", NULL);
|
cnt = of_property_count_u32_elems(np, "cpufreq_tbl");
|
||||||
if (!prop || !prop->value) {
|
if (cnt <= 0) {
|
||||||
pr_err("Invalid cpufreq_tbl\n");
|
pr_err("Invalid cpufreq_tbl\n");
|
||||||
ret = -ENODEV;
|
ret = -ENODEV;
|
||||||
goto out_put_node;
|
goto out_put_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
cnt = prop->length / sizeof(u32);
|
|
||||||
val = prop->value;
|
|
||||||
|
|
||||||
freq_tbl = kcalloc(cnt + 1, sizeof(*freq_tbl), GFP_KERNEL);
|
freq_tbl = kcalloc(cnt + 1, sizeof(*freq_tbl), GFP_KERNEL);
|
||||||
if (!freq_tbl) {
|
if (!freq_tbl) {
|
||||||
ret = -ENOMEM;
|
ret = -ENOMEM;
|
||||||
goto out_put_node;
|
goto out_put_node;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < cnt; i++)
|
of_property_for_each_u32(np, "cpufreq_tbl", val)
|
||||||
freq_tbl[i].frequency = be32_to_cpup(val++);
|
freq_tbl[i++].frequency = val;
|
||||||
|
|
||||||
freq_tbl[i].frequency = CPUFREQ_TABLE_END;
|
freq_tbl[cnt].frequency = CPUFREQ_TABLE_END;
|
||||||
|
|
||||||
spear_cpufreq.freq_tbl = freq_tbl;
|
spear_cpufreq.freq_tbl = freq_tbl;
|
||||||
|
|
||||||
|
|
|
@ -267,7 +267,7 @@ static int __init sti_cpufreq_init(void)
|
||||||
goto skip_voltage_scaling;
|
goto skip_voltage_scaling;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!of_get_property(ddata.cpu->of_node, "operating-points-v2", NULL)) {
|
if (!of_property_present(ddata.cpu->of_node, "operating-points-v2")) {
|
||||||
dev_err(ddata.cpu, "OPP-v2 not supported\n");
|
dev_err(ddata.cpu, "OPP-v2 not supported\n");
|
||||||
goto skip_voltage_scaling;
|
goto skip_voltage_scaling;
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,7 +146,7 @@ static bool dt_has_supported_hw(void)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
for_each_child_of_node_scoped(np, opp) {
|
for_each_child_of_node_scoped(np, opp) {
|
||||||
if (of_find_property(opp, "opp-supported-hw", NULL)) {
|
if (of_property_present(opp, "opp-supported-hw")) {
|
||||||
has_opp_supported_hw = true;
|
has_opp_supported_hw = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <linux/pm_opp.h>
|
#include <linux/pm_opp.h>
|
||||||
#include <linux/regmap.h>
|
#include <linux/regmap.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/sys_soc.h>
|
||||||
|
|
||||||
#define REVISION_MASK 0xF
|
#define REVISION_MASK 0xF
|
||||||
#define REVISION_SHIFT 28
|
#define REVISION_SHIFT 28
|
||||||
|
@ -90,6 +91,9 @@ struct ti_cpufreq_soc_data {
|
||||||
unsigned long efuse_shift;
|
unsigned long efuse_shift;
|
||||||
unsigned long rev_offset;
|
unsigned long rev_offset;
|
||||||
bool multi_regulator;
|
bool multi_regulator;
|
||||||
|
/* Backward compatibility hack: Might have missing syscon */
|
||||||
|
#define TI_QUIRK_SYSCON_MAY_BE_MISSING 0x1
|
||||||
|
u8 quirks;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ti_cpufreq_data {
|
struct ti_cpufreq_data {
|
||||||
|
@ -254,6 +258,7 @@ static struct ti_cpufreq_soc_data omap34xx_soc_data = {
|
||||||
.efuse_mask = BIT(3),
|
.efuse_mask = BIT(3),
|
||||||
.rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE,
|
.rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE,
|
||||||
.multi_regulator = false,
|
.multi_regulator = false,
|
||||||
|
.quirks = TI_QUIRK_SYSCON_MAY_BE_MISSING,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -281,6 +286,7 @@ static struct ti_cpufreq_soc_data omap36xx_soc_data = {
|
||||||
.efuse_mask = BIT(9),
|
.efuse_mask = BIT(9),
|
||||||
.rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE,
|
.rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE,
|
||||||
.multi_regulator = true,
|
.multi_regulator = true,
|
||||||
|
.quirks = TI_QUIRK_SYSCON_MAY_BE_MISSING,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -295,6 +301,14 @@ static struct ti_cpufreq_soc_data am3517_soc_data = {
|
||||||
.efuse_mask = 0,
|
.efuse_mask = 0,
|
||||||
.rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE,
|
.rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE,
|
||||||
.multi_regulator = false,
|
.multi_regulator = false,
|
||||||
|
.quirks = TI_QUIRK_SYSCON_MAY_BE_MISSING,
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct soc_device_attribute k3_cpufreq_soc[] = {
|
||||||
|
{ .family = "AM62X", .revision = "SR1.0" },
|
||||||
|
{ .family = "AM62AX", .revision = "SR1.0" },
|
||||||
|
{ .family = "AM62PX", .revision = "SR1.0" },
|
||||||
|
{ /* sentinel */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ti_cpufreq_soc_data am625_soc_data = {
|
static struct ti_cpufreq_soc_data am625_soc_data = {
|
||||||
|
@ -340,7 +354,7 @@ static int ti_cpufreq_get_efuse(struct ti_cpufreq_data *opp_data,
|
||||||
|
|
||||||
ret = regmap_read(opp_data->syscon, opp_data->soc_data->efuse_offset,
|
ret = regmap_read(opp_data->syscon, opp_data->soc_data->efuse_offset,
|
||||||
&efuse);
|
&efuse);
|
||||||
if (ret == -EIO) {
|
if (opp_data->soc_data->quirks & TI_QUIRK_SYSCON_MAY_BE_MISSING && ret == -EIO) {
|
||||||
/* not a syscon register! */
|
/* not a syscon register! */
|
||||||
void __iomem *regs = ioremap(OMAP3_SYSCON_BASE +
|
void __iomem *regs = ioremap(OMAP3_SYSCON_BASE +
|
||||||
opp_data->soc_data->efuse_offset, 4);
|
opp_data->soc_data->efuse_offset, 4);
|
||||||
|
@ -378,10 +392,20 @@ static int ti_cpufreq_get_rev(struct ti_cpufreq_data *opp_data,
|
||||||
struct device *dev = opp_data->cpu_dev;
|
struct device *dev = opp_data->cpu_dev;
|
||||||
u32 revision;
|
u32 revision;
|
||||||
int ret;
|
int ret;
|
||||||
|
if (soc_device_match(k3_cpufreq_soc)) {
|
||||||
|
/*
|
||||||
|
* Since the SR is 1.0, hard code the revision_value as
|
||||||
|
* 0x1 here. This way we avoid re using the same register
|
||||||
|
* that is giving us required information inside socinfo
|
||||||
|
* anyway.
|
||||||
|
*/
|
||||||
|
*revision_value = 0x1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
ret = regmap_read(opp_data->syscon, opp_data->soc_data->rev_offset,
|
ret = regmap_read(opp_data->syscon, opp_data->soc_data->rev_offset,
|
||||||
&revision);
|
&revision);
|
||||||
if (ret == -EIO) {
|
if (opp_data->soc_data->quirks & TI_QUIRK_SYSCON_MAY_BE_MISSING && ret == -EIO) {
|
||||||
/* not a syscon register! */
|
/* not a syscon register! */
|
||||||
void __iomem *regs = ioremap(OMAP3_SYSCON_BASE +
|
void __iomem *regs = ioremap(OMAP3_SYSCON_BASE +
|
||||||
opp_data->soc_data->rev_offset, 4);
|
opp_data->soc_data->rev_offset, 4);
|
||||||
|
@ -400,6 +424,7 @@ static int ti_cpufreq_get_rev(struct ti_cpufreq_data *opp_data,
|
||||||
|
|
||||||
*revision_value = BIT((revision >> REVISION_SHIFT) & REVISION_MASK);
|
*revision_value = BIT((revision >> REVISION_SHIFT) & REVISION_MASK);
|
||||||
|
|
||||||
|
done:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,7 +444,7 @@ static int ti_cpufreq_setup_syscon_register(struct ti_cpufreq_data *opp_data)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct of_device_id ti_cpufreq_of_match[] = {
|
static const struct of_device_id ti_cpufreq_of_match[] __maybe_unused = {
|
||||||
{ .compatible = "ti,am33xx", .data = &am3x_soc_data, },
|
{ .compatible = "ti,am33xx", .data = &am3x_soc_data, },
|
||||||
{ .compatible = "ti,am3517", .data = &am3517_soc_data, },
|
{ .compatible = "ti,am3517", .data = &am3517_soc_data, },
|
||||||
{ .compatible = "ti,am43", .data = &am4x_soc_data, },
|
{ .compatible = "ti,am43", .data = &am4x_soc_data, },
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#define pr_fmt(fmt) "cpuidle-riscv-sbi: " fmt
|
#define pr_fmt(fmt) "cpuidle-riscv-sbi: " fmt
|
||||||
|
|
||||||
|
#include <linux/cleanup.h>
|
||||||
#include <linux/cpuhotplug.h>
|
#include <linux/cpuhotplug.h>
|
||||||
#include <linux/cpuidle.h>
|
#include <linux/cpuidle.h>
|
||||||
#include <linux/cpumask.h>
|
#include <linux/cpumask.h>
|
||||||
|
@ -236,19 +237,16 @@ static int sbi_cpuidle_dt_init_states(struct device *dev,
|
||||||
{
|
{
|
||||||
struct sbi_cpuidle_data *data = per_cpu_ptr(&sbi_cpuidle_data, cpu);
|
struct sbi_cpuidle_data *data = per_cpu_ptr(&sbi_cpuidle_data, cpu);
|
||||||
struct device_node *state_node;
|
struct device_node *state_node;
|
||||||
struct device_node *cpu_node;
|
|
||||||
u32 *states;
|
u32 *states;
|
||||||
int i, ret;
|
int i, ret;
|
||||||
|
|
||||||
cpu_node = of_cpu_device_node_get(cpu);
|
struct device_node *cpu_node __free(device_node) = of_cpu_device_node_get(cpu);
|
||||||
if (!cpu_node)
|
if (!cpu_node)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
states = devm_kcalloc(dev, state_count, sizeof(*states), GFP_KERNEL);
|
states = devm_kcalloc(dev, state_count, sizeof(*states), GFP_KERNEL);
|
||||||
if (!states) {
|
if (!states)
|
||||||
ret = -ENOMEM;
|
return -ENOMEM;
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Parse SBI specific details from state DT nodes */
|
/* Parse SBI specific details from state DT nodes */
|
||||||
for (i = 1; i < state_count; i++) {
|
for (i = 1; i < state_count; i++) {
|
||||||
|
@ -264,10 +262,8 @@ static int sbi_cpuidle_dt_init_states(struct device *dev,
|
||||||
|
|
||||||
pr_debug("sbi-state %#x index %d\n", states[i], i);
|
pr_debug("sbi-state %#x index %d\n", states[i], i);
|
||||||
}
|
}
|
||||||
if (i != state_count) {
|
if (i != state_count)
|
||||||
ret = -ENODEV;
|
return -ENODEV;
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Initialize optional data, used for the hierarchical topology. */
|
/* Initialize optional data, used for the hierarchical topology. */
|
||||||
ret = sbi_dt_cpu_init_topology(drv, data, state_count, cpu);
|
ret = sbi_dt_cpu_init_topology(drv, data, state_count, cpu);
|
||||||
|
@ -277,10 +273,7 @@ static int sbi_cpuidle_dt_init_states(struct device *dev,
|
||||||
/* Store states in the per-cpu struct. */
|
/* Store states in the per-cpu struct. */
|
||||||
data->states = states;
|
data->states = states;
|
||||||
|
|
||||||
fail:
|
return 0;
|
||||||
of_node_put(cpu_node);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sbi_cpuidle_deinit_cpu(int cpu)
|
static void sbi_cpuidle_deinit_cpu(int cpu)
|
||||||
|
@ -455,7 +448,6 @@ static void sbi_pd_remove(void)
|
||||||
|
|
||||||
static int sbi_genpd_probe(struct device_node *np)
|
static int sbi_genpd_probe(struct device_node *np)
|
||||||
{
|
{
|
||||||
struct device_node *node;
|
|
||||||
int ret = 0, pd_count = 0;
|
int ret = 0, pd_count = 0;
|
||||||
|
|
||||||
if (!np)
|
if (!np)
|
||||||
|
@ -465,13 +457,13 @@ static int sbi_genpd_probe(struct device_node *np)
|
||||||
* Parse child nodes for the "#power-domain-cells" property and
|
* Parse child nodes for the "#power-domain-cells" property and
|
||||||
* initialize a genpd/genpd-of-provider pair when it's found.
|
* initialize a genpd/genpd-of-provider pair when it's found.
|
||||||
*/
|
*/
|
||||||
for_each_child_of_node(np, node) {
|
for_each_child_of_node_scoped(np, node) {
|
||||||
if (!of_property_present(node, "#power-domain-cells"))
|
if (!of_property_present(node, "#power-domain-cells"))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ret = sbi_pd_init(node);
|
ret = sbi_pd_init(node);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto put_node;
|
goto remove_pd;
|
||||||
|
|
||||||
pd_count++;
|
pd_count++;
|
||||||
}
|
}
|
||||||
|
@ -487,8 +479,6 @@ static int sbi_genpd_probe(struct device_node *np)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
put_node:
|
|
||||||
of_node_put(node);
|
|
||||||
remove_pd:
|
remove_pd:
|
||||||
sbi_pd_remove();
|
sbi_pd_remove();
|
||||||
pr_err("failed to create CPU PM domains ret=%d\n", ret);
|
pr_err("failed to create CPU PM domains ret=%d\n", ret);
|
||||||
|
|
|
@ -228,10 +228,7 @@ noinstr int cpuidle_enter_state(struct cpuidle_device *dev,
|
||||||
if (broadcast && tick_broadcast_enter()) {
|
if (broadcast && tick_broadcast_enter()) {
|
||||||
index = find_deepest_state(drv, dev, target_state->exit_latency_ns,
|
index = find_deepest_state(drv, dev, target_state->exit_latency_ns,
|
||||||
CPUIDLE_FLAG_TIMER_STOP, false);
|
CPUIDLE_FLAG_TIMER_STOP, false);
|
||||||
if (index < 0) {
|
|
||||||
default_idle_call();
|
|
||||||
return -EBUSY;
|
|
||||||
}
|
|
||||||
target_state = &drv->states[index];
|
target_state = &drv->states[index];
|
||||||
broadcast = false;
|
broadcast = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,7 +160,6 @@ static void exynos_bus_exit(struct device *dev)
|
||||||
platform_device_unregister(bus->icc_pdev);
|
platform_device_unregister(bus->icc_pdev);
|
||||||
|
|
||||||
dev_pm_opp_of_remove_table(dev);
|
dev_pm_opp_of_remove_table(dev);
|
||||||
clk_disable_unprepare(bus->clk);
|
|
||||||
dev_pm_opp_put_regulators(bus->opp_token);
|
dev_pm_opp_put_regulators(bus->opp_token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +170,6 @@ static void exynos_bus_passive_exit(struct device *dev)
|
||||||
platform_device_unregister(bus->icc_pdev);
|
platform_device_unregister(bus->icc_pdev);
|
||||||
|
|
||||||
dev_pm_opp_of_remove_table(dev);
|
dev_pm_opp_of_remove_table(dev);
|
||||||
clk_disable_unprepare(bus->clk);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int exynos_bus_parent_parse_of(struct device_node *np,
|
static int exynos_bus_parent_parse_of(struct device_node *np,
|
||||||
|
@ -247,23 +245,16 @@ static int exynos_bus_parse_of(struct device_node *np,
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* Get the clock to provide each bus with source clock */
|
/* Get the clock to provide each bus with source clock */
|
||||||
bus->clk = devm_clk_get(dev, "bus");
|
bus->clk = devm_clk_get_enabled(dev, "bus");
|
||||||
if (IS_ERR(bus->clk)) {
|
if (IS_ERR(bus->clk))
|
||||||
dev_err(dev, "failed to get bus clock\n");
|
return dev_err_probe(dev, PTR_ERR(bus->clk),
|
||||||
return PTR_ERR(bus->clk);
|
"failed to get bus clock\n");
|
||||||
}
|
|
||||||
|
|
||||||
ret = clk_prepare_enable(bus->clk);
|
|
||||||
if (ret < 0) {
|
|
||||||
dev_err(dev, "failed to get enable clock\n");
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the freq and voltage from OPP table to scale the bus freq */
|
/* Get the freq and voltage from OPP table to scale the bus freq */
|
||||||
ret = dev_pm_opp_of_add_table(dev);
|
ret = dev_pm_opp_of_add_table(dev);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
dev_err(dev, "failed to get OPP table\n");
|
dev_err(dev, "failed to get OPP table\n");
|
||||||
goto err_clk;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
rate = clk_get_rate(bus->clk);
|
rate = clk_get_rate(bus->clk);
|
||||||
|
@ -281,8 +272,6 @@ static int exynos_bus_parse_of(struct device_node *np,
|
||||||
|
|
||||||
err_opp:
|
err_opp:
|
||||||
dev_pm_opp_of_remove_table(dev);
|
dev_pm_opp_of_remove_table(dev);
|
||||||
err_clk:
|
|
||||||
clk_disable_unprepare(bus->clk);
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -453,7 +442,6 @@ static int exynos_bus_probe(struct platform_device *pdev)
|
||||||
|
|
||||||
err:
|
err:
|
||||||
dev_pm_opp_of_remove_table(dev);
|
dev_pm_opp_of_remove_table(dev);
|
||||||
clk_disable_unprepare(bus->clk);
|
|
||||||
err_reg:
|
err_reg:
|
||||||
dev_pm_opp_put_regulators(bus->opp_token);
|
dev_pm_opp_put_regulators(bus->opp_token);
|
||||||
|
|
||||||
|
|
|
@ -58,4 +58,5 @@ static void __exit devfreq_performance_exit(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
module_exit(devfreq_performance_exit);
|
module_exit(devfreq_performance_exit);
|
||||||
|
MODULE_DESCRIPTION("DEVFREQ Performance governor");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -58,4 +58,5 @@ static void __exit devfreq_powersave_exit(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
module_exit(devfreq_powersave_exit);
|
module_exit(devfreq_powersave_exit);
|
||||||
|
MODULE_DESCRIPTION("DEVFREQ Powersave governor");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -140,4 +140,5 @@ static void __exit devfreq_simple_ondemand_exit(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
module_exit(devfreq_simple_ondemand_exit);
|
module_exit(devfreq_simple_ondemand_exit);
|
||||||
|
MODULE_DESCRIPTION("DEVFREQ Simple On-demand governor");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -153,4 +153,5 @@ static void __exit devfreq_userspace_exit(void)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
module_exit(devfreq_userspace_exit);
|
module_exit(devfreq_userspace_exit);
|
||||||
|
MODULE_DESCRIPTION("DEVFREQ Userspace governor");
|
||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
|
|
|
@ -59,7 +59,7 @@ static int imx_bus_init_icc(struct device *dev)
|
||||||
struct imx_bus *priv = dev_get_drvdata(dev);
|
struct imx_bus *priv = dev_get_drvdata(dev);
|
||||||
const char *icc_driver_name;
|
const char *icc_driver_name;
|
||||||
|
|
||||||
if (!of_get_property(dev->of_node, "#interconnect-cells", NULL))
|
if (!of_property_present(dev->of_node, "#interconnect-cells"))
|
||||||
return 0;
|
return 0;
|
||||||
if (!IS_ENABLED(CONFIG_INTERCONNECT_IMX)) {
|
if (!IS_ENABLED(CONFIG_INTERCONNECT_IMX)) {
|
||||||
dev_warn(dev, "imx interconnect drivers disabled\n");
|
dev_warn(dev, "imx interconnect drivers disabled\n");
|
||||||
|
|
|
@ -1022,6 +1022,45 @@ static struct cpuidle_state spr_cstates[] __initdata = {
|
||||||
.enter = NULL }
|
.enter = NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct cpuidle_state gnr_cstates[] __initdata = {
|
||||||
|
{
|
||||||
|
.name = "C1",
|
||||||
|
.desc = "MWAIT 0x00",
|
||||||
|
.flags = MWAIT2flg(0x00),
|
||||||
|
.exit_latency = 1,
|
||||||
|
.target_residency = 1,
|
||||||
|
.enter = &intel_idle,
|
||||||
|
.enter_s2idle = intel_idle_s2idle, },
|
||||||
|
{
|
||||||
|
.name = "C1E",
|
||||||
|
.desc = "MWAIT 0x01",
|
||||||
|
.flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE,
|
||||||
|
.exit_latency = 4,
|
||||||
|
.target_residency = 4,
|
||||||
|
.enter = &intel_idle,
|
||||||
|
.enter_s2idle = intel_idle_s2idle, },
|
||||||
|
{
|
||||||
|
.name = "C6",
|
||||||
|
.desc = "MWAIT 0x20",
|
||||||
|
.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED |
|
||||||
|
CPUIDLE_FLAG_INIT_XSTATE,
|
||||||
|
.exit_latency = 170,
|
||||||
|
.target_residency = 650,
|
||||||
|
.enter = &intel_idle,
|
||||||
|
.enter_s2idle = intel_idle_s2idle, },
|
||||||
|
{
|
||||||
|
.name = "C6P",
|
||||||
|
.desc = "MWAIT 0x21",
|
||||||
|
.flags = MWAIT2flg(0x21) | CPUIDLE_FLAG_TLB_FLUSHED |
|
||||||
|
CPUIDLE_FLAG_INIT_XSTATE,
|
||||||
|
.exit_latency = 210,
|
||||||
|
.target_residency = 1000,
|
||||||
|
.enter = &intel_idle,
|
||||||
|
.enter_s2idle = intel_idle_s2idle, },
|
||||||
|
{
|
||||||
|
.enter = NULL }
|
||||||
|
};
|
||||||
|
|
||||||
static struct cpuidle_state atom_cstates[] __initdata = {
|
static struct cpuidle_state atom_cstates[] __initdata = {
|
||||||
{
|
{
|
||||||
.name = "C1E",
|
.name = "C1E",
|
||||||
|
@ -1453,6 +1492,12 @@ static const struct idle_cpu idle_cpu_spr __initconst = {
|
||||||
.use_acpi = true,
|
.use_acpi = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct idle_cpu idle_cpu_gnr __initconst = {
|
||||||
|
.state_table = gnr_cstates,
|
||||||
|
.disable_promotion_to_c1e = true,
|
||||||
|
.use_acpi = true,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct idle_cpu idle_cpu_avn __initconst = {
|
static const struct idle_cpu idle_cpu_avn __initconst = {
|
||||||
.state_table = avn_cstates,
|
.state_table = avn_cstates,
|
||||||
.disable_promotion_to_c1e = true,
|
.disable_promotion_to_c1e = true,
|
||||||
|
@ -1475,6 +1520,10 @@ static const struct idle_cpu idle_cpu_dnv __initconst = {
|
||||||
.use_acpi = true,
|
.use_acpi = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static const struct idle_cpu idle_cpu_tmt __initconst = {
|
||||||
|
.disable_promotion_to_c1e = true,
|
||||||
|
};
|
||||||
|
|
||||||
static const struct idle_cpu idle_cpu_snr __initconst = {
|
static const struct idle_cpu idle_cpu_snr __initconst = {
|
||||||
.state_table = snr_cstates,
|
.state_table = snr_cstates,
|
||||||
.disable_promotion_to_c1e = true,
|
.disable_promotion_to_c1e = true,
|
||||||
|
@ -1533,11 +1582,14 @@ static const struct x86_cpu_id intel_idle_ids[] __initconst = {
|
||||||
X86_MATCH_VFM(INTEL_ATOM_GRACEMONT, &idle_cpu_gmt),
|
X86_MATCH_VFM(INTEL_ATOM_GRACEMONT, &idle_cpu_gmt),
|
||||||
X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X, &idle_cpu_spr),
|
X86_MATCH_VFM(INTEL_SAPPHIRERAPIDS_X, &idle_cpu_spr),
|
||||||
X86_MATCH_VFM(INTEL_EMERALDRAPIDS_X, &idle_cpu_spr),
|
X86_MATCH_VFM(INTEL_EMERALDRAPIDS_X, &idle_cpu_spr),
|
||||||
|
X86_MATCH_VFM(INTEL_GRANITERAPIDS_X, &idle_cpu_gnr),
|
||||||
X86_MATCH_VFM(INTEL_XEON_PHI_KNL, &idle_cpu_knl),
|
X86_MATCH_VFM(INTEL_XEON_PHI_KNL, &idle_cpu_knl),
|
||||||
X86_MATCH_VFM(INTEL_XEON_PHI_KNM, &idle_cpu_knl),
|
X86_MATCH_VFM(INTEL_XEON_PHI_KNM, &idle_cpu_knl),
|
||||||
X86_MATCH_VFM(INTEL_ATOM_GOLDMONT, &idle_cpu_bxt),
|
X86_MATCH_VFM(INTEL_ATOM_GOLDMONT, &idle_cpu_bxt),
|
||||||
X86_MATCH_VFM(INTEL_ATOM_GOLDMONT_PLUS, &idle_cpu_bxt),
|
X86_MATCH_VFM(INTEL_ATOM_GOLDMONT_PLUS, &idle_cpu_bxt),
|
||||||
X86_MATCH_VFM(INTEL_ATOM_GOLDMONT_D, &idle_cpu_dnv),
|
X86_MATCH_VFM(INTEL_ATOM_GOLDMONT_D, &idle_cpu_dnv),
|
||||||
|
X86_MATCH_VFM(INTEL_ATOM_TREMONT, &idle_cpu_tmt),
|
||||||
|
X86_MATCH_VFM(INTEL_ATOM_TREMONT_L, &idle_cpu_tmt),
|
||||||
X86_MATCH_VFM(INTEL_ATOM_TREMONT_D, &idle_cpu_snr),
|
X86_MATCH_VFM(INTEL_ATOM_TREMONT_D, &idle_cpu_snr),
|
||||||
X86_MATCH_VFM(INTEL_ATOM_CRESTMONT, &idle_cpu_grr),
|
X86_MATCH_VFM(INTEL_ATOM_CRESTMONT, &idle_cpu_grr),
|
||||||
X86_MATCH_VFM(INTEL_ATOM_CRESTMONT_X, &idle_cpu_srf),
|
X86_MATCH_VFM(INTEL_ATOM_CRESTMONT_X, &idle_cpu_srf),
|
||||||
|
@ -2075,7 +2127,7 @@ static void __init intel_idle_cpuidle_driver_init(struct cpuidle_driver *drv)
|
||||||
|
|
||||||
drv->state_count = 1;
|
drv->state_count = 1;
|
||||||
|
|
||||||
if (icpu)
|
if (icpu && icpu->state_table)
|
||||||
intel_idle_init_cstates_icpu(drv);
|
intel_idle_init_cstates_icpu(drv);
|
||||||
else
|
else
|
||||||
intel_idle_init_cstates_acpi(drv);
|
intel_idle_init_cstates_acpi(drv);
|
||||||
|
@ -2209,7 +2261,11 @@ static int __init intel_idle_init(void)
|
||||||
|
|
||||||
icpu = (const struct idle_cpu *)id->driver_data;
|
icpu = (const struct idle_cpu *)id->driver_data;
|
||||||
if (icpu) {
|
if (icpu) {
|
||||||
cpuidle_state_table = icpu->state_table;
|
if (icpu->state_table)
|
||||||
|
cpuidle_state_table = icpu->state_table;
|
||||||
|
else if (!intel_idle_acpi_cst_extract())
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
auto_demotion_disable_flags = icpu->auto_demotion_disable_flags;
|
auto_demotion_disable_flags = icpu->auto_demotion_disable_flags;
|
||||||
if (icpu->disable_promotion_to_c1e)
|
if (icpu->disable_promotion_to_c1e)
|
||||||
c1e_promotion = C1E_PROMOTION_DISABLE;
|
c1e_promotion = C1E_PROMOTION_DISABLE;
|
||||||
|
|
|
@ -405,7 +405,7 @@ static struct platform_driver ti_opp_supply_driver = {
|
||||||
.probe = ti_opp_supply_probe,
|
.probe = ti_opp_supply_probe,
|
||||||
.driver = {
|
.driver = {
|
||||||
.name = "ti_opp_supply",
|
.name = "ti_opp_supply",
|
||||||
.of_match_table = of_match_ptr(ti_opp_supply_of_match),
|
.of_match_table = ti_opp_supply_of_match,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
module_platform_driver(ti_opp_supply_driver);
|
module_platform_driver(ti_opp_supply_driver);
|
||||||
|
|
|
@ -740,7 +740,7 @@ static struct rapl_primitive_info *get_rpi(struct rapl_package *rp, int prim)
|
||||||
{
|
{
|
||||||
struct rapl_primitive_info *rpi = rp->priv->rpi;
|
struct rapl_primitive_info *rpi = rp->priv->rpi;
|
||||||
|
|
||||||
if (prim < 0 || prim > NR_RAPL_PRIMITIVES || !rpi)
|
if (prim < 0 || prim >= NR_RAPL_PRIMITIVES || !rpi)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return &rpi[prim];
|
return &rpi[prim];
|
||||||
|
@ -1267,6 +1267,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = {
|
||||||
X86_MATCH_VFM(INTEL_LUNARLAKE_M, &rapl_defaults_core),
|
X86_MATCH_VFM(INTEL_LUNARLAKE_M, &rapl_defaults_core),
|
||||||
X86_MATCH_VFM(INTEL_ARROWLAKE_H, &rapl_defaults_core),
|
X86_MATCH_VFM(INTEL_ARROWLAKE_H, &rapl_defaults_core),
|
||||||
X86_MATCH_VFM(INTEL_ARROWLAKE, &rapl_defaults_core),
|
X86_MATCH_VFM(INTEL_ARROWLAKE, &rapl_defaults_core),
|
||||||
|
X86_MATCH_VFM(INTEL_ARROWLAKE_U, &rapl_defaults_core),
|
||||||
X86_MATCH_VFM(INTEL_LAKEFIELD, &rapl_defaults_core),
|
X86_MATCH_VFM(INTEL_LAKEFIELD, &rapl_defaults_core),
|
||||||
|
|
||||||
X86_MATCH_VFM(INTEL_ATOM_SILVERMONT, &rapl_defaults_byt),
|
X86_MATCH_VFM(INTEL_ATOM_SILVERMONT, &rapl_defaults_byt),
|
||||||
|
@ -1285,6 +1286,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = {
|
||||||
|
|
||||||
X86_MATCH_VENDOR_FAM(AMD, 0x17, &rapl_defaults_amd),
|
X86_MATCH_VENDOR_FAM(AMD, 0x17, &rapl_defaults_amd),
|
||||||
X86_MATCH_VENDOR_FAM(AMD, 0x19, &rapl_defaults_amd),
|
X86_MATCH_VENDOR_FAM(AMD, 0x19, &rapl_defaults_amd),
|
||||||
|
X86_MATCH_VENDOR_FAM(AMD, 0x1A, &rapl_defaults_amd),
|
||||||
X86_MATCH_VENDOR_FAM(HYGON, 0x18, &rapl_defaults_amd),
|
X86_MATCH_VENDOR_FAM(HYGON, 0x18, &rapl_defaults_amd),
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
|
@ -2128,6 +2130,21 @@ void rapl_remove_package(struct rapl_package *rp)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(rapl_remove_package);
|
EXPORT_SYMBOL_GPL(rapl_remove_package);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* RAPL Package energy counter scope:
|
||||||
|
* 1. AMD/HYGON platforms use per-PKG package energy counter
|
||||||
|
* 2. For Intel platforms
|
||||||
|
* 2.1 CLX-AP platform has per-DIE package energy counter
|
||||||
|
* 2.2 Other platforms that uses MSR RAPL are single die systems so the
|
||||||
|
* package energy counter can be considered as per-PKG/per-DIE,
|
||||||
|
* here it is considered as per-DIE.
|
||||||
|
* 2.3 New platforms that use TPMI RAPL doesn't care about the
|
||||||
|
* scope because they are not MSR/CPU based.
|
||||||
|
*/
|
||||||
|
#define rapl_msrs_are_pkg_scope() \
|
||||||
|
(boot_cpu_data.x86_vendor == X86_VENDOR_AMD || \
|
||||||
|
boot_cpu_data.x86_vendor == X86_VENDOR_HYGON)
|
||||||
|
|
||||||
/* caller to ensure CPU hotplug lock is held */
|
/* caller to ensure CPU hotplug lock is held */
|
||||||
struct rapl_package *rapl_find_package_domain_cpuslocked(int id, struct rapl_if_priv *priv,
|
struct rapl_package *rapl_find_package_domain_cpuslocked(int id, struct rapl_if_priv *priv,
|
||||||
bool id_is_cpu)
|
bool id_is_cpu)
|
||||||
|
@ -2135,8 +2152,14 @@ struct rapl_package *rapl_find_package_domain_cpuslocked(int id, struct rapl_if_
|
||||||
struct rapl_package *rp;
|
struct rapl_package *rp;
|
||||||
int uid;
|
int uid;
|
||||||
|
|
||||||
if (id_is_cpu)
|
if (id_is_cpu) {
|
||||||
uid = topology_logical_die_id(id);
|
uid = rapl_msrs_are_pkg_scope() ?
|
||||||
|
topology_physical_package_id(id) : topology_logical_die_id(id);
|
||||||
|
if (uid < 0) {
|
||||||
|
pr_err("topology_logical_(package/die)_id() returned a negative value");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
uid = id;
|
uid = id;
|
||||||
|
|
||||||
|
@ -2168,9 +2191,14 @@ struct rapl_package *rapl_add_package_cpuslocked(int id, struct rapl_if_priv *pr
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
if (id_is_cpu) {
|
if (id_is_cpu) {
|
||||||
rp->id = topology_logical_die_id(id);
|
rp->id = rapl_msrs_are_pkg_scope() ?
|
||||||
|
topology_physical_package_id(id) : topology_logical_die_id(id);
|
||||||
|
if ((int)(rp->id) < 0) {
|
||||||
|
pr_err("topology_logical_(package/die)_id() returned a negative value");
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
}
|
||||||
rp->lead_cpu = id;
|
rp->lead_cpu = id;
|
||||||
if (topology_max_dies_per_package() > 1)
|
if (!rapl_msrs_are_pkg_scope() && topology_max_dies_per_package() > 1)
|
||||||
snprintf(rp->name, PACKAGE_DOMAIN_NAME_LENGTH, "package-%d-die-%d",
|
snprintf(rp->name, PACKAGE_DOMAIN_NAME_LENGTH, "package-%d-die-%d",
|
||||||
topology_physical_package_id(id), topology_die_id(id));
|
topology_physical_package_id(id), topology_die_id(id));
|
||||||
else
|
else
|
||||||
|
|
|
@ -161,34 +161,37 @@ extern int cppc_get_epp_perf(int cpunum, u64 *epp_perf);
|
||||||
extern int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable);
|
extern int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable);
|
||||||
extern int cppc_get_auto_sel_caps(int cpunum, struct cppc_perf_caps *perf_caps);
|
extern int cppc_get_auto_sel_caps(int cpunum, struct cppc_perf_caps *perf_caps);
|
||||||
extern int cppc_set_auto_sel(int cpu, bool enable);
|
extern int cppc_set_auto_sel(int cpu, bool enable);
|
||||||
|
extern int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf);
|
||||||
|
extern int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator);
|
||||||
|
extern int amd_detect_prefcore(bool *detected);
|
||||||
#else /* !CONFIG_ACPI_CPPC_LIB */
|
#else /* !CONFIG_ACPI_CPPC_LIB */
|
||||||
static inline int cppc_get_desired_perf(int cpunum, u64 *desired_perf)
|
static inline int cppc_get_desired_perf(int cpunum, u64 *desired_perf)
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
static inline int cppc_get_nominal_perf(int cpunum, u64 *nominal_perf)
|
static inline int cppc_get_nominal_perf(int cpunum, u64 *nominal_perf)
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
static inline int cppc_get_highest_perf(int cpunum, u64 *highest_perf)
|
static inline int cppc_get_highest_perf(int cpunum, u64 *highest_perf)
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
static inline int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
|
static inline int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
static inline int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
|
static inline int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
static inline int cppc_set_enable(int cpu, bool enable)
|
static inline int cppc_set_enable(int cpu, bool enable)
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
static inline int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps)
|
static inline int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps)
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
static inline bool cppc_perf_ctrs_in_pcc(void)
|
static inline bool cppc_perf_ctrs_in_pcc(void)
|
||||||
{
|
{
|
||||||
|
@ -212,27 +215,39 @@ static inline bool cpc_ffh_supported(void)
|
||||||
}
|
}
|
||||||
static inline int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val)
|
static inline int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val)
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
static inline int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val)
|
static inline int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val)
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
static inline int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable)
|
static inline int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable)
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
static inline int cppc_get_epp_perf(int cpunum, u64 *epp_perf)
|
static inline int cppc_get_epp_perf(int cpunum, u64 *epp_perf)
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
static inline int cppc_set_auto_sel(int cpu, bool enable)
|
static inline int cppc_set_auto_sel(int cpu, bool enable)
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
}
|
}
|
||||||
static inline int cppc_get_auto_sel_caps(int cpunum, struct cppc_perf_caps *perf_caps)
|
static inline int cppc_get_auto_sel_caps(int cpunum, struct cppc_perf_caps *perf_caps)
|
||||||
{
|
{
|
||||||
return -ENOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
static inline int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf)
|
||||||
|
{
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
static inline int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator)
|
||||||
|
{
|
||||||
|
return -EOPNOTSUPP;
|
||||||
|
}
|
||||||
|
static inline int amd_detect_prefcore(bool *detected)
|
||||||
|
{
|
||||||
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
#endif /* !CONFIG_ACPI_CPPC_LIB */
|
#endif /* !CONFIG_ACPI_CPPC_LIB */
|
||||||
|
|
||||||
|
|
|
@ -577,12 +577,6 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div,
|
||||||
#define CPUFREQ_POLICY_POWERSAVE (1)
|
#define CPUFREQ_POLICY_POWERSAVE (1)
|
||||||
#define CPUFREQ_POLICY_PERFORMANCE (2)
|
#define CPUFREQ_POLICY_PERFORMANCE (2)
|
||||||
|
|
||||||
/*
|
|
||||||
* The polling frequency depends on the capability of the processor. Default
|
|
||||||
* polling frequency is 1000 times the transition latency of the processor.
|
|
||||||
*/
|
|
||||||
#define LATENCY_MULTIPLIER (1000)
|
|
||||||
|
|
||||||
struct cpufreq_governor {
|
struct cpufreq_governor {
|
||||||
char name[CPUFREQ_NAME_LEN];
|
char name[CPUFREQ_NAME_LEN];
|
||||||
int (*init)(struct cpufreq_policy *policy);
|
int (*init)(struct cpufreq_policy *policy);
|
||||||
|
|
|
@ -1123,11 +1123,11 @@ static const char * const hibernation_modes[] = {
|
||||||
static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
|
static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
|
ssize_t count = 0;
|
||||||
int i;
|
int i;
|
||||||
char *start = buf;
|
|
||||||
|
|
||||||
if (!hibernation_available())
|
if (!hibernation_available())
|
||||||
return sprintf(buf, "[disabled]\n");
|
return sysfs_emit(buf, "[disabled]\n");
|
||||||
|
|
||||||
for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
|
for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
|
||||||
if (!hibernation_modes[i])
|
if (!hibernation_modes[i])
|
||||||
|
@ -1147,12 +1147,16 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (i == hibernation_mode)
|
if (i == hibernation_mode)
|
||||||
buf += sprintf(buf, "[%s] ", hibernation_modes[i]);
|
count += sysfs_emit_at(buf, count, "[%s] ", hibernation_modes[i]);
|
||||||
else
|
else
|
||||||
buf += sprintf(buf, "%s ", hibernation_modes[i]);
|
count += sysfs_emit_at(buf, count, "%s ", hibernation_modes[i]);
|
||||||
}
|
}
|
||||||
buf += sprintf(buf, "\n");
|
|
||||||
return buf-start;
|
/* Convert the last space to a newline if needed. */
|
||||||
|
if (count > 0)
|
||||||
|
buf[count - 1] = '\n';
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
|
static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
|
@ -1210,8 +1214,8 @@ power_attr(disk);
|
||||||
static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
|
static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
return sprintf(buf, "%d:%d\n", MAJOR(swsusp_resume_device),
|
return sysfs_emit(buf, "%d:%d\n", MAJOR(swsusp_resume_device),
|
||||||
MINOR(swsusp_resume_device));
|
MINOR(swsusp_resume_device));
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
|
static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
|
@ -1270,7 +1274,7 @@ power_attr(resume);
|
||||||
static ssize_t resume_offset_show(struct kobject *kobj,
|
static ssize_t resume_offset_show(struct kobject *kobj,
|
||||||
struct kobj_attribute *attr, char *buf)
|
struct kobj_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
return sprintf(buf, "%llu\n", (unsigned long long)swsusp_resume_block);
|
return sysfs_emit(buf, "%llu\n", (unsigned long long)swsusp_resume_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t resume_offset_store(struct kobject *kobj,
|
static ssize_t resume_offset_store(struct kobject *kobj,
|
||||||
|
@ -1293,7 +1297,7 @@ power_attr(resume_offset);
|
||||||
static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr,
|
static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
return sprintf(buf, "%lu\n", image_size);
|
return sysfs_emit(buf, "%lu\n", image_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *attr,
|
static ssize_t image_size_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
|
@ -1314,7 +1318,7 @@ power_attr(image_size);
|
||||||
static ssize_t reserved_size_show(struct kobject *kobj,
|
static ssize_t reserved_size_show(struct kobject *kobj,
|
||||||
struct kobj_attribute *attr, char *buf)
|
struct kobj_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
return sprintf(buf, "%lu\n", reserved_size);
|
return sysfs_emit(buf, "%lu\n", reserved_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t reserved_size_store(struct kobject *kobj,
|
static ssize_t reserved_size_store(struct kobject *kobj,
|
||||||
|
|
|
@ -115,7 +115,7 @@ int pm_async_enabled = 1;
|
||||||
static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,
|
static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
return sprintf(buf, "%d\n", pm_async_enabled);
|
return sysfs_emit(buf, "%d\n", pm_async_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr,
|
static ssize_t pm_async_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
|
@ -139,7 +139,7 @@ power_attr(pm_async);
|
||||||
static ssize_t mem_sleep_show(struct kobject *kobj, struct kobj_attribute *attr,
|
static ssize_t mem_sleep_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
char *s = buf;
|
ssize_t count = 0;
|
||||||
suspend_state_t i;
|
suspend_state_t i;
|
||||||
|
|
||||||
for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) {
|
for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++) {
|
||||||
|
@ -149,17 +149,17 @@ static ssize_t mem_sleep_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
const char *label = mem_sleep_states[i];
|
const char *label = mem_sleep_states[i];
|
||||||
|
|
||||||
if (mem_sleep_current == i)
|
if (mem_sleep_current == i)
|
||||||
s += sprintf(s, "[%s] ", label);
|
count += sysfs_emit_at(buf, count, "[%s] ", label);
|
||||||
else
|
else
|
||||||
s += sprintf(s, "%s ", label);
|
count += sysfs_emit_at(buf, count, "%s ", label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Convert the last space to a newline if needed. */
|
/* Convert the last space to a newline if needed. */
|
||||||
if (s != buf)
|
if (count > 0)
|
||||||
*(s-1) = '\n';
|
buf[count - 1] = '\n';
|
||||||
|
|
||||||
return (s - buf);
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static suspend_state_t decode_suspend_state(const char *buf, size_t n)
|
static suspend_state_t decode_suspend_state(const char *buf, size_t n)
|
||||||
|
@ -220,7 +220,7 @@ bool sync_on_suspend_enabled = !IS_ENABLED(CONFIG_SUSPEND_SKIP_SYNC);
|
||||||
static ssize_t sync_on_suspend_show(struct kobject *kobj,
|
static ssize_t sync_on_suspend_show(struct kobject *kobj,
|
||||||
struct kobj_attribute *attr, char *buf)
|
struct kobj_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
return sprintf(buf, "%d\n", sync_on_suspend_enabled);
|
return sysfs_emit(buf, "%d\n", sync_on_suspend_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t sync_on_suspend_store(struct kobject *kobj,
|
static ssize_t sync_on_suspend_store(struct kobject *kobj,
|
||||||
|
@ -257,22 +257,22 @@ static const char * const pm_tests[__TEST_AFTER_LAST] = {
|
||||||
static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,
|
static ssize_t pm_test_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
char *s = buf;
|
ssize_t count = 0;
|
||||||
int level;
|
int level;
|
||||||
|
|
||||||
for (level = TEST_FIRST; level <= TEST_MAX; level++)
|
for (level = TEST_FIRST; level <= TEST_MAX; level++)
|
||||||
if (pm_tests[level]) {
|
if (pm_tests[level]) {
|
||||||
if (level == pm_test_level)
|
if (level == pm_test_level)
|
||||||
s += sprintf(s, "[%s] ", pm_tests[level]);
|
count += sysfs_emit_at(buf, count, "[%s] ", pm_tests[level]);
|
||||||
else
|
else
|
||||||
s += sprintf(s, "%s ", pm_tests[level]);
|
count += sysfs_emit_at(buf, count, "%s ", pm_tests[level]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s != buf)
|
/* Convert the last space to a newline if needed. */
|
||||||
/* convert the last space to a newline */
|
if (count > 0)
|
||||||
*(s-1) = '\n';
|
buf[count - 1] = '\n';
|
||||||
|
|
||||||
return (s - buf);
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
|
static ssize_t pm_test_store(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
|
@ -390,7 +390,7 @@ static const char * const suspend_step_names[] = {
|
||||||
static ssize_t _name##_show(struct kobject *kobj, \
|
static ssize_t _name##_show(struct kobject *kobj, \
|
||||||
struct kobj_attribute *attr, char *buf) \
|
struct kobj_attribute *attr, char *buf) \
|
||||||
{ \
|
{ \
|
||||||
return sprintf(buf, format_str, suspend_stats._name); \
|
return sysfs_emit(buf, format_str, suspend_stats._name);\
|
||||||
} \
|
} \
|
||||||
static struct kobj_attribute _name = __ATTR_RO(_name)
|
static struct kobj_attribute _name = __ATTR_RO(_name)
|
||||||
|
|
||||||
|
@ -404,7 +404,7 @@ suspend_attr(max_hw_sleep, "%llu\n");
|
||||||
static ssize_t _name##_show(struct kobject *kobj, \
|
static ssize_t _name##_show(struct kobject *kobj, \
|
||||||
struct kobj_attribute *attr, char *buf) \
|
struct kobj_attribute *attr, char *buf) \
|
||||||
{ \
|
{ \
|
||||||
return sprintf(buf, "%u\n", \
|
return sysfs_emit(buf, "%u\n", \
|
||||||
suspend_stats.step_failures[step-1]); \
|
suspend_stats.step_failures[step-1]); \
|
||||||
} \
|
} \
|
||||||
static struct kobj_attribute _name = __ATTR_RO(_name)
|
static struct kobj_attribute _name = __ATTR_RO(_name)
|
||||||
|
@ -428,7 +428,7 @@ static ssize_t last_failed_dev_show(struct kobject *kobj,
|
||||||
index %= REC_FAILED_NUM;
|
index %= REC_FAILED_NUM;
|
||||||
last_failed_dev = suspend_stats.failed_devs[index];
|
last_failed_dev = suspend_stats.failed_devs[index];
|
||||||
|
|
||||||
return sprintf(buf, "%s\n", last_failed_dev);
|
return sysfs_emit(buf, "%s\n", last_failed_dev);
|
||||||
}
|
}
|
||||||
static struct kobj_attribute last_failed_dev = __ATTR_RO(last_failed_dev);
|
static struct kobj_attribute last_failed_dev = __ATTR_RO(last_failed_dev);
|
||||||
|
|
||||||
|
@ -442,7 +442,7 @@ static ssize_t last_failed_errno_show(struct kobject *kobj,
|
||||||
index %= REC_FAILED_NUM;
|
index %= REC_FAILED_NUM;
|
||||||
last_failed_errno = suspend_stats.errno[index];
|
last_failed_errno = suspend_stats.errno[index];
|
||||||
|
|
||||||
return sprintf(buf, "%d\n", last_failed_errno);
|
return sysfs_emit(buf, "%d\n", last_failed_errno);
|
||||||
}
|
}
|
||||||
static struct kobj_attribute last_failed_errno = __ATTR_RO(last_failed_errno);
|
static struct kobj_attribute last_failed_errno = __ATTR_RO(last_failed_errno);
|
||||||
|
|
||||||
|
@ -456,7 +456,7 @@ static ssize_t last_failed_step_show(struct kobject *kobj,
|
||||||
index %= REC_FAILED_NUM;
|
index %= REC_FAILED_NUM;
|
||||||
step = suspend_stats.failed_steps[index];
|
step = suspend_stats.failed_steps[index];
|
||||||
|
|
||||||
return sprintf(buf, "%s\n", suspend_step_names[step]);
|
return sysfs_emit(buf, "%s\n", suspend_step_names[step]);
|
||||||
}
|
}
|
||||||
static struct kobj_attribute last_failed_step = __ATTR_RO(last_failed_step);
|
static struct kobj_attribute last_failed_step = __ATTR_RO(last_failed_step);
|
||||||
|
|
||||||
|
@ -571,7 +571,7 @@ bool pm_print_times_enabled;
|
||||||
static ssize_t pm_print_times_show(struct kobject *kobj,
|
static ssize_t pm_print_times_show(struct kobject *kobj,
|
||||||
struct kobj_attribute *attr, char *buf)
|
struct kobj_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
return sprintf(buf, "%d\n", pm_print_times_enabled);
|
return sysfs_emit(buf, "%d\n", pm_print_times_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t pm_print_times_store(struct kobject *kobj,
|
static ssize_t pm_print_times_store(struct kobject *kobj,
|
||||||
|
@ -604,7 +604,7 @@ static ssize_t pm_wakeup_irq_show(struct kobject *kobj,
|
||||||
if (!pm_wakeup_irq())
|
if (!pm_wakeup_irq())
|
||||||
return -ENODATA;
|
return -ENODATA;
|
||||||
|
|
||||||
return sprintf(buf, "%u\n", pm_wakeup_irq());
|
return sysfs_emit(buf, "%u\n", pm_wakeup_irq());
|
||||||
}
|
}
|
||||||
|
|
||||||
power_attr_ro(pm_wakeup_irq);
|
power_attr_ro(pm_wakeup_irq);
|
||||||
|
@ -620,7 +620,7 @@ EXPORT_SYMBOL_GPL(pm_debug_messages_should_print);
|
||||||
static ssize_t pm_debug_messages_show(struct kobject *kobj,
|
static ssize_t pm_debug_messages_show(struct kobject *kobj,
|
||||||
struct kobj_attribute *attr, char *buf)
|
struct kobj_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
return sprintf(buf, "%d\n", pm_debug_messages_on);
|
return sysfs_emit(buf, "%d\n", pm_debug_messages_on);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t pm_debug_messages_store(struct kobject *kobj,
|
static ssize_t pm_debug_messages_store(struct kobject *kobj,
|
||||||
|
@ -668,21 +668,23 @@ struct kobject *power_kobj;
|
||||||
static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
|
static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
char *s = buf;
|
ssize_t count = 0;
|
||||||
#ifdef CONFIG_SUSPEND
|
#ifdef CONFIG_SUSPEND
|
||||||
suspend_state_t i;
|
suspend_state_t i;
|
||||||
|
|
||||||
for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++)
|
for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++)
|
||||||
if (pm_states[i])
|
if (pm_states[i])
|
||||||
s += sprintf(s,"%s ", pm_states[i]);
|
count += sysfs_emit_at(buf, count, "%s ", pm_states[i]);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
if (hibernation_available())
|
if (hibernation_available())
|
||||||
s += sprintf(s, "disk ");
|
count += sysfs_emit_at(buf, count, "disk ");
|
||||||
if (s != buf)
|
|
||||||
/* convert the last space to a newline */
|
/* Convert the last space to a newline if needed. */
|
||||||
*(s-1) = '\n';
|
if (count > 0)
|
||||||
return (s - buf);
|
buf[count - 1] = '\n';
|
||||||
|
|
||||||
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static suspend_state_t decode_state(const char *buf, size_t n)
|
static suspend_state_t decode_state(const char *buf, size_t n)
|
||||||
|
@ -782,7 +784,7 @@ static ssize_t wakeup_count_show(struct kobject *kobj,
|
||||||
unsigned int val;
|
unsigned int val;
|
||||||
|
|
||||||
return pm_get_wakeup_count(&val, true) ?
|
return pm_get_wakeup_count(&val, true) ?
|
||||||
sprintf(buf, "%u\n", val) : -EINTR;
|
sysfs_emit(buf, "%u\n", val) : -EINTR;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t wakeup_count_store(struct kobject *kobj,
|
static ssize_t wakeup_count_store(struct kobject *kobj,
|
||||||
|
@ -824,17 +826,17 @@ static ssize_t autosleep_show(struct kobject *kobj,
|
||||||
suspend_state_t state = pm_autosleep_state();
|
suspend_state_t state = pm_autosleep_state();
|
||||||
|
|
||||||
if (state == PM_SUSPEND_ON)
|
if (state == PM_SUSPEND_ON)
|
||||||
return sprintf(buf, "off\n");
|
return sysfs_emit(buf, "off\n");
|
||||||
|
|
||||||
#ifdef CONFIG_SUSPEND
|
#ifdef CONFIG_SUSPEND
|
||||||
if (state < PM_SUSPEND_MAX)
|
if (state < PM_SUSPEND_MAX)
|
||||||
return sprintf(buf, "%s\n", pm_states[state] ?
|
return sysfs_emit(buf, "%s\n", pm_states[state] ?
|
||||||
pm_states[state] : "error");
|
pm_states[state] : "error");
|
||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_HIBERNATION
|
#ifdef CONFIG_HIBERNATION
|
||||||
return sprintf(buf, "disk\n");
|
return sysfs_emit(buf, "disk\n");
|
||||||
#else
|
#else
|
||||||
return sprintf(buf, "error");
|
return sysfs_emit(buf, "error\n");
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -903,7 +905,7 @@ int pm_trace_enabled;
|
||||||
static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr,
|
static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
return sprintf(buf, "%d\n", pm_trace_enabled);
|
return sysfs_emit(buf, "%d\n", pm_trace_enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
|
@ -940,7 +942,7 @@ power_attr_ro(pm_trace_dev_match);
|
||||||
static ssize_t pm_freeze_timeout_show(struct kobject *kobj,
|
static ssize_t pm_freeze_timeout_show(struct kobject *kobj,
|
||||||
struct kobj_attribute *attr, char *buf)
|
struct kobj_attribute *attr, char *buf)
|
||||||
{
|
{
|
||||||
return sprintf(buf, "%u\n", freeze_timeout_msecs);
|
return sysfs_emit(buf, "%u\n", freeze_timeout_msecs);
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t pm_freeze_timeout_store(struct kobject *kobj,
|
static ssize_t pm_freeze_timeout_store(struct kobject *kobj,
|
||||||
|
|
|
@ -1365,11 +1365,6 @@ static unsigned int count_highmem_pages(void)
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
static inline void *saveable_highmem_page(struct zone *z, unsigned long p)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#endif /* CONFIG_HIGHMEM */
|
#endif /* CONFIG_HIGHMEM */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
8
tools/power/cpupower/bindings/python/.gitignore
vendored
Normal file
8
tools/power/cpupower/bindings/python/.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
__pycache__/
|
||||||
|
raw_pylibcpupower_wrap.c
|
||||||
|
*.o
|
||||||
|
*.so
|
||||||
|
*.py
|
||||||
|
!test_raw_pylibcpupower.py
|
||||||
|
# git keeps ignoring this file, use git add -f raw_libcpupower.i
|
||||||
|
!raw_pylibcpupower.i
|
33
tools/power/cpupower/bindings/python/Makefile
Normal file
33
tools/power/cpupower/bindings/python/Makefile
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
# Makefile for libcpupower's Python bindings
|
||||||
|
#
|
||||||
|
# This Makefile expects you have already run the makefile for cpupower to build
|
||||||
|
# the .o files in the lib directory for the bindings to be created.
|
||||||
|
|
||||||
|
CC := gcc
|
||||||
|
HAVE_SWIG := $(shell if which swig >/dev/null 2>&1; then echo 1; else echo 0; fi)
|
||||||
|
HAVE_PYCONFIG := $(shell if which python-config >/dev/null 2>&1; then echo 1; else echo 0; fi)
|
||||||
|
|
||||||
|
LIB_DIR := ../../lib
|
||||||
|
PY_INCLUDE = $(firstword $(shell python-config --includes))
|
||||||
|
OBJECTS_LIB = $(wildcard $(LIB_DIR)/*.o)
|
||||||
|
|
||||||
|
all: _raw_pylibcpupower.so
|
||||||
|
|
||||||
|
_raw_pylibcpupower.so: raw_pylibcpupower_wrap.o
|
||||||
|
$(CC) -shared $(OBJECTS_LIB) raw_pylibcpupower_wrap.o -o _raw_pylibcpupower.so
|
||||||
|
|
||||||
|
raw_pylibcpupower_wrap.o: raw_pylibcpupower_wrap.c
|
||||||
|
$(CC) -fPIC -c raw_pylibcpupower_wrap.c $(PY_INCLUDE)
|
||||||
|
|
||||||
|
raw_pylibcpupower_wrap.c: raw_pylibcpupower.i
|
||||||
|
ifeq ($(HAVE_SWIG),0)
|
||||||
|
$(error "swig was not found. Make sure you have it installed and in the PATH to generate the bindings.")
|
||||||
|
else ifeq ($(HAVE_PYCONFIG),0)
|
||||||
|
$(error "python-config was not found. Make sure you have it installed and in the PATH to generate the bindings.")
|
||||||
|
endif
|
||||||
|
swig -python raw_pylibcpupower.i
|
||||||
|
|
||||||
|
# Will only clean the bindings folder; will not clean the actual cpupower folder
|
||||||
|
clean:
|
||||||
|
rm -f raw_pylibcpupower.py raw_pylibcpupower_wrap.c raw_pylibcpupower_wrap.o _raw_pylibcpupower.so
|
59
tools/power/cpupower/bindings/python/README
Normal file
59
tools/power/cpupower/bindings/python/README
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
This folder contains the necessary files to build the Python bindings for
|
||||||
|
libcpupower (aside from the libcpupower object files).
|
||||||
|
|
||||||
|
|
||||||
|
requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
* You need the object files in the libcpupower directory compiled by
|
||||||
|
cpupower's makefile.
|
||||||
|
* The SWIG program must be installed.
|
||||||
|
* The Python's development libraries installed.
|
||||||
|
|
||||||
|
Please check that your version of SWIG is compatible with the version of Python
|
||||||
|
installed on your machine by checking the SWIG changelog on their website.
|
||||||
|
https://swig.org/
|
||||||
|
|
||||||
|
Note that while SWIG itself is GPL v3+ licensed; the resulting output,
|
||||||
|
the bindings code: is permissively licensed + the license of libcpupower's .o
|
||||||
|
files. For these bindings that means GPL v2.
|
||||||
|
|
||||||
|
Please see https://swig.org/legal.html and the discussion [1] for more details.
|
||||||
|
|
||||||
|
[1]
|
||||||
|
https://lore.kernel.org/linux-pm/Zqv9BOjxLAgyNP5B@hatbackup/
|
||||||
|
|
||||||
|
|
||||||
|
build
|
||||||
|
-----
|
||||||
|
|
||||||
|
Install SWIG and the Python development files provided by your distribution.
|
||||||
|
|
||||||
|
Build the object files for libcpupower by running make in the cpupower
|
||||||
|
directory.
|
||||||
|
|
||||||
|
Return to the directory this README is in to run:
|
||||||
|
|
||||||
|
$ make
|
||||||
|
|
||||||
|
|
||||||
|
testing
|
||||||
|
-------
|
||||||
|
|
||||||
|
Please verify the _raw_pylibcpupower.so and raw_pylibcpupower.py files have
|
||||||
|
been created.
|
||||||
|
|
||||||
|
To run the test script:
|
||||||
|
|
||||||
|
$ python test_raw_pylibcpupower.py
|
||||||
|
|
||||||
|
|
||||||
|
credits
|
||||||
|
-------
|
||||||
|
|
||||||
|
Original Bindings Author:
|
||||||
|
John B. Wyatt IV
|
||||||
|
jwyatt@redhat.com
|
||||||
|
sageofredondo@gmail.com
|
||||||
|
|
||||||
|
Copyright (C) 2024 Red Hat
|
247
tools/power/cpupower/bindings/python/raw_pylibcpupower.i
Normal file
247
tools/power/cpupower/bindings/python/raw_pylibcpupower.i
Normal file
|
@ -0,0 +1,247 @@
|
||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
|
||||||
|
%module raw_pylibcpupower
|
||||||
|
%{
|
||||||
|
#include "../../lib/cpupower_intern.h"
|
||||||
|
#include "../../lib/acpi_cppc.h"
|
||||||
|
#include "../../lib/cpufreq.h"
|
||||||
|
#include "../../lib/cpuidle.h"
|
||||||
|
#include "../../lib/cpupower.h"
|
||||||
|
#include "../../lib/powercap.h"
|
||||||
|
%}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cpupower_intern.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define PATH_TO_CPU "/sys/devices/system/cpu/"
|
||||||
|
#define MAX_LINE_LEN 4096
|
||||||
|
#define SYSFS_PATH_MAX 255
|
||||||
|
|
||||||
|
int is_valid_path(const char *path);
|
||||||
|
|
||||||
|
unsigned int cpupower_read_sysfs(const char *path, char *buf, size_t buflen);
|
||||||
|
|
||||||
|
unsigned int cpupower_write_sysfs(const char *path, char *buf, size_t buflen);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* acpi_cppc.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
enum acpi_cppc_value {
|
||||||
|
HIGHEST_PERF,
|
||||||
|
LOWEST_PERF,
|
||||||
|
NOMINAL_PERF,
|
||||||
|
LOWEST_NONLINEAR_PERF,
|
||||||
|
LOWEST_FREQ,
|
||||||
|
NOMINAL_FREQ,
|
||||||
|
REFERENCE_PERF,
|
||||||
|
WRAPAROUND_TIME,
|
||||||
|
MAX_CPPC_VALUE_FILES
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned long acpi_cppc_get_data(unsigned int cpu,
|
||||||
|
enum acpi_cppc_value which);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cpufreq.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct cpufreq_policy {
|
||||||
|
unsigned long min;
|
||||||
|
unsigned long max;
|
||||||
|
char *governor;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cpufreq_available_governors {
|
||||||
|
char *governor;
|
||||||
|
struct cpufreq_available_governors *next;
|
||||||
|
struct cpufreq_available_governors *first;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cpufreq_available_frequencies {
|
||||||
|
unsigned long frequency;
|
||||||
|
struct cpufreq_available_frequencies *next;
|
||||||
|
struct cpufreq_available_frequencies *first;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct cpufreq_affected_cpus {
|
||||||
|
unsigned int cpu;
|
||||||
|
struct cpufreq_affected_cpus *next;
|
||||||
|
struct cpufreq_affected_cpus *first;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cpufreq_stats {
|
||||||
|
unsigned long frequency;
|
||||||
|
unsigned long long time_in_state;
|
||||||
|
struct cpufreq_stats *next;
|
||||||
|
struct cpufreq_stats *first;
|
||||||
|
};
|
||||||
|
|
||||||
|
unsigned long cpufreq_get_freq_kernel(unsigned int cpu);
|
||||||
|
|
||||||
|
unsigned long cpufreq_get_freq_hardware(unsigned int cpu);
|
||||||
|
|
||||||
|
#define cpufreq_get(cpu) cpufreq_get_freq_kernel(cpu);
|
||||||
|
|
||||||
|
unsigned long cpufreq_get_transition_latency(unsigned int cpu);
|
||||||
|
|
||||||
|
int cpufreq_get_hardware_limits(unsigned int cpu,
|
||||||
|
unsigned long *min,
|
||||||
|
unsigned long *max);
|
||||||
|
|
||||||
|
char *cpufreq_get_driver(unsigned int cpu);
|
||||||
|
|
||||||
|
void cpufreq_put_driver(char *ptr);
|
||||||
|
|
||||||
|
struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu);
|
||||||
|
|
||||||
|
void cpufreq_put_policy(struct cpufreq_policy *policy);
|
||||||
|
|
||||||
|
struct cpufreq_available_governors
|
||||||
|
*cpufreq_get_available_governors(unsigned int cpu);
|
||||||
|
|
||||||
|
void cpufreq_put_available_governors(
|
||||||
|
struct cpufreq_available_governors *first);
|
||||||
|
|
||||||
|
struct cpufreq_available_frequencies
|
||||||
|
*cpufreq_get_available_frequencies(unsigned int cpu);
|
||||||
|
|
||||||
|
void cpufreq_put_available_frequencies(
|
||||||
|
struct cpufreq_available_frequencies *first);
|
||||||
|
|
||||||
|
struct cpufreq_available_frequencies
|
||||||
|
*cpufreq_get_boost_frequencies(unsigned int cpu);
|
||||||
|
|
||||||
|
void cpufreq_put_boost_frequencies(
|
||||||
|
struct cpufreq_available_frequencies *first);
|
||||||
|
|
||||||
|
struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned
|
||||||
|
int cpu);
|
||||||
|
|
||||||
|
void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *first);
|
||||||
|
|
||||||
|
struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned
|
||||||
|
int cpu);
|
||||||
|
|
||||||
|
void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *first);
|
||||||
|
|
||||||
|
struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu,
|
||||||
|
unsigned long long *total_time);
|
||||||
|
|
||||||
|
void cpufreq_put_stats(struct cpufreq_stats *stats);
|
||||||
|
|
||||||
|
unsigned long cpufreq_get_transitions(unsigned int cpu);
|
||||||
|
|
||||||
|
int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy);
|
||||||
|
|
||||||
|
int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq);
|
||||||
|
|
||||||
|
int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq);
|
||||||
|
|
||||||
|
int cpufreq_modify_policy_governor(unsigned int cpu, char *governor);
|
||||||
|
|
||||||
|
int cpufreq_set_frequency(unsigned int cpu,
|
||||||
|
unsigned long target_frequency);
|
||||||
|
|
||||||
|
unsigned long cpufreq_get_sysfs_value_from_table(unsigned int cpu,
|
||||||
|
const char **table,
|
||||||
|
unsigned int index,
|
||||||
|
unsigned int size);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cpuidle.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
int cpuidle_is_state_disabled(unsigned int cpu,
|
||||||
|
unsigned int idlestate);
|
||||||
|
int cpuidle_state_disable(unsigned int cpu, unsigned int idlestate,
|
||||||
|
unsigned int disable);
|
||||||
|
unsigned long cpuidle_state_latency(unsigned int cpu,
|
||||||
|
unsigned int idlestate);
|
||||||
|
unsigned long cpuidle_state_usage(unsigned int cpu,
|
||||||
|
unsigned int idlestate);
|
||||||
|
unsigned long long cpuidle_state_time(unsigned int cpu,
|
||||||
|
unsigned int idlestate);
|
||||||
|
char *cpuidle_state_name(unsigned int cpu,
|
||||||
|
unsigned int idlestate);
|
||||||
|
char *cpuidle_state_desc(unsigned int cpu,
|
||||||
|
unsigned int idlestate);
|
||||||
|
unsigned int cpuidle_state_count(unsigned int cpu);
|
||||||
|
|
||||||
|
char *cpuidle_get_governor(void);
|
||||||
|
|
||||||
|
char *cpuidle_get_driver(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* cpupower.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct cpupower_topology {
|
||||||
|
/* Amount of CPU cores, packages and threads per core in the system */
|
||||||
|
unsigned int cores;
|
||||||
|
unsigned int pkgs;
|
||||||
|
unsigned int threads; /* per core */
|
||||||
|
|
||||||
|
/* Array gets mallocated with cores entries, holding per core info */
|
||||||
|
struct cpuid_core_info *core_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct cpuid_core_info {
|
||||||
|
int pkg;
|
||||||
|
int core;
|
||||||
|
int cpu;
|
||||||
|
|
||||||
|
/* flags */
|
||||||
|
unsigned int is_online:1;
|
||||||
|
};
|
||||||
|
|
||||||
|
int get_cpu_topology(struct cpupower_topology *cpu_top);
|
||||||
|
|
||||||
|
void cpu_topology_release(struct cpupower_topology cpu_top);
|
||||||
|
|
||||||
|
int cpupower_is_cpu_online(unsigned int cpu);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* powercap.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct powercap_zone {
|
||||||
|
char name[MAX_LINE_LEN];
|
||||||
|
/*
|
||||||
|
* sys_name relative to PATH_TO_POWERCAP,
|
||||||
|
* do not forget the / in between
|
||||||
|
*/
|
||||||
|
char sys_name[SYSFS_PATH_MAX];
|
||||||
|
int tree_depth;
|
||||||
|
struct powercap_zone *parent;
|
||||||
|
struct powercap_zone *children[POWERCAP_MAX_CHILD_ZONES];
|
||||||
|
/* More possible caps or attributes to be added? */
|
||||||
|
uint32_t has_power_uw:1,
|
||||||
|
has_energy_uj:1;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
int powercap_walk_zones(struct powercap_zone *zone,
|
||||||
|
int (*f)(struct powercap_zone *zone));
|
||||||
|
|
||||||
|
struct powercap_zone *powercap_init_zones(void);
|
||||||
|
|
||||||
|
int powercap_get_enabled(int *mode);
|
||||||
|
|
||||||
|
int powercap_set_enabled(int mode);
|
||||||
|
|
||||||
|
int powercap_get_driver(char *driver, int buflen);
|
||||||
|
|
||||||
|
int powercap_get_max_energy_range_uj(struct powercap_zone *zone, uint64_t *val);
|
||||||
|
|
||||||
|
int powercap_get_energy_uj(struct powercap_zone *zone, uint64_t *val);
|
||||||
|
|
||||||
|
int powercap_get_max_power_range_uw(struct powercap_zone *zone, uint64_t *val);
|
||||||
|
|
||||||
|
int powercap_get_power_uw(struct powercap_zone *zone, uint64_t *val);
|
||||||
|
|
||||||
|
int powercap_zone_get_enabled(struct powercap_zone *zone, int *mode);
|
||||||
|
|
||||||
|
int powercap_zone_set_enabled(struct powercap_zone *zone, int mode);
|
42
tools/power/cpupower/bindings/python/test_raw_pylibcpupower.py
Executable file
42
tools/power/cpupower/bindings/python/test_raw_pylibcpupower.py
Executable file
|
@ -0,0 +1,42 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
|
||||||
|
import raw_pylibcpupower as p
|
||||||
|
|
||||||
|
# Simple function call
|
||||||
|
|
||||||
|
"""
|
||||||
|
Get cstate count
|
||||||
|
"""
|
||||||
|
cpu_cstates_count = p.cpuidle_state_count(0)
|
||||||
|
if cpu_cstates_count > -1:
|
||||||
|
print(f"CPU 0 has {cpu_cstates_count} c-states")
|
||||||
|
else:
|
||||||
|
print(f"cstate count error: return code: {cpu_cstates_count}")
|
||||||
|
|
||||||
|
"""
|
||||||
|
Disable cstate (will fail if the above is 0, ex: a virtual machine)
|
||||||
|
"""
|
||||||
|
cstate_disabled = p.cpuidle_state_disable(0, 0, 1)
|
||||||
|
if cpu_cstates_count == 0:
|
||||||
|
print(f"CPU 0 has {cpu_cstates_count} c-states")
|
||||||
|
else:
|
||||||
|
print(f"cstate count error: return code: {cpu_cstates_count}")
|
||||||
|
|
||||||
|
match cstate_disabled:
|
||||||
|
case 0:
|
||||||
|
print(f"CPU state disabled")
|
||||||
|
case -1:
|
||||||
|
print(f"Idlestate not available")
|
||||||
|
case _:
|
||||||
|
print(f"Not documented")
|
||||||
|
|
||||||
|
|
||||||
|
# Pointer example
|
||||||
|
|
||||||
|
topo = p.cpupower_topology()
|
||||||
|
total_cpus = p.get_cpu_topology(topo)
|
||||||
|
if total_cpus > 0:
|
||||||
|
print(f"Number of total cpus: {total_cpus} and number of cores: {topo.cores}")
|
||||||
|
else:
|
||||||
|
print(f"Error: could not get cpu topology")
|
|
@ -116,6 +116,7 @@ enum idlestate_value {
|
||||||
IDLESTATE_USAGE,
|
IDLESTATE_USAGE,
|
||||||
IDLESTATE_POWER,
|
IDLESTATE_POWER,
|
||||||
IDLESTATE_LATENCY,
|
IDLESTATE_LATENCY,
|
||||||
|
IDLESTATE_RESIDENCY,
|
||||||
IDLESTATE_TIME,
|
IDLESTATE_TIME,
|
||||||
IDLESTATE_DISABLE,
|
IDLESTATE_DISABLE,
|
||||||
MAX_IDLESTATE_VALUE_FILES
|
MAX_IDLESTATE_VALUE_FILES
|
||||||
|
@ -125,6 +126,7 @@ static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
|
||||||
[IDLESTATE_USAGE] = "usage",
|
[IDLESTATE_USAGE] = "usage",
|
||||||
[IDLESTATE_POWER] = "power",
|
[IDLESTATE_POWER] = "power",
|
||||||
[IDLESTATE_LATENCY] = "latency",
|
[IDLESTATE_LATENCY] = "latency",
|
||||||
|
[IDLESTATE_RESIDENCY] = "residency",
|
||||||
[IDLESTATE_TIME] = "time",
|
[IDLESTATE_TIME] = "time",
|
||||||
[IDLESTATE_DISABLE] = "disable",
|
[IDLESTATE_DISABLE] = "disable",
|
||||||
};
|
};
|
||||||
|
@ -254,6 +256,12 @@ unsigned long cpuidle_state_latency(unsigned int cpu,
|
||||||
return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
|
return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsigned long cpuidle_state_residency(unsigned int cpu,
|
||||||
|
unsigned int idlestate)
|
||||||
|
{
|
||||||
|
return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_RESIDENCY);
|
||||||
|
}
|
||||||
|
|
||||||
unsigned long cpuidle_state_usage(unsigned int cpu,
|
unsigned long cpuidle_state_usage(unsigned int cpu,
|
||||||
unsigned int idlestate)
|
unsigned int idlestate)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,6 +8,8 @@ int cpuidle_state_disable(unsigned int cpu, unsigned int idlestate,
|
||||||
unsigned int disable);
|
unsigned int disable);
|
||||||
unsigned long cpuidle_state_latency(unsigned int cpu,
|
unsigned long cpuidle_state_latency(unsigned int cpu,
|
||||||
unsigned int idlestate);
|
unsigned int idlestate);
|
||||||
|
unsigned long cpuidle_state_residency(unsigned int cpu,
|
||||||
|
unsigned int idlestate);
|
||||||
unsigned long cpuidle_state_usage(unsigned int cpu,
|
unsigned long cpuidle_state_usage(unsigned int cpu,
|
||||||
unsigned int idlestate);
|
unsigned int idlestate);
|
||||||
unsigned long long cpuidle_state_time(unsigned int cpu,
|
unsigned long long cpuidle_state_time(unsigned int cpu,
|
||||||
|
|
|
@ -77,6 +77,14 @@ int powercap_get_enabled(int *mode)
|
||||||
return sysfs_get_enabled(path, mode);
|
return sysfs_get_enabled(path, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: implement function. Returns dummy 0 for now.
|
||||||
|
*/
|
||||||
|
int powercap_set_enabled(int mode)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Hardcoded, because rapl is the only powercap implementation
|
* Hardcoded, because rapl is the only powercap implementation
|
||||||
- * this needs to get more generic if more powercap implementations
|
- * this needs to get more generic if more powercap implementations
|
||||||
|
|
|
@ -64,6 +64,8 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose)
|
||||||
|
|
||||||
printf(_("Latency: %lu\n"),
|
printf(_("Latency: %lu\n"),
|
||||||
cpuidle_state_latency(cpu, idlestate));
|
cpuidle_state_latency(cpu, idlestate));
|
||||||
|
printf(_("Residency: %lu\n"),
|
||||||
|
cpuidle_state_residency(cpu, idlestate));
|
||||||
printf(_("Usage: %lu\n"),
|
printf(_("Usage: %lu\n"),
|
||||||
cpuidle_state_usage(cpu, idlestate));
|
cpuidle_state_usage(cpu, idlestate));
|
||||||
printf(_("Duration: %llu\n"),
|
printf(_("Duration: %llu\n"),
|
||||||
|
@ -115,6 +117,8 @@ static void proc_cpuidle_cpu_output(unsigned int cpu)
|
||||||
printf(_("promotion[--] demotion[--] "));
|
printf(_("promotion[--] demotion[--] "));
|
||||||
printf(_("latency[%03lu] "),
|
printf(_("latency[%03lu] "),
|
||||||
cpuidle_state_latency(cpu, cstate));
|
cpuidle_state_latency(cpu, cstate));
|
||||||
|
printf(_("residency[%05lu] "),
|
||||||
|
cpuidle_state_residency(cpu, cstate));
|
||||||
printf(_("usage[%08lu] "),
|
printf(_("usage[%08lu] "),
|
||||||
cpuidle_state_usage(cpu, cstate));
|
cpuidle_state_usage(cpu, cstate));
|
||||||
printf(_("duration[%020Lu] \n"),
|
printf(_("duration[%020Lu] \n"),
|
||||||
|
|
3
tools/power/pm-graph/.gitignore
vendored
Normal file
3
tools/power/pm-graph/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
# sleepgraph.py artifacts
|
||||||
|
suspend-[0-9]*-[0-9]*
|
||||||
|
suspend-[0-9]*-[0-9]*-x[0-9]*
|
|
@ -1,51 +1,86 @@
|
||||||
# SPDX-License-Identifier: GPL-2.0
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
PREFIX ?= /usr
|
#
|
||||||
DESTDIR ?=
|
# Copyright (c) 2013, Intel Corporation.
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify it
|
||||||
|
# under the terms and conditions of the GNU General Public License,
|
||||||
|
# version 2, as published by the Free Software Foundation.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
# more details.
|
||||||
|
#
|
||||||
|
# Authors:
|
||||||
|
# Todd Brandt <todd.e.brandt@linux.intel.com>
|
||||||
|
|
||||||
|
# Prefix to the directories we're installing to
|
||||||
|
DESTDIR ?=
|
||||||
|
|
||||||
|
# Directory definitions. These are default and most probably
|
||||||
|
# do not need to be changed. Please note that DESTDIR is
|
||||||
|
# added in front of any of them
|
||||||
|
|
||||||
|
BINDIR ?= /usr/bin
|
||||||
|
MANDIR ?= /usr/share/man
|
||||||
|
LIBDIR ?= /usr/lib
|
||||||
|
|
||||||
|
# Toolchain: what tools do we use, and what options do they need:
|
||||||
|
INSTALL = /usr/bin/install
|
||||||
|
INSTALL_DATA = ${INSTALL} -m 644
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@echo "Nothing to build"
|
@echo "Nothing to build"
|
||||||
|
|
||||||
install : uninstall
|
install : uninstall
|
||||||
install -d $(DESTDIR)$(PREFIX)/lib/pm-graph
|
$(INSTALL) -d $(DESTDIR)$(LIBDIR)/pm-graph
|
||||||
install sleepgraph.py $(DESTDIR)$(PREFIX)/lib/pm-graph
|
$(INSTALL) sleepgraph.py $(DESTDIR)$(LIBDIR)/pm-graph
|
||||||
install bootgraph.py $(DESTDIR)$(PREFIX)/lib/pm-graph
|
$(INSTALL) bootgraph.py $(DESTDIR)$(LIBDIR)/pm-graph
|
||||||
install -d $(DESTDIR)$(PREFIX)/lib/pm-graph/config
|
$(INSTALL) -d $(DESTDIR)$(LIBDIR)/pm-graph/config
|
||||||
install -m 644 config/cgskip.txt $(DESTDIR)$(PREFIX)/lib/pm-graph/config
|
$(INSTALL_DATA) config/cgskip.txt $(DESTDIR)$(LIBDIR)/pm-graph/config
|
||||||
install -m 644 config/freeze-callgraph.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
|
$(INSTALL_DATA) config/freeze-callgraph.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
|
||||||
install -m 644 config/freeze.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
|
$(INSTALL_DATA) config/freeze.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
|
||||||
install -m 644 config/freeze-dev.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
|
$(INSTALL_DATA) config/freeze-dev.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
|
||||||
install -m 644 config/standby-callgraph.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
|
$(INSTALL_DATA) config/standby-callgraph.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
|
||||||
install -m 644 config/standby.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
|
$(INSTALL_DATA) config/standby.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
|
||||||
install -m 644 config/standby-dev.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
|
$(INSTALL_DATA) config/standby-dev.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
|
||||||
install -m 644 config/suspend-callgraph.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
|
$(INSTALL_DATA) config/suspend-callgraph.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
|
||||||
install -m 644 config/suspend.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
|
$(INSTALL_DATA) config/suspend.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
|
||||||
install -m 644 config/suspend-dev.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
|
$(INSTALL_DATA) config/suspend-dev.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
|
||||||
install -m 644 config/suspend-x2-proc.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
|
$(INSTALL_DATA) config/suspend-x2-proc.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
|
||||||
|
|
||||||
install -d $(DESTDIR)$(PREFIX)/bin
|
$(INSTALL) -d $(DESTDIR)$(BINDIR)
|
||||||
ln -s ../lib/pm-graph/bootgraph.py $(DESTDIR)$(PREFIX)/bin/bootgraph
|
ln -s ../lib/pm-graph/bootgraph.py $(DESTDIR)$(BINDIR)/bootgraph
|
||||||
ln -s ../lib/pm-graph/sleepgraph.py $(DESTDIR)$(PREFIX)/bin/sleepgraph
|
ln -s ../lib/pm-graph/sleepgraph.py $(DESTDIR)$(BINDIR)/sleepgraph
|
||||||
|
|
||||||
install -d $(DESTDIR)$(PREFIX)/share/man/man8
|
$(INSTALL) -d $(DESTDIR)$(MANDIR)/man8
|
||||||
install bootgraph.8 $(DESTDIR)$(PREFIX)/share/man/man8
|
$(INSTALL) bootgraph.8 $(DESTDIR)$(MANDIR)/man8
|
||||||
install sleepgraph.8 $(DESTDIR)$(PREFIX)/share/man/man8
|
$(INSTALL) sleepgraph.8 $(DESTDIR)$(MANDIR)/man8
|
||||||
|
|
||||||
uninstall :
|
uninstall :
|
||||||
rm -f $(DESTDIR)$(PREFIX)/share/man/man8/bootgraph.8
|
rm -f $(DESTDIR)$(MANDIR)/man8/bootgraph.8
|
||||||
rm -f $(DESTDIR)$(PREFIX)/share/man/man8/sleepgraph.8
|
rm -f $(DESTDIR)$(MANDIR)/man8/sleepgraph.8
|
||||||
|
|
||||||
rm -f $(DESTDIR)$(PREFIX)/bin/bootgraph
|
rm -f $(DESTDIR)$(BINDIR)/bootgraph
|
||||||
rm -f $(DESTDIR)$(PREFIX)/bin/sleepgraph
|
rm -f $(DESTDIR)$(BINDIR)/sleepgraph
|
||||||
|
|
||||||
rm -f $(DESTDIR)$(PREFIX)/lib/pm-graph/config/*
|
rm -f $(DESTDIR)$(LIBDIR)/pm-graph/config/*
|
||||||
if [ -d $(DESTDIR)$(PREFIX)/lib/pm-graph/config ] ; then \
|
if [ -d $(DESTDIR)$(LIBDIR)/pm-graph/config ] ; then \
|
||||||
rmdir $(DESTDIR)$(PREFIX)/lib/pm-graph/config; \
|
rmdir $(DESTDIR)$(LIBDIR)/pm-graph/config; \
|
||||||
fi;
|
fi;
|
||||||
rm -f $(DESTDIR)$(PREFIX)/lib/pm-graph/__pycache__/*
|
rm -f $(DESTDIR)$(LIBDIR)/pm-graph/__pycache__/*
|
||||||
if [ -d $(DESTDIR)$(PREFIX)/lib/pm-graph/__pycache__ ] ; then \
|
if [ -d $(DESTDIR)$(LIBDIR)/pm-graph/__pycache__ ] ; then \
|
||||||
rmdir $(DESTDIR)$(PREFIX)/lib/pm-graph/__pycache__; \
|
rmdir $(DESTDIR)$(LIBDIR)/pm-graph/__pycache__; \
|
||||||
fi;
|
fi;
|
||||||
rm -f $(DESTDIR)$(PREFIX)/lib/pm-graph/*
|
rm -f $(DESTDIR)$(LIBDIR)/pm-graph/*
|
||||||
if [ -d $(DESTDIR)$(PREFIX)/lib/pm-graph ] ; then \
|
if [ -d $(DESTDIR)$(LIBDIR)/pm-graph ] ; then \
|
||||||
rmdir $(DESTDIR)$(PREFIX)/lib/pm-graph; \
|
rmdir $(DESTDIR)$(LIBDIR)/pm-graph; \
|
||||||
fi;
|
fi;
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo 'Building targets:'
|
||||||
|
@echo ' all - Nothing to build'
|
||||||
|
@echo ' install - Install the program and create necessary directories'
|
||||||
|
@echo ' uninstall - Remove installed files and directories'
|
||||||
|
|
||||||
|
.PHONY: all install uninstall help
|
||||||
|
|
Loading…
Reference in New Issue
Block a user