Commit 02824a5f authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 11b31250 0a06811d
......@@ -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``
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
``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.
``amd_pstate_lowest_nonlinear_freq``
......@@ -262,6 +264,17 @@ lowest non-linear performance in `AMD CPPC Performance Capability
<perf_cap_>`_.)
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``
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.
maintainers:
- Nishanth Menon <nm@ti.com>
- Dhruva Gole <d-gole@ti.com>
allOf:
- $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
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()
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
unset.
The UNIVERSAL_DEV_PM_OPS macro is similar to SIMPLE_DEV_PM_OPS, but it
additionally sets the .runtime_resume() pointer to the same value as
.resume() (and .thaw(), and .restore()) and the .runtime_suspend() pointer to
the same value as .suspend() (and .freeze() and .poweroff()).
The DEFINE_RUNTIME_DEV_PM_OPS() is similar to DEFINE_SIMPLE_DEV_PM_OPS(), but it
additionally sets the .runtime_resume() pointer to pm_runtime_force_resume()
and the .runtime_suspend() pointer to pm_runtime_force_suspend().
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
.suspend(), .freeze(), and .poweroff() members and one resume routine is to
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,
poweroff and runtime suspend callback, and similarly for system resume, thaw,
restore, and runtime resume, can achieve this with the help of the
UNIVERSAL_DEV_PM_OPS macro defined in include/linux/pm.h (possibly setting its
restore, and runtime resume, can achieve similar behaviour with the help of the
DEFINE_RUNTIME_DEV_PM_OPS() defined in include/linux/pm_runtime.h (possibly setting its
last argument to NULL).
8. "No-Callback" Devices
......
......@@ -5851,6 +5851,9 @@ CPU POWER MONITORING SUBSYSTEM
M: Thomas Renninger <trenn@suse.com>
M: Shuah Khan <shuah@kernel.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
S: Maintained
F: tools/power/cpupower/
......
......@@ -691,8 +691,6 @@ static inline u32 per_cpu_l2c_id(unsigned int cpu)
}
#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
* operations.
......@@ -705,7 +703,6 @@ static __always_inline void amd_clear_divider(void)
extern void amd_check_microcode(void);
#else
static inline u32 amd_get_highest_perf(void) { return 0; }
static inline void amd_clear_divider(void) { }
static inline void amd_check_microcode(void) { }
#endif
......
......@@ -282,9 +282,22 @@ static inline long arch_scale_freq_capacity(int cpu)
}
#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 freq_invariance_set_perf_ratio(u64 ratio, bool turbo_disabled);
#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 freq_invariance_set_perf_ratio(u64 ratio, bool turbo_disabled) { }
#endif
......
......@@ -9,6 +9,17 @@
#include <asm/processor.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 */
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)
{
struct cppc_perf_caps perf_caps;
u64 highest_perf, nominal_perf;
u64 numerator, nominal_perf;
u64 perf_ratio;
int rc;
rc = cppc_get_perf_caps(0, &perf_caps);
if (rc) {
pr_debug("Could not retrieve perf counters (%d)\n", rc);
pr_warn("Could not retrieve perf counters (%d)\n", rc);
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;
if (!highest_perf || !nominal_perf) {
pr_debug("Could not retrieve highest or nominal performance\n");
if (!nominal_perf) {
pr_warn("Could not retrieve nominal performance\n");
return;
}
perf_ratio = div_u64(highest_perf * SCHED_CAPACITY_SCALE, nominal_perf);
/* midpoint between max_boost and max_P */
perf_ratio = (perf_ratio + SCHED_CAPACITY_SCALE) >> 1;
if (!perf_ratio) {
pr_debug("Non-zero highest/nominal perf values led to a 0 ratio\n");
return;
}
perf_ratio = (div_u64(numerator * SCHED_CAPACITY_SCALE, nominal_perf) + SCHED_CAPACITY_SCALE) >> 1;
freq_invariance_set_perf_ratio(perf_ratio, false);
}
......@@ -116,3 +126,143 @@ void init_freq_invariance_cppc(void)
init_done = true;
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);
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)
{
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;
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)
{
u64 freq_scale;
u64 freq_scale, freq_ratio;
if (!arch_scale_freq_invariant())
return;
......@@ -359,7 +439,12 @@ static void scale_freq_tick(u64 acnt, u64 mcnt)
if (check_shl_overflow(acnt, 2*SCHED_CAPACITY_SHIFT, &acnt))
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;
freq_scale = div64_u64(acnt, mcnt);
......
......@@ -231,9 +231,7 @@ if X86
source "drivers/cpufreq/Kconfig.x86"
endif
if ARM || ARM64
source "drivers/cpufreq/Kconfig.arm"
endif
if PPC32 || PPC64
source "drivers/cpufreq/Kconfig.powerpc"
......
......@@ -5,7 +5,7 @@
config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM
tristate "Allwinner nvmem based SUN50I CPUFreq driver"
depends on ARCH_SUNXI
depends on ARCH_SUNXI || COMPILE_TEST
depends on NVMEM_SUNXI_SID
select PM_OPP
help
......@@ -26,15 +26,17 @@ config ARM_APPLE_SOC_CPUFREQ
config ARM_ARMADA_37XX_CPUFREQ
tristate "Armada 37xx CPUFreq support"
depends on ARCH_MVEBU && CPUFREQ_DT
depends on ARCH_MVEBU || COMPILE_TEST
depends on CPUFREQ_DT
help
This adds the CPUFreq driver support for Marvell Armada 37xx SoCs.
The Armada 37xx PMU supports 4 frequency and VDD levels.
config ARM_ARMADA_8K_CPUFREQ
tristate "Armada 8K CPUFreq driver"
depends on ARCH_MVEBU && CPUFREQ_DT
select ARMADA_AP_CPU_CLK
depends on ARCH_MVEBU || COMPILE_TEST
depends on CPUFREQ_DT
select ARMADA_AP_CPU_CLK if COMMON_CLK
help
This enables the CPUFreq driver support for Marvell
Armada8k SOCs.
......@@ -56,7 +58,7 @@ config ARM_SCPI_CPUFREQ
config ARM_VEXPRESS_SPC_CPUFREQ
tristate "Versatile Express SPC based CPUfreq driver"
depends on ARM_CPU_TOPOLOGY && HAVE_CLK
depends on ARCH_VEXPRESS_SPC
depends on ARCH_VEXPRESS_SPC || COMPILE_TEST
select PM_OPP
help
This add the CPUfreq driver support for Versatile Express
......@@ -75,7 +77,8 @@ config ARM_BRCMSTB_AVS_CPUFREQ
config ARM_HIGHBANK_CPUFREQ
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
help
This adds the CPUFreq driver for Calxeda Highbank SoC
......@@ -96,7 +99,8 @@ config ARM_IMX6Q_CPUFREQ
config ARM_IMX_CPUFREQ_DT
tristate "Freescale i.MX8M cpufreq support"
depends on ARCH_MXC && CPUFREQ_DT
depends on CPUFREQ_DT
depends on ARCH_MXC || COMPILE_TEST
help
This adds cpufreq driver support for Freescale i.MX7/i.MX8M
series SoCs, based on cpufreq-dt.
......@@ -111,7 +115,8 @@ config ARM_KIRKWOOD_CPUFREQ
config ARM_MEDIATEK_CPUFREQ
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
help
This adds the CPUFreq driver support for MediaTek SoCs.
......@@ -130,12 +135,12 @@ config ARM_MEDIATEK_CPUFREQ_HW
config ARM_OMAP2PLUS_CPUFREQ
bool "TI OMAP2+"
depends on ARCH_OMAP2PLUS
depends on ARCH_OMAP2PLUS || COMPILE_TEST
default ARCH_OMAP2PLUS
config ARM_QCOM_CPUFREQ_NVMEM
tristate "Qualcomm nvmem based CPUFreq"
depends on ARCH_QCOM
depends on ARCH_QCOM || COMPILE_TEST
depends on NVMEM_QCOM_QFPROM
depends on QCOM_SMEM
select PM_OPP
......@@ -166,7 +171,7 @@ config ARM_RASPBERRYPI_CPUFREQ
config ARM_S3C64XX_CPUFREQ
bool "Samsung S3C64XX"
depends on CPU_S3C6410
depends on CPU_S3C6410 || COMPILE_TEST
default y
help
This adds the CPUFreq driver for Samsung S3C6410 SoC.
......@@ -175,7 +180,7 @@ config ARM_S3C64XX_CPUFREQ
config ARM_S5PV210_CPUFREQ
bool "Samsung S5PV210 and S5PC110"
depends on CPU_S5PV210
depends on CPU_S5PV210 || COMPILE_TEST
default y
help
This adds the CPUFreq driver for Samsung S5PV210 and
......@@ -199,14 +204,15 @@ config ARM_SCMI_CPUFREQ
config ARM_SPEAR_CPUFREQ
bool "SPEAr CPUFreq support"
depends on PLAT_SPEAR
depends on PLAT_SPEAR || COMPILE_TEST
default y
help
This adds the CPUFreq driver support for SPEAr SOCs.
config ARM_STI_CPUFREQ
tristate "STi CPUFreq support"
depends on CPUFREQ_DT && SOC_STIH407
depends on CPUFREQ_DT
depends on SOC_STIH407 || COMPILE_TEST
help
This driver uses the generic OPP framework to match the running
platform with a predefined set of suitable values. If not provided
......@@ -216,34 +222,38 @@ config ARM_STI_CPUFREQ
config ARM_TEGRA20_CPUFREQ
tristate "Tegra20/30 CPUFreq support"
depends on ARCH_TEGRA && CPUFREQ_DT
depends on ARCH_TEGRA || COMPILE_TEST
depends on CPUFREQ_DT
default y
help
This adds the CPUFreq driver support for Tegra20/30 SOCs.
config ARM_TEGRA124_CPUFREQ
bool "Tegra124 CPUFreq support"
depends on ARCH_TEGRA && CPUFREQ_DT
depends on ARCH_TEGRA || COMPILE_TEST
depends on CPUFREQ_DT
default y
help
This adds the CPUFreq driver support for Tegra124 SOCs.
config ARM_TEGRA186_CPUFREQ
tristate "Tegra186 CPUFreq support"
depends on ARCH_TEGRA && TEGRA_BPMP
depends on ARCH_TEGRA || COMPILE_TEST
depends on TEGRA_BPMP
help
This adds the CPUFreq driver support for Tegra186 SOCs.
config ARM_TEGRA194_CPUFREQ
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
help
This adds CPU frequency driver support for Tegra194 SOCs.
config ARM_TI_CPUFREQ
bool "Texas Instruments CPUFreq support"
depends on ARCH_OMAP2PLUS || ARCH_K3
depends on ARCH_OMAP2PLUS || ARCH_K3 || COMPILE_TEST
default y
help
This driver enables valid OPPs on the running platform based on
......@@ -255,7 +265,7 @@ config ARM_TI_CPUFREQ
config ARM_PXA2xx_CPUFREQ
tristate "Intel PXA2xx CPUfreq driver"
depends on PXA27x || PXA25x
depends on PXA27x || PXA25x || COMPILE_TEST
help
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;
}
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
highest_perf = amd_get_highest_perf();
else
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
ret = amd_get_boost_ratio_numerator(cpu, &highest_perf);
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;
}
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_perf(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[] = {
{"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_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)
......@@ -257,6 +259,43 @@ static void amd_pstate_ut_check_freq(u32 index)
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)
{
u32 i = 0, arr_size = ARRAY_SIZE(amd_pstate_ut_cases);
......
This diff is collapsed.
......@@ -103,4 +103,18 @@ struct amd_cpudata {
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 */
......@@ -85,7 +85,7 @@ static const struct apple_soc_cpufreq_info soc_default_info = {
.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",
.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;
struct freq_table *freq_tables;
struct device_node *node;
struct cpumask cpus;
static struct cpumask cpus;
node = of_find_matching_node_and_match(NULL, armada_8k_cpufreq_of_match,
NULL);
......
......@@ -166,6 +166,7 @@ static const struct of_device_id blocklist[] __initconst = {
{ .compatible = "qcom,sm6350", },
{ .compatible = "qcom,sm6375", },
{ .compatible = "qcom,sm7225", },
{ .compatible = "qcom,sm7325", },
{ .compatible = "qcom,sm8150", },
{ .compatible = "qcom,sm8250", },
{ .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)
{
struct device_node *np __free(device_node) = of_node_get(dev->of_node);
struct property *pp;
int cpu = dev->id;
/* This must be valid for sure */
......@@ -77,14 +76,10 @@ static const char *find_supply_name(struct device *dev)
return NULL;
/* Try "cpu0" for older DTs */
if (!cpu) {
pp = of_find_property(np, "cpu0-supply", NULL);
if (pp)
return "cpu0";
}
if (!cpu && of_property_present(np, "cpu0-supply"))
return "cpu0";
pp = of_find_property(np, "cpu-supply", NULL);
if (pp)
if (of_property_present(np, "cpu-supply"))
return "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;
latency = policy->cpuinfo.transition_latency / NSEC_PER_USEC;
if (latency) {
unsigned int max_delay_us = 2 * MSEC_PER_SEC;
if (latency)
/* Give a 50% breathing room between updates */
return latency + (latency >> 1);
/*
* 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;
return USEC_PER_MSEC;
}
EXPORT_SYMBOL_GPL(cpufreq_policy_transition_delay_us);
......
......@@ -16,6 +16,7 @@
#include <linux/tick.h>
#include <linux/slab.h>
#include <linux/sched/cpufreq.h>
#include <linux/sched/smt.h>
#include <linux/list.h>
#include <linux/cpu.h>
#include <linux/cpufreq.h>
......@@ -215,6 +216,7 @@ struct global_params {
* @hwp_req_cached: Cached value of the last HWP Request MSR
* @hwp_cap_cached: Cached value of the last HWP Capabilities MSR
* @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
* @hwp_boost_min: Last HWP boosted min performance
* @suspended: Whether or not the driver has been suspended.
......@@ -253,6 +255,7 @@ struct cpudata {
u64 hwp_req_cached;
u64 hwp_cap_cached;
u64 last_io_update;
unsigned int capacity_perf;
unsigned int sched_flags;
u32 hwp_boost_min;
bool suspended;
......@@ -295,6 +298,7 @@ static int hwp_mode_bdw __ro_after_init;
static bool per_cpu_limits __ro_after_init;
static bool hwp_forced __ro_after_init;
static bool hwp_boost __read_mostly;
static bool hwp_is_hybrid;
static struct cpufreq_driver *intel_pstate_driver __read_mostly;
......@@ -934,6 +938,139 @@ static struct freq_attr *hwp_cpufreq_attrs[] = {
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)
{
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)
{
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);
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
......@@ -1165,21 +1355,46 @@ static void __intel_pstate_update_max_freq(struct cpudata *cpudata,
static void intel_pstate_update_limits(unsigned int cpu)
{
struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpu);
struct cpudata *cpudata;
if (!policy)
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);
hybrid_update_capacity(cpudata);
mutex_unlock(&intel_pstate_driver_lock);
}
static void intel_pstate_update_limits_for_all(void)
{
int cpu;
for_each_possible_cpu(cpu)
intel_pstate_update_limits(cpu);
for_each_possible_cpu(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 ************************/
......@@ -1618,6 +1833,13 @@ static void intel_pstate_notify_work(struct work_struct *work)
__intel_pstate_update_max_freq(cpudata, 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);
......@@ -2034,8 +2256,10 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
if (pstate_funcs.get_cpu_scaling) {
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);
hwp_is_hybrid = true;
}
} else {
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_SAPPHIRERAPIDS_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
......@@ -2703,6 +2931,8 @@ static int intel_pstate_cpu_online(struct cpufreq_policy *policy)
*/
intel_pstate_hwp_reenable(cpu);
cpu->suspended = false;
hybrid_update_capacity(cpu);
}
return 0;
......@@ -3143,6 +3373,8 @@ static int intel_pstate_register_driver(struct cpufreq_driver *driver)
global.min_perf_pct = min_perf_pct_min();
hybrid_init_cpu_capacity_scaling();
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)
{
int retries;
unsigned int cpu = smp_processor_id();
unsigned int cpu = raw_smp_processor_id();
unsigned int package = cpu_data[cpu].package;
union smc_message msg, last;
......
......@@ -238,4 +238,5 @@ static int __init maple_cpufreq_init(void)
module_init(maple_cpufreq_init);
MODULE_DESCRIPTION("cpufreq driver for Maple 970FX/970MP boards");
MODULE_LICENSE("GPL");
......@@ -738,7 +738,7 @@ static const struct mtk_cpufreq_platform_data mt8516_platform_data = {
};
/* 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,mt2712", .data = &mt2701_platform_data },
{ .compatible = "mediatek,mt7622", .data = &mt7622_platform_data },
......
......@@ -28,9 +28,6 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <asm/smp_plat.h>
#include <asm/cpu.h>
/* OPP tolerance in percentage */
#define OPP_TOLERANCE 4
......
......@@ -269,5 +269,6 @@ static void __exit pas_cpufreq_exit(void)
module_init(pas_cpufreq_init);
module_exit(pas_cpufreq_exit);
MODULE_DESCRIPTION("cpufreq driver for PA Semi PWRficient");
MODULE_LICENSE("GPL");
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;
if (strcmp(loc, "CPU CLOCK"))
continue;
if (!of_get_property(hwclock, "platform-get-frequency", NULL))
if (!of_property_present(hwclock, "platform-get-frequency"))
continue;
break;
}
......@@ -671,4 +671,5 @@ static int __init g5_cpufreq_init(void)
module_init(g5_cpufreq_init);
MODULE_DESCRIPTION("cpufreq driver for SMU & 970FX based G5 Macs");
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
* 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_DESCRIPTION("cpufreq driver for IBM/OpenPOWER powernv systems");
MODULE_LICENSE("GPL");
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_exit(cbe_cpufreq_exit);
MODULE_DESCRIPTION("cpufreq driver for Cell BE processors");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Christian Krafft <krafft@de.ibm.com>");
......@@ -9,6 +9,7 @@
#include <linux/init.h>
#include <linux/interconnect.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.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,msm8909", .data = &match_data_msm8909 },
{ .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)
{
struct device_node *np;
const struct property *prop;
struct cpufreq_frequency_table *freq_tbl;
const __be32 *val;
int cnt, i, ret;
u32 val;
int cnt, ret, i = 0;
np = of_cpu_device_node_get(0);
if (!np) {
......@@ -186,26 +185,23 @@ static int spear_cpufreq_probe(struct platform_device *pdev)
&spear_cpufreq.transition_latency))
spear_cpufreq.transition_latency = CPUFREQ_ETERNAL;
prop = of_find_property(np, "cpufreq_tbl", NULL);
if (!prop || !prop->value) {
cnt = of_property_count_u32_elems(np, "cpufreq_tbl");
if (cnt <= 0) {
pr_err("Invalid cpufreq_tbl\n");
ret = -ENODEV;
goto out_put_node;
}
cnt = prop->length / sizeof(u32);
val = prop->value;
freq_tbl = kcalloc(cnt + 1, sizeof(*freq_tbl), GFP_KERNEL);
if (!freq_tbl) {
ret = -ENOMEM;
goto out_put_node;
}
for (i = 0; i < cnt; i++)
freq_tbl[i].frequency = be32_to_cpup(val++);
of_property_for_each_u32(np, "cpufreq_tbl", 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;
......
......@@ -267,7 +267,7 @@ static int __init sti_cpufreq_init(void)
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");
goto skip_voltage_scaling;
}
......
......@@ -146,7 +146,7 @@ static bool dt_has_supported_hw(void)
return false;
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;
break;
}
......
......@@ -16,6 +16,7 @@
#include <linux/pm_opp.h>
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/sys_soc.h>
#define REVISION_MASK 0xF
#define REVISION_SHIFT 28
......@@ -90,6 +91,9 @@ struct ti_cpufreq_soc_data {
unsigned long efuse_shift;
unsigned long rev_offset;
bool multi_regulator;
/* Backward compatibility hack: Might have missing syscon */
#define TI_QUIRK_SYSCON_MAY_BE_MISSING 0x1
u8 quirks;
};
struct ti_cpufreq_data {
......@@ -254,6 +258,7 @@ static struct ti_cpufreq_soc_data omap34xx_soc_data = {
.efuse_mask = BIT(3),
.rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE,
.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),
.rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE,
.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,
.rev_offset = OMAP3_CONTROL_IDCODE - OMAP3_SYSCON_BASE,
.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 = {
......@@ -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,
&efuse);
if (ret == -EIO) {
if (opp_data->soc_data->quirks & TI_QUIRK_SYSCON_MAY_BE_MISSING && ret == -EIO) {
/* not a syscon register! */
void __iomem *regs = ioremap(OMAP3_SYSCON_BASE +
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;
u32 revision;
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,
&revision);
if (ret == -EIO) {
if (opp_data->soc_data->quirks & TI_QUIRK_SYSCON_MAY_BE_MISSING && ret == -EIO) {
/* not a syscon register! */
void __iomem *regs = ioremap(OMAP3_SYSCON_BASE +
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);
done:
return 0;
}
......@@ -419,7 +444,7 @@ static int ti_cpufreq_setup_syscon_register(struct ti_cpufreq_data *opp_data)
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,am3517", .data = &am3517_soc_data, },
{ .compatible = "ti,am43", .data = &am4x_soc_data, },
......
......@@ -8,6 +8,7 @@
#define pr_fmt(fmt) "cpuidle-riscv-sbi: " fmt
#include <linux/cleanup.h>
#include <linux/cpuhotplug.h>
#include <linux/cpuidle.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 device_node *state_node;
struct device_node *cpu_node;
u32 *states;
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)
return -ENODEV;
states = devm_kcalloc(dev, state_count, sizeof(*states), GFP_KERNEL);
if (!states) {
ret = -ENOMEM;
goto fail;
}
if (!states)
return -ENOMEM;
/* Parse SBI specific details from state DT nodes */
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);
}
if (i != state_count) {
ret = -ENODEV;
goto fail;
}
if (i != state_count)
return -ENODEV;
/* Initialize optional data, used for the hierarchical topology. */
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. */
data->states = states;
fail:
of_node_put(cpu_node);
return ret;
return 0;
}
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)
{
struct device_node *node;
int ret = 0, pd_count = 0;
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
* 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"))
continue;
ret = sbi_pd_init(node);
if (ret)
goto put_node;
goto remove_pd;
pd_count++;
}
......@@ -487,8 +479,6 @@ static int sbi_genpd_probe(struct device_node *np)
return 0;
put_node:
of_node_put(node);
remove_pd:
sbi_pd_remove();
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()) {
index = find_deepest_state(drv, dev, target_state->exit_latency_ns,
CPUIDLE_FLAG_TIMER_STOP, false);
if (index < 0) {
default_idle_call();
return -EBUSY;
}
target_state = &drv->states[index];
broadcast = false;
}
......
......@@ -160,7 +160,6 @@ static void exynos_bus_exit(struct device *dev)
platform_device_unregister(bus->icc_pdev);
dev_pm_opp_of_remove_table(dev);
clk_disable_unprepare(bus->clk);
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);
dev_pm_opp_of_remove_table(dev);
clk_disable_unprepare(bus->clk);
}
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;
/* Get the clock to provide each bus with source clock */
bus->clk = devm_clk_get(dev, "bus");
if (IS_ERR(bus->clk)) {
dev_err(dev, "failed to get bus clock\n");
return PTR_ERR(bus->clk);
}
ret = clk_prepare_enable(bus->clk);
if (ret < 0) {
dev_err(dev, "failed to get enable clock\n");
return ret;
}
bus->clk = devm_clk_get_enabled(dev, "bus");
if (IS_ERR(bus->clk))
return dev_err_probe(dev, PTR_ERR(bus->clk),
"failed to get bus clock\n");
/* Get the freq and voltage from OPP table to scale the bus freq */
ret = dev_pm_opp_of_add_table(dev);
if (ret < 0) {
dev_err(dev, "failed to get OPP table\n");
goto err_clk;
return ret;
}
rate = clk_get_rate(bus->clk);
......@@ -281,8 +272,6 @@ static int exynos_bus_parse_of(struct device_node *np,
err_opp:
dev_pm_opp_of_remove_table(dev);
err_clk:
clk_disable_unprepare(bus->clk);
return ret;
}
......@@ -453,7 +442,6 @@ static int exynos_bus_probe(struct platform_device *pdev)
err:
dev_pm_opp_of_remove_table(dev);
clk_disable_unprepare(bus->clk);
err_reg:
dev_pm_opp_put_regulators(bus->opp_token);
......
......@@ -58,4 +58,5 @@ static void __exit devfreq_performance_exit(void)
return;
}
module_exit(devfreq_performance_exit);
MODULE_DESCRIPTION("DEVFREQ Performance governor");
MODULE_LICENSE("GPL");
......@@ -58,4 +58,5 @@ static void __exit devfreq_powersave_exit(void)
return;
}
module_exit(devfreq_powersave_exit);
MODULE_DESCRIPTION("DEVFREQ Powersave governor");
MODULE_LICENSE("GPL");
......@@ -140,4 +140,5 @@ static void __exit devfreq_simple_ondemand_exit(void)
return;
}
module_exit(devfreq_simple_ondemand_exit);
MODULE_DESCRIPTION("DEVFREQ Simple On-demand governor");
MODULE_LICENSE("GPL");
......@@ -153,4 +153,5 @@ static void __exit devfreq_userspace_exit(void)
return;
}
module_exit(devfreq_userspace_exit);
MODULE_DESCRIPTION("DEVFREQ Userspace governor");
MODULE_LICENSE("GPL");
......@@ -59,7 +59,7 @@ static int imx_bus_init_icc(struct device *dev)
struct imx_bus *priv = dev_get_drvdata(dev);
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;
if (!IS_ENABLED(CONFIG_INTERCONNECT_IMX)) {
dev_warn(dev, "imx interconnect drivers disabled\n");
......
......@@ -1022,6 +1022,45 @@ static struct cpuidle_state spr_cstates[] __initdata = {
.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 = {
{
.name = "C1E",
......@@ -1453,6 +1492,12 @@ static const struct idle_cpu idle_cpu_spr __initconst = {
.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 = {
.state_table = avn_cstates,
.disable_promotion_to_c1e = true,
......@@ -1475,6 +1520,10 @@ static const struct idle_cpu idle_cpu_dnv __initconst = {
.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 = {
.state_table = snr_cstates,
.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_SAPPHIRERAPIDS_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_KNM, &idle_cpu_knl),
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_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_CRESTMONT, &idle_cpu_grr),
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;
if (icpu)
if (icpu && icpu->state_table)
intel_idle_init_cstates_icpu(drv);
else
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;
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;
if (icpu->disable_promotion_to_c1e)
c1e_promotion = C1E_PROMOTION_DISABLE;
......
......@@ -405,7 +405,7 @@ static struct platform_driver ti_opp_supply_driver = {
.probe = ti_opp_supply_probe,
.driver = {
.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);
......
......@@ -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;
if (prim < 0 || prim > NR_RAPL_PRIMITIVES || !rpi)
if (prim < 0 || prim >= NR_RAPL_PRIMITIVES || !rpi)
return NULL;
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_ARROWLAKE_H, &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_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, 0x19, &rapl_defaults_amd),
X86_MATCH_VENDOR_FAM(AMD, 0x1A, &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);
/*
* 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 */
struct rapl_package *rapl_find_package_domain_cpuslocked(int id, struct rapl_if_priv *priv,
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;
int uid;
if (id_is_cpu)
uid = topology_logical_die_id(id);
if (id_is_cpu) {
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
uid = id;
......@@ -2168,9 +2191,14 @@ struct rapl_package *rapl_add_package_cpuslocked(int id, struct rapl_if_priv *pr
return ERR_PTR(-ENOMEM);
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;
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",
topology_physical_package_id(id), topology_die_id(id));
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_get_auto_sel_caps(int cpunum, struct cppc_perf_caps *perf_caps);
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 */
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)
{
return -ENOTSUPP;
return -EOPNOTSUPP;
}
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)
{
return -ENOTSUPP;
return -EOPNOTSUPP;
}
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)
{
return -ENOTSUPP;
return -EOPNOTSUPP;
}
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)
{
......@@ -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)
{
return -ENOTSUPP;
return -EOPNOTSUPP;
}
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)
{
return -ENOTSUPP;
return -EOPNOTSUPP;
}
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)
{
return -ENOTSUPP;
return -EOPNOTSUPP;
}
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 */
......
......@@ -577,12 +577,6 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div,
#define CPUFREQ_POLICY_POWERSAVE (1)
#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 {
char name[CPUFREQ_NAME_LEN];
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,
char *buf)
{
ssize_t count = 0;
int i;
char *start = buf;
if (!hibernation_available())
return sprintf(buf, "[disabled]\n");
return sysfs_emit(buf, "[disabled]\n");
for (i = HIBERNATION_FIRST; i <= HIBERNATION_MAX; i++) {
if (!hibernation_modes[i])
......@@ -1147,12 +1147,16 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr,
continue;
}
if (i == hibernation_mode)
buf += sprintf(buf, "[%s] ", hibernation_modes[i]);
count += sysfs_emit_at(buf, count, "[%s] ", hibernation_modes[i]);
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,
......@@ -1210,8 +1214,8 @@ power_attr(disk);
static ssize_t resume_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
return sprintf(buf, "%d:%d\n", MAJOR(swsusp_resume_device),
MINOR(swsusp_resume_device));
return sysfs_emit(buf, "%d:%d\n", MAJOR(swsusp_resume_device),
MINOR(swsusp_resume_device));
}
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,
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,
......@@ -1293,7 +1297,7 @@ power_attr(resume_offset);
static ssize_t image_size_show(struct kobject *kobj, struct kobj_attribute *attr,
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,
......@@ -1314,7 +1318,7 @@ power_attr(image_size);
static ssize_t reserved_size_show(struct kobject *kobj,
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,
......
......@@ -115,7 +115,7 @@ int pm_async_enabled = 1;
static ssize_t pm_async_show(struct kobject *kobj, struct kobj_attribute *attr,
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,
......@@ -139,7 +139,7 @@ power_attr(pm_async);
static ssize_t mem_sleep_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
char *s = buf;
ssize_t count = 0;
suspend_state_t 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];
if (mem_sleep_current == i)
s += sprintf(s, "[%s] ", label);
count += sysfs_emit_at(buf, count, "[%s] ", label);
else
s += sprintf(s, "%s ", label);
count += sysfs_emit_at(buf, count, "%s ", label);
}
}
/* Convert the last space to a newline if needed. */
if (s != buf)
*(s-1) = '\n';
if (count > 0)
buf[count - 1] = '\n';
return (s - buf);
return count;
}
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,
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,
......@@ -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,
char *buf)
{
char *s = buf;
ssize_t count = 0;
int level;
for (level = TEST_FIRST; level <= TEST_MAX; level++)
if (pm_tests[level]) {
if (level == pm_test_level)
s += sprintf(s, "[%s] ", pm_tests[level]);
count += sysfs_emit_at(buf, count, "[%s] ", pm_tests[level]);
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 */
*(s-1) = '\n';
/* Convert the last space to a newline if needed. */
if (count > 0)
buf[count - 1] = '\n';
return (s - buf);
return count;
}
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, \
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)
......@@ -404,7 +404,7 @@ suspend_attr(max_hw_sleep, "%llu\n");
static ssize_t _name##_show(struct kobject *kobj, \
struct kobj_attribute *attr, char *buf) \
{ \
return sprintf(buf, "%u\n", \
return sysfs_emit(buf, "%u\n", \
suspend_stats.step_failures[step-1]); \
} \
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;
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);
......@@ -442,7 +442,7 @@ static ssize_t last_failed_errno_show(struct kobject *kobj,
index %= REC_FAILED_NUM;
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);
......@@ -456,7 +456,7 @@ static ssize_t last_failed_step_show(struct kobject *kobj,
index %= REC_FAILED_NUM;
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);
......@@ -571,7 +571,7 @@ bool pm_print_times_enabled;
static ssize_t pm_print_times_show(struct kobject *kobj,
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,
......@@ -604,7 +604,7 @@ static ssize_t pm_wakeup_irq_show(struct kobject *kobj,
if (!pm_wakeup_irq())
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);
......@@ -620,7 +620,7 @@ EXPORT_SYMBOL_GPL(pm_debug_messages_should_print);
static ssize_t pm_debug_messages_show(struct kobject *kobj,
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,
......@@ -668,21 +668,23 @@ struct kobject *power_kobj;
static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
char *s = buf;
ssize_t count = 0;
#ifdef CONFIG_SUSPEND
suspend_state_t i;
for (i = PM_SUSPEND_MIN; i < PM_SUSPEND_MAX; i++)
if (pm_states[i])
s += sprintf(s,"%s ", pm_states[i]);
count += sysfs_emit_at(buf, count, "%s ", pm_states[i]);
#endif
if (hibernation_available())
s += sprintf(s, "disk ");
if (s != buf)
/* convert the last space to a newline */
*(s-1) = '\n';
return (s - buf);
count += sysfs_emit_at(buf, count, "disk ");
/* Convert the last space to a newline if needed. */
if (count > 0)
buf[count - 1] = '\n';
return count;
}
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;
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,
......@@ -824,17 +826,17 @@ static ssize_t autosleep_show(struct kobject *kobj,
suspend_state_t state = pm_autosleep_state();
if (state == PM_SUSPEND_ON)
return sprintf(buf, "off\n");
return sysfs_emit(buf, "off\n");
#ifdef CONFIG_SUSPEND
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");
#endif
#ifdef CONFIG_HIBERNATION
return sprintf(buf, "disk\n");
return sysfs_emit(buf, "disk\n");
#else
return sprintf(buf, "error");
return sysfs_emit(buf, "error\n");
#endif
}
......@@ -903,7 +905,7 @@ int pm_trace_enabled;
static ssize_t pm_trace_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
return sprintf(buf, "%d\n", pm_trace_enabled);
return sysfs_emit(buf, "%d\n", pm_trace_enabled);
}
static ssize_t
......@@ -940,7 +942,7 @@ power_attr_ro(pm_trace_dev_match);
static ssize_t pm_freeze_timeout_show(struct kobject *kobj,
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,
......
......@@ -1365,11 +1365,6 @@ static unsigned int count_highmem_pages(void)
}
return n;
}
#else
static inline void *saveable_highmem_page(struct zone *z, unsigned long p)
{
return NULL;
}
#endif /* CONFIG_HIGHMEM */
/**
......
__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
# 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
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
/* 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);
#!/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_POWER,
IDLESTATE_LATENCY,
IDLESTATE_RESIDENCY,
IDLESTATE_TIME,
IDLESTATE_DISABLE,
MAX_IDLESTATE_VALUE_FILES
......@@ -125,6 +126,7 @@ static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
[IDLESTATE_USAGE] = "usage",
[IDLESTATE_POWER] = "power",
[IDLESTATE_LATENCY] = "latency",
[IDLESTATE_RESIDENCY] = "residency",
[IDLESTATE_TIME] = "time",
[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);
}
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 int idlestate)
{
......
......@@ -8,6 +8,8 @@ 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_residency(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,
......
......@@ -77,6 +77,14 @@ int powercap_get_enabled(int *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
- * 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"),
cpuidle_state_latency(cpu, idlestate));
printf(_("Residency: %lu\n"),
cpuidle_state_residency(cpu, idlestate));
printf(_("Usage: %lu\n"),
cpuidle_state_usage(cpu, idlestate));
printf(_("Duration: %llu\n"),
......@@ -115,6 +117,8 @@ static void proc_cpuidle_cpu_output(unsigned int cpu)
printf(_("promotion[--] demotion[--] "));
printf(_("latency[%03lu] "),
cpuidle_state_latency(cpu, cstate));
printf(_("residency[%05lu] "),
cpuidle_state_residency(cpu, cstate));
printf(_("usage[%08lu] "),
cpuidle_state_usage(cpu, cstate));
printf(_("duration[%020Lu] \n"),
......
# sleepgraph.py artifacts
suspend-[0-9]*-[0-9]*
suspend-[0-9]*-[0-9]*-x[0-9]*
# 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:
@echo "Nothing to build"
install : uninstall
install -d $(DESTDIR)$(PREFIX)/lib/pm-graph
install sleepgraph.py $(DESTDIR)$(PREFIX)/lib/pm-graph
install bootgraph.py $(DESTDIR)$(PREFIX)/lib/pm-graph
install -d $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/cgskip.txt $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/freeze-callgraph.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/freeze.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/freeze-dev.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/standby-callgraph.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/standby.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/standby-dev.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/suspend-callgraph.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/suspend.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/suspend-dev.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -m 644 config/suspend-x2-proc.cfg $(DESTDIR)$(PREFIX)/lib/pm-graph/config
install -d $(DESTDIR)$(PREFIX)/bin
ln -s ../lib/pm-graph/bootgraph.py $(DESTDIR)$(PREFIX)/bin/bootgraph
ln -s ../lib/pm-graph/sleepgraph.py $(DESTDIR)$(PREFIX)/bin/sleepgraph
install -d $(DESTDIR)$(PREFIX)/share/man/man8
install bootgraph.8 $(DESTDIR)$(PREFIX)/share/man/man8
install sleepgraph.8 $(DESTDIR)$(PREFIX)/share/man/man8
$(INSTALL) -d $(DESTDIR)$(LIBDIR)/pm-graph
$(INSTALL) sleepgraph.py $(DESTDIR)$(LIBDIR)/pm-graph
$(INSTALL) bootgraph.py $(DESTDIR)$(LIBDIR)/pm-graph
$(INSTALL) -d $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/cgskip.txt $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/freeze-callgraph.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/freeze.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/freeze-dev.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/standby-callgraph.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/standby.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/standby-dev.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/suspend-callgraph.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/suspend.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/suspend-dev.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL_DATA) config/suspend-x2-proc.cfg $(DESTDIR)$(LIBDIR)/pm-graph/config
$(INSTALL) -d $(DESTDIR)$(BINDIR)
ln -s ../lib/pm-graph/bootgraph.py $(DESTDIR)$(BINDIR)/bootgraph
ln -s ../lib/pm-graph/sleepgraph.py $(DESTDIR)$(BINDIR)/sleepgraph
$(INSTALL) -d $(DESTDIR)$(MANDIR)/man8
$(INSTALL) bootgraph.8 $(DESTDIR)$(MANDIR)/man8
$(INSTALL) sleepgraph.8 $(DESTDIR)$(MANDIR)/man8
uninstall :
rm -f $(DESTDIR)$(PREFIX)/share/man/man8/bootgraph.8
rm -f $(DESTDIR)$(PREFIX)/share/man/man8/sleepgraph.8
rm -f $(DESTDIR)$(MANDIR)/man8/bootgraph.8
rm -f $(DESTDIR)$(MANDIR)/man8/sleepgraph.8
rm -f $(DESTDIR)$(PREFIX)/bin/bootgraph
rm -f $(DESTDIR)$(PREFIX)/bin/sleepgraph
rm -f $(DESTDIR)$(BINDIR)/bootgraph
rm -f $(DESTDIR)$(BINDIR)/sleepgraph
rm -f $(DESTDIR)$(PREFIX)/lib/pm-graph/config/*
if [ -d $(DESTDIR)$(PREFIX)/lib/pm-graph/config ] ; then \
rmdir $(DESTDIR)$(PREFIX)/lib/pm-graph/config; \
rm -f $(DESTDIR)$(LIBDIR)/pm-graph/config/*
if [ -d $(DESTDIR)$(LIBDIR)/pm-graph/config ] ; then \
rmdir $(DESTDIR)$(LIBDIR)/pm-graph/config; \
fi;
rm -f $(DESTDIR)$(PREFIX)/lib/pm-graph/__pycache__/*
if [ -d $(DESTDIR)$(PREFIX)/lib/pm-graph/__pycache__ ] ; then \
rmdir $(DESTDIR)$(PREFIX)/lib/pm-graph/__pycache__; \
rm -f $(DESTDIR)$(LIBDIR)/pm-graph/__pycache__/*
if [ -d $(DESTDIR)$(LIBDIR)/pm-graph/__pycache__ ] ; then \
rmdir $(DESTDIR)$(LIBDIR)/pm-graph/__pycache__; \
fi;
rm -f $(DESTDIR)$(PREFIX)/lib/pm-graph/*
if [ -d $(DESTDIR)$(PREFIX)/lib/pm-graph ] ; then \
rmdir $(DESTDIR)$(PREFIX)/lib/pm-graph; \
rm -f $(DESTDIR)$(LIBDIR)/pm-graph/*
if [ -d $(DESTDIR)$(LIBDIR)/pm-graph ] ; then \
rmdir $(DESTDIR)$(LIBDIR)/pm-graph; \
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
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment