RHEL-117344 Update to the upstream version 0.1.0 and enable Nova Lake

Update to the upstream version 0.1.0 and include the latest patches to
enable Nova Lake CPU.

Resolves: RHEL-117344

Signed-off-by: Kate Hsuan <hpa@redhat.com>
This commit is contained in:
Kate Hsuan 2026-08-19 21:09:10 +08:00
parent 0941e189a6
commit 3d06be8d79
62 changed files with 14906 additions and 136 deletions

View File

@ -0,0 +1,33 @@
From 48fc07ee76506f8412f5770116d19a337254caf3 Mon Sep 17 00:00:00 2001
From: Bin Li <libin3479@gmail.com>
Date: Fri, 19 Dec 2025 22:23:18 +0800
Subject: [PATCH 01/56] Deprecate the dbus-glib dependency at Install
Dependencies
---
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/README.md b/README.md
index 292ee76..d65ae0d 100644
--- a/README.md
+++ b/README.md
@@ -17,13 +17,13 @@ man intel_lpmd_config.xml
### Fedora
```sh
-dnf install automake autoconf-archive gcc glib2-devel dbus-glib-devel libxml2-devel libnl3-devel systemd-devel gtk-doc upower-devel
+dnf install automake autoconf-archive gcc glib2-devel libxml2-devel libnl3-devel systemd-devel gtk-doc upower-devel
```
### Ubuntu
```sh
-sudo apt install autoconf autoconf-archive gcc libglib2.0-dev libdbus-1-dev libdbus-glib-1-dev libxml2-dev libnl-3-dev libnl-genl-3-dev libsystemd-dev gtk-doc-tools libupower-glib-dev
+sudo apt install autoconf autoconf-archive gcc libglib2.0-dev libdbus-1-dev libxml2-dev libnl-3-dev libnl-genl-3-dev libsystemd-dev gtk-doc-tools libupower-glib-dev
```
### OpenSUSE
--
2.55.0

View File

@ -1,37 +0,0 @@
From c2cea33c873146f1b6186c02fe79d1a2bb1c7867 Mon Sep 17 00:00:00 2001
From: Kate Hsuan <hpa@redhat.com>
Date: Fri, 2 May 2025 16:49:00 +0800
Subject: [PATCH 1/4] lpmd_util: Remove unused variables
Remove unused variables.
---
src/lpmd_util.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/src/lpmd_util.c b/src/lpmd_util.c
index cd3123a..55f7874 100644
--- a/src/lpmd_util.c
+++ b/src/lpmd_util.c
@@ -83,7 +83,6 @@ static int probe_gfx_util_sysfs(void)
{
FILE *fp;
char buf[8];
- bool gt0_is_gt;
if (access("/sys/class/drm/card0/device/tile0/gt0/gtidle/idle_residency_ms", R_OK))
return 1;
@@ -119,11 +118,9 @@ static int get_gfx_util_sysfs(unsigned long long time_ms)
{
static unsigned long long gfx_rc6_prev = ULLONG_MAX, sam_mc6_prev = ULLONG_MAX;
unsigned long long gfx_rc6, sam_mc6;
- unsigned long long val;
FILE *fp;
int gfx_util, sam_util;
int ret;
- int i;
gfx_util = sam_util = -1;
--
2.49.0

View File

@ -0,0 +1,27 @@
From 3f642fc7bb5f7798e53acb8be9ede2b99a88eac1 Mon Sep 17 00:00:00 2001
From: Qubic <ThatQubicFox@protonmail.com>
Date: Tue, 17 Feb 2026 17:57:30 +0100
Subject: [PATCH 02/56] lpmd_cpu: Tablets are also a Mobile platform see:
https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#preferred-pm-profile-system-types
Signed-off-by: Qubic <ThatQubicFox@protonmail.com>
---
src/lpmd_cpu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lpmd_cpu.c b/src/lpmd_cpu.c
index caa6d11..e611b78 100644
--- a/src/lpmd_cpu.c
+++ b/src/lpmd_cpu.c
@@ -96,7 +96,7 @@ int detect_supported_platform(lpmd_config_t *lpmd_config)
return -1;
}
- if (val != 2) {
+ if (val != 2 && val != 8) {
lpmd_log_info("Non-Mobile PM profile detected. %s returns %d\n", PATH_PM_PROFILE, val);
return -1;
}
--
2.55.0

View File

@ -1,26 +0,0 @@
From 311b7929d4c821630fabf5293ec5b4bec5411162 Mon Sep 17 00:00:00 2001
From: Kate Hsuan <hpa@redhat.com>
Date: Fri, 2 May 2025 16:49:42 +0800
Subject: [PATCH 2/4] wlt_proxy: state_manager: Fix -Werror=switch
Fix the swicth expression to avoid -Werror=switch warnning.
---
src/wlt_proxy/state_manager.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/wlt_proxy/state_manager.c b/src/wlt_proxy/state_manager.c
index 7841135..9753442 100644
--- a/src/wlt_proxy/state_manager.c
+++ b/src/wlt_proxy/state_manager.c
@@ -285,6 +285,8 @@ int staytime_to_staycount(enum state_idx state)
case PERF_MODE:
stay_count = (int)PERF_MODE_STAY/get_poll_ms(PERF_MODE);
break;
+ default:
+ break;
}
return stay_count;
}
--
2.49.0

View File

@ -0,0 +1,54 @@
From e1b353ab97f820654e402e549d43939987a5b512 Mon Sep 17 00:00:00 2001
From: Jan Engelhardt <jengelh@inai.de>
Date: Fri, 16 Jan 2026 11:18:08 +0100
Subject: [PATCH 03/56] build: replace open-coded `if` in configure.ac with
`AS_IF`
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The manual says: "This macro should be used instead of plain if in
code outside of an AC_DEFUN macro, when the contents of the if
use AC_REQUIRE directly or indirectly". Since one cannot know
whether something is going to be AC_REQUIRED indirectly, it is safer
to just always use AS_IF.
Signed-off-by: Jan Engelhardt <jengelh@inai.de>
---
configure.ac | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/configure.ac b/configure.ac
index 36ed1d0..8bf5a78 100644
--- a/configure.ac
+++ b/configure.ac
@@ -18,11 +18,11 @@ AM_MAINTAINER_MODE([enable])
GTK_DOC_CHECK([1.11],[--flavour no-tmpl])
AC_ARG_WITH(dbus-sys-dir, AS_HELP_STRING([--with-dbus-sys-dir=DIR], [where D-BUS system.d directory is]))
-if test -n "$with_dbus_sys_dir" ; then
+AS_IF([test -n "$with_dbus_sys_dir"], [
DBUS_SYS_DIR="$with_dbus_sys_dir"
-else
+], [
DBUS_SYS_DIR="/etc/dbus-1/system.d"
-fi
+])
AC_SUBST(DBUS_SYS_DIR)
# paths
@@ -34,9 +34,9 @@ PKG_PROG_PKG_CONFIG
AC_ARG_WITH([systemdsystemunitdir],
AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
[], [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
-if test "x$with_systemdsystemunitdir" != xno; then
+AS_IF(["x$with_systemdsystemunitdir" != xno], [
AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
-fi
+])
AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ])
--
2.55.0

View File

@ -1,29 +0,0 @@
From 4277f3496dc51f89ed0815e0f51659338f7a6ba9 Mon Sep 17 00:00:00 2001
From: Kate Hsuan <hpa@redhat.com>
Date: Fri, 2 May 2025 16:52:16 +0800
Subject: [PATCH 3/4] wlt_proxy: state_util: Remove unused variables
Remove unused variables.
---
src/wlt_proxy/state_util.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/src/wlt_proxy/state_util.c b/src/wlt_proxy/state_util.c
index 95422c8..9d633d5 100644
--- a/src/wlt_proxy/state_util.c
+++ b/src/wlt_proxy/state_util.c
@@ -381,10 +381,9 @@ static int read_aperf_mperf_tsc_perf(struct thread_data *t, int cpu) {
/*Calc perf [cpu utilization per core] difference from MSR registers */
int update_perf_diffs(float *sum_norm_perf, int stat_init_only) {
- int fd, maxed_cpu = -1;
+ int maxed_cpu = -1;
float min_load = 100.0, min_s0 = 1.0, next_s0 = 1.0;
float max_load = 0, max_2nd_load = 0, max_3rd_load = 0, next_load = 0;
- uint64_t aperf_raw, mperf_raw, pperf_raw, tsc_raw, poll_cpu_us = 0;
int t, min_s0_cpu = 0, first_pass = 1;
for (t = 0; t < get_max_online_cpu(); t++) {
--
2.49.0

View File

@ -0,0 +1,30 @@
From 0911dcf1d2350f99f02198bbfb00cc31c317efc5 Mon Sep 17 00:00:00 2001
From: Jan Engelhardt <jengelh@inai.de>
Date: Fri, 16 Jan 2026 11:21:27 +0100
Subject: [PATCH 04/56] build: avoid use of `test ... -a`
The use of `-a` is non-portable, and it has been actively removed
from POSIX.1-2024
<https://pubs.opengroup.org/onlinepubs/9799919799/utilities/test.html>.
Signed-off-by: Jan Engelhardt <jengelh@inai.de>
---
configure.ac | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac
index 8bf5a78..4f79d86 100644
--- a/configure.ac
+++ b/configure.ac
@@ -38,7 +38,7 @@ AS_IF(["x$with_systemdsystemunitdir" != xno], [
AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
])
-AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ])
+AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" && test "x$with_systemdsystemunitdir" != xno])
# print configuration
echo
--
2.55.0

View File

@ -1,33 +0,0 @@
From af6d8f93a0a1041bd936b8901707e1253c5e5279 Mon Sep 17 00:00:00 2001
From: Kate Hsuan <hpa@redhat.com>
Date: Fri, 2 May 2025 17:07:21 +0800
Subject: [PATCH 4/4] wlt_proxy: state_util: Drop unused function
read_tsc_config()
Drop the unused function read_tsc_config().
---
src/wlt_proxy/state_util.c | 8 --------
1 file changed, 8 deletions(-)
diff --git a/src/wlt_proxy/state_util.c b/src/wlt_proxy/state_util.c
index 9d633d5..f35242e 100644
--- a/src/wlt_proxy/state_util.c
+++ b/src/wlt_proxy/state_util.c
@@ -268,14 +268,6 @@ static unsigned int read_mperf_config(void) {
return read_perf_counter_info_n(path, format);
}
-/*helper - pperf reading */
-static unsigned int read_tsc_config(void) {
- const char *const path = "/sys/bus/event_source/devices/msr/events/tsc";
- const char *const format = "event=%x";
-
- return read_perf_counter_info_n(path, format);
-}
-
/*helper - pperf reading */
static unsigned int read_msr_type(void) {
const char *const path = "/sys/bus/event_source/devices/msr/type";
--
2.49.0

View File

@ -0,0 +1,27 @@
From e08ccef11217a1b0cd7355ba5708fce56a1d02cd Mon Sep 17 00:00:00 2001
From: Jan Engelhardt <jengelh@inai.de>
Date: Fri, 16 Jan 2026 11:41:50 +0100
Subject: [PATCH 05/56] build: fix spelling in error message when libsystemd is
absent
Signed-off-by: Jan Engelhardt <jengelh@inai.de>
---
configure.ac | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac
index 4f79d86..d35d75b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -69,7 +69,7 @@ PKG_CHECK_MODULES(libnlgenl30, [libnl-genl-3.0], libnlgenl30=yes, libnlgenl30=no
PKG_CHECK_MODULES([SYSTEMD], [libsystemd], [],
[PKG_CHECK_MODULES([SYSTEMD], [libsystemd-daemon], [],
- AC_MSG_ERROR([libsystemd support requested but found]))])
+ AC_MSG_ERROR([libsystemd support requested but not found]))])
PKG_CHECK_MODULES(UPOWER, upower-glib)
--
2.55.0

View File

@ -0,0 +1,124 @@
From ec31f9c65057dd9f2aa41449e994ba8af7569041 Mon Sep 17 00:00:00 2001
From: Jan Engelhardt <jengelh@inai.de>
Date: Fri, 16 Jan 2026 11:43:09 +0100
Subject: [PATCH 06/56] build: apply consistent argument quoting in
configure.ac
Signed-off-by: Jan Engelhardt <jengelh@inai.de>
---
configure.ac | 44 ++++++++++++++++++++++----------------------
1 file changed, 22 insertions(+), 22 deletions(-)
diff --git a/configure.ac b/configure.ac
index d35d75b..b212c4d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,4 +1,4 @@
-AC_PREREQ(1.0)
+AC_PREREQ([1.0])
m4_define([lpmd_major_version], [0])
m4_define([lpmd_minor_version], [1.0])
@@ -9,7 +9,7 @@ AC_INIT([intel_lpmd], [lpmd_version], [], [intel_lpmd])
m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])])
AC_CONFIG_MACRO_DIR([m4])
-AC_CONFIG_AUX_DIR(build-aux)
+AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
AM_INIT_AUTOMAKE([1.11 foreign no-define subdir-objects])
@@ -17,28 +17,28 @@ AM_MAINTAINER_MODE([enable])
GTK_DOC_CHECK([1.11],[--flavour no-tmpl])
-AC_ARG_WITH(dbus-sys-dir, AS_HELP_STRING([--with-dbus-sys-dir=DIR], [where D-BUS system.d directory is]))
+AC_ARG_WITH([dbus-sys-dir], [AS_HELP_STRING([--with-dbus-sys-dir=DIR], [where D-BUS system.d directory is])])
AS_IF([test -n "$with_dbus_sys_dir"], [
DBUS_SYS_DIR="$with_dbus_sys_dir"
], [
DBUS_SYS_DIR="/etc/dbus-1/system.d"
])
-AC_SUBST(DBUS_SYS_DIR)
+AC_SUBST([DBUS_SYS_DIR])
# paths
-AC_SUBST(lpmd_binary, "$sbindir/$PACKAGE", [Binary executable])
-AC_SUBST(lpmd_confdir, "$sysconfdir/$PACKAGE", [Configuration directory])
-AC_SUBST(lpmd_rundir, "$localstatedir/run/$PACKAGE", [Runtime state directory])
+AC_SUBST([lpmd_binary], ["$sbindir/$PACKAGE"], [Binary executable])
+AC_SUBST([lpmd_confdir], ["$sysconfdir/$PACKAGE"], [Configuration directory])
+AC_SUBST([lpmd_rundir], ["$localstatedir/run/$PACKAGE"], [Runtime state directory])
PKG_PROG_PKG_CONFIG
AC_ARG_WITH([systemdsystemunitdir],
- AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
- [], [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
+ [AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files])],
+ [], [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
AS_IF(["x$with_systemdsystemunitdir" != xno], [
AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
])
-AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" && test "x$with_systemdsystemunitdir" != xno])
+AM_CONDITIONAL([HAVE_SYSTEMD], [test -n "$with_systemdsystemunitdir" && test "x$with_systemdsystemunitdir" != xno])
# print configuration
echo
@@ -52,26 +52,26 @@ echo " lpmd_rundir: $lpmd_rundir"
echo
GETTEXT_PACKAGE=intel_lpmd
-AC_SUBST(GETTEXT_PACKAGE)
-AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Gettext package])
+AC_SUBST([GETTEXT_PACKAGE])
+AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["$GETTEXT_PACKAGE"], [Gettext package])
GLIB_VERSION_DEFINES="-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_26"
-PKG_CHECK_MODULES(GLIB, gio-unix-2.0 >= 2.22 gmodule-2.0 glib-2.0 gobject-2.0)
+PKG_CHECK_MODULES([GLIB], [gio-unix-2.0 >= 2.22 gmodule-2.0 glib-2.0 gobject-2.0])
GLIB_CFLAGS="$GLIB_CFLAGS $GLIB_VERSION_DEFINES"
-AC_SUBST(GLIB_CFLAGS)
-AC_SUBST(GLIB_LIBS)
+AC_SUBST([GLIB_CFLAGS])
+AC_SUBST([GLIB_LIBS])
-PKG_CHECK_MODULES(XML, libxml-2.0 >= 2.4)
+PKG_CHECK_MODULES([XML], [libxml-2.0 >= 2.4])
-PKG_CHECK_MODULES(libnl30, [libnl-3.0], libnl30=yes, libnl30=no)
-PKG_CHECK_MODULES(libnlgenl30, [libnl-genl-3.0], libnlgenl30=yes, libnlgenl30=no)
+PKG_CHECK_MODULES([libnl30], [libnl-3.0], [libnl30=yes], [libnl30=no])
+PKG_CHECK_MODULES([libnlgenl30], [libnl-genl-3.0], libnlgenl30=yes, libnlgenl30=no)
PKG_CHECK_MODULES([SYSTEMD], [libsystemd], [],
[PKG_CHECK_MODULES([SYSTEMD], [libsystemd-daemon], [],
- AC_MSG_ERROR([libsystemd support requested but not found]))])
+ [AC_MSG_ERROR([libsystemd support requested but not found])])])
-PKG_CHECK_MODULES(UPOWER, upower-glib)
+PKG_CHECK_MODULES([UPOWER], [upower-glib])
AC_PATH_PROG([GDBUS_CODEGEN],[gdbus-codegen])
@@ -81,14 +81,14 @@ AC_C_CONST
AC_C_INLINE
AC_TYPE_SIZE_T
-AC_ARG_ENABLE(werror, AS_HELP_STRING([--disable-werror], [Disable -Werror]))
+AC_ARG_ENABLE([werror], [AS_HELP_STRING([--disable-werror], [Disable -Werror])])
AS_IF([test "x$enable_werror" != "xno"], [CFLAGS="$CFLAGS -Werror"])
AC_CONFIG_FILES([Makefile
data/Makefile
tools/Makefile])
-AC_ARG_ENABLE(gdbus,
+AC_ARG_ENABLE([gdbus],
[AS_HELP_STRING([--disable-gdbus],
[Switch DBus backend to glib-dbus. (Default: GDBus)])],
[],
--
2.55.0

View File

@ -0,0 +1,45 @@
From 9b40a73836b81f339fa419b594052c2c587964e4 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Thu, 12 Mar 2026 15:22:15 +0100
Subject: [PATCH 07/56] lpmd_cgroup: simple isolation fix - works without
interference
cgroup isolation mode doesn't work in LPMD because when writing
'isolated' to cpuset.cpus.partition file the expectation is that
cpuset.cpus will be a subset of cpuset.cpus.exclusive of that cgroup.
The simple fix is to write the same content to cpuset.cpus and
cpuset.cpus.exclusive when switching into the isolated mode.
However a problem can appear if there are any other cgroups on the
system that have exclusive cpus claimed. For one LPMD will just shut
down if it can't set affinity into any cpu it wants during core type
discovery phase. Aside from that using this simple version of the fix
will later result in creating an invalid cgroup partition.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/lpmd_cgroup.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/lpmd_cgroup.c b/src/lpmd_cgroup.c
index 46a3c50..5b53179 100644
--- a/src/lpmd_cgroup.c
+++ b/src/lpmd_cgroup.c
@@ -177,10 +177,12 @@ static int process_cpu_isolate(lpmd_config_state_t *state)
return 1;
if (!cpumask_equal(state->cpumask_idx, CPUMASK_ONLINE)) {
- if (lpmd_write_str ("/sys/fs/cgroup/lpm/cpuset.cpus", get_cpu_isolation_str(state->cpumask_idx), LPMD_LOG_DEBUG))
+ if (lpmd_write_str ("/sys/fs/cgroup/lpm/cpuset.cpus.exclusive", get_cpu_isolation_str(state->cpumask_idx), LPMD_LOG_DEBUG))
return 1;
if (lpmd_write_str ("/sys/fs/cgroup/lpm/cpuset.cpus.partition", "isolated", LPMD_LOG_DEBUG))
return 1;
+ if (lpmd_write_str ("/sys/fs/cgroup/lpm/cpuset.cpus", get_cpu_isolation_str(state->cpumask_idx), LPMD_LOG_DEBUG))
+ return 1;
} else {
if (lpmd_write_str ("/sys/fs/cgroup/lpm/cpuset.cpus", get_cpu_isolation_str(CPUMASK_ONLINE), LPMD_LOG_DEBUG))
return 1;
--
2.55.0

View File

@ -0,0 +1,48 @@
From 9bc60393b78df98a80ceec5b50dc487e8778f187 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Wed, 11 Feb 2026 18:45:10 +0100
Subject: [PATCH 08/56] state_machine: Fix issue #106 - incorrect order of
polling interval writes
When WLT proxy is enabled it's supposed to set it's own polling timeout.
The problem is in the state machine an early return happens - that
disables polling timeout - when the non-proxy polling is disabled. Given
that it has nothing to do with the proxy polling it should not interfere
in the proxy setting it's own timeouts.
Change order of the early returns so that it happens after the WLT proxy
check - thereby not overwriting the interval assigned by the proxy code.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/lpmd_state_machine.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/lpmd_state_machine.c b/src/lpmd_state_machine.c
index f1b736a..1f40c02 100644
--- a/src/lpmd_state_machine.c
+++ b/src/lpmd_state_machine.c
@@ -174,16 +174,16 @@ static int get_config_state_interval(lpmd_config_t *config, int idx)
{
lpmd_config_state_t *state = &config->config_states[idx];
+ /* wlt proxy updates polling separately */
+ if (config->wlt_proxy_enable)
+ return 0;
+
/* Start polling only when needed */
if (!polling_enabled) {
config->data.polling_interval = -1;
return 0;
}
- /* wlt proxy updates polling separately */
- if (config->wlt_proxy_enable)
- return 0;
-
/* Always start with minumum polling interval for a new state */
if (idx != current_idx) {
config->data.polling_interval = state->min_poll_interval;
--
2.55.0

View File

@ -0,0 +1,82 @@
From 256ae2ba3ec0847b2a5f570509f7eccefb19ad45 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Tue, 31 Mar 2026 22:51:43 +0200
Subject: [PATCH 09/56] lpmd_state_machine: Fix deadlock on power profile
switch
If one profile, let's say the balanced one, is set to enable AUTO LPMD,
and another one like the performance one, has LPMD OFF, then a deadlock
might happen when using the wlt proxy system. Basically when going into
the OFF state, polling gets disabled and there is no specific code flow
to get it enabled again after switching back to an AUTO state.
This only affects the wlt proxy as other polling and non-polling systems
seem to be able to get themselves back up again.
Reinitialize the polling interval when switching power profiles.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/include/lpmd.h | 2 ++
src/lpmd_proc.c | 5 ++++-
src/lpmd_state_machine.c | 8 ++++++++
3 files changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/include/lpmd.h b/src/include/lpmd.h
index 6319a41..447ffdd 100644
--- a/src/include/lpmd.h
+++ b/src/include/lpmd.h
@@ -284,6 +284,8 @@ enum power_profile_daemon_mode {
PPD_INVALID
};
+#define DEF_POLLING_INTERVAL 100
+
/* lpmd_main.c */
int in_debug_mode(void);
int do_platform_check(void);
diff --git a/src/lpmd_proc.c b/src/lpmd_proc.c
index e6d2445..450b890 100644
--- a/src/lpmd_proc.c
+++ b/src/lpmd_proc.c
@@ -150,6 +150,9 @@ static void power_profiles_changed_cb(void)
} else {
lpmd_log_warn("Ignore unsupported power profile: %s\n", active_profile);
}
+
+ if (lpmd_config.wlt_proxy_enable)
+ lpmd_config.data.polling_interval = DEF_POLLING_INTERVAL;
}
}
@@ -300,7 +303,7 @@ static void* lpmd_core_main_loop(void *arg)
{
int n;
- lpmd_config.data.polling_interval = 100;
+ lpmd_config.data.polling_interval = DEF_POLLING_INTERVAL;
for (;;) {
diff --git a/src/lpmd_state_machine.c b/src/lpmd_state_machine.c
index 1f40c02..9e7bcf2 100644
--- a/src/lpmd_state_machine.c
+++ b/src/lpmd_state_machine.c
@@ -396,6 +396,14 @@ int lpmd_enter_next_state(void)
}
idx = choose_next_state(config);
+
+ /*
+ * After switching power profiles polling gets disabled and needs to be
+ * updated.
+ */
+ if (config->data.polling_interval == -1 && polling_enabled && idx != DEFAULT_OFF)
+ get_config_state_interval(config, idx);
+
/* No action needed, keep previous idx and interval */
if (idx == STATE_NONE)
goto end;
--
2.55.0

View File

@ -0,0 +1,37 @@
From 01285c1b192fe586e9106bdd370b8646bf474294 Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Fri, 10 Apr 2026 16:41:45 -0700
Subject: [PATCH 10/56] Process itmt read error
When fail to read PATH_ITMT_CONTROL, return error.
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
src/lpmd_misc.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/src/lpmd_misc.c b/src/lpmd_misc.c
index b993b4d..b315bf0 100644
--- a/src/lpmd_misc.c
+++ b/src/lpmd_misc.c
@@ -28,12 +28,15 @@ static int saved_itmt = SETTING_IGNORE;
int get_itmt(void)
{
- int val;
+ int val, ret;
if (!has_itmt)
return -1;
- lpmd_read_int(PATH_ITMT_CONTROL, &val, -1);
+ ret = lpmd_read_int(PATH_ITMT_CONTROL, &val, -1);
+ if (ret)
+ return -1;
+
return val;
}
--
2.55.0

View File

@ -0,0 +1,193 @@
From fec5fa9152769152ab7bfc933fbcf05fbfaddece Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Fri, 10 Apr 2026 17:06:31 -0700
Subject: [PATCH 11/56] lpmd_misc: Fix ITMT
ITMT became broken when the enabling file was moved to the debugfs. The
data in the file also changed from printing out 0 or 1 to printing out N
or Y characters. However 0 and 1 are still accepted for writing.
Change the file that's being accesses to the debugfs and add helpers for
the Y/N format.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
[Also kept the legacy /procfs control when debugfs doesn't exist]
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
src/include/lpmd.h | 2 ++
src/lpmd_helpers.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++
src/lpmd_misc.c | 32 ++++++++++++++++++---
3 files changed, 102 insertions(+), 4 deletions(-)
diff --git a/src/include/lpmd.h b/src/include/lpmd.h
index 447ffdd..d14156f 100644
--- a/src/include/lpmd.h
+++ b/src/include/lpmd.h
@@ -410,6 +410,8 @@ int lpmd_write_str_append(const char *name, char *str, int print_level);
int lpmd_write_int(const char *name, int val, int print_level);
int lpmd_open(const char *name, int print_level);
int lpmd_read_int(const char *name, int *val, int print_level);
+int lpmd_read_yn(const char *name, int *val, int print_level);
+int lpmd_write_yn(const char *name, int val, int print_level);
char* get_time(void);
void time_start(void);
char* time_delta(void);
diff --git a/src/lpmd_helpers.c b/src/lpmd_helpers.c
index f316912..2e27369 100644
--- a/src/lpmd_helpers.c
+++ b/src/lpmd_helpers.c
@@ -252,6 +252,78 @@ int lpmd_read_int(const char *name, int *val, int print_level)
}
+int lpmd_write_yn(const char *name, int val, int print_level)
+{
+ char str[5];
+ int ret;
+
+ if (!name)
+ return 0;
+
+ ret = snprintf(str, 4, "%d", val);
+ if (ret < 0)
+ return 1;
+
+ return _write_str (name, str, print_level, 2, "r+");
+}
+
+int lpmd_read_yn(const char *name, int *val, int print_level)
+{
+ char prefix[16];
+ FILE *filep;
+ int i, ret;
+
+ if (!name || !val)
+ return 1;
+
+ if (print_level >= 15)
+ return 1;
+
+ if (print_level < 0) {
+ prefix[0] = '\0';
+ }
+ else {
+ for (i = 0; i < print_level; i++)
+ prefix[i] = '\t';
+ prefix[i] = '\0';
+ }
+
+ filep = fopen (name, "r");
+ if (!filep) {
+ lpmd_log_error ("%sOpen %s failed\n", prefix, name);
+ return 1;
+ }
+
+ ret = fgetc(filep);
+ if (ret == EOF) {
+ if (feof(filep)) {
+ lpmd_log_error ("%sRead %s failed due to EOF\n", prefix, name);
+ } else if (ferror(filep)) {
+ lpmd_log_error ("%sRead %s failed, error %s\n", prefix, name, strerror(errno));
+ }
+ fclose (filep);
+ return 1;
+ }
+
+ fclose (filep);
+
+ if (ret == 'Y') {
+ *val = 1;
+ } else if (ret == 'N') {
+ *val = 0;
+ } else {
+ lpmd_log_error ("%sRead %s failed, read %c\n", prefix, name, ret);
+ return 1;
+ }
+
+ if (print_level >= 0)
+ lpmd_log_debug ("%sRead \"%c\" from %s\n", prefix, *val, name);
+
+ return 0;
+
+}
+
+
/*
* lpmd_open does not require print on success
* print_level: -1: don't print on error
diff --git a/src/lpmd_misc.c b/src/lpmd_misc.c
index b315bf0..18fc9a6 100644
--- a/src/lpmd_misc.c
+++ b/src/lpmd_misc.c
@@ -22,6 +22,7 @@
/* ITMT Management */
#define PATH_ITMT_CONTROL "/proc/sys/kernel/sched_itmt_enabled"
+#define PATH_ITMT_CONTROL_DEBUGFS "/sys/kernel/debug/x86/sched_itmt_enabled"
static int has_itmt;
static int saved_itmt = SETTING_IGNORE;
@@ -33,15 +34,30 @@ int get_itmt(void)
if (!has_itmt)
return -1;
+ ret = lpmd_read_yn(PATH_ITMT_CONTROL_DEBUGFS, &val, -1);
+ if (!ret)
+ return val;
+
+ lpmd_log_debug("Read ITMT debugfs failed, fallback to sysctl\n");
ret = lpmd_read_int(PATH_ITMT_CONTROL, &val, -1);
- if (ret)
- return -1;
+ if (ret) {
+ lpmd_log_error("Read ITMT sysctl failed\n");
+ return -1;
+ }
return val;
}
int itmt_init(void)
{
+
+ if (lpmd_read_yn(PATH_ITMT_CONTROL_DEBUGFS, &saved_itmt, -1)) {
+ lpmd_log_debug("ITMT debugfs not detected\n");
+ } else {
+ has_itmt = 1;
+ return 0;
+ }
+
if (lpmd_read_int(PATH_ITMT_CONTROL, &saved_itmt, -1))
lpmd_log_debug("ITMT not detected\n");
else
@@ -52,6 +68,8 @@ int itmt_init(void)
int process_itmt(lpmd_config_state_t *state)
{
+ int ret;
+
if (!has_itmt)
return 0;
@@ -60,10 +78,16 @@ int process_itmt(lpmd_config_state_t *state)
lpmd_log_debug("Ignore ITMT\n");
return 0;
case SETTING_RESTORE:
- return lpmd_write_int(PATH_ITMT_CONTROL, saved_itmt, -1);
+ ret = lpmd_write_yn(PATH_ITMT_CONTROL_DEBUGFS, saved_itmt, -1);
+ if (ret)
+ return lpmd_write_int(PATH_ITMT_CONTROL, saved_itmt, -1);
+ return ret;
default:
lpmd_log_debug ("%s ITMT\n", state->itmt_state ? "Enable" : "Disable");
- return lpmd_write_int(PATH_ITMT_CONTROL, state->itmt_state, -1);
+ ret = lpmd_write_yn(PATH_ITMT_CONTROL_DEBUGFS, state->itmt_state, -1);
+ if (ret)
+ return lpmd_write_int(PATH_ITMT_CONTROL, state->itmt_state, -1);
+ return ret;
}
}
--
2.55.0

View File

@ -0,0 +1,74 @@
From 9b789e1727986df2703db152ed7aa11e6a508313 Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Fri, 10 Apr 2026 17:31:38 -0700
Subject: [PATCH 12/56] make itmt_init() to void
itmt_init() only returns 0, no use of using return value.
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
src/include/lpmd.h | 2 +-
src/lpmd_misc.c | 6 ++----
src/lpmd_proc.c | 4 +---
3 files changed, 4 insertions(+), 8 deletions(-)
diff --git a/src/include/lpmd.h b/src/include/lpmd.h
index d14156f..223467b 100644
--- a/src/include/lpmd.h
+++ b/src/include/lpmd.h
@@ -335,7 +335,7 @@ int wlt_exit(void);
int wlt_update(int fd);
/* lpmd_misc.c */
-int itmt_init(void);
+void itmt_init(void);
int get_itmt(void);
int process_itmt(lpmd_config_state_t *state);
diff --git a/src/lpmd_misc.c b/src/lpmd_misc.c
index 18fc9a6..77725e4 100644
--- a/src/lpmd_misc.c
+++ b/src/lpmd_misc.c
@@ -48,22 +48,20 @@ int get_itmt(void)
return val;
}
-int itmt_init(void)
+void itmt_init(void)
{
if (lpmd_read_yn(PATH_ITMT_CONTROL_DEBUGFS, &saved_itmt, -1)) {
lpmd_log_debug("ITMT debugfs not detected\n");
} else {
has_itmt = 1;
- return 0;
+ return;
}
if (lpmd_read_int(PATH_ITMT_CONTROL, &saved_itmt, -1))
lpmd_log_debug("ITMT not detected\n");
else
has_itmt = 1;
-
- return 0;
}
int process_itmt(lpmd_config_state_t *state)
diff --git a/src/lpmd_proc.c b/src/lpmd_proc.c
index 450b890..ad58c29 100644
--- a/src/lpmd_proc.c
+++ b/src/lpmd_proc.c
@@ -408,9 +408,7 @@ int lpmd_main(void)
if (ret)
return ret;
- ret = itmt_init();
- if (ret)
- return ret;
+ itmt_init();
ret = epp_epb_init();
if (ret)
--
2.55.0

View File

@ -0,0 +1,46 @@
From bb67af59b038ea965c93a1ec8b184f5ab167d2c6 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Fri, 12 Dec 2025 13:49:25 +0100
Subject: [PATCH 13/56] config: Fix incorrect cpu numbers
The cpu name in the config file is described as having 16 cores while
the specific tags in the config file try to enable higher core indices
than 16.
Correct the indices.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
data/intel_lpmd_config_F6_M204.xml | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/data/intel_lpmd_config_F6_M204.xml b/data/intel_lpmd_config_F6_M204.xml
index ba5d4e4..a67fa8b 100644
--- a/data/intel_lpmd_config_F6_M204.xml
+++ b/data/intel_lpmd_config_F6_M204.xml
@@ -146,19 +146,19 @@ for Intel Energy Optimizer (LPMD) daemon
<ID> 1 </ID>
<Name> UTIL_IDLE </Name>
<WLTType> 1 </WLTType>
- <ActiveCPUs>16-19</ActiveCPUs>
+ <ActiveCPUs>12-15</ActiveCPUs>
</State>
<State>
<ID> 2 </ID>
<Name> UTIL_IDLE_SUSTAIN </Name>
<WLTType> 2 </WLTType>
- <ActiveCPUs>0-19</ActiveCPUs>
+ <ActiveCPUs>0-15</ActiveCPUs>
</State>
<State>
<ID> 3 </ID>
<Name> UTIL_IDLE_BURSTY </Name>
<WLTType> 3 </WLTType>
- <ActiveCPUs>0-19</ActiveCPUs>
+ <ActiveCPUs>0-15</ActiveCPUs>
</State>
</States>
--
2.55.0

View File

@ -0,0 +1,61 @@
From 9466f9555bd83f51dac06c20141ddd76a48279f8 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Tue, 7 Apr 2026 17:17:14 +0200
Subject: [PATCH 14/56] readme: Reformat long lines into markdown readable
blocks
Get the readme source to a readable format for editing.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
README.md | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/README.md b/README.md
index d65ae0d..e446ee2 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,11 @@
# Intel Low Power Mode Daemon
-Intel Low Power Mode Daemon (lpmd) is a Linux daemon designed to optimize active idle power. It selects the most power-efficient CPUs based on a configuration file or CPU topology. Depending on system utilization and other hints, it puts the system into Low Power Mode by activating the power-efficient CPUs and disabling the rest, and restores the system from Low Power Mode by activating all CPUs.
+Intel Low Power Mode Daemon (lpmd) is a Linux daemon designed to optimize active
+idle power. It selects the most power-efficient CPUs based on a configuration
+file or CPU topology. Depending on system utilization and other hints, it puts
+the system into Low Power Mode by activating the power-efficient CPUs and
+disabling the rest, and restores the system from Low Power Mode by activating
+all CPUs.
## Usage
@@ -40,10 +45,13 @@ make
sudo make install
```
-The generated artifacts are copied to respective directories under `/usr/local`. If a custom install path is preferred other than system default, make sure `--localstatedir` and `--sysconfdir` are set to the right path that the system can understand. If installed via RPM then artifacts would be under `/usr`.
-
-Example command for installation using prefix under `/opt/lpmd_install` dir with `--localstatedir` and `--sysconfdir` set to system default
+The generated artifacts are copied to respective directories under `/usr/local`.
+If a custom install path is preferred other than system default, make sure
+`--localstatedir` and `--sysconfdir` are set to the right path that the system
+can understand. If installed via RPM then artifacts would be under `/usr`.
+Example command for installation using prefix under `/opt/lpmd_install` dir with
+`--localstatedir` and `--sysconfdir` set to system default
```sh
./autogen.sh prefix=/opt/lpmd_install --localstatedir=/var --sysconfdir=/etc
@@ -87,8 +95,8 @@ Start `lpmd` using:
sudo sh tests/lpm_test_interface.sh 4
```
-Run a workload and monitor `lpmd` to ensure it puts the system in the appropriate state based on the load.
-
+Run a workload and monitor `lpmd` to ensure it puts the system in the
+appropriate state based on the load.
## Releases
--
2.55.0

View File

@ -0,0 +1,35 @@
From 720cf64206367b0e9857e49b7a59f9df3a963261 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Tue, 7 Apr 2026 20:31:53 +0200
Subject: [PATCH 15/56] readme: Emphasize expectations from the user
Make clear how to start the program to avoid confusion around the
default behavior.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
README.md | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index e446ee2..fb420e8 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,13 @@ the system into Low Power Mode by activating the power-efficient CPUs and
disabling the rest, and restores the system from Low Power Mode by activating
all CPUs.
-## Usage
+## Before You Start
+
+**Please note** that the installed configuration files serve as templates of
+best practices for specific platform models and disable lpmd by default. For
+LPMD to start the user is expected to either edit the main
+"intel_lpmd_config.xml" config file or after starting the program, enable LPMD
+by using the intel_lpmd_control tool.
Refer to the man pages for command line arguments and XML configurations:
--
2.55.0

View File

@ -0,0 +1,90 @@
From bae9adf43fba53c0d28e1ca0793320c713499f96 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Fri, 27 Mar 2026 18:11:58 +0100
Subject: [PATCH 16/56] man: Update the main man page
Update the main man page with new informations about LPMD. Mention what
are the expectation towards the user, clear up intel_lpmd_control
section since it has it's own man page and add how to enable the system
service persistently in the examples section.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
man/intel_lpmd.8 | 46 +++++++++++++++++++++++++---------------------
1 file changed, 25 insertions(+), 21 deletions(-)
diff --git a/man/intel_lpmd.8 b/man/intel_lpmd.8
index 1002457..8e36e73 100644
--- a/man/intel_lpmd.8
+++ b/man/intel_lpmd.8
@@ -21,7 +21,7 @@
.\"
.\" Copyright (C) 2012 Intel Corporation. All rights reserved.
.\"
-.TH intel_lpmd "8" "1 Jun 2023"
+.TH intel_lpmd "8" "08 Apr 2026"
.SH NAME
intel_lpmd \- Intel Energy Optimizer (LPMD) Daemon
@@ -31,25 +31,24 @@ intel_lpmd \- Intel Energy Optimizer (LPMD) Daemon
.SH DESCRIPTION
.B intel_lpmd
-is a Linux daemon used for energy optimization on Intel hybrid systems.
-This daemon uses a configuration file "intel_lpmd_config.xml".
-Based on the configuration, it will choose right set of CPUs
-to enable. For example, this daemon can monitor system utilization
-and choose a set of low power CPUs to enable and disable the rest.
-This enable disable of CPUs are done using Linux cpuset feature
-of intel power clamp driver.
-
-There is a control utility distributed along with this daemon.
-This control utility is called "intel_lpmd_control". This utility
-can be used to set different modes for this daemon.
-For example:
-intel_lpmd_control ON
- To turn on low power mode operation.
-intel_lpmd_control OFF
- To turn off low power mode operation.
-intel_lpmd_control AUTO
- To turn on low power mode operation in auto mode, which
- allows low power mode based on system utilization.
+is a Linux daemon used for energy optimization on Intel hybrid systems. This
+daemon uses a configuration file called "intel_lpmd_config.xml". The other
+installed configuration files are to be treated as best practice templates. The
+main configuration file should be edited by the user to enable LPMD and it's
+desired functionalities. Based on the configuration and system utilization LPMD
+can:
+
+- choose the best set of CPU cores to enable for a given moment in time
+
+- choose the best EPP (energe performance preference) and EPB (energy
+performance bias) value
+
+- pick the best SoC power slider settings
+
+There is a control utility distributed along with this daemon. It's called
+"intel_lpmd_control" and it can be used to change modes in the running LPMD
+instance.
+
.SH OPTIONS
.TP
.B -h --help
@@ -88,8 +87,13 @@ Run intel_lpmd with log directed to stdout
.B intel_lpmd --systemd --dbus-enable
Run intel_lpmd as a service with logs directed to system journal
+.TP
+.B sudo systemctl enable intel_lpmd.service --now
+Enable and run intel_lpmd as a systemd service that's persistent after system
+reboot.
+
.SH SEE ALSO
-intel_lpmd_config.xml(5)
+intel_lpmd_config.xml(5), intel_lpmd_control(8)
.SH AUTHOR
Written by Zhang Rui <rui.zhang@intel.com>
--
2.55.0

View File

@ -0,0 +1,59 @@
From a75414281d43e2154bd9f3aa2f7b47618c437796 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Tue, 7 Apr 2026 22:16:14 +0200
Subject: [PATCH 17/56] man: Update lpmd control utility man page
Cleanup the long lines and link in the config man page at the end.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
man/intel_lpmd_control.8 | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/man/intel_lpmd_control.8 b/man/intel_lpmd_control.8
index 347dbde..854cd6f 100644
--- a/man/intel_lpmd_control.8
+++ b/man/intel_lpmd_control.8
@@ -21,7 +21,7 @@
.\"
.\" Copyright (C) 2025 Intel Corporation. All rights reserved.
.\"
-.TH intel_lpmd_control "8" "7 Mar 2025"
+.TH intel_lpmd_control "8" "8 Apr 2026"
.SH NAME
intel_lpmd_control \- Control utility for the Intel Low Power Mode Daemon (LPMD)
@@ -31,7 +31,9 @@ intel_lpmd_control \- Control utility for the Intel Low Power Mode Daemon (LPMD)
.SH DESCRIPTION
.B intel_lpmd_control
-is a command-line utility used to control the Intel Low Power Mode Daemon (LPMD). It allows users to enable, disable, or set the daemon to automatic mode based on system utilization.
+is a command-line utility used to control the Intel Low Power Mode Daemon
+(LPMD). It allows users to enable, disable, or set the daemon to automatic mode
+based on system utilization.
.SH OPTIONS
.TP
@@ -42,7 +44,8 @@ Enables low power mode operation.
Disables low power mode operation.
.TP
.B AUTO
-Enables low power mode operation in automatic mode, allowing system utilization to determine low power state activation.
+Enables operation in automatic mode, allowing system utilization to determine
+low power state activation.
.SH EXAMPLES
.TP
@@ -56,7 +59,7 @@ Turns off low power mode operation.
Turns on low power mode operation in automatic mode.
.SH SEE ALSO
-.B intel_lpmd(8)
+.B intel_lpmd_config.xml(5), intel_lpmd(8)
.SH AUTHOR
Written by Deepak Sundar <deepak.sundar@intel.com>
\ No newline at end of file
--
2.55.0

View File

@ -0,0 +1,137 @@
From f851bd0647ce9892635bd31ca30a6babf3a7efb6 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Wed, 8 Apr 2026 19:45:00 +0200
Subject: [PATCH 18/56] man: Generic updates to the config man page
Cleanup some topics that expanded since they were written. Make general
cleanups and small corrections to typos or style.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
[Change MTL to Lunar Lake]
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
man/intel_lpmd_config.xml.5 | 53 +++++++++++++++++++------------------
1 file changed, 27 insertions(+), 26 deletions(-)
diff --git a/man/intel_lpmd_config.xml.5 b/man/intel_lpmd_config.xml.5
index 2792665..507939a 100644
--- a/man/intel_lpmd_config.xml.5
+++ b/man/intel_lpmd_config.xml.5
@@ -21,7 +21,7 @@
.\"
.\" Copyright (C) 2012 Intel Corporation. All rights reserved.
.\"
-.TH intel_lpmd_config.xml "5" "1 Jun 2023"
+.TH intel_lpmd_config.xml "5" "8 Apr 2026"
.SH NAME
intel_lpmd_config.xml \- Configuration file for intel_lpmd
@@ -30,18 +30,22 @@ $(TDCONFDIR)/etc/intel_lpmd/intel_lpmd_config.xml
.SH DESCRIPTION
.B intel_lpmd_config.xml
-is a configuration file for the Intel Low Power Mode Daemon.
-It is used to describe the lp_mode_cpus to use in Low Power Mode,
-as well as the way to restrict work to those CPUs. It also describes
-if and how the HFI monitor and utilization monitor works. The location
-of this file depends on the configuration option used during build time.
+is a configuration file for the Intel Low Power Mode Daemon. It's used to
+describe states and rules of switching between the states. These states are
+custom, user defined sets of parameters that the platform should use for optimal
+performance and energy saving. The rules of switching refer to what system
+information dictates whether a change of state is needed or not. It can be
+either information from a hardware source or software calculated if the hardware
+features are not supported.
+
.PP
.B lp_mode_cpus
-is a set of active CPUs when system is in Low Power Mode.
-This usually equals a group of most power efficient CPUs on a platform to
-achieve best power saving. When not specified, intel_lpmd tool can detect this
-automatically. E.g. it uses an E-core Module on Intel Alderlake platform, and
-it uses the Low Power E-cores on SoC Die on Intel Meteorlake platform.
+is a set of active CPUs when system is in Low Power Mode. This usually equals a
+group of most power efficient CPUs on a platform to achieve best power saving.
+When not specified, intel_lpmd tool can detect this automatically. E.g. it uses
+L-cores on Intel PantherLake platform, the E-core Module on Intel Alderlake
+platform, and it uses the Low Power E-cores on SoC Die on Intel Meteorlake
+platform.
.PP
.B Mode
specifies the way to migrate the tasks to the lp_mode_cpus.
@@ -56,8 +60,8 @@ lp_mode_cpus only.
Mode 2: Force idle injection to the non-lp_mode_cpus and leverage the
scheduler to schedule the other tasks to the lp_mode_cpus.
.PP
-.B PerformanceDef
-specifies the default behavior when power setting is set to Performance.
+.B PerformanceDef / BalancedDef / PowersaverDef
+specifies the default behavior for a given power profile.
.IP \(bu 2
-1 : Never enter Low Power Mode.
.IP \(bu 2
@@ -65,12 +69,6 @@ specifies the default behavior when power setting is set to Performance.
.IP \(bu 2
1 : Always stay in Low Power Mode.
.PP
-.B BalancedDef
-specifies the default behavior when power setting is set to Balanced.
-.PP
-.B PowersaverDef
-specifies the default behavior when power setting is set to Power saver.
-.PP
.B HfiLpmEnable
specifies if the HFI monitor can capture the HFI hints for Low Power Mode.
.PP
@@ -127,16 +125,18 @@ Setting to 0 or leaving this empty disables this hysteresis algorithm.
Avoid changing scheduler ITMT flag. This means that during transition to
low power mode, ITMT flag is not changed. This reduces latency during
switching. This flag is not used when configuration uses "State" based
-configuration, where this flag can be defined per state.
+configuration, where this flag can be defined per state. ITMT is only relevant
+for platforms before Lunar Lake and the debugfs file is not present on later
+platforms.
.PP
.B States
Allows one to define per platform low power states. Each state defines
has an entry condition and set of parameters to use.
.SH State Definition
-There can be multiple State configuration can be present. Each
-configuration is valid for a platform. A State header defines parameters,
-which are used to match a platform.
+There can be multiple state configurations present. Each configuration is valid
+for a platform. A state header defines parameters, which are used to match a
+platform.
.B CPUFamily
CPU generation to match.
.PP
@@ -160,7 +160,7 @@ A name for the state.
.PP
.B EntrySystemLoadThres
System Entry load threshold in percent. System utilization is different
-based on the number of CPUs are active in a configuration. This value
+based on the number of active CPUs in a configuration. This value
is calculated from /proc/stat sysfs. To enter into this state, the
system utilization must be less or equal to this value.
.PP
@@ -186,13 +186,14 @@ EPP to apply for this state. -1 to ignore.
EPB to apply for this state. -1 to ignore.
.PP
.B ITMTState
-Set the state of ITMT flag. -1 to ignore.
+Set the state of ITMT flag. -1 to ignore. ITMT is only relevant for platforms
+before MTL and the debugfs file is not present on later platforms.
.PP
.B IRQMigrate
Migrate IRQs to the active CPUs in this state. -1 to ignore.
.PP
.B MinPollInterval
-Minimum polling interval in milli seconds.
+Minimum polling interval in milliseconds.
.PP
.B MaxPollInterval
Maximum polling interval in milli seconds. This is optional,
--
2.55.0

View File

@ -0,0 +1,177 @@
From f7bb8c57d709df3faaec3edbda3db7c0c79006a8 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Wed, 8 Apr 2026 20:08:33 +0200
Subject: [PATCH 19/56] man: Move unused config options to the unused section
Some options are not currently doing anything. Move them out of the
proper part of the man page to avoid confusing users.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
man/intel_lpmd_config.xml.5 | 108 +++++++++++-------------------------
1 file changed, 32 insertions(+), 76 deletions(-)
diff --git a/man/intel_lpmd_config.xml.5 b/man/intel_lpmd_config.xml.5
index 507939a..e6bea7c 100644
--- a/man/intel_lpmd_config.xml.5
+++ b/man/intel_lpmd_config.xml.5
@@ -86,7 +86,6 @@ specifies the system utilization threshold for entering Low Power Mode.
The system workload is considered to fit the lp_mode_cpus capacity when system
utilization is under this threshold.
Setting to 0 or leaving this empty disables the utilization monitor.
-
.PP
.B util_exit_threshold
specifies the CPU utilization threshold for exiting Low Power Mode.
@@ -94,33 +93,6 @@ The system workload is considered to not fit the lp_mode_cpus capacity when
the utilization of the busiest lp_mode_cpus is above this threshold.
Setting to 0 or leaving this empty disables the utilization monitor.
.PP
-.B EntryDelayMS
-specifies the sample interval used by the utilization Monitor when system
-wants to enter Low Power Mode based on system utilization.
-Setting to 0 or leaving this empty will cause the utilization Monitor to use
-the default interval, 1000 milli seconds.
-.PP
-.B ExitDelayMS
-specifies the sample interval used by the utilization Monitor when system
-wants to exit Low Power Mode based on CPU utilization.
-Setting to 0 or leaving this empty will cause the utilization Monitor to use
-the adaptive value. The adaptive interval is based on CPU utilization.
-The busier the CPU is, the shorter interval the utilization monitor uses.
-.PP
-.B EntryHystMS
-specifies a hysteresis threshold when system is in Low Power Mode.
-If set, when the previous average time stayed in Low Power Mode is lower than
-this value, the current enter Low Power Mode request will be ignored because
-it is expected that the system will exit Low Power Mode soon.
-Setting to 0 or leaving this empty disables this hysteresis algorithm.
-.PP
-.B ExitHystMS
-specifies a hysteresis threshold when system is not in Low Power Mode.
-If set, when the previous average time stayed out of Low-Power-Mode is lower
-than this value, the current exit Low Power Mode request will be ignored
-because it is expected that the system will enter Low Power Mode soon.
-Setting to 0 or leaving this empty disables this hysteresis algorithm.
-.PP
.B IgnoreITMT
Avoid changing scheduler ITMT flag. This means that during transition to
low power mode, ITMT flag is not changed. This reduces latency during
@@ -272,30 +244,6 @@ The configuration file format conforms to XML specifications.
-->
<util_exit_threshold>Example threshold</util_exit_threshold>
- <!--
- Entry delay. Minimum delay in non Low Power mode to
- enter LPM mode.
- -->
- <EntryDelayMS>Example delay</EntryDelayMS>
-
- <!--
- Exit delay. Minimum delay in Low Power mode to
- exit LPM mode.
- -->
- <ExitDelayMS>Example delay</ExitDelayMS>
-
- <!--
- Lowest hyst average in-LP-mode time in msec to enter LP mode
- 0: to disable hyst support
- -->
- <EntryHystMS>Example hyst</EntryHystMS>
-
- <!--
- Lowest hyst average out-of-LP-mode time in msec to exit LP mode
- 0: to disable hyst support
- -->
- <ExitHystMS>Example hyst</ExitHystMS>
-
<!--
EPP to use in Low Power Mode
0-255: Valid EPP value to use in Low Power Mode
@@ -323,14 +271,6 @@ util_entry_threshold: 0. Disable utilization monitor.
.IP \(bu 2
util_exit_threshold: 0. Disable utilization monitor.
.IP \(bu 2
-EntryDelayMS: 0. Do not take effect when utilization monitor is disabled.
-.IP \(bu 2
-ExitDelayMS: 0. Do not take effect when utilization monitor is disabled.
-.IP \(bu 2
-EntryHystMS: 0. Do not take effect when utilization monitor is disabled.
-.IP \(bu 2
-ExitHystMS: 0. Do not take effect when utilization monitor is disabled.
-.IP \(bu 2
lp_mode_epp: -1. Do not change EPP when entering Low Power Mode.
.sp 1
@@ -343,10 +283,6 @@ lp_mode_epp: -1. Do not change EPP when entering Low Power Mode.
<HfiSuvEnable>0</HfiSuvEnable>
<util_entry_threshold>0</util_entry_threshold>
<util_exit_threshold>0</util_exit_threshold>
- <EntryDelayMS>0</EntryDelayMS>
- <ExitDelayMS>0</ExitDelayMS>
- <EntryHystMS>0</EntryHystMS>
- <ExitHystMS>0</ExitHystMS>
<lp_mode_epp>-1</lp_mode_epp>
</Configuration>
.PP
@@ -365,14 +301,6 @@ util_entry_threshold: 5. Enter Low Power Mode when system utilization is lower t
.IP \(bu 2
util_exit_threshold: 95. Exit Low Power Mode when the utilization of any of the lp_mode_cpus is higher than 95%.
.IP \(bu 2
-EntryDelayMS: 0. Resample every 1000ms when system is out of Low Power Mode.
-.IP \(bu 2
-ExitDelayMS: 0. Resample adaptively based on the utilization of lp_mode_cpus when system is in Low Power Mode.
-.IP \(bu 2
-EntryHystMS: 2000. Ignore the current Enter Low Power Mode request when the previous average time stayed in Low Power Mode is lower than 2000ms.
-.IP \(bu 2
-ExitHystMS: 3000. Ignore the current Exit Low Power Mode request when the previous average time stayed out of Low Power Mode is lower than 3000ms.
-.IP \(bu 2
lp_mode_epp: -1. Do not change EPP when entering Low Power Mode.
.sp 1
@@ -385,10 +313,38 @@ lp_mode_epp: -1. Do not change EPP when entering Low Power Mode.
<HfiSuvEnable>1</HfiSuvEnable>
<util_entry_threshold>5</util_entry_threshold>
<util_exit_threshold>95</util_exit_threshold>
- <EntryDelayMS>0</EntryDelayMS>
- <ExitDelayMS>0</ExitDelayMS>
- <EntryHystMS>2000</EntryHystMS>
- <ExitHystMS>3000</ExitHystMS>
<lp_mode_epp>-1</lp_mode_epp>
</Configuration>
.EE
+
+.SH Currently unimplemented options
+.PP
+.B EntryDelayMS
+specifies the sample interval used by the utilization Monitor when system
+wants to enter Low Power Mode based on system utilization.
+Setting to 0 or leaving this empty will cause the utilization Monitor to use
+the default interval, 1000 milli seconds.
+.PP
+.B ExitDelayMS
+specifies the sample interval used by the utilization Monitor when system
+wants to exit Low Power Mode based on CPU utilization.
+Setting to 0 or leaving this empty will cause the utilization Monitor to use
+the adaptive value. The adaptive interval is based on CPU utilization.
+The busier the CPU is, the shorter interval the utilization monitor uses.
+.PP
+.B EntryHystMS
+specifies a hysteresis threshold when system is in Low Power Mode.
+If set, when the previous average time stayed in Low Power Mode is lower than
+this value, the current enter Low Power Mode request will be ignored because
+it is expected that the system will exit Low Power Mode soon.
+Setting to 0 or leaving this empty disables this hysteresis algorithm.
+.PP
+.B ExitHystMS
+specifies a hysteresis threshold when system is not in Low Power Mode.
+If set, when the previous average time stayed out of Low-Power-Mode is lower
+than this value, the current exit Low Power Mode request will be ignored
+because it is expected that the system will enter Low Power Mode soon.
+Setting to 0 or leaving this empty disables this hysteresis algorithm.
+
+.SH SEE ALSO
+intel_lpmd(8), intel_lpmd_control(8)
--
2.55.0

View File

@ -0,0 +1,48 @@
From c1506542e97424151018e9cb4958ff02dad616d2 Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Sun, 12 Apr 2026 16:53:58 -0700
Subject: [PATCH 20/56] Add Panther Lake 4P0E4L
Add configuration for Panther Lake 4P+0E+4L.
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
data/intel_lpmd_config_F6_M204.xml | 24 ++++++++++++++++++++++++
1 file changed, 24 insertions(+)
diff --git a/data/intel_lpmd_config_F6_M204.xml b/data/intel_lpmd_config_F6_M204.xml
index a67fa8b..f1e36da 100644
--- a/data/intel_lpmd_config_F6_M204.xml
+++ b/data/intel_lpmd_config_F6_M204.xml
@@ -186,4 +186,28 @@ for Intel Energy Optimizer (LPMD) daemon
</State>
</States>
+ <States>
+ <CPUFamily> 6 </CPUFamily>
+ <CPUModel> 204 </CPUModel>
+ <CPUConfig> 4P0E4L-25W </CPUConfig>
+ <State>
+ <ID> 1 </ID>
+ <Name> UTIL_IDLE </Name>
+ <WLTType> 1 </WLTType>
+ <ActiveCPUs>4-7</ActiveCPUs>
+ </State>
+ <State>
+ <ID> 2 </ID>
+ <Name> UTIL_IDLE_SUSTAIN </Name>
+ <WLTType> 2 </WLTType>
+ <ActiveCPUs>0-7</ActiveCPUs>
+ </State>
+ <State>
+ <ID> 3 </ID>
+ <Name> UTIL_IDLE_BURSTY </Name>
+ <WLTType> 3 </WLTType>
+ <ActiveCPUs>0-7</ActiveCPUs>
+ </State>
+ </States>
+
</Configuration>
--
2.55.0

View File

@ -0,0 +1,30 @@
From ba2ad5431881f7fc0ee4b5ab9a3f14ec9126c032 Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Sun, 12 Apr 2026 16:57:14 -0700
Subject: [PATCH 21/56] Remove power group
There is no use case of special power group to send message to LPMD.
Allow only root users.
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
data/org.freedesktop.intel_lpmd.conf | 4 ----
1 file changed, 4 deletions(-)
diff --git a/data/org.freedesktop.intel_lpmd.conf b/data/org.freedesktop.intel_lpmd.conf
index 239004b..f06fd34 100644
--- a/data/org.freedesktop.intel_lpmd.conf
+++ b/data/org.freedesktop.intel_lpmd.conf
@@ -16,9 +16,5 @@
<deny send_destination="org.freedesktop.intel_lpmd"/>
<allow receive_sender="org.freedesktop.intel_lpmd"/>
</policy>
- <policy group="power">
- <allow send_destination="org.freedesktop.intel_lpmd"/>
- <allow receive_sender="org.freedesktop.intel_lpmd"/>
- </policy>
</busconfig>
--
2.55.0

View File

@ -0,0 +1,121 @@
From ba4395eb9bc20f530c567b623b07b8bab86be8ba Mon Sep 17 00:00:00 2001
From: Peter Jung <ptr1337@archlinux.org>
Date: Sat, 11 Apr 2026 10:32:52 +0200
Subject: [PATCH 22/56] Add GetState D-Bus method to query current LPM control
mode
Expose the current daemon state (OFF/ON/AUTO/FREEZE/TERMINATE) via a new
GetState D-Bus method and a STATUS command in intel_lpmd_control, so
clients can query the active mode without having to track it externally.
Signed-off-by: Peter Jung <ptr1337@archlinux.org>
---
src/intel_lpmd_dbus_interface.xml | 4 ++++
src/lpmd_dbus_server.c | 17 ++++++++++++++
tools/intel_lpmd_control.c | 38 +++++++++++++++++++++++++++----
3 files changed, 54 insertions(+), 5 deletions(-)
diff --git a/src/intel_lpmd_dbus_interface.xml b/src/intel_lpmd_dbus_interface.xml
index add0fd5..b723034 100644
--- a/src/intel_lpmd_dbus_interface.xml
+++ b/src/intel_lpmd_dbus_interface.xml
@@ -19,5 +19,9 @@
<method name="LPM_AUTO">
</method>
+ <method name="GetState">
+ <arg type="s" name="state" direction="out"/>
+ </method>
+
</interface>
</node>
diff --git a/src/lpmd_dbus_server.c b/src/lpmd_dbus_server.c
index 318d96b..0b2960b 100644
--- a/src/lpmd_dbus_server.c
+++ b/src/lpmd_dbus_server.c
@@ -155,6 +155,23 @@ lpmd_dbus_handle_method_call(GDBusConnection *connection,
return;
}
+ if (g_strcmp0(method_name, "GetState") == 0) {
+ const char *state_names[] = {
+ [LPMD_OFF] = "OFF",
+ [LPMD_ON] = "ON",
+ [LPMD_AUTO] = "AUTO",
+ [LPMD_FREEZE] = "FREEZE",
+ [LPMD_RESTORE] = "RESTORE",
+ [LPMD_TERMINATE] = "TERMINATE",
+ };
+ int state = get_lpmd_state();
+ const char *name = (state >= 0 && state <= LPMD_TERMINATE) ? state_names[state] : "UNKNOWN";
+
+ g_dbus_method_invocation_return_value(invocation,
+ g_variant_new("(s)", name));
+ return;
+ }
+
g_set_error(&error,
G_DBUS_ERROR,
G_DBUS_ERROR_UNKNOWN_METHOD,
diff --git a/tools/intel_lpmd_control.c b/tools/intel_lpmd_control.c
index 293ee49..81dc340 100644
--- a/tools/intel_lpmd_control.c
+++ b/tools/intel_lpmd_control.c
@@ -51,10 +51,42 @@ main(int argc, char **argv)
if (argc < 2) {
fprintf (stderr, "intel_lpmd_control: missing control command\n");
fprintf (stderr, "syntax:\n");
- fprintf (stderr, "intel_lpmd_control ON|OFF|AUTO\n");
+ fprintf (stderr, "intel_lpmd_control ON|OFF|AUTO|STATUS\n");
exit (0);
}
+ connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
+ if (connection == NULL)
+ return FALSE;
+
+ if (!strncmp (argv[1], "STATUS", 6)) {
+ g_autoptr(GVariant) result = NULL;
+
+ result = g_dbus_connection_call_sync (connection,
+ INTEL_LPMD_SERVICE_NAME,
+ INTEL_LPMD_SERVICE_OBJECT_PATH,
+ INTEL_LPMD_SERVICE_INTERFACE,
+ "GetState",
+ NULL,
+ G_VARIANT_TYPE ("(s)"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+
+ if (error != NULL) {
+ g_warning ("Fail on connecting lpmd: %s", error->message);
+ exit (1);
+ }
+
+ const gchar *state;
+
+ g_variant_get (result, "(&s)", &state);
+ g_print ("%s\n", state);
+
+ return 0;
+ }
+
if (!strncmp (argv[1], "ON", 2))
command = g_string_new ("LPM_FORCE_ON");
else if (!strncmp (argv[1], "OFF", 3))
@@ -66,10 +98,6 @@ main(int argc, char **argv)
exit (1);
}
- connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error);
- if (connection == NULL)
- return FALSE;
-
g_dbus_connection_call_sync (connection,
INTEL_LPMD_SERVICE_NAME,
INTEL_LPMD_SERVICE_OBJECT_PATH,
--
2.55.0

View File

@ -0,0 +1,26 @@
From 8c150e609c55dad801f5b7925b5ccc33d81d83b7 Mon Sep 17 00:00:00 2001
From: Peter Jung <admin@ptr1337.dev>
Date: Sat, 11 Apr 2026 11:34:15 +0200
Subject: [PATCH 23/56] fix: restore systemd unit install path
Signed-off-by: Peter Jung <admin@ptr1337.dev>
---
configure.ac | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac
index b212c4d..f0f5250 100644
--- a/configure.ac
+++ b/configure.ac
@@ -34,7 +34,7 @@ PKG_PROG_PKG_CONFIG
AC_ARG_WITH([systemdsystemunitdir],
[AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files])],
[], [with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)])
-AS_IF(["x$with_systemdsystemunitdir" != xno], [
+AS_IF([test "x$with_systemdsystemunitdir" != xno], [
AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
])
--
2.55.0

View File

@ -0,0 +1,83 @@
From 8c175e8db8259ed041a7826269521cef5029b474 Mon Sep 17 00:00:00 2001
From: Joy Philip Pilli <joyphilip.p2001@gmail.com>
Date: Fri, 24 Apr 2026 20:02:49 +0530
Subject: [PATCH 24/56] fix: prevent cgroup isolation churn during WLT polling
When changing state with cgroup isolation mode enabled,
cpuset.cpus.partition is set to member state temporarily. Then the
exclusive cpus value is written and partition is changed to isolated
again. When partition is in member state temporarily tasks can get
scheduled briefly on cpus that should be isolated and not used. When
states change quickly this can happen quite often and will decrease
efficiency.
Don't update the cgroups if the final cpu masks will be the same,
thereby optimizing for the inefficiency mentioned above.
Signed-off-by: Joy Philip Pilli <joyphilip.p2001@gmail.com>
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/lpmd_cgroup.c | 28 +++++++++++++++++++++++-----
1 file changed, 23 insertions(+), 5 deletions(-)
diff --git a/src/lpmd_cgroup.c b/src/lpmd_cgroup.c
index 5b53179..e4396c7 100644
--- a/src/lpmd_cgroup.c
+++ b/src/lpmd_cgroup.c
@@ -170,6 +170,8 @@ static int process_cpu_cgroupv2(lpmd_config_state_t *state)
}
}
+static enum cpumask_idx last_applied_cpumask = CPUMASK_NONE;
+
/* Support for cgroup based cpu isolation */
static int process_cpu_isolate(lpmd_config_state_t *state)
{
@@ -193,7 +195,10 @@ static int process_cpu_isolate(lpmd_config_state_t *state)
int cgroup_cleanup(void)
{
- DIR *dir = opendir("/sys/fs/cgroup/lpm");
+ DIR *dir;
+
+ last_applied_cpumask = CPUMASK_NONE;
+ *dir = opendir("/sys/fs/cgroup/lpm");
if (dir) {
closedir(dir);
rmdir("/sys/fs/cgroup/lpm");
@@ -213,15 +218,28 @@ int cgroup_init(lpmd_config_t *config)
int process_cgroup(lpmd_config_state_t *state, enum lpm_cpu_process_mode mode)
{
+ int ret;
+
if (state->cpumask_idx == CPUMASK_NONE) {
lpmd_log_debug ("Ignore cgroup processing\n");
return 0;
}
+ if (last_applied_cpumask != CPUMASK_NONE &&
+ cpumask_equal(state->cpumask_idx, last_applied_cpumask)) {
+ lpmd_log_debug("Skip cgroup: cpumask unchanged\n");
+ return 0;
+ }
+
lpmd_log_info ("Process Cgroup ...\n");
if (mode == LPM_CPU_CGROUPV2)
- return process_cpu_cgroupv2(state);
- if (mode == LPM_CPU_ISOLATE)
- return process_cpu_isolate(state);
- return 0;
+ ret = process_cpu_cgroupv2(state);
+ else if (mode == LPM_CPU_ISOLATE)
+ ret = process_cpu_isolate(state);
+ else
+ ret = 0;
+
+ if (!ret)
+ last_applied_cpumask = state->cpumask_idx;
+ return ret;
}
--
2.55.0

View File

@ -0,0 +1,31 @@
From 9cbc47334aedd36ccdab62ad25e63a63af0aa605 Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Fri, 5 Jun 2026 15:13:55 -0700
Subject: [PATCH 25/56] Fix build breakage with the last commit
Last commit
"fix: prevent cgroup isolation churn during WLT polling
"
introduced build error for *dir. Fix that.
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
src/lpmd_cgroup.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lpmd_cgroup.c b/src/lpmd_cgroup.c
index e4396c7..e74c8cf 100644
--- a/src/lpmd_cgroup.c
+++ b/src/lpmd_cgroup.c
@@ -198,7 +198,7 @@ int cgroup_cleanup(void)
DIR *dir;
last_applied_cpumask = CPUMASK_NONE;
- *dir = opendir("/sys/fs/cgroup/lpm");
+ dir = opendir("/sys/fs/cgroup/lpm");
if (dir) {
closedir(dir);
rmdir("/sys/fs/cgroup/lpm");
--
2.55.0

View File

@ -0,0 +1,62 @@
From 1303d156352c459fd9eb4aa29270af73d9d85f8d Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Thu, 11 Dec 2025 12:18:05 +0100
Subject: [PATCH 26/56] git: Setup gitignore
After building the project the temporary files and binaries show up in
git as untracked.
Create .gitignore and add them to it.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
.gitignore | 37 +++++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
create mode 100644 .gitignore
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..52038ed
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,37 @@
+# Root directory subdirectories
+/autom4te.cache/*
+/build-aux/*
+/config.*
+/m4/*.m4
+/.deps/*
+
+# Root directory autogenerated files
+/intel_lpmd
+/configure
+/configure~
+/aclocal.m4
+/lpmd-resource.c
+/stamp-h1
+/gtk-doc.make
+
+# Source autogenerated subdirectories
+/src/.deps/*
+/src/wlt_proxy/.deps/*
+
+# Tools autogenerated subdirectories and binaries
+/tools/.deps/*
+/tools/intel_lpmd_control
+
+# Autogenerated services
+/data/intel_lpmd.service
+/data/org.freedesktop.intel_lpmd.service
+
+# Object files, makefiles and others across the whole repository
+*.o
+.dirstamp
+Makefile
+Makefile.in
+
+# LSP files
+/.cache/*
+/compile_commands.json
--
2.55.0

View File

@ -0,0 +1,171 @@
From 327fdec26fb07949d2b0d1d83fc43e8cf5a8d8f4 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Thu, 11 Dec 2025 21:46:12 +0100
Subject: [PATCH 27/56] lpmd_config: Cleanup code indentation in parse states
function
Higher code indentation is more difficult to read and it's easy to
rewrite using early return/continue statements.
Refactor the code to diminish the indentation level by two in
lpmd_parse_states().
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/lpmd_config.c | 137 +++++++++++++++++++++++-----------------------
1 file changed, 70 insertions(+), 67 deletions(-)
diff --git a/src/lpmd_config.c b/src/lpmd_config.c
index 7137db2..a5c21ad 100644
--- a/src/lpmd_config.c
+++ b/src/lpmd_config.c
@@ -39,76 +39,79 @@ static void lpmd_parse_state(xmlDoc *doc, xmlNode *a_node, lpmd_config_t *config
lpmd_init_config_state(state);
for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
- if (cur_node->type == XML_ELEMENT_NODE) {
- tmp_value = (char*) xmlNodeListGetString (doc, cur_node->xmlChildrenNode, 1);
- if (tmp_value) {
- if (!strncmp((const char*)cur_node->name, "ID", strlen("ID")))
- state->id = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "Name", strlen("Name"))) {
- snprintf(state->name, MAX_STATE_NAME - 1, "%s", tmp_value);
- state->name[MAX_STATE_NAME - 1] = '\0';
- }
- if (!strncmp((const char*)cur_node->name, "WLTType", strlen("WLTType")))
- state->wlt_type = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "EntrySystemLoadThres", strlen("EntrySystemLoadThres")))
- state->entry_system_load_thres = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "ExitSystemLoadThres", strlen("ExitSystemLoadThres")))
- state->exit_system_load_thres = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "ExitSystemLoadhysteresis", strlen("ExitSystemLoadhysteresis")))
- state->exit_system_load_hyst = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "EnterCPULoadThres", strlen("EnterCPULoadThres")))
- state->enter_cpu_load_thres = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "ExitCPULoadThres", strlen("ExitCPULoadThres")))
- state->exit_cpu_load_thres = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "EnterGFXLoadThres", strlen("EnterGFXLoadThres")))
- state->enter_gfx_load_thres = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "ExitGFXLoadThres", strlen("ExitGFXLoadThres")))
- state->exit_gfx_load_thres = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "MinPollInterval", strlen("MinPollInterval")))
- state->min_poll_interval = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "MaxPollInterval", strlen("MaxPollInterval")))
- state->max_poll_interval = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "PollIntervalIncrement", strlen("PollIntervalIncrement")))
- state->poll_interval_increment = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "EPP", strlen("EPP")))
- state->epp = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "EPB", strlen("EPB")))
- state->epb = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "ITMTState", strlen("ITMTState")))
- state->itmt_state = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "IRQMigrate", strlen("IRQMigrate")))
- state->irq_migrate = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "Island0Pcores", strlen("Island0Pcores")))
- state->island_0_number_p_cores = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "Island0Ecores", strlen("Island0Ecores")))
- state->island_0_number_e_cores = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "Island1Pcores", strlen("Island1Pcores")))
- state->island_1_number_p_cores = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "Island1Ecores", strlen("Island1Ecores")))
- state->island_1_number_e_cores = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "Island2Pcores", strlen("Island2Pcores")))
- state->island_2_number_p_cores = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "Island2Ecores", strlen("Island2Ecores")))
- state->island_2_number_e_cores = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "ActiveCPUs", strlen("ActiveCPUs"))) {
- if (!strncmp (tmp_value, "-1", strlen ("-1")))
- state->active_cpus[0] = '\0';
- else
- copy_user_string(tmp_value, state->active_cpus, sizeof(state->active_cpus));
- }
- if (!strncmp((const char*)cur_node->name, "BalanceSliderAC", strlen("BalanceSliderAC")))
- state->balance_slider_ac = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "SliderOffsetAC", strlen("SliderOffsetAC")))
- state->slider_offset_ac = strtol (tmp_value, &pos, 10);
+ if (cur_node->type != XML_ELEMENT_NODE)
+ continue;
- if (!strncmp((const char*)cur_node->name, "BalanceSliderDC", strlen("BalanceSliderDC")))
- state->balance_slider_dc = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "SliderOffsetDC", strlen("SliderOffsetDC")))
- state->slider_offset_dc = strtol (tmp_value, &pos, 10);
+ tmp_value = (char*) xmlNodeListGetString (doc, cur_node->xmlChildrenNode, 1);
- xmlFree(tmp_value);
- }
+ if (!tmp_value)
+ continue;
+
+ if (!strncmp((const char*)cur_node->name, "ID", strlen("ID")))
+ state->id = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "Name", strlen("Name"))) {
+ snprintf(state->name, MAX_STATE_NAME - 1, "%s", tmp_value);
+ state->name[MAX_STATE_NAME - 1] = '\0';
}
+ if (!strncmp((const char*)cur_node->name, "WLTType", strlen("WLTType")))
+ state->wlt_type = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "EntrySystemLoadThres", strlen("EntrySystemLoadThres")))
+ state->entry_system_load_thres = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "ExitSystemLoadThres", strlen("ExitSystemLoadThres")))
+ state->exit_system_load_thres = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "ExitSystemLoadhysteresis", strlen("ExitSystemLoadhysteresis")))
+ state->exit_system_load_hyst = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "EnterCPULoadThres", strlen("EnterCPULoadThres")))
+ state->enter_cpu_load_thres = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "ExitCPULoadThres", strlen("ExitCPULoadThres")))
+ state->exit_cpu_load_thres = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "EnterGFXLoadThres", strlen("EnterGFXLoadThres")))
+ state->enter_gfx_load_thres = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "ExitGFXLoadThres", strlen("ExitGFXLoadThres")))
+ state->exit_gfx_load_thres = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "MinPollInterval", strlen("MinPollInterval")))
+ state->min_poll_interval = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "MaxPollInterval", strlen("MaxPollInterval")))
+ state->max_poll_interval = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "PollIntervalIncrement", strlen("PollIntervalIncrement")))
+ state->poll_interval_increment = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "EPP", strlen("EPP")))
+ state->epp = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "EPB", strlen("EPB")))
+ state->epb = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "ITMTState", strlen("ITMTState")))
+ state->itmt_state = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "IRQMigrate", strlen("IRQMigrate")))
+ state->irq_migrate = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "Island0Pcores", strlen("Island0Pcores")))
+ state->island_0_number_p_cores = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "Island0Ecores", strlen("Island0Ecores")))
+ state->island_0_number_e_cores = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "Island1Pcores", strlen("Island1Pcores")))
+ state->island_1_number_p_cores = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "Island1Ecores", strlen("Island1Ecores")))
+ state->island_1_number_e_cores = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "Island2Pcores", strlen("Island2Pcores")))
+ state->island_2_number_p_cores = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "Island2Ecores", strlen("Island2Ecores")))
+ state->island_2_number_e_cores = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "ActiveCPUs", strlen("ActiveCPUs"))) {
+ if (!strncmp (tmp_value, "-1", strlen ("-1")))
+ state->active_cpus[0] = '\0';
+ else
+ copy_user_string(tmp_value, state->active_cpus, sizeof(state->active_cpus));
+ }
+ if (!strncmp((const char*)cur_node->name, "BalanceSliderAC", strlen("BalanceSliderAC")))
+ state->balance_slider_ac = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "SliderOffsetAC", strlen("SliderOffsetAC")))
+ state->slider_offset_ac = strtol (tmp_value, &pos, 10);
+
+ if (!strncmp((const char*)cur_node->name, "BalanceSliderDC", strlen("BalanceSliderDC")))
+ state->balance_slider_dc = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "SliderOffsetDC", strlen("SliderOffsetDC")))
+ state->slider_offset_dc = strtol (tmp_value, &pos, 10);
+
+ xmlFree(tmp_value);
}
}
--
2.55.0

View File

@ -0,0 +1,108 @@
From 8ef15d7854d4d9b433f373f5959c2744ce9b8a6a Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Fri, 12 Dec 2025 17:27:48 +0100
Subject: [PATCH 28/56] lpmd_config: Rename island number cores tags
Redo these config options into a number of active cores of a given type
to specify per state. This is a preparation for a configuration feature
to name a number of a specific core type instead of hardcoding the
actual core indices.
Remove the excess island number cores tags since they're not used
anywhere.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/include/lpmd.h | 9 +++------
src/lpmd_config.c | 18 ++++++------------
src/lpmd_state_machine.c | 18 ++++++------------
3 files changed, 15 insertions(+), 30 deletions(-)
diff --git a/src/include/lpmd.h b/src/include/lpmd.h
index 223467b..f3701df 100644
--- a/src/include/lpmd.h
+++ b/src/include/lpmd.h
@@ -164,12 +164,9 @@ typedef struct {
char active_cpus[MAX_STR_LENGTH];
// If active CPUs are specified then
// the below counts don't matter
- int island_0_number_p_cores;
- int island_0_number_e_cores;
- int island_1_number_p_cores;
- int island_1_number_e_cores;
- int island_2_number_p_cores;
- int island_2_number_e_cores;
+ int active_p_cores;
+ int active_e_cores;
+ int active_l_cores;
int itmt_state;
int irq_migrate;
diff --git a/src/lpmd_config.c b/src/lpmd_config.c
index a5c21ad..214f251 100644
--- a/src/lpmd_config.c
+++ b/src/lpmd_config.c
@@ -83,18 +83,12 @@ static void lpmd_parse_state(xmlDoc *doc, xmlNode *a_node, lpmd_config_t *config
state->itmt_state = strtol (tmp_value, &pos, 10);
if (!strncmp((const char*)cur_node->name, "IRQMigrate", strlen("IRQMigrate")))
state->irq_migrate = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "Island0Pcores", strlen("Island0Pcores")))
- state->island_0_number_p_cores = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "Island0Ecores", strlen("Island0Ecores")))
- state->island_0_number_e_cores = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "Island1Pcores", strlen("Island1Pcores")))
- state->island_1_number_p_cores = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "Island1Ecores", strlen("Island1Ecores")))
- state->island_1_number_e_cores = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "Island2Pcores", strlen("Island2Pcores")))
- state->island_2_number_p_cores = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "Island2Ecores", strlen("Island2Ecores")))
- state->island_2_number_e_cores = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "ActivePcores", strlen("ActivePcores")))
+ state->active_p_cores = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "ActiveEcores", strlen("ActiveEcores")))
+ state->active_e_cores = strtol (tmp_value, &pos, 10);
+ if (!strncmp((const char*)cur_node->name, "ActiveLcores", strlen("ActiveLcores")))
+ state->active_l_cores = strtol (tmp_value, &pos, 10);
if (!strncmp((const char*)cur_node->name, "ActiveCPUs", strlen("ActiveCPUs"))) {
if (!strncmp (tmp_value, "-1", strlen ("-1")))
state->active_cpus[0] = '\0';
diff --git a/src/lpmd_state_machine.c b/src/lpmd_state_machine.c
index 9e7bcf2..c5b2f98 100644
--- a/src/lpmd_state_machine.c
+++ b/src/lpmd_state_machine.c
@@ -109,12 +109,9 @@ int lpmd_init_config_state(lpmd_config_state_t *state)
state->active_cpus[0] = '\0';
state->cpumask_idx = CPUMASK_NONE;
- state->island_0_number_p_cores = 0;
- state->island_0_number_e_cores = 0;
- state->island_1_number_p_cores = 0;
- state->island_1_number_e_cores = 0;
- state->island_2_number_p_cores = 0;
- state->island_2_number_e_cores = 0;
+ state->active_p_cores = 0;
+ state->active_e_cores = 0;
+ state->active_l_cores = 0;
state->itmt_state = SETTING_IGNORE;
state->irq_migrate = SETTING_IGNORE;
@@ -477,12 +474,9 @@ static void dump_states(lpmd_config_t *lpmd_config)
if (state->active_cpus[0] != '\0')
lpmd_log_info ("\tactive_cpus:%s\n", state->active_cpus);
lpmd_log_info ("\tCPUMASK idx:%d\n", state->cpumask_idx);
- lpmd_log_info ("\tisland_0_number_p_cores:%d\n", state->island_0_number_p_cores);
- lpmd_log_info ("\tisland_0_number_e_cores:%d\n", state->island_0_number_e_cores);
- lpmd_log_info ("\tisland_1_number_p_cores:%d\n", state->island_1_number_p_cores);
- lpmd_log_info ("\tisland_1_number_e_cores:%d\n", state->island_1_number_e_cores);
- lpmd_log_info ("\tisland_2_number_p_cores:%d\n", state->island_2_number_p_cores);
- lpmd_log_info ("\tisland_2_number_e_cores:%d\n", state->island_2_number_e_cores);
+ lpmd_log_info ("\tactive_p_cores:%d\n", state->active_p_cores);
+ lpmd_log_info ("\tactive_e_cores:%d\n", state->active_e_cores);
+ lpmd_log_info ("\tactive_l_cores:%d\n", state->active_l_cores);
lpmd_log_info ("\tBalancedSliderAC:%d\n", state->balance_slider_ac);
lpmd_log_info ("\tBalancedSliderDC:%d\n", state->balance_slider_dc);
lpmd_log_info ("\tSliderOffsetAC:%d\n", state->slider_offset_ac);
--
2.55.0

View File

@ -0,0 +1,262 @@
From ee708ab0d546fbbc7f55437ae4a4126c5c706805 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Fri, 12 Dec 2025 18:00:32 +0100
Subject: [PATCH 29/56] lpmd_state_machine: Count system of specifing active
cores
Instead of supplying the specific cpu core indices in the ActiveCpus
tags in the configuration it would be more convenient to only put down
the desired number of cores of a specific type / types.
Add a simple system of core type bitmasks from which the program can
later derive cpumasks based on the usage of ActiveP/E/Lcores in the
configuration states.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/include/lpmd.h | 15 +++++++++++
src/lpmd_cpu.c | 14 +++++++---
src/lpmd_cpumask.c | 35 +++++++++++++++++++++++++
src/lpmd_state_machine.c | 52 +++++++++++++++++++++++++++++++++++---
src/wlt_proxy/state_util.c | 6 -----
5 files changed, 109 insertions(+), 13 deletions(-)
diff --git a/src/include/lpmd.h b/src/include/lpmd.h
index f3701df..3bb8fb9 100644
--- a/src/include/lpmd.h
+++ b/src/include/lpmd.h
@@ -108,6 +108,7 @@ typedef struct {
#define MAX_CONFIG_STATES 10
#define MAX_STATE_NAME 32
#define MAX_CONFIG_LEN 64
+#define MAX_CPUS 64
enum lpmd_states {
LPMD_OFF,
@@ -144,6 +145,13 @@ enum default_config_state {
STATE_NONE = MAX_STATES,
};
+#define CORE_TYPES_COUNT 3
+enum core_type {
+ P_CORE,
+ E_CORE,
+ L_CORE
+};
+
typedef struct {
int id;
int valid;
@@ -183,6 +191,10 @@ typedef struct {
int steady;
}lpmd_config_state_t;
+struct core_masks_t {
+ unsigned char cmask[CORE_TYPES_COUNT][MAX_CPUS / 8];
+};
+
// lpmd config data
typedef struct {
int mode;
@@ -219,6 +231,8 @@ typedef struct {
int config_state_count;
int tdp;
+ struct core_masks_t core_type_masks;
+
int balance_slider_def_ac;
int slider_offset_def_ac;
int balance_slider_def_dc;
@@ -380,6 +394,7 @@ int cpumask_reset(enum cpumask_idx idx);
int cpumask_add_cpu(int cpu, enum cpumask_idx idx);
int cpumask_init_cpus(char *buf, enum cpumask_idx idx);
+int cpumask_init_cpus_type(int count, enum cpumask_idx idx, struct core_masks_t *cmasks, enum core_type type);
int cpumask_nr_cpus(enum cpumask_idx idx);
int cpumask_has_cpu(enum cpumask_idx idx);
diff --git a/src/lpmd_cpu.c b/src/lpmd_cpu.c
index e611b78..d71ca6c 100644
--- a/src/lpmd_cpu.c
+++ b/src/lpmd_cpu.c
@@ -341,15 +341,23 @@ int detect_cpu_topo(lpmd_config_t *lpmd_config)
/* Here it is the first time we migrate CPUs, must clear the previous cgroup settings */
cgroup_cleanup();
+ memset(lpmd_config->core_type_masks.cmask[0], 0, CORE_TYPES_COUNT * MAX_CPUS / 8);
+
for (i = 0; i < get_max_cpus(); i++) {
if (!is_cpu_online(i))
continue;
- if (is_cpu_pcore(i))
+ if (is_cpu_pcore(i)) {
pcores++;
- else if (is_cpu_ecore(i))
+ lpmd_config->core_type_masks.cmask[P_CORE][i / 8] |= 1 << (i % 8);
+ }
+ else if (is_cpu_ecore(i)) {
ecores++;
- else if (is_cpu_lcore(i))
+ lpmd_config->core_type_masks.cmask[E_CORE][i / 8] |= 1 << (i % 8);
+ }
+ else if (is_cpu_lcore(i)) {
lcores++;
+ lpmd_config->core_type_masks.cmask[L_CORE][i / 8] |= 1 << (i % 8);
+ }
}
tdp = get_tdp();
diff --git a/src/lpmd_cpumask.c b/src/lpmd_cpumask.c
index 7de08e5..d110703 100644
--- a/src/lpmd_cpumask.c
+++ b/src/lpmd_cpumask.c
@@ -177,6 +177,41 @@ int cpumask_add_cpu(int cpu, enum cpumask_idx idx)
return LPMD_SUCCESS;
}
+static unsigned int get_next_cpu_cmask(unsigned int id, enum core_type type, unsigned char *cmask)
+{
+ bool ret;
+ int i;
+
+ for (i = id ; i < MAX_CPUS ; i++) {
+ ret = !!(cmask[i / 8] & (1 << (i % 8)));
+ if (ret)
+ return i;
+ }
+ return id;
+}
+
+
+int cpumask_init_cpus_type(int count, enum cpumask_idx idx, struct core_masks_t *cmasks, enum core_type type)
+{
+ unsigned int current, next;
+ int nr_cpus = 0;
+
+ if (!count)
+ return 0;
+
+ current = get_next_cpu_cmask(0, type, cmasks->cmask[type]);
+ while(nr_cpus != count) {
+ cpumask_add_cpu(current, idx);
+ next = get_next_cpu_cmask(current + 1, type, cmasks->cmask[type]);
+ if(next == current) /* Couldn't find next core of the provided type */
+ return nr_cpus;
+ nr_cpus++;
+ current = next;
+ }
+
+ return nr_cpus;
+}
+
int cpumask_init_cpus(char *buf, enum cpumask_idx idx)
{
unsigned int start, end;
diff --git a/src/lpmd_state_machine.c b/src/lpmd_state_machine.c
index c5b2f98..22fd997 100644
--- a/src/lpmd_state_machine.c
+++ b/src/lpmd_state_machine.c
@@ -607,7 +607,11 @@ static int config_states_update_config(lpmd_config_t *config)
}
-static int build_state_cpumask(lpmd_config_state_t *state)
+/*
+ * Return 0 on success - either when nothing requires setting up Return -1 on error
+ * and -2 if there are no active cpus specified.
+ */
+static int build_state_cpumask_activecpus(lpmd_config_state_t *state)
{
state->steady = 1;
@@ -615,7 +619,7 @@ static int build_state_cpumask(lpmd_config_state_t *state)
return 0;
if (state->active_cpus[0] == '\0')
- return 0;
+ return -2;
if (!strncmp(state->active_cpus, "all", sizeof("all")) ||
!strncmp(state->active_cpus, "ALL", sizeof("ALL"))) {
@@ -651,19 +655,59 @@ static int build_state_cpumask(lpmd_config_state_t *state)
return 0;
}
+static int build_state_cpumask_cputypes(lpmd_config_state_t *state, struct core_masks_t *cmasks)
+{
+ int ret;
+
+ if (state->cpumask_idx != CPUMASK_NONE)
+ return 0;
+
+ state->cpumask_idx = cpumask_alloc();
+ if (state->cpumask_idx == CPUMASK_NONE) {
+ lpmd_log_error("Cannot alloc CPUMASK\n");
+ return -1;
+ }
+
+ /* Setup the specified P-cores */
+ ret = cpumask_init_cpus_type(state->active_p_cores, state->cpumask_idx, cmasks, P_CORE);
+ if (ret < 0) {
+ cpumask_free(state->cpumask_idx);
+ return -1;
+ }
+
+ /* Setup the specified E-cores */
+ ret = cpumask_init_cpus_type(state->active_e_cores, state->cpumask_idx, cmasks, E_CORE);
+ if (ret < 0) {
+ cpumask_free(state->cpumask_idx);
+ return -1;
+ }
+
+ /* Setup the specified L-cores */
+ ret = cpumask_init_cpus_type(state->active_l_cores, state->cpumask_idx, cmasks, L_CORE);
+ if (ret < 0) {
+ cpumask_free(state->cpumask_idx);
+ return -1;
+ }
+
+ return 0;
+}
+
#define DEFAULT_POLL_RATE_MS 1000
int lpmd_build_config_states(lpmd_config_t *lpmd_config)
{
lpmd_config_state_t *state;
- int i;
+ int ret, i;
build_default_states(lpmd_config);
for (i = CONFIG_STATE_BASE; i < CONFIG_STATE_BASE + lpmd_config->config_state_count; i++) {
state = &lpmd_config->config_states[i];
- if (build_state_cpumask(state))
+ ret = build_state_cpumask_activecpus(state);
+ if (ret == -2)
+ build_state_cpumask_cputypes(state, &lpmd_config->core_type_masks);
+ else if (ret)
continue;
if (state->entry_system_load_thres || state->enter_cpu_load_thres || state->enter_gfx_load_thres)
diff --git a/src/wlt_proxy/state_util.c b/src/wlt_proxy/state_util.c
index f35242e..d937d5f 100644
--- a/src/wlt_proxy/state_util.c
+++ b/src/wlt_proxy/state_util.c
@@ -42,12 +42,6 @@
static int sample[3][SMA_LENGTH];
-enum core_type {
- P_CORE = 1,
- E_CORE = 2,
- L_CORE = 3
-};
-
typedef struct {
int cpu;
--
2.55.0

View File

@ -0,0 +1,258 @@
From 212ec106b49f4ef92bfac9282f3ea98a7df68685 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Tue, 16 Dec 2025 13:38:12 +0100
Subject: [PATCH 30/56] lpmd_cpumask: Dynamic core type cpumask allocation
Statically allocated setup of the core type bitmasks can be optimized by
moving to dynamic allocation. The shift is made easier by the program
already discovering the maximum number of cpus on the system.
Setup dynamic allocation and freeing of the core type bitmasks.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/include/lpmd.h | 13 +++++--------
src/lpmd_cpu.c | 13 +++++++++----
src/lpmd_cpumask.c | 28 ++++++++++++++++++++++++----
src/lpmd_proc.c | 16 +++++++++++-----
src/lpmd_state_machine.c | 4 ++--
5 files changed, 51 insertions(+), 23 deletions(-)
diff --git a/src/include/lpmd.h b/src/include/lpmd.h
index 3bb8fb9..f35b46e 100644
--- a/src/include/lpmd.h
+++ b/src/include/lpmd.h
@@ -108,7 +108,6 @@ typedef struct {
#define MAX_CONFIG_STATES 10
#define MAX_STATE_NAME 32
#define MAX_CONFIG_LEN 64
-#define MAX_CPUS 64
enum lpmd_states {
LPMD_OFF,
@@ -191,10 +190,6 @@ typedef struct {
int steady;
}lpmd_config_state_t;
-struct core_masks_t {
- unsigned char cmask[CORE_TYPES_COUNT][MAX_CPUS / 8];
-};
-
// lpmd config data
typedef struct {
int mode;
@@ -231,8 +226,6 @@ typedef struct {
int config_state_count;
int tdp;
- struct core_masks_t core_type_masks;
-
int balance_slider_def_ac;
int slider_offset_def_ac;
int balance_slider_def_dc;
@@ -240,6 +233,7 @@ typedef struct {
lpmd_config_state_t config_states[MAX_STATES];
lpmd_data_t data;
+ unsigned char *core_type_masks[CORE_TYPES_COUNT];
} lpmd_config_t;
enum lpm_cpu_process_mode {
@@ -392,9 +386,12 @@ int cpumask_alloc(void);
int cpumask_free(enum cpumask_idx idx);
int cpumask_reset(enum cpumask_idx idx);
+void free_cpu_type_masks(lpmd_config_t *lpmd_config);
+int allocate_cpu_type_masks(lpmd_config_t *lpmd_config);
+
int cpumask_add_cpu(int cpu, enum cpumask_idx idx);
int cpumask_init_cpus(char *buf, enum cpumask_idx idx);
-int cpumask_init_cpus_type(int count, enum cpumask_idx idx, struct core_masks_t *cmasks, enum core_type type);
+int cpumask_init_cpus_type(int count, enum cpumask_idx idx, unsigned char **cmasks, enum core_type type);
int cpumask_nr_cpus(enum cpumask_idx idx);
int cpumask_has_cpu(enum cpumask_idx idx);
diff --git a/src/lpmd_cpu.c b/src/lpmd_cpu.c
index d71ca6c..1930eab 100644
--- a/src/lpmd_cpu.c
+++ b/src/lpmd_cpu.c
@@ -313,6 +313,11 @@ int detect_cpu_topo(lpmd_config_t *lpmd_config)
if (ret)
return ret;
+ /* Allocate space for per-type cpu masks */
+ ret = allocate_cpu_type_masks(lpmd_config);
+ if (ret)
+ return ret;
+
cpumask_reset(CPUMASK_ONLINE);
pcores = ecores = lcores = 0;
@@ -341,22 +346,22 @@ int detect_cpu_topo(lpmd_config_t *lpmd_config)
/* Here it is the first time we migrate CPUs, must clear the previous cgroup settings */
cgroup_cleanup();
- memset(lpmd_config->core_type_masks.cmask[0], 0, CORE_TYPES_COUNT * MAX_CPUS / 8);
+ memset(lpmd_config->core_type_masks[0], 0, CORE_TYPES_COUNT * get_max_cpus() / 8);
for (i = 0; i < get_max_cpus(); i++) {
if (!is_cpu_online(i))
continue;
if (is_cpu_pcore(i)) {
pcores++;
- lpmd_config->core_type_masks.cmask[P_CORE][i / 8] |= 1 << (i % 8);
+ lpmd_config->core_type_masks[P_CORE][i / 8] |= 1 << (i % 8);
}
else if (is_cpu_ecore(i)) {
ecores++;
- lpmd_config->core_type_masks.cmask[E_CORE][i / 8] |= 1 << (i % 8);
+ lpmd_config->core_type_masks[E_CORE][i / 8] |= 1 << (i % 8);
}
else if (is_cpu_lcore(i)) {
lcores++;
- lpmd_config->core_type_masks.cmask[L_CORE][i / 8] |= 1 << (i % 8);
+ lpmd_config->core_type_masks[L_CORE][i / 8] |= 1 << (i % 8);
}
}
diff --git a/src/lpmd_cpumask.c b/src/lpmd_cpumask.c
index d110703..1dddd23 100644
--- a/src/lpmd_cpumask.c
+++ b/src/lpmd_cpumask.c
@@ -177,12 +177,32 @@ int cpumask_add_cpu(int cpu, enum cpumask_idx idx)
return LPMD_SUCCESS;
}
+void free_cpu_type_masks(lpmd_config_t *lpmd_config)
+{
+ int i;
+ for (i = 0 ; i < CORE_TYPES_COUNT ; i++)
+ free(lpmd_config->core_type_masks[i]);
+}
+
+int allocate_cpu_type_masks(lpmd_config_t *lpmd_config)
+{
+ int i;
+ for (i = 0 ; i < CORE_TYPES_COUNT ; i++) {
+ lpmd_config->core_type_masks[i] = malloc(get_max_cpus() / 8);
+ if (!lpmd_config->core_type_masks[i]) {
+ free_cpu_type_masks(lpmd_config);
+ return -1;
+ }
+ }
+ return 0;
+}
+
static unsigned int get_next_cpu_cmask(unsigned int id, enum core_type type, unsigned char *cmask)
{
bool ret;
int i;
- for (i = id ; i < MAX_CPUS ; i++) {
+ for (i = id ; i < get_max_cpus() ; i++) {
ret = !!(cmask[i / 8] & (1 << (i % 8)));
if (ret)
return i;
@@ -191,7 +211,7 @@ static unsigned int get_next_cpu_cmask(unsigned int id, enum core_type type, uns
}
-int cpumask_init_cpus_type(int count, enum cpumask_idx idx, struct core_masks_t *cmasks, enum core_type type)
+int cpumask_init_cpus_type(int count, enum cpumask_idx idx, unsigned char **cmasks, enum core_type type)
{
unsigned int current, next;
int nr_cpus = 0;
@@ -199,10 +219,10 @@ int cpumask_init_cpus_type(int count, enum cpumask_idx idx, struct core_masks_t
if (!count)
return 0;
- current = get_next_cpu_cmask(0, type, cmasks->cmask[type]);
+ current = get_next_cpu_cmask(0, type, cmasks[type]);
while(nr_cpus != count) {
cpumask_add_cpu(current, idx);
- next = get_next_cpu_cmask(current + 1, type, cmasks->cmask[type]);
+ next = get_next_cpu_cmask(current + 1, type, cmasks[type]);
if(next == current) /* Couldn't find next core of the provided type */
return nr_cpus;
nr_cpus++;
diff --git a/src/lpmd_proc.c b/src/lpmd_proc.c
index ad58c29..1c69af2 100644
--- a/src/lpmd_proc.c
+++ b/src/lpmd_proc.c
@@ -391,28 +391,28 @@ int lpmd_main(void)
ret = detect_cpu_topo(&lpmd_config);
if (ret)
- return ret;
+ goto cleanup;
// Call all lpmd related functions here
ret = lpmd_get_config (&lpmd_config);
if (ret)
- return ret;
+ goto cleanup;
pthread_mutex_init (&lpmd_mutex, NULL);
ret = detect_lpm_cpus(lpmd_config.lp_mode_cpus);
if (ret)
- return ret;
+ goto cleanup;
ret = cgroup_init(&lpmd_config);
if (ret)
- return ret;
+ goto cleanup;
itmt_init();
ret = epp_epb_init();
if (ret)
- return ret;
+ goto cleanup;
if (!has_hfi_capability ())
lpmd_config.hfi_lpm_enable = 0;
@@ -420,6 +420,9 @@ int lpmd_main(void)
/* Must done after init_cpu() */
lpmd_build_config_states(&lpmd_config);
+ /* Cleanup dynamically allocated core-type cpumasks */
+ free_cpu_type_masks(&lpmd_config);
+
ret = irq_init();
if (ret)
return ret;
@@ -514,4 +517,7 @@ int lpmd_main(void)
lpmd_log_debug ("lpmd_init succeeds\n");
return LPMD_SUCCESS;
+cleanup:
+ free_cpu_type_masks(&lpmd_config);
+ return ret;
}
diff --git a/src/lpmd_state_machine.c b/src/lpmd_state_machine.c
index 22fd997..a3b69c6 100644
--- a/src/lpmd_state_machine.c
+++ b/src/lpmd_state_machine.c
@@ -655,7 +655,7 @@ static int build_state_cpumask_activecpus(lpmd_config_state_t *state)
return 0;
}
-static int build_state_cpumask_cputypes(lpmd_config_state_t *state, struct core_masks_t *cmasks)
+static int build_state_cpumask_cputypes(lpmd_config_state_t *state, unsigned char **cmasks)
{
int ret;
@@ -706,7 +706,7 @@ int lpmd_build_config_states(lpmd_config_t *lpmd_config)
ret = build_state_cpumask_activecpus(state);
if (ret == -2)
- build_state_cpumask_cputypes(state, &lpmd_config->core_type_masks);
+ build_state_cpumask_cputypes(state, lpmd_config->core_type_masks);
else if (ret)
continue;
--
2.55.0

View File

@ -0,0 +1,173 @@
From f3bf1533d8e552e072ba6ce15cf7f217a6655cb8 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Tue, 16 Dec 2025 16:00:18 +0100
Subject: [PATCH 31/56] lpmd_config: ALL keyword for active P/E/L cores tag
Allow using the 'ALL' keyword to specify all cores of a given type when
using the ActivePcores/ActiveEcores/ActiveLcores tags.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
[srinivas: Fix coverity error for sizeof(dst_string)]
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
src/include/lpmd.h | 8 ++++----
src/lpmd_config.c | 22 +++++++++++++---------
src/lpmd_cpumask.c | 30 ++++++++++++++++++++++++------
src/lpmd_state_machine.c | 15 +++++++++------
4 files changed, 50 insertions(+), 25 deletions(-)
diff --git a/src/include/lpmd.h b/src/include/lpmd.h
index f35b46e..720c822 100644
--- a/src/include/lpmd.h
+++ b/src/include/lpmd.h
@@ -171,9 +171,9 @@ typedef struct {
char active_cpus[MAX_STR_LENGTH];
// If active CPUs are specified then
// the below counts don't matter
- int active_p_cores;
- int active_e_cores;
- int active_l_cores;
+ char active_p_cores[MAX_STR_LENGTH];
+ char active_e_cores[MAX_STR_LENGTH];
+ char active_l_cores[MAX_STR_LENGTH];
int itmt_state;
int irq_migrate;
@@ -391,7 +391,7 @@ int allocate_cpu_type_masks(lpmd_config_t *lpmd_config);
int cpumask_add_cpu(int cpu, enum cpumask_idx idx);
int cpumask_init_cpus(char *buf, enum cpumask_idx idx);
-int cpumask_init_cpus_type(int count, enum cpumask_idx idx, unsigned char **cmasks, enum core_type type);
+int cpumask_init_cpus_type(char * buf, enum cpumask_idx idx, unsigned char **cmasks, enum core_type type);
int cpumask_nr_cpus(enum cpumask_idx idx);
int cpumask_has_cpu(enum cpumask_idx idx);
diff --git a/src/lpmd_config.c b/src/lpmd_config.c
index 214f251..7c37375 100644
--- a/src/lpmd_config.c
+++ b/src/lpmd_config.c
@@ -25,6 +25,14 @@
#define CONFIG_FILE_NAME "intel_lpmd_config.xml"
#define MAX_FILE_NAME_PATH 128
+static void save_string_or_zero(char * tmp_value, char * dst_string, int dest_size)
+{
+ if (!strncmp (tmp_value, "-1", strlen ("-1")))
+ dst_string[0] = '\0';
+ else
+ copy_user_string(tmp_value, dst_string, dest_size);
+}
+
static void lpmd_parse_state(xmlDoc *doc, xmlNode *a_node, lpmd_config_t *config, int idx)
{
xmlNode *cur_node = NULL;
@@ -84,17 +92,13 @@ static void lpmd_parse_state(xmlDoc *doc, xmlNode *a_node, lpmd_config_t *config
if (!strncmp((const char*)cur_node->name, "IRQMigrate", strlen("IRQMigrate")))
state->irq_migrate = strtol (tmp_value, &pos, 10);
if (!strncmp((const char*)cur_node->name, "ActivePcores", strlen("ActivePcores")))
- state->active_p_cores = strtol (tmp_value, &pos, 10);
+ save_string_or_zero(tmp_value, state->active_p_cores, sizeof(state->active_p_cores));
if (!strncmp((const char*)cur_node->name, "ActiveEcores", strlen("ActiveEcores")))
- state->active_e_cores = strtol (tmp_value, &pos, 10);
+ save_string_or_zero(tmp_value, state->active_e_cores, sizeof(state->active_e_cores));
if (!strncmp((const char*)cur_node->name, "ActiveLcores", strlen("ActiveLcores")))
- state->active_l_cores = strtol (tmp_value, &pos, 10);
- if (!strncmp((const char*)cur_node->name, "ActiveCPUs", strlen("ActiveCPUs"))) {
- if (!strncmp (tmp_value, "-1", strlen ("-1")))
- state->active_cpus[0] = '\0';
- else
- copy_user_string(tmp_value, state->active_cpus, sizeof(state->active_cpus));
- }
+ save_string_or_zero(tmp_value, state->active_l_cores, sizeof(state->active_l_cores));
+ if (!strncmp((const char*)cur_node->name, "ActiveCPUs", strlen("ActiveCPUs")))
+ save_string_or_zero(tmp_value, state->active_cpus, sizeof(state->active_cpus));
if (!strncmp((const char*)cur_node->name, "BalanceSliderAC", strlen("BalanceSliderAC")))
state->balance_slider_ac = strtol (tmp_value, &pos, 10);
if (!strncmp((const char*)cur_node->name, "SliderOffsetAC", strlen("SliderOffsetAC")))
diff --git a/src/lpmd_cpumask.c b/src/lpmd_cpumask.c
index 1dddd23..9d41931 100644
--- a/src/lpmd_cpumask.c
+++ b/src/lpmd_cpumask.c
@@ -197,6 +197,18 @@ int allocate_cpu_type_masks(lpmd_config_t *lpmd_config)
return 0;
}
+static unsigned int count_cpu_type_cores(unsigned char * bitmask)
+{
+ unsigned int count = 0;
+ int i;
+
+ for (i = 0 ; i < get_max_cpus() ; i++) {
+ if (!!(bitmask[i / 8] & (1 << (i % 8))))
+ count++;
+ }
+ return count;
+}
+
static unsigned int get_next_cpu_cmask(unsigned int id, enum core_type type, unsigned char *cmask)
{
bool ret;
@@ -210,14 +222,20 @@ static unsigned int get_next_cpu_cmask(unsigned int id, enum core_type type, uns
return id;
}
-
-int cpumask_init_cpus_type(int count, enum cpumask_idx idx, unsigned char **cmasks, enum core_type type)
+int cpumask_init_cpus_type(char * buf, enum cpumask_idx idx, unsigned char **cmasks, enum core_type type)
{
- unsigned int current, next;
+ unsigned int current, next, count;
int nr_cpus = 0;
-
- if (!count)
- return 0;
+ char * end;
+
+ if (!strncmp(buf, "ALL", strlen("ALL")) || !strncmp(buf, "all", strlen("all")))
+ count = count_cpu_type_cores(cmasks[type]);
+ else {
+ errno = 0;
+ count = strtol(buf, &end, 10);
+ if (errno || *end != '\0' || !count)
+ return 0;
+ }
current = get_next_cpu_cmask(0, type, cmasks[type]);
while(nr_cpus != count) {
diff --git a/src/lpmd_state_machine.c b/src/lpmd_state_machine.c
index a3b69c6..15216c5 100644
--- a/src/lpmd_state_machine.c
+++ b/src/lpmd_state_machine.c
@@ -109,9 +109,9 @@ int lpmd_init_config_state(lpmd_config_state_t *state)
state->active_cpus[0] = '\0';
state->cpumask_idx = CPUMASK_NONE;
- state->active_p_cores = 0;
- state->active_e_cores = 0;
- state->active_l_cores = 0;
+ state->active_p_cores[0] = '\0';
+ state->active_e_cores[0] = '\0';
+ state->active_l_cores[0] = '\0';
state->itmt_state = SETTING_IGNORE;
state->irq_migrate = SETTING_IGNORE;
@@ -473,10 +473,13 @@ static void dump_states(lpmd_config_t *lpmd_config)
lpmd_log_info ("\tIRQMigrate:%d\n", state->irq_migrate);
if (state->active_cpus[0] != '\0')
lpmd_log_info ("\tactive_cpus:%s\n", state->active_cpus);
+ if (state->active_p_cores[0] != '\0')
+ lpmd_log_info ("\tactive_p_cores:%s\n", state->active_p_cores);
+ if (state->active_e_cores[0] != '\0')
+ lpmd_log_info ("\tactive_e_cores:%s\n", state->active_e_cores);
+ if (state->active_l_cores[0] != '\0')
+ lpmd_log_info ("\tactive_l_cores:%s\n", state->active_l_cores);
lpmd_log_info ("\tCPUMASK idx:%d\n", state->cpumask_idx);
- lpmd_log_info ("\tactive_p_cores:%d\n", state->active_p_cores);
- lpmd_log_info ("\tactive_e_cores:%d\n", state->active_e_cores);
- lpmd_log_info ("\tactive_l_cores:%d\n", state->active_l_cores);
lpmd_log_info ("\tBalancedSliderAC:%d\n", state->balance_slider_ac);
lpmd_log_info ("\tBalancedSliderDC:%d\n", state->balance_slider_dc);
lpmd_log_info ("\tSliderOffsetAC:%d\n", state->slider_offset_ac);
--
2.55.0

View File

@ -0,0 +1,74 @@
From d5438618f4f700f78bbf75371ca2d7fc9a2ec631 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Mon, 15 Dec 2025 16:16:38 +0100
Subject: [PATCH 32/56] config: Simplify the M204 configuration
Using the new mechanism for adding only cores of a specified type
simplify the PTL configuration file to avoid hardcoding core index
ranges.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
data/intel_lpmd_config_F6_M204.xml | 32 ++++--------------------------
1 file changed, 4 insertions(+), 28 deletions(-)
diff --git a/data/intel_lpmd_config_F6_M204.xml b/data/intel_lpmd_config_F6_M204.xml
index f1e36da..9029f13 100644
--- a/data/intel_lpmd_config_F6_M204.xml
+++ b/data/intel_lpmd_config_F6_M204.xml
@@ -141,48 +141,24 @@ for Intel Energy Optimizer (LPMD) daemon
<States>
<CPUFamily> 6 </CPUFamily>
<CPUModel> 204 </CPUModel>
- <CPUConfig> 4P8E4L-25W </CPUConfig>
+ <CPUConfig> * </CPUConfig>
<State>
<ID> 1 </ID>
<Name> UTIL_IDLE </Name>
<WLTType> 1 </WLTType>
- <ActiveCPUs>12-15</ActiveCPUs>
+ <ActiveLcores>ALL</ActiveLcores>
</State>
<State>
<ID> 2 </ID>
<Name> UTIL_IDLE_SUSTAIN </Name>
<WLTType> 2 </WLTType>
- <ActiveCPUs>0-15</ActiveCPUs>
+ <ActiveCpus> * </ActiveCpus>
</State>
<State>
<ID> 3 </ID>
<Name> UTIL_IDLE_BURSTY </Name>
<WLTType> 3 </WLTType>
- <ActiveCPUs>0-15</ActiveCPUs>
- </State>
- </States>
-
- <States>
- <CPUFamily> 6 </CPUFamily>
- <CPUModel> 204 </CPUModel>
- <CPUConfig> 4P4E4L-25W </CPUConfig>
- <State>
- <ID> 1 </ID>
- <Name> UTIL_IDLE </Name>
- <WLTType> 1 </WLTType>
- <ActiveCPUs>8-11</ActiveCPUs>
- </State>
- <State>
- <ID> 2 </ID>
- <Name> UTIL_IDLE_SUSTAIN </Name>
- <WLTType> 2 </WLTType>
- <ActiveCPUs>0-11</ActiveCPUs>
- </State>
- <State>
- <ID> 3 </ID>
- <Name> UTIL_IDLE_BURSTY </Name>
- <WLTType> 3 </WLTType>
- <ActiveCPUs>0-11</ActiveCPUs>
+ <ActiveCpus> * </ActiveCpus>
</State>
</States>
--
2.55.0

View File

@ -0,0 +1,36 @@
From a9906b1c75cad102c08fa7c6652e1f8f0b91ef65 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Fri, 9 Jan 2026 11:45:16 +0100
Subject: [PATCH 33/56] lpmd_cpu: Fix incorrect struct initialization
Per cpu type bitmasks are allocated dynamically and therefore need to
have each pointer separately zeroed out for proper operation.
Previous version of zeroing all bitmasks with one memset worked
only for statically allocated bitmasks. Every other execution some data
would be left over in the bitmasks and an incorrect value would be
displayed.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/lpmd_cpu.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/lpmd_cpu.c b/src/lpmd_cpu.c
index 1930eab..e57b672 100644
--- a/src/lpmd_cpu.c
+++ b/src/lpmd_cpu.c
@@ -346,7 +346,9 @@ int detect_cpu_topo(lpmd_config_t *lpmd_config)
/* Here it is the first time we migrate CPUs, must clear the previous cgroup settings */
cgroup_cleanup();
- memset(lpmd_config->core_type_masks[0], 0, CORE_TYPES_COUNT * get_max_cpus() / 8);
+ for (i = 0 ; i < CORE_TYPES_COUNT ; i++) {
+ memset(lpmd_config->core_type_masks[i], 0, get_max_cpus() / 8);
+ }
for (i = 0; i < get_max_cpus(); i++) {
if (!is_cpu_online(i))
--
2.55.0

View File

@ -0,0 +1,224 @@
From 14c1b59eb5687477f6f4b1e06987c5ba1b150393 Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Tue, 14 Apr 2026 16:50:16 -0700
Subject: [PATCH 34/56] Introduce WLT state mask and notification delay
Notification Delay:
Set user configurable
/sys/bus/pci/devices/0000\:00\:04.0/workload_hint/notification_delay_ms
On some SoCs the default delay of 100ms causes too many interrupts.
WLT state mask
Each state using WLT can use a mask of WLTs instead of one value.
This allows one state for multiple WLT values, which doesn't need any
special config. This way state tranistion can be avoided.
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
man/intel_lpmd_config.xml.5 | 7 +++++++
src/include/lpmd.h | 3 +++
src/lpmd_config.c | 11 ++++++++++-
src/lpmd_proc.c | 5 +++++
src/lpmd_state_machine.c | 15 ++++++++++++++-
src/lpmd_wlt.c | 22 ++++++++++++++++++++++
6 files changed, 61 insertions(+), 2 deletions(-)
diff --git a/man/intel_lpmd_config.xml.5 b/man/intel_lpmd_config.xml.5
index e6bea7c..013448e 100644
--- a/man/intel_lpmd_config.xml.5
+++ b/man/intel_lpmd_config.xml.5
@@ -77,6 +77,8 @@ specifies if the HFI monitor can capture the HFI hints for survivability mode.
.PP
.B WLTHintEnable
Enable use of hardware Workload type hints.
+.B WLTHintNotificationDelay
+Set hardware workload notification delay in milliseconds.
.PP
.B WLTProxyEnable
Enable use of Proxy Workload type hints.
@@ -147,6 +149,11 @@ Workload type value to enter into this state. If this value is defined
then utilization based entry triggers are not used. To use this
WLTHintEnable must be enabled, so that hardware notifications are enabled.
.PP
+.B WLTTypeMask
+Mask of workload type values to enter into this state. This has higher priority
+than WLTType. If this value is defined then utilization based entry triggers
+are not used.
+.PP
.B ActiveCPUs
Active CPUs in this state. The list can be comma separated or use "-" for
a range. This is optional to have active CPUs in a state.
diff --git a/src/include/lpmd.h b/src/include/lpmd.h
index 720c822..f13fcb8 100644
--- a/src/include/lpmd.h
+++ b/src/include/lpmd.h
@@ -156,6 +156,7 @@ typedef struct {
int valid;
char name[MAX_STATE_NAME];
int wlt_type;
+ int wlt_type_mask;
int entry_system_load_thres;
int exit_system_load_thres;
int exit_system_load_hyst;
@@ -198,6 +199,7 @@ typedef struct {
int powersaver_def;
int hfi_lpm_enable;
int wlt_hint_enable;
+ int wlt_notification_delay;
int wlt_hint_poll_enable;
int wlt_proxy_enable;
int wlt_hint_mask;
@@ -338,6 +340,7 @@ int hfi_update(void);
int wlt_init(void);
int wlt_exit(void);
int wlt_update(int fd);
+int wlt_set_notification_delay(int delay);
/* lpmd_misc.c */
void itmt_init(void);
diff --git a/src/lpmd_config.c b/src/lpmd_config.c
index 7c37375..b459651 100644
--- a/src/lpmd_config.c
+++ b/src/lpmd_config.c
@@ -61,7 +61,9 @@ static void lpmd_parse_state(xmlDoc *doc, xmlNode *a_node, lpmd_config_t *config
snprintf(state->name, MAX_STATE_NAME - 1, "%s", tmp_value);
state->name[MAX_STATE_NAME - 1] = '\0';
}
- if (!strncmp((const char*)cur_node->name, "WLTType", strlen("WLTType")))
+ if (!strncmp((const char*)cur_node->name, "WLTTypeMask", strlen("WLTTypeMask")))
+ state->wlt_type_mask = strtol (tmp_value, &pos, 10);
+ else if (!strncmp((const char*)cur_node->name, "WLTType", strlen("WLTType")))
state->wlt_type = strtol (tmp_value, &pos, 10);
if (!strncmp((const char*)cur_node->name, "EntrySystemLoadThres", strlen("EntrySystemLoadThres")))
state->entry_system_load_thres = strtol (tmp_value, &pos, 10);
@@ -207,6 +209,7 @@ static void lpmd_init_config(lpmd_config_t *config)
config->slider_offset_def_ac = -1;
config->slider_offset_def_dc = -1;
config->wlt_hint_mask = -1;
+ config->wlt_notification_delay = -1;
}
static int lpmd_fill_config(xmlDoc *doc, xmlNode *a_node, lpmd_config_t *lpmd_config)
@@ -245,6 +248,12 @@ static int lpmd_fill_config(xmlDoc *doc, xmlNode *a_node, lpmd_config_t *lpmd_co
|| (lpmd_config->wlt_hint_enable != 1 && lpmd_config->wlt_hint_enable != 0))
goto err;
}
+ else if (!strncmp((const char*)cur_node->name, "WLTHintNotificationDelay", strlen("WLTHintNotificationDelay"))) {
+ errno = 0;
+ lpmd_config->wlt_notification_delay = strtol (tmp_value, &pos, 10);
+ if (errno || *pos != '\0' || lpmd_config->wlt_notification_delay < 0)
+ goto err;
+ }
else if (!strncmp((const char*)cur_node->name, "WLTHintMask", strlen("WLTHintMask"))) {
errno = 0;
lpmd_config->wlt_hint_mask = strtol (tmp_value, &pos, 10);
diff --git a/src/lpmd_proc.c b/src/lpmd_proc.c
index 1c69af2..91d1d15 100644
--- a/src/lpmd_proc.c
+++ b/src/lpmd_proc.c
@@ -493,6 +493,11 @@ int lpmd_main(void)
}
}
}
+ if (lpmd_config.wlt_notification_delay != -1) {
+ if (wlt_set_notification_delay(lpmd_config.wlt_notification_delay) != LPMD_SUCCESS) {
+ lpmd_log_error ("Error setting WLT notification delay. wlt_notification_delay set to default value\n");
+ }
+ }
}
pthread_attr_init (&lpmd_attr);
diff --git a/src/lpmd_state_machine.c b/src/lpmd_state_machine.c
index 15216c5..593de9e 100644
--- a/src/lpmd_state_machine.c
+++ b/src/lpmd_state_machine.c
@@ -91,6 +91,7 @@ int lpmd_init_config_state(lpmd_config_state_t *state)
state->name[0] = '\0';
state->wlt_type = -1;
+ state->wlt_type_mask = -1;
state->entry_system_load_thres = 0;
state->exit_system_load_thres = 0;
@@ -141,6 +142,13 @@ static int config_state_match(lpmd_config_t *config, int idx)
if (!state->valid)
return 0;
+ if (state->wlt_type_mask != -1) {
+ if (config->wlt_hint_mask != -1)
+ wlt_index &= config->wlt_hint_mask;
+
+ if (!(state->wlt_type_mask & (1 << wlt_index)))
+ return 0;
+ }
if (state->wlt_type != -1) {
if (config->wlt_hint_mask != -1)
wlt_index &= config->wlt_hint_mask;
@@ -221,6 +229,9 @@ static void dump_state(lpmd_config_state_t *state, char *str, int debug)
if (state->wlt_type)
offset += snprintf(buf + offset , MAX_STR_LENGTH - offset, "WLT [%2d] ", state->wlt_type);
+ if (state->wlt_type_mask)
+ offset += snprintf(buf + offset , MAX_STR_LENGTH - offset, "WLTMASK [%2d] ", state->wlt_type_mask);
+
if (state->entry_system_load_thres)
offset += snprintf(buf + offset , MAX_STR_LENGTH - offset, "SYS [%6d] ", state->entry_system_load_thres / 100);
@@ -431,6 +442,7 @@ static void dump_states(lpmd_config_t *lpmd_config)
lpmd_log_info ("Mode:%d\n", lpmd_config->mode);
lpmd_log_info ("HFI LPM Enable:%d\n", lpmd_config->hfi_lpm_enable);
lpmd_log_info ("WLT Hint Enable:%d\n", lpmd_config->wlt_hint_enable);
+ lpmd_log_info ("WLT Hint Notification Delay:%d\n", lpmd_config->wlt_notification_delay);
lpmd_log_info ("WLT Proxy Enable:%d\n", lpmd_config->wlt_proxy_enable);
lpmd_log_info ("WLT Proxy Enable:%d\n", lpmd_config->wlt_hint_poll_enable);
lpmd_log_info ("WLT Hint mask:%d\n", lpmd_config->wlt_hint_mask);
@@ -464,6 +476,7 @@ static void dump_states(lpmd_config_t *lpmd_config)
lpmd_log_info ("\tentry_gfx_load_thres:%d\n", state->enter_gfx_load_thres);
lpmd_log_info ("\texit_gfx_load_thres:%d\n", state->exit_gfx_load_thres);
lpmd_log_info ("\tWLT Type:%d\n", state->wlt_type);
+ lpmd_log_info ("\tWLT Type Mask:%d\n", state->wlt_type_mask);
lpmd_log_info ("\tmin_poll_interval:%d\n", state->min_poll_interval);
lpmd_log_info ("\tmax_poll_interval:%d\n", state->max_poll_interval);
lpmd_log_info ("\tpoll_interval_increment:%d\n", state->poll_interval_increment);
@@ -594,7 +607,7 @@ static int config_states_update_config(lpmd_config_t *config)
if (state->cpumask_idx == CPUMASK_HFI)
config->hfi_lpm_enable = 1;
- if (state->wlt_type != -1)
+ if (state->wlt_type != -1 || state->wlt_type_mask != -1)
config->wlt_hint_enable = 1;
if (state->entry_system_load_thres)
diff --git a/src/lpmd_wlt.c b/src/lpmd_wlt.c
index 4592772..d44a895 100644
--- a/src/lpmd_wlt.c
+++ b/src/lpmd_wlt.c
@@ -120,3 +120,25 @@ int wlt_init (void)
return fd;
}
+
+int wlt_set_notification_delay(int delay)
+{
+ char delay_str[64];
+ int fd;
+
+ // Set notification delay
+ fd = open(WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE, O_RDWR);
+ if (fd < 0)
+ return -1;
+
+ snprintf(delay_str, sizeof(delay_str), "%d\n", delay);
+
+ if (write(fd, delay_str, strlen(delay_str)) < 0) {
+ close(fd);
+ return -1;
+ }
+
+ close(fd);
+
+ return 0;
+}
--
2.55.0

View File

@ -0,0 +1,217 @@
From 684ad19d34a385a41a92f352db8c074eb42d5e4e Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Thu, 8 Jan 2026 16:52:30 +0100
Subject: [PATCH 35/56] Arrow Lake enabling
Add Arrow Lake U config file and CPU model (181) to the supported CPU model
table.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
data/Makefile.am | 1 +
data/intel_lpmd_config_F6_M181.xml | 168 +++++++++++++++++++++++++++++
src/lpmd_cpu.c | 1 +
3 files changed, 170 insertions(+)
create mode 100644 data/intel_lpmd_config_F6_M181.xml
diff --git a/data/Makefile.am b/data/Makefile.am
index 935cc55..a67bfde 100644
--- a/data/Makefile.am
+++ b/data/Makefile.am
@@ -30,6 +30,7 @@ lpmd_configdir = $(lpmd_confdir)
lpmd_config_DATA = \
intel_lpmd_config.xml \
intel_lpmd_config_F6_M170.xml \
+ intel_lpmd_config_F6_M181.xml \
intel_lpmd_config_F6_M189.xml \
intel_lpmd_config_F6_M204.xml
diff --git a/data/intel_lpmd_config_F6_M181.xml b/data/intel_lpmd_config_F6_M181.xml
new file mode 100644
index 0000000..d39cf0d
--- /dev/null
+++ b/data/intel_lpmd_config_F6_M181.xml
@@ -0,0 +1,168 @@
+<?xml version="1.0"?>
+
+<!--
+Specifies the configuration data
+for Intel Energy Optimizer (LPMD) daemon
+-->
+
+<Configuration>
+ <!--
+ CPU format example: 1,2,4..6,8-10
+ -->
+ <lp_mode_cpus></lp_mode_cpus>
+
+ <!--
+ EPP to use in Low Power Mode
+ 0-255: Valid EPP value to use in Low Power Mode
+ -1: Don't change EPP in Low Power Mode
+ -->
+ <lp_mode_epp></lp_mode_epp>
+
+ <!--
+ Mode values
+ 0: Cgroup v2
+ 1: Cgroup v2 isolate
+ 2: CPU idle injection
+ -->
+ <Mode>0</Mode>
+
+ <!--
+ Default behavior when Performance power setting is used
+ -1: force off. (Never enter Low Power Mode)
+ 1: force on. (Always stay in Low Power Mode)
+ 0: auto. (opportunistic Low Power Mode enter/exit)
+ -->
+ <PerformanceDef>-1</PerformanceDef>
+
+ <!--
+ Default behavior when Balanced power setting is used
+ -1: force off. (Never enter Low Power Mode)
+ 1: force on. (Always stay in Low Power Mode)
+ 0: auto. (opportunistic Low Power Mode enter/exit)
+ -->
+ <BalancedDef>-1</BalancedDef>
+
+ <!--
+ Default behavior when Power saver setting is used
+ -1: force off. (Never enter Low Power Mode)
+ 1: force on. (Always stay in Low Power Mode)
+ 0: auto. (opportunistic Low Power Mode enter/exit)
+ -->
+ <PowersaverDef>-1</PowersaverDef>
+
+ <!--
+ Use HFI LPM hints
+ 0 : No
+ 1 : Yes
+ -->
+ <HfiLpmEnable>0</HfiLpmEnable>
+
+ <!--
+ Use WLT hints
+ 0 : No
+ 1 : Yes
+ -->
+ <WLTHintEnable>1</WLTHintEnable>
+
+ <!--
+ Use WLT Notification delay in milliseconds
+ -1 : default (100 ms)
+ -->
+ <WLTHintNotificationDelay>1024</WLTHintNotificationDelay>
+
+ <!--
+ Use WLT hint Poll enable
+ 0 : No
+ 1 : Yes
+ -->
+ <WLTHintPollEnable>0</WLTHintPollEnable>
+
+ <!--
+ Use HFI SUV hints
+ 0 : No
+ 1 : Yes
+ -->
+ <HfiSuvEnable>0</HfiSuvEnable>
+
+ <!--
+ System utilization threshold to enter LP mode
+ from 0 - 100
+ clear both util_entry_threshold and util_exit_threshold to disable util monitor
+ -->
+ <util_entry_threshold>10</util_entry_threshold>
+
+ <!--
+ System utilization threshold to exit LP mode
+ from 0 - 100
+ clear both util_entry_threshold and util_exit_threshold to disable util monitor
+ -->
+ <util_exit_threshold>95</util_exit_threshold>
+
+ <!--
+ Entry delay. Minimum delay in non Low Power mode to
+ enter LPM mode.
+ -->
+ <EntryDelayMS>0</EntryDelayMS>
+
+ <!--
+ Exit delay. Minimum delay in Low Power mode to
+ exit LPM mode.
+ -->
+ <ExitDelayMS>0</ExitDelayMS>
+
+ <!--
+ Lowest hysteresis average in-LP-mode time in msec to enter LP mode
+ 0: to disable hysteresis support
+ -->
+ <EntryHystMS>0</EntryHystMS>
+
+ <!--
+ Lowest hysteresis average out-of-LP-mode time in msec to exit LP mode
+ 0: to disable hysteresis support
+ -->
+ <ExitHystMS>0</ExitHystMS>
+
+ <!--
+ Ignore ITMT setting during LP-mode enter/exit
+ 0: disable ITMT upon LP-mode enter and re-enable ITMT upon LP-mode exit
+ 1: do not touch ITMT setting during LP-mode enter/exit
+ -->
+ <IgnoreITMT>0</IgnoreITMT>
+
+ <!--
+ Example WorkLoad Type hints based config states applied to
+ 4P-8E-2Lcore 15W TDP Arrow Lake platform.
+ Need to set WLTHintEnable to make it work.
+ -->
+ <States>
+ <CPUFamily> 6 </CPUFamily>
+ <CPUModel> 181 </CPUModel>
+ <CPUConfig> * </CPUConfig>
+ <State>
+ <ID> 1 </ID>
+ <Name> UTIL_BL </Name>
+ <WLTTypeMask> 3 </WLTTypeMask>
+ <EPP> 128 </EPP>
+ <EPB> 6 </EPB>
+ <IRQMigrate> 1 </IRQMigrate>
+ <ActiveLcores>ALL</ActiveLcores>
+ <ActiveEcores>ALL</ActiveEcores>
+ </State>
+ <State>
+ <ID> 2 </ID>
+ <Name> UTIL_IDLE_SUSTAIN </Name>
+ <WLTType> 2 </WLTType>
+ <EPP> 64 </EPP>
+ <EPB> 4 </EPB>
+ <ActiveCPUs> * </ActiveCPUs>
+ </State>
+ <State>
+ <ID> 3 </ID>
+ <Name> UTIL_IDLE_BURSTY </Name>
+ <WLTType> 3 </WLTType>
+ <EPP> 128 </EPP>
+ <EPB> 6 </EPB>
+ <ActiveCPUs> * </ActiveCPUs>
+ </State>
+ </States>
+</Configuration>
diff --git a/src/lpmd_cpu.c b/src/lpmd_cpu.c
index e57b672..4eb1ab6 100644
--- a/src/lpmd_cpu.c
+++ b/src/lpmd_cpu.c
@@ -40,6 +40,7 @@ static struct cpu_model_entry id_table[] = {
{ 6, 0xbf }, // Raptorlake S
{ 6, 0xaa }, // Meteorlake
{ 6, 0xac }, // Meteorlake
+ { 6, 0xb5 }, // ArrowLake
{ 6, 0xbd }, // Lunarlake
{ 6, 0xcc }, // Pantherlake
{ 0, 0 } // Last Invalid entry
--
2.55.0

View File

@ -0,0 +1,230 @@
From 3d269dadacc56e4db587dad6f4299ad72c247fee Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Wed, 17 Dec 2025 20:24:10 +0100
Subject: [PATCH 36/56] lpmd_config: Skip platform check if a matching config
file exists
A platform that's not added to the model list in the source code is
discarded early when launching the program.
For easier scaling it's beneficial to accept platforms that have a
matching configuration file in the appropriate directory.
Skip matching the platform model to the source code defined list of
supported models if a matching config file exists.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
[srinivas: Fix coverity error for uninitialized file_name]
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
src/include/lpmd.h | 4 ++++
src/lpmd_config.c | 60 ++++++++++++++++++++++++++++++++++++----------
src/lpmd_cpu.c | 27 +++++++++++++++------
3 files changed, 71 insertions(+), 20 deletions(-)
diff --git a/src/include/lpmd.h b/src/include/lpmd.h
index f13fcb8..cf9a4fd 100644
--- a/src/include/lpmd.h
+++ b/src/include/lpmd.h
@@ -105,6 +105,7 @@ typedef struct {
} message_capsul_t;
#define MAX_STR_LENGTH 256
+#define MAX_FILE_NAME_PATH 128
#define MAX_CONFIG_STATES 10
#define MAX_STATE_NAME 32
#define MAX_CONFIG_LEN 64
@@ -227,6 +228,7 @@ typedef struct {
char cpu_config[MAX_CONFIG_LEN];
int config_state_count;
int tdp;
+ char file_name[MAX_FILE_NAME_PATH];
int balance_slider_def_ac;
int slider_offset_def_ac;
@@ -319,6 +321,7 @@ void update_reason(int reason);
int intel_dbus_server_init(gboolean (*exit_handler)(void));
/* lpmd_config.c */
+int match_config_file(int family, int model, int tdp, char *save_file_name);
int lpmd_get_config(lpmd_config_t *lpmd_config);
/* lpmd_state_machine.c */
@@ -372,6 +375,7 @@ int check_cpu_hotplug(void);
int detect_supported_platform(lpmd_config_t *lpmd_config);
int detect_cpu_topo(lpmd_config_t *lpmd_config);
int detect_lpm_cpus(char *cmd_cpus);
+int get_tdp(void);
int is_cpu_ecore(int cpu);
int is_cpu_pcore(int cpu);
diff --git a/src/lpmd_config.c b/src/lpmd_config.c
index b459651..f9179cb 100644
--- a/src/lpmd_config.c
+++ b/src/lpmd_config.c
@@ -23,7 +23,6 @@
#include <libxml/tree.h>
#define CONFIG_FILE_NAME "intel_lpmd_config.xml"
-#define MAX_FILE_NAME_PATH 128
static void save_string_or_zero(char * tmp_value, char * dst_string, int dest_size)
{
@@ -428,31 +427,64 @@ err: xmlFree (tmp_value);
return LPMD_SUCCESS;
}
-int lpmd_get_config(lpmd_config_t *lpmd_config)
+int match_config_file(int family, int model, int tdp, char *save_file_name)
{
char file_name[MAX_FILE_NAME_PATH];
+ struct stat s;
+ int ret;
+
+ snprintf(file_name, MAX_FILE_NAME_PATH,
+ "%s/intel_lpmd_config_F%d_M%d_T%d.xml", TDCONFDIR, family,
+ model, tdp);
+
+ lpmd_log_msg ("Looking for config file %s\n", file_name);
+ ret = stat (file_name, &s);
+ if (!ret) {
+ strncpy(save_file_name, file_name, MAX_FILE_NAME_PATH);
+ return ret;
+ }
+
+ snprintf(file_name, MAX_FILE_NAME_PATH,
+ "%s/intel_lpmd_config_F%d_M%d.xml", TDCONFDIR, family, model);
+
+ lpmd_log_msg("Looking for config file %s\n", file_name);
+
+ ret = stat(file_name, &s);
+ if (!ret) {
+ strncpy(save_file_name, file_name, MAX_FILE_NAME_PATH);
+ return ret;
+ }
+
+ return ret;
+}
+
+int lpmd_get_config(lpmd_config_t *lpmd_config)
+{
+ char file_name_str[MAX_FILE_NAME_PATH];
xmlNode *root_element;
xmlNode *cur_node;
+ char *file_name;
struct stat s;
xmlDoc *doc;
if (!lpmd_config)
return LPMD_ERROR;
-
- snprintf(file_name, MAX_FILE_NAME_PATH, "%s/intel_lpmd_config_F%d_M%d_T%d.xml",
- TDCONFDIR, lpmd_config->cpu_family, lpmd_config->cpu_model, lpmd_config->tdp);
-
- lpmd_log_msg ("Looking for config file %s\n", file_name);
- if (!stat (file_name, &s))
+ /*
+ * If a config file was already found skip looking for it the second
+ * time.
+ */
+ if (strcmp(lpmd_config->file_name, "")) {
+ file_name = lpmd_config->file_name;
goto process_xml;
+ }
- snprintf(file_name, MAX_FILE_NAME_PATH, "%s/intel_lpmd_config_F%d_M%d.xml",
- TDCONFDIR, lpmd_config->cpu_family, lpmd_config->cpu_model);
- lpmd_log_msg ("Looking for config file %s\n", file_name);
- if (!stat (file_name, &s))
- goto process_xml;
+ file_name = file_name_str;
+ /*
+ * If a model specific config file was not found use the generic
+ * config file.
+ */
snprintf (file_name, MAX_FILE_NAME_PATH, "%s/%s", TDCONFDIR, CONFIG_FILE_NAME);
lpmd_log_msg ("Reading configuration file %s\n", file_name);
@@ -462,6 +494,8 @@ int lpmd_get_config(lpmd_config_t *lpmd_config)
return LPMD_ERROR;
}
+ strncpy(lpmd_config->file_name, file_name, MAX_FILE_NAME_PATH - 1);
+
process_xml:
doc = xmlReadFile (file_name, NULL, 0);
if (doc == NULL) {
diff --git a/src/lpmd_cpu.c b/src/lpmd_cpu.c
index 4eb1ab6..bb3ecd3 100644
--- a/src/lpmd_cpu.c
+++ b/src/lpmd_cpu.c
@@ -49,7 +49,8 @@ static struct cpu_model_entry id_table[] = {
int detect_supported_platform(lpmd_config_t *lpmd_config)
{
unsigned int eax, ebx, ecx, edx;
- unsigned int max_level, family, model, stepping;
+ unsigned int max_level, family, model, stepping, tdp;
+ char file_name[MAX_FILE_NAME_PATH] = "\0";
int val;
cpuid(0, eax, ebx, ecx, edx);
@@ -69,9 +70,16 @@ int detect_supported_platform(lpmd_config_t *lpmd_config)
if (family == 6)
model += ((eax >> 16) & 0xf) << 4;
+ tdp = get_tdp();
+
lpmd_log_info("%u CPUID levels; family:model:stepping 0x%x:%x:%x (%u:%u:%u)\n",
max_level, family, model, stepping, family, model, stepping);
+ if (!match_config_file(family, model, tdp, file_name)) {
+ lpmd_log_info("Found a config file matching the platform model - skipping platform check\n");
+ goto end;
+ }
+
if (!do_platform_check()) {
lpmd_log_info("Ignore platform check\n");
goto end;
@@ -125,6 +133,11 @@ int detect_supported_platform(lpmd_config_t *lpmd_config)
end:
lpmd_config->cpu_family = family;
lpmd_config->cpu_model = model;
+ lpmd_config->tdp = tdp;
+ if (file_name[0] != '\0')
+ strncpy(lpmd_config->file_name, file_name, MAX_FILE_NAME_PATH);
+ else
+ lpmd_config->file_name[0] = '\0';
return 0;
}
@@ -206,7 +219,7 @@ int is_cpu_lcore(int cpu)
}
#define PATH_RAPL "/sys/class/powercap"
-static int get_tdp(void)
+int get_tdp(void)
{
FILE *filep;
DIR *dir;
@@ -368,11 +381,11 @@ int detect_cpu_topo(lpmd_config_t *lpmd_config)
}
}
- tdp = get_tdp();
- lpmd_log_info("Detected %d Pcores, %d Ecores, %d Lcores, TDP %dW\n", pcores, ecores, lcores, tdp);
- ret = snprintf(lpmd_config->cpu_config, MAX_CONFIG_LEN - 1, " %dP%dE%dL-%dW ", pcores, ecores, lcores, tdp);
-
- lpmd_config->tdp = tdp;
+ lpmd_log_info("Detected %d Pcores, %d Ecores, %d Lcores, TDP %dW\n",
+ pcores, ecores, lcores, lpmd_config->tdp);
+ ret = snprintf(lpmd_config->cpu_config, MAX_CONFIG_LEN - 1,
+ " %dP%dE%dL-%dW ", pcores, ecores, lcores,
+ lpmd_config->tdp);
return 0;
}
--
2.55.0

View File

@ -0,0 +1,189 @@
From 7789bdfed92fe2eae62bb50a7fcdc33d43300c55 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Thu, 29 Jan 2026 21:08:19 +0100
Subject: [PATCH 37/56] config: Nova Lake enabling
Add the Nova Lake config file. With the recent addition of config file
based model matching, installing this file is enough to enable LPMD on
the Nova Lake platform.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
data/intel_lpmd_config_F18_M1.xml | 165 ++++++++++++++++++++++++++++++
1 file changed, 165 insertions(+)
create mode 100644 data/intel_lpmd_config_F18_M1.xml
diff --git a/data/intel_lpmd_config_F18_M1.xml b/data/intel_lpmd_config_F18_M1.xml
new file mode 100644
index 0000000..9772ec3
--- /dev/null
+++ b/data/intel_lpmd_config_F18_M1.xml
@@ -0,0 +1,165 @@
+<?xml version="1.0"?>
+
+<!--
+Specifies the configuration data
+for Intel Energy Optimizer (LPMD) daemon
+-->
+
+<Configuration>
+ <!--
+ CPU format example: 1,2,4..6,8-10
+ -->
+ <lp_mode_cpus></lp_mode_cpus>
+
+ <!--
+ EPP to use in Low Power Mode
+ 0-255: Valid EPP value to use in Low Power Mode
+ -1: Don't change EPP in Low Power Mode
+ -->
+ <lp_mode_epp></lp_mode_epp>
+
+ <!--
+ Mode values
+ 0: Cgroup v2
+ 1: Cgroup v2 isolate
+ 2: CPU idle injection
+ <Mode>0</Mode>
+ -->
+
+ <!--
+ Default behavior when Performance power setting is used
+ -1: force off. (Never enter Low Power Mode)
+ 1: force on. (Always stay in Low Power Mode)
+ 0: auto. (opportunistic Low Power Mode enter/exit)
+ -->
+ <PerformanceDef>-1</PerformanceDef>
+
+ <!--
+ Default behavior when Balanced power setting is used
+ -1: force off. (Never enter Low Power Mode)
+ 1: force on. (Always stay in Low Power Mode)
+ 0: auto. (opportunistic Low Power Mode enter/exit)
+ -->
+ <BalancedDef>-1</BalancedDef>
+
+ <!--
+ Default behavior when Power saver setting is used
+ -1: force off. (Never enter Low Power Mode)
+ 1: force on. (Always stay in Low Power Mode)
+ 0: auto. (opportunistic Low Power Mode enter/exit)
+ -->
+ <PowersaverDef>-1</PowersaverDef>
+
+ <!--
+ Use HFI LPM hints
+ 0 : No
+ 1 : Yes
+ -->
+ <HfiLpmEnable>0</HfiLpmEnable>
+
+ <!--
+ Use WLT hints
+ 0 : No
+ 1 : Yes
+ -->
+ <WLTHintEnable>1</WLTHintEnable>
+
+ <!--
+ Use WLT hint Poll enable
+ 0 : No
+ 1 : Yes
+ -->
+ <WLTHintPollEnable>0</WLTHintPollEnable>
+
+ <!--
+ Use WLT hint Mask
+ 0 : Non
+ * : Value to AND with with the hardware hint
+ -->
+ <WLTHintMask>15</WLTHintMask>
+
+ <!--
+ Use HFI SUV hints
+ 0 : No
+ 1 : Yes
+ -->
+ <HfiSuvEnable>0</HfiSuvEnable>
+
+ <!--
+ System utilization threshold to enter LP mode
+ from 0 - 100
+ clear both util_entry_threshold and util_exit_threshold to disable util monitor
+ <util_entry_threshold>0</util_entry_threshold>
+ -->
+
+ <!--
+ System utilization threshold to exit LP mode
+ from 0 - 100
+ clear both util_entry_threshold and util_exit_threshold to disable util monitor
+ <util_exit_threshold>0</util_exit_threshold>
+ -->
+
+ <!--
+ Entry delay. Minimum delay in non Low Power mode to
+ enter LPM mode.
+ <EntryDelayMS>0</EntryDelayMS>
+ -->
+
+ <!--
+ Exit delay. Minimum delay in Low Power mode to
+ exit LPM mode.
+ <ExitDelayMS>0</ExitDelayMS>
+ -->
+
+ <!--
+ Lowest hysteresis average in-LP-mode time in msec to enter LP mode
+ 0: to disable hysteresis support
+ <EntryHystMS>0</EntryHystMS>
+ -->
+
+ <!--
+ Lowest hysteresis average out-of-LP-mode time in msec to exit LP mode
+ 0: to disable hysteresis support
+ <ExitHystMS>0</ExitHystMS>
+ -->
+
+ <!--
+ Ignore ITMT setting during LP-mode enter/exit
+ 0: disable ITMT upon LP-mode enter and re-enable ITMT upon LP-mode exit
+ 1: do not touch ITMT setting during LP-mode enter/exit
+ -->
+ <IgnoreITMT>0</IgnoreITMT>
+
+ <!--
+ Slider default configuration for AC and DC
+ -->
+ <BalancedSliderAC>1</BalancedSliderAC>
+ <BalancedSliderDC>3</BalancedSliderDC>
+ <SliderOffsetAC>0</SliderOffsetAC>
+ <SliderOffsetDC>3</SliderOffsetDC>
+
+ <States>
+ <CPUFamily> 18 </CPUFamily>
+ <CPUModel> 1 </CPUModel>
+ <CPUConfig> * </CPUConfig>
+ <State>
+ <ID> 1 </ID>
+ <Name> UTIL_IDLE </Name>
+ <WLTType> 1 </WLTType>
+ <ActiveLcores>ALL</ActiveLcores>
+ </State>
+ <State>
+ <ID> 2 </ID>
+ <Name> UTIL_IDLE_SUSTAIN </Name>
+ <WLTType> 2 </WLTType>
+ <ActiveCpus> * </ActiveCpus>
+ </State>
+ <State>
+ <ID> 3 </ID>
+ <Name> UTIL_IDLE_BURSTY </Name>
+ <WLTType> 3 </WLTType>
+ <ActiveCpus> * </ActiveCpus>
+ </State>
+ </States>
+
+</Configuration>
--
2.55.0

View File

@ -0,0 +1,72 @@
From 77a697a502db74ccd3ac727f6729167602451664 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Tue, 10 Feb 2026 13:52:46 +0100
Subject: [PATCH 38/56] lpmd_cpu: Add wildcard * for active_cpus and cpu types
Allow using the star "*" wildcard operator in the configuration of which
cpu cores should be used. It's use is synonymous to the "ALL" / "all"
keywords.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/include/lpmd.h | 1 +
src/lpmd_config.c | 2 +-
src/lpmd_cpumask.c | 2 +-
src/lpmd_state_machine.c | 3 ++-
4 files changed, 5 insertions(+), 3 deletions(-)
diff --git a/src/include/lpmd.h b/src/include/lpmd.h
index cf9a4fd..456e65e 100644
--- a/src/include/lpmd.h
+++ b/src/include/lpmd.h
@@ -323,6 +323,7 @@ int intel_dbus_server_init(gboolean (*exit_handler)(void));
/* lpmd_config.c */
int match_config_file(int family, int model, int tdp, char *save_file_name);
int lpmd_get_config(lpmd_config_t *lpmd_config);
+int is_wildcard(char *str);
/* lpmd_state_machine.c */
int update_lpmd_state(int state);
diff --git a/src/lpmd_config.c b/src/lpmd_config.c
index f9179cb..8527e94 100644
--- a/src/lpmd_config.c
+++ b/src/lpmd_config.c
@@ -114,7 +114,7 @@ static void lpmd_parse_state(xmlDoc *doc, xmlNode *a_node, lpmd_config_t *config
}
}
-static int is_wildcard(char *str)
+int is_wildcard(char *str)
{
if (!str)
return 1;
diff --git a/src/lpmd_cpumask.c b/src/lpmd_cpumask.c
index 9d41931..6b9b6a8 100644
--- a/src/lpmd_cpumask.c
+++ b/src/lpmd_cpumask.c
@@ -228,7 +228,7 @@ int cpumask_init_cpus_type(char * buf, enum cpumask_idx idx, unsigned char **cma
int nr_cpus = 0;
char * end;
- if (!strncmp(buf, "ALL", strlen("ALL")) || !strncmp(buf, "all", strlen("all")))
+ if (!strncmp(buf, "ALL", strlen("ALL")) || !strncmp(buf, "all", strlen("all")) || is_wildcard(buf))
count = count_cpu_type_cores(cmasks[type]);
else {
errno = 0;
diff --git a/src/lpmd_state_machine.c b/src/lpmd_state_machine.c
index 593de9e..677dc0d 100644
--- a/src/lpmd_state_machine.c
+++ b/src/lpmd_state_machine.c
@@ -638,7 +638,8 @@ static int build_state_cpumask_activecpus(lpmd_config_state_t *state)
return -2;
if (!strncmp(state->active_cpus, "all", sizeof("all")) ||
- !strncmp(state->active_cpus, "ALL", sizeof("ALL"))) {
+ !strncmp(state->active_cpus, "ALL", sizeof("ALL")) ||
+ is_wildcard(state->active_cpus)) {
state->cpumask_idx = CPUMASK_ONLINE;
return 0;
}
--
2.55.0

View File

@ -0,0 +1,57 @@
From 10044d978632ceb21616bfe2c8824dcbbec0b8b9 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Tue, 10 Feb 2026 14:15:16 +0100
Subject: [PATCH 39/56] data: Fix active cpu spelling
Lowercase 'cpus' were causing this tag to not get loaded properly when
constructing cpu bitmasks.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
data/intel_lpmd_config_F18_M1.xml | 4 ++--
data/intel_lpmd_config_F6_M204.xml | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/data/intel_lpmd_config_F18_M1.xml b/data/intel_lpmd_config_F18_M1.xml
index 9772ec3..732b107 100644
--- a/data/intel_lpmd_config_F18_M1.xml
+++ b/data/intel_lpmd_config_F18_M1.xml
@@ -152,13 +152,13 @@ for Intel Energy Optimizer (LPMD) daemon
<ID> 2 </ID>
<Name> UTIL_IDLE_SUSTAIN </Name>
<WLTType> 2 </WLTType>
- <ActiveCpus> * </ActiveCpus>
+ <ActiveCPUs> * </ActiveCPUs>
</State>
<State>
<ID> 3 </ID>
<Name> UTIL_IDLE_BURSTY </Name>
<WLTType> 3 </WLTType>
- <ActiveCpus> * </ActiveCpus>
+ <ActiveCPUs> * </ActiveCPUs>
</State>
</States>
diff --git a/data/intel_lpmd_config_F6_M204.xml b/data/intel_lpmd_config_F6_M204.xml
index 9029f13..83a0fb2 100644
--- a/data/intel_lpmd_config_F6_M204.xml
+++ b/data/intel_lpmd_config_F6_M204.xml
@@ -152,13 +152,13 @@ for Intel Energy Optimizer (LPMD) daemon
<ID> 2 </ID>
<Name> UTIL_IDLE_SUSTAIN </Name>
<WLTType> 2 </WLTType>
- <ActiveCpus> * </ActiveCpus>
+ <ActiveCPUs> * </ActiveCPUs>
</State>
<State>
<ID> 3 </ID>
<Name> UTIL_IDLE_BURSTY </Name>
<WLTType> 3 </WLTType>
- <ActiveCpus> * </ActiveCpus>
+ <ActiveCPUs> * </ActiveCPUs>
</State>
</States>
--
2.55.0

View File

@ -0,0 +1,43 @@
From 1eea93c6f96ca435161101f685345383ea6d8f18 Mon Sep 17 00:00:00 2001
From: Mohsin Shariff <mohsin.shariff@intel.com>
Date: Fri, 27 Feb 2026 20:25:31 +0530
Subject: [PATCH 40/56] Enable platform-agnostic config fallback for unknown
platforms
- Remove hard platform whitelist check failure (return -1)
- Unknown platforms now continue to config loading instead of exiting
- Allows fallback to generic intel_lpmd_config.xml for unsupported models
- Improves daemon robustness for new/preview platforms like M213
- Updated log messages to indicate fallback attempt
[srinivas: Fixed log message and sign-off of the author]
Signed-off-by: Mohsin Shariff <mohsin.shariff@intel.com>
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
src/lpmd_cpu.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/lpmd_cpu.c b/src/lpmd_cpu.c
index bb3ecd3..9080584 100644
--- a/src/lpmd_cpu.c
+++ b/src/lpmd_cpu.c
@@ -120,14 +120,13 @@ int detect_supported_platform(lpmd_config_t *lpmd_config)
/* Unsupported model */
if (!id_table[val].family) {
- lpmd_log_info("Platform not supported yet.\n");
- lpmd_log_debug("Supported platforms:\n");
+ lpmd_log_info("Platform model %d not in supported platform list. Attempt fallback to generic config.\n", model);
+ lpmd_log_debug("Supported platforms (with optimized configs):\n");
val = 0;
while (id_table[val].family) {
lpmd_log_debug("\tfamily %d model %d\n", id_table[val].family, id_table[val].model);
val++;
}
- return -1;
}
end:
--
2.55.0

View File

@ -0,0 +1,38 @@
From 38cb4c6052fd54aae28fba05e623537fba2096c2 Mon Sep 17 00:00:00 2001
From: Mohsin Shariff <mohsin.shariff@intel.com>
Date: Mon, 2 Mar 2026 11:03:54 +0530
Subject: [PATCH 41/56] docs: Clarify slider config
docs: Clarify slider config is for Panther Lake and later platforms
[srinivas: Changed PTL to Panther Lake and sign-off of the author]
Signed-off-by: Mohsin Shariff <mohsin.shariff@intel.com>
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
data/intel_lpmd_config.xml | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/data/intel_lpmd_config.xml b/data/intel_lpmd_config.xml
index 2ef361a..f9e8876 100644
--- a/data/intel_lpmd_config.xml
+++ b/data/intel_lpmd_config.xml
@@ -102,5 +102,16 @@ for Intel Energy Optimizer (LPMD) daemon
-->
<IgnoreITMT>0</IgnoreITMT>
+ <!--
+ Slider default configuration for AC and DC (for platforms after Panther Lake onwards)
+ These are default values used when platform-specific configs are unavailable.
+ AC: Plugged into power adapter
+ DC: Running on battery
+ -->
+ <BalancedSliderAC>1</BalancedSliderAC>
+ <BalancedSliderDC>3</BalancedSliderDC>
+ <SliderOffsetAC>0</SliderOffsetAC>
+ <SliderOffsetDC>3</SliderOffsetDC>
+
</Configuration>
--
2.55.0

View File

@ -0,0 +1,244 @@
From 4935e3fd8a766cd9924ec03275d3b5dc652df038 Mon Sep 17 00:00:00 2001
From: Mohsin Shariff <mohsin.shariff@intel.com>
Date: Mon, 13 Apr 2026 13:53:25 -0700
Subject: [PATCH 42/56] Validate slider balance and offset configuration
Make sure that slider balance and offset values are configured under limits.
Slider value can be set from 1-5 and offset can be from 0-6.
[srinivas: Squashed all related commits and added commit log]
Signed-off-by: Mohsin Shariff <mohsin.shariff@intel.com>
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
src/include/lpmd.h | 15 ++++++
src/lpmd_config.c | 124 ++++++++++++++++++++++++++++++++++++++-------
2 files changed, 121 insertions(+), 18 deletions(-)
diff --git a/src/include/lpmd.h b/src/include/lpmd.h
index 456e65e..8c7193d 100644
--- a/src/include/lpmd.h
+++ b/src/include/lpmd.h
@@ -86,6 +86,19 @@ static int dummy_printf(const char *__restrict __format, ...)
#define LPMD_ERROR -1
#define LPMD_FATAL_ERROR -2
+/* Slider parameter types for explicit type-safe validation */
+enum slider_param_type {
+ SLIDER_TYPE_BALANCE,
+ SLIDER_TYPE_OFFSET,
+ SLIDER_TYPE_MAX
+};
+
+// Slider validation defines
+#define SLIDER_BALANCE_MIN 1
+#define SLIDER_BALANCE_MAX 5
+#define SLIDER_OFFSET_MIN 0
+#define SLIDER_OFFSET_MAX 6
+
// Dbus related
/* Well-known name for this service. */
#define INTEL_LPMD_SERVICE_NAME "org.freedesktop.intel_lpmd"
@@ -180,6 +193,7 @@ typedef struct {
int itmt_state;
int irq_migrate;
+ /* balance: 1-5, offset: 0-6, or -1 to disable */
int balance_slider_ac;
int slider_offset_ac;
int balance_slider_dc;
@@ -230,6 +244,7 @@ typedef struct {
int tdp;
char file_name[MAX_FILE_NAME_PATH];
+ /* balance: 1-5, offset: 0-6, or -1 to disable */
int balance_slider_def_ac;
int slider_offset_def_ac;
int balance_slider_def_dc;
diff --git a/src/lpmd_config.c b/src/lpmd_config.c
index 8527e94..cfeb910 100644
--- a/src/lpmd_config.c
+++ b/src/lpmd_config.c
@@ -24,6 +24,82 @@
#define CONFIG_FILE_NAME "intel_lpmd_config.xml"
+static int validate_slider_value(int value, const char *param_name, int state_id,
+ int min_val, int max_val)
+{
+ /* -1 is a special value meaning "ignore/disable" */
+ if (value == -1)
+ return LPMD_SUCCESS; /* Valid */
+
+ if (value < min_val || value > max_val) {
+ if (state_id >= 0) {
+ /* State-level parameter */
+ lpmd_log_error("Invalid %s value: %d in state ID %d. "
+ "Valid range: %d-%d or %d to disable\n",
+ param_name, value, state_id,
+ min_val, max_val, -1);
+ } else {
+ /* Global/default parameter */
+ lpmd_log_error("Invalid %s (global default) value: %d. "
+ "Valid range: %d-%d or %d to disable\n",
+ param_name, value,
+ min_val, max_val, -1);
+ }
+ return LPMD_ERROR; /* Invalid */
+ }
+
+ return LPMD_SUCCESS; /* Valid */
+}
+
+/*
+ * Helper function to parse and validate slider parameters.
+ * Handles both parsing (with error checking) and range validation in one call.
+ * Returns 0 on success, LPMD_ERROR on failure (fail-fast approach).
+ */
+static int read_slider_and_validate(int *dest_ptr, const char *src_value,
+ const char *param_name, int state_id,
+ enum slider_param_type type)
+{
+ char *endptr;
+ int value;
+
+ errno = 0;
+ value = strtol(src_value, &endptr, 10);
+
+ /* Check for parsing errors */
+ if (errno == ERANGE || endptr == src_value) {
+ if (state_id >= 0) {
+ lpmd_log_error("Failed to parse %s value: '%s' is not a valid integer in state ID %d\n",
+ param_name, src_value, state_id);
+ } else {
+ lpmd_log_error("Failed to parse %s value: '%s' is not a valid integer\n",
+ param_name, src_value);
+ }
+ return LPMD_ERROR;
+ }
+
+ /* Validate the parsed value based on type */
+ switch (type) {
+ case SLIDER_TYPE_OFFSET:
+ if (validate_slider_value(value, param_name, state_id,
+ SLIDER_OFFSET_MIN, SLIDER_OFFSET_MAX) != LPMD_SUCCESS)
+ return LPMD_ERROR;
+ break;
+ case SLIDER_TYPE_BALANCE:
+ if (validate_slider_value(value, param_name, state_id,
+ SLIDER_BALANCE_MIN, SLIDER_BALANCE_MAX) != LPMD_SUCCESS)
+ return LPMD_ERROR;
+ break;
+ default:
+ lpmd_log_error("Unexpected slider type value: %d\n", type);
+ return LPMD_ERROR;
+ }
+
+ /* Success - update the destination pointer */
+ *dest_ptr = value;
+ return LPMD_SUCCESS;
+}
+
static void save_string_or_zero(char * tmp_value, char * dst_string, int dest_size)
{
if (!strncmp (tmp_value, "-1", strlen ("-1")))
@@ -37,6 +113,7 @@ static void lpmd_parse_state(xmlDoc *doc, xmlNode *a_node, lpmd_config_t *config
xmlNode *cur_node = NULL;
char *tmp_value;
char *pos;
+ int ret = 0;
lpmd_config_state_t *state = &config->config_states[idx];
if (!doc || !a_node || !state)
@@ -101,16 +178,17 @@ static void lpmd_parse_state(xmlDoc *doc, xmlNode *a_node, lpmd_config_t *config
if (!strncmp((const char*)cur_node->name, "ActiveCPUs", strlen("ActiveCPUs")))
save_string_or_zero(tmp_value, state->active_cpus, sizeof(state->active_cpus));
if (!strncmp((const char*)cur_node->name, "BalanceSliderAC", strlen("BalanceSliderAC")))
- state->balance_slider_ac = strtol (tmp_value, &pos, 10);
+ ret = read_slider_and_validate(&state->balance_slider_ac, tmp_value, "BalanceSliderAC", state->id, SLIDER_TYPE_BALANCE);
if (!strncmp((const char*)cur_node->name, "SliderOffsetAC", strlen("SliderOffsetAC")))
- state->slider_offset_ac = strtol (tmp_value, &pos, 10);
-
+ ret = read_slider_and_validate(&state->slider_offset_ac, tmp_value, "SliderOffsetAC", state->id, SLIDER_TYPE_OFFSET);
if (!strncmp((const char*)cur_node->name, "BalanceSliderDC", strlen("BalanceSliderDC")))
- state->balance_slider_dc = strtol (tmp_value, &pos, 10);
+ ret = read_slider_and_validate(&state->balance_slider_dc, tmp_value, "BalanceSliderDC", state->id, SLIDER_TYPE_BALANCE);
if (!strncmp((const char*)cur_node->name, "SliderOffsetDC", strlen("SliderOffsetDC")))
- state->slider_offset_dc = strtol (tmp_value, &pos, 10);
+ ret = read_slider_and_validate(&state->slider_offset_dc, tmp_value, "SliderOffsetDC", state->id, SLIDER_TYPE_OFFSET);
xmlFree(tmp_value);
+ if (ret)
+ return;
}
}
@@ -216,6 +294,7 @@ static int lpmd_fill_config(xmlDoc *doc, xmlNode *a_node, lpmd_config_t *lpmd_co
xmlNode *cur_node = NULL;
char *tmp_value;
char *pos;
+ int config_error = 0; /* Track if we encountered a parsing error */
if (!doc || !a_node || !lpmd_config)
return LPMD_ERROR;
@@ -390,21 +469,24 @@ static int lpmd_fill_config(xmlDoc *doc, xmlNode *a_node, lpmd_config_t *lpmd_co
lpmd_parse_states(doc, cur_node->children, lpmd_config);
}
else if (!strncmp((const char*)cur_node->name, "BalancedSliderAC", strlen ("BalancedSliderAC"))) {
- errno = 0;
- lpmd_config->balance_slider_def_ac = strtol (tmp_value, &pos, 10);
-
+ if (read_slider_and_validate(&lpmd_config->balance_slider_def_ac, tmp_value, "BalancedSliderAC", -1, SLIDER_TYPE_BALANCE) != 0) {
+ goto err;
+ }
}
else if (!strncmp((const char*)cur_node->name, "BalancedSliderDC", strlen ("BalancedSliderDC"))) {
- errno = 0;
- lpmd_config->balance_slider_def_dc = strtol (tmp_value, &pos, 10);
+ if (read_slider_and_validate(&lpmd_config->balance_slider_def_dc, tmp_value, "BalancedSliderDC", -1, SLIDER_TYPE_BALANCE) != 0) {
+ goto err;
+ }
}
else if (!strncmp((const char*)cur_node->name, "SliderOffsetAC", strlen ("SliderOffsetAC"))) {
- errno = 0;
- lpmd_config->slider_offset_def_ac = strtol (tmp_value, &pos, 10);
+ if (read_slider_and_validate(&lpmd_config->slider_offset_def_ac, tmp_value, "SliderOffsetAC", -1, SLIDER_TYPE_OFFSET) != 0) {
+ goto err;
+ }
}
else if (!strncmp((const char*)cur_node->name, "SliderOffsetDC", strlen ("SliderOffsetDC"))) {
- errno = 0;
- lpmd_config->slider_offset_def_dc = strtol (tmp_value, &pos, 10);
+ if (read_slider_and_validate(&lpmd_config->slider_offset_def_dc, tmp_value, "SliderOffsetDC", -1, SLIDER_TYPE_OFFSET) != 0) {
+ goto err;
+ }
}
else {
if (!strncmp((const char*)cur_node->name, "HfiSuvEnable", strlen("HfiSuvEnable"))) {
@@ -416,14 +498,20 @@ static int lpmd_fill_config(xmlDoc *doc, xmlNode *a_node, lpmd_config_t *lpmd_co
}
xmlFree (tmp_value);
continue;
-err: xmlFree (tmp_value);
- lpmd_log_error ("node type: Element, name: %s value: %s\n", cur_node->name,
- tmp_value);
- return LPMD_ERROR;
+err:
+ lpmd_log_error("node type: Element, name: %s value: %s\n", cur_node->name,
+ tmp_value);
+ xmlFree(tmp_value);
+ config_error = 1; /* Mark that a parsing error occurred */
+ break; /* Exit loop and validate before returning error */
}
}
}
+ /* If a parsing error occurred, return error */
+ if (config_error)
+ return LPMD_ERROR;
+
return LPMD_SUCCESS;
}
--
2.55.0

View File

@ -0,0 +1,115 @@
From 88a42cafb9695f6111e3133d72986df8e26c1c58 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Mon, 16 Mar 2026 16:05:58 +0100
Subject: [PATCH 43/56] lpmd_cpumask: Refactor get_cgroup_systemd_vals() to
avoid passing the size
Passing size as an argument in unnecessary as it can be obtained through
the get_max_cpus() global LPMD call.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/include/lpmd.h | 2 +-
src/lpmd_cgroup.c | 8 ++++----
src/lpmd_cpumask.c | 15 +++++++--------
3 files changed, 12 insertions(+), 13 deletions(-)
diff --git a/src/include/lpmd.h b/src/include/lpmd.h
index 8c7193d..123c785 100644
--- a/src/include/lpmd.h
+++ b/src/include/lpmd.h
@@ -427,7 +427,7 @@ char* get_cpus_hexstr(enum cpumask_idx idx);
char *get_proc_irq_str(enum cpumask_idx idx);
char *get_irqbalance_str(enum cpumask_idx idx);
char *get_cpu_isolation_str(enum cpumask_idx idx);
-uint8_t *get_cgroup_systemd_vals(enum cpumask_idx idx, int *size);
+uint8_t *get_cgroup_systemd_vals(enum cpumask_idx idx);
/* socket.c */
int socket_init_connection(char *name);
diff --git a/src/lpmd_cgroup.c b/src/lpmd_cgroup.c
index e74c8cf..1dddce0 100644
--- a/src/lpmd_cgroup.c
+++ b/src/lpmd_cgroup.c
@@ -115,10 +115,10 @@ finish: if (ret >= 0) {
static int restore_systemd_cgroup(void)
{
- int size;
+ int size = get_max_cpus() / 8;
uint8_t *vals;
- vals = get_cgroup_systemd_vals(CPUMASK_ONLINE, &size);
+ vals = get_cgroup_systemd_vals(CPUMASK_ONLINE);
if (!vals)
return -1;
@@ -131,11 +131,11 @@ static int restore_systemd_cgroup(void)
static int update_systemd_cgroup(lpmd_config_state_t *state)
{
- int size;
+ int size = get_max_cpus() / 8;
uint8_t *vals;
int ret;
- vals = get_cgroup_systemd_vals(state->cpumask_idx, &size);
+ vals = get_cgroup_systemd_vals(state->cpumask_idx);
if (!vals)
return -1;
diff --git a/src/lpmd_cpumask.c b/src/lpmd_cpumask.c
index 6b9b6a8..95d3781 100644
--- a/src/lpmd_cpumask.c
+++ b/src/lpmd_cpumask.c
@@ -502,11 +502,12 @@ static char* get_cpus_str_reverse(enum cpumask_idx idx)
return cpumasks[idx].str_reverse;
}
-static uint8_t *get_cpus_hexvals(enum cpumask_idx idx, int *size)
+static uint8_t *get_cpus_hexvals(enum cpumask_idx idx)
{
- int i, j, k;
+ int size = topo_max_cpus / 8;
uint8_t v = 0;
uint8_t *vals;
+ int i, j, k;
if (!cpumasks[idx].mask)
return NULL;
@@ -514,12 +515,10 @@ static uint8_t *get_cpus_hexvals(enum cpumask_idx idx, int *size)
if (!CPU_COUNT_S(size_cpumask, cpumasks[idx].mask))
return NULL;
- *size = topo_max_cpus / 8;
-
if (cpumasks[idx].hexvals)
return cpumasks[idx].hexvals;
- vals = calloc (*size, 1);
+ vals = calloc (size, 1);
if (!vals)
return NULL;
@@ -527,7 +526,7 @@ static uint8_t *get_cpus_hexvals(enum cpumask_idx idx, int *size)
j = i % 8;
k = i / 8;
- if (k >= *size) {
+ if (k >= size) {
lpmd_log_error ("size too big\n");
free(vals);
return NULL;
@@ -565,7 +564,7 @@ char *get_cpu_isolation_str(enum cpumask_idx idx)
return get_cpus_str_reverse(idx);
}
-uint8_t *get_cgroup_systemd_vals(enum cpumask_idx idx, int *size)
+uint8_t *get_cgroup_systemd_vals(enum cpumask_idx idx)
{
- return get_cpus_hexvals(idx, size);
+ return get_cpus_hexvals(idx);
}
--
2.55.0

View File

@ -0,0 +1,70 @@
From d31613630df19ac191590dd4c0cbed2a38fedc2d Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Tue, 17 Mar 2026 13:16:13 +0100
Subject: [PATCH 44/56] lpmd_cpu: Add a CPU blacklist cpumask
Add a new cpumask that's used to clearing cores from other cpumasks.
Fill the new cpumask with CPUs that couldn't be reached with
sched_setaffinity() indicating that they are not available.
The specific context of this change is for cases when CPUs are claimed by
other cgroups as exclusive and therefore are not available for the lpm
cgroup. For the cgroup isolation mode this results in LPMD not working
correctly.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/include/lpmd.h | 1 +
src/lpmd_cpu.c | 4 +++-
src/lpmd_cpumask.c | 1 +
3 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/src/include/lpmd.h b/src/include/lpmd.h
index 123c785..08ded1c 100644
--- a/src/include/lpmd.h
+++ b/src/include/lpmd.h
@@ -271,6 +271,7 @@ enum cpumask_idx {
CPUMASK_HFI_BANNED,
CPUMASK_HFI_LAST,
CPUMASK_UTIL,
+ CPUMASK_BLACKLIST,
CPUMASK_USER,
CPUMASK_MAX = CPUMASK_USER + NUM_USER_CPUMASKS,
CPUMASK_NONE = CPUMASK_MAX,
diff --git a/src/lpmd_cpu.c b/src/lpmd_cpu.c
index 9080584..fc3fe4b 100644
--- a/src/lpmd_cpu.c
+++ b/src/lpmd_cpu.c
@@ -152,6 +152,7 @@ int is_cpu_atom(int cpu)
if (cpu_migrate(cpu) < 0) {
lpmd_log_error("Failed to migrated to cpu%d\n", cpu);
+ cpumask_add_cpu(cpu, CPUMASK_BLACKLIST);
return -1;
}
@@ -169,7 +170,8 @@ static int is_cpu_in_l3(int cpu)
if (cpu_migrate(cpu) < 0) {
lpmd_log_error("Failed to migrated to cpu%d\n", cpu);
- err (1, "cpu migrate");
+ cpumask_add_cpu(cpu, CPUMASK_BLACKLIST);
+ return -1;
}
for(subleaf = 0;; subleaf++) {
diff --git a/src/lpmd_cpumask.c b/src/lpmd_cpumask.c
index 95d3781..b1b6d6b 100644
--- a/src/lpmd_cpumask.c
+++ b/src/lpmd_cpumask.c
@@ -43,6 +43,7 @@ static struct lpm_cpus cpumasks[CPUMASK_MAX] = {
[CPUMASK_HFI] = { .name = "HFI Low Power", },
[CPUMASK_HFI_BANNED] = { .name = "HFI BANNED", },
[CPUMASK_HFI_LAST] = { .name = "HFI LAST", },
+ [CPUMASK_BLACKLIST] = { .name = "Blacklist", },
};
int is_cpu_online(int cpu)
--
2.55.0

View File

@ -0,0 +1,40 @@
From cfeccc5ddf0be8c3594e26cc5b413b91bfc1548b Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Tue, 17 Mar 2026 13:21:52 +0100
Subject: [PATCH 45/56] lpmd_cpu: Skip filling out type cpumasks if there was
an error
Don't add CPUs to type related cpumasks if their discovery function
ended with an error.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/lpmd_cpu.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/lpmd_cpu.c b/src/lpmd_cpu.c
index fc3fe4b..7a4ca9f 100644
--- a/src/lpmd_cpu.c
+++ b/src/lpmd_cpu.c
@@ -368,15 +368,15 @@ int detect_cpu_topo(lpmd_config_t *lpmd_config)
for (i = 0; i < get_max_cpus(); i++) {
if (!is_cpu_online(i))
continue;
- if (is_cpu_pcore(i)) {
+ if (is_cpu_pcore(i) > 0) {
pcores++;
lpmd_config->core_type_masks[P_CORE][i / 8] |= 1 << (i % 8);
}
- else if (is_cpu_ecore(i)) {
+ else if (is_cpu_ecore(i) > 0) {
ecores++;
lpmd_config->core_type_masks[E_CORE][i / 8] |= 1 << (i % 8);
}
- else if (is_cpu_lcore(i)) {
+ else if (is_cpu_lcore(i) > 0) {
lcores++;
lpmd_config->core_type_masks[L_CORE][i / 8] |= 1 << (i % 8);
}
--
2.55.0

View File

@ -0,0 +1,154 @@
From 1d313da29ec41be617e6118a6a5766be74e7f1fa Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Thu, 12 Mar 2026 23:41:18 +0100
Subject: [PATCH 46/56] lpmd_cpumask: init level complex isolation fix -
blacklist unavailable CPUs
To use the isolated cgroup feature the cpuset.cpus.exclusive file needs
to be filled with available CPUs - only then a subset of these CPUs can
be written into cpuset.cpus. Otherwise the isolated mode is not in a
valid state.
While the simple case of all CPUs being available works after being
patched, the case of some other cgroup claiming exclusive ownership of a
couple of CPUs causes the isolated mode in LPMD to be broken again. The
CPUs claimed by the other cgroup need to be taken into account.
Use the Blacklist CPUs mechanism to exclude the cores that were found to
be unavailable during topology discovery. The blacklist cpumask should
be complete after the topology is discovered. The unavailable cores are
detected by checking onto which core the program cannot be migrated. All
the calls to update other cpumasks are done after that.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/include/lpmd.h | 1 +
src/lpmd_cpu.c | 3 +++
src/lpmd_cpumask.c | 46 ++++++++++++++++++++++++++++++++++++++--------
3 files changed, 42 insertions(+), 8 deletions(-)
diff --git a/src/include/lpmd.h b/src/include/lpmd.h
index 08ded1c..2f7fdcf 100644
--- a/src/include/lpmd.h
+++ b/src/include/lpmd.h
@@ -414,6 +414,7 @@ void free_cpu_type_masks(lpmd_config_t *lpmd_config);
int allocate_cpu_type_masks(lpmd_config_t *lpmd_config);
int cpumask_add_cpu(int cpu, enum cpumask_idx idx);
+int cpumask_blacklist(enum cpumask_idx idx);
int cpumask_init_cpus(char *buf, enum cpumask_idx idx);
int cpumask_init_cpus_type(char * buf, enum cpumask_idx idx, unsigned char **cmasks, enum core_type type);
int cpumask_nr_cpus(enum cpumask_idx idx);
diff --git a/src/lpmd_cpu.c b/src/lpmd_cpu.c
index 7a4ca9f..ed270f2 100644
--- a/src/lpmd_cpu.c
+++ b/src/lpmd_cpu.c
@@ -382,6 +382,9 @@ int detect_cpu_topo(lpmd_config_t *lpmd_config)
}
}
+ /* Clear the CPUs claimed by other cgroups from the ONLINE mask */
+ cpumask_blacklist(CPUMASK_ONLINE);
+
lpmd_log_info("Detected %d Pcores, %d Ecores, %d Lcores, TDP %dW\n",
pcores, ecores, lcores, lpmd_config->tdp);
ret = snprintf(lpmd_config->cpu_config, MAX_CONFIG_LEN - 1,
diff --git a/src/lpmd_cpumask.c b/src/lpmd_cpumask.c
index b1b6d6b..e6a98b2 100644
--- a/src/lpmd_cpumask.c
+++ b/src/lpmd_cpumask.c
@@ -243,19 +243,21 @@ int cpumask_init_cpus_type(char * buf, enum cpumask_idx idx, unsigned char **cma
cpumask_add_cpu(current, idx);
next = get_next_cpu_cmask(current + 1, type, cmasks[type]);
if(next == current) /* Couldn't find next core of the provided type */
- return nr_cpus;
+ goto blacklist;
nr_cpus++;
current = next;
}
- return nr_cpus;
+blacklist:
+ cpumask_blacklist(idx);
+
+ return CPU_COUNT_S(size_cpumask, cpumasks[idx].mask);
}
int cpumask_init_cpus(char *buf, enum cpumask_idx idx)
{
unsigned int start, end;
char *next;
- int nr_cpus = 0;
if (buf[0] == '\0')
return 0;
@@ -279,7 +281,6 @@ int cpumask_init_cpus(char *buf, enum cpumask_idx idx)
start = strtoul (next, &next, 10);
cpumask_add_cpu (start, idx);
- nr_cpus++;
if (*next == '\0')
break;
@@ -304,10 +305,8 @@ int cpumask_init_cpus(char *buf, enum cpumask_idx idx)
if (end <= start)
goto error;
- while (++start <= end) {
+ while (++start <= end)
cpumask_add_cpu (start, idx);
- nr_cpus++;
- }
if (*next == ',')
next += 1;
@@ -315,7 +314,9 @@ int cpumask_init_cpus(char *buf, enum cpumask_idx idx)
goto error;
}
- return nr_cpus;
+ cpumask_blacklist(idx);
+
+ return CPU_COUNT_S(size_cpumask, cpumasks[idx].mask);
error:
lpmd_log_error ("CPU string malformed: %s\n", buf);
return -1;
@@ -547,6 +548,35 @@ set_val: if (j == 7) {
return cpumasks[idx].hexvals;
}
+int cpumask_blacklist(enum cpumask_idx idx)
+{
+ if (!cpumasks[idx].mask)
+ alloc_cpu_set (&cpumasks[idx].mask);
+
+ /* Return due to blacklist not getting initialized yet. */
+ if (!cpumasks[CPUMASK_BLACKLIST].mask) {
+ alloc_cpu_set (&cpumasks[CPUMASK_BLACKLIST].mask);
+ return LPMD_ERROR;
+ }
+
+ /* Return due to blacklist being empty. */
+ if (!CPU_COUNT_S(size_cpumask, cpumasks[CPUMASK_BLACKLIST].mask))
+ return LPMD_ERROR;
+
+ /* Otherwise clear blacklisted cpus from the chosen cpumask */
+ for (int i = 0 ; i < topo_max_cpus ; i++)
+ if (CPU_ISSET_S(i, size_cpumask, cpumasks[CPUMASK_BLACKLIST].mask))
+ CPU_CLR_S(i, size_cpumask, cpumasks[idx].mask);
+
+ if (!CPU_COUNT_S(size_cpumask, cpumasks[idx].mask)) {
+ lpmd_log_error("%s : cpumask[%d] is empty after blacklisting due to unavailable cpus\n", cpumasks[idx].name, idx);
+ lpmd_log_error("It's possible another cgroup claimed all cores required by cpumask[%d]\n", idx);
+ }
+
+ return LPMD_SUCCESS;
+}
+
+
char *get_proc_irq_str(enum cpumask_idx idx)
{
return get_cpus_hexstr(idx);
--
2.55.0

View File

@ -0,0 +1,211 @@
From 50e0d1eaea860d00adb56ac162c3de346742c3ed Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Tue, 17 Mar 2026 13:16:31 +0100
Subject: [PATCH 47/56] lpmd_cpumask: Refresh cached data when blacklisting
cpus
When blacklisting CPUs they are cleared from their cpumask. Other cached
data like hexadecimal representation of the cpumask or decimal numerical
strings for /sys/fs purposes need to be updated when the cpumask
changes. Otherwise only the cached value is displayed since so far the
idea was that once initialized the cached values wouldn't change.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/include/lpmd.h | 4 +--
src/lpmd_cpu.c | 2 +-
src/lpmd_cpumask.c | 55 ++++++++++++++++++++++++++--------------
src/lpmd_state_machine.c | 4 +--
4 files changed, 41 insertions(+), 24 deletions(-)
diff --git a/src/include/lpmd.h b/src/include/lpmd.h
index 2f7fdcf..2e9ff33 100644
--- a/src/include/lpmd.h
+++ b/src/include/lpmd.h
@@ -424,8 +424,8 @@ int cpumask_equal(enum cpumask_idx idx1, enum cpumask_idx idx2);
void cpumask_copy(enum cpumask_idx source, enum cpumask_idx dest);
void cpumask_exclude_copy(enum cpumask_idx source, enum cpumask_idx dest, enum cpumask_idx exlude);
-char *get_cpus_str(enum cpumask_idx idx);
-char* get_cpus_hexstr(enum cpumask_idx idx);
+char* get_cpus_str(enum cpumask_idx idx, bool refresh);
+char* get_cpus_hexstr(enum cpumask_idx idx, bool refresh);
char *get_proc_irq_str(enum cpumask_idx idx);
char *get_irqbalance_str(enum cpumask_idx idx);
char *get_cpu_isolation_str(enum cpumask_idx idx);
diff --git a/src/lpmd_cpu.c b/src/lpmd_cpu.c
index ed270f2..aa7c1da 100644
--- a/src/lpmd_cpu.c
+++ b/src/lpmd_cpu.c
@@ -516,7 +516,7 @@ int detect_lpm_cpus(char *cmd_cpus)
end: if (cpumask_has_cpu(CPUMASK_LPM_DEFAULT))
lpmd_log_info ("\tUse CPU %s as Default Low Power CPUs (%s)\n",
- get_cpus_str (CPUMASK_LPM_DEFAULT), str);
+ get_cpus_str (CPUMASK_LPM_DEFAULT, false), str);
return 0;
}
diff --git a/src/lpmd_cpumask.c b/src/lpmd_cpumask.c
index e6a98b2..796004e 100644
--- a/src/lpmd_cpumask.c
+++ b/src/lpmd_cpumask.c
@@ -441,7 +441,7 @@ static int cpumask_to_hexstr(cpu_set_t *mask, char *str, int size)
return 0;
}
-char* get_cpus_str(enum cpumask_idx idx)
+char* get_cpus_str(enum cpumask_idx idx, bool refresh)
{
if (!cpumasks[idx].mask)
return NULL;
@@ -449,10 +449,13 @@ char* get_cpus_str(enum cpumask_idx idx)
if (!CPU_COUNT_S(size_cpumask, cpumasks[idx].mask))
return NULL;
- if (cpumasks[idx].str)
- return cpumasks[idx].str;
+ if (cpumasks[idx].str) {
+ if (!refresh)
+ return cpumasks[idx].str;
+ } else {
+ cpumasks[idx].str = calloc (MAX_STR_LENGTH, 1);
+ }
- cpumasks[idx].str = calloc (MAX_STR_LENGTH, 1);
if (!cpumasks[idx].str)
err (3, "STR_ALLOC");
@@ -460,7 +463,7 @@ char* get_cpus_str(enum cpumask_idx idx)
return cpumasks[idx].str;
}
-char* get_cpus_hexstr(enum cpumask_idx idx)
+char* get_cpus_hexstr(enum cpumask_idx idx, bool refresh)
{
if (!cpumasks[idx].mask)
return NULL;
@@ -468,10 +471,14 @@ char* get_cpus_hexstr(enum cpumask_idx idx)
if (!CPU_COUNT_S(size_cpumask, cpumasks[idx].mask))
return NULL;
- if (cpumasks[idx].hexstr)
- return cpumasks[idx].hexstr;
+ if (cpumasks[idx].hexstr) {
+ /* Already was allocated, it's okay to use the cached version */
+ if (!refresh)
+ return cpumasks[idx].hexstr;
+ } else {
+ cpumasks[idx].hexstr = calloc (MAX_STR_LENGTH, 1);
+ }
- cpumasks[idx].hexstr = calloc (MAX_STR_LENGTH, 1);
if (!cpumasks[idx].hexstr)
err (3, "STR_ALLOC");
@@ -479,7 +486,7 @@ char* get_cpus_hexstr(enum cpumask_idx idx)
return cpumasks[idx].hexstr;
}
-static char* get_cpus_str_reverse(enum cpumask_idx idx)
+static char* get_cpus_str_reverse(enum cpumask_idx idx, bool refresh)
{
cpu_set_t *mask;
@@ -489,10 +496,13 @@ static char* get_cpus_str_reverse(enum cpumask_idx idx)
if (!CPU_COUNT_S(size_cpumask, cpumasks[idx].mask))
return NULL;
- if (cpumasks[idx].str_reverse)
- return cpumasks[idx].str_reverse;
+ if (cpumasks[idx].str_reverse) {
+ if (!refresh)
+ return cpumasks[idx].str_reverse;
+ } else {
+ cpumasks[idx].str_reverse = calloc (MAX_STR_LENGTH, 1);
+ }
- cpumasks[idx].str_reverse = calloc (MAX_STR_LENGTH, 1);
if (!cpumasks[idx].str_reverse)
err (3, "STR_ALLOC");
@@ -504,7 +514,7 @@ static char* get_cpus_str_reverse(enum cpumask_idx idx)
return cpumasks[idx].str_reverse;
}
-static uint8_t *get_cpus_hexvals(enum cpumask_idx idx)
+static uint8_t *get_cpus_hexvals(enum cpumask_idx idx, bool refresh)
{
int size = topo_max_cpus / 8;
uint8_t v = 0;
@@ -518,7 +528,8 @@ static uint8_t *get_cpus_hexvals(enum cpumask_idx idx)
return NULL;
if (cpumasks[idx].hexvals)
- return cpumasks[idx].hexvals;
+ if (!refresh)
+ return cpumasks[idx].hexvals;
vals = calloc (size, 1);
if (!vals)
@@ -568,6 +579,12 @@ int cpumask_blacklist(enum cpumask_idx idx)
if (CPU_ISSET_S(i, size_cpumask, cpumasks[CPUMASK_BLACKLIST].mask))
CPU_CLR_S(i, size_cpumask, cpumasks[idx].mask);
+ /* Update any relevant cached data. */
+ cpumasks[idx].hexstr = get_cpus_hexstr(idx, true);
+ cpumasks[idx].str = get_cpus_str(idx, true);
+ cpumasks[idx].str_reverse = get_cpus_str_reverse(idx, true);
+ cpumasks[idx].hexvals = get_cpus_hexvals(idx, true);
+
if (!CPU_COUNT_S(size_cpumask, cpumasks[idx].mask)) {
lpmd_log_error("%s : cpumask[%d] is empty after blacklisting due to unavailable cpus\n", cpumasks[idx].name, idx);
lpmd_log_error("It's possible another cgroup claimed all cores required by cpumask[%d]\n", idx);
@@ -579,23 +596,23 @@ int cpumask_blacklist(enum cpumask_idx idx)
char *get_proc_irq_str(enum cpumask_idx idx)
{
- return get_cpus_hexstr(idx);
+ return get_cpus_hexstr(idx, false);
}
char *get_irqbalance_str(enum cpumask_idx idx)
{
- return get_cpus_str_reverse(idx);
+ return get_cpus_str_reverse(idx, false);
}
char *get_cpu_isolation_str(enum cpumask_idx idx)
{
if (idx == CPUMASK_ONLINE)
- return get_cpus_str(idx);
+ return get_cpus_str(idx, false);
else
- return get_cpus_str_reverse(idx);
+ return get_cpus_str_reverse(idx, false);
}
uint8_t *get_cgroup_systemd_vals(enum cpumask_idx idx)
{
- return get_cpus_hexvals(idx);
+ return get_cpus_hexvals(idx, false);
}
diff --git a/src/lpmd_state_machine.c b/src/lpmd_state_machine.c
index 677dc0d..8964b9a 100644
--- a/src/lpmd_state_machine.c
+++ b/src/lpmd_state_machine.c
@@ -370,9 +370,9 @@ static void dump_data(lpmd_config_t *config, int idx)
}
if (state->cpumask_idx != CPUMASK_NONE)
- offset += snprintf(buf + offset , MAX_STR_LENGTH - offset, "CPUMASK [%s] ", get_cpus_hexstr(state->cpumask_idx));
+ offset += snprintf(buf + offset , MAX_STR_LENGTH - offset, "CPUMASK [%s] ", get_cpus_hexstr(state->cpumask_idx, false));
else
- offset += snprintf(buf + offset , MAX_STR_LENGTH - offset, "CPUMASK [%s] ", get_cpus_hexstr(CPUMASK_ONLINE));
+ offset += snprintf(buf + offset , MAX_STR_LENGTH - offset, "CPUMASK [%s] ", get_cpus_hexstr(CPUMASK_ONLINE, false));
offset += snprintf(buf + offset , MAX_STR_LENGTH - offset, "ITMT [%d] ", get_itmt());
--
2.55.0

View File

@ -0,0 +1,118 @@
From c48bf5e87ce9ef232cc228dfa6325ff6c99123e3 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Mon, 16 Mar 2026 16:23:42 +0100
Subject: [PATCH 48/56] lpmd_cpumask: Refactor getting cached values
Getting cached values have common init code that checks a few simple
values or allocates the space in case it's the first time the cached
value is accessed.
Move it all to a helper to simplify these calls.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/lpmd_cpumask.c | 60 ++++++++++++++++++----------------------------
1 file changed, 23 insertions(+), 37 deletions(-)
diff --git a/src/lpmd_cpumask.c b/src/lpmd_cpumask.c
index 796004e..2a446cf 100644
--- a/src/lpmd_cpumask.c
+++ b/src/lpmd_cpumask.c
@@ -441,23 +441,33 @@ static int cpumask_to_hexstr(cpu_set_t *mask, char *str, int size)
return 0;
}
-char* get_cpus_str(enum cpumask_idx idx, bool refresh)
+int get_cached_value_init(enum cpumask_idx idx, bool refresh,
+ char **cached_str, const char *cached_name)
{
if (!cpumasks[idx].mask)
- return NULL;
+ return LPMD_ERROR;
if (!CPU_COUNT_S(size_cpumask, cpumasks[idx].mask))
- return NULL;
+ return LPMD_ERROR;
- if (cpumasks[idx].str) {
+ if (*cached_str) {
if (!refresh)
- return cpumasks[idx].str;
+ return LPMD_SUCCESS;
} else {
- cpumasks[idx].str = calloc (MAX_STR_LENGTH, 1);
+ *cached_str = calloc (MAX_STR_LENGTH, 1);
}
- if (!cpumasks[idx].str)
- err (3, "STR_ALLOC");
+ if (!(*cached_str))
+ err (3, "%s_ALLOC", cached_name);
+
+ return LPMD_SUCCESS;
+}
+
+char* get_cpus_str(enum cpumask_idx idx, bool refresh)
+{
+ int ret = get_cached_value_init(idx, refresh, &cpumasks[idx].str, "STR");
+ if (ret)
+ return NULL;
cpumask_to_str (cpumasks[idx].mask, cpumasks[idx].str, MAX_STR_LENGTH);
return cpumasks[idx].str;
@@ -465,23 +475,10 @@ char* get_cpus_str(enum cpumask_idx idx, bool refresh)
char* get_cpus_hexstr(enum cpumask_idx idx, bool refresh)
{
- if (!cpumasks[idx].mask)
- return NULL;
-
- if (!CPU_COUNT_S(size_cpumask, cpumasks[idx].mask))
+ int ret = get_cached_value_init(idx, refresh, &cpumasks[idx].hexstr, "HEXSTR");
+ if (ret)
return NULL;
- if (cpumasks[idx].hexstr) {
- /* Already was allocated, it's okay to use the cached version */
- if (!refresh)
- return cpumasks[idx].hexstr;
- } else {
- cpumasks[idx].hexstr = calloc (MAX_STR_LENGTH, 1);
- }
-
- if (!cpumasks[idx].hexstr)
- err (3, "STR_ALLOC");
-
cpumask_to_hexstr (cpumasks[idx].mask, cpumasks[idx].hexstr, MAX_STR_LENGTH);
return cpumasks[idx].hexstr;
}
@@ -489,23 +486,12 @@ char* get_cpus_hexstr(enum cpumask_idx idx, bool refresh)
static char* get_cpus_str_reverse(enum cpumask_idx idx, bool refresh)
{
cpu_set_t *mask;
+ int ret;
- if (!cpumasks[idx].mask)
- return NULL;
-
- if (!CPU_COUNT_S(size_cpumask, cpumasks[idx].mask))
+ ret = get_cached_value_init(idx, refresh, &cpumasks[idx].str_reverse, "STR_REVERSE");
+ if (ret)
return NULL;
- if (cpumasks[idx].str_reverse) {
- if (!refresh)
- return cpumasks[idx].str_reverse;
- } else {
- cpumasks[idx].str_reverse = calloc (MAX_STR_LENGTH, 1);
- }
-
- if (!cpumasks[idx].str_reverse)
- err (3, "STR_ALLOC");
-
alloc_cpu_set (&mask);
CPU_XOR_S(size_cpumask, mask, cpumasks[idx].mask, cpumasks[CPUMASK_ONLINE].mask);
cpumask_to_str (mask, cpumasks[idx].str_reverse, MAX_STR_LENGTH);
--
2.55.0

View File

@ -0,0 +1,76 @@
From c01f695e4c8fcb23696db7e39c430c7605a15361 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Mon, 16 Mar 2026 20:01:16 +0100
Subject: [PATCH 49/56] lpmd_proc: Export the state name when an empty cpumask
is caught
Blacklisting CPUs can result in empty cpumask if some other cgroup
claims all cores present in a given cpumask. A warning without the state
name is not very useful for the user that might want to debug this.
Try matching the state name by the cpumask idx. It should work for user
defined states as they receive unique cpumask indexes.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/include/lpmd.h | 2 ++
src/lpmd_cpumask.c | 3 ++-
src/lpmd_proc.c | 15 +++++++++++++++
3 files changed, 19 insertions(+), 1 deletion(-)
diff --git a/src/include/lpmd.h b/src/include/lpmd.h
index 2e9ff33..cab53b0 100644
--- a/src/include/lpmd.h
+++ b/src/include/lpmd.h
@@ -329,6 +329,8 @@ void lpmd_set_auto(void);
int is_on_battery(void);
int get_ppd_mode(void);
+char *user_cpumask_idx_to_state_name(enum cpumask_idx idx);
+
/* lpmd_proc.c: init func */
int lpmd_main(void);
void update_reason(int reason);
diff --git a/src/lpmd_cpumask.c b/src/lpmd_cpumask.c
index 2a446cf..3d6a22b 100644
--- a/src/lpmd_cpumask.c
+++ b/src/lpmd_cpumask.c
@@ -572,7 +572,8 @@ int cpumask_blacklist(enum cpumask_idx idx)
cpumasks[idx].hexvals = get_cpus_hexvals(idx, true);
if (!CPU_COUNT_S(size_cpumask, cpumasks[idx].mask)) {
- lpmd_log_error("%s : cpumask[%d] is empty after blacklisting due to unavailable cpus\n", cpumasks[idx].name, idx);
+ char *state_name = user_cpumask_idx_to_state_name(idx);
+ lpmd_log_error("%s: cpumask[%d] is empty after blacklisting due to unavailable cpus\n", state_name, idx);
lpmd_log_error("It's possible another cgroup claimed all cores required by cpumask[%d]\n", idx);
}
diff --git a/src/lpmd_proc.c b/src/lpmd_proc.c
index 91d1d15..3c3fafb 100644
--- a/src/lpmd_proc.c
+++ b/src/lpmd_proc.c
@@ -298,6 +298,21 @@ void update_reason(int reason)
lpmd_config.data.need_update |= 1 << reason;
}
+/*
+ * This function should only work for user defined states - the ones located in
+ * config files inside the <State> tag. Others like the default ones can share
+ * their cpumasks with other states and therefore can't be uniquely identified
+ * by their cpumask idx.
+ */
+char *user_cpumask_idx_to_state_name(enum cpumask_idx idx) {
+
+ for (int i = 0 ; i < MAX_STATES ; i++) {
+ if (lpmd_config.config_states[i].cpumask_idx == idx)
+ return lpmd_config.config_states[i].name;
+ }
+ return NULL;
+}
+
// LPMD processing thread. This is callback to pthread lpmd_core_main
static void* lpmd_core_main_loop(void *arg)
{
--
2.55.0

View File

@ -0,0 +1,57 @@
From 978e8f1efe56b1b01e93c159ca4b612f1ba244c6 Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Mon, 20 Apr 2026 10:53:59 -0700
Subject: [PATCH 50/56] Use return value of lpmd_read_int()
Don't ignore return value of lpmd_read_int(). Return error to caller
to handle.
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
src/lpmd_misc.c | 6 ++++--
src/lpmd_state_machine.c | 4 ++--
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/lpmd_misc.c b/src/lpmd_misc.c
index 77725e4..b0def2b 100644
--- a/src/lpmd_misc.c
+++ b/src/lpmd_misc.c
@@ -381,6 +381,7 @@ static char *get_ppd_default_epp(void)
int get_epp_epb(int *epp, char *epp_str, int size, int *epb)
{
char path[MAX_STR_LENGTH];
+ int ret;
*epp = -1;
epp_str[0] = '\0';
@@ -389,9 +390,10 @@ int get_epp_epb(int *epp, char *epp_str, int size, int *epb)
get_epp (path, epp, epp_str, size);
epp_str[size - 1] = '\0';
+ *epb = -1;
snprintf(path, MAX_STR_LENGTH, "/sys/devices/system/cpu/cpu%d/power/energy_perf_bias", 0);
- lpmd_read_int(path, epb, -1);
- return 0;
+ ret = lpmd_read_int(path, epb, -1);
+ return ret;
}
int process_epp_epb(lpmd_config_state_t *state)
diff --git a/src/lpmd_state_machine.c b/src/lpmd_state_machine.c
index 8964b9a..9927377 100644
--- a/src/lpmd_state_machine.c
+++ b/src/lpmd_state_machine.c
@@ -376,8 +376,8 @@ static void dump_data(lpmd_config_t *config, int idx)
offset += snprintf(buf + offset , MAX_STR_LENGTH - offset, "ITMT [%d] ", get_itmt());
- get_epp_epb(&epp, epp_str, 32, &epb);
- if (epp == -1)
+ int ret = get_epp_epb(&epp, epp_str, 32, &epb);
+ if (ret || epp == -1)
offset += snprintf(buf + offset , MAX_STR_LENGTH - offset, "EPB [%d] EPP[%s] ", epb, epp_str);
else
offset += snprintf(buf + offset , MAX_STR_LENGTH - offset, "EPB [%d] EPP[%d] ", epb, epp);
--
2.55.0

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,209 @@
From 3ae7d167215da71489b54f84de15562444677a3d Mon Sep 17 00:00:00 2001
From: "Fabio M. De Francesco" <fabio.m.de.francesco@linux.intel.com>
Date: Fri, 5 Jun 2026 12:54:48 -0700
Subject: [PATCH 52/56] Add a simple Makefile to use without autotools
Kernel tools don't use the autogen system and a smaller, simpler build
system makes things easier to install, there are less dependencies.
Use the same logic to create a Makefile.simple.
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Fabio M. De Francesco <fabio.m.de.francesco@linux.intel.com>
Tested-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
[Srinivas- Kept autotools Makefiles for easy migrations for current distro]
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
Makefile.simple | 179 ++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 179 insertions(+)
create mode 100644 Makefile.simple
diff --git a/Makefile.simple b/Makefile.simple
new file mode 100644
index 0000000..652c14b
--- /dev/null
+++ b/Makefile.simple
@@ -0,0 +1,179 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Install paths (matching automake defaults)
+prefix ?= /usr/local
+sbindir ?= $(prefix)/sbin
+confdir ?= $(prefix)/etc/intel_lpmd
+rundir ?= $(prefix)/var/run/intel_lpmd
+systemd_unitdir ?= /usr/lib/systemd/system
+dbus_sysdir ?= /etc/dbus-1/system.d
+mandir ?= $(prefix)/share/man
+
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(CURDIR)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+endif
+
+# Do not use make's built-in rules
+MAKEFLAGS += -r
+
+VERSION = 0.1.0
+
+# pkg-config dependencies
+ifeq ($(shell pkg-config --exists glib-2.0 gio-2.0 gio-unix-2.0 gmodule-2.0 && echo yes),yes)
+ GLIB_CFLAGS := $(shell pkg-config --cflags glib-2.0 gio-2.0 gio-unix-2.0 gmodule-2.0)
+ GLIB_LIBS := $(shell pkg-config --libs glib-2.0 gio-2.0 gio-unix-2.0 gmodule-2.0)
+else
+ $(error No glib-2.0 pkg-config found, please install libglib2.0-dev/glib2-devel)
+endif
+
+ifeq ($(shell pkg-config --exists libxml-2.0 && echo yes),yes)
+ XML2_CFLAGS := $(shell pkg-config --cflags libxml-2.0)
+ XML2_LIBS := $(shell pkg-config --libs libxml-2.0)
+else
+ $(error No libxml-2.0 pkg-config found, please install libxml2-dev/libxml2-devel)
+endif
+
+ifeq ($(shell pkg-config --exists upower-glib && echo yes),yes)
+ UPOWER_CFLAGS := $(shell pkg-config --cflags upower-glib)
+ UPOWER_LIBS := $(shell pkg-config --libs upower-glib)
+else
+ $(error No upower-glib pkg-config found, please install libupower-glib-dev/upower-devel)
+endif
+
+ifeq ($(shell pkg-config --exists libnl-3.0 libnl-genl-3.0 && echo yes),yes)
+ NL3_CFLAGS := $(shell pkg-config --cflags libnl-3.0 libnl-genl-3.0)
+ NL3_LIBS := $(shell pkg-config --libs libnl-3.0 libnl-genl-3.0)
+else
+ $(error No libnl-3.0 pkg-config found, please install libnl-3-dev libnl-genl-3-dev/libnl3-devel)
+endif
+
+ifeq ($(shell pkg-config --exists libsystemd && echo yes),yes)
+ SYSTEMD_CFLAGS := $(shell pkg-config --cflags libsystemd)
+ SYSTEMD_LIBS := $(shell pkg-config --libs libsystemd)
+else
+ $(error No libsystemd pkg-config found, please install libsystemd-dev/systemd-devel)
+endif
+
+override CFLAGS += -O2 -Wall -g -DGDBUS=1 \
+ -DGLIB_SUPPORT \
+ -DGETTEXT_PACKAGE=\"intel_lpmd\" \
+ -DPACKAGE_VERSION=\"$(VERSION)\" \
+ -DTDCONFDIR=\"$(confdir)\" \
+ -DTDRUNDIR=\"$(rundir)\" \
+ -DTDLOCALEDIR=\"$(prefix)/share/locale\" \
+ -I. -Isrc/include -Isrc/wlt_proxy/include \
+ $(GLIB_CFLAGS) $(XML2_CFLAGS) $(UPOWER_CFLAGS) $(NL3_CFLAGS) $(SYSTEMD_CFLAGS)
+
+override LDFLAGS += \
+ $(GLIB_LIBS) $(XML2_LIBS) $(UPOWER_LIBS) $(NL3_LIBS) $(SYSTEMD_LIBS) -lm
+
+# Source files
+LPMD_SRCS = \
+ src/lpmd_cgroup.c \
+ src/lpmd_config.c \
+ src/lpmd_cpu.c \
+ src/lpmd_cpumask.c \
+ src/lpmd_dbus_server.c \
+ src/lpmd_helpers.c \
+ src/lpmd_hfi.c \
+ src/lpmd_irq.c \
+ src/lpmd_main.c \
+ src/lpmd_misc.c \
+ src/lpmd_proc.c \
+ src/lpmd_socket.c \
+ src/lpmd_state_machine.c \
+ src/lpmd_uevent.c \
+ src/lpmd_util.c \
+ src/lpmd_wlt.c \
+ src/wlt_proxy/spike_mgmt.c \
+ src/wlt_proxy/state_machine.c \
+ src/wlt_proxy/state_manager.c \
+ src/wlt_proxy/state_util.c \
+ src/wlt_proxy/wlt_proxy.c
+
+LPMD_OBJS = $(LPMD_SRCS:.c=.o) lpmd-resource.o
+CTRL_OBJS = tools/intel_lpmd_control.o
+
+ALL_TARGETS := intel_lpmd intel_lpmd_control
+ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
+
+all: $(ALL_PROGRAMS)
+
+# Generated files
+config.h: FORCE
+ $(QUIET_GEN)echo '/* Auto-generated - do not edit */' > $@ && \
+ echo '#define GDBUS 1' >> $@ && \
+ echo '#define GETTEXT_PACKAGE "intel_lpmd"' >> $@ && \
+ echo '#define PACKAGE_VERSION "$(VERSION)"' >> $@
+
+lpmd-resource.c: lpmd-resource.gresource.xml src/intel_lpmd_dbus_interface.xml
+ $(QUIET_GEN)glib-compile-resources --sourcedir=. --generate-source \
+ --target=$@ $<
+
+prepare: config.h lpmd-resource.c
+
+%.o: %.c | prepare
+ $(Q)mkdir -p $(dir $@)
+ $(QUIET_CC)$(CC) $(CFLAGS) -c -o $@ $<
+
+$(OUTPUT)intel_lpmd: $(LPMD_OBJS)
+ $(QUIET_LINK)$(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@
+
+$(OUTPUT)intel_lpmd_control: $(CTRL_OBJS)
+ $(QUIET_LINK)$(CC) $(CFLAGS) $< $(GLIB_LIBS) -o $@
+
+$(OUTPUT)intel_lpmd_focus_helper: $(FOCUS_OBJS)
+ $(QUIET_LINK)$(CC) $(CFLAGS) $< $(GLIB_LIBS) -o $@
+
+DATA_CONFIGS = \
+ data/intel_lpmd_config.xml \
+ data/intel_lpmd_config_examples.xml \
+ data/intel_lpmd_config_experimental.xml \
+ data/intel_lpmd_config_F6_M170.xml \
+ data/intel_lpmd_config_F6_M189.xml \
+ data/intel_lpmd_config_F6_M204.xml
+
+MAN_PAGES = \
+ man/intel_lpmd.8 \
+ man/intel_lpmd_control.8 \
+ man/intel_lpmd_config.xml.5
+
+install: $(ALL_PROGRAMS)
+ install -d -m 755 $(DESTDIR)$(sbindir)
+ install $(OUTPUT)intel_lpmd $(DESTDIR)$(sbindir)
+ install $(OUTPUT)intel_lpmd_control $(DESTDIR)$(sbindir)
+ install -d -m 755 $(DESTDIR)$(confdir)
+ install -m 644 $(DATA_CONFIGS) $(DESTDIR)$(confdir)
+ install -d -m 755 $(DESTDIR)$(rundir)
+ install -d -m 755 $(DESTDIR)$(systemd_unitdir)
+ sed 's|@sbindir@|$(sbindir)|g' data/intel_lpmd.service.in > \
+ $(DESTDIR)$(systemd_unitdir)/intel_lpmd.service
+ install -d -m 755 $(DESTDIR)$(dbus_sysdir)
+ install -m 644 data/org.freedesktop.intel_lpmd.conf $(DESTDIR)$(dbus_sysdir)
+ install -d -m 755 $(DESTDIR)$(mandir)/man5
+ install -m 644 man/intel_lpmd_config.xml.5 $(DESTDIR)$(mandir)/man5/
+ install -d -m 755 $(DESTDIR)$(mandir)/man8
+ install -m 644 man/intel_lpmd.8 $(DESTDIR)$(mandir)/man8/
+ install -m 644 man/intel_lpmd_control.8 $(DESTDIR)$(mandir)/man8/
+
+uninstall:
+ rm -f $(DESTDIR)$(sbindir)/intel_lpmd
+ rm -f $(DESTDIR)$(sbindir)/intel_lpmd_control
+ rm -rf $(DESTDIR)$(confdir)
+ rm -f $(DESTDIR)$(systemd_unitdir)/intel_lpmd.service
+ rm -f $(DESTDIR)$(dbus_sysdir)/org.freedesktop.intel_lpmd.conf
+ rm -f $(DESTDIR)$(mandir)/man5/intel_lpmd_config.xml.5
+ rm -f $(DESTDIR)$(mandir)/man8/intel_lpmd.8
+ rm -f $(DESTDIR)$(mandir)/man8/intel_lpmd_control.8
+ @echo "Note: $(DESTDIR)$(rundir) not removed (may contain runtime data)"
+
+clean:
+ rm -f $(ALL_PROGRAMS) config.h lpmd-resource.c
+ find $(or $(OUTPUT),.) -name '*.o' -delete -o -name '\.*.d' -delete
+
+FORCE:
+
+.PHONY: all install uninstall clean FORCE prepare
--
2.55.0

View File

@ -0,0 +1,42 @@
From ca4a67ede41f896407946c56563d56ad4c136682 Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Tue, 19 May 2026 15:44:01 +0200
Subject: [PATCH 53/56] Minor printf formatting fixes
Two small bugs for formatting found by copilot.
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/lpmd_helpers.c | 2 +-
src/lpmd_state_machine.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/lpmd_helpers.c b/src/lpmd_helpers.c
index 3bcd55a..a90df40 100644
--- a/src/lpmd_helpers.c
+++ b/src/lpmd_helpers.c
@@ -296,7 +296,7 @@ int lpmd_read_yn(const char *name, int *val, int print_level)
}
if (print_level >= 0)
- lpmd_log_debug("%sRead \"%c\" from %s\n", prefix, *val, name);
+ lpmd_log_debug("%sRead \"%d\" from %s\n", prefix, *val, name);
return 0;
}
diff --git a/src/lpmd_state_machine.c b/src/lpmd_state_machine.c
index 833d98d..ed7d4dd 100644
--- a/src/lpmd_state_machine.c
+++ b/src/lpmd_state_machine.c
@@ -250,7 +250,7 @@ static void dump_state(struct lpmd_config_state_t *state, char *str, int debug)
offset += snprintf(buf + offset, MAX_STR_LENGTH - offset,
"SliderAC [%d] ", state->balance_slider_ac);
offset += snprintf(buf + offset, MAX_STR_LENGTH - offset,
- "SliderDC [%d] ", state->balance_slider_ac);
+ "SliderDC [%d] ", state->balance_slider_dc);
offset += snprintf(buf + offset, MAX_STR_LENGTH - offset,
"OffsetAC [%d] ", state->slider_offset_ac);
offset += snprintf(buf + offset, MAX_STR_LENGTH - offset,
--
2.55.0

View File

@ -0,0 +1,28 @@
From 86b4fabadf89ac00d93e179c21ffe8a48c76653e Mon Sep 17 00:00:00 2001
From: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
Date: Fri, 22 May 2026 11:43:24 +0200
Subject: [PATCH 54/56] lpmd_config: Fix compilation warning on buffer size
Fix unnecessary -1 in strncpy() by moving it over to snprintf().
Signed-off-by: Maciej Wieczor-Retman <maciej.wieczor-retman@intel.com>
---
src/lpmd_config.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/lpmd_config.c b/src/lpmd_config.c
index b6ae995..444ee98 100644
--- a/src/lpmd_config.c
+++ b/src/lpmd_config.c
@@ -571,7 +571,7 @@ int lpmd_get_config(struct lpmd_config_t *lpmd_config)
return LPMD_ERROR;
}
- strncpy(lpmd_config->file_name, file_name, MAX_FILE_NAME_PATH - 1);
+ snprintf(lpmd_config->file_name, MAX_FILE_NAME_PATH, "%s", file_name);
process_xml:
doc = xmlReadFile(file_name, NULL, 0);
--
2.55.0

View File

@ -0,0 +1,34 @@
From df3a7214656e66972c9bec68fa937fbae4bfb633 Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Thu, 28 May 2026 16:53:07 -0700
Subject: [PATCH 55/56] Fix cpumask_exclude_copy destination population
cpumask_exclude_copy() reset the destination mask and filtered
excluded CPUs, but never added the remaining CPUs to the destination.
That left the result empty for the HFI banned-CPU path.
Add the missing cpumask_add_cpu() call so CPUMASK_HFI is built as
online CPUs minus banned CPUs, and the resulting mask can be applied
correctly by the HFI state flow.
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
src/lpmd_cpumask.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/lpmd_cpumask.c b/src/lpmd_cpumask.c
index fc87371..6b70fed 100644
--- a/src/lpmd_cpumask.c
+++ b/src/lpmd_cpumask.c
@@ -357,6 +357,8 @@ void cpumask_exclude_copy(enum cpumask_idx source, enum cpumask_idx dest, enum c
if (CPU_ISSET_S(i, size_cpumask, cpumasks[exclude].mask))
continue;
+
+ cpumask_add_cpu(i, dest);
}
}
--
2.55.0

View File

@ -0,0 +1,35 @@
From 89d706eca1a17f466a5875ff2743dd4decddb536 Mon Sep 17 00:00:00 2001
From: "Pandruvada, Srinivas" <srinivas.pandruvada@intel.com>
Date: Mon, 8 Jun 2026 11:54:09 -0700
Subject: [PATCH 56/56] When GFX trigger is enabled don't disable util
calculation
When GFX util is used as trigger in a state, it can be used along
with WLT with polling enabled. This is done for Lunar Lake config
file.
So, don't reset lpmd_config.util_enable = 0 when wlt_polling is
enabled and there is a GFX util trigger in a state.
Signed-off-by: Pandruvada, Srinivas <srinivas.pandruvada@intel.com>
---
src/lpmd_proc.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/lpmd_proc.c b/src/lpmd_proc.c
index a459fda..2c4e335 100644
--- a/src/lpmd_proc.c
+++ b/src/lpmd_proc.c
@@ -475,7 +475,8 @@ int lpmd_main(void)
}
if (lpmd_config.wlt_hint_enable && !lpmd_config.hfi_lpm_enable) {
- lpmd_config.util_enable = 0;
+ if (!lpmd_config.util_gfx_enable && lpmd_config.wlt_hint_poll_enable)
+ lpmd_config.util_enable = 0;
if (!lpmd_config.wlt_proxy_enable) {
poll_fds[poll_fd_cnt].fd = wlt_init();
if (poll_fds[poll_fd_cnt].fd > 0) {
--
2.55.0

View File

@ -1,23 +1,72 @@
%global daemon_name intel_lpmd
Name: intel-lpmd
Version: 0.0.9
Version: 0.1.0
Release: 1%{?dist}
Summary: Intel Low Power Mode Daemon
License: GPL-2.0-or-later
URL: https://github.com/intel/intel-lpmd
Source0: %{url}/archive/v%{version}/%{name}-%{version}.tar.gz
# Drop unused variables https://github.com/intel/intel-lpmd/pull/93
# https://github.com/intel/intel-lpmd/commit/c2cea33c873146f1b6186c02fe79d1a2bb1c7867.patch
Patch1001: 0001-lpmd_util-Remove-unused-variables.patch
# https://github.com/intel/intel-lpmd/commit/311b7929d4c821630fabf5293ec5b4bec5411162.patch
Patch1002: 0002-wlt_proxy-state_manager-Fix-Werror-switch.patch
# https://github.com/intel/intel-lpmd/commit/4277f3496dc51f89ed0815e0f51659338f7a6ba9.patch
Patch1003: 0003-wlt_proxy-state_util-Remove-unused-variables.patch
# https://github.com/intel/intel-lpmd/commit/af6d8f93a0a1041bd936b8901707e1253c5e5279.patch
Patch1004: 0004-wlt_proxy-state_util-Drop-unused-function-read_tsc_c.patch
# Rebase to the latest commits
Patch1001: 0001-Deprecate-the-dbus-glib-dependency-at-Install-Depend.patch
Patch1002: 0002-lpmd_cpu-Tablets-are-also-a-Mobile-platform.patch
Patch1003: 0003-build-replace-open-coded-if-in-configure.ac-with-AS_.patch
Patch1004: 0004-build-avoid-use-of-test-.-a.patch
Patch1005: 0005-build-fix-spelling-in-error-message-when-libsystemd-.patch
Patch1006: 0006-build-apply-consistent-argument-quoting-in-configure.patch
Patch1007: 0007-lpmd_cgroup-simple-isolation-fix-works-without-inter.patch
Patch1008: 0008-state_machine-Fix-issue-106-incorrect-order-of-polli.patch
Patch1009: 0009-lpmd_state_machine-Fix-deadlock-on-power-profile-swi.patch
Patch1010: 0010-Process-itmt-read-error.patch
Patch1011: 0011-lpmd_misc-Fix-ITMT.patch
Patch1012: 0012-make-itmt_init-to-void.patch
Patch1013: 0013-config-Fix-incorrect-cpu-numbers.patch
Patch1014: 0014-readme-Reformat-long-lines-into-markdown-readable-bl.patch
Patch1015: 0015-readme-Emphasize-expectations-from-the-user.patch
Patch1016: 0016-man-Update-the-main-man-page.patch
Patch1017: 0017-man-Update-lpmd-control-utility-man-page.patch
Patch1018: 0018-man-Generic-updates-to-the-config-man-page.patch
Patch1019: 0019-man-Move-unused-config-options-to-the-unused-section.patch
Patch1020: 0020-Add-Panther-Lake-4P0E4L.patch
Patch1021: 0021-Remove-power-group.patch
Patch1022: 0022-Add-GetState-D-Bus-method-to-query-current-LPM-contr.patch
Patch1023: 0023-fix-restore-systemd-unit-install-path.patch
Patch1024: 0024-fix-prevent-cgroup-isolation-churn-during-WLT-pollin.patch
Patch1025: 0025-Fix-build-breakage-with-the-last-commit.patch
Patch1026: 0026-git-Setup-gitignore.patch
Patch1027: 0027-lpmd_config-Cleanup-code-indentation-in-parse-states.patch
Patch1028: 0028-lpmd_config-Rename-island-number-cores-tags.patch
Patch1029: 0029-lpmd_state_machine-Count-system-of-specifing-active-.patch
Patch1030: 0030-lpmd_cpumask-Dynamic-core-type-cpumask-allocation.patch
Patch1031: 0031-lpmd_config-ALL-keyword-for-active-P-E-L-cores-tag.patch
Patch1032: 0032-config-Simplify-the-M204-configuration.patch
Patch1033: 0033-lpmd_cpu-Fix-incorrect-struct-initialization.patch
Patch1034: 0034-Introduce-WLT-state-mask-and-notification-delay.patch
Patch1035: 0035-Arrow-Lake-enabling.patch
Patch1036: 0036-lpmd_config-Skip-platform-check-if-a-matching-config.patch
Patch1037: 0037-config-Nova-Lake-enabling.patch
Patch1038: 0038-lpmd_cpu-Add-wildcard-for-active_cpus-and-cpu-types.patch
Patch1039: 0039-data-Fix-active-cpu-spelling.patch
Patch1040: 0040-Enable-platform-agnostic-config-fallback-for-unknown.patch
Patch1041: 0041-docs-Clarify-slider-config.patch
Patch1042: 0042-Validate-slider-balance-and-offset-configuration.patch
Patch1043: 0043-lpmd_cpumask-Refactor-get_cgroup_systemd_vals-to-avo.patch
Patch1044: 0044-lpmd_cpu-Add-a-CPU-blacklist-cpumask.patch
Patch1045: 0045-lpmd_cpu-Skip-filling-out-type-cpumasks-if-there-was.patch
Patch1046: 0046-lpmd_cpumask-init-level-complex-isolation-fix-blackl.patch
Patch1047: 0047-lpmd_cpumask-Refresh-cached-data-when-blacklisting-c.patch
Patch1048: 0048-lpmd_cpumask-Refactor-getting-cached-values.patch
Patch1049: 0049-lpmd_proc-Export-the-state-name-when-an-empty-cpumas.patch
Patch1050: 0050-Use-return-value-of-lpmd_read_int.patch
Patch1051: 0051-all-Apply-kernel-formatting.patch
Patch1052: 0052-Add-a-simple-Makefile-to-use-without-autotools.patch
Patch1053: 0053-Minor-printf-formatting-fixes.patch
Patch1054: 0054-lpmd_config-Fix-compilation-warning-on-buffer-size.patch
Patch1055: 0055-Fix-cpumask_exclude_copy-destination-population.patch
Patch1056: 0056-When-GFX-trigger-is-enabled-don-t-disable-util-calcu.patch
ExclusiveArch: x86_64
@ -57,6 +106,8 @@ autoreconf --install --verbose
%install
%make_install
install -D -p -m 644 src/%{daemon_name}_dbus_interface.xml %{buildroot}/%{_datadir}/dbus-1/interfaces/org.freedesktop.%{daemon_name}.xml
# Nova lake config
install -D -p -m 644 data/intel_lpmd_config_F18_M1.xml %{buildroot}/%{_sysconfdir}/%{daemon_name}/intel_lpmd_config_F18_M1.xml
%post
%systemd_post %{daemon_name}.service
@ -76,6 +127,10 @@ install -D -p -m 644 src/%{daemon_name}_dbus_interface.xml %{buildroot}/%{_datad
%config(noreplace) %{_sysconfdir}/%{daemon_name}/%{daemon_name}_config.xml
%config(noreplace) %{_sysconfdir}/%{daemon_name}/intel_lpmd_config_F6_M170.xml
%config(noreplace) %{_sysconfdir}/%{daemon_name}/intel_lpmd_config_F6_M189.xml
%config(noreplace) %{_sysconfdir}/%{daemon_name}/intel_lpmd_config_F6_M181.xml
%config(noreplace) %{_sysconfdir}/%{daemon_name}/intel_lpmd_config_F6_M204.xml
%config(noreplace) %{_sysconfdir}/%{daemon_name}/intel_lpmd_config_F18_M1.xml
%{_datadir}/dbus-1/interfaces/org.freedesktop.%{daemon_name}.xml
%{_datadir}/dbus-1/system.d/org.freedesktop.%{daemon_name}.conf
%{_datadir}/dbus-1/system-services/org.freedesktop.%{daemon_name}.service

View File

@ -1 +1 @@
SHA512 (intel-lpmd-0.0.9.tar.gz) = ed7977960b9794e0fd9ba46f37f3aaaee4082ad4c884a69855faa75b6b3b2c1ac13992bbc808c88460717455144ef54da89b21de58773283259752ad88f1f03b
SHA512 (intel-lpmd-0.1.0.tar.gz) = 45f18b7c98814af6f56659fcf63d32cfb3df3daa93bb6561b271094d5a2d91d50589a50475ae3b59aaeaca489e76a45879754a74af0dad443686697269f8b51d