projects/linux·commit a5778046

Merge tag 'pm-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

a5778046 · Linus Torvalds <[email protected]> · 2026-08-18 08:47:09 -07:00

Pull power management updates from Rafael Wysocki:
 "As has been the case for quite some time, this set of changes is
  dominated by cpufreq updates including intel-pstate and amd-pstate
  driver updates, minor fixes and cleanups of other assorted cpufreq
  drivers, schedutil governor updates, fixes of the Rust bindings, new
  hardware support (IPQ5210 in qcom-nvmem), and some updates of self
  tests related to cpufreq.

  The second largest group of changes are cpuidle updates consisting of
  intel_idle driver updates and ACPI processor idle driver updates, both
  mostly related to ACPI _LPI support.

  There are also updates related to system sleep, mostly in the
  hibernation core code, two operating performance points (OPP) updates,
  one runtime PM framework update, one power capping update, and some
  tools updates including the addition of ACPI CPPC support to cpupower.

  Specifics:

   - Minor fixes and cleanups in assorted cpufreq drivers (Dan
     Carpenter, Guru Das Srinagesh, Haoxiang Li, Karl Mehltretter, Sasha
     Finkelstein, and Pan Chuang)

   - Fix cpufreq table creation and bios_limits() callback in the Rust
     bindings (Priya Bala Govindasamy)

   - Add IPQ5210 support to qcom-nvmem driver (Varadarajan Narayanan)

   - Adjust the .adjust_perf() cpufreq driver callback to allow the
     maximum performance value to be passed to drivers and update the
     intel_pstate driver to use it (Rafael Wysocki)

   - Set policy->cur to the actual requested frequency in the
     intel_pstate driver when the performance policy is used (Rafael
     Wysocki)

   - Simplify HWP handling on Broadwell processors in intel_pstate
     (Rafael Wysocki)

   - Fix setting minimum P-state at init time in intel_pstate (Rafael
     Wysocki)

   - Consolidate frequency values computation in intel_pstate and clean
     up code in that driver (Rafael Wysocki)

   - Add missing kernel-doc descriptions for structure and union members
     in the amd-pstate driver (David Vernet)

   - Handle missing policy in dynamic EPP callbacks in the amd-pstate
     driver (EDAMAMEX)

   - Introduce EXPORT_SYMBOL_FOR_PSTATE_UT() to export amd-pstate driver
     symbols to the amd-pstate-ut subdriver (K Prateek Nayak)

   - Add dynamic EPP as an "energy_performance_preference" mode in
     amd-pstate, remove the "amd_dynamic_epp" kernel command line option
     and the "dynamic_epp" sysfs attribute, and update the dynamic_epp
     documentation accordingly (K Prateek Nayak)

   - Add unit tests for CPPC Performance Priority and the "dynamic" EPP
     mode in the amd-pstate driver (K Prateek Nayak)

   - Set min_limit_freq based on bios_min_perf in amd-pstate and remove
     the defensive check for bios_min_perf from it (K Prateek Nayak)

   - Fix EPP return type and handle errors in amd-pstate during
     initialization, toggle auto_sel in active mode on shared memory
     systems, and cache the firmware programmed EPP value (Marco
     Scardovi)

   - Skip tests in amd-pstate-ut if the amd-pstate driver is not in
     active use (Qianheng Peng)

   - Replace sprintf() with sysfs_emit() in sysfs show in the cpufreq
     schedutil governor and fix a self-contradictory comment in
     sugov_iowait_apply() (Zhongqiu Han)

   - Fix the usage example for the sampling_rate tunable of the ondemand
     cpufreq governor in admin-guide (wangxiaodong)

   - Avoid using deep idle states during initialization in the
     intel_idle driver to work around device handling issues (Rafael
     Wysocki)

   - Fix and refactor the ACPI processor driver code related to ACPI
     _LPI support and add ACPI _LPI support to intel_idle based on that
     ACPI processor driver update (Rafael Wysocki)

   - Backup and restore governor for cpufreq sptests (Yiwei Lin)

   - Remove unnecessary sudo from quick_shuffle() and remove unused
     local variables from switch_show_governor() in cpufreq selftests
     (Jinseok Kim)

   - Rename the PM core module parameter prefix to "pm" and allow the PM
     transition (DPM) watchdog to be disabled by default (Tzung-Bi Shih)

   - Fix off-by-one in wakelocks number limit check in the system sleep
     sysfs interface (Haowen Tu)

   - Remove kernel-doc markings from helper descriptions in the core
     hibernation code (Adi Nata)

   - Use %pe to print error pointer values in the hibernation core
     (Ronan Marchal)

   - Fix memory leak in snapshot_write_next() error path (Malaya Kumar
     Rout)

   - Delay allocating and linking the next swap_map_page in the
     hibernation image saving code until another image page actually
     needs to be recorded (Haesung Kim)

   - Fix cleanup ordering around scope-based pointers in OPP (Gregor
     Herburger).

   - Use clk_get_optional() for optional clocks in OPP (Praveen Talari).

   - Stop setting runtime_error on runtime resume callback failures to
     allow drivers to recover from resume issues (Praveen Talari)

   - Handle PMU registration failure during probe in the intel_rapl_tpmi
     driver (Sumeet Pawnikar)

   - Avoid optional imports in intel_pstate_tracer unless they are
     really needed (Yousef Alhouseen)

   - Add generic CPPC performance display to the cpupower utility, build
     and call CPPC information on non-AMD processors, make cpupower
     print kernel and hardware frequency information, and add libm to
     cpupower for generic CPPC view (Jeremy Linton)

   - Remove conditional return with no effect from cpupower (Sang-Heon
     Jeon)"

* tag 'pm-7.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (76 commits)
  cpufreq: imx6q: fix out-of-bounds write when probed more than once
  cpufreq: imx6q: fix devres accumulation across driver rebind
  rust: cpufreq: Fix temporary write in Registration::bios_limit_callback
  rust: cpufreq: Add CPUFREQ_TABLE_END as last table entry in TableBuilder::to_table
  opp: Use clk_get_optional() to avoid leaving opp_table->clk as an error pointer
  intel_idle: Avoid using deep idle states during initialization
  cpupower: remove conditional return with no effect
  cpufreq: intel_pstate: Adjust policy->cur in active mode to policy
  cpufreq/amd-pstate: Document missing kernel-doc members
  cpufreq/amd-pstate-ut: Add unit test for CPPC Performance Priority
  cpufreq/amd-pstate-ut: Add unit test for "dynamic" EPP mode
  cpufreq/amd-pstate: Reduce the scope of exported symbols
  Documentation/amd-pstate: Update dynamic_epp documentation with new behavior
  cpufreq/amd-pstate: Remove "amd_dynamic_epp" cmdline and "dynamic_epp" sysfs
  cpufreq/amd-pstate: Add dynamic EPP as an "energy_performance_preference" mode
  cpufreq/amd-pstate: Extract platform profile to EPP conversion into a helper
  cpufreq/amd-pstate: Remove the defensive check for bios_min_perf
  cpufreq/amd-pstate: Set min_limit_freq based on bios_min_perf
  powercap: intel_rapl_tpmi: Handle PMU registration failure during probe
  PM: sleep: Allow disabling DPM watchdog by default
  ...
Commit
a5778046a02570fd23bdf0b48dce330237d1996c
Parents
0d508f17 · 7544a367

Merge commit. Changes below are compared with the first parent: 0d508f17.

Changes

39 files changed · +1274 −737

FileStatusAddDelContent
Documentation/admin-guide/kernel-parameters.txtmodified+7−0View file
Documentation/admin-guide/pm/amd-pstate.rstmodified+22−23View file
Documentation/admin-guide/pm/cpufreq.rstmodified+1−1View file
Documentation/admin-guide/pm/intel_idle.rstmodified+31−23View file
drivers/acpi/acpi_processor.cmodified+354−0View file
drivers/acpi/processor_idle.cmodified+2−267View file
drivers/base/power/main.cmodified+14−0View file
drivers/base/power/runtime.cmodified+3−3View file
drivers/cpufreq/amd-pstate-ut.cmodified+113−23View file
drivers/cpufreq/amd-pstate.cmodified+139−131View file
drivers/cpufreq/amd-pstate.hmodified+15−0View file
drivers/cpufreq/apple-soc-cpufreq.cmodified+15−23View file
drivers/cpufreq/brcmstb-avs-cpufreq.cmodified+1−4View file
drivers/cpufreq/cpufreq-dt-platdev.cmodified+1−0View file
drivers/cpufreq/cpufreq.cmodified+9−5View file
drivers/cpufreq/imx6q-cpufreq.cmodified+4−2View file
drivers/cpufreq/intel_pstate.cmodified+90−80View file
drivers/cpufreq/qcom-cpufreq-nvmem.cmodified+8−0View file
drivers/cpufreq/rcpufreq_dt.rsmodified+10−3View file
drivers/cpufreq/spear-cpufreq.cmodified+2−2View file
drivers/idle/intel_idle.cmodified+183−35View file
drivers/opp/core.cmodified+29−38View file
drivers/powercap/intel_rapl_tpmi.cmodified+4−1View file
include/linux/acpi.hmodified+13−0View file
include/linux/cpufreq.hmodified+2−0View file
kernel/power/Kconfigmodified+10−0View file
kernel/power/snapshot.cmodified+24−23View file
kernel/power/swap.cmodified+22−12View file
kernel/power/wakelock.cmodified+1−1View file
kernel/sched/cpufreq_schedutil.cmodified+5−3View file
rust/kernel/cpufreq.rsmodified+26−9View file
tools/power/cpupower/Makefilemodified+3−3View file
tools/power/cpupower/utils/cpufreq-info.cmodified+6−5View file
tools/power/cpupower/utils/helpers/cppc.cadded+56−0View file
tools/power/cpupower/utils/helpers/helpers.hmodified+2−0View file
tools/power/cpupower/utils/powercap-info.cmodified+0−2View file
tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.pymodified+10−8View file
tools/testing/selftests/cpufreq/governor.shmodified+21−5View file
tools/testing/selftests/cpufreq/special-tests.shmodified+16−2View file

Only the first 600 diff lines are shown. Download the complete patch.

Documentation/admin-guide/kernel-parameters.txt

View file
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index e8ff369..c6ce3cc 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -47,6 +47,7 @@
PCI PCI bus support is enabled.
PCIE PCI Express support is enabled.
PCMCIA The PCMCIA subsystem is enabled.
+ PM Power Management support is enabled.
PNP Plug & Play support is enabled.
PPC PowerPC architecture is enabled.
PPT Parallel port support is enabled.
@@ -5354,6 +5355,12 @@ Kernel parameters
pm_debug_messages [SUSPEND,KNL]
Enable suspend/resume debug messages during boot up.
+ pm.dpm_watchdog_enabled=
+ [PM] Enable or disable the DPM watchdog. Requires
+ CONFIG_PM_SLEEP and CONFIG_DPM_WATCHDOG enabled.
+ Format: <bool>
+ Default value is set by CONFIG_DPM_WATCHDOG_ENABLED.
+
pnp.debug=1 [PNP]
Enable PNP debug messages (depends on the
CONFIG_PNP_DEBUG_MESSAGES option). Change at run-time

Documentation/admin-guide/pm/amd-pstate.rst

View file
diff --git a/Documentation/admin-guide/pm/amd-pstate.rst b/Documentation/admin-guide/pm/amd-pstate.rst
index a95e2eb..c7bf7cc 100644
--- a/Documentation/admin-guide/pm/amd-pstate.rst
+++ b/Documentation/admin-guide/pm/amd-pstate.rst
@@ -317,7 +317,9 @@ These profiles represent different hints that are provided
to the low-level firmware about the user's desired energy vs efficiency
tradeoff. ``default`` represents the epp value is set by platform
firmware. ``custom`` designates that integer values 0-255 may be written
-as well. This attribute is read-only.
+as well. ``dynamic`` designates that the EPP is modified dynamically
+on kernel events. See ``Dynamic energy performance profile`` section below to
+know more about the ``dynamic`` mode. This attribute is read-only.
``energy_performance_preference``
@@ -326,13 +328,11 @@ and user can change current preference according to energy or performance needs
Coarse named profiles are available in the attribute
``energy_performance_available_preferences``.
Users can also write individual integer values between 0 to 255.
-When dynamic EPP is enabled, writes to energy_performance_preference are blocked
-even when EPP feature is enabled by platform firmware. Lower epp values shift the bias
-towards improved performance while a higher epp value shifts the bias towards
-power-savings. The exact impact can change from one platform to the other.
-If a valid integer was last written, then a number will be returned on future reads.
-If a valid string was last written then a string will be returned on future reads.
-This attribute is read-write.
+Lower epp values shift the bias towards improved performance while a higher epp
+value shifts the bias towards power-savings. The exact impact can change from
+one platform to the other. If a valid integer was last written, then a number
+will be returned on future reads. If a valid string was last written then a
+string will be returned on future reads. This attribute is read-write.
``boost``
The `boost` sysfs attribute provides control over the CPU core
@@ -356,21 +356,20 @@ Other performance and frequency values can be read back from
Dynamic energy performance profile
==================================
The amd-pstate driver supports dynamically selecting the energy performance
-profile based on whether the machine is running on AC or DC power.
-
-Whether this behavior is enabled by default depends on the kernel command line option
-``amd_dynamic_epp`` is set. This behavior can also be overridden
-at runtime by the sysfs file ``/sys/devices/system/cpu/amd_pstate/dynamic_epp``.
-
-When set to enabled, the driver will select a different energy performance
-profile when the machine is running on battery or AC power. The driver will
-also register with the platform profile handler to receive notifications of
-user desired power state and react to those.
-When set to disabled, the driver will not change the energy performance profile
-based on the power source and will not react to user desired power state.
-
-Attempting to manually write to the ``energy_performance_preference`` sysfs
-file will fail when ``dynamic_epp`` is enabled.
+profile based on the system profile and the current power source in active mode.
+
+The ``dynamic`` mode is listed in
+``/sys/devices/system/cpu/cpuX/cpufreq/energy_performance_available_preferences``
+when available while running under the ``powersave`` governor. The ``dynamic``
+mode can be toggled on by writing the same to the sysfs file
+``/sys/devices/system/cpu/cpuX/cpufreq/energy_performance_preference`` when
+available.
+
+When ``energy_performance_preference`` is set to ``dynamic``, the driver will
+select a different energy performance profile when the machine is running on
+battery or AC power. The driver will also register with the platform profile
+handler to receive notifications of user desired power state and react to
+those.
``amd-pstate`` vs ``acpi-cpufreq``
======================================

Documentation/admin-guide/pm/cpufreq.rst

View file
diff --git a/Documentation/admin-guide/pm/cpufreq.rst b/Documentation/admin-guide/pm/cpufreq.rst
index 8831cfa..34baf20 100644
--- a/Documentation/admin-guide/pm/cpufreq.rst
+++ b/Documentation/admin-guide/pm/cpufreq.rst
@@ -497,7 +497,7 @@ This governor exposes the following tunables:
represented by it to be 1.5 times as high as the transition latency
(the default)::
- # echo `$(($(cat cpuinfo_transition_latency) * 3 / 2))` > ondemand/sampling_rate
+ # echo $(($(cat cpuinfo_transition_latency) * 3 / 2)) > ondemand/sampling_rate
``up_threshold``
If the estimated CPU load is above this value (in percent), the governor

Documentation/admin-guide/pm/intel_idle.rst

View file
diff --git a/Documentation/admin-guide/pm/intel_idle.rst b/Documentation/admin-guide/pm/intel_idle.rst
index 188d52c..996e5bd 100644
--- a/Documentation/admin-guide/pm/intel_idle.rst
+++ b/Documentation/admin-guide/pm/intel_idle.rst
@@ -87,17 +87,22 @@ tables with any processor model recognized by it; see
`below <intel-idle-parameters_>`_.]
If the ACPI tables are going to be used for building the list of available idle
-states, ``intel_idle`` first looks for a ``_CST`` object under one of the ACPI
-objects corresponding to the CPUs in the system (refer to the ACPI specification
-[2]_ for the description of ``_CST`` and its output package). Because the
-``CPUIdle`` subsystem expects that the list of idle states supplied by the
-driver will be suitable for all of the CPUs handled by it and ``intel_idle`` is
-registered as the ``CPUIdle`` driver for all of the CPUs in the system, the
-driver looks for the first ``_CST`` object returning at least one valid idle
-state description and such that all of the idle states included in its return
-package are of the FFH (Functional Fixed Hardware) type, which means that the
-``MWAIT`` instruction is expected to be used to tell the processor that it can
-enter one of them. The return package of that ``_CST`` is then assumed to be
+states, ``intel_idle`` will be looking for ``_LPI`` or ``_CST`` objects in them
+(refer to the ACPI specification [2]_ for the definitions of the ``_LPI`` and
+``_CST`` objects). If ``_LPI`` is present under at least one of the ACPI
+objects representing the CPUs in the system and ``_LPI`` processing produces a
+non-empty list of valid idle states, it will be used. Otherwise, ``_CST`` will
+be used so long as it is present under at least one of the ACPI objects
+representing the CPUs in the system and it returns a non-empty list of valid
+idle states. In either case, since the ``CPUIdle`` subsystem expects that the
+list of idle states supplied by the driver will be suitable for all of the CPUs
+handled by it and ``intel_idle`` is registered as the ``CPUIdle`` driver for all
+of the CPUs in the system, ``intel_idle`` looks for the first CPU where the
+ACPI-supplied list of idle states (coming from either ``_LPI`` or ``_CST``)
+is not empty. Moreover, all of the states in that list need to be of the FFH
+(Functional Fixed Hardware) type, which means that the ``MWAIT`` instruction is
+expected to be used to tell the processor that the given idle state may be
+entered. If that expectation is met, the list of idle states is assumed to be
applicable to all of the other CPUs in the system and the idle state
descriptions extracted from it are stored in a preliminary list of idle states
coming from the ACPI tables. [This step is skipped if ``intel_idle`` is
@@ -129,18 +134,21 @@ If the given processor model is not recognized by ``intel_idle``, but it
supports ``MWAIT``, the preliminary list of idle states coming from the ACPI
tables is used for building the final list that will be supplied to the
``CPUIdle`` core during driver registration. For each idle state in that list,
-the description, ``MWAIT`` hint and exit latency are copied to the corresponding
-entry in the final list of idle states. The name of the idle state represented
-by it (to be returned by the ``name`` idle state attribute in ``sysfs``) is
-"CX_ACPI", where X is the index of that idle state in the final list (note that
-the minimum value of X is 1, because 0 is reserved for the "polling" state), and
-its target residency is based on the exit latency value. Specifically, for
-C1-type idle states the exit latency value is also used as the target residency
-(for compatibility with the majority of the "internal" tables of idle states for
-various processor models recognized by ``intel_idle``) and for the other idle
-state types (C2 and C3) the target residency value is 3 times the exit latency
-(again, that is because it reflects the target residency to exit latency ratio
-in the majority of cases for the processor models recognized by ``intel_idle``).
+the description, ``MWAIT`` hint and exit (wake) latency are copied to the
+corresponding entry in the final list of idle states. If the preliminary list
+of idle states has been obtained through ``_LPI`` processing, the minimum
+residency parameter of the given idle state is taken as its target residency.
+Otherwise, for C1-type idle states, the exit latency value is also used as the
+target residency (for compatibility with the majority of the "internal" tables
+of idle states for various processor models recognized by ``intel_idle``), and
+for the other idle state types (C2 and C3) the target residency value is 3 times
+the exit latency (again, that is because it reflects the target residency to
+exit latency ratio in the majority of cases for the processor models recognized
+by ``intel_idle``). The name of the idle state (to be returned by the ``name``
+idle state attribute in ``sysfs``) is either "Cx_LPI" (if it comes from ``_LPI``
+processing) or "Cx_ACPI", where x is the index of that idle state in the final
+list (note that the minimum value of x is 1, because 0 is reserved for the
+"polling" state), and its target residency is based on the exit latency value.
All of the idle states in the final list are enabled by default in this case.

drivers/acpi/acpi_processor.c

View file
diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index 00775b9..5fbab54 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -994,3 +994,357 @@ end:
}
EXPORT_SYMBOL_NS_GPL(acpi_processor_evaluate_cst, "ACPI_PROCESSOR_IDLE");
#endif /* CONFIG_ACPI_PROCESSOR_CSTATE */
+
+#ifdef CONFIG_ACPI_PROCESSOR_IDLE
+struct acpi_lpi_states_array {
+ unsigned int size;
+ unsigned int composite_states_size;
+ struct acpi_lpi_state *entries;
+ struct acpi_lpi_state *composite_states[ACPI_PROCESSOR_MAX_POWER];
+};
+
+static int obj_get_integer(union acpi_object *obj, u32 *value)
+{
+ if (obj->type != ACPI_TYPE_INTEGER)
+ return -EINVAL;
+
+ *value = obj->integer.value;
+ return 0;
+}
+
+#define lpi_state_debug(handle, message, state_idx) \
+ acpi_handle_debug(handle, message " for _LPI state %u\n", state_idx)
+
+static void process_lpi_state_package(union acpi_object *lpi_pkg,
+ struct acpi_lpi_state *lpi_state,
+ acpi_handle handle,
+ unsigned int state_idx, bool strict)
+{
+ union acpi_object *lpi_pkg_elem, *obj;
+
+ if (lpi_pkg->type != ACPI_TYPE_PACKAGE || lpi_pkg->package.count < 7)
+ return;
+
+ lpi_pkg_elem = lpi_pkg->package.elements;
+
+ /* Get the entry method first and skip the state if that fails. */
+ obj = &lpi_pkg_elem[6];
+ if (obj->type == ACPI_TYPE_BUFFER) {
+ struct acpi_power_register *reg;
+
+ if (obj->buffer.length < sizeof(*reg)) {
+ lpi_state_debug(handle, "Invalid register data", state_idx);
+ return;
+ }
+
+ reg = (struct acpi_power_register *)obj->buffer.pointer;
+ if (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE) {
+ lpi_state_debug(handle, "Unsupported entry method", state_idx);
+ return;
+ }
+
+ lpi_state->entry_method = ACPI_CSTATE_FFH;
+ lpi_state->address = reg->address;
+ } else if (obj->type == ACPI_TYPE_INTEGER) {
+ lpi_state->entry_method = ACPI_CSTATE_INTEGER;
+ lpi_state->address = obj->integer.value;
+ } else {
+ lpi_state_debug(handle, "Invalid entry method", state_idx);
+ return;
+ }
+
+ if (obj_get_integer(&lpi_pkg_elem[0], &lpi_state->min_residency)) {
+ if (strict) {
+ lpi_state_debug(handle, "No min. residency", state_idx);
+ return;
+ }
+
+ lpi_state_debug(handle, "Assuming 10 us min. residency", state_idx);
+ lpi_state->min_residency = 10;
+ }
+
+ if (obj_get_integer(&lpi_pkg_elem[1], &lpi_state->wake_latency)) {
+ if (strict) {
+ lpi_state_debug(handle, "No wake latency", state_idx);
+ return;
+ }
+
+ lpi_state_debug(handle, "Assuming 10 us wake latency", state_idx);
+ lpi_state->wake_latency = 10;
+ }
+
+ if (obj_get_integer(&lpi_pkg_elem[2], &lpi_state->flags))
+ lpi_state->flags = 0;
+
+ if (obj_get_integer(&lpi_pkg_elem[3], &lpi_state->arch_flags))
+ lpi_state->arch_flags = 0;
+
+ if (obj_get_integer(&lpi_pkg_elem[4], &lpi_state->res_cnt_freq))
+ lpi_state->res_cnt_freq = 1;
+
+ if (obj_get_integer(&lpi_pkg_elem[5], &lpi_state->enable_parent_state))
+ lpi_state->enable_parent_state = 0;
+
+ /* Skip elements [7-8] i.e. Residency/Usage counters. */
+
+ /*
+ * Avoid out-of-bounds access if the size of the package is less than
+ * expected.
+ */
+ if (lpi_pkg->package.count < 10)
+ return;
+
+ obj = &lpi_pkg_elem[9];
+ if (obj->type == ACPI_TYPE_STRING)
+ strscpy(lpi_state->desc, obj->string.pointer, ACPI_CX_DESC_LEN);
+}
+
+static int acpi_processor_evaluate_lpi(acpi_handle handle,
+ struct acpi_lpi_states_array *info,
+ bool strict)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *lpi_data, *lpi_pkg;
+ unsigned int lpi_pkg_count, state_idx;
+ struct acpi_lpi_state *lpi_state;
+ acpi_status status;
+ int ret = 0;
+
+ status = acpi_evaluate_object(handle, "_LPI", NULL, &buffer);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_debug(handle, "No _LPI, giving up\n");
+ return -ENODEV;
+ }
+
+ lpi_data = buffer.pointer;
+
+ /* There must be at least 4 elements = 3 elements + 1 package */
+ if (!lpi_data || lpi_data->type != ACPI_TYPE_PACKAGE ||
+ lpi_data->package.count < 4) {
+ acpi_handle_debug(handle, "Not enough elements in _LPI\n");
+ ret = -ENODATA;
+ goto end;
+ }
+
+ lpi_pkg_count = lpi_data->package.elements[2].integer.value;
+
+ /* Validate number of power states. */
+ if (!lpi_pkg_count || lpi_pkg_count != lpi_data->package.count - 3) {
+ acpi_handle_debug(handle, "Invalid _LPI state count\n");
+ ret = -ENODATA;
+ goto end;
+ }
+
+ lpi_state = kzalloc_objs(*lpi_state, lpi_pkg_count);
+ if (!lpi_state) {
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ info->size = lpi_pkg_count;
+ info->entries = lpi_state;
+
+ /* _LPI State packages start at index 3. */
+ lpi_pkg = &lpi_data->package.elements[3];
+
+ for (state_idx = 1; state_idx <= lpi_pkg_count; state_idx++) {
+ lpi_state->index = state_idx;
+ process_lpi_state_package(lpi_pkg++, lpi_state++, handle,
+ state_idx, strict);
+ }
+
+ acpi_handle_debug(handle, "Found %u power states\n", lpi_pkg_count);
+end:
+ kfree(buffer.pointer);
+ return ret;
+}
+
+/**
+ * combine_lpi_states - combine local and parent LPI states to form a composite LPI state
+ *
+ * @local: local LPI state
+ * @parent: parent LPI state
+ * @result: composite LPI state
+ */
+static bool combine_lpi_states(struct acpi_lpi_state *local,
+ struct acpi_lpi_state *parent,
+ struct acpi_lpi_state *result)
+{
+ if (parent->entry_method == ACPI_CSTATE_INTEGER) {
+ if (!parent->address) /* 0 means autopromotable */
+ return false;
+ result->address = local->address + parent->address;
+ } else {
+ result->address = parent->address;
+ }
+
+ result->min_residency = max(local->min_residency, parent->min_residency);
+ result->wake_latency = local->wake_latency + parent->wake_latency;
+ result->enable_parent_state = parent->enable_parent_state;
+ result->entry_method = local->entry_method;
+
+ result->flags = parent->flags;
+ result->arch_flags = parent->arch_flags;
+ result->index = parent->index;
+
+ scnprintf(result->desc, ACPI_CX_DESC_LEN, "%s+%s", local->desc, parent->desc);
+ return true;
+}
+
+#define ACPI_LPI_STATE_FLAGS_ENABLED BIT(0)
+
+static void stash_composite_state(struct acpi_lpi_states_array *curr_level,
+ struct acpi_lpi_state *t)
+{
+ curr_level->composite_states[curr_level->composite_states_size++] = t;
+}
+
+static bool too_many_states(acpi_handle handle, unsigned int state_count)
+{
+ if (state_count < ACPI_PROCESSOR_MAX_POWER)
+ return false;
+
+ acpi_handle_info(handle, "No space for more _LPI states than %d\n",
+ ACPI_PROCESSOR_MAX_POWER);
+ return true;
+}
+
+static unsigned int flatten_lpi_states(acpi_handle handle,
+ struct acpi_lpi_state *lpi_states,
+ unsigned int state_count,
+ struct acpi_lpi_states_array *curr,
+ struct acpi_lpi_states_array *prev)
+{
+ struct acpi_lpi_state *parent_lpi = curr->entries;
+ unsigned int j;
+
+ /*
+ * Combine each of the "raw" _LPI states from the current (processor
+ * container) level with all of the composite _LPI states from the
+ * previous (processor or processor container) level.
+ */
+ for (j = 0; j < curr->size; j++, parent_lpi++) {
+ struct acpi_lpi_state *flpi;
+ int i;
+
+ if (!(parent_lpi->flags & ACPI_LPI_STATE_FLAGS_ENABLED))
+ continue;
+
+ if (too_many_states(handle, state_count))
+ break;
+
+ flpi = &lpi_states[state_count];
+
+ for (i = 0; i < prev->composite_states_size; i++) {
+ struct acpi_lpi_state *local_lpi = prev->composite_states[i];
+
+ if (parent_lpi->index > local_lpi->enable_parent_state)
+ continue;
+
+ if (!combine_lpi_states(local_lpi, parent_lpi, flpi))
+ continue;
+
+ stash_composite_state(curr, flpi);
+ state_count++;
+ flpi++;
+
+ if (state_count >= ACPI_PROCESSOR_MAX_POWER)
+ break;
+ }
+ }
+
+ return state_count;
+}
+
+int acpi_processor_extract_lpi_info(acpi_handle pr_handle,
+ struct acpi_processor_power *pr_power,
+ bool strict)
+{
+ struct acpi_lpi_states_array info[2], *prev, *curr;
+ acpi_handle handle = pr_handle;
+ unsigned int state_count = 0;
+ unsigned int i;
+ int ret;
+
+ if (!osc_pc_lpi_support_confirmed)
+ return -EOPNOTSUPP;
+
+ curr = &info[0];
+ curr->composite_states_size = 0;
+
+ ret = acpi_processor_evaluate_lpi(handle, curr, strict);
+ if (ret)
+ return ret;
+
+ /* Copy all of the usable first-level states to power.lpi_states[]. */
+ for (i = 0; i < curr->size; i++) {
+ struct acpi_lpi_state *lpi = &curr->entries[i];
+ struct acpi_lpi_state *flpi;
+
+ /*
+ * Skip states that are not enabled or have an inadequate entry
+ * method for this level.
+ */
+ if (!(lpi->flags & ACPI_LPI_STATE_FLAGS_ENABLED) ||
+ lpi->entry_method == ACPI_CSTATE_INTEGER)
+ continue;
+
+ if (too_many_states(pr_handle, state_count))
+ break;
+
+ flpi = &pr_power->lpi_states[state_count++];
+ memcpy(flpi, lpi, sizeof(*lpi));
+ stash_composite_state(curr, flpi);
+ }
+
+ kfree(curr->entries);
+
+ /*
+ * If there are no _LPI states at the first level, there are no _LPI
+ * states at all.
+ */
+ if (!state_count)
+ return -ENODATA;
+
+ prev = curr;
+ curr = &info[1];
+
+ for (;;) {
+ struct acpi_lpi_states_array *tmp;
+ struct acpi_device *d;
+
+ if (ACPI_FAILURE(acpi_get_parent(handle, &handle)))
+ break;
+
+ d = acpi_fetch_acpi_dev(handle);
+ if (!d)
+ break;
+
+ if (strcmp(acpi_device_hid(d), ACPI_PROCESSOR_CONTAINER_HID))
+ break;
+
+ curr->composite_states_size = 0;
+
+ ret = acpi_processor_evaluate_lpi(handle, curr, strict);
+ if (ret)
+ break;
+
+ /* flatten all the LPI states in this level of hierarchy */
+ state_count = flatten_lpi_states(pr_handle, pr_power->lpi_states,
+ state_count, curr, prev);
+
+ kfree(curr->entries);
+
+ tmp = prev, prev = curr, curr = tmp;
+ }
+
+ /* reset the index after flattening */
+ for (i = 0; i < state_count; i++)
+ pr_power->lpi_states[i].index = i;
+
+ pr_power->count = state_count;
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(acpi_processor_extract_lpi_info, "ACPI_PROCESSOR_IDLE");
+#endif /* CONFIG_ACPI_PROCESSOR_IDLE */

drivers/acpi/processor_idle.c

View file
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 4482cf2..e113bcb 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -853,223 +853,6 @@ static int acpi_processor_setup_cstates(struct acpi_processor *pr)
#endif /* CONFIG_ACPI_PROCESSOR_CSTATE */
-struct acpi_lpi_states_array {
- unsigned int size;
- unsigned int composite_states_size;
- struct acpi_lpi_state *entries;
- struct acpi_lpi_state *composite_states[ACPI_PROCESSOR_MAX_POWER];
-};
-
-static int obj_get_integer(union acpi_object *obj, u32 *value)
-{
- if (obj->type != ACPI_TYPE_INTEGER)
- return -EINVAL;
-
- *value = obj->integer.value;
- return 0;
-}
-
-static int acpi_processor_evaluate_lpi(acpi_handle handle,
- struct acpi_lpi_states_array *info)
-{
- acpi_status status;
- int ret = 0;
- int pkg_count, state_idx = 1, loop;
- struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *lpi_data;
- struct acpi_lpi_state *lpi_state;
-
- status = acpi_evaluate_object(handle, "_LPI", NULL, &buffer);
- if (ACPI_FAILURE(status)) {
- acpi_handle_debug(handle, "No _LPI, giving up\n");
- return -ENODEV;
- }
-
- lpi_data = buffer.pointer;
-
- /* There must be at least 4 elements = 3 elements + 1 package */
- if (!lpi_data || lpi_data->type != ACPI_TYPE_PACKAGE ||
- lpi_data->package.count < 4) {
- pr_debug("not enough elements in _LPI\n");
- ret = -ENODATA;
- goto end;
- }
-
- pkg_count = lpi_data->package.elements[2].integer.value;
-
- /* Validate number of power states. */
- if (pkg_count < 1 || pkg_count != lpi_data->package.count - 3) {
- pr_debug("count given by _LPI is not valid\n");
- ret = -ENODATA;
- goto end;
- }

This diff is incomplete. Download the complete patch.

drivers/base/power/main.c

View file

This diff is incomplete. Download the complete patch.

drivers/base/power/runtime.c

View file

This diff is incomplete. Download the complete patch.

drivers/cpufreq/amd-pstate-ut.c

View file

This diff is incomplete. Download the complete patch.

drivers/cpufreq/amd-pstate.c

View file

This diff is incomplete. Download the complete patch.

drivers/cpufreq/amd-pstate.h

View file

This diff is incomplete. Download the complete patch.

drivers/cpufreq/apple-soc-cpufreq.c

View file

This diff is incomplete. Download the complete patch.

drivers/cpufreq/brcmstb-avs-cpufreq.c

View file

This diff is incomplete. Download the complete patch.

drivers/cpufreq/cpufreq-dt-platdev.c

View file

This diff is incomplete. Download the complete patch.

drivers/cpufreq/cpufreq.c

View file

This diff is incomplete. Download the complete patch.

drivers/cpufreq/imx6q-cpufreq.c

View file

This diff is incomplete. Download the complete patch.

drivers/cpufreq/intel_pstate.c

View file

This diff is incomplete. Download the complete patch.

drivers/cpufreq/qcom-cpufreq-nvmem.c

View file

This diff is incomplete. Download the complete patch.

drivers/cpufreq/rcpufreq_dt.rs

View file

This diff is incomplete. Download the complete patch.

drivers/cpufreq/spear-cpufreq.c

View file

This diff is incomplete. Download the complete patch.

drivers/idle/intel_idle.c

View file

This diff is incomplete. Download the complete patch.

drivers/opp/core.c

View file

This diff is incomplete. Download the complete patch.

drivers/powercap/intel_rapl_tpmi.c

View file

This diff is incomplete. Download the complete patch.

include/linux/acpi.h

View file

This diff is incomplete. Download the complete patch.

include/linux/cpufreq.h

View file

This diff is incomplete. Download the complete patch.

kernel/power/Kconfig

View file

This diff is incomplete. Download the complete patch.

kernel/power/snapshot.c

View file

This diff is incomplete. Download the complete patch.

kernel/power/swap.c

View file

This diff is incomplete. Download the complete patch.

kernel/power/wakelock.c

View file

This diff is incomplete. Download the complete patch.

kernel/sched/cpufreq_schedutil.c

View file

This diff is incomplete. Download the complete patch.

rust/kernel/cpufreq.rs

View file

This diff is incomplete. Download the complete patch.

tools/power/cpupower/Makefile

View file

This diff is incomplete. Download the complete patch.

tools/power/cpupower/utils/cpufreq-info.c

View file

This diff is incomplete. Download the complete patch.

tools/power/cpupower/utils/helpers/cppc.c

View file

This diff is incomplete. Download the complete patch.

tools/power/cpupower/utils/helpers/helpers.h

View file

This diff is incomplete. Download the complete patch.

tools/power/cpupower/utils/powercap-info.c

View file

This diff is incomplete. Download the complete patch.

tools/power/x86/intel_pstate_tracer/intel_pstate_tracer.py

View file

This diff is incomplete. Download the complete patch.

tools/testing/selftests/cpufreq/governor.sh

View file

This diff is incomplete. Download the complete patch.

tools/testing/selftests/cpufreq/special-tests.sh

View file

This diff is incomplete. Download the complete patch.