* [PATCH v3 0/7] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface
@ 2026-03-01 13:11 Shyam Sundar S K
2026-03-01 13:11 ` [PATCH v3 1/7] platform/x86/amd/pmf: Add util layer and userspace misc device interface Shyam Sundar S K
` (7 more replies)
0 siblings, 8 replies; 30+ messages in thread
From: Shyam Sundar S K @ 2026-03-01 13:11 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami, Shyam Sundar S K
This patch series introduces a new util layer for the AMD Platform
Management Framework (PMF) driver that exposes a minimal userspace
interface for metrics monitoring and feature discovery.
AMD PMF currently manages power and thermal policies internally through
Smart PC features, Auto Mode, Policy Builder, Static/Dynamic Power
Sliders. However, system designers and OEMs need visibility into PMF
metrics and feature status for validation, debugging, and integration
with monitoring tools.
This series addresses that need by adding a character device interface
that allows controlled access to PMF metrics data while maintaining
the driver's existing automated policy management.
The primary use case is integration with userspace tools like AMD
SystemDeck, which are widely used by system designers to:
- Monitor real-time power and thermal behavior
- Validate PMF feature operation during platform bring-up
- Debug thermal issues by tracking skin temperature, C-state residency,
and socket power metrics
- Verify BIOS input/output policy values during Smart PC operation
The util layer reads from the existing Trusted Application (TA) shared
memory buffer and cached BIOS output values, adding no new communication
overhead with the TA.
v3:
- Stop exporting battery information via util layer.
- Optimize the core logic for fetching BIOS outputs.
- Update the documentation patch to reflect the current util layer design.
- Consolidate amd-pmf-io.h changes into common UAPI header.
- Define a single unified uAPI structure and IOCTL.
- Address other v2 review remarks [1]
v2:
- address remarks from v1
- add a new tool that exercises the IOCTLs from PMF interface
[1] https://lore.kernel.org/platform-driver-x86/20251111071010.4179492-1-Shyam-sundar.S-k@amd.com/
Shyam Sundar S K (7):
platform/x86/amd/pmf: Add util layer and userspace misc device
interface
platform/x86/amd/pmf: cache BIOS output values for user-space metrics
via util IOCTL
platform/x86/amd/pmf: Add feature discovery support to util interface
platform/x86/amd/pmf: Store commonly used enums in the header file
platform/x86/amd/pmf: Move debug helper functions to UAPI header
platform/x86/amd/pmf: Introduce AMD PMF testing tool for driver
metrics and features
Documentation/ABI: add testing entry for AMD PMF misc device interface
.../ABI/testing/misc-amdpmf_interface | 70 ++++
MAINTAINERS | 1 +
.../amd-sfh-hid/sfh1_1/amd_sfh_interface.c | 1 +
drivers/platform/x86/amd/pmf/Kconfig | 10 +
drivers/platform/x86/amd/pmf/Makefile | 2 +
drivers/platform/x86/amd/pmf/core.c | 8 +
drivers/platform/x86/amd/pmf/pmf.h | 32 +-
drivers/platform/x86/amd/pmf/spc.c | 55 +--
drivers/platform/x86/amd/pmf/tee-if.c | 9 +-
drivers/platform/x86/amd/pmf/util.c | 210 ++++++++++++
include/linux/amd-pmf-io.h | 9 -
include/uapi/linux/amd-pmf.h | 324 ++++++++++++++++++
tools/testing/selftests/Makefile | 1 +
.../drivers/platform/x86/amd/pmf/Makefile | 8 +
.../drivers/platform/x86/amd/pmf/test_pmf.c | 243 +++++++++++++
15 files changed, 897 insertions(+), 86 deletions(-)
create mode 100644 Documentation/ABI/testing/misc-amdpmf_interface
create mode 100644 drivers/platform/x86/amd/pmf/util.c
create mode 100644 include/uapi/linux/amd-pmf.h
create mode 100644 tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile
create mode 100644 tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c
--
2.34.1
^ permalink raw reply [flat|nested] 30+ messages in thread
* [PATCH v3 1/7] platform/x86/amd/pmf: Add util layer and userspace misc device interface
2026-03-01 13:11 [PATCH v3 0/7] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
@ 2026-03-01 13:11 ` Shyam Sundar S K
2026-03-01 18:45 ` Randy Dunlap
` (3 more replies)
2026-03-01 13:11 ` [PATCH v3 2/7] platform/x86/amd/pmf: cache BIOS output values for user-space metrics via util IOCTL Shyam Sundar S K
` (6 subsequent siblings)
7 siblings, 4 replies; 30+ messages in thread
From: Shyam Sundar S K @ 2026-03-01 13:11 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami, Shyam Sundar S K
Add a util layer to AMD PMF that exposes a minimal userspace interface
via a misc character device for metrics monitoring and feature discovery.
This creates /dev/amdpmf_interface with basic ioctl support to retrieve
PMF metrics such as:
*Power source and power slider position
*Platform type, lid state, and user presence
*Skin temperature and ambient light
*BIOS input parameters (1-10)
*Graphics workload metrics
*CPU C-state residency (average and maximum)
*Socket power consumption
The interface enables smoother integration with userspace tools such as
AMD SystemDeck [1], which is widely used for monitoring and controlling
power and thermal behavior on AMD platforms. These tools help designers
keep major components within thermal limits to ensure proper operation
and enhance overall system stability and reliability.
The feature is gated behind the CONFIG_AMD_PMF_UTIL_SUPPORT Kconfig
option, allowing it to be disabled if not needed. The implementation
uses existing PMF infrastructure to populate data from the TA (Trusted
Application) shared memory buffer.
Link: https://docs.amd.com/v/u/en-US/68773_0.50 [1]
Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
---
drivers/platform/x86/amd/pmf/Kconfig | 10 ++
drivers/platform/x86/amd/pmf/Makefile | 2 +
drivers/platform/x86/amd/pmf/core.c | 5 +
drivers/platform/x86/amd/pmf/pmf.h | 9 ++
drivers/platform/x86/amd/pmf/util.c | 174 ++++++++++++++++++++++++++
include/uapi/linux/amd-pmf.h | 115 +++++++++++++++++
6 files changed, 315 insertions(+)
create mode 100644 drivers/platform/x86/amd/pmf/util.c
create mode 100644 include/uapi/linux/amd-pmf.h
diff --git a/drivers/platform/x86/amd/pmf/Kconfig b/drivers/platform/x86/amd/pmf/Kconfig
index 25b8f7ae3abd..ad21f679b8ab 100644
--- a/drivers/platform/x86/amd/pmf/Kconfig
+++ b/drivers/platform/x86/amd/pmf/Kconfig
@@ -30,3 +30,13 @@ config AMD_PMF_DEBUG
in the PMF config store.
Say Y here to enable more debug logs and Say N here if you are not sure.
+
+config AMD_PMF_UTIL_SUPPORT
+ bool "AMD PMF Util layer support"
+ depends on AMD_PMF
+ help
+ Enabling this option provides a character device for userspace to capture
+ PMF features (Smart PC Builder, Auto Mode, Static Power Slider, Dynamic
+ Power Slider AC/DC) along with PMF metrics from the AMD PMF driver.
+
+ Say Y here to enable it and Say N here if you are not sure.
diff --git a/drivers/platform/x86/amd/pmf/Makefile b/drivers/platform/x86/amd/pmf/Makefile
index 5978464e0eb7..bf7aad80b9e9 100644
--- a/drivers/platform/x86/amd/pmf/Makefile
+++ b/drivers/platform/x86/amd/pmf/Makefile
@@ -8,3 +8,5 @@ obj-$(CONFIG_AMD_PMF) += amd-pmf.o
amd-pmf-y := core.o acpi.o sps.o \
auto-mode.o cnqf.o \
tee-if.o spc.o
+# Build util.c only when AMD_PMF_UTIL_SUPPORT is enabled
+amd-pmf-$(CONFIG_AMD_PMF_UTIL_SUPPORT) += util.o
diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
index b9e5a2cf3aae..919d02f30aae 100644
--- a/drivers/platform/x86/amd/pmf/core.c
+++ b/drivers/platform/x86/amd/pmf/core.c
@@ -634,6 +634,10 @@ static int amd_pmf_probe(struct platform_device *pdev)
pmf_device = dev->dev;
+ err = amd_pmf_cdev_register(dev);
+ if (err)
+ dev_warn(dev->dev, "failed to register util interface: %d\n", err);
+
dev_info(dev->dev, "registered PMF device successfully\n");
return 0;
@@ -646,6 +650,7 @@ static void amd_pmf_remove(struct platform_device *pdev)
amd_pmf_deinit_features(dev);
if (is_apmf_func_supported(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_UNLOAD);
+ amd_pmf_cdev_unregister();
apmf_acpi_deinit(dev);
amd_pmf_dbgfs_unregister(dev);
}
diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
index 69fef7448744..6f61076a9386 100644
--- a/drivers/platform/x86/amd/pmf/pmf.h
+++ b/drivers/platform/x86/amd/pmf/pmf.h
@@ -928,4 +928,13 @@ int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid);
void amd_pmf_tee_deinit(struct amd_pmf_dev *dev);
int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev);
+/* Util Layer */
+#if IS_ENABLED(CONFIG_AMD_PMF_UTIL_SUPPORT)
+int amd_pmf_cdev_register(struct amd_pmf_dev *dev);
+void amd_pmf_cdev_unregister(void);
+#else
+static inline int amd_pmf_cdev_register(struct amd_pmf_dev *dev) { return 0; }
+static inline void amd_pmf_cdev_unregister(void) {}
+#endif
+
#endif /* PMF_H */
diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
new file mode 100644
index 000000000000..c6837caa44e0
--- /dev/null
+++ b/drivers/platform/x86/amd/pmf/util.c
@@ -0,0 +1,174 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD Platform Management Framework Util Layer
+ *
+ * Copyright (c) 2026, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+ * Sanket Goswami <Sanket.Goswami@amd.com>
+ */
+
+#include <linux/amd-pmf.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
+#include <linux/uaccess.h>
+
+#include "pmf.h"
+
+/* Convert BIOS input control code to array index (0-9) */
+static int amd_pmf_get_bios_idx(u32 control_code)
+{
+ if (control_code >= IOCTL_BIOS_INPUT_1 && control_code <= IOCTL_BIOS_INPUT_10)
+ return control_code - IOCTL_BIOS_INPUT_1;
+
+ return -EINVAL;
+}
+
+static long long amd_pmf_populate_bios_input(struct ta_pmf_enact_table *in, u32 control_code)
+{
+ u32 idx;
+
+ idx = amd_pmf_get_bios_idx(control_code);
+
+ return (idx < 2) ? in->ev_info.bios_input_1[idx] : in->ev_info.bios_input_2[idx - 2];
+}
+
+static long long amd_pmf_device_state(struct ta_pmf_enact_table *in, u32 control_code)
+{
+ switch (control_code) {
+ case IOCTL_PLATFORM_TYPE:
+ return in->ev_info.platform_type;
+ case IOCTL_LAPTOP_PLACEMENT:
+ return in->ev_info.device_state;
+ case IOCTL_LID_STATE:
+ return in->ev_info.lid_state;
+ case IOCTL_USER_PRESENCE:
+ return in->ev_info.user_present;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int amd_pmf_populate_data(struct device *dev, void __user *argp)
+{
+ struct amd_pmf_ioctl_info output = {0};
+ struct ta_pmf_shared_memory *ta_sm = NULL;
+ struct ta_pmf_enact_table *in = NULL;
+ struct amd_pmf_dev *pdev;
+
+ pdev = dev_get_drvdata(dev);
+ if (!pdev)
+ return -EINVAL;
+
+ memset(pdev->shbuf, 0, pdev->policy_sz);
+ ta_sm = pdev->shbuf;
+ in = &ta_sm->pmf_input.enact_table;
+
+ if (copy_from_user(&output, argp, sizeof(output)))
+ return -EFAULT;
+
+ switch (output.control_code) {
+ case IOCTL_POWER_SOURCE:
+ output.val = in->ev_info.power_source;
+ break;
+ case IOCTL_POWER_SLIDER_POSITION:
+ output.val = in->ev_info.power_slider;
+ break;
+ case IOCTL_SKIN_TEMP:
+ /* Convert from centi-degrees to degrees Celsius */
+ output.val = in->ev_info.skin_temperature / 100;
+ break;
+ case IOCTL_PLATFORM_TYPE ... IOCTL_LID_STATE:
+ case IOCTL_USER_PRESENCE:
+ output.val = amd_pmf_device_state(in, output.control_code);
+ break;
+ case IOCTL_BIOS_INPUT_1 ... IOCTL_BIOS_INPUT_10:
+ output.val = amd_pmf_populate_bios_input(in, output.control_code);
+ break;
+ case IOCTL_GFX_WORKLOAD:
+ output.val = in->ev_info.gfx_busy;
+ break;
+ case IOCTL_AMBIENT_LIGHT:
+ output.val = in->ev_info.ambient_light;
+ break;
+ case IOCTL_AVG_C0_RES:
+ output.val = in->ev_info.avg_c0residency;
+ break;
+ case IOCTL_MAX_C0_RES:
+ output.val = in->ev_info.max_c0residency;
+ break;
+ case IOCTL_SOCKET_POWER:
+ output.val = in->ev_info.socket_power;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (copy_to_user(argp, &output, sizeof(output)))
+ return -EFAULT;
+
+ return 0;
+}
+
+#if IS_ENABLED(CONFIG_AMD_PMF_UTIL_SUPPORT)
+static struct amd_pmf_dev *pmf_dev_handle;
+static DEFINE_MUTEX(pmf_util_lock);
+
+static long amd_pmf_set_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ struct amd_pmf_dev *pdev = filp->private_data;
+ void __user *argp = (void __user *)arg;
+
+ if (cmd != IOCTL_PMF_POPULATE_DATA)
+ return -EINVAL;
+
+ guard(mutex)(&pmf_util_lock);
+ return amd_pmf_populate_data(pdev->dev, argp);
+}
+
+static int amd_pmf_open(struct inode *inode, struct file *filp)
+{
+ guard(mutex)(&pmf_util_lock);
+ if (!pmf_dev_handle)
+ return -ENODEV;
+
+ filp->private_data = pmf_dev_handle;
+ return 0;
+}
+
+static const struct file_operations pmf_if_ops = {
+ .owner = THIS_MODULE,
+ .open = amd_pmf_open,
+ .unlocked_ioctl = amd_pmf_set_ioctl,
+};
+
+static struct miscdevice amd_pmf_util_if = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "amdpmf_interface",
+ .fops = &pmf_if_ops,
+};
+
+int amd_pmf_cdev_register(struct amd_pmf_dev *dev)
+{
+ int ret;
+
+ guard(mutex)(&pmf_util_lock);
+ pmf_dev_handle = dev;
+ ret = misc_register(&amd_pmf_util_if);
+ if (ret)
+ pmf_dev_handle = NULL;
+
+ return ret;
+}
+
+void amd_pmf_cdev_unregister(void)
+{
+ guard(mutex)(&pmf_util_lock);
+ pmf_dev_handle = NULL;
+ misc_deregister(&amd_pmf_util_if);
+}
+#else
+int amd_pmf_cdev_register(struct amd_pmf_dev *dev) { return 0; }
+void amd_pmf_cdev_unregister(void) {}
+#endif
diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
new file mode 100644
index 000000000000..d29431c67eaa
--- /dev/null
+++ b/include/uapi/linux/amd-pmf.h
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */
+/*
+ * AMD Platform Management Framework (PMF) UAPI Header
+ *
+ * Copyright (c) 2026, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * This file defines the user-space API for interacting with the AMD PMF
+ * driver. It provides ioctl interfaces to query platform-specific metrics
+ * such as power source, slider position, platform type, laptop placement,
+ * and various BIOS input/output parameters.
+ */
+
+#ifndef _UAPI_LINUX_AMD_PMF_H
+#define _UAPI_LINUX_AMD_PMF_H
+
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+/**
+ * AMD_PMF_IOC_MAGIC - Magic number for AMD PMF ioctl commands
+ *
+ * This magic number uniquely identifies AMD PMF ioctl operations.
+ */
+#define AMD_PMF_IOC_MAGIC 'p'
+
+/**
+ * IOCTL_PMF_POPULATE_DATA - ioctl command to retrieve PMF metrics data
+ *
+ * This ioctl command is used to populate the amd_pmf_ioctl_info structure
+ * with the requested metrics data based on the control_code provided.
+ */
+#define IOCTL_PMF_POPULATE_DATA _IOWR(AMD_PMF_IOC_MAGIC, 0x00, struct amd_pmf_ioctl_info)
+
+/**
+ * enum pmf_ioctl_id - Control codes for PMF ioctl operations
+ * @IOCTL_POWER_SOURCE: Query current power source (AC/DC)
+ * @IOCTL_POWER_SLIDER_POSITION: Query current power slider position
+ * @IOCTL_PLATFORM_TYPE: Query current platform/form factor type
+ * @IOCTL_LAPTOP_PLACEMENT: Query laptop physical placement state
+ * @IOCTL_LID_STATE: Query laptop lid open/close state
+ * @IOCTL_HETERO_STATE: Query heterogeneous computing state
+ * @IOCTL_SKIN_TEMP: Query skin temperature sensor reading
+ * @IOCTL_USER_PRESENCE: Query user presence detection state
+ * @IOCTL_DISPLAY_NUM: Query number of active displays
+ * @IOCTL_USER_ENGAGED: Query user engagement state
+ * @IOCTL_BIOS_INPUT_1: Query BIOS input parameter 1
+ * @IOCTL_BIOS_INPUT_2: Query BIOS input parameter 2
+ * @IOCTL_BIOS_INPUT_3: Query BIOS input parameter 3
+ * @IOCTL_BIOS_INPUT_4: Query BIOS input parameter 4
+ * @IOCTL_BIOS_INPUT_5: Query BIOS input parameter 5
+ * @IOCTL_BIOS_INPUT_6: Query BIOS input parameter 6
+ * @IOCTL_BIOS_INPUT_7: Query BIOS input parameter 7
+ * @IOCTL_BIOS_INPUT_8: Query BIOS input parameter 8
+ * @IOCTL_BIOS_INPUT_9: Query BIOS input parameter 9
+ * @IOCTL_BIOS_INPUT_10: Query BIOS input parameter 10
+ * @IOCTL_GFX_WORKLOAD: Query current graphics workload type
+ * @IOCTL_AMBIENT_LIGHT: Query ambient light sensor reading
+ * @IOCTL_AVG_C0_RES: Query average C0 residency
+ * @IOCTL_MAX_C0_RES: Query maximum C0 residency
+ * @IOCTL_SOCKET_POWER: Query current socket power consumption
+ * @IOCTL_TA_BIN_VER: Query Trusted Application binary version
+ *
+ * These control codes are used with the IOCTL_PMF_POPULATE_DATA ioctl
+ * to specify which metrics data to retrieve from the AMD PMF driver.
+ */
+enum pmf_ioctl_id {
+ IOCTL_POWER_SOURCE,
+ IOCTL_POWER_SLIDER_POSITION,
+ IOCTL_PLATFORM_TYPE,
+ IOCTL_LAPTOP_PLACEMENT,
+ IOCTL_LID_STATE,
+ IOCTL_HETERO_STATE,
+ IOCTL_SKIN_TEMP,
+ IOCTL_USER_PRESENCE,
+ IOCTL_DISPLAY_NUM,
+ IOCTL_USER_ENGAGED,
+ IOCTL_BIOS_INPUT_1,
+ IOCTL_BIOS_INPUT_2,
+ IOCTL_BIOS_INPUT_3,
+ IOCTL_BIOS_INPUT_4,
+ IOCTL_BIOS_INPUT_5,
+ IOCTL_BIOS_INPUT_6,
+ IOCTL_BIOS_INPUT_7,
+ IOCTL_BIOS_INPUT_8,
+ IOCTL_BIOS_INPUT_9,
+ IOCTL_BIOS_INPUT_10,
+ IOCTL_GFX_WORKLOAD,
+ IOCTL_AMBIENT_LIGHT = 29,
+ IOCTL_AVG_C0_RES = 36,
+ IOCTL_MAX_C0_RES,
+ IOCTL_SOCKET_POWER = 50,
+ IOCTL_TA_BIN_VER
+};
+
+/**
+ * struct amd_pmf_ioctl_info - Structure for PMF ioctl data exchange
+ * @control_code: Input parameter specifying which data to query (enum pmf_ioctl_id)
+ * @feature_supported: Output flag indicating if the queried feature is supported
+ * @feature_version: Output field containing the feature version number
+ * @val: Output field containing the queried value
+ *
+ * This structure is used with the IOCTL_PMF_POPULATE_DATA ioctl command
+ * to exchange data between user space and the AMD PMF kernel driver.
+ * The user provides the control_code to specify the query type, and the
+ * driver populates the remaining fields with the response data.
+ */
+struct amd_pmf_ioctl_info {
+ enum pmf_ioctl_id control_code; /* In */
+ bool feature_supported; /* Out */
+ unsigned long feature_version; /* Out */
+ long long val; /* Out */
+};
+
+#endif /* _UAPI_LINUX_AMD_PMF_H */
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 2/7] platform/x86/amd/pmf: cache BIOS output values for user-space metrics via util IOCTL
2026-03-01 13:11 [PATCH v3 0/7] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
2026-03-01 13:11 ` [PATCH v3 1/7] platform/x86/amd/pmf: Add util layer and userspace misc device interface Shyam Sundar S K
@ 2026-03-01 13:11 ` Shyam Sundar S K
2026-03-25 14:08 ` Ilpo Järvinen
2026-03-01 13:11 ` [PATCH v3 3/7] platform/x86/amd/pmf: Add feature discovery support to util interface Shyam Sundar S K
` (5 subsequent siblings)
7 siblings, 1 reply; 30+ messages in thread
From: Shyam Sundar S K @ 2026-03-01 13:11 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami, Shyam Sundar S K
Add a bios_output[] cache to amd_pmf_dev and store the latest values for
BIOS output policies when applying PMF policies. This enables the AMD PMF
util layer to expose these BIOS outputs alongside selected thermal and
power metrics to user space via /dev/amdpmf_interface and a new IOCTL,
supporting real-time monitoring tools such as SystemDeck.
The bios_output array is initialized to zero during device probe, and
bounds checking is added to prevent potential buffer overflows when
caching values.
Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
---
drivers/platform/x86/amd/pmf/core.c | 3 +++
drivers/platform/x86/amd/pmf/pmf.h | 1 +
drivers/platform/x86/amd/pmf/tee-if.c | 9 ++++++++-
drivers/platform/x86/amd/pmf/util.c | 15 +++++++++++++++
include/uapi/linux/amd-pmf.h | 22 +++++++++++++++++++++-
5 files changed, 48 insertions(+), 2 deletions(-)
diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
index 919d02f30aae..b5cab7c937ce 100644
--- a/drivers/platform/x86/amd/pmf/core.c
+++ b/drivers/platform/x86/amd/pmf/core.c
@@ -634,6 +634,9 @@ static int amd_pmf_probe(struct platform_device *pdev)
pmf_device = dev->dev;
+ /* Initialize BIOS output cache for util layer */
+ memset(dev->bios_output, 0, sizeof(dev->bios_output));
+
err = amd_pmf_cdev_register(dev);
if (err)
dev_warn(dev->dev, "failed to register util interface: %d\n", err);
diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
index 6f61076a9386..0d879f0fd8e2 100644
--- a/drivers/platform/x86/amd/pmf/pmf.h
+++ b/drivers/platform/x86/amd/pmf/pmf.h
@@ -442,6 +442,7 @@ struct amd_pmf_dev {
struct pmf_cbi_ring_buffer cbi_buf;
struct mutex cbi_mutex; /* Protects ring buffer access */
struct mutex metrics_mutex;
+ u32 bios_output[10];
};
struct apmf_sps_prop_granular_v2 {
diff --git a/drivers/platform/x86/amd/pmf/tee-if.c b/drivers/platform/x86/amd/pmf/tee-if.c
index 7ccd93f506b2..f749115bf970 100644
--- a/drivers/platform/x86/amd/pmf/tee-if.c
+++ b/drivers/platform/x86/amd/pmf/tee-if.c
@@ -98,10 +98,17 @@ static int amd_pmf_get_bios_output_idx(u32 action_idx)
static void amd_pmf_update_bios_output(struct amd_pmf_dev *pdev, struct ta_pmf_action *action)
{
u32 bios_idx;
+ int ret;
bios_idx = amd_pmf_get_bios_output_idx(action->action_index);
+ if (bios_idx >= ARRAY_SIZE(pdev->bios_output)) {
+ dev_warn(pdev->dev, "BIOS output index %u out of bounds\n", bios_idx);
+ return;
+ }
- amd_pmf_smartpc_apply_bios_output(pdev, action->value, BIT(bios_idx), bios_idx);
+ ret = amd_pmf_smartpc_apply_bios_output(pdev, action->value, BIT(bios_idx), bios_idx);
+ if (!ret)
+ pdev->bios_output[bios_idx] = action->value;
}
static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_result *out)
diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
index c6837caa44e0..59a125deb6b6 100644
--- a/drivers/platform/x86/amd/pmf/util.c
+++ b/drivers/platform/x86/amd/pmf/util.c
@@ -22,6 +22,9 @@ static int amd_pmf_get_bios_idx(u32 control_code)
if (control_code >= IOCTL_BIOS_INPUT_1 && control_code <= IOCTL_BIOS_INPUT_10)
return control_code - IOCTL_BIOS_INPUT_1;
+ if (control_code >= IOCTL_BIOS_OUTPUT_1 && control_code <= IOCTL_BIOS_OUTPUT_10)
+ return control_code - IOCTL_BIOS_OUTPUT_1;
+
return -EINVAL;
}
@@ -34,6 +37,15 @@ static long long amd_pmf_populate_bios_input(struct ta_pmf_enact_table *in, u32
return (idx < 2) ? in->ev_info.bios_input_1[idx] : in->ev_info.bios_input_2[idx - 2];
}
+static long long amd_pmf_populate_bios_output(struct amd_pmf_dev *pdev, u32 control_code)
+{
+ u32 idx;
+
+ idx = amd_pmf_get_bios_idx(control_code);
+
+ return pdev->bios_output[idx];
+}
+
static long long amd_pmf_device_state(struct ta_pmf_enact_table *in, u32 control_code)
{
switch (control_code) {
@@ -101,6 +113,9 @@ static int amd_pmf_populate_data(struct device *dev, void __user *argp)
case IOCTL_SOCKET_POWER:
output.val = in->ev_info.socket_power;
break;
+ case IOCTL_BIOS_OUTPUT_1 ... IOCTL_BIOS_OUTPUT_10:
+ output.val = amd_pmf_populate_bios_output(pdev, output.control_code);
+ break;
default:
return -EINVAL;
}
diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
index d29431c67eaa..f93767248169 100644
--- a/include/uapi/linux/amd-pmf.h
+++ b/include/uapi/linux/amd-pmf.h
@@ -60,6 +60,16 @@
* @IOCTL_MAX_C0_RES: Query maximum C0 residency
* @IOCTL_SOCKET_POWER: Query current socket power consumption
* @IOCTL_TA_BIN_VER: Query Trusted Application binary version
+ * @IOCTL_BIOS_OUTPUT_1: Query BIOS output parameter 1
+ * @IOCTL_BIOS_OUTPUT_2: Query BIOS output parameter 2
+ * @IOCTL_BIOS_OUTPUT_3: Query BIOS output parameter 3
+ * @IOCTL_BIOS_OUTPUT_4: Query BIOS output parameter 4
+ * @IOCTL_BIOS_OUTPUT_5: Query BIOS output parameter 5
+ * @IOCTL_BIOS_OUTPUT_6: Query BIOS output parameter 6
+ * @IOCTL_BIOS_OUTPUT_7: Query BIOS output parameter 7
+ * @IOCTL_BIOS_OUTPUT_8: Query BIOS output parameter 8
+ * @IOCTL_BIOS_OUTPUT_9: Query BIOS output parameter 9
+ * @IOCTL_BIOS_OUTPUT_10: Query BIOS output parameter 10
*
* These control codes are used with the IOCTL_PMF_POPULATE_DATA ioctl
* to specify which metrics data to retrieve from the AMD PMF driver.
@@ -90,7 +100,17 @@ enum pmf_ioctl_id {
IOCTL_AVG_C0_RES = 36,
IOCTL_MAX_C0_RES,
IOCTL_SOCKET_POWER = 50,
- IOCTL_TA_BIN_VER
+ IOCTL_TA_BIN_VER,
+ IOCTL_BIOS_OUTPUT_1,
+ IOCTL_BIOS_OUTPUT_2,
+ IOCTL_BIOS_OUTPUT_3,
+ IOCTL_BIOS_OUTPUT_4,
+ IOCTL_BIOS_OUTPUT_5,
+ IOCTL_BIOS_OUTPUT_6,
+ IOCTL_BIOS_OUTPUT_7,
+ IOCTL_BIOS_OUTPUT_8,
+ IOCTL_BIOS_OUTPUT_9,
+ IOCTL_BIOS_OUTPUT_10
};
/**
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 3/7] platform/x86/amd/pmf: Add feature discovery support to util interface
2026-03-01 13:11 [PATCH v3 0/7] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
2026-03-01 13:11 ` [PATCH v3 1/7] platform/x86/amd/pmf: Add util layer and userspace misc device interface Shyam Sundar S K
2026-03-01 13:11 ` [PATCH v3 2/7] platform/x86/amd/pmf: cache BIOS output values for user-space metrics via util IOCTL Shyam Sundar S K
@ 2026-03-01 13:11 ` Shyam Sundar S K
2026-03-25 14:07 ` Ilpo Järvinen
2026-03-01 13:11 ` [PATCH v3 4/7] platform/x86/amd/pmf: Store commonly used enums in the header file Shyam Sundar S K
` (4 subsequent siblings)
7 siblings, 1 reply; 30+ messages in thread
From: Shyam Sundar S K @ 2026-03-01 13:11 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami, Shyam Sundar S K
Add feature discovery capability to the util layer interface, allowing
userspace tools to query which PMF features are supported and enabled
on the current platform.
The following features can now be queried through the
/dev/amdpmf_interface ioctl:
*Auto Mode: Automatic power profile switching based on system activity
*Static Power Slider: User-selectable power profiles
*Policy Builder (Smart PC): Action based policy management
*Dynamic Power Slider AC: Adaptive power profiles when on AC power
*Dynamic Power Slider DC: Adaptive power profiles when on battery
Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
---
drivers/platform/x86/amd/pmf/util.c | 33 +++++++++++++++++++++++++++++
include/uapi/linux/amd-pmf.h | 12 ++++++++++-
2 files changed, 44 insertions(+), 1 deletion(-)
diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
index 59a125deb6b6..9a14467f412c 100644
--- a/drivers/platform/x86/amd/pmf/util.c
+++ b/drivers/platform/x86/amd/pmf/util.c
@@ -16,6 +16,8 @@
#include "pmf.h"
+#define AMD_PMF_IOCTL_VERSION 0x02
+
/* Convert BIOS input control code to array index (0-9) */
static int amd_pmf_get_bios_idx(u32 control_code)
{
@@ -46,6 +48,33 @@ static long long amd_pmf_populate_bios_output(struct amd_pmf_dev *pdev, u32 cont
return pdev->bios_output[idx];
}
+static bool amd_pmf_is_feature_supported(struct amd_pmf_dev *pdev, u32 control_code)
+{
+ bool feat;
+
+ switch (control_code) {
+ case IOCTL_FEATURE_AUTO_MODE:
+ feat = is_apmf_func_supported(pdev, APMF_FUNC_AUTO_MODE);
+ break;
+ case IOCTL_FEATURE_STATIC_POWER_SLIDER:
+ feat = is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR);
+ break;
+ case IOCTL_FEATURE_POLICY_BUILDER:
+ feat = pdev->smart_pc_enabled;
+ break;
+ case IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC:
+ feat = is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_AC);
+ break;
+ case IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC:
+ feat = is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_DC);
+ break;
+ default:
+ return false;
+ }
+
+ return feat;
+}
+
static long long amd_pmf_device_state(struct ta_pmf_enact_table *in, u32 control_code)
{
switch (control_code) {
@@ -116,6 +145,10 @@ static int amd_pmf_populate_data(struct device *dev, void __user *argp)
case IOCTL_BIOS_OUTPUT_1 ... IOCTL_BIOS_OUTPUT_10:
output.val = amd_pmf_populate_bios_output(pdev, output.control_code);
break;
+ case IOCTL_FEATURE_AUTO_MODE ... IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC:
+ output.feature_supported = amd_pmf_is_feature_supported(pdev, output.control_code);
+ output.feature_version = AMD_PMF_IOCTL_VERSION;
+ break;
default:
return -EINVAL;
}
diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
index f93767248169..f34c5d744039 100644
--- a/include/uapi/linux/amd-pmf.h
+++ b/include/uapi/linux/amd-pmf.h
@@ -70,6 +70,11 @@
* @IOCTL_BIOS_OUTPUT_8: Query BIOS output parameter 8
* @IOCTL_BIOS_OUTPUT_9: Query BIOS output parameter 9
* @IOCTL_BIOS_OUTPUT_10: Query BIOS output parameter 10
+ * @IOCTL_FEATURE_AUTO_MODE: Query if Auto Mode feature is supported
+ * @IOCTL_FEATURE_STATIC_POWER_SLIDER: Query if Static Power Slider is supported
+ * @IOCTL_FEATURE_POLICY_BUILDER: Query if Policy Builder feature is supported
+ * @IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC: Query if Dynamic Power Slider (AC) is supported
+ * @IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC: Query if Dynamic Power Slider (DC) is supported
*
* These control codes are used with the IOCTL_PMF_POPULATE_DATA ioctl
* to specify which metrics data to retrieve from the AMD PMF driver.
@@ -110,7 +115,12 @@ enum pmf_ioctl_id {
IOCTL_BIOS_OUTPUT_7,
IOCTL_BIOS_OUTPUT_8,
IOCTL_BIOS_OUTPUT_9,
- IOCTL_BIOS_OUTPUT_10
+ IOCTL_BIOS_OUTPUT_10,
+ IOCTL_FEATURE_AUTO_MODE,
+ IOCTL_FEATURE_STATIC_POWER_SLIDER,
+ IOCTL_FEATURE_POLICY_BUILDER,
+ IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC,
+ IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC
};
/**
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 4/7] platform/x86/amd/pmf: Store commonly used enums in the header file
2026-03-01 13:11 [PATCH v3 0/7] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
` (2 preceding siblings ...)
2026-03-01 13:11 ` [PATCH v3 3/7] platform/x86/amd/pmf: Add feature discovery support to util interface Shyam Sundar S K
@ 2026-03-01 13:11 ` Shyam Sundar S K
2026-03-25 13:34 ` Ilpo Järvinen
2026-03-01 13:11 ` [PATCH v3 5/7] platform/x86/amd/pmf: Move debug helper functions to UAPI header Shyam Sundar S K
` (3 subsequent siblings)
7 siblings, 1 reply; 30+ messages in thread
From: Shyam Sundar S K @ 2026-03-01 13:11 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami, Shyam Sundar S K
Relocate commonly used enums from multiple source files into a shared
header file to simplify code structure, improve readability, and
enhance maintainability. Also, remove the initialization of the first
enum member, since it is not needed.
Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
---
.../amd-sfh-hid/sfh1_1/amd_sfh_interface.c | 1 +
drivers/platform/x86/amd/pmf/pmf.h | 22 ------
drivers/platform/x86/amd/pmf/spc.c | 1 +
include/linux/amd-pmf-io.h | 9 ---
include/uapi/linux/amd-pmf.h | 74 +++++++++++++++++++
5 files changed, 76 insertions(+), 31 deletions(-)
diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
index 837d59e7a661..d9751c9ebfe8 100644
--- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
+++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
@@ -7,6 +7,7 @@
*
* Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
*/
+#include <linux/amd-pmf.h>
#include <linux/amd-pmf-io.h>
#include <linux/io-64-nonatomic-lo-hi.h>
#include <linux/iopoll.h>
diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
index 0d879f0fd8e2..f668c0450457 100644
--- a/drivers/platform/x86/amd/pmf/pmf.h
+++ b/drivers/platform/x86/amd/pmf/pmf.h
@@ -681,14 +681,6 @@ enum system_state {
SYSTEM_STATE_MAX,
};
-enum ta_slider {
- TA_BEST_BATTERY,
- TA_BETTER_BATTERY,
- TA_BETTER_PERFORMANCE,
- TA_BEST_PERFORMANCE,
- TA_MAX,
-};
-
struct amd_pmf_pb_bitmap {
const char *name;
u32 bit_mask;
@@ -720,20 +712,6 @@ static const struct amd_pmf_pb_bitmap custom_bios_inputs_v1[] __used = {
{"NOTIFY_CUSTOM_BIOS_INPUT10", BIT(16)},
};
-enum platform_type {
- PTYPE_UNKNOWN = 0,
- LID_CLOSE,
- CLAMSHELL,
- FLAT,
- TENT,
- STAND,
- TABLET,
- BOOK,
- PRESENTATION,
- PULL_FWD,
- PTYPE_INVALID = 0xf,
-};
-
/* Command ids for TA communication */
enum ta_pmf_command {
TA_PMF_COMMAND_POLICY_BUILDER_INITIALIZE,
diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c
index f48678a23cc7..a40419b5e1b7 100644
--- a/drivers/platform/x86/amd/pmf/spc.c
+++ b/drivers/platform/x86/amd/pmf/spc.c
@@ -10,6 +10,7 @@
*/
#include <acpi/button.h>
+#include <linux/amd-pmf.h>
#include <linux/amd-pmf-io.h>
#include <linux/cleanup.h>
#include <linux/power_supply.h>
diff --git a/include/linux/amd-pmf-io.h b/include/linux/amd-pmf-io.h
index 55198d2875cc..e014d4ce5a20 100644
--- a/include/linux/amd-pmf-io.h
+++ b/include/linux/amd-pmf-io.h
@@ -52,15 +52,6 @@ struct amd_sfh_info {
u32 laptop_placement;
};
-enum laptop_placement {
- LP_UNKNOWN = 0,
- ON_TABLE,
- ON_LAP_MOTION,
- IN_BAG,
- OUT_OF_BAG,
- LP_UNDEFINED,
-};
-
/**
* struct amd_pmf_npu_metrics: Get NPU metrics data from PMF driver
* @npuclk_freq: NPU clock frequency [MHz]
diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
index f34c5d744039..00fab9269238 100644
--- a/include/uapi/linux/amd-pmf.h
+++ b/include/uapi/linux/amd-pmf.h
@@ -32,6 +32,80 @@
*/
#define IOCTL_PMF_POPULATE_DATA _IOWR(AMD_PMF_IOC_MAGIC, 0x00, struct amd_pmf_ioctl_info)
+/**
+ * enum laptop_placement - Describes the physical placement of the laptop
+ * @LP_UNKNOWN: Placement cannot be determined
+ * @ON_TABLE: Laptop is placed on a stable surface like a table or desk
+ * @ON_LAP_MOTION: Laptop is on a lap with detected motion
+ * @IN_BAG: Laptop is detected to be inside a bag or case
+ * @OUT_OF_BAG: Laptop has been removed from bag or case
+ * @LP_UNDEFINED: Placement state is undefined
+ *
+ * This enumeration represents the physical placement state of the laptop
+ * as detected by platform sensors. Used for adaptive power management
+ * and thermal policies.
+ */
+enum laptop_placement {
+ LP_UNKNOWN,
+ ON_TABLE,
+ ON_LAP_MOTION,
+ IN_BAG,
+ OUT_OF_BAG,
+ LP_UNDEFINED,
+};
+
+/**
+ * enum ta_slider - Trusted Application power slider positions
+ * @TA_BEST_BATTERY: Maximum battery savings, minimal performance
+ * @TA_BETTER_BATTERY: Balanced towards battery life
+ * @TA_BETTER_PERFORMANCE: Balanced towards performance
+ * @TA_BEST_PERFORMANCE: Maximum performance, higher power consumption
+ * @TA_MAX: Sentinel value indicating maximum enum value
+ *
+ * This enumeration defines the power slider positions used by the
+ * AMD PMF Trusted Application for dynamic power management decisions.
+ * These correspond to the Windows power slider UI positions.
+ */
+enum ta_slider {
+ TA_BEST_BATTERY,
+ TA_BETTER_BATTERY,
+ TA_BETTER_PERFORMANCE,
+ TA_BEST_PERFORMANCE,
+ TA_MAX,
+};
+
+/**
+ * enum platform_type - Describes the physical form factor orientation
+ * @PTYPE_UNKNOWN: Platform type cannot be determined
+ * @LID_CLOSE: Laptop lid is closed
+ * @CLAMSHELL: Traditional laptop mode with keyboard and screen
+ * @FLAT: Device is lying flat on a surface
+ * @TENT: Device is in tent mode (keyboard folded back, standing)
+ * @STAND: Device is propped up in stand orientation
+ * @TABLET: Device is in tablet mode with keyboard hidden
+ * @BOOK: Device is in book reading orientation
+ * @PRESENTATION: Device is in presentation mode
+ * @PULL_FWD: Screen is pulled forward towards user
+ * @PTYPE_INVALID: Invalid platform type marker
+ *
+ * This enumeration describes the current physical orientation or form
+ * factor of convertible/2-in-1 devices. Used for optimizing power and
+ * thermal management based on device posture.
+ */
+enum platform_type {
+ PTYPE_UNKNOWN,
+ LID_CLOSE,
+ CLAMSHELL,
+ FLAT,
+ TENT,
+ STAND,
+ TABLET,
+ BOOK,
+ PRESENTATION,
+ PULL_FWD,
+ PTYPE_INVALID = 0xf,
+};
+
/**
* enum pmf_ioctl_id - Control codes for PMF ioctl operations
* @IOCTL_POWER_SOURCE: Query current power source (AC/DC)
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 5/7] platform/x86/amd/pmf: Move debug helper functions to UAPI header
2026-03-01 13:11 [PATCH v3 0/7] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
` (3 preceding siblings ...)
2026-03-01 13:11 ` [PATCH v3 4/7] platform/x86/amd/pmf: Store commonly used enums in the header file Shyam Sundar S K
@ 2026-03-01 13:11 ` Shyam Sundar S K
2026-03-25 13:39 ` Ilpo Järvinen
2026-03-01 13:11 ` [PATCH v3 6/7] platform/x86/amd/pmf: Introduce AMD PMF testing tool for driver metrics and features Shyam Sundar S K
` (2 subsequent siblings)
7 siblings, 1 reply; 30+ messages in thread
From: Shyam Sundar S K @ 2026-03-01 13:11 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami, Shyam Sundar S K
These debug helper functions convert enumerated values to appropriate
message and can be useful for userspace tools and other kernel components
that need to interpret AMD PMF state values.
By making them inline functions in the UAPI header, they become available
to both kernel and userspace without code duplication.
Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
---
drivers/platform/x86/amd/pmf/spc.c | 54 --------------
drivers/platform/x86/amd/pmf/util.c | 12 ----
include/uapi/linux/amd-pmf.h | 105 ++++++++++++++++++++++++++++
3 files changed, 105 insertions(+), 66 deletions(-)
diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c
index a40419b5e1b7..f91feaac5238 100644
--- a/drivers/platform/x86/amd/pmf/spc.c
+++ b/drivers/platform/x86/amd/pmf/spc.c
@@ -18,60 +18,6 @@
#include "pmf.h"
#ifdef CONFIG_AMD_PMF_DEBUG
-static const char *platform_type_as_str(u16 platform_type)
-{
- switch (platform_type) {
- case CLAMSHELL:
- return "CLAMSHELL";
- case FLAT:
- return "FLAT";
- case TENT:
- return "TENT";
- case STAND:
- return "STAND";
- case TABLET:
- return "TABLET";
- case BOOK:
- return "BOOK";
- case PRESENTATION:
- return "PRESENTATION";
- case PULL_FWD:
- return "PULL_FWD";
- default:
- return "UNKNOWN";
- }
-}
-
-static const char *laptop_placement_as_str(u16 device_state)
-{
- switch (device_state) {
- case ON_TABLE:
- return "ON_TABLE";
- case ON_LAP_MOTION:
- return "ON_LAP_MOTION";
- case IN_BAG:
- return "IN_BAG";
- case OUT_OF_BAG:
- return "OUT_OF_BAG";
- default:
- return "UNKNOWN";
- }
-}
-
-static const char *ta_slider_as_str(unsigned int state)
-{
- switch (state) {
- case TA_BEST_PERFORMANCE:
- return "PERFORMANCE";
- case TA_BETTER_PERFORMANCE:
- return "BALANCED";
- case TA_BEST_BATTERY:
- return "POWER_SAVER";
- default:
- return "Unknown TA Slider State";
- }
-}
-
static u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index)
{
switch (index) {
diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
index 9a14467f412c..20dc7aa9f250 100644
--- a/drivers/platform/x86/amd/pmf/util.c
+++ b/drivers/platform/x86/amd/pmf/util.c
@@ -18,18 +18,6 @@
#define AMD_PMF_IOCTL_VERSION 0x02
-/* Convert BIOS input control code to array index (0-9) */
-static int amd_pmf_get_bios_idx(u32 control_code)
-{
- if (control_code >= IOCTL_BIOS_INPUT_1 && control_code <= IOCTL_BIOS_INPUT_10)
- return control_code - IOCTL_BIOS_INPUT_1;
-
- if (control_code >= IOCTL_BIOS_OUTPUT_1 && control_code <= IOCTL_BIOS_OUTPUT_10)
- return control_code - IOCTL_BIOS_OUTPUT_1;
-
- return -EINVAL;
-}
-
static long long amd_pmf_populate_bios_input(struct ta_pmf_enact_table *in, u32 control_code)
{
u32 idx;
diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
index 00fab9269238..e2125b304b83 100644
--- a/include/uapi/linux/amd-pmf.h
+++ b/include/uapi/linux/amd-pmf.h
@@ -14,6 +14,7 @@
#ifndef _UAPI_LINUX_AMD_PMF_H
#define _UAPI_LINUX_AMD_PMF_H
+#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/types.h>
@@ -106,6 +107,88 @@ enum platform_type {
PTYPE_INVALID = 0xf,
};
+/**
+ * platform_type_as_str() - Convert platform type enum to string
+ * @platform_type: The platform type value to convert
+ *
+ * Returns a human-readable string representation of the platform type.
+ *
+ * Return: Constant string describing the platform type, or "UNKNOWN"
+ * if the value is not recognized.
+ */
+static inline const char *platform_type_as_str(unsigned int platform_type)
+{
+ switch (platform_type) {
+ case CLAMSHELL:
+ return "CLAMSHELL";
+ case FLAT:
+ return "FLAT";
+ case TENT:
+ return "TENT";
+ case STAND:
+ return "STAND";
+ case TABLET:
+ return "TABLET";
+ case BOOK:
+ return "BOOK";
+ case PRESENTATION:
+ return "PRESENTATION";
+ case PULL_FWD:
+ return "PULL_FWD";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+/**
+ * laptop_placement_as_str() - Convert laptop placement enum to string
+ * @device_state: The laptop placement value to convert
+ *
+ * Returns a human-readable string representation of the laptop placement.
+ *
+ * Return: Constant string describing the placement, or "UNKNOWN"
+ * if the value is not recognized.
+ */
+static inline const char *laptop_placement_as_str(unsigned int device_state)
+{
+ switch (device_state) {
+ case ON_TABLE:
+ return "ON_TABLE";
+ case ON_LAP_MOTION:
+ return "ON_LAP_MOTION";
+ case IN_BAG:
+ return "IN_BAG";
+ case OUT_OF_BAG:
+ return "OUT_OF_BAG";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+/**
+ * ta_slider_as_str() - Convert TA slider enum to string
+ * @state: The TA slider state value to convert
+ *
+ * Returns a human-readable string representation of the power slider
+ * position suitable for display purposes.
+ *
+ * Return: Constant string describing the slider state, or
+ * "Unknown TA Slider State" if the value is not recognized.
+ */
+static inline const char *ta_slider_as_str(unsigned int state)
+{
+ switch (state) {
+ case TA_BEST_PERFORMANCE:
+ return "PERFORMANCE";
+ case TA_BETTER_PERFORMANCE:
+ return "BALANCED";
+ case TA_BEST_BATTERY:
+ return "POWER_SAVER";
+ default:
+ return "Unknown TA Slider State";
+ }
+}
+
/**
* enum pmf_ioctl_id - Control codes for PMF ioctl operations
* @IOCTL_POWER_SOURCE: Query current power source (AC/DC)
@@ -197,6 +280,28 @@ enum pmf_ioctl_id {
IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC
};
+/**
+ * amd_pmf_get_bios_idx() - Convert BIOS control code to array index
+ * @control_code: The BIOS input or output control code
+ *
+ * Converts a BIOS input (IOCTL_BIOS_INPUT_1 to IOCTL_BIOS_INPUT_10) or
+ * BIOS output (IOCTL_BIOS_OUTPUT_1 to IOCTL_BIOS_OUTPUT_10) control code
+ * to a zero-based array index (0-9).
+ *
+ * Return: Array index (0-9) on success, -EINVAL if the control code
+ * is not a valid BIOS input or output code.
+ */
+static inline int amd_pmf_get_bios_idx(unsigned int control_code)
+{
+ if (control_code >= IOCTL_BIOS_INPUT_1 && control_code <= IOCTL_BIOS_INPUT_10)
+ return control_code - IOCTL_BIOS_INPUT_1;
+
+ if (control_code >= IOCTL_BIOS_OUTPUT_1 && control_code <= IOCTL_BIOS_OUTPUT_10)
+ return control_code - IOCTL_BIOS_OUTPUT_1;
+
+ return -EINVAL;
+}
+
/**
* struct amd_pmf_ioctl_info - Structure for PMF ioctl data exchange
* @control_code: Input parameter specifying which data to query (enum pmf_ioctl_id)
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 6/7] platform/x86/amd/pmf: Introduce AMD PMF testing tool for driver metrics and features
2026-03-01 13:11 [PATCH v3 0/7] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
` (4 preceding siblings ...)
2026-03-01 13:11 ` [PATCH v3 5/7] platform/x86/amd/pmf: Move debug helper functions to UAPI header Shyam Sundar S K
@ 2026-03-01 13:11 ` Shyam Sundar S K
2026-03-25 13:54 ` Ilpo Järvinen
2026-03-01 13:11 ` [PATCH v3 7/7] Documentation/ABI: add testing entry for AMD PMF misc device interface Shyam Sundar S K
2026-03-02 19:36 ` [PATCH v3 0/7] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Mario Limonciello
7 siblings, 1 reply; 30+ messages in thread
From: Shyam Sundar S K @ 2026-03-01 13:11 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami, Shyam Sundar S K
This tool leverages amd-pmf ioctls exposed via the util layer, allowing
validation of its newly integrated util layer and /dev/amdpmf_interface.
It includes a user-space test application, test_pmf, designed to interact
with the PMF driver and retrieve relevant metrics for the testing and
analysis.
It provides definitions for test metrics, feature IDs, and device states,
and includes tests for various AMD PMF metrics such as power source, skin
temperature, battery state, and custom BIOS inputs/outputs. It also
enables the testing of PMF metrics data and feature support reporting.
Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
---
tools/testing/selftests/Makefile | 1 +
.../drivers/platform/x86/amd/pmf/Makefile | 8 +
.../drivers/platform/x86/amd/pmf/test_pmf.c | 243 ++++++++++++++++++
3 files changed, 252 insertions(+)
create mode 100644 tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile
create mode 100644 tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
index 450f13ba4cca..d850fb09eeb9 100644
--- a/tools/testing/selftests/Makefile
+++ b/tools/testing/selftests/Makefile
@@ -26,6 +26,7 @@ TARGETS += drivers/net/netconsole
TARGETS += drivers/net/team
TARGETS += drivers/net/virtio_net
TARGETS += drivers/platform/x86/intel/ifs
+TARGETS += drivers/platform/x86/amd/pmf
TARGETS += dt
TARGETS += efivarfs
TARGETS += exec
diff --git a/tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile b/tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile
new file mode 100644
index 000000000000..876424941e83
--- /dev/null
+++ b/tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile
@@ -0,0 +1,8 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+CFLAGS += $(KHDR_INCLUDES)
+
+TEST_GEN_PROGS := test_pmf
+
+top_srcdir ?=../../../../..
+
+include ../../../../../lib.mk
diff --git a/tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c b/tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c
new file mode 100644
index 000000000000..a040ef01ba90
--- /dev/null
+++ b/tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c
@@ -0,0 +1,243 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * AMD Platform Management Framework Test Tool
+ *
+ * Copyright (c) 2026, Advanced Micro Devices, Inc.
+ * All Rights Reserved.
+ *
+ * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+ * Sanket Goswami <Sanket.Goswami@amd.com>
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <linux/amd-pmf.h>
+
+#include "../../../../../kselftest.h"
+
+#define DEVICE_NODE "/dev/amdpmf_interface"
+
+static int pmf_open_device(void)
+{
+ int fd;
+
+ fd = open(DEVICE_NODE, O_RDONLY);
+ if (fd < 0)
+ fprintf(stderr, "opening PMF Device Node failed: %s\n", strerror(errno));
+
+ return fd;
+}
+
+/* Helper to run IOCTL_PMF_POPULATE_DATA for one control code and return 0 on success. */
+static int pmf_get_fd(int fd, enum pmf_ioctl_id code, struct amd_pmf_ioctl_info *out)
+{
+ struct amd_pmf_ioctl_info info = {0};
+ int ret;
+
+ if (!out)
+ return -EINVAL;
+
+ info.control_code = code;
+
+ ret = ioctl(fd, IOCTL_PMF_POPULATE_DATA, &info);
+ if (ret < 0)
+ return ret;
+
+ *out = info;
+ return 0;
+}
+
+static int pmf_get_data(enum pmf_ioctl_id code, struct amd_pmf_ioctl_info *out)
+{
+ int fd, ret;
+
+ fd = pmf_open_device();
+ if (fd < 0)
+ return fd;
+
+ ret = pmf_get_fd(fd, code, out);
+
+ close(fd);
+ return ret;
+}
+
+static int pmf_get_feature_status(unsigned int code)
+{
+ struct amd_pmf_ioctl_info info = {0};
+ int ret;
+
+ ret = pmf_get_data(code, &info);
+ if (ret < 0)
+ return ret;
+
+ switch (code) {
+ case IOCTL_FEATURE_AUTO_MODE:
+ printf("Auto Mode: %-24s\n", info.feature_supported ? "Yes" : "No");
+ break;
+ case IOCTL_FEATURE_STATIC_POWER_SLIDER:
+ printf("Static Power Slider: %-24s\n", info.feature_supported ? "Yes" : "No");
+ break;
+ case IOCTL_FEATURE_POLICY_BUILDER:
+ printf("Policy Builder: %s\n", info.feature_supported ? "Yes" : "No");
+ break;
+ case IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC:
+ printf("Dynamic Power Slider AC: %s\n", info.feature_supported ? "Yes" : "No");
+ break;
+ case IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC:
+ printf("Dynamic Power Slider DC: %s\n", info.feature_supported ? "Yes" : "No");
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int pmf_get_device_state(unsigned int code)
+{
+ struct amd_pmf_ioctl_info info = {0};
+ int ret;
+
+ ret = pmf_get_data(code, &info);
+ if (ret < 0)
+ return ret;
+
+ switch (code) {
+ case IOCTL_PLATFORM_TYPE:
+ printf("Platform Type: %s\n", platform_type_as_str(info.val));
+ break;
+ case IOCTL_LAPTOP_PLACEMENT:
+ printf("Laptop placement: %s\n", laptop_placement_as_str(info.val));
+ break;
+ case IOCTL_LID_STATE:
+ printf("Lid State: %s\n", info.val ? "Close" : "Open");
+ break;
+ case IOCTL_USER_PRESENCE:
+ printf("User Presence: %s\n", info.val ? "Present" : "Away");
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int pmf_get_custom_bios_input(unsigned int code)
+{
+ struct amd_pmf_ioctl_info info = {0};
+ int idx, ret;
+
+ ret = pmf_get_data(code, &info);
+ if (ret < 0)
+ return ret;
+
+ switch (code) {
+ case IOCTL_BIOS_INPUT_1 ... IOCTL_BIOS_INPUT_10:
+ idx = amd_pmf_get_bios_idx(code);
+ printf("Custom BIOS input%u: %lu\n", idx + 1, (int64_t)info.val);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int pmf_get_bios_output(unsigned int code)
+{
+ struct amd_pmf_ioctl_info info = {0};
+ int idx, ret;
+
+ ret = pmf_get_data(code, &info);
+ if (ret < 0)
+ return ret;
+
+ switch (code) {
+ case IOCTL_BIOS_OUTPUT_1 ... IOCTL_BIOS_OUTPUT_10:
+ idx = amd_pmf_get_bios_idx(code);
+ printf("BIOS output%u: %lu\n", idx + 1, (int64_t)info.val);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int pmf_get_misc_info(unsigned int code)
+{
+ struct amd_pmf_ioctl_info info = {0};
+ int ret;
+
+ ret = pmf_get_data(code, &info);
+ if (ret < 0)
+ return ret;
+
+ switch (code) {
+ case IOCTL_POWER_SLIDER_POSITION:
+ printf("Slider Position: %s\n", ta_slider_as_str(info.val));
+ break;
+ case IOCTL_SKIN_TEMP:
+ printf("Skin Temperature: %lu\n", (int64_t)info.val);
+ break;
+ case IOCTL_GFX_WORKLOAD:
+ printf("GFX Busy: %lu\n", (int64_t)info.val);
+ break;
+ case IOCTL_AMBIENT_LIGHT:
+ printf("Ambient Light: %ld\n", (int64_t)info.val);
+ break;
+ case IOCTL_AVG_C0_RES:
+ printf("Avg C0 Residency: %lu\n", (int64_t)info.val);
+ break;
+ case IOCTL_MAX_C0_RES:
+ printf("Max C0 Residency: %lu\n", (int64_t)info.val);
+ break;
+ case IOCTL_SOCKET_POWER:
+ printf("Socket Power: %lu\n", (int64_t)info.val);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+int main(void)
+{
+ unsigned int idx;
+
+ printf("Feature Name Supported\n");
+ printf("---------------------------------\n");
+ for (idx = IOCTL_FEATURE_AUTO_MODE; idx <= IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC; idx++)
+ pmf_get_feature_status(idx);
+
+ printf("\nDevice State\n---------------\n");
+ for (idx = IOCTL_PLATFORM_TYPE; idx <= IOCTL_USER_PRESENCE; idx++)
+ pmf_get_device_state(idx);
+
+ printf("\nCustom BIOS Inputs\n-------------------\n");
+ for (idx = IOCTL_BIOS_INPUT_1; idx <= IOCTL_BIOS_INPUT_10; idx++)
+ pmf_get_custom_bios_input(idx);
+
+ printf("\nBIOS Outputs\n--------------\n");
+ for (idx = IOCTL_BIOS_OUTPUT_1; idx <= IOCTL_BIOS_OUTPUT_10; idx++)
+ pmf_get_bios_output(idx);
+
+ printf("\nMisc\n------\n");
+ pmf_get_misc_info(IOCTL_SKIN_TEMP);
+ pmf_get_misc_info(IOCTL_GFX_WORKLOAD);
+ pmf_get_misc_info(IOCTL_AMBIENT_LIGHT);
+ pmf_get_misc_info(IOCTL_AVG_C0_RES);
+ pmf_get_misc_info(IOCTL_MAX_C0_RES);
+ pmf_get_misc_info(IOCTL_SOCKET_POWER);
+ pmf_get_misc_info(IOCTL_POWER_SLIDER_POSITION);
+
+ return 0;
+}
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* [PATCH v3 7/7] Documentation/ABI: add testing entry for AMD PMF misc device interface
2026-03-01 13:11 [PATCH v3 0/7] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
` (5 preceding siblings ...)
2026-03-01 13:11 ` [PATCH v3 6/7] platform/x86/amd/pmf: Introduce AMD PMF testing tool for driver metrics and features Shyam Sundar S K
@ 2026-03-01 13:11 ` Shyam Sundar S K
2026-03-25 13:58 ` Ilpo Järvinen
2026-03-02 19:36 ` [PATCH v3 0/7] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Mario Limonciello
7 siblings, 1 reply; 30+ messages in thread
From: Shyam Sundar S K @ 2026-03-01 13:11 UTC (permalink / raw)
To: hansg, ilpo.jarvinen
Cc: platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami, Shyam Sundar S K
Add a Documentation/ABI/testing entry describing the AMD PMF util layer
misc device (/dev/amdpmf_interface) and the initial ioctls used to query
feature support and metrics data information. This interface is available
when CONFIG_AMD_PMF_UTIL_SUPPORT=y.
Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
---
.../ABI/testing/misc-amdpmf_interface | 70 +++++++++++++++++++
MAINTAINERS | 1 +
2 files changed, 71 insertions(+)
create mode 100644 Documentation/ABI/testing/misc-amdpmf_interface
diff --git a/Documentation/ABI/testing/misc-amdpmf_interface b/Documentation/ABI/testing/misc-amdpmf_interface
new file mode 100644
index 000000000000..62b0175e1345
--- /dev/null
+++ b/Documentation/ABI/testing/misc-amdpmf_interface
@@ -0,0 +1,70 @@
+What: /dev/amdpmf_interface
+Date: February 2026
+KernelVersion: 7.1
+Contact: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
+Description:
+ The AMD Platform Management Framework (PMF) util layer exposes a
+ minimal user-space interface via a misc character device for
+ feature discovery and metrics monitoring.
+
+ When CONFIG_AMD_PMF_UTIL_SUPPORT is enabled, the driver creates
+ a character device:
+
+ ======================
+ /dev/amdpmf_interface
+ ======================
+
+ The interface currently supports following ioctls:
+
+ ======================== =========================================
+ IOCTL Usage
+ IOCTL_PMF_POPULATE_DATA User passes a struct amd_pmf_ioctl_info
+ with control_code set to the desired
+ metric or feature ID. The driver returns
+ the requested data in val, or feature
+ support status in feature_supported.
+ ======================== =========================================
+
+ Following are the control codes supported (enum pmf_ioctl_id):
+
+ ============== ================================================================
+ Control Code Description
+ 0 IOCTL_POWER_SOURCE: AC/DC power source
+ 1 IOCTL_POWER_SLIDER_POSITION: Current power slider
+ 2 IOCTL_PLATFORM_TYPE: Platform form factor
+ 3 IOCTL_LAPTOP_PLACEMENT: Device placement (on table/lap/bag)
+ 4 IOCTL_LID_STATE: Lid open/closed status
+ 6 IOCTL_SKIN_TEMP: Skin temperature (degrees Celsius)
+ 7 IOCTL_USER_PRESENCE: User presence detection
+ 10-19 IOCTL_BIOS_INPUT_1 to IOCTL_BIOS_INPUT_10: Custom BIOS inputs
+ 20 IOCTL_GFX_WORKLOAD: Graphics workload percentage
+ 29 IOCTL_AMBIENT_LIGHT: Ambient light sensor reading
+ 36 IOCTL_AVG_C0_RES: Average C0 state residency
+ 37 IOCTL_MAX_C0_RES: Maximum C0 state residency
+ 50 IOCTL_SOCKET_POWER: Socket power consumption
+ 52-61 IOCTL_BIOS_OUTPUT_1 to IOCTL_BIOS_OUTPUT_10: BIOS output values
+ ============== ================================================================
+
+ Feature Discovery:
+
+ ============== =============================================================
+ Control Code Description
+ 62 IOCTL_FEATURE_AUTO_MODE: Auto Mode feature support
+ 63 IOCTL_FEATURE_STATIC_POWER_SLIDER: Static Power Slider
+ 64 IOCTL_FEATURE_POLICY_BUILDER: Policy Builder (Smart PC)
+ 65 IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC: Dynamic slider on AC
+ 66 IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC: Dynamic slider on DC
+ ============== =============================================================
+
+ Following are the return codes:
+
+ ============= ============================================================
+ Return code Description
+ 0 success
+ EINVAL control_code is not recognized or handle is not available
+ EFAULT copy_to_user/copy_from_user failures
+ ENODEV PMF device not available
+ ============= ============================================================
+
+ User-space tools integrating with AMD PMF to discover capabilities and
+ monitor real-time metrics for thermal and power management validation.
diff --git a/MAINTAINERS b/MAINTAINERS
index 55af015174a5..78773373172c 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1224,6 +1224,7 @@ AMD PMF DRIVER
M: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
L: platform-driver-x86@vger.kernel.org
S: Supported
+F: Documentation/ABI/testing/misc-amdpmf_interface
F: Documentation/ABI/testing/sysfs-amd-pmf
F: drivers/platform/x86/amd/pmf/
--
2.34.1
^ permalink raw reply related [flat|nested] 30+ messages in thread
* Re: [PATCH v3 1/7] platform/x86/amd/pmf: Add util layer and userspace misc device interface
2026-03-01 13:11 ` [PATCH v3 1/7] platform/x86/amd/pmf: Add util layer and userspace misc device interface Shyam Sundar S K
@ 2026-03-01 18:45 ` Randy Dunlap
2026-03-03 15:22 ` Shyam Sundar S K
2026-03-25 13:16 ` Ilpo Järvinen
` (2 subsequent siblings)
3 siblings, 1 reply; 30+ messages in thread
From: Randy Dunlap @ 2026-03-01 18:45 UTC (permalink / raw)
To: Shyam Sundar S K, hansg, ilpo.jarvinen
Cc: platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami
On 3/1/26 5:11 AM, Shyam Sundar S K wrote:
> diff --git a/drivers/platform/x86/amd/pmf/Kconfig b/drivers/platform/x86/amd/pmf/Kconfig
> index 25b8f7ae3abd..ad21f679b8ab 100644
> --- a/drivers/platform/x86/amd/pmf/Kconfig
> +++ b/drivers/platform/x86/amd/pmf/Kconfig
> @@ -30,3 +30,13 @@ config AMD_PMF_DEBUG
> in the PMF config store.
>
> Say Y here to enable more debug logs and Say N here if you are not sure.
> +
> +config AMD_PMF_UTIL_SUPPORT
> + bool "AMD PMF Util layer support"
> + depends on AMD_PMF
> + help
> + Enabling this option provides a character device for userspace to capture
> + PMF features (Smart PC Builder, Auto Mode, Static Power Slider, Dynamic
> + Power Slider AC/DC) along with PMF metrics from the AMD PMF driver.
> +
> + Say Y here to enable it and Say N here if you are not sure.
Missing indentation of help text.
from coding-style.rst:
10) Kconfig configuration files
-------------------------------
For all of the Kconfig* configuration files throughout the source tree,
the indentation is somewhat different. Lines under a ``config`` definition
are indented with one tab, while help text is indented an additional two
spaces.
--
~Randy
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 0/7] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface
2026-03-01 13:11 [PATCH v3 0/7] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
` (6 preceding siblings ...)
2026-03-01 13:11 ` [PATCH v3 7/7] Documentation/ABI: add testing entry for AMD PMF misc device interface Shyam Sundar S K
@ 2026-03-02 19:36 ` Mario Limonciello
2026-03-03 15:23 ` Shyam Sundar S K
7 siblings, 1 reply; 30+ messages in thread
From: Mario Limonciello @ 2026-03-02 19:36 UTC (permalink / raw)
To: Shyam Sundar S K, hansg, ilpo.jarvinen
Cc: platform-driver-x86, Yijun.Shen, Sanket.Goswami
On 3/1/26 7:11 AM, Shyam Sundar S K wrote:
> This patch series introduces a new util layer for the AMD Platform
> Management Framework (PMF) driver that exposes a minimal userspace
> interface for metrics monitoring and feature discovery.
>
> AMD PMF currently manages power and thermal policies internally through
> Smart PC features, Auto Mode, Policy Builder, Static/Dynamic Power
> Sliders. However, system designers and OEMs need visibility into PMF
> metrics and feature status for validation, debugging, and integration
> with monitoring tools.
>
> This series addresses that need by adding a character device interface
> that allows controlled access to PMF metrics data while maintaining
> the driver's existing automated policy management.
>
> The primary use case is integration with userspace tools like AMD
> SystemDeck, which are widely used by system designers to:
> - Monitor real-time power and thermal behavior
> - Validate PMF feature operation during platform bring-up
> - Debug thermal issues by tracking skin temperature, C-state residency,
> and socket power metrics
> - Verify BIOS input/output policy values during Smart PC operation
>
> The util layer reads from the existing Trusted Application (TA) shared
> memory buffer and cached BIOS output values, adding no new communication
> overhead with the TA.
>
> v3:
> - Stop exporting battery information via util layer.
> - Optimize the core logic for fetching BIOS outputs.
> - Update the documentation patch to reflect the current util layer design.
> - Consolidate amd-pmf-io.h changes into common UAPI header.
> - Define a single unified uAPI structure and IOCTL.
> - Address other v2 review remarks [1]
>
> v2:
> - address remarks from v1
> - add a new tool that exercises the IOCTLs from PMF interface
>
> [1] https://lore.kernel.org/platform-driver-x86/20251111071010.4179492-1-Shyam-sundar.S-k@amd.com/
>
> Shyam Sundar S K (7):
> platform/x86/amd/pmf: Add util layer and userspace misc device
> interface
> platform/x86/amd/pmf: cache BIOS output values for user-space metrics
> via util IOCTL
> platform/x86/amd/pmf: Add feature discovery support to util interface
> platform/x86/amd/pmf: Store commonly used enums in the header file
> platform/x86/amd/pmf: Move debug helper functions to UAPI header
> platform/x86/amd/pmf: Introduce AMD PMF testing tool for driver
> metrics and features
> Documentation/ABI: add testing entry for AMD PMF misc device interface
>
> .../ABI/testing/misc-amdpmf_interface | 70 ++++
> MAINTAINERS | 1 +
> .../amd-sfh-hid/sfh1_1/amd_sfh_interface.c | 1 +
> drivers/platform/x86/amd/pmf/Kconfig | 10 +
> drivers/platform/x86/amd/pmf/Makefile | 2 +
> drivers/platform/x86/amd/pmf/core.c | 8 +
> drivers/platform/x86/amd/pmf/pmf.h | 32 +-
> drivers/platform/x86/amd/pmf/spc.c | 55 +--
> drivers/platform/x86/amd/pmf/tee-if.c | 9 +-
> drivers/platform/x86/amd/pmf/util.c | 210 ++++++++++++
> include/linux/amd-pmf-io.h | 9 -
> include/uapi/linux/amd-pmf.h | 324 ++++++++++++++++++
> tools/testing/selftests/Makefile | 1 +
> .../drivers/platform/x86/amd/pmf/Makefile | 8 +
> .../drivers/platform/x86/amd/pmf/test_pmf.c | 243 +++++++++++++
> 15 files changed, 897 insertions(+), 86 deletions(-)
> create mode 100644 Documentation/ABI/testing/misc-amdpmf_interface
> create mode 100644 drivers/platform/x86/amd/pmf/util.c
> create mode 100644 include/uapi/linux/amd-pmf.h
> create mode 100644 tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile
> create mode 100644 tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c
>
Thanks, looks good to me. You can add this to the next version (which
incorporates Randy's feedback).
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 1/7] platform/x86/amd/pmf: Add util layer and userspace misc device interface
2026-03-01 18:45 ` Randy Dunlap
@ 2026-03-03 15:22 ` Shyam Sundar S K
0 siblings, 0 replies; 30+ messages in thread
From: Shyam Sundar S K @ 2026-03-03 15:22 UTC (permalink / raw)
To: Randy Dunlap, hansg, ilpo.jarvinen
Cc: platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami
On 3/2/2026 00:15, Randy Dunlap wrote:
>
>
> On 3/1/26 5:11 AM, Shyam Sundar S K wrote:
>> diff --git a/drivers/platform/x86/amd/pmf/Kconfig b/drivers/platform/x86/amd/pmf/Kconfig
>> index 25b8f7ae3abd..ad21f679b8ab 100644
>> --- a/drivers/platform/x86/amd/pmf/Kconfig
>> +++ b/drivers/platform/x86/amd/pmf/Kconfig
>> @@ -30,3 +30,13 @@ config AMD_PMF_DEBUG
>> in the PMF config store.
>>
>> Say Y here to enable more debug logs and Say N here if you are not sure.
>> +
>> +config AMD_PMF_UTIL_SUPPORT
>> + bool "AMD PMF Util layer support"
>> + depends on AMD_PMF
>> + help
>> + Enabling this option provides a character device for userspace to capture
>> + PMF features (Smart PC Builder, Auto Mode, Static Power Slider, Dynamic
>> + Power Slider AC/DC) along with PMF metrics from the AMD PMF driver.
>> +
>> + Say Y here to enable it and Say N here if you are not sure.
>
> Missing indentation of help text.
> from coding-style.rst:
>
> 10) Kconfig configuration files
> -------------------------------
>
> For all of the Kconfig* configuration files throughout the source tree,
> the indentation is somewhat different. Lines under a ``config`` definition
> are indented with one tab, while help text is indented an additional two
> spaces.
>
Thank you. I will fix that in the next revision.
thanks,
Shyam
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 0/7] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface
2026-03-02 19:36 ` [PATCH v3 0/7] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Mario Limonciello
@ 2026-03-03 15:23 ` Shyam Sundar S K
0 siblings, 0 replies; 30+ messages in thread
From: Shyam Sundar S K @ 2026-03-03 15:23 UTC (permalink / raw)
To: Mario Limonciello, hansg, ilpo.jarvinen
Cc: platform-driver-x86, Yijun.Shen, Sanket.Goswami
On 3/3/2026 01:06, Mario Limonciello wrote:
> On 3/1/26 7:11 AM, Shyam Sundar S K wrote:
>> This patch series introduces a new util layer for the AMD Platform
>> Management Framework (PMF) driver that exposes a minimal userspace
>> interface for metrics monitoring and feature discovery.
>>
>> AMD PMF currently manages power and thermal policies internally through
>> Smart PC features, Auto Mode, Policy Builder, Static/Dynamic Power
>> Sliders. However, system designers and OEMs need visibility into PMF
>> metrics and feature status for validation, debugging, and integration
>> with monitoring tools.
>>
>> This series addresses that need by adding a character device interface
>> that allows controlled access to PMF metrics data while maintaining
>> the driver's existing automated policy management.
>>
>> The primary use case is integration with userspace tools like AMD
>> SystemDeck, which are widely used by system designers to:
>> - Monitor real-time power and thermal behavior
>> - Validate PMF feature operation during platform bring-up
>> - Debug thermal issues by tracking skin temperature, C-state residency,
>> and socket power metrics
>> - Verify BIOS input/output policy values during Smart PC operation
>>
>> The util layer reads from the existing Trusted Application (TA) shared
>> memory buffer and cached BIOS output values, adding no new
>> communication
>> overhead with the TA.
>>
>> v3:
>> - Stop exporting battery information via util layer.
>> - Optimize the core logic for fetching BIOS outputs.
>> - Update the documentation patch to reflect the current util layer
>> design.
>> - Consolidate amd-pmf-io.h changes into common UAPI header.
>> - Define a single unified uAPI structure and IOCTL.
>> - Address other v2 review remarks [1]
>>
>> v2:
>> - address remarks from v1
>> - add a new tool that exercises the IOCTLs from PMF interface
>>
>> [1] https://lore.kernel.org/platform-driver-
>> x86/20251111071010.4179492-1-Shyam-sundar.S-k@amd.com/
>>
>> Shyam Sundar S K (7):
>> platform/x86/amd/pmf: Add util layer and userspace misc device
>> interface
>> platform/x86/amd/pmf: cache BIOS output values for user-space
>> metrics
>> via util IOCTL
>> platform/x86/amd/pmf: Add feature discovery support to util
>> interface
>> platform/x86/amd/pmf: Store commonly used enums in the header file
>> platform/x86/amd/pmf: Move debug helper functions to UAPI header
>> platform/x86/amd/pmf: Introduce AMD PMF testing tool for driver
>> metrics and features
>> Documentation/ABI: add testing entry for AMD PMF misc device
>> interface
>>
>> .../ABI/testing/misc-amdpmf_interface | 70 ++++
>> MAINTAINERS | 1 +
>> .../amd-sfh-hid/sfh1_1/amd_sfh_interface.c | 1 +
>> drivers/platform/x86/amd/pmf/Kconfig | 10 +
>> drivers/platform/x86/amd/pmf/Makefile | 2 +
>> drivers/platform/x86/amd/pmf/core.c | 8 +
>> drivers/platform/x86/amd/pmf/pmf.h | 32 +-
>> drivers/platform/x86/amd/pmf/spc.c | 55 +--
>> drivers/platform/x86/amd/pmf/tee-if.c | 9 +-
>> drivers/platform/x86/amd/pmf/util.c | 210 ++++++++++++
>> include/linux/amd-pmf-io.h | 9 -
>> include/uapi/linux/amd-pmf.h | 324 ++++++++++++++
>> ++++
>> tools/testing/selftests/Makefile | 1 +
>> .../drivers/platform/x86/amd/pmf/Makefile | 8 +
>> .../drivers/platform/x86/amd/pmf/test_pmf.c | 243 +++++++++++++
>> 15 files changed, 897 insertions(+), 86 deletions(-)
>> create mode 100644 Documentation/ABI/testing/misc-amdpmf_interface
>> create mode 100644 drivers/platform/x86/amd/pmf/util.c
>> create mode 100644 include/uapi/linux/amd-pmf.h
>> create mode 100644 tools/testing/selftests/drivers/platform/x86/
>> amd/pmf/Makefile
>> create mode 100644 tools/testing/selftests/drivers/platform/x86/
>> amd/pmf/test_pmf.c
>>
>
> Thanks, looks good to me. You can add this to the next version (which
> incorporates Randy's feedback).
>
> Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
>
Sure. Thanks! I will wait for other feedback to come in before
re-spinning.
Thanks,
Shyam
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 1/7] platform/x86/amd/pmf: Add util layer and userspace misc device interface
2026-03-01 13:11 ` [PATCH v3 1/7] platform/x86/amd/pmf: Add util layer and userspace misc device interface Shyam Sundar S K
2026-03-01 18:45 ` Randy Dunlap
@ 2026-03-25 13:16 ` Ilpo Järvinen
2026-03-25 13:18 ` Ilpo Järvinen
2026-03-25 14:05 ` Ilpo Järvinen
3 siblings, 0 replies; 30+ messages in thread
From: Ilpo Järvinen @ 2026-03-25 13:16 UTC (permalink / raw)
To: Shyam Sundar S K
Cc: Hans de Goede, platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami
On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
> Add a util layer to AMD PMF that exposes a minimal userspace interface
> via a misc character device for metrics monitoring and feature discovery.
>
> This creates /dev/amdpmf_interface with basic ioctl support to retrieve
> PMF metrics such as:
> *Power source and power slider position
> *Platform type, lid state, and user presence
> *Skin temperature and ambient light
> *BIOS input parameters (1-10)
> *Graphics workload metrics
> *CPU C-state residency (average and maximum)
> *Socket power consumption
>
> The interface enables smoother integration with userspace tools such as
> AMD SystemDeck [1], which is widely used for monitoring and controlling
> power and thermal behavior on AMD platforms. These tools help designers
> keep major components within thermal limits to ensure proper operation
> and enhance overall system stability and reliability.
>
> The feature is gated behind the CONFIG_AMD_PMF_UTIL_SUPPORT Kconfig
> option, allowing it to be disabled if not needed. The implementation
> uses existing PMF infrastructure to populate data from the TA (Trusted
> Application) shared memory buffer.
>
> Link: https://docs.amd.com/v/u/en-US/68773_0.50 [1]
>
> Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
> Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> ---
> drivers/platform/x86/amd/pmf/Kconfig | 10 ++
> drivers/platform/x86/amd/pmf/Makefile | 2 +
> drivers/platform/x86/amd/pmf/core.c | 5 +
> drivers/platform/x86/amd/pmf/pmf.h | 9 ++
> drivers/platform/x86/amd/pmf/util.c | 174 ++++++++++++++++++++++++++
> include/uapi/linux/amd-pmf.h | 115 +++++++++++++++++
> 6 files changed, 315 insertions(+)
> create mode 100644 drivers/platform/x86/amd/pmf/util.c
> create mode 100644 include/uapi/linux/amd-pmf.h
>
> diff --git a/drivers/platform/x86/amd/pmf/Kconfig b/drivers/platform/x86/amd/pmf/Kconfig
> index 25b8f7ae3abd..ad21f679b8ab 100644
> --- a/drivers/platform/x86/amd/pmf/Kconfig
> +++ b/drivers/platform/x86/amd/pmf/Kconfig
> @@ -30,3 +30,13 @@ config AMD_PMF_DEBUG
> in the PMF config store.
>
> Say Y here to enable more debug logs and Say N here if you are not sure.
> +
> +config AMD_PMF_UTIL_SUPPORT
> + bool "AMD PMF Util layer support"
> + depends on AMD_PMF
> + help
> + Enabling this option provides a character device for userspace to capture
> + PMF features (Smart PC Builder, Auto Mode, Static Power Slider, Dynamic
> + Power Slider AC/DC) along with PMF metrics from the AMD PMF driver.
> +
> + Say Y here to enable it and Say N here if you are not sure.
> diff --git a/drivers/platform/x86/amd/pmf/Makefile b/drivers/platform/x86/amd/pmf/Makefile
> index 5978464e0eb7..bf7aad80b9e9 100644
> --- a/drivers/platform/x86/amd/pmf/Makefile
> +++ b/drivers/platform/x86/amd/pmf/Makefile
> @@ -8,3 +8,5 @@ obj-$(CONFIG_AMD_PMF) += amd-pmf.o
> amd-pmf-y := core.o acpi.o sps.o \
> auto-mode.o cnqf.o \
> tee-if.o spc.o
> +# Build util.c only when AMD_PMF_UTIL_SUPPORT is enabled
> +amd-pmf-$(CONFIG_AMD_PMF_UTIL_SUPPORT) += util.o
> diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
> index b9e5a2cf3aae..919d02f30aae 100644
> --- a/drivers/platform/x86/amd/pmf/core.c
> +++ b/drivers/platform/x86/amd/pmf/core.c
> @@ -634,6 +634,10 @@ static int amd_pmf_probe(struct platform_device *pdev)
>
> pmf_device = dev->dev;
>
> + err = amd_pmf_cdev_register(dev);
> + if (err)
> + dev_warn(dev->dev, "failed to register util interface: %d\n", err);
> +
> dev_info(dev->dev, "registered PMF device successfully\n");
>
> return 0;
> @@ -646,6 +650,7 @@ static void amd_pmf_remove(struct platform_device *pdev)
> amd_pmf_deinit_features(dev);
> if (is_apmf_func_supported(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
> amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_UNLOAD);
> + amd_pmf_cdev_unregister();
> apmf_acpi_deinit(dev);
> amd_pmf_dbgfs_unregister(dev);
> }
> diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
> index 69fef7448744..6f61076a9386 100644
> --- a/drivers/platform/x86/amd/pmf/pmf.h
> +++ b/drivers/platform/x86/amd/pmf/pmf.h
> @@ -928,4 +928,13 @@ int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid);
> void amd_pmf_tee_deinit(struct amd_pmf_dev *dev);
> int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev);
>
> +/* Util Layer */
> +#if IS_ENABLED(CONFIG_AMD_PMF_UTIL_SUPPORT)
> +int amd_pmf_cdev_register(struct amd_pmf_dev *dev);
> +void amd_pmf_cdev_unregister(void);
> +#else
> +static inline int amd_pmf_cdev_register(struct amd_pmf_dev *dev) { return 0; }
> +static inline void amd_pmf_cdev_unregister(void) {}
> +#endif
> +
> #endif /* PMF_H */
> diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
> new file mode 100644
> index 000000000000..c6837caa44e0
> --- /dev/null
> +++ b/drivers/platform/x86/amd/pmf/util.c
> @@ -0,0 +1,174 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * AMD Platform Management Framework Util Layer
> + *
> + * Copyright (c) 2026, Advanced Micro Devices, Inc.
> + * All Rights Reserved.
> + *
> + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> + * Sanket Goswami <Sanket.Goswami@amd.com>
Nit, I don't know why these are aligned so oddly.
> + */
> +
> +#include <linux/amd-pmf.h>
> +#include <linux/miscdevice.h>
> +#include <linux/mutex.h>
> +#include <linux/uaccess.h>
> +
> +#include "pmf.h"
> +
> +/* Convert BIOS input control code to array index (0-9) */
> +static int amd_pmf_get_bios_idx(u32 control_code)
> +{
> + if (control_code >= IOCTL_BIOS_INPUT_1 && control_code <= IOCTL_BIOS_INPUT_10)
> + return control_code - IOCTL_BIOS_INPUT_1;
> +
> + return -EINVAL;
> +}
> +
> +static long long amd_pmf_populate_bios_input(struct ta_pmf_enact_table *in, u32 control_code)
> +{
> + u32 idx;
> +
> + idx = amd_pmf_get_bios_idx(control_code);
> +
> + return (idx < 2) ? in->ev_info.bios_input_1[idx] : in->ev_info.bios_input_2[idx - 2];
> +}
> +
> +static long long amd_pmf_device_state(struct ta_pmf_enact_table *in, u32 control_code)
> +{
> + switch (control_code) {
> + case IOCTL_PLATFORM_TYPE:
> + return in->ev_info.platform_type;
> + case IOCTL_LAPTOP_PLACEMENT:
> + return in->ev_info.device_state;
> + case IOCTL_LID_STATE:
> + return in->ev_info.lid_state;
> + case IOCTL_USER_PRESENCE:
> + return in->ev_info.user_present;
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int amd_pmf_populate_data(struct device *dev, void __user *argp)
> +{
> + struct amd_pmf_ioctl_info output = {0};
= {}; is enough to do default initialization.
> + struct ta_pmf_shared_memory *ta_sm = NULL;
> + struct ta_pmf_enact_table *in = NULL;
> + struct amd_pmf_dev *pdev;
> +
> + pdev = dev_get_drvdata(dev);
> + if (!pdev)
> + return -EINVAL;
> +
> + memset(pdev->shbuf, 0, pdev->policy_sz);
> + ta_sm = pdev->shbuf;
> + in = &ta_sm->pmf_input.enact_table;
> +
> + if (copy_from_user(&output, argp, sizeof(output)))
> + return -EFAULT;
> +
> + switch (output.control_code) {
> + case IOCTL_POWER_SOURCE:
> + output.val = in->ev_info.power_source;
> + break;
> + case IOCTL_POWER_SLIDER_POSITION:
> + output.val = in->ev_info.power_slider;
> + break;
> + case IOCTL_SKIN_TEMP:
> + /* Convert from centi-degrees to degrees Celsius */
> + output.val = in->ev_info.skin_temperature / 100;
> + break;
> + case IOCTL_PLATFORM_TYPE ... IOCTL_LID_STATE:
> + case IOCTL_USER_PRESENCE:
> + output.val = amd_pmf_device_state(in, output.control_code);
> + break;
> + case IOCTL_BIOS_INPUT_1 ... IOCTL_BIOS_INPUT_10:
> + output.val = amd_pmf_populate_bios_input(in, output.control_code);
> + break;
> + case IOCTL_GFX_WORKLOAD:
> + output.val = in->ev_info.gfx_busy;
> + break;
> + case IOCTL_AMBIENT_LIGHT:
> + output.val = in->ev_info.ambient_light;
> + break;
> + case IOCTL_AVG_C0_RES:
> + output.val = in->ev_info.avg_c0residency;
> + break;
> + case IOCTL_MAX_C0_RES:
> + output.val = in->ev_info.max_c0residency;
> + break;
> + case IOCTL_SOCKET_POWER:
> + output.val = in->ev_info.socket_power;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + if (copy_to_user(argp, &output, sizeof(output)))
> + return -EFAULT;
> +
> + return 0;
> +}
> +
> +#if IS_ENABLED(CONFIG_AMD_PMF_UTIL_SUPPORT)
[...snip...]
> +#else
> +int amd_pmf_cdev_register(struct amd_pmf_dev *dev) { return 0; }
> +void amd_pmf_cdev_unregister(void) {}
You don't build this file without UTIL_SUPPORT so these are dead code.
> +#endif
> diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
> new file mode 100644
> index 000000000000..d29431c67eaa
> --- /dev/null
> +++ b/include/uapi/linux/amd-pmf.h
> @@ -0,0 +1,115 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */
> +/*
> + * AMD Platform Management Framework (PMF) UAPI Header
> + *
> + * Copyright (c) 2026, Advanced Micro Devices, Inc.
> + * All Rights Reserved.
> + *
> + * This file defines the user-space API for interacting with the AMD PMF
> + * driver. It provides ioctl interfaces to query platform-specific metrics
> + * such as power source, slider position, platform type, laptop placement,
> + * and various BIOS input/output parameters.
> + */
> +
> +#ifndef _UAPI_LINUX_AMD_PMF_H
> +#define _UAPI_LINUX_AMD_PMF_H
> +
> +#include <linux/ioctl.h>
> +#include <linux/types.h>
> +
> +/**
> + * AMD_PMF_IOC_MAGIC - Magic number for AMD PMF ioctl commands
> + *
> + * This magic number uniquely identifies AMD PMF ioctl operations.
> + */
> +#define AMD_PMF_IOC_MAGIC 'p'
> +
> +/**
> + * IOCTL_PMF_POPULATE_DATA - ioctl command to retrieve PMF metrics data
> + *
> + * This ioctl command is used to populate the amd_pmf_ioctl_info structure
> + * with the requested metrics data based on the control_code provided.
> + */
> +#define IOCTL_PMF_POPULATE_DATA _IOWR(AMD_PMF_IOC_MAGIC, 0x00, struct amd_pmf_ioctl_info)
> +
> +/**
> + * enum pmf_ioctl_id - Control codes for PMF ioctl operations
> + * @IOCTL_POWER_SOURCE: Query current power source (AC/DC)
> + * @IOCTL_POWER_SLIDER_POSITION: Query current power slider position
> + * @IOCTL_PLATFORM_TYPE: Query current platform/form factor type
> + * @IOCTL_LAPTOP_PLACEMENT: Query laptop physical placement state
> + * @IOCTL_LID_STATE: Query laptop lid open/close state
> + * @IOCTL_HETERO_STATE: Query heterogeneous computing state
> + * @IOCTL_SKIN_TEMP: Query skin temperature sensor reading
> + * @IOCTL_USER_PRESENCE: Query user presence detection state
> + * @IOCTL_DISPLAY_NUM: Query number of active displays
> + * @IOCTL_USER_ENGAGED: Query user engagement state
> + * @IOCTL_BIOS_INPUT_1: Query BIOS input parameter 1
> + * @IOCTL_BIOS_INPUT_2: Query BIOS input parameter 2
> + * @IOCTL_BIOS_INPUT_3: Query BIOS input parameter 3
> + * @IOCTL_BIOS_INPUT_4: Query BIOS input parameter 4
> + * @IOCTL_BIOS_INPUT_5: Query BIOS input parameter 5
> + * @IOCTL_BIOS_INPUT_6: Query BIOS input parameter 6
> + * @IOCTL_BIOS_INPUT_7: Query BIOS input parameter 7
> + * @IOCTL_BIOS_INPUT_8: Query BIOS input parameter 8
> + * @IOCTL_BIOS_INPUT_9: Query BIOS input parameter 9
> + * @IOCTL_BIOS_INPUT_10: Query BIOS input parameter 10
> + * @IOCTL_GFX_WORKLOAD: Query current graphics workload type
> + * @IOCTL_AMBIENT_LIGHT: Query ambient light sensor reading
> + * @IOCTL_AVG_C0_RES: Query average C0 residency
> + * @IOCTL_MAX_C0_RES: Query maximum C0 residency
> + * @IOCTL_SOCKET_POWER: Query current socket power consumption
> + * @IOCTL_TA_BIN_VER: Query Trusted Application binary version
> + *
> + * These control codes are used with the IOCTL_PMF_POPULATE_DATA ioctl
> + * to specify which metrics data to retrieve from the AMD PMF driver.
> + */
> +enum pmf_ioctl_id {
> + IOCTL_POWER_SOURCE,
> + IOCTL_POWER_SLIDER_POSITION,
> + IOCTL_PLATFORM_TYPE,
> + IOCTL_LAPTOP_PLACEMENT,
> + IOCTL_LID_STATE,
> + IOCTL_HETERO_STATE,
> + IOCTL_SKIN_TEMP,
> + IOCTL_USER_PRESENCE,
> + IOCTL_DISPLAY_NUM,
> + IOCTL_USER_ENGAGED,
> + IOCTL_BIOS_INPUT_1,
> + IOCTL_BIOS_INPUT_2,
> + IOCTL_BIOS_INPUT_3,
> + IOCTL_BIOS_INPUT_4,
> + IOCTL_BIOS_INPUT_5,
> + IOCTL_BIOS_INPUT_6,
> + IOCTL_BIOS_INPUT_7,
> + IOCTL_BIOS_INPUT_8,
> + IOCTL_BIOS_INPUT_9,
> + IOCTL_BIOS_INPUT_10,
> + IOCTL_GFX_WORKLOAD,
> + IOCTL_AMBIENT_LIGHT = 29,
> + IOCTL_AVG_C0_RES = 36,
> + IOCTL_MAX_C0_RES,
> + IOCTL_SOCKET_POWER = 50,
> + IOCTL_TA_BIN_VER
> +};
> +
> +/**
> + * struct amd_pmf_ioctl_info - Structure for PMF ioctl data exchange
> + * @control_code: Input parameter specifying which data to query (enum pmf_ioctl_id)
> + * @feature_supported: Output flag indicating if the queried feature is supported
> + * @feature_version: Output field containing the feature version number
> + * @val: Output field containing the queried value
> + *
> + * This structure is used with the IOCTL_PMF_POPULATE_DATA ioctl command
> + * to exchange data between user space and the AMD PMF kernel driver.
> + * The user provides the control_code to specify the query type, and the
> + * driver populates the remaining fields with the response data.
> + */
> +struct amd_pmf_ioctl_info {
> + enum pmf_ioctl_id control_code; /* In */
> + bool feature_supported; /* Out */
> + unsigned long feature_version; /* Out */
> + long long val; /* Out */
> +};
> +
> +#endif /* _UAPI_LINUX_AMD_PMF_H */
>
--
i.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 1/7] platform/x86/amd/pmf: Add util layer and userspace misc device interface
2026-03-01 13:11 ` [PATCH v3 1/7] platform/x86/amd/pmf: Add util layer and userspace misc device interface Shyam Sundar S K
2026-03-01 18:45 ` Randy Dunlap
2026-03-25 13:16 ` Ilpo Järvinen
@ 2026-03-25 13:18 ` Ilpo Järvinen
2026-03-25 14:05 ` Ilpo Järvinen
3 siblings, 0 replies; 30+ messages in thread
From: Ilpo Järvinen @ 2026-03-25 13:18 UTC (permalink / raw)
To: Shyam Sundar S K
Cc: Hans de Goede, platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami
On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
> Add a util layer to AMD PMF that exposes a minimal userspace interface
> via a misc character device for metrics monitoring and feature discovery.
>
> This creates /dev/amdpmf_interface with basic ioctl support to retrieve
> PMF metrics such as:
> *Power source and power slider position
> *Platform type, lid state, and user presence
> *Skin temperature and ambient light
> *BIOS input parameters (1-10)
> *Graphics workload metrics
> *CPU C-state residency (average and maximum)
> *Socket power consumption
Also, can you please add a space after those * chars.
Consider e.g. 2 space indentation for the list.
> +/**
> + * struct amd_pmf_ioctl_info - Structure for PMF ioctl data exchange
> + * @control_code: Input parameter specifying which data to query (enum pmf_ioctl_id)
> + * @feature_supported: Output flag indicating if the queried feature is supported
> + * @feature_version: Output field containing the feature version number
> + * @val: Output field containing the queried value
> + *
> + * This structure is used with the IOCTL_PMF_POPULATE_DATA ioctl command
> + * to exchange data between user space and the AMD PMF kernel driver.
> + * The user provides the control_code to specify the query type, and the
> + * driver populates the remaining fields with the response data.
> + */
> +struct amd_pmf_ioctl_info {
> + enum pmf_ioctl_id control_code; /* In */
> + bool feature_supported; /* Out */
> + unsigned long feature_version; /* Out */
> + long long val; /* Out */
Align comments.
--
i.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 4/7] platform/x86/amd/pmf: Store commonly used enums in the header file
2026-03-01 13:11 ` [PATCH v3 4/7] platform/x86/amd/pmf: Store commonly used enums in the header file Shyam Sundar S K
@ 2026-03-25 13:34 ` Ilpo Järvinen
0 siblings, 0 replies; 30+ messages in thread
From: Ilpo Järvinen @ 2026-03-25 13:34 UTC (permalink / raw)
To: Shyam Sundar S K
Cc: Hans de Goede, platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami
On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
> Relocate commonly used enums from multiple source files into a shared
> header file to simplify code structure, improve readability, and
> enhance maintainability. Also, remove the initialization of the first
> enum member, since it is not needed.
>
> Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
> Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> ---
> .../amd-sfh-hid/sfh1_1/amd_sfh_interface.c | 1 +
> drivers/platform/x86/amd/pmf/pmf.h | 22 ------
> drivers/platform/x86/amd/pmf/spc.c | 1 +
> include/linux/amd-pmf-io.h | 9 ---
> include/uapi/linux/amd-pmf.h | 74 +++++++++++++++++++
> 5 files changed, 76 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
> index 837d59e7a661..d9751c9ebfe8 100644
> --- a/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
> +++ b/drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
> @@ -7,6 +7,7 @@
> *
> * Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com>
> */
> +#include <linux/amd-pmf.h>
> #include <linux/amd-pmf-io.h>
> #include <linux/io-64-nonatomic-lo-hi.h>
> #include <linux/iopoll.h>
> diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
> index 0d879f0fd8e2..f668c0450457 100644
> --- a/drivers/platform/x86/amd/pmf/pmf.h
> +++ b/drivers/platform/x86/amd/pmf/pmf.h
> @@ -681,14 +681,6 @@ enum system_state {
> SYSTEM_STATE_MAX,
> };
>
> -enum ta_slider {
> - TA_BEST_BATTERY,
> - TA_BETTER_BATTERY,
> - TA_BETTER_PERFORMANCE,
> - TA_BEST_PERFORMANCE,
> - TA_MAX,
> -};
> -
> struct amd_pmf_pb_bitmap {
> const char *name;
> u32 bit_mask;
> @@ -720,20 +712,6 @@ static const struct amd_pmf_pb_bitmap custom_bios_inputs_v1[] __used = {
> {"NOTIFY_CUSTOM_BIOS_INPUT10", BIT(16)},
> };
>
> -enum platform_type {
> - PTYPE_UNKNOWN = 0,
> - LID_CLOSE,
> - CLAMSHELL,
> - FLAT,
> - TENT,
> - STAND,
> - TABLET,
> - BOOK,
> - PRESENTATION,
> - PULL_FWD,
> - PTYPE_INVALID = 0xf,
> -};
> -
> /* Command ids for TA communication */
> enum ta_pmf_command {
> TA_PMF_COMMAND_POLICY_BUILDER_INITIALIZE,
> diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c
> index f48678a23cc7..a40419b5e1b7 100644
> --- a/drivers/platform/x86/amd/pmf/spc.c
> +++ b/drivers/platform/x86/amd/pmf/spc.c
> @@ -10,6 +10,7 @@
> */
>
> #include <acpi/button.h>
> +#include <linux/amd-pmf.h>
> #include <linux/amd-pmf-io.h>
> #include <linux/cleanup.h>
> #include <linux/power_supply.h>
> diff --git a/include/linux/amd-pmf-io.h b/include/linux/amd-pmf-io.h
> index 55198d2875cc..e014d4ce5a20 100644
> --- a/include/linux/amd-pmf-io.h
> +++ b/include/linux/amd-pmf-io.h
> @@ -52,15 +52,6 @@ struct amd_sfh_info {
> u32 laptop_placement;
> };
>
> -enum laptop_placement {
> - LP_UNKNOWN = 0,
> - ON_TABLE,
> - ON_LAP_MOTION,
> - IN_BAG,
> - OUT_OF_BAG,
> - LP_UNDEFINED,
> -};
> -
> /**
> * struct amd_pmf_npu_metrics: Get NPU metrics data from PMF driver
> * @npuclk_freq: NPU clock frequency [MHz]
> diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
> index f34c5d744039..00fab9269238 100644
> --- a/include/uapi/linux/amd-pmf.h
> +++ b/include/uapi/linux/amd-pmf.h
> @@ -32,6 +32,80 @@
> */
> #define IOCTL_PMF_POPULATE_DATA _IOWR(AMD_PMF_IOC_MAGIC, 0x00, struct amd_pmf_ioctl_info)
>
> +/**
> + * enum laptop_placement - Describes the physical placement of the laptop
> + * @LP_UNKNOWN: Placement cannot be determined
> + * @ON_TABLE: Laptop is placed on a stable surface like a table or desk
> + * @ON_LAP_MOTION: Laptop is on a lap with detected motion
> + * @IN_BAG: Laptop is detected to be inside a bag or case
> + * @OUT_OF_BAG: Laptop has been removed from bag or case
> + * @LP_UNDEFINED: Placement state is undefined
> + *
> + * This enumeration represents the physical placement state of the laptop
> + * as detected by platform sensors. Used for adaptive power management
> + * and thermal policies.
> + */
> +enum laptop_placement {
> + LP_UNKNOWN,
> + ON_TABLE,
> + ON_LAP_MOTION,
> + IN_BAG,
> + OUT_OF_BAG,
> + LP_UNDEFINED,
These look way too generic names to be used in an uapi header, so you'll
also need to add a prefix.
> +};
> +
> +/**
> + * enum ta_slider - Trusted Application power slider positions
> + * @TA_BEST_BATTERY: Maximum battery savings, minimal performance
> + * @TA_BETTER_BATTERY: Balanced towards battery life
> + * @TA_BETTER_PERFORMANCE: Balanced towards performance
> + * @TA_BEST_PERFORMANCE: Maximum performance, higher power consumption
> + * @TA_MAX: Sentinel value indicating maximum enum value
> + *
> + * This enumeration defines the power slider positions used by the
> + * AMD PMF Trusted Application for dynamic power management decisions.
> + * These correspond to the Windows power slider UI positions.
> + */
> +enum ta_slider {
> + TA_BEST_BATTERY,
> + TA_BETTER_BATTERY,
> + TA_BETTER_PERFORMANCE,
> + TA_BEST_PERFORMANCE,
> + TA_MAX,
> +};
> +
> +/**
> + * enum platform_type - Describes the physical form factor orientation
> + * @PTYPE_UNKNOWN: Platform type cannot be determined
> + * @LID_CLOSE: Laptop lid is closed
> + * @CLAMSHELL: Traditional laptop mode with keyboard and screen
> + * @FLAT: Device is lying flat on a surface
> + * @TENT: Device is in tent mode (keyboard folded back, standing)
> + * @STAND: Device is propped up in stand orientation
> + * @TABLET: Device is in tablet mode with keyboard hidden
> + * @BOOK: Device is in book reading orientation
> + * @PRESENTATION: Device is in presentation mode
> + * @PULL_FWD: Screen is pulled forward towards user
> + * @PTYPE_INVALID: Invalid platform type marker
> + *
> + * This enumeration describes the current physical orientation or form
> + * factor of convertible/2-in-1 devices. Used for optimizing power and
> + * thermal management based on device posture.
> + */
> +enum platform_type {
> + PTYPE_UNKNOWN,
> + LID_CLOSE,
> + CLAMSHELL,
> + FLAT,
> + TENT,
> + STAND,
> + TABLET,
> + BOOK,
> + PRESENTATION,
> + PULL_FWD,
> + PTYPE_INVALID = 0xf,
These too are too generic names.
> +};
> +
> /**
> * enum pmf_ioctl_id - Control codes for PMF ioctl operations
> * @IOCTL_POWER_SOURCE: Query current power source (AC/DC)
>
--
i.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 5/7] platform/x86/amd/pmf: Move debug helper functions to UAPI header
2026-03-01 13:11 ` [PATCH v3 5/7] platform/x86/amd/pmf: Move debug helper functions to UAPI header Shyam Sundar S K
@ 2026-03-25 13:39 ` Ilpo Järvinen
2026-03-30 11:45 ` Shyam Sundar S K
0 siblings, 1 reply; 30+ messages in thread
From: Ilpo Järvinen @ 2026-03-25 13:39 UTC (permalink / raw)
To: Shyam Sundar S K, Hans de Goede
Cc: platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami
On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
> These debug helper functions convert enumerated values to appropriate
> message and can be useful for userspace tools and other kernel components
> that need to interpret AMD PMF state values.
>
> By making them inline functions in the UAPI header, they become available
> to both kernel and userspace without code duplication.
>
> Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
> Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
Here too I'm not happy with the naming and I'm a little skeptical about
the sharing string conversion helpers as well.
Hans,
do you have something to say on having this kind of string conversions in
an uapi header?
> ---
> drivers/platform/x86/amd/pmf/spc.c | 54 --------------
> drivers/platform/x86/amd/pmf/util.c | 12 ----
> include/uapi/linux/amd-pmf.h | 105 ++++++++++++++++++++++++++++
> 3 files changed, 105 insertions(+), 66 deletions(-)
>
> diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c
> index a40419b5e1b7..f91feaac5238 100644
> --- a/drivers/platform/x86/amd/pmf/spc.c
> +++ b/drivers/platform/x86/amd/pmf/spc.c
> @@ -18,60 +18,6 @@
> #include "pmf.h"
>
> #ifdef CONFIG_AMD_PMF_DEBUG
> -static const char *platform_type_as_str(u16 platform_type)
> -{
> - switch (platform_type) {
> - case CLAMSHELL:
> - return "CLAMSHELL";
> - case FLAT:
> - return "FLAT";
> - case TENT:
> - return "TENT";
> - case STAND:
> - return "STAND";
> - case TABLET:
> - return "TABLET";
> - case BOOK:
> - return "BOOK";
> - case PRESENTATION:
> - return "PRESENTATION";
> - case PULL_FWD:
> - return "PULL_FWD";
> - default:
> - return "UNKNOWN";
> - }
> -}
> -
> -static const char *laptop_placement_as_str(u16 device_state)
> -{
> - switch (device_state) {
> - case ON_TABLE:
> - return "ON_TABLE";
> - case ON_LAP_MOTION:
> - return "ON_LAP_MOTION";
> - case IN_BAG:
> - return "IN_BAG";
> - case OUT_OF_BAG:
> - return "OUT_OF_BAG";
> - default:
> - return "UNKNOWN";
> - }
> -}
> -
> -static const char *ta_slider_as_str(unsigned int state)
> -{
> - switch (state) {
> - case TA_BEST_PERFORMANCE:
> - return "PERFORMANCE";
> - case TA_BETTER_PERFORMANCE:
> - return "BALANCED";
> - case TA_BEST_BATTERY:
> - return "POWER_SAVER";
> - default:
> - return "Unknown TA Slider State";
> - }
> -}
> -
> static u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index)
> {
> switch (index) {
> diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
> index 9a14467f412c..20dc7aa9f250 100644
> --- a/drivers/platform/x86/amd/pmf/util.c
> +++ b/drivers/platform/x86/amd/pmf/util.c
> @@ -18,18 +18,6 @@
>
> #define AMD_PMF_IOCTL_VERSION 0x02
>
> -/* Convert BIOS input control code to array index (0-9) */
> -static int amd_pmf_get_bios_idx(u32 control_code)
> -{
> - if (control_code >= IOCTL_BIOS_INPUT_1 && control_code <= IOCTL_BIOS_INPUT_10)
> - return control_code - IOCTL_BIOS_INPUT_1;
> -
> - if (control_code >= IOCTL_BIOS_OUTPUT_1 && control_code <= IOCTL_BIOS_OUTPUT_10)
> - return control_code - IOCTL_BIOS_OUTPUT_1;
> -
> - return -EINVAL;
> -}
> -
> static long long amd_pmf_populate_bios_input(struct ta_pmf_enact_table *in, u32 control_code)
> {
> u32 idx;
> diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
> index 00fab9269238..e2125b304b83 100644
> --- a/include/uapi/linux/amd-pmf.h
> +++ b/include/uapi/linux/amd-pmf.h
> @@ -14,6 +14,7 @@
> #ifndef _UAPI_LINUX_AMD_PMF_H
> #define _UAPI_LINUX_AMD_PMF_H
>
> +#include <linux/errno.h>
> #include <linux/ioctl.h>
> #include <linux/types.h>
>
> @@ -106,6 +107,88 @@ enum platform_type {
> PTYPE_INVALID = 0xf,
> };
>
> +/**
> + * platform_type_as_str() - Convert platform type enum to string
> + * @platform_type: The platform type value to convert
> + *
> + * Returns a human-readable string representation of the platform type.
> + *
> + * Return: Constant string describing the platform type, or "UNKNOWN"
> + * if the value is not recognized.
> + */
> +static inline const char *platform_type_as_str(unsigned int platform_type)
> +{
> + switch (platform_type) {
> + case CLAMSHELL:
> + return "CLAMSHELL";
> + case FLAT:
> + return "FLAT";
> + case TENT:
> + return "TENT";
> + case STAND:
> + return "STAND";
> + case TABLET:
> + return "TABLET";
> + case BOOK:
> + return "BOOK";
> + case PRESENTATION:
> + return "PRESENTATION";
> + case PULL_FWD:
> + return "PULL_FWD";
> + default:
> + return "UNKNOWN";
> + }
> +}
> +
> +/**
> + * laptop_placement_as_str() - Convert laptop placement enum to string
> + * @device_state: The laptop placement value to convert
> + *
> + * Returns a human-readable string representation of the laptop placement.
> + *
> + * Return: Constant string describing the placement, or "UNKNOWN"
> + * if the value is not recognized.
> + */
> +static inline const char *laptop_placement_as_str(unsigned int device_state)
> +{
> + switch (device_state) {
> + case ON_TABLE:
> + return "ON_TABLE";
> + case ON_LAP_MOTION:
> + return "ON_LAP_MOTION";
> + case IN_BAG:
> + return "IN_BAG";
> + case OUT_OF_BAG:
> + return "OUT_OF_BAG";
> + default:
> + return "UNKNOWN";
> + }
> +}
> +
> +/**
> + * ta_slider_as_str() - Convert TA slider enum to string
> + * @state: The TA slider state value to convert
> + *
> + * Returns a human-readable string representation of the power slider
> + * position suitable for display purposes.
> + *
> + * Return: Constant string describing the slider state, or
> + * "Unknown TA Slider State" if the value is not recognized.
> + */
> +static inline const char *ta_slider_as_str(unsigned int state)
> +{
> + switch (state) {
> + case TA_BEST_PERFORMANCE:
> + return "PERFORMANCE";
> + case TA_BETTER_PERFORMANCE:
> + return "BALANCED";
> + case TA_BEST_BATTERY:
> + return "POWER_SAVER";
> + default:
> + return "Unknown TA Slider State";
> + }
> +}
> +
> /**
> * enum pmf_ioctl_id - Control codes for PMF ioctl operations
> * @IOCTL_POWER_SOURCE: Query current power source (AC/DC)
> @@ -197,6 +280,28 @@ enum pmf_ioctl_id {
> IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC
> };
>
> +/**
> + * amd_pmf_get_bios_idx() - Convert BIOS control code to array index
> + * @control_code: The BIOS input or output control code
> + *
> + * Converts a BIOS input (IOCTL_BIOS_INPUT_1 to IOCTL_BIOS_INPUT_10) or
> + * BIOS output (IOCTL_BIOS_OUTPUT_1 to IOCTL_BIOS_OUTPUT_10) control code
> + * to a zero-based array index (0-9).
> + *
> + * Return: Array index (0-9) on success, -EINVAL if the control code
> + * is not a valid BIOS input or output code.
> + */
> +static inline int amd_pmf_get_bios_idx(unsigned int control_code)
> +{
> + if (control_code >= IOCTL_BIOS_INPUT_1 && control_code <= IOCTL_BIOS_INPUT_10)
> + return control_code - IOCTL_BIOS_INPUT_1;
> +
> + if (control_code >= IOCTL_BIOS_OUTPUT_1 && control_code <= IOCTL_BIOS_OUTPUT_10)
> + return control_code - IOCTL_BIOS_OUTPUT_1;
> +
> + return -EINVAL;
> +}
> +
> /**
> * struct amd_pmf_ioctl_info - Structure for PMF ioctl data exchange
> * @control_code: Input parameter specifying which data to query (enum pmf_ioctl_id)
>
--
i.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 6/7] platform/x86/amd/pmf: Introduce AMD PMF testing tool for driver metrics and features
2026-03-01 13:11 ` [PATCH v3 6/7] platform/x86/amd/pmf: Introduce AMD PMF testing tool for driver metrics and features Shyam Sundar S K
@ 2026-03-25 13:54 ` Ilpo Järvinen
2026-03-25 15:07 ` Mario Limonciello
0 siblings, 1 reply; 30+ messages in thread
From: Ilpo Järvinen @ 2026-03-25 13:54 UTC (permalink / raw)
To: Shyam Sundar S K, Shuah Khan, Shuah Khan, linux-kselftest
Cc: Hans de Goede, platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami
+ Selftest people.
On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
> This tool leverages amd-pmf ioctls exposed via the util layer, allowing
> validation of its newly integrated util layer and /dev/amdpmf_interface.
> It includes a user-space test application, test_pmf, designed to interact
> with the PMF driver and retrieve relevant metrics for the testing and
> analysis.
>
> It provides definitions for test metrics, feature IDs, and device states,
> and includes tests for various AMD PMF metrics such as power source, skin
> temperature, battery state, and custom BIOS inputs/outputs. It also
> enables the testing of PMF metrics data and feature support reporting.
>
> Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
> Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> ---
> tools/testing/selftests/Makefile | 1 +
> .../drivers/platform/x86/amd/pmf/Makefile | 8 +
> .../drivers/platform/x86/amd/pmf/test_pmf.c | 243 ++++++++++++++++++
> 3 files changed, 252 insertions(+)
> create mode 100644 tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile
> create mode 100644 tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c
Please Cc also selftest people in the next version submission! Maube you
should also check why your patch sending process did not capture those
receipient for you.
To me it looks this "tool" doesn't really perform a selftest the way I've
understood "selftests" work. That is, it doesn't have notion of Pass/Fail
at all AFAICT. I'm not sure if there are other selftests like this but
hopefully the selftest people know.
> diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
> index 450f13ba4cca..d850fb09eeb9 100644
> --- a/tools/testing/selftests/Makefile
> +++ b/tools/testing/selftests/Makefile
> @@ -26,6 +26,7 @@ TARGETS += drivers/net/netconsole
> TARGETS += drivers/net/team
> TARGETS += drivers/net/virtio_net
> TARGETS += drivers/platform/x86/intel/ifs
> +TARGETS += drivers/platform/x86/amd/pmf
> TARGETS += dt
> TARGETS += efivarfs
> TARGETS += exec
> diff --git a/tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile b/tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile
> new file mode 100644
> index 000000000000..876424941e83
> --- /dev/null
> +++ b/tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile
> @@ -0,0 +1,8 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +CFLAGS += $(KHDR_INCLUDES)
> +
> +TEST_GEN_PROGS := test_pmf
> +
> +top_srcdir ?=../../../../..
> +
> +include ../../../../../lib.mk
> diff --git a/tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c b/tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c
> new file mode 100644
> index 000000000000..a040ef01ba90
> --- /dev/null
> +++ b/tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c
> @@ -0,0 +1,243 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * AMD Platform Management Framework Test Tool
> + *
> + * Copyright (c) 2026, Advanced Micro Devices, Inc.
> + * All Rights Reserved.
> + *
> + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> + * Sanket Goswami <Sanket.Goswami@amd.com>
> + */
> +
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <inttypes.h>
> +#include <stdbool.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <string.h>
> +#include <sys/ioctl.h>
> +#include <unistd.h>
> +#include <linux/amd-pmf.h>
> +
> +#include "../../../../../kselftest.h"
> +
> +#define DEVICE_NODE "/dev/amdpmf_interface"
> +
> +static int pmf_open_device(void)
> +{
> + int fd;
> +
> + fd = open(DEVICE_NODE, O_RDONLY);
> + if (fd < 0)
> + fprintf(stderr, "opening PMF Device Node failed: %s\n", strerror(errno));
> +
> + return fd;
> +}
> +
> +/* Helper to run IOCTL_PMF_POPULATE_DATA for one control code and return 0 on success. */
Reflow this comment to 80 chars.
> +static int pmf_get_fd(int fd, enum pmf_ioctl_id code, struct amd_pmf_ioctl_info *out)
> +{
> + struct amd_pmf_ioctl_info info = {0};
= {}; should be enough to initialize to default values.
> + int ret;
> +
> + if (!out)
> + return -EINVAL;
> +
> + info.control_code = code;
> +
> + ret = ioctl(fd, IOCTL_PMF_POPULATE_DATA, &info);
> + if (ret < 0)
> + return ret;
> +
> + *out = info;
> + return 0;
> +}
> +
> +static int pmf_get_data(enum pmf_ioctl_id code, struct amd_pmf_ioctl_info *out)
> +{
> + int fd, ret;
> +
> + fd = pmf_open_device();
> + if (fd < 0)
> + return fd;
> +
> + ret = pmf_get_fd(fd, code, out);
> +
> + close(fd);
> + return ret;
> +}
> +
> +static int pmf_get_feature_status(unsigned int code)
> +{
> + struct amd_pmf_ioctl_info info = {0};
> + int ret;
> +
> + ret = pmf_get_data(code, &info);
> + if (ret < 0)
> + return ret;
> +
> + switch (code) {
> + case IOCTL_FEATURE_AUTO_MODE:
> + printf("Auto Mode: %-24s\n", info.feature_supported ? "Yes" : "No");
> + break;
> + case IOCTL_FEATURE_STATIC_POWER_SLIDER:
> + printf("Static Power Slider: %-24s\n", info.feature_supported ? "Yes" : "No");
> + break;
> + case IOCTL_FEATURE_POLICY_BUILDER:
> + printf("Policy Builder: %s\n", info.feature_supported ? "Yes" : "No");
> + break;
> + case IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC:
> + printf("Dynamic Power Slider AC: %s\n", info.feature_supported ? "Yes" : "No");
> + break;
> + case IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC:
> + printf("Dynamic Power Slider DC: %s\n", info.feature_supported ? "Yes" : "No");
> + break;
> + default:
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int pmf_get_device_state(unsigned int code)
> +{
> + struct amd_pmf_ioctl_info info = {0};
> + int ret;
> +
> + ret = pmf_get_data(code, &info);
> + if (ret < 0)
> + return ret;
> +
> + switch (code) {
> + case IOCTL_PLATFORM_TYPE:
> + printf("Platform Type: %s\n", platform_type_as_str(info.val));
> + break;
> + case IOCTL_LAPTOP_PLACEMENT:
> + printf("Laptop placement: %s\n", laptop_placement_as_str(info.val));
> + break;
> + case IOCTL_LID_STATE:
> + printf("Lid State: %s\n", info.val ? "Close" : "Open");
> + break;
> + case IOCTL_USER_PRESENCE:
> + printf("User Presence: %s\n", info.val ? "Present" : "Away");
> + break;
> + default:
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int pmf_get_custom_bios_input(unsigned int code)
> +{
> + struct amd_pmf_ioctl_info info = {0};
> + int idx, ret;
> +
> + ret = pmf_get_data(code, &info);
> + if (ret < 0)
> + return ret;
> +
> + switch (code) {
> + case IOCTL_BIOS_INPUT_1 ... IOCTL_BIOS_INPUT_10:
> + idx = amd_pmf_get_bios_idx(code);
> + printf("Custom BIOS input%u: %lu\n", idx + 1, (int64_t)info.val);
%lu is for printing unsigned long, not int64_t.
> + break;
> + default:
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int pmf_get_bios_output(unsigned int code)
> +{
> + struct amd_pmf_ioctl_info info = {0};
> + int idx, ret;
> +
> + ret = pmf_get_data(code, &info);
> + if (ret < 0)
> + return ret;
> +
> + switch (code) {
> + case IOCTL_BIOS_OUTPUT_1 ... IOCTL_BIOS_OUTPUT_10:
> + idx = amd_pmf_get_bios_idx(code);
> + printf("BIOS output%u: %lu\n", idx + 1, (int64_t)info.val);
> + break;
> + default:
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +static int pmf_get_misc_info(unsigned int code)
> +{
> + struct amd_pmf_ioctl_info info = {0};
> + int ret;
> +
> + ret = pmf_get_data(code, &info);
> + if (ret < 0)
> + return ret;
> +
> + switch (code) {
> + case IOCTL_POWER_SLIDER_POSITION:
> + printf("Slider Position: %s\n", ta_slider_as_str(info.val));
> + break;
> + case IOCTL_SKIN_TEMP:
> + printf("Skin Temperature: %lu\n", (int64_t)info.val);
> + break;
> + case IOCTL_GFX_WORKLOAD:
> + printf("GFX Busy: %lu\n", (int64_t)info.val);
> + break;
> + case IOCTL_AMBIENT_LIGHT:
> + printf("Ambient Light: %ld\n", (int64_t)info.val);
> + break;
> + case IOCTL_AVG_C0_RES:
> + printf("Avg C0 Residency: %lu\n", (int64_t)info.val);
> + break;
> + case IOCTL_MAX_C0_RES:
> + printf("Max C0 Residency: %lu\n", (int64_t)info.val);
> + break;
> + case IOCTL_SOCKET_POWER:
> + printf("Socket Power: %lu\n", (int64_t)info.val);
Please think the printf formatting strings and types through.
> + break;
> + default:
> + return -1;
> + }
> +
> + return 0;
> +}
> +
> +int main(void)
> +{
> + unsigned int idx;
> +
> + printf("Feature Name Supported\n");
> + printf("---------------------------------\n");
> + for (idx = IOCTL_FEATURE_AUTO_MODE; idx <= IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC; idx++)
> + pmf_get_feature_status(idx);
> +
> + printf("\nDevice State\n---------------\n");
> + for (idx = IOCTL_PLATFORM_TYPE; idx <= IOCTL_USER_PRESENCE; idx++)
> + pmf_get_device_state(idx);
> +
> + printf("\nCustom BIOS Inputs\n-------------------\n");
> + for (idx = IOCTL_BIOS_INPUT_1; idx <= IOCTL_BIOS_INPUT_10; idx++)
> + pmf_get_custom_bios_input(idx);
> +
> + printf("\nBIOS Outputs\n--------------\n");
> + for (idx = IOCTL_BIOS_OUTPUT_1; idx <= IOCTL_BIOS_OUTPUT_10; idx++)
> + pmf_get_bios_output(idx);
> +
> + printf("\nMisc\n------\n");
> + pmf_get_misc_info(IOCTL_SKIN_TEMP);
> + pmf_get_misc_info(IOCTL_GFX_WORKLOAD);
> + pmf_get_misc_info(IOCTL_AMBIENT_LIGHT);
> + pmf_get_misc_info(IOCTL_AVG_C0_RES);
> + pmf_get_misc_info(IOCTL_MAX_C0_RES);
> + pmf_get_misc_info(IOCTL_SOCKET_POWER);
> + pmf_get_misc_info(IOCTL_POWER_SLIDER_POSITION);
> +
> + return 0;
> +}
>
--
i.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 7/7] Documentation/ABI: add testing entry for AMD PMF misc device interface
2026-03-01 13:11 ` [PATCH v3 7/7] Documentation/ABI: add testing entry for AMD PMF misc device interface Shyam Sundar S K
@ 2026-03-25 13:58 ` Ilpo Järvinen
2026-03-25 15:08 ` Mario Limonciello
0 siblings, 1 reply; 30+ messages in thread
From: Ilpo Järvinen @ 2026-03-25 13:58 UTC (permalink / raw)
To: Shyam Sundar S K
Cc: Hans de Goede, platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami
On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
> Add a Documentation/ABI/testing entry describing the AMD PMF util layer
> misc device (/dev/amdpmf_interface) and the initial ioctls used to query
> feature support and metrics data information. This interface is available
> when CONFIG_AMD_PMF_UTIL_SUPPORT=y.
>
> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> ---
> .../ABI/testing/misc-amdpmf_interface | 70 +++++++++++++++++++
> MAINTAINERS | 1 +
> 2 files changed, 71 insertions(+)
> create mode 100644 Documentation/ABI/testing/misc-amdpmf_interface
>
> diff --git a/Documentation/ABI/testing/misc-amdpmf_interface b/Documentation/ABI/testing/misc-amdpmf_interface
> new file mode 100644
> index 000000000000..62b0175e1345
> --- /dev/null
> +++ b/Documentation/ABI/testing/misc-amdpmf_interface
> @@ -0,0 +1,70 @@
> +What: /dev/amdpmf_interface
> +Date: February 2026
As always, these get stale as we go. Please estimate the targetted kernel
version's release date instead to fill this field in.
> +KernelVersion: 7.1
> +Contact: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> +Description:
> + The AMD Platform Management Framework (PMF) util layer exposes a
> + minimal user-space interface via a misc character device for
> + feature discovery and metrics monitoring.
> +
> + When CONFIG_AMD_PMF_UTIL_SUPPORT is enabled, the driver creates
> + a character device:
> +
> + ======================
> + /dev/amdpmf_interface
> + ======================
> +
> + The interface currently supports following ioctls:
> +
> + ======================== =========================================
> + IOCTL Usage
> + IOCTL_PMF_POPULATE_DATA User passes a struct amd_pmf_ioctl_info
> + with control_code set to the desired
> + metric or feature ID. The driver returns
> + the requested data in val, or feature
> + support status in feature_supported.
> + ======================== =========================================
> +
> + Following are the control codes supported (enum pmf_ioctl_id):
> +
> + ============== ================================================================
> + Control Code Description
> + 0 IOCTL_POWER_SOURCE: AC/DC power source
> + 1 IOCTL_POWER_SLIDER_POSITION: Current power slider
> + 2 IOCTL_PLATFORM_TYPE: Platform form factor
> + 3 IOCTL_LAPTOP_PLACEMENT: Device placement (on table/lap/bag)
> + 4 IOCTL_LID_STATE: Lid open/closed status
> + 6 IOCTL_SKIN_TEMP: Skin temperature (degrees Celsius)
> + 7 IOCTL_USER_PRESENCE: User presence detection
> + 10-19 IOCTL_BIOS_INPUT_1 to IOCTL_BIOS_INPUT_10: Custom BIOS inputs
> + 20 IOCTL_GFX_WORKLOAD: Graphics workload percentage
> + 29 IOCTL_AMBIENT_LIGHT: Ambient light sensor reading
> + 36 IOCTL_AVG_C0_RES: Average C0 state residency
> + 37 IOCTL_MAX_C0_RES: Maximum C0 state residency
> + 50 IOCTL_SOCKET_POWER: Socket power consumption
> + 52-61 IOCTL_BIOS_OUTPUT_1 to IOCTL_BIOS_OUTPUT_10: BIOS output values
> + ============== ================================================================
> +
> + Feature Discovery:
> +
> + ============== =============================================================
> + Control Code Description
> + 62 IOCTL_FEATURE_AUTO_MODE: Auto Mode feature support
> + 63 IOCTL_FEATURE_STATIC_POWER_SLIDER: Static Power Slider
> + 64 IOCTL_FEATURE_POLICY_BUILDER: Policy Builder (Smart PC)
> + 65 IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC: Dynamic slider on AC
> + 66 IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC: Dynamic slider on DC
> + ============== =============================================================
> +
> + Following are the return codes:
> +
> + ============= ============================================================
> + Return code Description
> + 0 success
> + EINVAL control_code is not recognized or handle is not available
> + EFAULT copy_to_user/copy_from_user failures
> + ENODEV PMF device not available
> + ============= ============================================================
> +
> + User-space tools integrating with AMD PMF to discover capabilities and
> + monitor real-time metrics for thermal and power management validation.
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 55af015174a5..78773373172c 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1224,6 +1224,7 @@ AMD PMF DRIVER
> M: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> L: platform-driver-x86@vger.kernel.org
> S: Supported
> +F: Documentation/ABI/testing/misc-amdpmf_interface
> F: Documentation/ABI/testing/sysfs-amd-pmf
> F: drivers/platform/x86/amd/pmf/
>
>
--
i.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 1/7] platform/x86/amd/pmf: Add util layer and userspace misc device interface
2026-03-01 13:11 ` [PATCH v3 1/7] platform/x86/amd/pmf: Add util layer and userspace misc device interface Shyam Sundar S K
` (2 preceding siblings ...)
2026-03-25 13:18 ` Ilpo Järvinen
@ 2026-03-25 14:05 ` Ilpo Järvinen
2026-03-30 12:12 ` Shyam Sundar S K
3 siblings, 1 reply; 30+ messages in thread
From: Ilpo Järvinen @ 2026-03-25 14:05 UTC (permalink / raw)
To: Shyam Sundar S K
Cc: Hans de Goede, platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami
On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
> Add a util layer to AMD PMF that exposes a minimal userspace interface
> via a misc character device for metrics monitoring and feature discovery.
>
> This creates /dev/amdpmf_interface with basic ioctl support to retrieve
> PMF metrics such as:
> *Power source and power slider position
> *Platform type, lid state, and user presence
> *Skin temperature and ambient light
> *BIOS input parameters (1-10)
> *Graphics workload metrics
> *CPU C-state residency (average and maximum)
> *Socket power consumption
>
> The interface enables smoother integration with userspace tools such as
> AMD SystemDeck [1], which is widely used for monitoring and controlling
> power and thermal behavior on AMD platforms. These tools help designers
> keep major components within thermal limits to ensure proper operation
> and enhance overall system stability and reliability.
>
> The feature is gated behind the CONFIG_AMD_PMF_UTIL_SUPPORT Kconfig
> option, allowing it to be disabled if not needed. The implementation
> uses existing PMF infrastructure to populate data from the TA (Trusted
> Application) shared memory buffer.
>
> Link: https://docs.amd.com/v/u/en-US/68773_0.50 [1]
>
> Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
> Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> ---
> drivers/platform/x86/amd/pmf/Kconfig | 10 ++
> drivers/platform/x86/amd/pmf/Makefile | 2 +
> drivers/platform/x86/amd/pmf/core.c | 5 +
> drivers/platform/x86/amd/pmf/pmf.h | 9 ++
> drivers/platform/x86/amd/pmf/util.c | 174 ++++++++++++++++++++++++++
> include/uapi/linux/amd-pmf.h | 115 +++++++++++++++++
> 6 files changed, 315 insertions(+)
> create mode 100644 drivers/platform/x86/amd/pmf/util.c
> create mode 100644 include/uapi/linux/amd-pmf.h
>
> diff --git a/drivers/platform/x86/amd/pmf/Kconfig b/drivers/platform/x86/amd/pmf/Kconfig
> index 25b8f7ae3abd..ad21f679b8ab 100644
> --- a/drivers/platform/x86/amd/pmf/Kconfig
> +++ b/drivers/platform/x86/amd/pmf/Kconfig
> @@ -30,3 +30,13 @@ config AMD_PMF_DEBUG
> in the PMF config store.
>
> Say Y here to enable more debug logs and Say N here if you are not sure.
> +
> +config AMD_PMF_UTIL_SUPPORT
> + bool "AMD PMF Util layer support"
> + depends on AMD_PMF
> + help
> + Enabling this option provides a character device for userspace to capture
> + PMF features (Smart PC Builder, Auto Mode, Static Power Slider, Dynamic
> + Power Slider AC/DC) along with PMF metrics from the AMD PMF driver.
> +
> + Say Y here to enable it and Say N here if you are not sure.
> diff --git a/drivers/platform/x86/amd/pmf/Makefile b/drivers/platform/x86/amd/pmf/Makefile
> index 5978464e0eb7..bf7aad80b9e9 100644
> --- a/drivers/platform/x86/amd/pmf/Makefile
> +++ b/drivers/platform/x86/amd/pmf/Makefile
> @@ -8,3 +8,5 @@ obj-$(CONFIG_AMD_PMF) += amd-pmf.o
> amd-pmf-y := core.o acpi.o sps.o \
> auto-mode.o cnqf.o \
> tee-if.o spc.o
> +# Build util.c only when AMD_PMF_UTIL_SUPPORT is enabled
> +amd-pmf-$(CONFIG_AMD_PMF_UTIL_SUPPORT) += util.o
> diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
> index b9e5a2cf3aae..919d02f30aae 100644
> --- a/drivers/platform/x86/amd/pmf/core.c
> +++ b/drivers/platform/x86/amd/pmf/core.c
> @@ -634,6 +634,10 @@ static int amd_pmf_probe(struct platform_device *pdev)
>
> pmf_device = dev->dev;
>
> + err = amd_pmf_cdev_register(dev);
> + if (err)
> + dev_warn(dev->dev, "failed to register util interface: %d\n", err);
> +
> dev_info(dev->dev, "registered PMF device successfully\n");
>
> return 0;
> @@ -646,6 +650,7 @@ static void amd_pmf_remove(struct platform_device *pdev)
> amd_pmf_deinit_features(dev);
> if (is_apmf_func_supported(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
> amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_UNLOAD);
> + amd_pmf_cdev_unregister();
> apmf_acpi_deinit(dev);
> amd_pmf_dbgfs_unregister(dev);
> }
> diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
> index 69fef7448744..6f61076a9386 100644
> --- a/drivers/platform/x86/amd/pmf/pmf.h
> +++ b/drivers/platform/x86/amd/pmf/pmf.h
> @@ -928,4 +928,13 @@ int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid);
> void amd_pmf_tee_deinit(struct amd_pmf_dev *dev);
> int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev);
>
> +/* Util Layer */
> +#if IS_ENABLED(CONFIG_AMD_PMF_UTIL_SUPPORT)
> +int amd_pmf_cdev_register(struct amd_pmf_dev *dev);
> +void amd_pmf_cdev_unregister(void);
> +#else
> +static inline int amd_pmf_cdev_register(struct amd_pmf_dev *dev) { return 0; }
> +static inline void amd_pmf_cdev_unregister(void) {}
> +#endif
> +
> #endif /* PMF_H */
> diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
> new file mode 100644
> index 000000000000..c6837caa44e0
> --- /dev/null
> +++ b/drivers/platform/x86/amd/pmf/util.c
> @@ -0,0 +1,174 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * AMD Platform Management Framework Util Layer
> + *
> + * Copyright (c) 2026, Advanced Micro Devices, Inc.
> + * All Rights Reserved.
> + *
> + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> + * Sanket Goswami <Sanket.Goswami@amd.com>
> + */
> +
> +#include <linux/amd-pmf.h>
> +#include <linux/miscdevice.h>
> +#include <linux/mutex.h>
> +#include <linux/uaccess.h>
> +
> +#include "pmf.h"
> +
> +/* Convert BIOS input control code to array index (0-9) */
> +static int amd_pmf_get_bios_idx(u32 control_code)
> +{
> + if (control_code >= IOCTL_BIOS_INPUT_1 && control_code <= IOCTL_BIOS_INPUT_10)
> + return control_code - IOCTL_BIOS_INPUT_1;
> +
> + return -EINVAL;
> +}
> +
> +static long long amd_pmf_populate_bios_input(struct ta_pmf_enact_table *in, u32 control_code)
> +{
> + u32 idx;
> +
> + idx = amd_pmf_get_bios_idx(control_code);
> +
> + return (idx < 2) ? in->ev_info.bios_input_1[idx] : in->ev_info.bios_input_2[idx - 2];
> +}
> +
> +static long long amd_pmf_device_state(struct ta_pmf_enact_table *in, u32 control_code)
> +{
> + switch (control_code) {
> + case IOCTL_PLATFORM_TYPE:
> + return in->ev_info.platform_type;
> + case IOCTL_LAPTOP_PLACEMENT:
> + return in->ev_info.device_state;
> + case IOCTL_LID_STATE:
> + return in->ev_info.lid_state;
> + case IOCTL_USER_PRESENCE:
> + return in->ev_info.user_present;
> + default:
> + return -EINVAL;
> + }
> +}
> +
> +static int amd_pmf_populate_data(struct device *dev, void __user *argp)
> +{
> + struct amd_pmf_ioctl_info output = {0};
> + struct ta_pmf_shared_memory *ta_sm = NULL;
> + struct ta_pmf_enact_table *in = NULL;
> + struct amd_pmf_dev *pdev;
> +
> + pdev = dev_get_drvdata(dev);
> + if (!pdev)
> + return -EINVAL;
> +
> + memset(pdev->shbuf, 0, pdev->policy_sz);
> + ta_sm = pdev->shbuf;
> + in = &ta_sm->pmf_input.enact_table;
> +
> + if (copy_from_user(&output, argp, sizeof(output)))
> + return -EFAULT;
> +
> + switch (output.control_code) {
> + case IOCTL_POWER_SOURCE:
> + output.val = in->ev_info.power_source;
> + break;
> + case IOCTL_POWER_SLIDER_POSITION:
> + output.val = in->ev_info.power_slider;
> + break;
> + case IOCTL_SKIN_TEMP:
> + /* Convert from centi-degrees to degrees Celsius */
> + output.val = in->ev_info.skin_temperature / 100;
> + break;
> + case IOCTL_PLATFORM_TYPE ... IOCTL_LID_STATE:
> + case IOCTL_USER_PRESENCE:
> + output.val = amd_pmf_device_state(in, output.control_code);
> + break;
> + case IOCTL_BIOS_INPUT_1 ... IOCTL_BIOS_INPUT_10:
> + output.val = amd_pmf_populate_bios_input(in, output.control_code);
> + break;
> + case IOCTL_GFX_WORKLOAD:
> + output.val = in->ev_info.gfx_busy;
> + break;
> + case IOCTL_AMBIENT_LIGHT:
> + output.val = in->ev_info.ambient_light;
> + break;
> + case IOCTL_AVG_C0_RES:
> + output.val = in->ev_info.avg_c0residency;
> + break;
> + case IOCTL_MAX_C0_RES:
> + output.val = in->ev_info.max_c0residency;
> + break;
> + case IOCTL_SOCKET_POWER:
> + output.val = in->ev_info.socket_power;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + if (copy_to_user(argp, &output, sizeof(output)))
> + return -EFAULT;
> +
> + return 0;
> +}
> +
> +#if IS_ENABLED(CONFIG_AMD_PMF_UTIL_SUPPORT)
> +static struct amd_pmf_dev *pmf_dev_handle;
> +static DEFINE_MUTEX(pmf_util_lock);
> +
> +static long amd_pmf_set_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> +{
> + struct amd_pmf_dev *pdev = filp->private_data;
> + void __user *argp = (void __user *)arg;
> +
> + if (cmd != IOCTL_PMF_POPULATE_DATA)
> + return -EINVAL;
> +
> + guard(mutex)(&pmf_util_lock);
> + return amd_pmf_populate_data(pdev->dev, argp);
> +}
> +
> +static int amd_pmf_open(struct inode *inode, struct file *filp)
> +{
> + guard(mutex)(&pmf_util_lock);
> + if (!pmf_dev_handle)
> + return -ENODEV;
> +
> + filp->private_data = pmf_dev_handle;
> + return 0;
> +}
> +
> +static const struct file_operations pmf_if_ops = {
> + .owner = THIS_MODULE,
> + .open = amd_pmf_open,
> + .unlocked_ioctl = amd_pmf_set_ioctl,
> +};
> +
> +static struct miscdevice amd_pmf_util_if = {
> + .minor = MISC_DYNAMIC_MINOR,
> + .name = "amdpmf_interface",
> + .fops = &pmf_if_ops,
> +};
> +
> +int amd_pmf_cdev_register(struct amd_pmf_dev *dev)
> +{
> + int ret;
> +
> + guard(mutex)(&pmf_util_lock);
> + pmf_dev_handle = dev;
> + ret = misc_register(&amd_pmf_util_if);
> + if (ret)
> + pmf_dev_handle = NULL;
> +
> + return ret;
> +}
> +
> +void amd_pmf_cdev_unregister(void)
> +{
> + guard(mutex)(&pmf_util_lock);
> + pmf_dev_handle = NULL;
> + misc_deregister(&amd_pmf_util_if);
> +}
> +#else
> +int amd_pmf_cdev_register(struct amd_pmf_dev *dev) { return 0; }
> +void amd_pmf_cdev_unregister(void) {}
> +#endif
> diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
> new file mode 100644
> index 000000000000..d29431c67eaa
> --- /dev/null
> +++ b/include/uapi/linux/amd-pmf.h
> @@ -0,0 +1,115 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */
> +/*
> + * AMD Platform Management Framework (PMF) UAPI Header
> + *
> + * Copyright (c) 2026, Advanced Micro Devices, Inc.
> + * All Rights Reserved.
> + *
> + * This file defines the user-space API for interacting with the AMD PMF
> + * driver. It provides ioctl interfaces to query platform-specific metrics
> + * such as power source, slider position, platform type, laptop placement,
> + * and various BIOS input/output parameters.
> + */
> +
> +#ifndef _UAPI_LINUX_AMD_PMF_H
> +#define _UAPI_LINUX_AMD_PMF_H
> +
> +#include <linux/ioctl.h>
> +#include <linux/types.h>
> +
> +/**
> + * AMD_PMF_IOC_MAGIC - Magic number for AMD PMF ioctl commands
> + *
> + * This magic number uniquely identifies AMD PMF ioctl operations.
> + */
> +#define AMD_PMF_IOC_MAGIC 'p'
> +
> +/**
> + * IOCTL_PMF_POPULATE_DATA - ioctl command to retrieve PMF metrics data
> + *
> + * This ioctl command is used to populate the amd_pmf_ioctl_info structure
> + * with the requested metrics data based on the control_code provided.
> + */
> +#define IOCTL_PMF_POPULATE_DATA _IOWR(AMD_PMF_IOC_MAGIC, 0x00, struct amd_pmf_ioctl_info)
> +
> +/**
> + * enum pmf_ioctl_id - Control codes for PMF ioctl operations
> + * @IOCTL_POWER_SOURCE: Query current power source (AC/DC)
> + * @IOCTL_POWER_SLIDER_POSITION: Query current power slider position
> + * @IOCTL_PLATFORM_TYPE: Query current platform/form factor type
> + * @IOCTL_LAPTOP_PLACEMENT: Query laptop physical placement state
> + * @IOCTL_LID_STATE: Query laptop lid open/close state
> + * @IOCTL_HETERO_STATE: Query heterogeneous computing state
> + * @IOCTL_SKIN_TEMP: Query skin temperature sensor reading
> + * @IOCTL_USER_PRESENCE: Query user presence detection state
> + * @IOCTL_DISPLAY_NUM: Query number of active displays
> + * @IOCTL_USER_ENGAGED: Query user engagement state
> + * @IOCTL_BIOS_INPUT_1: Query BIOS input parameter 1
> + * @IOCTL_BIOS_INPUT_2: Query BIOS input parameter 2
> + * @IOCTL_BIOS_INPUT_3: Query BIOS input parameter 3
> + * @IOCTL_BIOS_INPUT_4: Query BIOS input parameter 4
> + * @IOCTL_BIOS_INPUT_5: Query BIOS input parameter 5
> + * @IOCTL_BIOS_INPUT_6: Query BIOS input parameter 6
> + * @IOCTL_BIOS_INPUT_7: Query BIOS input parameter 7
> + * @IOCTL_BIOS_INPUT_8: Query BIOS input parameter 8
> + * @IOCTL_BIOS_INPUT_9: Query BIOS input parameter 9
> + * @IOCTL_BIOS_INPUT_10: Query BIOS input parameter 10
> + * @IOCTL_GFX_WORKLOAD: Query current graphics workload type
> + * @IOCTL_AMBIENT_LIGHT: Query ambient light sensor reading
> + * @IOCTL_AVG_C0_RES: Query average C0 residency
> + * @IOCTL_MAX_C0_RES: Query maximum C0 residency
> + * @IOCTL_SOCKET_POWER: Query current socket power consumption
> + * @IOCTL_TA_BIN_VER: Query Trusted Application binary version
> + *
> + * These control codes are used with the IOCTL_PMF_POPULATE_DATA ioctl
> + * to specify which metrics data to retrieve from the AMD PMF driver.
> + */
> +enum pmf_ioctl_id {
> + IOCTL_POWER_SOURCE,
> + IOCTL_POWER_SLIDER_POSITION,
> + IOCTL_PLATFORM_TYPE,
> + IOCTL_LAPTOP_PLACEMENT,
> + IOCTL_LID_STATE,
> + IOCTL_HETERO_STATE,
> + IOCTL_SKIN_TEMP,
> + IOCTL_USER_PRESENCE,
> + IOCTL_DISPLAY_NUM,
> + IOCTL_USER_ENGAGED,
> + IOCTL_BIOS_INPUT_1,
> + IOCTL_BIOS_INPUT_2,
> + IOCTL_BIOS_INPUT_3,
> + IOCTL_BIOS_INPUT_4,
> + IOCTL_BIOS_INPUT_5,
> + IOCTL_BIOS_INPUT_6,
> + IOCTL_BIOS_INPUT_7,
> + IOCTL_BIOS_INPUT_8,
> + IOCTL_BIOS_INPUT_9,
> + IOCTL_BIOS_INPUT_10,
> + IOCTL_GFX_WORKLOAD,
> + IOCTL_AMBIENT_LIGHT = 29,
> + IOCTL_AVG_C0_RES = 36,
> + IOCTL_MAX_C0_RES,
> + IOCTL_SOCKET_POWER = 50,
> + IOCTL_TA_BIN_VER
> +};
> +
> +/**
> + * struct amd_pmf_ioctl_info - Structure for PMF ioctl data exchange
> + * @control_code: Input parameter specifying which data to query (enum pmf_ioctl_id)
> + * @feature_supported: Output flag indicating if the queried feature is supported
> + * @feature_version: Output field containing the feature version number
> + * @val: Output field containing the queried value
> + *
> + * This structure is used with the IOCTL_PMF_POPULATE_DATA ioctl command
> + * to exchange data between user space and the AMD PMF kernel driver.
> + * The user provides the control_code to specify the query type, and the
> + * driver populates the remaining fields with the response data.
> + */
> +struct amd_pmf_ioctl_info {
> + enum pmf_ioctl_id control_code; /* In */
> + bool feature_supported; /* Out */
> + unsigned long feature_version; /* Out */
> + long long val; /* Out */
I somehow seem to now recall that Hans suggested that the interface should
be a struct which encodes many/all values...
Yes, it seems so. This is what he said:
https://lore.kernel.org/all/6104959e-0214-492d-8ceb-c7376d3b1121@kernel.org/
--
i.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 3/7] platform/x86/amd/pmf: Add feature discovery support to util interface
2026-03-01 13:11 ` [PATCH v3 3/7] platform/x86/amd/pmf: Add feature discovery support to util interface Shyam Sundar S K
@ 2026-03-25 14:07 ` Ilpo Järvinen
2026-03-30 11:41 ` Shyam Sundar S K
0 siblings, 1 reply; 30+ messages in thread
From: Ilpo Järvinen @ 2026-03-25 14:07 UTC (permalink / raw)
To: Shyam Sundar S K; +Cc: platform-driver-x86, Yijun.Shen, Sanket.Goswami
On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
> Add feature discovery capability to the util layer interface, allowing
> userspace tools to query which PMF features are supported and enabled
> on the current platform.
>
> The following features can now be queried through the
> /dev/amdpmf_interface ioctl:
> *Auto Mode: Automatic power profile switching based on system activity
> *Static Power Slider: User-selectable power profiles
> *Policy Builder (Smart PC): Action based policy management
> *Dynamic Power Slider AC: Adaptive power profiles when on AC power
> *Dynamic Power Slider DC: Adaptive power profiles when on battery
Same comments to the list as to the other patch.
> Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
> Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> ---
> drivers/platform/x86/amd/pmf/util.c | 33 +++++++++++++++++++++++++++++
> include/uapi/linux/amd-pmf.h | 12 ++++++++++-
> 2 files changed, 44 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
> index 59a125deb6b6..9a14467f412c 100644
> --- a/drivers/platform/x86/amd/pmf/util.c
> +++ b/drivers/platform/x86/amd/pmf/util.c
> @@ -16,6 +16,8 @@
>
> #include "pmf.h"
>
> +#define AMD_PMF_IOCTL_VERSION 0x02
> +
> /* Convert BIOS input control code to array index (0-9) */
> static int amd_pmf_get_bios_idx(u32 control_code)
> {
> @@ -46,6 +48,33 @@ static long long amd_pmf_populate_bios_output(struct amd_pmf_dev *pdev, u32 cont
> return pdev->bios_output[idx];
> }
>
> +static bool amd_pmf_is_feature_supported(struct amd_pmf_dev *pdev, u32 control_code)
> +{
> + bool feat;
> +
> + switch (control_code) {
> + case IOCTL_FEATURE_AUTO_MODE:
> + feat = is_apmf_func_supported(pdev, APMF_FUNC_AUTO_MODE);
> + break;
> + case IOCTL_FEATURE_STATIC_POWER_SLIDER:
> + feat = is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR);
> + break;
> + case IOCTL_FEATURE_POLICY_BUILDER:
> + feat = pdev->smart_pc_enabled;
> + break;
> + case IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC:
> + feat = is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_AC);
> + break;
> + case IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC:
> + feat = is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_DC);
> + break;
> + default:
> + return false;
> + }
> +
> + return feat;
> +}
> +
> static long long amd_pmf_device_state(struct ta_pmf_enact_table *in, u32 control_code)
> {
> switch (control_code) {
> @@ -116,6 +145,10 @@ static int amd_pmf_populate_data(struct device *dev, void __user *argp)
> case IOCTL_BIOS_OUTPUT_1 ... IOCTL_BIOS_OUTPUT_10:
> output.val = amd_pmf_populate_bios_output(pdev, output.control_code);
> break;
> + case IOCTL_FEATURE_AUTO_MODE ... IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC:
> + output.feature_supported = amd_pmf_is_feature_supported(pdev, output.control_code);
> + output.feature_version = AMD_PMF_IOCTL_VERSION;
> + break;
> default:
> return -EINVAL;
> }
> diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
> index f93767248169..f34c5d744039 100644
> --- a/include/uapi/linux/amd-pmf.h
> +++ b/include/uapi/linux/amd-pmf.h
> @@ -70,6 +70,11 @@
> * @IOCTL_BIOS_OUTPUT_8: Query BIOS output parameter 8
> * @IOCTL_BIOS_OUTPUT_9: Query BIOS output parameter 9
> * @IOCTL_BIOS_OUTPUT_10: Query BIOS output parameter 10
> + * @IOCTL_FEATURE_AUTO_MODE: Query if Auto Mode feature is supported
> + * @IOCTL_FEATURE_STATIC_POWER_SLIDER: Query if Static Power Slider is supported
> + * @IOCTL_FEATURE_POLICY_BUILDER: Query if Policy Builder feature is supported
> + * @IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC: Query if Dynamic Power Slider (AC) is supported
> + * @IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC: Query if Dynamic Power Slider (DC) is supported
> *
> * These control codes are used with the IOCTL_PMF_POPULATE_DATA ioctl
> * to specify which metrics data to retrieve from the AMD PMF driver.
> @@ -110,7 +115,12 @@ enum pmf_ioctl_id {
> IOCTL_BIOS_OUTPUT_7,
> IOCTL_BIOS_OUTPUT_8,
> IOCTL_BIOS_OUTPUT_9,
> - IOCTL_BIOS_OUTPUT_10
> + IOCTL_BIOS_OUTPUT_10,
> + IOCTL_FEATURE_AUTO_MODE,
> + IOCTL_FEATURE_STATIC_POWER_SLIDER,
> + IOCTL_FEATURE_POLICY_BUILDER,
> + IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC,
> + IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC
I'm trying to confirm whether there are some special requirements when
it comes to trailing commas for uapi headers. If somebody knows for sure
if trailing commas are safe or not for userspace builds, please chime in.
--
i.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 2/7] platform/x86/amd/pmf: cache BIOS output values for user-space metrics via util IOCTL
2026-03-01 13:11 ` [PATCH v3 2/7] platform/x86/amd/pmf: cache BIOS output values for user-space metrics via util IOCTL Shyam Sundar S K
@ 2026-03-25 14:08 ` Ilpo Järvinen
0 siblings, 0 replies; 30+ messages in thread
From: Ilpo Järvinen @ 2026-03-25 14:08 UTC (permalink / raw)
To: Shyam Sundar S K
Cc: Hans de Goede, platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami
On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
> Add a bios_output[] cache to amd_pmf_dev and store the latest values for
> BIOS output policies when applying PMF policies. This enables the AMD PMF
> util layer to expose these BIOS outputs alongside selected thermal and
> power metrics to user space via /dev/amdpmf_interface and a new IOCTL,
> supporting real-time monitoring tools such as SystemDeck.
>
> The bios_output array is initialized to zero during device probe, and
> bounds checking is added to prevent potential buffer overflows when
> caching values.
>
> Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
> Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> ---
> drivers/platform/x86/amd/pmf/core.c | 3 +++
> drivers/platform/x86/amd/pmf/pmf.h | 1 +
> drivers/platform/x86/amd/pmf/tee-if.c | 9 ++++++++-
> drivers/platform/x86/amd/pmf/util.c | 15 +++++++++++++++
> include/uapi/linux/amd-pmf.h | 22 +++++++++++++++++++++-
> 5 files changed, 48 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
> index 919d02f30aae..b5cab7c937ce 100644
> --- a/drivers/platform/x86/amd/pmf/core.c
> +++ b/drivers/platform/x86/amd/pmf/core.c
> @@ -634,6 +634,9 @@ static int amd_pmf_probe(struct platform_device *pdev)
>
> pmf_device = dev->dev;
>
> + /* Initialize BIOS output cache for util layer */
> + memset(dev->bios_output, 0, sizeof(dev->bios_output));
You allocate dev with devm_kzalloc() so why is this necessary?
> +
> err = amd_pmf_cdev_register(dev);
> if (err)
> dev_warn(dev->dev, "failed to register util interface: %d\n", err);
> diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
> index 6f61076a9386..0d879f0fd8e2 100644
> --- a/drivers/platform/x86/amd/pmf/pmf.h
> +++ b/drivers/platform/x86/amd/pmf/pmf.h
> @@ -442,6 +442,7 @@ struct amd_pmf_dev {
> struct pmf_cbi_ring_buffer cbi_buf;
> struct mutex cbi_mutex; /* Protects ring buffer access */
> struct mutex metrics_mutex;
> + u32 bios_output[10];
> };
>
> struct apmf_sps_prop_granular_v2 {
> diff --git a/drivers/platform/x86/amd/pmf/tee-if.c b/drivers/platform/x86/amd/pmf/tee-if.c
> index 7ccd93f506b2..f749115bf970 100644
> --- a/drivers/platform/x86/amd/pmf/tee-if.c
> +++ b/drivers/platform/x86/amd/pmf/tee-if.c
> @@ -98,10 +98,17 @@ static int amd_pmf_get_bios_output_idx(u32 action_idx)
> static void amd_pmf_update_bios_output(struct amd_pmf_dev *pdev, struct ta_pmf_action *action)
> {
> u32 bios_idx;
> + int ret;
>
> bios_idx = amd_pmf_get_bios_output_idx(action->action_index);
> + if (bios_idx >= ARRAY_SIZE(pdev->bios_output)) {
Add include.
> + dev_warn(pdev->dev, "BIOS output index %u out of bounds\n", bios_idx);
Add include.
> + return;
> + }
>
> - amd_pmf_smartpc_apply_bios_output(pdev, action->value, BIT(bios_idx), bios_idx);
> + ret = amd_pmf_smartpc_apply_bios_output(pdev, action->value, BIT(bios_idx), bios_idx);
Somewhat unrelated to the change here, the include for BIT() is also
missing (linux/bits.h). But I don't mind if you stick its addition into
this patch since you're anyway touching this line.
> + if (!ret)
> + pdev->bios_output[bios_idx] = action->value;
> }
>
> static void amd_pmf_apply_policies(struct amd_pmf_dev *dev, struct ta_pmf_enact_result *out)
> diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
> index c6837caa44e0..59a125deb6b6 100644
> --- a/drivers/platform/x86/amd/pmf/util.c
> +++ b/drivers/platform/x86/amd/pmf/util.c
> @@ -22,6 +22,9 @@ static int amd_pmf_get_bios_idx(u32 control_code)
> if (control_code >= IOCTL_BIOS_INPUT_1 && control_code <= IOCTL_BIOS_INPUT_10)
> return control_code - IOCTL_BIOS_INPUT_1;
>
> + if (control_code >= IOCTL_BIOS_OUTPUT_1 && control_code <= IOCTL_BIOS_OUTPUT_10)
> + return control_code - IOCTL_BIOS_OUTPUT_1;
> +
> return -EINVAL;
> }
>
> @@ -34,6 +37,15 @@ static long long amd_pmf_populate_bios_input(struct ta_pmf_enact_table *in, u32
> return (idx < 2) ? in->ev_info.bios_input_1[idx] : in->ev_info.bios_input_2[idx - 2];
> }
>
> +static long long amd_pmf_populate_bios_output(struct amd_pmf_dev *pdev, u32 control_code)
> +{
> + u32 idx;
> +
> + idx = amd_pmf_get_bios_idx(control_code);
> +
> + return pdev->bios_output[idx];
> +}
> +
> static long long amd_pmf_device_state(struct ta_pmf_enact_table *in, u32 control_code)
> {
> switch (control_code) {
> @@ -101,6 +113,9 @@ static int amd_pmf_populate_data(struct device *dev, void __user *argp)
> case IOCTL_SOCKET_POWER:
> output.val = in->ev_info.socket_power;
> break;
> + case IOCTL_BIOS_OUTPUT_1 ... IOCTL_BIOS_OUTPUT_10:
> + output.val = amd_pmf_populate_bios_output(pdev, output.control_code);
> + break;
> default:
> return -EINVAL;
> }
> diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
> index d29431c67eaa..f93767248169 100644
> --- a/include/uapi/linux/amd-pmf.h
> +++ b/include/uapi/linux/amd-pmf.h
> @@ -60,6 +60,16 @@
> * @IOCTL_MAX_C0_RES: Query maximum C0 residency
> * @IOCTL_SOCKET_POWER: Query current socket power consumption
> * @IOCTL_TA_BIN_VER: Query Trusted Application binary version
> + * @IOCTL_BIOS_OUTPUT_1: Query BIOS output parameter 1
> + * @IOCTL_BIOS_OUTPUT_2: Query BIOS output parameter 2
> + * @IOCTL_BIOS_OUTPUT_3: Query BIOS output parameter 3
> + * @IOCTL_BIOS_OUTPUT_4: Query BIOS output parameter 4
> + * @IOCTL_BIOS_OUTPUT_5: Query BIOS output parameter 5
> + * @IOCTL_BIOS_OUTPUT_6: Query BIOS output parameter 6
> + * @IOCTL_BIOS_OUTPUT_7: Query BIOS output parameter 7
> + * @IOCTL_BIOS_OUTPUT_8: Query BIOS output parameter 8
> + * @IOCTL_BIOS_OUTPUT_9: Query BIOS output parameter 9
> + * @IOCTL_BIOS_OUTPUT_10: Query BIOS output parameter 10
> *
> * These control codes are used with the IOCTL_PMF_POPULATE_DATA ioctl
> * to specify which metrics data to retrieve from the AMD PMF driver.
> @@ -90,7 +100,17 @@ enum pmf_ioctl_id {
> IOCTL_AVG_C0_RES = 36,
> IOCTL_MAX_C0_RES,
> IOCTL_SOCKET_POWER = 50,
> - IOCTL_TA_BIN_VER
> + IOCTL_TA_BIN_VER,
> + IOCTL_BIOS_OUTPUT_1,
> + IOCTL_BIOS_OUTPUT_2,
> + IOCTL_BIOS_OUTPUT_3,
> + IOCTL_BIOS_OUTPUT_4,
> + IOCTL_BIOS_OUTPUT_5,
> + IOCTL_BIOS_OUTPUT_6,
> + IOCTL_BIOS_OUTPUT_7,
> + IOCTL_BIOS_OUTPUT_8,
> + IOCTL_BIOS_OUTPUT_9,
> + IOCTL_BIOS_OUTPUT_10
> };
>
> /**
>
--
i.
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 6/7] platform/x86/amd/pmf: Introduce AMD PMF testing tool for driver metrics and features
2026-03-25 13:54 ` Ilpo Järvinen
@ 2026-03-25 15:07 ` Mario Limonciello
2026-03-26 10:20 ` Ilpo Järvinen
0 siblings, 1 reply; 30+ messages in thread
From: Mario Limonciello @ 2026-03-25 15:07 UTC (permalink / raw)
To: Ilpo Järvinen, Shyam Sundar S K, Shuah Khan, Shuah Khan,
linux-kselftest
Cc: Hans de Goede, platform-driver-x86, Yijun.Shen, Sanket.Goswami
On 3/25/26 08:54, Ilpo Järvinen wrote:
> + Selftest people.
>
> On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
>
>> This tool leverages amd-pmf ioctls exposed via the util layer, allowing
>> validation of its newly integrated util layer and /dev/amdpmf_interface.
>> It includes a user-space test application, test_pmf, designed to interact
>> with the PMF driver and retrieve relevant metrics for the testing and
>> analysis.
>>
>> It provides definitions for test metrics, feature IDs, and device states,
>> and includes tests for various AMD PMF metrics such as power source, skin
>> temperature, battery state, and custom BIOS inputs/outputs. It also
>> enables the testing of PMF metrics data and feature support reporting.
>>
>> Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
>> Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
>> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>> ---
>> tools/testing/selftests/Makefile | 1 +
>> .../drivers/platform/x86/amd/pmf/Makefile | 8 +
>> .../drivers/platform/x86/amd/pmf/test_pmf.c | 243 ++++++++++++++++++
>> 3 files changed, 252 insertions(+)
>> create mode 100644 tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile
>> create mode 100644 tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c
>
> Please Cc also selftest people in the next version submission! Maube you
> should also check why your patch sending process did not capture those
> receipient for you.
>
> To me it looks this "tool" doesn't really perform a selftest the way I've
> understood "selftests" work. That is, it doesn't have notion of Pass/Fail
> at all AFAICT. I'm not sure if there are other selftests like this but
> hopefully the selftest people know.
For a similar "tool" I have it outside of selftests:
linux/tools/crypto/ccp
Ilpo,
Maybe we want a directory structure like this?
tools/platform/x86/amd
>
>> diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile
>> index 450f13ba4cca..d850fb09eeb9 100644
>> --- a/tools/testing/selftests/Makefile
>> +++ b/tools/testing/selftests/Makefile
>> @@ -26,6 +26,7 @@ TARGETS += drivers/net/netconsole
>> TARGETS += drivers/net/team
>> TARGETS += drivers/net/virtio_net
>> TARGETS += drivers/platform/x86/intel/ifs
>> +TARGETS += drivers/platform/x86/amd/pmf
>> TARGETS += dt
>> TARGETS += efivarfs
>> TARGETS += exec
>> diff --git a/tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile b/tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile
>> new file mode 100644
>> index 000000000000..876424941e83
>> --- /dev/null
>> +++ b/tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile
>> @@ -0,0 +1,8 @@
>> +# SPDX-License-Identifier: GPL-2.0-or-later
>> +CFLAGS += $(KHDR_INCLUDES)
>> +
>> +TEST_GEN_PROGS := test_pmf
>> +
>> +top_srcdir ?=../../../../..
>> +
>> +include ../../../../../lib.mk
>> diff --git a/tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c b/tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c
>> new file mode 100644
>> index 000000000000..a040ef01ba90
>> --- /dev/null
>> +++ b/tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c
>> @@ -0,0 +1,243 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * AMD Platform Management Framework Test Tool
>> + *
>> + * Copyright (c) 2026, Advanced Micro Devices, Inc.
>> + * All Rights Reserved.
>> + *
>> + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>> + * Sanket Goswami <Sanket.Goswami@amd.com>
>> + */
>> +
>> +#include <errno.h>
>> +#include <fcntl.h>
>> +#include <inttypes.h>
>> +#include <stdbool.h>
>> +#include <stdint.h>
>> +#include <stdio.h>
>> +#include <string.h>
>> +#include <sys/ioctl.h>
>> +#include <unistd.h>
>> +#include <linux/amd-pmf.h>
>> +
>> +#include "../../../../../kselftest.h"
>> +
>> +#define DEVICE_NODE "/dev/amdpmf_interface"
>> +
>> +static int pmf_open_device(void)
>> +{
>> + int fd;
>> +
>> + fd = open(DEVICE_NODE, O_RDONLY);
>> + if (fd < 0)
>> + fprintf(stderr, "opening PMF Device Node failed: %s\n", strerror(errno));
>> +
>> + return fd;
>> +}
>> +
>> +/* Helper to run IOCTL_PMF_POPULATE_DATA for one control code and return 0 on success. */
>
> Reflow this comment to 80 chars.
>
>> +static int pmf_get_fd(int fd, enum pmf_ioctl_id code, struct amd_pmf_ioctl_info *out)
>> +{
>> + struct amd_pmf_ioctl_info info = {0};
>
> = {}; should be enough to initialize to default values.
>
>> + int ret;
>> +
>> + if (!out)
>> + return -EINVAL;
>> +
>> + info.control_code = code;
>> +
>> + ret = ioctl(fd, IOCTL_PMF_POPULATE_DATA, &info);
>> + if (ret < 0)
>> + return ret;
>> +
>> + *out = info;
>> + return 0;
>> +}
>> +
>> +static int pmf_get_data(enum pmf_ioctl_id code, struct amd_pmf_ioctl_info *out)
>> +{
>> + int fd, ret;
>> +
>> + fd = pmf_open_device();
>> + if (fd < 0)
>> + return fd;
>> +
>> + ret = pmf_get_fd(fd, code, out);
>> +
>> + close(fd);
>> + return ret;
>> +}
>> +
>> +static int pmf_get_feature_status(unsigned int code)
>> +{
>> + struct amd_pmf_ioctl_info info = {0};
>> + int ret;
>> +
>> + ret = pmf_get_data(code, &info);
>> + if (ret < 0)
>> + return ret;
>> +
>> + switch (code) {
>> + case IOCTL_FEATURE_AUTO_MODE:
>> + printf("Auto Mode: %-24s\n", info.feature_supported ? "Yes" : "No");
>> + break;
>> + case IOCTL_FEATURE_STATIC_POWER_SLIDER:
>> + printf("Static Power Slider: %-24s\n", info.feature_supported ? "Yes" : "No");
>> + break;
>> + case IOCTL_FEATURE_POLICY_BUILDER:
>> + printf("Policy Builder: %s\n", info.feature_supported ? "Yes" : "No");
>> + break;
>> + case IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC:
>> + printf("Dynamic Power Slider AC: %s\n", info.feature_supported ? "Yes" : "No");
>> + break;
>> + case IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC:
>> + printf("Dynamic Power Slider DC: %s\n", info.feature_supported ? "Yes" : "No");
>> + break;
>> + default:
>> + return -1;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int pmf_get_device_state(unsigned int code)
>> +{
>> + struct amd_pmf_ioctl_info info = {0};
>> + int ret;
>> +
>> + ret = pmf_get_data(code, &info);
>> + if (ret < 0)
>> + return ret;
>> +
>> + switch (code) {
>> + case IOCTL_PLATFORM_TYPE:
>> + printf("Platform Type: %s\n", platform_type_as_str(info.val));
>> + break;
>> + case IOCTL_LAPTOP_PLACEMENT:
>> + printf("Laptop placement: %s\n", laptop_placement_as_str(info.val));
>> + break;
>> + case IOCTL_LID_STATE:
>> + printf("Lid State: %s\n", info.val ? "Close" : "Open");
>> + break;
>> + case IOCTL_USER_PRESENCE:
>> + printf("User Presence: %s\n", info.val ? "Present" : "Away");
>> + break;
>> + default:
>> + return -1;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int pmf_get_custom_bios_input(unsigned int code)
>> +{
>> + struct amd_pmf_ioctl_info info = {0};
>> + int idx, ret;
>> +
>> + ret = pmf_get_data(code, &info);
>> + if (ret < 0)
>> + return ret;
>> +
>> + switch (code) {
>> + case IOCTL_BIOS_INPUT_1 ... IOCTL_BIOS_INPUT_10:
>> + idx = amd_pmf_get_bios_idx(code);
>> + printf("Custom BIOS input%u: %lu\n", idx + 1, (int64_t)info.val);
>
> %lu is for printing unsigned long, not int64_t.
>
>> + break;
>> + default:
>> + return -1;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int pmf_get_bios_output(unsigned int code)
>> +{
>> + struct amd_pmf_ioctl_info info = {0};
>> + int idx, ret;
>> +
>> + ret = pmf_get_data(code, &info);
>> + if (ret < 0)
>> + return ret;
>> +
>> + switch (code) {
>> + case IOCTL_BIOS_OUTPUT_1 ... IOCTL_BIOS_OUTPUT_10:
>> + idx = amd_pmf_get_bios_idx(code);
>> + printf("BIOS output%u: %lu\n", idx + 1, (int64_t)info.val);
>> + break;
>> + default:
>> + return -1;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int pmf_get_misc_info(unsigned int code)
>> +{
>> + struct amd_pmf_ioctl_info info = {0};
>> + int ret;
>> +
>> + ret = pmf_get_data(code, &info);
>> + if (ret < 0)
>> + return ret;
>> +
>> + switch (code) {
>> + case IOCTL_POWER_SLIDER_POSITION:
>> + printf("Slider Position: %s\n", ta_slider_as_str(info.val));
>> + break;
>> + case IOCTL_SKIN_TEMP:
>> + printf("Skin Temperature: %lu\n", (int64_t)info.val);
>> + break;
>> + case IOCTL_GFX_WORKLOAD:
>> + printf("GFX Busy: %lu\n", (int64_t)info.val);
>> + break;
>> + case IOCTL_AMBIENT_LIGHT:
>> + printf("Ambient Light: %ld\n", (int64_t)info.val);
>> + break;
>> + case IOCTL_AVG_C0_RES:
>> + printf("Avg C0 Residency: %lu\n", (int64_t)info.val);
>> + break;
>> + case IOCTL_MAX_C0_RES:
>> + printf("Max C0 Residency: %lu\n", (int64_t)info.val);
>> + break;
>> + case IOCTL_SOCKET_POWER:
>> + printf("Socket Power: %lu\n", (int64_t)info.val);
>
> Please think the printf formatting strings and types through.
>
>> + break;
>> + default:
>> + return -1;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +int main(void)
>> +{
>> + unsigned int idx;
>> +
>> + printf("Feature Name Supported\n");
>> + printf("---------------------------------\n");
>> + for (idx = IOCTL_FEATURE_AUTO_MODE; idx <= IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC; idx++)
>> + pmf_get_feature_status(idx);
>> +
>> + printf("\nDevice State\n---------------\n");
>> + for (idx = IOCTL_PLATFORM_TYPE; idx <= IOCTL_USER_PRESENCE; idx++)
>> + pmf_get_device_state(idx);
>> +
>> + printf("\nCustom BIOS Inputs\n-------------------\n");
>> + for (idx = IOCTL_BIOS_INPUT_1; idx <= IOCTL_BIOS_INPUT_10; idx++)
>> + pmf_get_custom_bios_input(idx);
>> +
>> + printf("\nBIOS Outputs\n--------------\n");
>> + for (idx = IOCTL_BIOS_OUTPUT_1; idx <= IOCTL_BIOS_OUTPUT_10; idx++)
>> + pmf_get_bios_output(idx);
>> +
>> + printf("\nMisc\n------\n");
>> + pmf_get_misc_info(IOCTL_SKIN_TEMP);
>> + pmf_get_misc_info(IOCTL_GFX_WORKLOAD);
>> + pmf_get_misc_info(IOCTL_AMBIENT_LIGHT);
>> + pmf_get_misc_info(IOCTL_AVG_C0_RES);
>> + pmf_get_misc_info(IOCTL_MAX_C0_RES);
>> + pmf_get_misc_info(IOCTL_SOCKET_POWER);
>> + pmf_get_misc_info(IOCTL_POWER_SLIDER_POSITION);
>> +
>> + return 0;
>> +}
>>
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 7/7] Documentation/ABI: add testing entry for AMD PMF misc device interface
2026-03-25 13:58 ` Ilpo Järvinen
@ 2026-03-25 15:08 ` Mario Limonciello
2026-03-26 10:14 ` Ilpo Järvinen
0 siblings, 1 reply; 30+ messages in thread
From: Mario Limonciello @ 2026-03-25 15:08 UTC (permalink / raw)
To: Ilpo Järvinen, Shyam Sundar S K
Cc: Hans de Goede, platform-driver-x86, Yijun.Shen, Sanket.Goswami
On 3/25/26 08:58, Ilpo Järvinen wrote:
> On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
>
>> Add a Documentation/ABI/testing entry describing the AMD PMF util layer
>> misc device (/dev/amdpmf_interface) and the initial ioctls used to query
>> feature support and metrics data information. This interface is available
>> when CONFIG_AMD_PMF_UTIL_SUPPORT=y.
>>
>> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>> ---
>> .../ABI/testing/misc-amdpmf_interface | 70 +++++++++++++++++++
>> MAINTAINERS | 1 +
>> 2 files changed, 71 insertions(+)
>> create mode 100644 Documentation/ABI/testing/misc-amdpmf_interface
>>
>> diff --git a/Documentation/ABI/testing/misc-amdpmf_interface b/Documentation/ABI/testing/misc-amdpmf_interface
>> new file mode 100644
>> index 000000000000..62b0175e1345
>> --- /dev/null
>> +++ b/Documentation/ABI/testing/misc-amdpmf_interface
>> @@ -0,0 +1,70 @@
>> +What: /dev/amdpmf_interface
>> +Date: February 2026
>
> As always, these get stale as we go. Please estimate the targetted kernel
> version's release date instead to fill this field in.
Honestly - do we have any value of these dates in the documentation at
all in the first place? Anyone can go look up the date that kernel 7.1
was released.
Maybe we should just stop using this field in new documentation?
>
>> +KernelVersion: 7.1
>> +Contact: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>> +Description:
>> + The AMD Platform Management Framework (PMF) util layer exposes a
>> + minimal user-space interface via a misc character device for
>> + feature discovery and metrics monitoring.
>> +
>> + When CONFIG_AMD_PMF_UTIL_SUPPORT is enabled, the driver creates
>> + a character device:
>> +
>> + ======================
>> + /dev/amdpmf_interface
>> + ======================
>> +
>> + The interface currently supports following ioctls:
>> +
>> + ======================== =========================================
>> + IOCTL Usage
>> + IOCTL_PMF_POPULATE_DATA User passes a struct amd_pmf_ioctl_info
>> + with control_code set to the desired
>> + metric or feature ID. The driver returns
>> + the requested data in val, or feature
>> + support status in feature_supported.
>> + ======================== =========================================
>> +
>> + Following are the control codes supported (enum pmf_ioctl_id):
>> +
>> + ============== ================================================================
>> + Control Code Description
>> + 0 IOCTL_POWER_SOURCE: AC/DC power source
>> + 1 IOCTL_POWER_SLIDER_POSITION: Current power slider
>> + 2 IOCTL_PLATFORM_TYPE: Platform form factor
>> + 3 IOCTL_LAPTOP_PLACEMENT: Device placement (on table/lap/bag)
>> + 4 IOCTL_LID_STATE: Lid open/closed status
>> + 6 IOCTL_SKIN_TEMP: Skin temperature (degrees Celsius)
>> + 7 IOCTL_USER_PRESENCE: User presence detection
>> + 10-19 IOCTL_BIOS_INPUT_1 to IOCTL_BIOS_INPUT_10: Custom BIOS inputs
>> + 20 IOCTL_GFX_WORKLOAD: Graphics workload percentage
>> + 29 IOCTL_AMBIENT_LIGHT: Ambient light sensor reading
>> + 36 IOCTL_AVG_C0_RES: Average C0 state residency
>> + 37 IOCTL_MAX_C0_RES: Maximum C0 state residency
>> + 50 IOCTL_SOCKET_POWER: Socket power consumption
>> + 52-61 IOCTL_BIOS_OUTPUT_1 to IOCTL_BIOS_OUTPUT_10: BIOS output values
>> + ============== ================================================================
>> +
>> + Feature Discovery:
>> +
>> + ============== =============================================================
>> + Control Code Description
>> + 62 IOCTL_FEATURE_AUTO_MODE: Auto Mode feature support
>> + 63 IOCTL_FEATURE_STATIC_POWER_SLIDER: Static Power Slider
>> + 64 IOCTL_FEATURE_POLICY_BUILDER: Policy Builder (Smart PC)
>> + 65 IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC: Dynamic slider on AC
>> + 66 IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC: Dynamic slider on DC
>> + ============== =============================================================
>> +
>> + Following are the return codes:
>> +
>> + ============= ============================================================
>> + Return code Description
>> + 0 success
>> + EINVAL control_code is not recognized or handle is not available
>> + EFAULT copy_to_user/copy_from_user failures
>> + ENODEV PMF device not available
>> + ============= ============================================================
>> +
>> + User-space tools integrating with AMD PMF to discover capabilities and
>> + monitor real-time metrics for thermal and power management validation.
>> diff --git a/MAINTAINERS b/MAINTAINERS
>> index 55af015174a5..78773373172c 100644
>> --- a/MAINTAINERS
>> +++ b/MAINTAINERS
>> @@ -1224,6 +1224,7 @@ AMD PMF DRIVER
>> M: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>> L: platform-driver-x86@vger.kernel.org
>> S: Supported
>> +F: Documentation/ABI/testing/misc-amdpmf_interface
>> F: Documentation/ABI/testing/sysfs-amd-pmf
>> F: drivers/platform/x86/amd/pmf/
>>
>>
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 7/7] Documentation/ABI: add testing entry for AMD PMF misc device interface
2026-03-25 15:08 ` Mario Limonciello
@ 2026-03-26 10:14 ` Ilpo Järvinen
0 siblings, 0 replies; 30+ messages in thread
From: Ilpo Järvinen @ 2026-03-26 10:14 UTC (permalink / raw)
To: Mario Limonciello, Jonathan Corbet, Shuah Khan, linux-doc
Cc: Shyam Sundar S K, Hans de Goede, platform-driver-x86, Yijun.Shen,
Sanket.Goswami
[-- Attachment #1: Type: text/plain, Size: 5960 bytes --]
+ Documentation people
On Wed, 25 Mar 2026, Mario Limonciello wrote:
> On 3/25/26 08:58, Ilpo Järvinen wrote:
> > On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
> >
> > > Add a Documentation/ABI/testing entry describing the AMD PMF util layer
> > > misc device (/dev/amdpmf_interface) and the initial ioctls used to query
> > > feature support and metrics data information. This interface is available
> > > when CONFIG_AMD_PMF_UTIL_SUPPORT=y.
> > >
> > > Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> > > ---
> > > .../ABI/testing/misc-amdpmf_interface | 70 +++++++++++++++++++
> > > MAINTAINERS | 1 +
> > > 2 files changed, 71 insertions(+)
> > > create mode 100644 Documentation/ABI/testing/misc-amdpmf_interface
> > >
> > > diff --git a/Documentation/ABI/testing/misc-amdpmf_interface
> > > b/Documentation/ABI/testing/misc-amdpmf_interface
> > > new file mode 100644
> > > index 000000000000..62b0175e1345
> > > --- /dev/null
> > > +++ b/Documentation/ABI/testing/misc-amdpmf_interface
> > > @@ -0,0 +1,70 @@
> > > +What: /dev/amdpmf_interface
> > > +Date: February 2026
> >
> > As always, these get stale as we go. Please estimate the targetted kernel
> > version's release date instead to fill this field in.
>
> Honestly - do we have any value of these dates in the documentation at all in
> the first place? Anyone can go look up the date that kernel 7.1 was released.
>
> Maybe we should just stop using this field in new documentation?
Hi Mario,
I share your opinion, it has limited value especially when we also have
the kernel version.
But I guess it would be fair to engage also documentation people in such a
discussion so I've added them.
--
i.
> > > +KernelVersion: 7.1
> > > +Contact: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> > > +Description:
> > > + The AMD Platform Management Framework (PMF) util layer exposes
> > > a
> > > + minimal user-space interface via a misc character device for
> > > + feature discovery and metrics monitoring.
> > > +
> > > + When CONFIG_AMD_PMF_UTIL_SUPPORT is enabled, the driver
> > > creates
> > > + a character device:
> > > +
> > > + ======================
> > > + /dev/amdpmf_interface
> > > + ======================
> > > +
> > > + The interface currently supports following ioctls:
> > > +
> > > + ========================
> > > =========================================
> > > + IOCTL Usage
> > > + IOCTL_PMF_POPULATE_DATA User passes a struct
> > > amd_pmf_ioctl_info
> > > + with control_code set to the desired
> > > + metric or feature ID. The driver
> > > returns
> > > + the requested data in val, or feature
> > > + support status in feature_supported.
> > > + ========================
> > > =========================================
> > > +
> > > + Following are the control codes supported (enum pmf_ioctl_id):
> > > +
> > > + ==============
> > > ================================================================
> > > + Control Code Description
> > > + 0 IOCTL_POWER_SOURCE: AC/DC power source
> > > + 1 IOCTL_POWER_SLIDER_POSITION: Current power
> > > slider
> > > + 2 IOCTL_PLATFORM_TYPE: Platform form factor
> > > + 3 IOCTL_LAPTOP_PLACEMENT: Device placement (on
> > > table/lap/bag)
> > > + 4 IOCTL_LID_STATE: Lid open/closed status
> > > + 6 IOCTL_SKIN_TEMP: Skin temperature (degrees
> > > Celsius)
> > > + 7 IOCTL_USER_PRESENCE: User presence detection
> > > + 10-19 IOCTL_BIOS_INPUT_1 to IOCTL_BIOS_INPUT_10:
> > > Custom BIOS inputs
> > > + 20 IOCTL_GFX_WORKLOAD: Graphics workload
> > > percentage
> > > + 29 IOCTL_AMBIENT_LIGHT: Ambient light sensor
> > > reading
> > > + 36 IOCTL_AVG_C0_RES: Average C0 state residency
> > > + 37 IOCTL_MAX_C0_RES: Maximum C0 state residency
> > > + 50 IOCTL_SOCKET_POWER: Socket power consumption
> > > + 52-61 IOCTL_BIOS_OUTPUT_1 to IOCTL_BIOS_OUTPUT_10:
> > > BIOS output values
> > > + ==============
> > > ================================================================
> > > +
> > > + Feature Discovery:
> > > +
> > > + ==============
> > > =============================================================
> > > + Control Code Description
> > > + 62 IOCTL_FEATURE_AUTO_MODE: Auto Mode feature
> > > support
> > > + 63 IOCTL_FEATURE_STATIC_POWER_SLIDER: Static
> > > Power Slider
> > > + 64 IOCTL_FEATURE_POLICY_BUILDER: Policy Builder
> > > (Smart PC)
> > > + 65 IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC: Dynamic
> > > slider on AC
> > > + 66 IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC: Dynamic
> > > slider on DC
> > > + ==============
> > > =============================================================
> > > +
> > > + Following are the return codes:
> > > +
> > > + =============
> > > ============================================================
> > > + Return code Description
> > > + 0 success
> > > + EINVAL control_code is not recognized or handle is
> > > not available
> > > + EFAULT copy_to_user/copy_from_user failures
> > > + ENODEV PMF device not available
> > > + =============
> > > ============================================================
> > > +
> > > + User-space tools integrating with AMD PMF to discover
> > > capabilities and
> > > + monitor real-time metrics for thermal and power management
> > > validation.
> > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > index 55af015174a5..78773373172c 100644
> > > --- a/MAINTAINERS
> > > +++ b/MAINTAINERS
> > > @@ -1224,6 +1224,7 @@ AMD PMF DRIVER
> > > M: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> > > L: platform-driver-x86@vger.kernel.org
> > > S: Supported
> > > +F: Documentation/ABI/testing/misc-amdpmf_interface
> > > F: Documentation/ABI/testing/sysfs-amd-pmf
> > > F: drivers/platform/x86/amd/pmf/
> > >
> >
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 6/7] platform/x86/amd/pmf: Introduce AMD PMF testing tool for driver metrics and features
2026-03-25 15:07 ` Mario Limonciello
@ 2026-03-26 10:20 ` Ilpo Järvinen
2026-03-30 11:42 ` Shyam Sundar S K
0 siblings, 1 reply; 30+ messages in thread
From: Ilpo Järvinen @ 2026-03-26 10:20 UTC (permalink / raw)
To: Mario Limonciello
Cc: Shyam Sundar S K, Shuah Khan, Shuah Khan, linux-kselftest,
Hans de Goede, platform-driver-x86, Yijun.Shen, Sanket.Goswami
[-- Attachment #1: Type: text/plain, Size: 11536 bytes --]
On Wed, 25 Mar 2026, Mario Limonciello wrote:
> On 3/25/26 08:54, Ilpo Järvinen wrote:
> > + Selftest people.
> >
> > On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
> >
> > > This tool leverages amd-pmf ioctls exposed via the util layer, allowing
> > > validation of its newly integrated util layer and /dev/amdpmf_interface.
> > > It includes a user-space test application, test_pmf, designed to interact
> > > with the PMF driver and retrieve relevant metrics for the testing and
> > > analysis.
> > >
> > > It provides definitions for test metrics, feature IDs, and device states,
> > > and includes tests for various AMD PMF metrics such as power source, skin
> > > temperature, battery state, and custom BIOS inputs/outputs. It also
> > > enables the testing of PMF metrics data and feature support reporting.
> > >
> > > Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
> > > Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
> > > Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> > > ---
> > > tools/testing/selftests/Makefile | 1 +
> > > .../drivers/platform/x86/amd/pmf/Makefile | 8 +
> > > .../drivers/platform/x86/amd/pmf/test_pmf.c | 243 ++++++++++++++++++
> > > 3 files changed, 252 insertions(+)
> > > create mode 100644
> > > tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile
> > > create mode 100644
> > > tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c
> >
> > Please Cc also selftest people in the next version submission! Maube you
> > should also check why your patch sending process did not capture those
> > receipient for you.
> >
> > To me it looks this "tool" doesn't really perform a selftest the way I've
> > understood "selftests" work. That is, it doesn't have notion of Pass/Fail
> > at all AFAICT. I'm not sure if there are other selftests like this but
> > hopefully the selftest people know.
>
> For a similar "tool" I have it outside of selftests:
>
> linux/tools/crypto/ccp
>
> Ilpo,
>
> Maybe we want a directory structure like this?
>
> tools/platform/x86/amd
At least to me it looks better than placing a non-selftest tool under
selftests/.
--
i.
> > > diff --git a/tools/testing/selftests/Makefile
> > > b/tools/testing/selftests/Makefile
> > > index 450f13ba4cca..d850fb09eeb9 100644
> > > --- a/tools/testing/selftests/Makefile
> > > +++ b/tools/testing/selftests/Makefile
> > > @@ -26,6 +26,7 @@ TARGETS += drivers/net/netconsole
> > > TARGETS += drivers/net/team
> > > TARGETS += drivers/net/virtio_net
> > > TARGETS += drivers/platform/x86/intel/ifs
> > > +TARGETS += drivers/platform/x86/amd/pmf
> > > TARGETS += dt
> > > TARGETS += efivarfs
> > > TARGETS += exec
> > > diff --git a/tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile
> > > b/tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile
> > > new file mode 100644
> > > index 000000000000..876424941e83
> > > --- /dev/null
> > > +++ b/tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile
> > > @@ -0,0 +1,8 @@
> > > +# SPDX-License-Identifier: GPL-2.0-or-later
> > > +CFLAGS += $(KHDR_INCLUDES)
> > > +
> > > +TEST_GEN_PROGS := test_pmf
> > > +
> > > +top_srcdir ?=../../../../..
> > > +
> > > +include ../../../../../lib.mk
> > > diff --git
> > > a/tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c
> > > b/tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c
> > > new file mode 100644
> > > index 000000000000..a040ef01ba90
> > > --- /dev/null
> > > +++ b/tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c
> > > @@ -0,0 +1,243 @@
> > > +// SPDX-License-Identifier: GPL-2.0-or-later
> > > +/*
> > > + * AMD Platform Management Framework Test Tool
> > > + *
> > > + * Copyright (c) 2026, Advanced Micro Devices, Inc.
> > > + * All Rights Reserved.
> > > + *
> > > + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> > > + * Sanket Goswami <Sanket.Goswami@amd.com>
> > > + */
> > > +
> > > +#include <errno.h>
> > > +#include <fcntl.h>
> > > +#include <inttypes.h>
> > > +#include <stdbool.h>
> > > +#include <stdint.h>
> > > +#include <stdio.h>
> > > +#include <string.h>
> > > +#include <sys/ioctl.h>
> > > +#include <unistd.h>
> > > +#include <linux/amd-pmf.h>
> > > +
> > > +#include "../../../../../kselftest.h"
> > > +
> > > +#define DEVICE_NODE "/dev/amdpmf_interface"
> > > +
> > > +static int pmf_open_device(void)
> > > +{
> > > + int fd;
> > > +
> > > + fd = open(DEVICE_NODE, O_RDONLY);
> > > + if (fd < 0)
> > > + fprintf(stderr, "opening PMF Device Node failed: %s\n",
> > > strerror(errno));
> > > +
> > > + return fd;
> > > +}
> > > +
> > > +/* Helper to run IOCTL_PMF_POPULATE_DATA for one control code and return
> > > 0 on success. */
> >
> > Reflow this comment to 80 chars.
> >
> > > +static int pmf_get_fd(int fd, enum pmf_ioctl_id code, struct
> > > amd_pmf_ioctl_info *out)
> > > +{
> > > + struct amd_pmf_ioctl_info info = {0};
> >
> > = {}; should be enough to initialize to default values.
> >
> > > + int ret;
> > > +
> > > + if (!out)
> > > + return -EINVAL;
> > > +
> > > + info.control_code = code;
> > > +
> > > + ret = ioctl(fd, IOCTL_PMF_POPULATE_DATA, &info);
> > > + if (ret < 0)
> > > + return ret;
> > > +
> > > + *out = info;
> > > + return 0;
> > > +}
> > > +
> > > +static int pmf_get_data(enum pmf_ioctl_id code, struct amd_pmf_ioctl_info
> > > *out)
> > > +{
> > > + int fd, ret;
> > > +
> > > + fd = pmf_open_device();
> > > + if (fd < 0)
> > > + return fd;
> > > +
> > > + ret = pmf_get_fd(fd, code, out);
> > > +
> > > + close(fd);
> > > + return ret;
> > > +}
> > > +
> > > +static int pmf_get_feature_status(unsigned int code)
> > > +{
> > > + struct amd_pmf_ioctl_info info = {0};
> > > + int ret;
> > > +
> > > + ret = pmf_get_data(code, &info);
> > > + if (ret < 0)
> > > + return ret;
> > > +
> > > + switch (code) {
> > > + case IOCTL_FEATURE_AUTO_MODE:
> > > + printf("Auto Mode: %-24s\n", info.feature_supported ? "Yes" :
> > > "No");
> > > + break;
> > > + case IOCTL_FEATURE_STATIC_POWER_SLIDER:
> > > + printf("Static Power Slider: %-24s\n", info.feature_supported
> > > ? "Yes" : "No");
> > > + break;
> > > + case IOCTL_FEATURE_POLICY_BUILDER:
> > > + printf("Policy Builder: %s\n", info.feature_supported ? "Yes"
> > > : "No");
> > > + break;
> > > + case IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC:
> > > + printf("Dynamic Power Slider AC: %s\n", info.feature_supported
> > > ? "Yes" : "No");
> > > + break;
> > > + case IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC:
> > > + printf("Dynamic Power Slider DC: %s\n", info.feature_supported
> > > ? "Yes" : "No");
> > > + break;
> > > + default:
> > > + return -1;
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int pmf_get_device_state(unsigned int code)
> > > +{
> > > + struct amd_pmf_ioctl_info info = {0};
> > > + int ret;
> > > +
> > > + ret = pmf_get_data(code, &info);
> > > + if (ret < 0)
> > > + return ret;
> > > +
> > > + switch (code) {
> > > + case IOCTL_PLATFORM_TYPE:
> > > + printf("Platform Type: %s\n", platform_type_as_str(info.val));
> > > + break;
> > > + case IOCTL_LAPTOP_PLACEMENT:
> > > + printf("Laptop placement: %s\n",
> > > laptop_placement_as_str(info.val));
> > > + break;
> > > + case IOCTL_LID_STATE:
> > > + printf("Lid State: %s\n", info.val ? "Close" : "Open");
> > > + break;
> > > + case IOCTL_USER_PRESENCE:
> > > + printf("User Presence: %s\n", info.val ? "Present" : "Away");
> > > + break;
> > > + default:
> > > + return -1;
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int pmf_get_custom_bios_input(unsigned int code)
> > > +{
> > > + struct amd_pmf_ioctl_info info = {0};
> > > + int idx, ret;
> > > +
> > > + ret = pmf_get_data(code, &info);
> > > + if (ret < 0)
> > > + return ret;
> > > +
> > > + switch (code) {
> > > + case IOCTL_BIOS_INPUT_1 ... IOCTL_BIOS_INPUT_10:
> > > + idx = amd_pmf_get_bios_idx(code);
> > > + printf("Custom BIOS input%u: %lu\n", idx + 1,
> > > (int64_t)info.val);
> >
> > %lu is for printing unsigned long, not int64_t.
> >
> > > + break;
> > > + default:
> > > + return -1;
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int pmf_get_bios_output(unsigned int code)
> > > +{
> > > + struct amd_pmf_ioctl_info info = {0};
> > > + int idx, ret;
> > > +
> > > + ret = pmf_get_data(code, &info);
> > > + if (ret < 0)
> > > + return ret;
> > > +
> > > + switch (code) {
> > > + case IOCTL_BIOS_OUTPUT_1 ... IOCTL_BIOS_OUTPUT_10:
> > > + idx = amd_pmf_get_bios_idx(code);
> > > + printf("BIOS output%u: %lu\n", idx + 1, (int64_t)info.val);
> > > + break;
> > > + default:
> > > + return -1;
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static int pmf_get_misc_info(unsigned int code)
> > > +{
> > > + struct amd_pmf_ioctl_info info = {0};
> > > + int ret;
> > > +
> > > + ret = pmf_get_data(code, &info);
> > > + if (ret < 0)
> > > + return ret;
> > > +
> > > + switch (code) {
> > > + case IOCTL_POWER_SLIDER_POSITION:
> > > + printf("Slider Position: %s\n", ta_slider_as_str(info.val));
> > > + break;
> > > + case IOCTL_SKIN_TEMP:
> > > + printf("Skin Temperature: %lu\n", (int64_t)info.val);
> > > + break;
> > > + case IOCTL_GFX_WORKLOAD:
> > > + printf("GFX Busy: %lu\n", (int64_t)info.val);
> > > + break;
> > > + case IOCTL_AMBIENT_LIGHT:
> > > + printf("Ambient Light: %ld\n", (int64_t)info.val);
> > > + break;
> > > + case IOCTL_AVG_C0_RES:
> > > + printf("Avg C0 Residency: %lu\n", (int64_t)info.val);
> > > + break;
> > > + case IOCTL_MAX_C0_RES:
> > > + printf("Max C0 Residency: %lu\n", (int64_t)info.val);
> > > + break;
> > > + case IOCTL_SOCKET_POWER:
> > > + printf("Socket Power: %lu\n", (int64_t)info.val);
> >
> > Please think the printf formatting strings and types through.
> >
> > > + break;
> > > + default:
> > > + return -1;
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +int main(void)
> > > +{
> > > + unsigned int idx;
> > > +
> > > + printf("Feature Name Supported\n");
> > > + printf("---------------------------------\n");
> > > + for (idx = IOCTL_FEATURE_AUTO_MODE; idx <=
> > > IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC; idx++)
> > > + pmf_get_feature_status(idx);
> > > +
> > > + printf("\nDevice State\n---------------\n");
> > > + for (idx = IOCTL_PLATFORM_TYPE; idx <= IOCTL_USER_PRESENCE; idx++)
> > > + pmf_get_device_state(idx);
> > > +
> > > + printf("\nCustom BIOS Inputs\n-------------------\n");
> > > + for (idx = IOCTL_BIOS_INPUT_1; idx <= IOCTL_BIOS_INPUT_10; idx++)
> > > + pmf_get_custom_bios_input(idx);
> > > +
> > > + printf("\nBIOS Outputs\n--------------\n");
> > > + for (idx = IOCTL_BIOS_OUTPUT_1; idx <= IOCTL_BIOS_OUTPUT_10; idx++)
> > > + pmf_get_bios_output(idx);
> > > +
> > > + printf("\nMisc\n------\n");
> > > + pmf_get_misc_info(IOCTL_SKIN_TEMP);
> > > + pmf_get_misc_info(IOCTL_GFX_WORKLOAD);
> > > + pmf_get_misc_info(IOCTL_AMBIENT_LIGHT);
> > > + pmf_get_misc_info(IOCTL_AVG_C0_RES);
> > > + pmf_get_misc_info(IOCTL_MAX_C0_RES);
> > > + pmf_get_misc_info(IOCTL_SOCKET_POWER);
> > > + pmf_get_misc_info(IOCTL_POWER_SLIDER_POSITION);
> > > +
> > > + return 0;
> > > +}
> > >
> >
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 3/7] platform/x86/amd/pmf: Add feature discovery support to util interface
2026-03-25 14:07 ` Ilpo Järvinen
@ 2026-03-30 11:41 ` Shyam Sundar S K
0 siblings, 0 replies; 30+ messages in thread
From: Shyam Sundar S K @ 2026-03-30 11:41 UTC (permalink / raw)
To: Ilpo Järvinen; +Cc: platform-driver-x86, Yijun.Shen, Sanket.Goswami
On 3/25/2026 19:37, Ilpo Järvinen wrote:
> On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
>
>> Add feature discovery capability to the util layer interface, allowing
>> userspace tools to query which PMF features are supported and enabled
>> on the current platform.
>>
>> The following features can now be queried through the
>> /dev/amdpmf_interface ioctl:
>> *Auto Mode: Automatic power profile switching based on system activity
>> *Static Power Slider: User-selectable power profiles
>> *Policy Builder (Smart PC): Action based policy management
>> *Dynamic Power Slider AC: Adaptive power profiles when on AC power
>> *Dynamic Power Slider DC: Adaptive power profiles when on battery
>
> Same comments to the list as to the other patch.
>
>> Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
>> Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
>> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>> ---
>> drivers/platform/x86/amd/pmf/util.c | 33 +++++++++++++++++++++++++++++
>> include/uapi/linux/amd-pmf.h | 12 ++++++++++-
>> 2 files changed, 44 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
>> index 59a125deb6b6..9a14467f412c 100644
>> --- a/drivers/platform/x86/amd/pmf/util.c
>> +++ b/drivers/platform/x86/amd/pmf/util.c
>> @@ -16,6 +16,8 @@
>>
>> #include "pmf.h"
>>
>> +#define AMD_PMF_IOCTL_VERSION 0x02
>> +
>> /* Convert BIOS input control code to array index (0-9) */
>> static int amd_pmf_get_bios_idx(u32 control_code)
>> {
>> @@ -46,6 +48,33 @@ static long long amd_pmf_populate_bios_output(struct amd_pmf_dev *pdev, u32 cont
>> return pdev->bios_output[idx];
>> }
>>
>> +static bool amd_pmf_is_feature_supported(struct amd_pmf_dev *pdev, u32 control_code)
>> +{
>> + bool feat;
>> +
>> + switch (control_code) {
>> + case IOCTL_FEATURE_AUTO_MODE:
>> + feat = is_apmf_func_supported(pdev, APMF_FUNC_AUTO_MODE);
>> + break;
>> + case IOCTL_FEATURE_STATIC_POWER_SLIDER:
>> + feat = is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR);
>> + break;
>> + case IOCTL_FEATURE_POLICY_BUILDER:
>> + feat = pdev->smart_pc_enabled;
>> + break;
>> + case IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC:
>> + feat = is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_AC);
>> + break;
>> + case IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC:
>> + feat = is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_DC);
>> + break;
>> + default:
>> + return false;
>> + }
>> +
>> + return feat;
>> +}
>> +
>> static long long amd_pmf_device_state(struct ta_pmf_enact_table *in, u32 control_code)
>> {
>> switch (control_code) {
>> @@ -116,6 +145,10 @@ static int amd_pmf_populate_data(struct device *dev, void __user *argp)
>> case IOCTL_BIOS_OUTPUT_1 ... IOCTL_BIOS_OUTPUT_10:
>> output.val = amd_pmf_populate_bios_output(pdev, output.control_code);
>> break;
>> + case IOCTL_FEATURE_AUTO_MODE ... IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC:
>> + output.feature_supported = amd_pmf_is_feature_supported(pdev, output.control_code);
>> + output.feature_version = AMD_PMF_IOCTL_VERSION;
>> + break;
>> default:
>> return -EINVAL;
>> }
>> diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
>> index f93767248169..f34c5d744039 100644
>> --- a/include/uapi/linux/amd-pmf.h
>> +++ b/include/uapi/linux/amd-pmf.h
>> @@ -70,6 +70,11 @@
>> * @IOCTL_BIOS_OUTPUT_8: Query BIOS output parameter 8
>> * @IOCTL_BIOS_OUTPUT_9: Query BIOS output parameter 9
>> * @IOCTL_BIOS_OUTPUT_10: Query BIOS output parameter 10
>> + * @IOCTL_FEATURE_AUTO_MODE: Query if Auto Mode feature is supported
>> + * @IOCTL_FEATURE_STATIC_POWER_SLIDER: Query if Static Power Slider is supported
>> + * @IOCTL_FEATURE_POLICY_BUILDER: Query if Policy Builder feature is supported
>> + * @IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC: Query if Dynamic Power Slider (AC) is supported
>> + * @IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC: Query if Dynamic Power Slider (DC) is supported
>> *
>> * These control codes are used with the IOCTL_PMF_POPULATE_DATA ioctl
>> * to specify which metrics data to retrieve from the AMD PMF driver.
>> @@ -110,7 +115,12 @@ enum pmf_ioctl_id {
>> IOCTL_BIOS_OUTPUT_7,
>> IOCTL_BIOS_OUTPUT_8,
>> IOCTL_BIOS_OUTPUT_9,
>> - IOCTL_BIOS_OUTPUT_10
>> + IOCTL_BIOS_OUTPUT_10,
>> + IOCTL_FEATURE_AUTO_MODE,
>> + IOCTL_FEATURE_STATIC_POWER_SLIDER,
>> + IOCTL_FEATURE_POLICY_BUILDER,
>> + IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC,
>> + IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC
>
> I'm trying to confirm whether there are some special requirements when
> it comes to trailing commas for uapi headers. If somebody knows for sure
> if trailing commas are safe or not for userspace builds, please chime in.
>
I randomly checked few files, and see a comma at the end.
include/uapi/linux/nexthop.h
include/uapi/linux/netdev.h
include/uapi/linux/xfrm.h
So, its upto you - your preference.
Thanks,
Shyam
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 6/7] platform/x86/amd/pmf: Introduce AMD PMF testing tool for driver metrics and features
2026-03-26 10:20 ` Ilpo Järvinen
@ 2026-03-30 11:42 ` Shyam Sundar S K
0 siblings, 0 replies; 30+ messages in thread
From: Shyam Sundar S K @ 2026-03-30 11:42 UTC (permalink / raw)
To: Ilpo Järvinen, Mario Limonciello
Cc: Shuah Khan, Shuah Khan, linux-kselftest, Hans de Goede,
platform-driver-x86, Yijun.Shen, Sanket.Goswami
On 3/26/2026 15:50, Ilpo Järvinen wrote:
> On Wed, 25 Mar 2026, Mario Limonciello wrote:
>> On 3/25/26 08:54, Ilpo Järvinen wrote:
>>> + Selftest people.
>>>
>>> On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
>>>
>>>> This tool leverages amd-pmf ioctls exposed via the util layer, allowing
>>>> validation of its newly integrated util layer and /dev/amdpmf_interface.
>>>> It includes a user-space test application, test_pmf, designed to interact
>>>> with the PMF driver and retrieve relevant metrics for the testing and
>>>> analysis.
>>>>
>>>> It provides definitions for test metrics, feature IDs, and device states,
>>>> and includes tests for various AMD PMF metrics such as power source, skin
>>>> temperature, battery state, and custom BIOS inputs/outputs. It also
>>>> enables the testing of PMF metrics data and feature support reporting.
>>>>
>>>> Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
>>>> Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
>>>> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>>>> ---
>>>> tools/testing/selftests/Makefile | 1 +
>>>> .../drivers/platform/x86/amd/pmf/Makefile | 8 +
>>>> .../drivers/platform/x86/amd/pmf/test_pmf.c | 243 ++++++++++++++++++
>>>> 3 files changed, 252 insertions(+)
>>>> create mode 100644
>>>> tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile
>>>> create mode 100644
>>>> tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c
>>>
>>> Please Cc also selftest people in the next version submission! Maube you
>>> should also check why your patch sending process did not capture those
>>> receipient for you.
>>>
>>> To me it looks this "tool" doesn't really perform a selftest the way I've
>>> understood "selftests" work. That is, it doesn't have notion of Pass/Fail
>>> at all AFAICT. I'm not sure if there are other selftests like this but
>>> hopefully the selftest people know.
>>
>> For a similar "tool" I have it outside of selftests:
>>
>> linux/tools/crypto/ccp
>>
>> Ilpo,
>>
>> Maybe we want a directory structure like this?
>>
>> tools/platform/x86/amd
>
> At least to me it looks better than placing a non-selftest tool under
> selftests/.
>
Even I think this is a good choice. Thanks! I will make this change in
the next version.
Thanks,
Shyam
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 5/7] platform/x86/amd/pmf: Move debug helper functions to UAPI header
2026-03-25 13:39 ` Ilpo Järvinen
@ 2026-03-30 11:45 ` Shyam Sundar S K
0 siblings, 0 replies; 30+ messages in thread
From: Shyam Sundar S K @ 2026-03-30 11:45 UTC (permalink / raw)
To: Ilpo Järvinen, Hans de Goede
Cc: platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami
On 3/25/2026 19:09, Ilpo Järvinen wrote:
> On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
>
>> These debug helper functions convert enumerated values to appropriate
>> message and can be useful for userspace tools and other kernel components
>> that need to interpret AMD PMF state values.
>>
>> By making them inline functions in the UAPI header, they become available
>> to both kernel and userspace without code duplication.
>>
>> Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
>> Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
>> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>
> Here too I'm not happy with the naming and I'm a little skeptical about
> the sharing string conversion helpers as well.
>
> Hans,
>
> do you have something to say on having this kind of string conversions in
> an uapi header?
Good question. Lets wait to hear from Hans as well.
The thought process was anyways we were trying to unify things under
UAPI, thought to move even the helpers in uapi headers.
But, I am open to suggestions.
Thanks,
Shyam
>
>> ---
>> drivers/platform/x86/amd/pmf/spc.c | 54 --------------
>> drivers/platform/x86/amd/pmf/util.c | 12 ----
>> include/uapi/linux/amd-pmf.h | 105 ++++++++++++++++++++++++++++
>> 3 files changed, 105 insertions(+), 66 deletions(-)
>>
>> diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c
>> index a40419b5e1b7..f91feaac5238 100644
>> --- a/drivers/platform/x86/amd/pmf/spc.c
>> +++ b/drivers/platform/x86/amd/pmf/spc.c
>> @@ -18,60 +18,6 @@
>> #include "pmf.h"
>>
>> #ifdef CONFIG_AMD_PMF_DEBUG
>> -static const char *platform_type_as_str(u16 platform_type)
>> -{
>> - switch (platform_type) {
>> - case CLAMSHELL:
>> - return "CLAMSHELL";
>> - case FLAT:
>> - return "FLAT";
>> - case TENT:
>> - return "TENT";
>> - case STAND:
>> - return "STAND";
>> - case TABLET:
>> - return "TABLET";
>> - case BOOK:
>> - return "BOOK";
>> - case PRESENTATION:
>> - return "PRESENTATION";
>> - case PULL_FWD:
>> - return "PULL_FWD";
>> - default:
>> - return "UNKNOWN";
>> - }
>> -}
>> -
>> -static const char *laptop_placement_as_str(u16 device_state)
>> -{
>> - switch (device_state) {
>> - case ON_TABLE:
>> - return "ON_TABLE";
>> - case ON_LAP_MOTION:
>> - return "ON_LAP_MOTION";
>> - case IN_BAG:
>> - return "IN_BAG";
>> - case OUT_OF_BAG:
>> - return "OUT_OF_BAG";
>> - default:
>> - return "UNKNOWN";
>> - }
>> -}
>> -
>> -static const char *ta_slider_as_str(unsigned int state)
>> -{
>> - switch (state) {
>> - case TA_BEST_PERFORMANCE:
>> - return "PERFORMANCE";
>> - case TA_BETTER_PERFORMANCE:
>> - return "BALANCED";
>> - case TA_BEST_BATTERY:
>> - return "POWER_SAVER";
>> - default:
>> - return "Unknown TA Slider State";
>> - }
>> -}
>> -
>> static u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index)
>> {
>> switch (index) {
>> diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
>> index 9a14467f412c..20dc7aa9f250 100644
>> --- a/drivers/platform/x86/amd/pmf/util.c
>> +++ b/drivers/platform/x86/amd/pmf/util.c
>> @@ -18,18 +18,6 @@
>>
>> #define AMD_PMF_IOCTL_VERSION 0x02
>>
>> -/* Convert BIOS input control code to array index (0-9) */
>> -static int amd_pmf_get_bios_idx(u32 control_code)
>> -{
>> - if (control_code >= IOCTL_BIOS_INPUT_1 && control_code <= IOCTL_BIOS_INPUT_10)
>> - return control_code - IOCTL_BIOS_INPUT_1;
>> -
>> - if (control_code >= IOCTL_BIOS_OUTPUT_1 && control_code <= IOCTL_BIOS_OUTPUT_10)
>> - return control_code - IOCTL_BIOS_OUTPUT_1;
>> -
>> - return -EINVAL;
>> -}
>> -
>> static long long amd_pmf_populate_bios_input(struct ta_pmf_enact_table *in, u32 control_code)
>> {
>> u32 idx;
>> diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
>> index 00fab9269238..e2125b304b83 100644
>> --- a/include/uapi/linux/amd-pmf.h
>> +++ b/include/uapi/linux/amd-pmf.h
>> @@ -14,6 +14,7 @@
>> #ifndef _UAPI_LINUX_AMD_PMF_H
>> #define _UAPI_LINUX_AMD_PMF_H
>>
>> +#include <linux/errno.h>
>> #include <linux/ioctl.h>
>> #include <linux/types.h>
>>
>> @@ -106,6 +107,88 @@ enum platform_type {
>> PTYPE_INVALID = 0xf,
>> };
>>
>> +/**
>> + * platform_type_as_str() - Convert platform type enum to string
>> + * @platform_type: The platform type value to convert
>> + *
>> + * Returns a human-readable string representation of the platform type.
>> + *
>> + * Return: Constant string describing the platform type, or "UNKNOWN"
>> + * if the value is not recognized.
>> + */
>> +static inline const char *platform_type_as_str(unsigned int platform_type)
>> +{
>> + switch (platform_type) {
>> + case CLAMSHELL:
>> + return "CLAMSHELL";
>> + case FLAT:
>> + return "FLAT";
>> + case TENT:
>> + return "TENT";
>> + case STAND:
>> + return "STAND";
>> + case TABLET:
>> + return "TABLET";
>> + case BOOK:
>> + return "BOOK";
>> + case PRESENTATION:
>> + return "PRESENTATION";
>> + case PULL_FWD:
>> + return "PULL_FWD";
>> + default:
>> + return "UNKNOWN";
>> + }
>> +}
>> +
>> +/**
>> + * laptop_placement_as_str() - Convert laptop placement enum to string
>> + * @device_state: The laptop placement value to convert
>> + *
>> + * Returns a human-readable string representation of the laptop placement.
>> + *
>> + * Return: Constant string describing the placement, or "UNKNOWN"
>> + * if the value is not recognized.
>> + */
>> +static inline const char *laptop_placement_as_str(unsigned int device_state)
>> +{
>> + switch (device_state) {
>> + case ON_TABLE:
>> + return "ON_TABLE";
>> + case ON_LAP_MOTION:
>> + return "ON_LAP_MOTION";
>> + case IN_BAG:
>> + return "IN_BAG";
>> + case OUT_OF_BAG:
>> + return "OUT_OF_BAG";
>> + default:
>> + return "UNKNOWN";
>> + }
>> +}
>> +
>> +/**
>> + * ta_slider_as_str() - Convert TA slider enum to string
>> + * @state: The TA slider state value to convert
>> + *
>> + * Returns a human-readable string representation of the power slider
>> + * position suitable for display purposes.
>> + *
>> + * Return: Constant string describing the slider state, or
>> + * "Unknown TA Slider State" if the value is not recognized.
>> + */
>> +static inline const char *ta_slider_as_str(unsigned int state)
>> +{
>> + switch (state) {
>> + case TA_BEST_PERFORMANCE:
>> + return "PERFORMANCE";
>> + case TA_BETTER_PERFORMANCE:
>> + return "BALANCED";
>> + case TA_BEST_BATTERY:
>> + return "POWER_SAVER";
>> + default:
>> + return "Unknown TA Slider State";
>> + }
>> +}
>> +
>> /**
>> * enum pmf_ioctl_id - Control codes for PMF ioctl operations
>> * @IOCTL_POWER_SOURCE: Query current power source (AC/DC)
>> @@ -197,6 +280,28 @@ enum pmf_ioctl_id {
>> IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC
>> };
>>
>> +/**
>> + * amd_pmf_get_bios_idx() - Convert BIOS control code to array index
>> + * @control_code: The BIOS input or output control code
>> + *
>> + * Converts a BIOS input (IOCTL_BIOS_INPUT_1 to IOCTL_BIOS_INPUT_10) or
>> + * BIOS output (IOCTL_BIOS_OUTPUT_1 to IOCTL_BIOS_OUTPUT_10) control code
>> + * to a zero-based array index (0-9).
>> + *
>> + * Return: Array index (0-9) on success, -EINVAL if the control code
>> + * is not a valid BIOS input or output code.
>> + */
>> +static inline int amd_pmf_get_bios_idx(unsigned int control_code)
>> +{
>> + if (control_code >= IOCTL_BIOS_INPUT_1 && control_code <= IOCTL_BIOS_INPUT_10)
>> + return control_code - IOCTL_BIOS_INPUT_1;
>> +
>> + if (control_code >= IOCTL_BIOS_OUTPUT_1 && control_code <= IOCTL_BIOS_OUTPUT_10)
>> + return control_code - IOCTL_BIOS_OUTPUT_1;
>> +
>> + return -EINVAL;
>> +}
>> +
>> /**
>> * struct amd_pmf_ioctl_info - Structure for PMF ioctl data exchange
>> * @control_code: Input parameter specifying which data to query (enum pmf_ioctl_id)
>>
>
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 1/7] platform/x86/amd/pmf: Add util layer and userspace misc device interface
2026-03-25 14:05 ` Ilpo Järvinen
@ 2026-03-30 12:12 ` Shyam Sundar S K
2026-03-30 15:10 ` Ilpo Järvinen
0 siblings, 1 reply; 30+ messages in thread
From: Shyam Sundar S K @ 2026-03-30 12:12 UTC (permalink / raw)
To: Ilpo Järvinen
Cc: Hans de Goede, platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami
Hi Ilpo,
Ack to all the comments in the series.
On 3/25/2026 19:35, Ilpo Järvinen wrote:
> On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
>
>> Add a util layer to AMD PMF that exposes a minimal userspace interface
>> via a misc character device for metrics monitoring and feature discovery.
>>
>> This creates /dev/amdpmf_interface with basic ioctl support to retrieve
>> PMF metrics such as:
>> *Power source and power slider position
>> *Platform type, lid state, and user presence
>> *Skin temperature and ambient light
>> *BIOS input parameters (1-10)
>> *Graphics workload metrics
>> *CPU C-state residency (average and maximum)
>> *Socket power consumption
>>
>> The interface enables smoother integration with userspace tools such as
>> AMD SystemDeck [1], which is widely used for monitoring and controlling
>> power and thermal behavior on AMD platforms. These tools help designers
>> keep major components within thermal limits to ensure proper operation
>> and enhance overall system stability and reliability.
>>
>> The feature is gated behind the CONFIG_AMD_PMF_UTIL_SUPPORT Kconfig
>> option, allowing it to be disabled if not needed. The implementation
>> uses existing PMF infrastructure to populate data from the TA (Trusted
>> Application) shared memory buffer.
>>
>> Link: https://docs.amd.com/v/u/en-US/68773_0.50 [1]
>>
>> Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
>> Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
>> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>> ---
>> drivers/platform/x86/amd/pmf/Kconfig | 10 ++
>> drivers/platform/x86/amd/pmf/Makefile | 2 +
>> drivers/platform/x86/amd/pmf/core.c | 5 +
>> drivers/platform/x86/amd/pmf/pmf.h | 9 ++
>> drivers/platform/x86/amd/pmf/util.c | 174 ++++++++++++++++++++++++++
>> include/uapi/linux/amd-pmf.h | 115 +++++++++++++++++
>> 6 files changed, 315 insertions(+)
>> create mode 100644 drivers/platform/x86/amd/pmf/util.c
>> create mode 100644 include/uapi/linux/amd-pmf.h
>>
>> diff --git a/drivers/platform/x86/amd/pmf/Kconfig b/drivers/platform/x86/amd/pmf/Kconfig
>> index 25b8f7ae3abd..ad21f679b8ab 100644
>> --- a/drivers/platform/x86/amd/pmf/Kconfig
>> +++ b/drivers/platform/x86/amd/pmf/Kconfig
>> @@ -30,3 +30,13 @@ config AMD_PMF_DEBUG
>> in the PMF config store.
>>
>> Say Y here to enable more debug logs and Say N here if you are not sure.
>> +
>> +config AMD_PMF_UTIL_SUPPORT
>> + bool "AMD PMF Util layer support"
>> + depends on AMD_PMF
>> + help
>> + Enabling this option provides a character device for userspace to capture
>> + PMF features (Smart PC Builder, Auto Mode, Static Power Slider, Dynamic
>> + Power Slider AC/DC) along with PMF metrics from the AMD PMF driver.
>> +
>> + Say Y here to enable it and Say N here if you are not sure.
>> diff --git a/drivers/platform/x86/amd/pmf/Makefile b/drivers/platform/x86/amd/pmf/Makefile
>> index 5978464e0eb7..bf7aad80b9e9 100644
>> --- a/drivers/platform/x86/amd/pmf/Makefile
>> +++ b/drivers/platform/x86/amd/pmf/Makefile
>> @@ -8,3 +8,5 @@ obj-$(CONFIG_AMD_PMF) += amd-pmf.o
>> amd-pmf-y := core.o acpi.o sps.o \
>> auto-mode.o cnqf.o \
>> tee-if.o spc.o
>> +# Build util.c only when AMD_PMF_UTIL_SUPPORT is enabled
>> +amd-pmf-$(CONFIG_AMD_PMF_UTIL_SUPPORT) += util.o
>> diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
>> index b9e5a2cf3aae..919d02f30aae 100644
>> --- a/drivers/platform/x86/amd/pmf/core.c
>> +++ b/drivers/platform/x86/amd/pmf/core.c
>> @@ -634,6 +634,10 @@ static int amd_pmf_probe(struct platform_device *pdev)
>>
>> pmf_device = dev->dev;
>>
>> + err = amd_pmf_cdev_register(dev);
>> + if (err)
>> + dev_warn(dev->dev, "failed to register util interface: %d\n", err);
>> +
>> dev_info(dev->dev, "registered PMF device successfully\n");
>>
>> return 0;
>> @@ -646,6 +650,7 @@ static void amd_pmf_remove(struct platform_device *pdev)
>> amd_pmf_deinit_features(dev);
>> if (is_apmf_func_supported(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
>> amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_UNLOAD);
>> + amd_pmf_cdev_unregister();
>> apmf_acpi_deinit(dev);
>> amd_pmf_dbgfs_unregister(dev);
>> }
>> diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
>> index 69fef7448744..6f61076a9386 100644
>> --- a/drivers/platform/x86/amd/pmf/pmf.h
>> +++ b/drivers/platform/x86/amd/pmf/pmf.h
>> @@ -928,4 +928,13 @@ int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid);
>> void amd_pmf_tee_deinit(struct amd_pmf_dev *dev);
>> int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev);
>>
>> +/* Util Layer */
>> +#if IS_ENABLED(CONFIG_AMD_PMF_UTIL_SUPPORT)
>> +int amd_pmf_cdev_register(struct amd_pmf_dev *dev);
>> +void amd_pmf_cdev_unregister(void);
>> +#else
>> +static inline int amd_pmf_cdev_register(struct amd_pmf_dev *dev) { return 0; }
>> +static inline void amd_pmf_cdev_unregister(void) {}
>> +#endif
>> +
>> #endif /* PMF_H */
>> diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
>> new file mode 100644
>> index 000000000000..c6837caa44e0
>> --- /dev/null
>> +++ b/drivers/platform/x86/amd/pmf/util.c
>> @@ -0,0 +1,174 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * AMD Platform Management Framework Util Layer
>> + *
>> + * Copyright (c) 2026, Advanced Micro Devices, Inc.
>> + * All Rights Reserved.
>> + *
>> + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
>> + * Sanket Goswami <Sanket.Goswami@amd.com>
>> + */
>> +
>> +#include <linux/amd-pmf.h>
>> +#include <linux/miscdevice.h>
>> +#include <linux/mutex.h>
>> +#include <linux/uaccess.h>
>> +
>> +#include "pmf.h"
>> +
>> +/* Convert BIOS input control code to array index (0-9) */
>> +static int amd_pmf_get_bios_idx(u32 control_code)
>> +{
>> + if (control_code >= IOCTL_BIOS_INPUT_1 && control_code <= IOCTL_BIOS_INPUT_10)
>> + return control_code - IOCTL_BIOS_INPUT_1;
>> +
>> + return -EINVAL;
>> +}
>> +
>> +static long long amd_pmf_populate_bios_input(struct ta_pmf_enact_table *in, u32 control_code)
>> +{
>> + u32 idx;
>> +
>> + idx = amd_pmf_get_bios_idx(control_code);
>> +
>> + return (idx < 2) ? in->ev_info.bios_input_1[idx] : in->ev_info.bios_input_2[idx - 2];
>> +}
>> +
>> +static long long amd_pmf_device_state(struct ta_pmf_enact_table *in, u32 control_code)
>> +{
>> + switch (control_code) {
>> + case IOCTL_PLATFORM_TYPE:
>> + return in->ev_info.platform_type;
>> + case IOCTL_LAPTOP_PLACEMENT:
>> + return in->ev_info.device_state;
>> + case IOCTL_LID_STATE:
>> + return in->ev_info.lid_state;
>> + case IOCTL_USER_PRESENCE:
>> + return in->ev_info.user_present;
>> + default:
>> + return -EINVAL;
>> + }
>> +}
>> +
>> +static int amd_pmf_populate_data(struct device *dev, void __user *argp)
>> +{
>> + struct amd_pmf_ioctl_info output = {0};
>> + struct ta_pmf_shared_memory *ta_sm = NULL;
>> + struct ta_pmf_enact_table *in = NULL;
>> + struct amd_pmf_dev *pdev;
>> +
>> + pdev = dev_get_drvdata(dev);
>> + if (!pdev)
>> + return -EINVAL;
>> +
>> + memset(pdev->shbuf, 0, pdev->policy_sz);
>> + ta_sm = pdev->shbuf;
>> + in = &ta_sm->pmf_input.enact_table;
>> +
>> + if (copy_from_user(&output, argp, sizeof(output)))
>> + return -EFAULT;
>> +
>> + switch (output.control_code) {
>> + case IOCTL_POWER_SOURCE:
>> + output.val = in->ev_info.power_source;
>> + break;
>> + case IOCTL_POWER_SLIDER_POSITION:
>> + output.val = in->ev_info.power_slider;
>> + break;
>> + case IOCTL_SKIN_TEMP:
>> + /* Convert from centi-degrees to degrees Celsius */
>> + output.val = in->ev_info.skin_temperature / 100;
>> + break;
>> + case IOCTL_PLATFORM_TYPE ... IOCTL_LID_STATE:
>> + case IOCTL_USER_PRESENCE:
>> + output.val = amd_pmf_device_state(in, output.control_code);
>> + break;
>> + case IOCTL_BIOS_INPUT_1 ... IOCTL_BIOS_INPUT_10:
>> + output.val = amd_pmf_populate_bios_input(in, output.control_code);
>> + break;
>> + case IOCTL_GFX_WORKLOAD:
>> + output.val = in->ev_info.gfx_busy;
>> + break;
>> + case IOCTL_AMBIENT_LIGHT:
>> + output.val = in->ev_info.ambient_light;
>> + break;
>> + case IOCTL_AVG_C0_RES:
>> + output.val = in->ev_info.avg_c0residency;
>> + break;
>> + case IOCTL_MAX_C0_RES:
>> + output.val = in->ev_info.max_c0residency;
>> + break;
>> + case IOCTL_SOCKET_POWER:
>> + output.val = in->ev_info.socket_power;
>> + break;
>> + default:
>> + return -EINVAL;
>> + }
>> +
>> + if (copy_to_user(argp, &output, sizeof(output)))
>> + return -EFAULT;
>> +
>> + return 0;
>> +}
>> +
>> +#if IS_ENABLED(CONFIG_AMD_PMF_UTIL_SUPPORT)
>> +static struct amd_pmf_dev *pmf_dev_handle;
>> +static DEFINE_MUTEX(pmf_util_lock);
>> +
>> +static long amd_pmf_set_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
>> +{
>> + struct amd_pmf_dev *pdev = filp->private_data;
>> + void __user *argp = (void __user *)arg;
>> +
>> + if (cmd != IOCTL_PMF_POPULATE_DATA)
>> + return -EINVAL;
>> +
>> + guard(mutex)(&pmf_util_lock);
>> + return amd_pmf_populate_data(pdev->dev, argp);
>> +}
>> +
>> +static int amd_pmf_open(struct inode *inode, struct file *filp)
>> +{
>> + guard(mutex)(&pmf_util_lock);
>> + if (!pmf_dev_handle)
>> + return -ENODEV;
>> +
>> + filp->private_data = pmf_dev_handle;
>> + return 0;
>> +}
>> +
>> +static const struct file_operations pmf_if_ops = {
>> + .owner = THIS_MODULE,
>> + .open = amd_pmf_open,
>> + .unlocked_ioctl = amd_pmf_set_ioctl,
>> +};
>> +
>> +static struct miscdevice amd_pmf_util_if = {
>> + .minor = MISC_DYNAMIC_MINOR,
>> + .name = "amdpmf_interface",
>> + .fops = &pmf_if_ops,
>> +};
>> +
>> +int amd_pmf_cdev_register(struct amd_pmf_dev *dev)
>> +{
>> + int ret;
>> +
>> + guard(mutex)(&pmf_util_lock);
>> + pmf_dev_handle = dev;
>> + ret = misc_register(&amd_pmf_util_if);
>> + if (ret)
>> + pmf_dev_handle = NULL;
>> +
>> + return ret;
>> +}
>> +
>> +void amd_pmf_cdev_unregister(void)
>> +{
>> + guard(mutex)(&pmf_util_lock);
>> + pmf_dev_handle = NULL;
>> + misc_deregister(&amd_pmf_util_if);
>> +}
>> +#else
>> +int amd_pmf_cdev_register(struct amd_pmf_dev *dev) { return 0; }
>> +void amd_pmf_cdev_unregister(void) {}
>> +#endif
>> diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
>> new file mode 100644
>> index 000000000000..d29431c67eaa
>> --- /dev/null
>> +++ b/include/uapi/linux/amd-pmf.h
>> @@ -0,0 +1,115 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */
>> +/*
>> + * AMD Platform Management Framework (PMF) UAPI Header
>> + *
>> + * Copyright (c) 2026, Advanced Micro Devices, Inc.
>> + * All Rights Reserved.
>> + *
>> + * This file defines the user-space API for interacting with the AMD PMF
>> + * driver. It provides ioctl interfaces to query platform-specific metrics
>> + * such as power source, slider position, platform type, laptop placement,
>> + * and various BIOS input/output parameters.
>> + */
>> +
>> +#ifndef _UAPI_LINUX_AMD_PMF_H
>> +#define _UAPI_LINUX_AMD_PMF_H
>> +
>> +#include <linux/ioctl.h>
>> +#include <linux/types.h>
>> +
>> +/**
>> + * AMD_PMF_IOC_MAGIC - Magic number for AMD PMF ioctl commands
>> + *
>> + * This magic number uniquely identifies AMD PMF ioctl operations.
>> + */
>> +#define AMD_PMF_IOC_MAGIC 'p'
>> +
>> +/**
>> + * IOCTL_PMF_POPULATE_DATA - ioctl command to retrieve PMF metrics data
>> + *
>> + * This ioctl command is used to populate the amd_pmf_ioctl_info structure
>> + * with the requested metrics data based on the control_code provided.
>> + */
>> +#define IOCTL_PMF_POPULATE_DATA _IOWR(AMD_PMF_IOC_MAGIC, 0x00, struct amd_pmf_ioctl_info)
>> +
>> +/**
>> + * enum pmf_ioctl_id - Control codes for PMF ioctl operations
>> + * @IOCTL_POWER_SOURCE: Query current power source (AC/DC)
>> + * @IOCTL_POWER_SLIDER_POSITION: Query current power slider position
>> + * @IOCTL_PLATFORM_TYPE: Query current platform/form factor type
>> + * @IOCTL_LAPTOP_PLACEMENT: Query laptop physical placement state
>> + * @IOCTL_LID_STATE: Query laptop lid open/close state
>> + * @IOCTL_HETERO_STATE: Query heterogeneous computing state
>> + * @IOCTL_SKIN_TEMP: Query skin temperature sensor reading
>> + * @IOCTL_USER_PRESENCE: Query user presence detection state
>> + * @IOCTL_DISPLAY_NUM: Query number of active displays
>> + * @IOCTL_USER_ENGAGED: Query user engagement state
>> + * @IOCTL_BIOS_INPUT_1: Query BIOS input parameter 1
>> + * @IOCTL_BIOS_INPUT_2: Query BIOS input parameter 2
>> + * @IOCTL_BIOS_INPUT_3: Query BIOS input parameter 3
>> + * @IOCTL_BIOS_INPUT_4: Query BIOS input parameter 4
>> + * @IOCTL_BIOS_INPUT_5: Query BIOS input parameter 5
>> + * @IOCTL_BIOS_INPUT_6: Query BIOS input parameter 6
>> + * @IOCTL_BIOS_INPUT_7: Query BIOS input parameter 7
>> + * @IOCTL_BIOS_INPUT_8: Query BIOS input parameter 8
>> + * @IOCTL_BIOS_INPUT_9: Query BIOS input parameter 9
>> + * @IOCTL_BIOS_INPUT_10: Query BIOS input parameter 10
>> + * @IOCTL_GFX_WORKLOAD: Query current graphics workload type
>> + * @IOCTL_AMBIENT_LIGHT: Query ambient light sensor reading
>> + * @IOCTL_AVG_C0_RES: Query average C0 residency
>> + * @IOCTL_MAX_C0_RES: Query maximum C0 residency
>> + * @IOCTL_SOCKET_POWER: Query current socket power consumption
>> + * @IOCTL_TA_BIN_VER: Query Trusted Application binary version
>> + *
>> + * These control codes are used with the IOCTL_PMF_POPULATE_DATA ioctl
>> + * to specify which metrics data to retrieve from the AMD PMF driver.
>> + */
>> +enum pmf_ioctl_id {
>> + IOCTL_POWER_SOURCE,
>> + IOCTL_POWER_SLIDER_POSITION,
>> + IOCTL_PLATFORM_TYPE,
>> + IOCTL_LAPTOP_PLACEMENT,
>> + IOCTL_LID_STATE,
>> + IOCTL_HETERO_STATE,
>> + IOCTL_SKIN_TEMP,
>> + IOCTL_USER_PRESENCE,
>> + IOCTL_DISPLAY_NUM,
>> + IOCTL_USER_ENGAGED,
>> + IOCTL_BIOS_INPUT_1,
>> + IOCTL_BIOS_INPUT_2,
>> + IOCTL_BIOS_INPUT_3,
>> + IOCTL_BIOS_INPUT_4,
>> + IOCTL_BIOS_INPUT_5,
>> + IOCTL_BIOS_INPUT_6,
>> + IOCTL_BIOS_INPUT_7,
>> + IOCTL_BIOS_INPUT_8,
>> + IOCTL_BIOS_INPUT_9,
>> + IOCTL_BIOS_INPUT_10,
>> + IOCTL_GFX_WORKLOAD,
>> + IOCTL_AMBIENT_LIGHT = 29,
>> + IOCTL_AVG_C0_RES = 36,
>> + IOCTL_MAX_C0_RES,
>> + IOCTL_SOCKET_POWER = 50,
>> + IOCTL_TA_BIN_VER
>> +};
>> +
>> +/**
>> + * struct amd_pmf_ioctl_info - Structure for PMF ioctl data exchange
>> + * @control_code: Input parameter specifying which data to query (enum pmf_ioctl_id)
>> + * @feature_supported: Output flag indicating if the queried feature is supported
>> + * @feature_version: Output field containing the feature version number
>> + * @val: Output field containing the queried value
>> + *
>> + * This structure is used with the IOCTL_PMF_POPULATE_DATA ioctl command
>> + * to exchange data between user space and the AMD PMF kernel driver.
>> + * The user provides the control_code to specify the query type, and the
>> + * driver populates the remaining fields with the response data.
>> + */
>> +struct amd_pmf_ioctl_info {
>> + int control_code; /* In */
>> + bool feature_supported; /* Out */
>> + unsigned long feature_version; /* Out */
>> + long long val; /* Out */
>
> I somehow seem to now recall that Hans suggested that the interface should
> be a struct which encodes many/all values...
>
> Yes, it seems so. This is what he said:
>
> https://lore.kernel.org/all/6104959e-0214-492d-8ceb-c7376d3b1121@kernel.org/
>
>
Double chekcing - You mean to say, I should move the enum members into
the amd_pmf_ioctl_info struct? i.e.
struct amd_pmf_ioctl_info {
/* Size field for versioning - must be first */
u64 size;
/* Version and feature info */
__u32 version;
__u32 features_supported;
__u32 features_enabled;
__u32 platform_type;
/* Power and state info */
__u32 power_source;
__u32 laptop_placement;
__u32 lid_state;
__u32 user_presence;
__u32 slider_position;
/* Thermal and power metrics */
__s32 skin_temp;
__u32 gfx_busy;
__s32 ambient_light;
__u32 avg_c0_residency;
__u32 max_c0_residency;
__u32 socket_power;
...
/* BIOS parameters */
__s64 bios_input[10];
__s64 bios_output[10];
...
/* Reserved for future expansion */
__u64 reserved[8];
};
Thanks,
Shyam
^ permalink raw reply [flat|nested] 30+ messages in thread
* Re: [PATCH v3 1/7] platform/x86/amd/pmf: Add util layer and userspace misc device interface
2026-03-30 12:12 ` Shyam Sundar S K
@ 2026-03-30 15:10 ` Ilpo Järvinen
0 siblings, 0 replies; 30+ messages in thread
From: Ilpo Järvinen @ 2026-03-30 15:10 UTC (permalink / raw)
To: Shyam Sundar S K
Cc: Hans de Goede, platform-driver-x86, mario.limonciello, Yijun.Shen,
Sanket.Goswami
[-- Attachment #1: Type: text/plain, Size: 17654 bytes --]
On Mon, 30 Mar 2026, Shyam Sundar S K wrote:
> Hi Ilpo,
>
> Ack to all the comments in the series.
>
> On 3/25/2026 19:35, Ilpo Järvinen wrote:
> > On Sun, 1 Mar 2026, Shyam Sundar S K wrote:
> >
> >> Add a util layer to AMD PMF that exposes a minimal userspace interface
> >> via a misc character device for metrics monitoring and feature discovery.
> >>
> >> This creates /dev/amdpmf_interface with basic ioctl support to retrieve
> >> PMF metrics such as:
> >> *Power source and power slider position
> >> *Platform type, lid state, and user presence
> >> *Skin temperature and ambient light
> >> *BIOS input parameters (1-10)
> >> *Graphics workload metrics
> >> *CPU C-state residency (average and maximum)
> >> *Socket power consumption
> >>
> >> The interface enables smoother integration with userspace tools such as
> >> AMD SystemDeck [1], which is widely used for monitoring and controlling
> >> power and thermal behavior on AMD platforms. These tools help designers
> >> keep major components within thermal limits to ensure proper operation
> >> and enhance overall system stability and reliability.
> >>
> >> The feature is gated behind the CONFIG_AMD_PMF_UTIL_SUPPORT Kconfig
> >> option, allowing it to be disabled if not needed. The implementation
> >> uses existing PMF infrastructure to populate data from the TA (Trusted
> >> Application) shared memory buffer.
> >>
> >> Link: https://docs.amd.com/v/u/en-US/68773_0.50 [1]
> >>
> >> Co-developed-by: Sanket Goswami <Sanket.Goswami@amd.com>
> >> Signed-off-by: Sanket Goswami <Sanket.Goswami@amd.com>
> >> Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> >> ---
> >> drivers/platform/x86/amd/pmf/Kconfig | 10 ++
> >> drivers/platform/x86/amd/pmf/Makefile | 2 +
> >> drivers/platform/x86/amd/pmf/core.c | 5 +
> >> drivers/platform/x86/amd/pmf/pmf.h | 9 ++
> >> drivers/platform/x86/amd/pmf/util.c | 174 ++++++++++++++++++++++++++
> >> include/uapi/linux/amd-pmf.h | 115 +++++++++++++++++
> >> 6 files changed, 315 insertions(+)
> >> create mode 100644 drivers/platform/x86/amd/pmf/util.c
> >> create mode 100644 include/uapi/linux/amd-pmf.h
> >>
> >> diff --git a/drivers/platform/x86/amd/pmf/Kconfig b/drivers/platform/x86/amd/pmf/Kconfig
> >> index 25b8f7ae3abd..ad21f679b8ab 100644
> >> --- a/drivers/platform/x86/amd/pmf/Kconfig
> >> +++ b/drivers/platform/x86/amd/pmf/Kconfig
> >> @@ -30,3 +30,13 @@ config AMD_PMF_DEBUG
> >> in the PMF config store.
> >>
> >> Say Y here to enable more debug logs and Say N here if you are not sure.
> >> +
> >> +config AMD_PMF_UTIL_SUPPORT
> >> + bool "AMD PMF Util layer support"
> >> + depends on AMD_PMF
> >> + help
> >> + Enabling this option provides a character device for userspace to capture
> >> + PMF features (Smart PC Builder, Auto Mode, Static Power Slider, Dynamic
> >> + Power Slider AC/DC) along with PMF metrics from the AMD PMF driver.
> >> +
> >> + Say Y here to enable it and Say N here if you are not sure.
> >> diff --git a/drivers/platform/x86/amd/pmf/Makefile b/drivers/platform/x86/amd/pmf/Makefile
> >> index 5978464e0eb7..bf7aad80b9e9 100644
> >> --- a/drivers/platform/x86/amd/pmf/Makefile
> >> +++ b/drivers/platform/x86/amd/pmf/Makefile
> >> @@ -8,3 +8,5 @@ obj-$(CONFIG_AMD_PMF) += amd-pmf.o
> >> amd-pmf-y := core.o acpi.o sps.o \
> >> auto-mode.o cnqf.o \
> >> tee-if.o spc.o
> >> +# Build util.c only when AMD_PMF_UTIL_SUPPORT is enabled
> >> +amd-pmf-$(CONFIG_AMD_PMF_UTIL_SUPPORT) += util.o
> >> diff --git a/drivers/platform/x86/amd/pmf/core.c b/drivers/platform/x86/amd/pmf/core.c
> >> index b9e5a2cf3aae..919d02f30aae 100644
> >> --- a/drivers/platform/x86/amd/pmf/core.c
> >> +++ b/drivers/platform/x86/amd/pmf/core.c
> >> @@ -634,6 +634,10 @@ static int amd_pmf_probe(struct platform_device *pdev)
> >>
> >> pmf_device = dev->dev;
> >>
> >> + err = amd_pmf_cdev_register(dev);
> >> + if (err)
> >> + dev_warn(dev->dev, "failed to register util interface: %d\n", err);
> >> +
> >> dev_info(dev->dev, "registered PMF device successfully\n");
> >>
> >> return 0;
> >> @@ -646,6 +650,7 @@ static void amd_pmf_remove(struct platform_device *pdev)
> >> amd_pmf_deinit_features(dev);
> >> if (is_apmf_func_supported(dev, APMF_FUNC_SBIOS_HEARTBEAT_V2))
> >> amd_pmf_notify_sbios_heartbeat_event_v2(dev, ON_UNLOAD);
> >> + amd_pmf_cdev_unregister();
> >> apmf_acpi_deinit(dev);
> >> amd_pmf_dbgfs_unregister(dev);
> >> }
> >> diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
> >> index 69fef7448744..6f61076a9386 100644
> >> --- a/drivers/platform/x86/amd/pmf/pmf.h
> >> +++ b/drivers/platform/x86/amd/pmf/pmf.h
> >> @@ -928,4 +928,13 @@ int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid);
> >> void amd_pmf_tee_deinit(struct amd_pmf_dev *dev);
> >> int amd_pmf_start_policy_engine(struct amd_pmf_dev *dev);
> >>
> >> +/* Util Layer */
> >> +#if IS_ENABLED(CONFIG_AMD_PMF_UTIL_SUPPORT)
> >> +int amd_pmf_cdev_register(struct amd_pmf_dev *dev);
> >> +void amd_pmf_cdev_unregister(void);
> >> +#else
> >> +static inline int amd_pmf_cdev_register(struct amd_pmf_dev *dev) { return 0; }
> >> +static inline void amd_pmf_cdev_unregister(void) {}
> >> +#endif
> >> +
> >> #endif /* PMF_H */
> >> diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
> >> new file mode 100644
> >> index 000000000000..c6837caa44e0
> >> --- /dev/null
> >> +++ b/drivers/platform/x86/amd/pmf/util.c
> >> @@ -0,0 +1,174 @@
> >> +// SPDX-License-Identifier: GPL-2.0-or-later
> >> +/*
> >> + * AMD Platform Management Framework Util Layer
> >> + *
> >> + * Copyright (c) 2026, Advanced Micro Devices, Inc.
> >> + * All Rights Reserved.
> >> + *
> >> + * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
> >> + * Sanket Goswami <Sanket.Goswami@amd.com>
> >> + */
> >> +
> >> +#include <linux/amd-pmf.h>
> >> +#include <linux/miscdevice.h>
> >> +#include <linux/mutex.h>
> >> +#include <linux/uaccess.h>
> >> +
> >> +#include "pmf.h"
> >> +
> >> +/* Convert BIOS input control code to array index (0-9) */
> >> +static int amd_pmf_get_bios_idx(u32 control_code)
> >> +{
> >> + if (control_code >= IOCTL_BIOS_INPUT_1 && control_code <= IOCTL_BIOS_INPUT_10)
> >> + return control_code - IOCTL_BIOS_INPUT_1;
> >> +
> >> + return -EINVAL;
> >> +}
> >> +
> >> +static long long amd_pmf_populate_bios_input(struct ta_pmf_enact_table *in, u32 control_code)
> >> +{
> >> + u32 idx;
> >> +
> >> + idx = amd_pmf_get_bios_idx(control_code);
> >> +
> >> + return (idx < 2) ? in->ev_info.bios_input_1[idx] : in->ev_info.bios_input_2[idx - 2];
> >> +}
> >> +
> >> +static long long amd_pmf_device_state(struct ta_pmf_enact_table *in, u32 control_code)
> >> +{
> >> + switch (control_code) {
> >> + case IOCTL_PLATFORM_TYPE:
> >> + return in->ev_info.platform_type;
> >> + case IOCTL_LAPTOP_PLACEMENT:
> >> + return in->ev_info.device_state;
> >> + case IOCTL_LID_STATE:
> >> + return in->ev_info.lid_state;
> >> + case IOCTL_USER_PRESENCE:
> >> + return in->ev_info.user_present;
> >> + default:
> >> + return -EINVAL;
> >> + }
> >> +}
> >> +
> >> +static int amd_pmf_populate_data(struct device *dev, void __user *argp)
> >> +{
> >> + struct amd_pmf_ioctl_info output = {0};
> >> + struct ta_pmf_shared_memory *ta_sm = NULL;
> >> + struct ta_pmf_enact_table *in = NULL;
> >> + struct amd_pmf_dev *pdev;
> >> +
> >> + pdev = dev_get_drvdata(dev);
> >> + if (!pdev)
> >> + return -EINVAL;
> >> +
> >> + memset(pdev->shbuf, 0, pdev->policy_sz);
> >> + ta_sm = pdev->shbuf;
> >> + in = &ta_sm->pmf_input.enact_table;
> >> +
> >> + if (copy_from_user(&output, argp, sizeof(output)))
> >> + return -EFAULT;
> >> +
> >> + switch (output.control_code) {
> >> + case IOCTL_POWER_SOURCE:
> >> + output.val = in->ev_info.power_source;
> >> + break;
> >> + case IOCTL_POWER_SLIDER_POSITION:
> >> + output.val = in->ev_info.power_slider;
> >> + break;
> >> + case IOCTL_SKIN_TEMP:
> >> + /* Convert from centi-degrees to degrees Celsius */
> >> + output.val = in->ev_info.skin_temperature / 100;
> >> + break;
> >> + case IOCTL_PLATFORM_TYPE ... IOCTL_LID_STATE:
> >> + case IOCTL_USER_PRESENCE:
> >> + output.val = amd_pmf_device_state(in, output.control_code);
> >> + break;
> >> + case IOCTL_BIOS_INPUT_1 ... IOCTL_BIOS_INPUT_10:
> >> + output.val = amd_pmf_populate_bios_input(in, output.control_code);
> >> + break;
> >> + case IOCTL_GFX_WORKLOAD:
> >> + output.val = in->ev_info.gfx_busy;
> >> + break;
> >> + case IOCTL_AMBIENT_LIGHT:
> >> + output.val = in->ev_info.ambient_light;
> >> + break;
> >> + case IOCTL_AVG_C0_RES:
> >> + output.val = in->ev_info.avg_c0residency;
> >> + break;
> >> + case IOCTL_MAX_C0_RES:
> >> + output.val = in->ev_info.max_c0residency;
> >> + break;
> >> + case IOCTL_SOCKET_POWER:
> >> + output.val = in->ev_info.socket_power;
> >> + break;
> >> + default:
> >> + return -EINVAL;
> >> + }
> >> +
> >> + if (copy_to_user(argp, &output, sizeof(output)))
> >> + return -EFAULT;
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +#if IS_ENABLED(CONFIG_AMD_PMF_UTIL_SUPPORT)
> >> +static struct amd_pmf_dev *pmf_dev_handle;
> >> +static DEFINE_MUTEX(pmf_util_lock);
> >> +
> >> +static long amd_pmf_set_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> >> +{
> >> + struct amd_pmf_dev *pdev = filp->private_data;
> >> + void __user *argp = (void __user *)arg;
> >> +
> >> + if (cmd != IOCTL_PMF_POPULATE_DATA)
> >> + return -EINVAL;
> >> +
> >> + guard(mutex)(&pmf_util_lock);
> >> + return amd_pmf_populate_data(pdev->dev, argp);
> >> +}
> >> +
> >> +static int amd_pmf_open(struct inode *inode, struct file *filp)
> >> +{
> >> + guard(mutex)(&pmf_util_lock);
> >> + if (!pmf_dev_handle)
> >> + return -ENODEV;
> >> +
> >> + filp->private_data = pmf_dev_handle;
> >> + return 0;
> >> +}
> >> +
> >> +static const struct file_operations pmf_if_ops = {
> >> + .owner = THIS_MODULE,
> >> + .open = amd_pmf_open,
> >> + .unlocked_ioctl = amd_pmf_set_ioctl,
> >> +};
> >> +
> >> +static struct miscdevice amd_pmf_util_if = {
> >> + .minor = MISC_DYNAMIC_MINOR,
> >> + .name = "amdpmf_interface",
> >> + .fops = &pmf_if_ops,
> >> +};
> >> +
> >> +int amd_pmf_cdev_register(struct amd_pmf_dev *dev)
> >> +{
> >> + int ret;
> >> +
> >> + guard(mutex)(&pmf_util_lock);
> >> + pmf_dev_handle = dev;
> >> + ret = misc_register(&amd_pmf_util_if);
> >> + if (ret)
> >> + pmf_dev_handle = NULL;
> >> +
> >> + return ret;
> >> +}
> >> +
> >> +void amd_pmf_cdev_unregister(void)
> >> +{
> >> + guard(mutex)(&pmf_util_lock);
> >> + pmf_dev_handle = NULL;
> >> + misc_deregister(&amd_pmf_util_if);
> >> +}
> >> +#else
> >> +int amd_pmf_cdev_register(struct amd_pmf_dev *dev) { return 0; }
> >> +void amd_pmf_cdev_unregister(void) {}
> >> +#endif
> >> diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
> >> new file mode 100644
> >> index 000000000000..d29431c67eaa
> >> --- /dev/null
> >> +++ b/include/uapi/linux/amd-pmf.h
> >> @@ -0,0 +1,115 @@
> >> +/* SPDX-License-Identifier: GPL-2.0-or-later WITH Linux-syscall-note */
> >> +/*
> >> + * AMD Platform Management Framework (PMF) UAPI Header
> >> + *
> >> + * Copyright (c) 2026, Advanced Micro Devices, Inc.
> >> + * All Rights Reserved.
> >> + *
> >> + * This file defines the user-space API for interacting with the AMD PMF
> >> + * driver. It provides ioctl interfaces to query platform-specific metrics
> >> + * such as power source, slider position, platform type, laptop placement,
> >> + * and various BIOS input/output parameters.
> >> + */
> >> +
> >> +#ifndef _UAPI_LINUX_AMD_PMF_H
> >> +#define _UAPI_LINUX_AMD_PMF_H
> >> +
> >> +#include <linux/ioctl.h>
> >> +#include <linux/types.h>
> >> +
> >> +/**
> >> + * AMD_PMF_IOC_MAGIC - Magic number for AMD PMF ioctl commands
> >> + *
> >> + * This magic number uniquely identifies AMD PMF ioctl operations.
> >> + */
> >> +#define AMD_PMF_IOC_MAGIC 'p'
> >> +
> >> +/**
> >> + * IOCTL_PMF_POPULATE_DATA - ioctl command to retrieve PMF metrics data
> >> + *
> >> + * This ioctl command is used to populate the amd_pmf_ioctl_info structure
> >> + * with the requested metrics data based on the control_code provided.
> >> + */
> >> +#define IOCTL_PMF_POPULATE_DATA _IOWR(AMD_PMF_IOC_MAGIC, 0x00, struct amd_pmf_ioctl_info)
> >> +
> >> +/**
> >> + * enum pmf_ioctl_id - Control codes for PMF ioctl operations
> >> + * @IOCTL_POWER_SOURCE: Query current power source (AC/DC)
> >> + * @IOCTL_POWER_SLIDER_POSITION: Query current power slider position
> >> + * @IOCTL_PLATFORM_TYPE: Query current platform/form factor type
> >> + * @IOCTL_LAPTOP_PLACEMENT: Query laptop physical placement state
> >> + * @IOCTL_LID_STATE: Query laptop lid open/close state
> >> + * @IOCTL_HETERO_STATE: Query heterogeneous computing state
> >> + * @IOCTL_SKIN_TEMP: Query skin temperature sensor reading
> >> + * @IOCTL_USER_PRESENCE: Query user presence detection state
> >> + * @IOCTL_DISPLAY_NUM: Query number of active displays
> >> + * @IOCTL_USER_ENGAGED: Query user engagement state
> >> + * @IOCTL_BIOS_INPUT_1: Query BIOS input parameter 1
> >> + * @IOCTL_BIOS_INPUT_2: Query BIOS input parameter 2
> >> + * @IOCTL_BIOS_INPUT_3: Query BIOS input parameter 3
> >> + * @IOCTL_BIOS_INPUT_4: Query BIOS input parameter 4
> >> + * @IOCTL_BIOS_INPUT_5: Query BIOS input parameter 5
> >> + * @IOCTL_BIOS_INPUT_6: Query BIOS input parameter 6
> >> + * @IOCTL_BIOS_INPUT_7: Query BIOS input parameter 7
> >> + * @IOCTL_BIOS_INPUT_8: Query BIOS input parameter 8
> >> + * @IOCTL_BIOS_INPUT_9: Query BIOS input parameter 9
> >> + * @IOCTL_BIOS_INPUT_10: Query BIOS input parameter 10
> >> + * @IOCTL_GFX_WORKLOAD: Query current graphics workload type
> >> + * @IOCTL_AMBIENT_LIGHT: Query ambient light sensor reading
> >> + * @IOCTL_AVG_C0_RES: Query average C0 residency
> >> + * @IOCTL_MAX_C0_RES: Query maximum C0 residency
> >> + * @IOCTL_SOCKET_POWER: Query current socket power consumption
> >> + * @IOCTL_TA_BIN_VER: Query Trusted Application binary version
> >> + *
> >> + * These control codes are used with the IOCTL_PMF_POPULATE_DATA ioctl
> >> + * to specify which metrics data to retrieve from the AMD PMF driver.
> >> + */
> >> +enum pmf_ioctl_id {
> >> + IOCTL_POWER_SOURCE,
> >> + IOCTL_POWER_SLIDER_POSITION,
> >> + IOCTL_PLATFORM_TYPE,
> >> + IOCTL_LAPTOP_PLACEMENT,
> >> + IOCTL_LID_STATE,
> >> + IOCTL_HETERO_STATE,
> >> + IOCTL_SKIN_TEMP,
> >> + IOCTL_USER_PRESENCE,
> >> + IOCTL_DISPLAY_NUM,
> >> + IOCTL_USER_ENGAGED,
> >> + IOCTL_BIOS_INPUT_1,
> >> + IOCTL_BIOS_INPUT_2,
> >> + IOCTL_BIOS_INPUT_3,
> >> + IOCTL_BIOS_INPUT_4,
> >> + IOCTL_BIOS_INPUT_5,
> >> + IOCTL_BIOS_INPUT_6,
> >> + IOCTL_BIOS_INPUT_7,
> >> + IOCTL_BIOS_INPUT_8,
> >> + IOCTL_BIOS_INPUT_9,
> >> + IOCTL_BIOS_INPUT_10,
> >> + IOCTL_GFX_WORKLOAD,
> >> + IOCTL_AMBIENT_LIGHT = 29,
> >> + IOCTL_AVG_C0_RES = 36,
> >> + IOCTL_MAX_C0_RES,
> >> + IOCTL_SOCKET_POWER = 50,
> >> + IOCTL_TA_BIN_VER
> >> +};
> >> +
> >> +/**
> >> + * struct amd_pmf_ioctl_info - Structure for PMF ioctl data exchange
> >> + * @control_code: Input parameter specifying which data to query (enum pmf_ioctl_id)
> >> + * @feature_supported: Output flag indicating if the queried feature is supported
> >> + * @feature_version: Output field containing the feature version number
> >> + * @val: Output field containing the queried value
> >> + *
> >> + * This structure is used with the IOCTL_PMF_POPULATE_DATA ioctl command
> >> + * to exchange data between user space and the AMD PMF kernel driver.
> >> + * The user provides the control_code to specify the query type, and the
> >> + * driver populates the remaining fields with the response data.
> >> + */
> >> +struct amd_pmf_ioctl_info {
> >> + int control_code; /* In */
> >> + bool feature_supported; /* Out */
> >> + unsigned long feature_version; /* Out */
> >> + long long val; /* Out */
> >
> > I somehow seem to now recall that Hans suggested that the interface should
> > be a struct which encodes many/all values...
> >
> > Yes, it seems so. This is what he said:
> >
> > https://lore.kernel.org/all/6104959e-0214-492d-8ceb-c7376d3b1121@kernel.org/
> >
> >
>
> Double chekcing - You mean to say, I should move the enum members into
> the amd_pmf_ioctl_info struct? i.e.
>
> struct amd_pmf_ioctl_info {
> /* Size field for versioning - must be first */
> u64 size;
>
> /* Version and feature info */
> __u32 version;
> __u32 features_supported;
> __u32 features_enabled;
> __u32 platform_type;
>
> /* Power and state info */
> __u32 power_source;
> __u32 laptop_placement;
> __u32 lid_state;
> __u32 user_presence;
> __u32 slider_position;
>
> /* Thermal and power metrics */
> __s32 skin_temp;
> __u32 gfx_busy;
> __s32 ambient_light;
> __u32 avg_c0_residency;
> __u32 max_c0_residency;
> __u32 socket_power;
>
> ...
>
> /* BIOS parameters */
> __s64 bios_input[10];
> __s64 bios_output[10];
>
> ...
>
> /* Reserved for future expansion */
> __u64 reserved[8];
> };
Yes, the point was that a result of the query covers more than one
value (all of them).
--
i.
^ permalink raw reply [flat|nested] 30+ messages in thread
end of thread, other threads:[~2026-03-30 15:10 UTC | newest]
Thread overview: 30+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-01 13:11 [PATCH v3 0/7] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
2026-03-01 13:11 ` [PATCH v3 1/7] platform/x86/amd/pmf: Add util layer and userspace misc device interface Shyam Sundar S K
2026-03-01 18:45 ` Randy Dunlap
2026-03-03 15:22 ` Shyam Sundar S K
2026-03-25 13:16 ` Ilpo Järvinen
2026-03-25 13:18 ` Ilpo Järvinen
2026-03-25 14:05 ` Ilpo Järvinen
2026-03-30 12:12 ` Shyam Sundar S K
2026-03-30 15:10 ` Ilpo Järvinen
2026-03-01 13:11 ` [PATCH v3 2/7] platform/x86/amd/pmf: cache BIOS output values for user-space metrics via util IOCTL Shyam Sundar S K
2026-03-25 14:08 ` Ilpo Järvinen
2026-03-01 13:11 ` [PATCH v3 3/7] platform/x86/amd/pmf: Add feature discovery support to util interface Shyam Sundar S K
2026-03-25 14:07 ` Ilpo Järvinen
2026-03-30 11:41 ` Shyam Sundar S K
2026-03-01 13:11 ` [PATCH v3 4/7] platform/x86/amd/pmf: Store commonly used enums in the header file Shyam Sundar S K
2026-03-25 13:34 ` Ilpo Järvinen
2026-03-01 13:11 ` [PATCH v3 5/7] platform/x86/amd/pmf: Move debug helper functions to UAPI header Shyam Sundar S K
2026-03-25 13:39 ` Ilpo Järvinen
2026-03-30 11:45 ` Shyam Sundar S K
2026-03-01 13:11 ` [PATCH v3 6/7] platform/x86/amd/pmf: Introduce AMD PMF testing tool for driver metrics and features Shyam Sundar S K
2026-03-25 13:54 ` Ilpo Järvinen
2026-03-25 15:07 ` Mario Limonciello
2026-03-26 10:20 ` Ilpo Järvinen
2026-03-30 11:42 ` Shyam Sundar S K
2026-03-01 13:11 ` [PATCH v3 7/7] Documentation/ABI: add testing entry for AMD PMF misc device interface Shyam Sundar S K
2026-03-25 13:58 ` Ilpo Järvinen
2026-03-25 15:08 ` Mario Limonciello
2026-03-26 10:14 ` Ilpo Järvinen
2026-03-02 19:36 ` [PATCH v3 0/7] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Mario Limonciello
2026-03-03 15:23 ` Shyam Sundar S K
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox