All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6 0/8] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface
@ 2026-05-27 14:01 Shyam Sundar S K
  2026-05-27 14:01 ` [PATCH v6 1/8] platform/x86/amd/pmf: Add util layer and userspace character device interface Shyam Sundar S K
                   ` (7 more replies)
  0 siblings, 8 replies; 17+ messages in thread
From: Shyam Sundar S K @ 2026-05-27 14:01 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, mario.limonciello, 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.

v6:
 - Guard misc_deregister() with pmf_dev_handle NULL check
 - Move amd_pmf_cdev_unregister() to top of amd_pmf_remove()
 - Fix bios_idx type from u32 to int and add negative-value bounds check
 - Add missing #include <linux/bits.h> to uapi/linux/amd-pmf.h
 - Rename amd_pmf_get_pt/lp/sp() to descriptive full names
 - Add missing enum entries in platform_type and slider_position helpers
 - Export amd_pmf_get_ta_custom_bios_inputs() for util layer use
 - Fix stale/incorrect entries in Documentation/ABI

v5:
 - Add actual ioctl implementation after all struct fields are defined
 - Move features_supported field just after size for early discovery
 - Add 8-byte alignment check for user_size to prevent odd-byte copies
 - Add AMD_PMF prefix to all UAPI enum names to avoid namespace collisions
 - Use size_t for loop variable instead of int with cast
 - Use ternary operator for checkbox output
 - Add empty line before Linux kernel headers
 - Refactor banner to const char * for cleaner formatting

v4:
 - Implement single amd_pmf_info structure which can cover all members.
 - Add amd_pmf prefix for enums/functions within the UAPI header.
 - Keep test-pmf tool outside of selftests directory.
 - Include necessary header files.
 - Address review comments received from Ilpo on v3.

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 (8):
  platform/x86/amd/pmf: Add util layer and userspace character device
    interface
  platform/x86/amd/pmf: store 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: Implement util layer ioctl handler
  platform/x86/amd/pmf: Introduce AMD PMF testing tool for driver
    metrics and features
  Documentation/ABI: add testing entry for AMD PMF character device
    interface

 Documentation/ABI/testing/amdpmf-interface    |  73 +++++++
 MAINTAINERS                                   |   1 +
 .../amd-sfh-hid/sfh1_1/amd_sfh_interface.c    |  13 +-
 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            |  34 ++-
 drivers/platform/x86/amd/pmf/spc.c            |  72 +------
 drivers/platform/x86/amd/pmf/tee-if.c         |  13 +-
 drivers/platform/x86/amd/pmf/util.c           | 171 +++++++++++++++
 include/linux/amd-pmf-io.h                    |   9 -
 include/uapi/linux/amd-pmf.h                  | 204 ++++++++++++++++++
 tools/platform/x86/amd/Makefile               |  60 ++++++
 tools/platform/x86/amd/test-pmf.c             | 142 ++++++++++++
 14 files changed, 709 insertions(+), 100 deletions(-)
 create mode 100644 Documentation/ABI/testing/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/platform/x86/amd/Makefile
 create mode 100644 tools/platform/x86/amd/test-pmf.c

-- 
2.34.1


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v6 1/8] platform/x86/amd/pmf: Add util layer and userspace character device interface
  2026-05-27 14:01 [PATCH v6 0/8] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
@ 2026-05-27 14:01 ` Shyam Sundar S K
  2026-06-08  9:36   ` Hans de Goede
  2026-05-27 14:01 ` [PATCH v6 2/8] platform/x86/amd/pmf: store BIOS output values for user-space metrics via util IOCTL Shyam Sundar S K
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Shyam Sundar S K @ 2026-05-27 14:01 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, mario.limonciello, Sanket.Goswami,
	Shyam Sundar S K

Add a util layer to AMD PMF that exposes a minimal userspace interface
via a 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   | 68 +++++++++++++++++++++++++++
 include/uapi/linux/amd-pmf.h          | 60 +++++++++++++++++++++++
 6 files changed, 154 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..ad4faf18de47 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..58d86b4c2828 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;
@@ -643,6 +647,7 @@ static void amd_pmf_remove(struct platform_device *pdev)
 {
 	struct amd_pmf_dev *dev = platform_get_drvdata(pdev);
 
+	amd_pmf_cdev_unregister();
 	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);
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..f8a283192ffe
--- /dev/null
+++ b/drivers/platform/x86/amd/pmf/util.c
@@ -0,0 +1,68 @@
+// 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"
+
+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)
+{
+	return -ENOTTY;
+}
+
+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);
+	if (pmf_dev_handle)
+		misc_deregister(&amd_pmf_util_if);
+	pmf_dev_handle = NULL;
+}
diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
new file mode 100644
index 000000000000..c7099e7f463f
--- /dev/null
+++ b/include/uapi/linux/amd-pmf.h
@@ -0,0 +1,60 @@
+/* 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_AMD_PMF_POPULATE_DATA - ioctl command to retrieve PMF metrics data
+ *
+ * This ioctl command is used to populate the amd_pmf_info structure
+ * with the requested PMF metrics information.
+ */
+#define IOCTL_AMD_PMF_POPULATE_DATA		_IOWR(AMD_PMF_IOC_MAGIC, 0x00, struct amd_pmf_info)
+
+#define AMD_PMF_BIOS_PARAMS_MAX		10
+
+struct amd_pmf_info {
+	__u64 size;
+
+	/* Power and state info */
+	__u32 platform_type;
+	__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 */
+	__u32 bios_input[AMD_PMF_BIOS_PARAMS_MAX];
+};
+
+#endif /* _UAPI_LINUX_AMD_PMF_H */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v6 2/8] platform/x86/amd/pmf: store BIOS output values for user-space metrics via util IOCTL
  2026-05-27 14:01 [PATCH v6 0/8] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
  2026-05-27 14:01 ` [PATCH v6 1/8] platform/x86/amd/pmf: Add util layer and userspace character device interface Shyam Sundar S K
@ 2026-05-27 14:01 ` Shyam Sundar S K
  2026-05-27 14:02 ` [PATCH v6 3/8] platform/x86/amd/pmf: Add feature discovery support to util interface Shyam Sundar S K
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 17+ messages in thread
From: Shyam Sundar S K @ 2026-05-27 14:01 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, mario.limonciello, Sanket.Goswami,
	Shyam Sundar S K

Add a bios_output[] to amd_pmf_dev struct 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.

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/pmf.h    |  2 ++
 drivers/platform/x86/amd/pmf/tee-if.c | 13 +++++++++++--
 include/uapi/linux/amd-pmf.h          |  1 +
 3 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
index 6f61076a9386..ffe74ebc46f8 100644
--- a/drivers/platform/x86/amd/pmf/pmf.h
+++ b/drivers/platform/x86/amd/pmf/pmf.h
@@ -130,6 +130,7 @@ struct cookie_header {
 #define GET_CMD		true
 
 #define METRICS_TABLE_ID	7
+#define BIOS_OUTPUT_MAX		10
 
 typedef void (*apmf_event_handler_t)(acpi_handle handle, u32 event, void *data);
 
@@ -442,6 +443,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[BIOS_OUTPUT_MAX];
 };
 
 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..3fe79f0f37c5 100644
--- a/drivers/platform/x86/amd/pmf/tee-if.c
+++ b/drivers/platform/x86/amd/pmf/tee-if.c
@@ -8,7 +8,9 @@
  * Author: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
  */
 
+#include <linux/array_size.h>
 #include <linux/debugfs.h>
+#include <linux/dev_printk.h>
 #include <linux/tee_drv.h>
 #include <linux/uuid.h>
 #include "pmf.h"
@@ -97,11 +99,18 @@ 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 bios_idx;
+	int ret;
 
 	bios_idx = amd_pmf_get_bios_output_idx(action->action_index);
+	if (bios_idx < 0 || bios_idx >= ARRAY_SIZE(pdev->bios_output)) {
+		dev_warn(pdev->dev, "BIOS output index %d 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/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
index c7099e7f463f..d29a4abe1145 100644
--- a/include/uapi/linux/amd-pmf.h
+++ b/include/uapi/linux/amd-pmf.h
@@ -55,6 +55,7 @@ struct amd_pmf_info {
 
 	/* BIOS parameters */
 	__u32 bios_input[AMD_PMF_BIOS_PARAMS_MAX];
+	__u32 bios_output[AMD_PMF_BIOS_PARAMS_MAX];
 };
 
 #endif /* _UAPI_LINUX_AMD_PMF_H */
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v6 3/8] platform/x86/amd/pmf: Add feature discovery support to util interface
  2026-05-27 14:01 [PATCH v6 0/8] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
  2026-05-27 14:01 ` [PATCH v6 1/8] platform/x86/amd/pmf: Add util layer and userspace character device interface Shyam Sundar S K
  2026-05-27 14:01 ` [PATCH v6 2/8] platform/x86/amd/pmf: store BIOS output values for user-space metrics via util IOCTL Shyam Sundar S K
@ 2026-05-27 14:02 ` Shyam Sundar S K
  2026-06-08  9:24   ` Hans de Goede
  2026-05-27 14:02 ` [PATCH v6 4/8] platform/x86/amd/pmf: Store commonly used enums in the header file Shyam Sundar S K
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 17+ messages in thread
From: Shyam Sundar S K @ 2026-05-27 14:02 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, mario.limonciello, 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>
---
 include/uapi/linux/amd-pmf.h | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
index d29a4abe1145..9de054cfeee7 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/bits.h>
 #include <linux/ioctl.h>
 #include <linux/types.h>
 
@@ -34,9 +35,19 @@
 
 #define AMD_PMF_BIOS_PARAMS_MAX		10
 
+/* AMD PMF feature flags - bitmask indicating supported features */
+#define AMD_PMF_FEAT_AUTO_MODE			BIT(0)
+#define AMD_PMF_FEAT_STATIC_POWER_SLIDER	BIT(1)
+#define AMD_PMF_FEAT_POLICY_BUILDER		BIT(2)
+#define AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_AC	BIT(3)
+#define AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_DC	BIT(4)
+
 struct amd_pmf_info {
 	__u64 size;
 
+	/* Feature info */
+	__u32 features_supported;
+
 	/* Power and state info */
 	__u32 platform_type;
 	__u32 power_source;
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v6 4/8] platform/x86/amd/pmf: Store commonly used enums in the header file
  2026-05-27 14:01 [PATCH v6 0/8] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
                   ` (2 preceding siblings ...)
  2026-05-27 14:02 ` [PATCH v6 3/8] platform/x86/amd/pmf: Add feature discovery support to util interface Shyam Sundar S K
@ 2026-05-27 14:02 ` Shyam Sundar S K
  2026-05-27 14:02 ` [PATCH v6 5/8] platform/x86/amd/pmf: Move debug helper functions to UAPI header Shyam Sundar S K
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 17+ messages in thread
From: Shyam Sundar S K @ 2026-05-27 14:02 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, mario.limonciello, 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.

Add the AMD_PMF_ prefix to the laptop_placement and platform_type enums
since these names are overly generic for inclusion in a UAPI header

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    | 13 ++--
 drivers/platform/x86/amd/pmf/pmf.h            | 22 ------
 drivers/platform/x86/amd/pmf/spc.c            | 37 +++++-----
 include/linux/amd-pmf-io.h                    |  9 ---
 include/uapi/linux/amd-pmf.h                  | 74 +++++++++++++++++++
 5 files changed, 100 insertions(+), 55 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..8ac44368a37d 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>
@@ -102,20 +103,20 @@ static int amd_sfh_mode_info(u32 *platform_type, u32 *laptop_placement)
 	*platform_type = mode.op_mode.devicemode;
 
 	if (mode.op_mode.ontablestate == 1) {
-		*laptop_placement = ON_TABLE;
+		*laptop_placement = AMD_PMF_ON_TABLE;
 	} else if (mode.op_mode.ontablestate == 2) {
-		*laptop_placement = ON_LAP_MOTION;
+		*laptop_placement = AMD_PMF_ON_LAP_MOTION;
 	} else if (mode.op_mode.inbagstate == 1) {
-		*laptop_placement = IN_BAG;
+		*laptop_placement = AMD_PMF_IN_BAG;
 	} else if (mode.op_mode.outbagstate == 1) {
-		*laptop_placement = OUT_OF_BAG;
+		*laptop_placement = AMD_PMF_OUT_OF_BAG;
 	} else if (mode.op_mode.ontablestate == 0 || mode.op_mode.inbagstate == 0 ||
 		 mode.op_mode.outbagstate == 0) {
-		*laptop_placement = LP_UNKNOWN;
+		*laptop_placement = AMD_PMF_LP_UNKNOWN;
 		pr_warn_once("Unknown laptop placement\n");
 	} else if (mode.op_mode.ontablestate == 3 || mode.op_mode.inbagstate == 3 ||
 		 mode.op_mode.outbagstate == 3) {
-		*laptop_placement = LP_UNDEFINED;
+		*laptop_placement = AMD_PMF_LP_UNDEFINED;
 		pr_warn_once("Undefined laptop placement\n");
 	}
 
diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
index ffe74ebc46f8..269c0a4b1cae 100644
--- a/drivers/platform/x86/amd/pmf/pmf.h
+++ b/drivers/platform/x86/amd/pmf/pmf.h
@@ -682,14 +682,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;
@@ -721,20 +713,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..05998946d1bd 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>
@@ -20,21 +21,21 @@
 static const char *platform_type_as_str(u16 platform_type)
 {
 	switch (platform_type) {
-	case CLAMSHELL:
+	case AMD_PMF_CLAMSHELL:
 		return "CLAMSHELL";
-	case FLAT:
+	case AMD_PMF_FLAT:
 		return "FLAT";
-	case TENT:
+	case AMD_PMF_TENT:
 		return "TENT";
-	case STAND:
+	case AMD_PMF_STAND:
 		return "STAND";
-	case TABLET:
+	case AMD_PMF_TABLET:
 		return "TABLET";
-	case BOOK:
+	case AMD_PMF_BOOK:
 		return "BOOK";
-	case PRESENTATION:
+	case AMD_PMF_PRESENTATION:
 		return "PRESENTATION";
-	case PULL_FWD:
+	case AMD_PMF_PULL_FWD:
 		return "PULL_FWD";
 	default:
 		return "UNKNOWN";
@@ -44,13 +45,13 @@ static const char *platform_type_as_str(u16 platform_type)
 static const char *laptop_placement_as_str(u16 device_state)
 {
 	switch (device_state) {
-	case ON_TABLE:
+	case AMD_PMF_ON_TABLE:
 		return "ON_TABLE";
-	case ON_LAP_MOTION:
+	case AMD_PMF_ON_LAP_MOTION:
 		return "ON_LAP_MOTION";
-	case IN_BAG:
+	case AMD_PMF_IN_BAG:
 		return "IN_BAG";
-	case OUT_OF_BAG:
+	case AMD_PMF_OUT_OF_BAG:
 		return "OUT_OF_BAG";
 	default:
 		return "UNKNOWN";
@@ -60,11 +61,11 @@ static const char *laptop_placement_as_str(u16 device_state)
 static const char *ta_slider_as_str(unsigned int state)
 {
 	switch (state) {
-	case TA_BEST_PERFORMANCE:
+	case AMD_PMF_TA_BEST_PERFORMANCE:
 		return "PERFORMANCE";
-	case TA_BETTER_PERFORMANCE:
+	case AMD_PMF_TA_BETTER_PERFORMANCE:
 		return "BALANCED";
-	case TA_BEST_BATTERY:
+	case AMD_PMF_TA_BEST_BATTERY:
 		return "POWER_SAVER";
 	default:
 		return "Unknown TA Slider State";
@@ -287,14 +288,14 @@ static int amd_pmf_get_slider_info(struct amd_pmf_dev *dev, struct ta_pmf_enact_
 	switch (dev->current_profile) {
 	case PLATFORM_PROFILE_PERFORMANCE:
 	case PLATFORM_PROFILE_BALANCED_PERFORMANCE:
-		val = TA_BEST_PERFORMANCE;
+		val = AMD_PMF_TA_BEST_PERFORMANCE;
 		break;
 	case PLATFORM_PROFILE_BALANCED:
-		val = TA_BETTER_PERFORMANCE;
+		val = AMD_PMF_TA_BETTER_PERFORMANCE;
 		break;
 	case PLATFORM_PROFILE_LOW_POWER:
 	case PLATFORM_PROFILE_QUIET:
-		val = TA_BEST_BATTERY;
+		val = AMD_PMF_TA_BEST_BATTERY;
 		break;
 	default:
 		dev_err(dev->dev, "Unknown Platform Profile.\n");
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 9de054cfeee7..c0bd818c0dab 100644
--- a/include/uapi/linux/amd-pmf.h
+++ b/include/uapi/linux/amd-pmf.h
@@ -42,6 +42,80 @@
 #define AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_AC	BIT(3)
 #define AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_DC	BIT(4)
 
+/**
+ * enum amd_pmf_laptop_placement - Describes the physical placement of the laptop
+ * @AMD_PMF_LP_UNKNOWN: Placement cannot be determined
+ * @AMD_PMF_ON_TABLE: Laptop is placed on a stable surface like a table or desk
+ * @AMD_PMF_ON_LAP_MOTION: Laptop is on a lap with detected motion
+ * @AMD_PMF_IN_BAG: Laptop is detected to be inside a bag or case
+ * @AMD_PMF_OUT_OF_BAG: Laptop has been removed from bag or case
+ * @AMD_PMF_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 amd_pmf_laptop_placement {
+	AMD_PMF_LP_UNKNOWN,
+	AMD_PMF_ON_TABLE,
+	AMD_PMF_ON_LAP_MOTION,
+	AMD_PMF_IN_BAG,
+	AMD_PMF_OUT_OF_BAG,
+	AMD_PMF_LP_UNDEFINED,
+};
+
+/**
+ * enum amd_pmf_ta_slider - Trusted Application power slider positions
+ * @AMD_PMF_TA_BEST_BATTERY: Maximum battery savings, minimal performance
+ * @AMD_PMF_TA_BETTER_BATTERY: Balanced towards battery life
+ * @AMD_PMF_TA_BETTER_PERFORMANCE: Balanced towards performance
+ * @AMD_PMF_TA_BEST_PERFORMANCE: Maximum performance, higher power consumption
+ * @AMD_PMF_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 amd_pmf_ta_slider {
+	AMD_PMF_TA_BEST_BATTERY,
+	AMD_PMF_TA_BETTER_BATTERY,
+	AMD_PMF_TA_BETTER_PERFORMANCE,
+	AMD_PMF_TA_BEST_PERFORMANCE,
+	AMD_PMF_TA_MAX,
+};
+
+/**
+ * enum amd_pmf_platform_type - Describes the physical form factor orientation
+ * @AMD_PMF_PTYPE_UNKNOWN: Platform type cannot be determined
+ * @AMD_PMF_LID_CLOSE: Laptop lid is closed
+ * @AMD_PMF_CLAMSHELL: Traditional laptop mode with keyboard and screen
+ * @AMD_PMF_FLAT: Device is lying flat on a surface
+ * @AMD_PMF_TENT: Device is in tent mode (keyboard folded back, standing)
+ * @AMD_PMF_STAND: Device is propped up in stand orientation
+ * @AMD_PMF_TABLET: Device is in tablet mode with keyboard hidden
+ * @AMD_PMF_BOOK: Device is in book reading orientation
+ * @AMD_PMF_PRESENTATION: Device is in presentation mode
+ * @AMD_PMF_PULL_FWD: Screen is pulled forward towards user
+ * @AMD_PMF_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 amd_pmf_platform_type {
+	AMD_PMF_PTYPE_UNKNOWN,
+	AMD_PMF_LID_CLOSE,
+	AMD_PMF_CLAMSHELL,
+	AMD_PMF_FLAT,
+	AMD_PMF_TENT,
+	AMD_PMF_STAND,
+	AMD_PMF_TABLET,
+	AMD_PMF_BOOK,
+	AMD_PMF_PRESENTATION,
+	AMD_PMF_PULL_FWD,
+	AMD_PMF_PTYPE_INVALID = 0xf,
+};
+
 struct amd_pmf_info {
 	__u64 size;
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v6 5/8] platform/x86/amd/pmf: Move debug helper functions to UAPI header
  2026-05-27 14:01 [PATCH v6 0/8] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
                   ` (3 preceding siblings ...)
  2026-05-27 14:02 ` [PATCH v6 4/8] platform/x86/amd/pmf: Store commonly used enums in the header file Shyam Sundar S K
@ 2026-05-27 14:02 ` Shyam Sundar S K
  2026-05-27 14:02 ` [PATCH v6 6/8] platform/x86/amd/pmf: Implement util layer ioctl handler Shyam Sundar S K
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 17+ messages in thread
From: Shyam Sundar S K @ 2026-05-27 14:02 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, mario.limonciello, 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. Also, prefix the
function names with amd_pmf_.

Also, include a case to cover unused enum entries.

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 | 62 +++---------------------------
 include/uapi/linux/amd-pmf.h       | 58 ++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+), 57 deletions(-)

diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c
index 05998946d1bd..6e33824ccadc 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 AMD_PMF_CLAMSHELL:
-		return "CLAMSHELL";
-	case AMD_PMF_FLAT:
-		return "FLAT";
-	case AMD_PMF_TENT:
-		return "TENT";
-	case AMD_PMF_STAND:
-		return "STAND";
-	case AMD_PMF_TABLET:
-		return "TABLET";
-	case AMD_PMF_BOOK:
-		return "BOOK";
-	case AMD_PMF_PRESENTATION:
-		return "PRESENTATION";
-	case AMD_PMF_PULL_FWD:
-		return "PULL_FWD";
-	default:
-		return "UNKNOWN";
-	}
-}
-
-static const char *laptop_placement_as_str(u16 device_state)
-{
-	switch (device_state) {
-	case AMD_PMF_ON_TABLE:
-		return "ON_TABLE";
-	case AMD_PMF_ON_LAP_MOTION:
-		return "ON_LAP_MOTION";
-	case AMD_PMF_IN_BAG:
-		return "IN_BAG";
-	case AMD_PMF_OUT_OF_BAG:
-		return "OUT_OF_BAG";
-	default:
-		return "UNKNOWN";
-	}
-}
-
-static const char *ta_slider_as_str(unsigned int state)
-{
-	switch (state) {
-	case AMD_PMF_TA_BEST_PERFORMANCE:
-		return "PERFORMANCE";
-	case AMD_PMF_TA_BETTER_PERFORMANCE:
-		return "BALANCED";
-	case AMD_PMF_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) {
@@ -89,7 +35,8 @@ void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *
 	int i;
 
 	dev_dbg(dev->dev, "==== TA inputs START ====\n");
-	dev_dbg(dev->dev, "Slider State: %s\n", ta_slider_as_str(in->ev_info.power_slider));
+	dev_dbg(dev->dev, "Slider State: %s\n",
+		amd_pmf_get_slider_position(in->ev_info.power_slider));
 	dev_dbg(dev->dev, "Power Source: %s\n", amd_pmf_source_as_str(in->ev_info.power_source));
 	dev_dbg(dev->dev, "Battery Percentage: %u\n", in->ev_info.bat_percentage);
 	dev_dbg(dev->dev, "Designed Battery Capacity: %u\n", in->ev_info.bat_design);
@@ -103,9 +50,10 @@ void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *
 	dev_dbg(dev->dev, "LID State: %s\n", in->ev_info.lid_state ? "close" : "open");
 	dev_dbg(dev->dev, "User Presence: %s\n", in->ev_info.user_present ? "Present" : "Away");
 	dev_dbg(dev->dev, "Ambient Light: %d\n", in->ev_info.ambient_light);
-	dev_dbg(dev->dev, "Platform type: %s\n", platform_type_as_str(in->ev_info.platform_type));
+	dev_dbg(dev->dev, "Platform type: %s\n",
+		amd_pmf_get_platform_type(in->ev_info.platform_type));
 	dev_dbg(dev->dev, "Laptop placement: %s\n",
-		laptop_placement_as_str(in->ev_info.device_state));
+		amd_pmf_get_laptop_placement(in->ev_info.device_state));
 	for (i = 0; i < ARRAY_SIZE(custom_bios_inputs); i++)
 		dev_dbg(dev->dev, "Custom BIOS input%d: %u\n", i + 1,
 			amd_pmf_get_ta_custom_bios_inputs(in, i));
diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
index c0bd818c0dab..9fc0f71f7bb4 100644
--- a/include/uapi/linux/amd-pmf.h
+++ b/include/uapi/linux/amd-pmf.h
@@ -116,6 +116,64 @@ enum amd_pmf_platform_type {
 	AMD_PMF_PTYPE_INVALID = 0xf,
 };
 
+static inline const char *amd_pmf_get_platform_type(unsigned int platform_type)
+{
+	switch (platform_type) {
+	case AMD_PMF_CLAMSHELL:
+		return "CLAMSHELL";
+	case AMD_PMF_LID_CLOSE:
+		return "LID_CLOSE";
+	case AMD_PMF_FLAT:
+		return "FLAT";
+	case AMD_PMF_TENT:
+		return "TENT";
+	case AMD_PMF_STAND:
+		return "STAND";
+	case AMD_PMF_TABLET:
+		return "TABLET";
+	case AMD_PMF_BOOK:
+		return "BOOK";
+	case AMD_PMF_PRESENTATION:
+		return "PRESENTATION";
+	case AMD_PMF_PULL_FWD:
+		return "PULL_FWD";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static inline const char *amd_pmf_get_laptop_placement(unsigned int device_state)
+{
+	switch (device_state) {
+	case AMD_PMF_ON_TABLE:
+		return "ON_TABLE";
+	case AMD_PMF_ON_LAP_MOTION:
+		return "ON_LAP_MOTION";
+	case AMD_PMF_IN_BAG:
+		return "IN_BAG";
+	case AMD_PMF_OUT_OF_BAG:
+		return "OUT_OF_BAG";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+static inline const char *amd_pmf_get_slider_position(unsigned int state)
+{
+	switch (state) {
+	case AMD_PMF_TA_BEST_PERFORMANCE:
+		return "PERFORMANCE";
+	case AMD_PMF_TA_BETTER_PERFORMANCE:
+		return "BALANCED_PERFORMANCE";
+	case AMD_PMF_TA_BEST_BATTERY:
+		return "POWER_SAVER";
+	case AMD_PMF_TA_BETTER_BATTERY:
+		return "BALANCED_BATTERY";
+	default:
+		return "Unknown TA Slider State";
+	}
+}
+
 struct amd_pmf_info {
 	__u64 size;
 
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v6 6/8] platform/x86/amd/pmf: Implement util layer ioctl handler
  2026-05-27 14:01 [PATCH v6 0/8] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
                   ` (4 preceding siblings ...)
  2026-05-27 14:02 ` [PATCH v6 5/8] platform/x86/amd/pmf: Move debug helper functions to UAPI header Shyam Sundar S K
@ 2026-05-27 14:02 ` Shyam Sundar S K
  2026-06-08  9:32   ` Hans de Goede
  2026-05-27 14:02 ` [PATCH v6 7/8] platform/x86/amd/pmf: Introduce AMD PMF testing tool for driver metrics and features Shyam Sundar S K
  2026-05-27 14:02 ` [PATCH v6 8/8] Documentation/ABI: add testing entry for AMD PMF character device interface Shyam Sundar S K
  7 siblings, 1 reply; 17+ messages in thread
From: Shyam Sundar S K @ 2026-05-27 14:02 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, mario.limonciello, Sanket.Goswami,
	Shyam Sundar S K

Implement the ioctl handler for the util layer character device. This
support adds the actual functionality to populate PMF metrics from the
TA shared memory buffer and return them to userspace.

The implementation includes:
- amd_pmf_populate_data() to extract metrics from TA shared memory
- amd_pmf_set_ioctl() to handle userspace ioctl requests
- Size negotiation for forward/backward compatibility
- Feature-based population of struct fields
- Export amd_pmf_get_ta_custom_bios_inputs()

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/pmf.h  |   1 +
 drivers/platform/x86/amd/pmf/spc.c  |   3 +-
 drivers/platform/x86/amd/pmf/util.c | 105 +++++++++++++++++++++++++++-
 3 files changed, 107 insertions(+), 2 deletions(-)

diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
index 269c0a4b1cae..752fa5dd2267 100644
--- a/drivers/platform/x86/amd/pmf/pmf.h
+++ b/drivers/platform/x86/amd/pmf/pmf.h
@@ -903,6 +903,7 @@ int amd_pmf_smartpc_apply_bios_output(struct amd_pmf_dev *dev, u32 val, u32 preq
 void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in);
 void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in);
 int amd_pmf_invoke_cmd_enact(struct amd_pmf_dev *dev);
+u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index);
 
 int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid);
 void amd_pmf_tee_deinit(struct amd_pmf_dev *dev);
diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c
index 6e33824ccadc..94355b435a66 100644
--- a/drivers/platform/x86/amd/pmf/spc.c
+++ b/drivers/platform/x86/amd/pmf/spc.c
@@ -18,7 +18,7 @@
 #include "pmf.h"
 
 #ifdef CONFIG_AMD_PMF_DEBUG
-static u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index)
+u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index)
 {
 	switch (index) {
 	case 0 ... 1:
@@ -29,6 +29,7 @@ static u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int
 		return 0;
 	}
 }
+EXPORT_SYMBOL(amd_pmf_get_ta_custom_bios_inputs);
 
 void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
 {
diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
index f8a283192ffe..30fb5c250362 100644
--- a/drivers/platform/x86/amd/pmf/util.c
+++ b/drivers/platform/x86/amd/pmf/util.c
@@ -9,6 +9,7 @@
  *	    Sanket Goswami <Sanket.Goswami@amd.com>
  */
 
+#include <linux/align.h>
 #include <linux/amd-pmf.h>
 #include <linux/miscdevice.h>
 #include <linux/mutex.h>
@@ -19,9 +20,111 @@
 static struct amd_pmf_dev *pmf_dev_handle;
 static DEFINE_MUTEX(pmf_util_lock);
 
+static int amd_pmf_populate_data(struct amd_pmf_dev *pdev, struct amd_pmf_info *info)
+{
+	struct ta_pmf_shared_memory *ta_sm = NULL;
+	struct ta_pmf_enact_table *in = NULL;
+	int idx;
+
+	if (!pdev || !info)
+		return -EINVAL;
+
+	if (!pdev->shbuf)
+		return -EINVAL;
+
+	ta_sm = pdev->shbuf;
+	in = &ta_sm->pmf_input.enact_table;
+
+	/* Set size */
+	info->size = sizeof(*info);
+
+	/* PMF Feature support flags */
+	if (is_apmf_func_supported(pdev, APMF_FUNC_AUTO_MODE))
+		info->features_supported |= AMD_PMF_FEAT_AUTO_MODE;
+	if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR))
+		info->features_supported |= AMD_PMF_FEAT_STATIC_POWER_SLIDER;
+	if (pdev->smart_pc_enabled)
+		info->features_supported |= AMD_PMF_FEAT_POLICY_BUILDER;
+	if (is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_AC))
+		info->features_supported |= AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_AC;
+	if (is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_DC))
+		info->features_supported |= AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_DC;
+
+	/* Device States */
+	info->platform_type = in->ev_info.platform_type;
+	info->laptop_placement = in->ev_info.device_state;
+	info->lid_state = in->ev_info.lid_state;
+	info->user_presence = in->ev_info.user_present;
+	info->slider_position = in->ev_info.power_slider;
+
+	/* Thermal and Power Metrics */
+	info->power_source = in->ev_info.power_source;
+	info->skin_temp = in->ev_info.skin_temperature;
+	info->gfx_busy = in->ev_info.gfx_busy;
+	info->ambient_light = in->ev_info.ambient_light;
+	info->avg_c0_residency = in->ev_info.avg_c0residency;
+	info->max_c0_residency = in->ev_info.max_c0residency;
+	info->socket_power = in->ev_info.socket_power;
+
+	/* Custom BIOS input parameters */
+	for (idx = 0; idx < AMD_PMF_BIOS_PARAMS_MAX; idx++)
+		info->bios_input[idx] = amd_pmf_get_ta_custom_bios_inputs(in, idx);
+
+	/* BIOS output parameters */
+	for (idx = 0; idx < AMD_PMF_BIOS_PARAMS_MAX; idx++)
+		info->bios_output[idx] = pdev->bios_output[idx];
+
+	return 0;
+}
+
 static long amd_pmf_set_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
-	return -ENOTTY;
+	struct amd_pmf_dev *pdev = filp->private_data;
+	void __user *argp = (void __user *)arg;
+	struct amd_pmf_info info = {};
+	size_t copy_size;
+	__u64 user_size;
+	int ret;
+
+	if (cmd != IOCTL_AMD_PMF_POPULATE_DATA)
+		return -ENOTTY;
+
+	/* First read just the size field from userspace */
+	if (copy_from_user(&user_size, argp, sizeof(user_size)))
+		return -EFAULT;
+
+	if (user_size > sizeof(info))
+		return -EINVAL;
+
+	if (!IS_ALIGNED(user_size, sizeof(__u64)))
+		return -EINVAL;
+
+	if (user_size > sizeof(__u64)) {
+		__u32 features_from_user = 0;
+
+		if (copy_from_user(&features_from_user, argp + offsetof(struct
+		    amd_pmf_info, features_supported), sizeof(features_from_user)))
+			return -EFAULT;
+
+		/* Reject non-zero values now */
+		if (features_from_user != 0)
+			return -EINVAL;
+	}
+
+	guard(mutex)(&pmf_util_lock);
+	ret = amd_pmf_populate_data(pdev, &info);
+	if (ret)
+		return ret;
+
+	copy_size = min_t(size_t, user_size, sizeof(info));
+
+	/* Set actual size being copied */
+	info.size = copy_size;
+
+	if (copy_to_user(argp, &info, copy_size))
+		return -EFAULT;
+
+	return 0;
 }
 
 static int amd_pmf_open(struct inode *inode, struct file *filp)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v6 7/8] platform/x86/amd/pmf: Introduce AMD PMF testing tool for driver metrics and features
  2026-05-27 14:01 [PATCH v6 0/8] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
                   ` (5 preceding siblings ...)
  2026-05-27 14:02 ` [PATCH v6 6/8] platform/x86/amd/pmf: Implement util layer ioctl handler Shyam Sundar S K
@ 2026-05-27 14:02 ` Shyam Sundar S K
  2026-05-27 14:02 ` [PATCH v6 8/8] Documentation/ABI: add testing entry for AMD PMF character device interface Shyam Sundar S K
  7 siblings, 0 replies; 17+ messages in thread
From: Shyam Sundar S K @ 2026-05-27 14:02 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, mario.limonciello, 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_amd_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/platform/x86/amd/Makefile   |  60 +++++++++++++
 tools/platform/x86/amd/test-pmf.c | 142 ++++++++++++++++++++++++++++++
 2 files changed, 202 insertions(+)
 create mode 100644 tools/platform/x86/amd/Makefile
 create mode 100644 tools/platform/x86/amd/test-pmf.c

diff --git a/tools/platform/x86/amd/Makefile b/tools/platform/x86/amd/Makefile
new file mode 100644
index 000000000000..5d820df5871f
--- /dev/null
+++ b/tools/platform/x86/amd/Makefile
@@ -0,0 +1,60 @@
+# SPDX-License-Identifier: GPL-2.0
+ifeq ($(srctree),)
+srctree := $(patsubst %/,%,$(dir $(CURDIR)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+srctree := $(patsubst %/,%,$(dir $(srctree)))
+endif
+
+# Include common tools build infrastructure
+include $(srctree)/tools/scripts/Makefile.include
+
+CC		= $(CROSS_COMPILE)gcc
+BUILD_OUTPUT	:= $(CURDIR)
+PREFIX		?= /usr
+DESTDIR		?=
+
+ifeq ("$(origin O)", "command line")
+	BUILD_OUTPUT := $(O)
+endif
+
+# Include paths: tools/include has linux/kernel.h with ARRAY_SIZE
+INCLUDES	= -I$(srctree)/tools/include
+INCLUDES	+= -I$(srctree)/tools/include/uapi
+INCLUDES	+= -I$(srctree)/include/uapi
+INCLUDES	+= -I$(srctree)/include
+
+override CFLAGS += -O2 -Wall -Wextra -D_GNU_SOURCE $(INCLUDES)
+override CFLAGS += -D_FILE_OFFSET_BITS=64
+override CFLAGS += -D__EXPORTED_HEADERS__
+
+TARGETS		= test_amd_pmf
+
+all: $(TARGETS)
+
+test_amd_pmf: test-pmf.c
+	$(QUIET_CC)$(CC) $(CFLAGS) $< -o $(BUILD_OUTPUT)/$@ $(LDFLAGS)
+
+.PHONY: clean
+clean:
+	$(call QUIET_CLEAN, test_amd_pmf)$(RM) $(BUILD_OUTPUT)/test_amd_pmf
+
+.PHONY: install
+install: $(TARGETS)
+	$(INSTALL) -d $(DESTDIR)$(PREFIX)/bin
+	$(INSTALL) $(BUILD_OUTPUT)/test_amd_pmf $(DESTDIR)$(PREFIX)/bin/test_amd_pmf
+
+.PHONY: help
+help:
+	@echo "AMD Platform Tools Makefile"
+	@echo ""
+	@echo "Targets:"
+	@echo "  all           - Build all tools (default)"
+	@echo "  test_amd_pmf  - Build the PMF test tool"
+	@echo "  clean         - Remove built files"
+	@echo "  install       - Install tools to $(PREFIX)/bin"
+	@echo ""
+	@echo "Variables:"
+	@echo "  O=<dir>        - Build output directory"
+	@echo "  PREFIX         - Installation prefix (default: /usr)"
+	@echo "  DESTDIR        - Destination directory for install"
diff --git a/tools/platform/x86/amd/test-pmf.c b/tools/platform/x86/amd/test-pmf.c
new file mode 100644
index 000000000000..34630534b0a4
--- /dev/null
+++ b/tools/platform/x86/amd/test-pmf.c
@@ -0,0 +1,142 @@
+// 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 <linux/kernel.h>
+
+#define DEVICE_NODE	"/dev/amdpmf_interface"
+
+/* Feature flag names */
+static const char * const feature_names[] = {
+	"Auto Mode",
+	"Static Power Slider",
+	"Policy Builder (Smart PC)",
+	"Dynamic Power Slider AC",
+	"Dynamic Power Slider DC",
+};
+
+static const char *banner =
+	"====================================================\n"
+	"      AMD PMF Metrics info and Feature Status\n"
+	"====================================================\n\n";
+
+/* Print feature flags */
+static void pmf_print_features(uint32_t flags)
+{
+	size_t  i;
+
+	for (i = 0; i < ARRAY_SIZE(feature_names); i++)
+		printf("  [%c] %s\n", (flags & (1U << i)) ? 'x' : ' ', feature_names[i]);
+}
+
+/* Print BIOS parameters */
+static void pmf_print_bios_params(const char *type, const __u32 *params)
+{
+	int i;
+
+	for (i = 0; i < AMD_PMF_BIOS_PARAMS_MAX; i++)
+		printf("  Custom BIOS %s%d: %u\n", type, i + 1, params[i]);
+}
+
+/* Open the PMF device */
+static int pmf_open_device(void)
+{
+	int fd;
+
+	fd = open(DEVICE_NODE, O_RDONLY);
+	if (fd < 0)
+		fprintf(stderr, "Error: Cannot open %s: %s\n", DEVICE_NODE, strerror(errno));
+
+	return fd;
+}
+
+/* Query PMF info using the single IOCTL */
+static int pmf_get_info(int fd, struct amd_pmf_info *info)
+{
+	int ret;
+
+	/* Zero-initialize and set size for versioning */
+	memset(info, 0, sizeof(*info));
+	info->size = sizeof(*info);
+
+	ret = ioctl(fd, IOCTL_AMD_PMF_POPULATE_DATA, info);
+	if (ret < 0) {
+		fprintf(stderr, "Error: IOCTL_AMD_PMF_POPULATE_DATA failed: %s\n", strerror(errno));
+		return ret;
+	}
+
+	return 0;
+}
+
+static void pmf_print_info(const struct amd_pmf_info *info)
+{
+	printf("%s", banner);
+
+	/* Feature status */
+	printf("Feature Status:\n");
+	pmf_print_features(info->features_supported);
+
+	/* Device states */
+	printf("\nDevice States:\n");
+	printf("  Platform Type:     %s\n", amd_pmf_get_platform_type(info->platform_type));
+	printf("  Laptop Placement:  %s\n", amd_pmf_get_laptop_placement(info->laptop_placement));
+	printf("  Lid State:         %s\n", info->lid_state ? "Closed" : "Open");
+	printf("  User Presence:     %s\n", info->user_presence ? "Present" : "Away");
+	printf("  Slider Position:   %s\n", amd_pmf_get_slider_position(info->slider_position));
+
+	/* Thermal and power metrics */
+	printf("\nThermal/Power Metrics:\n");
+	printf("  Skin Temperature:  %d\n", info->skin_temp / 100);
+	printf("  GFX Busy:          %u\n", info->gfx_busy);
+	printf("  Ambient Light:     %d\n", info->ambient_light);
+	printf("  Avg C0 Residency:  %u\n", info->avg_c0_residency);
+	printf("  Max C0 Residency:  %u\n", info->max_c0_residency);
+	printf("  Socket Power:      %u\n", info->socket_power);
+
+	/* BIOS parameters */
+	printf("\nCustom BIOS Input Parameters:\n");
+	pmf_print_bios_params("Input", info->bios_input);
+	printf("\nCustom BIOS Output Parameters:\n");
+	pmf_print_bios_params("Output", info->bios_output);
+
+	printf("\n=================================================\n");
+}
+
+int main(void)
+{
+	struct amd_pmf_info info;
+	int fd, ret;
+
+	fd = pmf_open_device();
+	if (fd < 0)
+		return -1;
+
+	/* Query all info with single IOCTL */
+	ret = pmf_get_info(fd, &info);
+	close(fd);
+
+	if (ret < 0)
+		return -1;
+
+	pmf_print_info(&info);
+
+	return 0;
+}
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v6 8/8] Documentation/ABI: add testing entry for AMD PMF character device interface
  2026-05-27 14:01 [PATCH v6 0/8] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
                   ` (6 preceding siblings ...)
  2026-05-27 14:02 ` [PATCH v6 7/8] platform/x86/amd/pmf: Introduce AMD PMF testing tool for driver metrics and features Shyam Sundar S K
@ 2026-05-27 14:02 ` Shyam Sundar S K
  7 siblings, 0 replies; 17+ messages in thread
From: Shyam Sundar S K @ 2026-05-27 14:02 UTC (permalink / raw)
  To: hansg, ilpo.jarvinen
  Cc: platform-driver-x86, mario.limonciello, Sanket.Goswami,
	Shyam Sundar S K

Add a Documentation/ABI/testing entry describing the AMD PMF util layer
character device (/dev/amdpmf_interface) and the initial ioctl used to
query feature support and metrics data information. This interface is
available when CONFIG_AMD_PMF_UTIL_SUPPORT=y.

Also update the MAINTAINERS record with the new UAPI header.

Signed-off-by: Shyam Sundar S K <Shyam-sundar.S-k@amd.com>
---
 Documentation/ABI/testing/amdpmf-interface | 73 ++++++++++++++++++++++
 MAINTAINERS                                |  1 +
 2 files changed, 74 insertions(+)
 create mode 100644 Documentation/ABI/testing/amdpmf-interface

diff --git a/Documentation/ABI/testing/amdpmf-interface b/Documentation/ABI/testing/amdpmf-interface
new file mode 100644
index 000000000000..625f90a013d0
--- /dev/null
+++ b/Documentation/ABI/testing/amdpmf-interface
@@ -0,0 +1,73 @@
+What:		/dev/amdpmf_interface
+Date:		June 2026
+KernelVersion:	7.2
+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 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 supports a single ioctl:
+
+		============================ =======================================
+		IOCTL			     Usage
+		IOCTL_AMD_PMF_POPULATE_DATA  User passes a struct amd_pmf_info with
+					     the size field set to sizeof(struct
+					     amd_pmf_info). The driver returns all
+					     available metrics and feature status
+					     in the structure.
+		============================ =======================================
+
+		struct amd_pmf_info layout:
+
+		======================= ========== ================================
+		Field			Type	   Description
+		size			__u64	   Structure size for versioning
+		features_supported	__u32	   Bitmask of supported features
+		platform_type		__u32	   Platform form factor orientation
+		power_source		__u32	   AC/DC power source
+		laptop_placement	__u32	   Device placement state
+		lid_state		__u32	   Lid open/closed status
+		user_presence		__u32	   User presence detection
+		slider_position		__u32	   Current power slider position
+		skin_temp		__s32	   Skin temperature (centidegrees)
+		gfx_busy		__u32	   Graphics workload percentage
+		ambient_light		__s32	   Ambient light sensor reading
+		avg_c0_residency	__u32	   Average C0 state residency
+		max_c0_residency	__u32	   Maximum C0 state residency
+		socket_power		__u32	   Socket power consumption
+		bios_input[10]		__u32	   Custom BIOS input parameters
+		bios_output[10]		__u32	   Custom BIOS output parameters
+		======================= ========== ================================
+
+		Feature Support Flags (features_supported bitmask):
+
+		=====================================    ====  =============================
+		Flag				         Bit   Description
+		AMD_PMF_FEAT_AUTO_MODE		         0     Auto Mode feature support
+		AMD_PMF_FEAT_STATIC_POWER_SLIDER         1     Static Power Slider support
+		AMD_PMF_FEAT_POLICY_BUILDER	         2     Policy Builder (Smart PC)
+		AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_AC     3     Dynamic slider on AC
+		AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_DC     4     Dynamic slider on DC
+		=====================================    ====  =============================
+
+		Return codes:
+
+		============= ============================================================
+		Return code   Description
+		0	      Success
+		EINVAL	      Invalid size or parameter
+		EFAULT	      copy_to_user/copy_from_user failures
+		ENODEV	      PMF device not available
+		ENOTTY	      Unknown ioctl command
+		============= ============================================================
+
+		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 839e39825455..ec061cd127b2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1216,6 +1216,7 @@ L:	platform-driver-x86@vger.kernel.org
 S:	Supported
 F:	Documentation/ABI/testing/sysfs-amd-pmf
 F:	drivers/platform/x86/amd/pmf/
+F:	include/uapi/linux/amd-pmf.h
 
 AMD POWERPLAY AND SWSMU
 M:	Kenneth Feng <kenneth.feng@amd.com>
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH v6 3/8] platform/x86/amd/pmf: Add feature discovery support to util interface
  2026-05-27 14:02 ` [PATCH v6 3/8] platform/x86/amd/pmf: Add feature discovery support to util interface Shyam Sundar S K
@ 2026-06-08  9:24   ` Hans de Goede
  2026-06-08 13:13     ` Ilpo Järvinen
  0 siblings, 1 reply; 17+ messages in thread
From: Hans de Goede @ 2026-06-08  9:24 UTC (permalink / raw)
  To: Shyam Sundar S K, ilpo.jarvinen
  Cc: platform-driver-x86, mario.limonciello, Sanket.Goswami

Hi,

On 27-May-26 4:02 PM, 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
> 
> 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>
> ---
>  include/uapi/linux/amd-pmf.h | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
> index d29a4abe1145..9de054cfeee7 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/bits.h>
>  #include <linux/ioctl.h>
>  #include <linux/types.h>
>  
> @@ -34,9 +35,19 @@
>  
>  #define AMD_PMF_BIOS_PARAMS_MAX		10
>  
> +/* AMD PMF feature flags - bitmask indicating supported features */
> +#define AMD_PMF_FEAT_AUTO_MODE			BIT(0)
> +#define AMD_PMF_FEAT_STATIC_POWER_SLIDER	BIT(1)
> +#define AMD_PMF_FEAT_POLICY_BUILDER		BIT(2)
> +#define AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_AC	BIT(3)
> +#define AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_DC	BIT(4)
> +
>  struct amd_pmf_info {
>  	__u64 size;
>  
> +	/* Feature info */
> +	__u32 features_supported;
> +
>  	/* Power and state info */
>  	__u32 platform_type;
>  	__u32 power_source;

You are now changing the userspace ABI between patch 1 and
this patch. Please just squash this patch into patch 1.

Regards,

Hans



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v6 6/8] platform/x86/amd/pmf: Implement util layer ioctl handler
  2026-05-27 14:02 ` [PATCH v6 6/8] platform/x86/amd/pmf: Implement util layer ioctl handler Shyam Sundar S K
@ 2026-06-08  9:32   ` Hans de Goede
  2026-06-08 14:33     ` Ilpo Järvinen
  0 siblings, 1 reply; 17+ messages in thread
From: Hans de Goede @ 2026-06-08  9:32 UTC (permalink / raw)
  To: Shyam Sundar S K, ilpo.jarvinen
  Cc: platform-driver-x86, mario.limonciello, Sanket.Goswami

Hi,

On 27-May-26 4:02 PM, Shyam Sundar S K wrote:
> Implement the ioctl handler for the util layer character device. This
> support adds the actual functionality to populate PMF metrics from the
> TA shared memory buffer and return them to userspace.
> 
> The implementation includes:
> - amd_pmf_populate_data() to extract metrics from TA shared memory
> - amd_pmf_set_ioctl() to handle userspace ioctl requests
> - Size negotiation for forward/backward compatibility
> - Feature-based population of struct fields
> - Export amd_pmf_get_ta_custom_bios_inputs()
> 
> 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/pmf.h  |   1 +
>  drivers/platform/x86/amd/pmf/spc.c  |   3 +-
>  drivers/platform/x86/amd/pmf/util.c | 105 +++++++++++++++++++++++++++-
>  3 files changed, 107 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
> index 269c0a4b1cae..752fa5dd2267 100644
> --- a/drivers/platform/x86/amd/pmf/pmf.h
> +++ b/drivers/platform/x86/amd/pmf/pmf.h
> @@ -903,6 +903,7 @@ int amd_pmf_smartpc_apply_bios_output(struct amd_pmf_dev *dev, u32 val, u32 preq
>  void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in);
>  void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in);
>  int amd_pmf_invoke_cmd_enact(struct amd_pmf_dev *dev);
> +u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index);
>  
>  int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid);
>  void amd_pmf_tee_deinit(struct amd_pmf_dev *dev);
> diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c
> index 6e33824ccadc..94355b435a66 100644
> --- a/drivers/platform/x86/amd/pmf/spc.c
> +++ b/drivers/platform/x86/amd/pmf/spc.c
> @@ -18,7 +18,7 @@
>  #include "pmf.h"
>  
>  #ifdef CONFIG_AMD_PMF_DEBUG
> -static u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index)
> +u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index)
>  {
>  	switch (index) {
>  	case 0 ... 1:
> @@ -29,6 +29,7 @@ static u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int
>  		return 0;
>  	}
>  }
> +EXPORT_SYMBOL(amd_pmf_get_ta_custom_bios_inputs);
>  
>  void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
>  {
> diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
> index f8a283192ffe..30fb5c250362 100644
> --- a/drivers/platform/x86/amd/pmf/util.c
> +++ b/drivers/platform/x86/amd/pmf/util.c
> @@ -9,6 +9,7 @@
>   *	    Sanket Goswami <Sanket.Goswami@amd.com>
>   */
>  
> +#include <linux/align.h>
>  #include <linux/amd-pmf.h>
>  #include <linux/miscdevice.h>
>  #include <linux/mutex.h>
> @@ -19,9 +20,111 @@
>  static struct amd_pmf_dev *pmf_dev_handle;
>  static DEFINE_MUTEX(pmf_util_lock);
>  
> +static int amd_pmf_populate_data(struct amd_pmf_dev *pdev, struct amd_pmf_info *info)
> +{
> +	struct ta_pmf_shared_memory *ta_sm = NULL;
> +	struct ta_pmf_enact_table *in = NULL;
> +	int idx;
> +
> +	if (!pdev || !info)
> +		return -EINVAL;
> +
> +	if (!pdev->shbuf)
> +		return -EINVAL;
> +
> +	ta_sm = pdev->shbuf;
> +	in = &ta_sm->pmf_input.enact_table;
> +
> +	/* Set size */
> +	info->size = sizeof(*info);
> +
> +	/* PMF Feature support flags */
> +	if (is_apmf_func_supported(pdev, APMF_FUNC_AUTO_MODE))
> +		info->features_supported |= AMD_PMF_FEAT_AUTO_MODE;
> +	if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR))
> +		info->features_supported |= AMD_PMF_FEAT_STATIC_POWER_SLIDER;
> +	if (pdev->smart_pc_enabled)
> +		info->features_supported |= AMD_PMF_FEAT_POLICY_BUILDER;
> +	if (is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_AC))
> +		info->features_supported |= AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_AC;
> +	if (is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_DC))
> +		info->features_supported |= AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_DC;
> +
> +	/* Device States */
> +	info->platform_type = in->ev_info.platform_type;
> +	info->laptop_placement = in->ev_info.device_state;
> +	info->lid_state = in->ev_info.lid_state;
> +	info->user_presence = in->ev_info.user_present;
> +	info->slider_position = in->ev_info.power_slider;
> +
> +	/* Thermal and Power Metrics */
> +	info->power_source = in->ev_info.power_source;
> +	info->skin_temp = in->ev_info.skin_temperature;
> +	info->gfx_busy = in->ev_info.gfx_busy;
> +	info->ambient_light = in->ev_info.ambient_light;
> +	info->avg_c0_residency = in->ev_info.avg_c0residency;
> +	info->max_c0_residency = in->ev_info.max_c0residency;
> +	info->socket_power = in->ev_info.socket_power;
> +
> +	/* Custom BIOS input parameters */
> +	for (idx = 0; idx < AMD_PMF_BIOS_PARAMS_MAX; idx++)
> +		info->bios_input[idx] = amd_pmf_get_ta_custom_bios_inputs(in, idx);
> +
> +	/* BIOS output parameters */
> +	for (idx = 0; idx < AMD_PMF_BIOS_PARAMS_MAX; idx++)
> +		info->bios_output[idx] = pdev->bios_output[idx];
> +
> +	return 0;
> +}
> +
>  static long amd_pmf_set_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
>  {
> -	return -ENOTTY;
> +	struct amd_pmf_dev *pdev = filp->private_data;
> +	void __user *argp = (void __user *)arg;
> +	struct amd_pmf_info info = {};
> +	size_t copy_size;
> +	__u64 user_size;
> +	int ret;
> +
> +	if (cmd != IOCTL_AMD_PMF_POPULATE_DATA)
> +		return -ENOTTY;
> +
> +	/* First read just the size field from userspace */
> +	if (copy_from_user(&user_size, argp, sizeof(user_size)))
> +		return -EFAULT;
> +
> +	if (user_size > sizeof(info))
> +		return -EINVAL;

Why? If the struct ever gets extended and a newer userspace runs on
an older kernel this will now trigger. Instead just clamp to
sizeof(info) .

> +
> +	if (!IS_ALIGNED(user_size, sizeof(__u64)))
> +		return -EINVAL;

Why ?  I guess on x86_64 this will always be true, but what about
i386 ?   More specifically this simply seems unnecessary and I believe this
entire check can be dropped.

> +
> +	if (user_size > sizeof(__u64)) {

This should be:

if (user_size >= (offsetof(struct amd_pmf_info, features_supported) + sizeof(features_from_user))) {

> +		__u32 features_from_user = 0;
> +
> +		if (copy_from_user(&features_from_user, argp + offsetof(struct
> +		    amd_pmf_info, features_supported), sizeof(features_from_user)))
> +			return -EFAULT;
> +
> +		/* Reject non-zero values now */
> +		if (features_from_user != 0)
> +			return -EINVAL;

Looking at amd_pmf_populate_data() features_supported is purely a kernel -> user thing,
so why read this from userspace at all ?  And why must it be non 0 ?

I believe this entire block can be dropped (instead of fixing the if condition).


> +	}
> +
> +	guard(mutex)(&pmf_util_lock);
> +	ret = amd_pmf_populate_data(pdev, &info);
> +	if (ret)
> +		return ret;
> +
> +	copy_size = min_t(size_t, user_size, sizeof(info));

So here you're clamping which means the earlier user_size > sizeof(info) above
can just be dropped.

Regards,

Hans



> +
> +	/* Set actual size being copied */
> +	info.size = copy_size;
> +
> +	if (copy_to_user(argp, &info, copy_size))
> +		return -EFAULT;
> +
> +	return 0;
>  }
>  
>  static int amd_pmf_open(struct inode *inode, struct file *filp)


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v6 1/8] platform/x86/amd/pmf: Add util layer and userspace character device interface
  2026-05-27 14:01 ` [PATCH v6 1/8] platform/x86/amd/pmf: Add util layer and userspace character device interface Shyam Sundar S K
@ 2026-06-08  9:36   ` Hans de Goede
  0 siblings, 0 replies; 17+ messages in thread
From: Hans de Goede @ 2026-06-08  9:36 UTC (permalink / raw)
  To: Shyam Sundar S K, ilpo.jarvinen
  Cc: platform-driver-x86, mario.limonciello, Sanket.Goswami

Hi,

On 27-May-26 4:01 PM, Shyam Sundar S K wrote:
> Add a util layer to AMD PMF that exposes a minimal userspace interface
> via a 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   | 68 +++++++++++++++++++++++++++
>  include/uapi/linux/amd-pmf.h          | 60 +++++++++++++++++++++++
>  6 files changed, 154 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..ad4faf18de47 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..58d86b4c2828 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;
> @@ -643,6 +647,7 @@ static void amd_pmf_remove(struct platform_device *pdev)
>  {
>  	struct amd_pmf_dev *dev = platform_get_drvdata(pdev);
>  
> +	amd_pmf_cdev_unregister();
>  	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);
> 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..f8a283192ffe
> --- /dev/null
> +++ b/drivers/platform/x86/amd/pmf/util.c
> @@ -0,0 +1,68 @@
> +// 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"
> +
> +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)
> +{
> +	return -ENOTTY;
> +}
> +
> +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);
> +	if (pmf_dev_handle)
> +		misc_deregister(&amd_pmf_util_if);
> +	pmf_dev_handle = NULL;
> +}
> diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
> new file mode 100644
> index 000000000000..c7099e7f463f
> --- /dev/null
> +++ b/include/uapi/linux/amd-pmf.h
> @@ -0,0 +1,60 @@
> +/* 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_AMD_PMF_POPULATE_DATA - ioctl command to retrieve PMF metrics data
> + *
> + * This ioctl command is used to populate the amd_pmf_info structure
> + * with the requested PMF metrics information.
> + */
> +#define IOCTL_AMD_PMF_POPULATE_DATA		_IOWR(AMD_PMF_IOC_MAGIC, 0x00, struct amd_pmf_info)

Since the IOCTL is designed to allow extending the struct I would not code the size
into the IOCTL cmd value. I'm not sure if there is a macro without the size argument,
otherwise just pass __u64 for the size if the size-member which is effectively
the min size?

Regards,

Hans




> +
> +#define AMD_PMF_BIOS_PARAMS_MAX		10
> +
> +struct amd_pmf_info {
> +	__u64 size;
> +
> +	/* Power and state info */
> +	__u32 platform_type;
> +	__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 */
> +	__u32 bios_input[AMD_PMF_BIOS_PARAMS_MAX];
> +};
> +
> +#endif /* _UAPI_LINUX_AMD_PMF_H */


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v6 3/8] platform/x86/amd/pmf: Add feature discovery support to util interface
  2026-06-08  9:24   ` Hans de Goede
@ 2026-06-08 13:13     ` Ilpo Järvinen
  2026-06-09  7:46       ` Shyam Sundar S K
  0 siblings, 1 reply; 17+ messages in thread
From: Ilpo Järvinen @ 2026-06-08 13:13 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Shyam Sundar S K, platform-driver-x86, mario.limonciello,
	Sanket.Goswami

On Mon, 8 Jun 2026, Hans de Goede wrote:
> On 27-May-26 4:02 PM, 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
> > 
> > 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>
> > ---
> >  include/uapi/linux/amd-pmf.h | 11 +++++++++++
> >  1 file changed, 11 insertions(+)
> > 
> > diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
> > index d29a4abe1145..9de054cfeee7 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/bits.h>
> >  #include <linux/ioctl.h>
> >  #include <linux/types.h>
> >  
> > @@ -34,9 +35,19 @@
> >  
> >  #define AMD_PMF_BIOS_PARAMS_MAX		10
> >  
> > +/* AMD PMF feature flags - bitmask indicating supported features */
> > +#define AMD_PMF_FEAT_AUTO_MODE			BIT(0)
> > +#define AMD_PMF_FEAT_STATIC_POWER_SLIDER	BIT(1)
> > +#define AMD_PMF_FEAT_POLICY_BUILDER		BIT(2)
> > +#define AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_AC	BIT(3)
> > +#define AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_DC	BIT(4)
> > +
> >  struct amd_pmf_info {
> >  	__u64 size;
> >  
> > +	/* Feature info */
> > +	__u32 features_supported;
> > +
> >  	/* Power and state info */
> >  	__u32 platform_type;
> >  	__u32 power_source;
> 
> You are now changing the userspace ABI between patch 1 and
> this patch. Please just squash this patch into patch 1.

I asked to only create the interface towards the end of the series so 
there is no real problem from the ordering.

-- 
 i.


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v6 6/8] platform/x86/amd/pmf: Implement util layer ioctl handler
  2026-06-08  9:32   ` Hans de Goede
@ 2026-06-08 14:33     ` Ilpo Järvinen
  2026-06-08 16:08       ` Hans de Goede
  2026-06-09  7:48       ` Shyam Sundar S K
  0 siblings, 2 replies; 17+ messages in thread
From: Ilpo Järvinen @ 2026-06-08 14:33 UTC (permalink / raw)
  To: Hans de Goede
  Cc: Shyam Sundar S K, platform-driver-x86, mario.limonciello,
	Sanket.Goswami

On Mon, 8 Jun 2026, Hans de Goede wrote:
> On 27-May-26 4:02 PM, Shyam Sundar S K wrote:
> > Implement the ioctl handler for the util layer character device. This
> > support adds the actual functionality to populate PMF metrics from the
> > TA shared memory buffer and return them to userspace.
> > 
> > The implementation includes:
> > - amd_pmf_populate_data() to extract metrics from TA shared memory
> > - amd_pmf_set_ioctl() to handle userspace ioctl requests
> > - Size negotiation for forward/backward compatibility
> > - Feature-based population of struct fields
> > - Export amd_pmf_get_ta_custom_bios_inputs()
> > 
> > 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/pmf.h  |   1 +
> >  drivers/platform/x86/amd/pmf/spc.c  |   3 +-
> >  drivers/platform/x86/amd/pmf/util.c | 105 +++++++++++++++++++++++++++-
> >  3 files changed, 107 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
> > index 269c0a4b1cae..752fa5dd2267 100644
> > --- a/drivers/platform/x86/amd/pmf/pmf.h
> > +++ b/drivers/platform/x86/amd/pmf/pmf.h
> > @@ -903,6 +903,7 @@ int amd_pmf_smartpc_apply_bios_output(struct amd_pmf_dev *dev, u32 val, u32 preq
> >  void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in);
> >  void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in);
> >  int amd_pmf_invoke_cmd_enact(struct amd_pmf_dev *dev);
> > +u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index);
> >  
> >  int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid);
> >  void amd_pmf_tee_deinit(struct amd_pmf_dev *dev);
> > diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c
> > index 6e33824ccadc..94355b435a66 100644
> > --- a/drivers/platform/x86/amd/pmf/spc.c
> > +++ b/drivers/platform/x86/amd/pmf/spc.c
> > @@ -18,7 +18,7 @@
> >  #include "pmf.h"
> >  
> >  #ifdef CONFIG_AMD_PMF_DEBUG
> > -static u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index)
> > +u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index)
> >  {
> >  	switch (index) {
> >  	case 0 ... 1:
> > @@ -29,6 +29,7 @@ static u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int
> >  		return 0;
> >  	}
> >  }
> > +EXPORT_SYMBOL(amd_pmf_get_ta_custom_bios_inputs);
> >  
> >  void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
> >  {
> > diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
> > index f8a283192ffe..30fb5c250362 100644
> > --- a/drivers/platform/x86/amd/pmf/util.c
> > +++ b/drivers/platform/x86/amd/pmf/util.c
> > @@ -9,6 +9,7 @@
> >   *	    Sanket Goswami <Sanket.Goswami@amd.com>
> >   */
> >  
> > +#include <linux/align.h>
> >  #include <linux/amd-pmf.h>
> >  #include <linux/miscdevice.h>
> >  #include <linux/mutex.h>
> > @@ -19,9 +20,111 @@
> >  static struct amd_pmf_dev *pmf_dev_handle;
> >  static DEFINE_MUTEX(pmf_util_lock);
> >  
> > +static int amd_pmf_populate_data(struct amd_pmf_dev *pdev, struct amd_pmf_info *info)
> > +{
> > +	struct ta_pmf_shared_memory *ta_sm = NULL;
> > +	struct ta_pmf_enact_table *in = NULL;
> > +	int idx;
> > +
> > +	if (!pdev || !info)
> > +		return -EINVAL;
> > +
> > +	if (!pdev->shbuf)
> > +		return -EINVAL;
> > +
> > +	ta_sm = pdev->shbuf;
> > +	in = &ta_sm->pmf_input.enact_table;
> > +
> > +	/* Set size */
> > +	info->size = sizeof(*info);
> > +
> > +	/* PMF Feature support flags */
> > +	if (is_apmf_func_supported(pdev, APMF_FUNC_AUTO_MODE))
> > +		info->features_supported |= AMD_PMF_FEAT_AUTO_MODE;
> > +	if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR))
> > +		info->features_supported |= AMD_PMF_FEAT_STATIC_POWER_SLIDER;
> > +	if (pdev->smart_pc_enabled)
> > +		info->features_supported |= AMD_PMF_FEAT_POLICY_BUILDER;
> > +	if (is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_AC))
> > +		info->features_supported |= AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_AC;
> > +	if (is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_DC))
> > +		info->features_supported |= AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_DC;
> > +
> > +	/* Device States */
> > +	info->platform_type = in->ev_info.platform_type;
> > +	info->laptop_placement = in->ev_info.device_state;
> > +	info->lid_state = in->ev_info.lid_state;
> > +	info->user_presence = in->ev_info.user_present;
> > +	info->slider_position = in->ev_info.power_slider;
> > +
> > +	/* Thermal and Power Metrics */
> > +	info->power_source = in->ev_info.power_source;
> > +	info->skin_temp = in->ev_info.skin_temperature;
> > +	info->gfx_busy = in->ev_info.gfx_busy;
> > +	info->ambient_light = in->ev_info.ambient_light;
> > +	info->avg_c0_residency = in->ev_info.avg_c0residency;
> > +	info->max_c0_residency = in->ev_info.max_c0residency;
> > +	info->socket_power = in->ev_info.socket_power;
> > +
> > +	/* Custom BIOS input parameters */
> > +	for (idx = 0; idx < AMD_PMF_BIOS_PARAMS_MAX; idx++)
> > +		info->bios_input[idx] = amd_pmf_get_ta_custom_bios_inputs(in, idx);
> > +
> > +	/* BIOS output parameters */
> > +	for (idx = 0; idx < AMD_PMF_BIOS_PARAMS_MAX; idx++)
> > +		info->bios_output[idx] = pdev->bios_output[idx];
> > +
> > +	return 0;
> > +}
> > +
> >  static long amd_pmf_set_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
> >  {
> > -	return -ENOTTY;
> > +	struct amd_pmf_dev *pdev = filp->private_data;
> > +	void __user *argp = (void __user *)arg;
> > +	struct amd_pmf_info info = {};
> > +	size_t copy_size;
> > +	__u64 user_size;
> > +	int ret;
> > +
> > +	if (cmd != IOCTL_AMD_PMF_POPULATE_DATA)
> > +		return -ENOTTY;
> > +
> > +	/* First read just the size field from userspace */
> > +	if (copy_from_user(&user_size, argp, sizeof(user_size)))
> > +		return -EFAULT;
> > +
> > +	if (user_size > sizeof(info))
> > +		return -EINVAL;
> 
> Why? If the struct ever gets extended and a newer userspace runs on
> an older kernel this will now trigger. Instead just clamp to
> sizeof(info) .

If this is not here, some of the content userspace wanted will not be 
there so part of the struct member will not be filled. Userspace needs to 
be extremely careful which fields it can access in such a case.

> > +	if (!IS_ALIGNED(user_size, sizeof(__u64)))
> > +		return -EINVAL;
> 
> Why ?  I guess on x86_64 this will always be true, but what about
> i386 ?

user_size comes from userspace so it could be anything userspace put 
there and is unrelated to the arch. It just doesn't look useful to copy 
partial fields if userspace gives a strange user_size. Of course it never 
happens if userspace uses sizeof() to fill the size in.

> More specifically this simply seems unnecessary and I believe this
> entire check can be dropped.
>
> > +	if (user_size > sizeof(__u64)) {
> 
> This should be:
> 
> if (user_size >= (offsetof(struct amd_pmf_info, features_supported) + sizeof(features_from_user))) {
> 
> > +		__u32 features_from_user = 0;
> > +
> > +		if (copy_from_user(&features_from_user, argp + offsetof(struct
> > +		    amd_pmf_info, features_supported), sizeof(features_from_user)))
> > +			return -EFAULT;
> > +
> > +		/* Reject non-zero values now */
> > +		if (features_from_user != 0)
> > +			return -EINVAL;
> 
> Looking at amd_pmf_populate_data() features_supported is purely a kernel -> user thing,
> so why read this from userspace at all ?  And why must it be non 0 ?
>
> I believe this entire block can be dropped (instead of fixing the if condition).

Okay. Perhaps you're right and this should not be added.

My thinking when suggesting this was that they'll eventually come up 
something that is every expensive to get and then want to indicate it's 
not required to get it every time. By checking the feature flags right 
from the start like this, such an extension would be easy to add later.

And as per the code says, the non-zero feature values lead to -EINVAL, not 
the other way around.


-- 
 i.


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v6 6/8] platform/x86/amd/pmf: Implement util layer ioctl handler
  2026-06-08 14:33     ` Ilpo Järvinen
@ 2026-06-08 16:08       ` Hans de Goede
  2026-06-09  7:48       ` Shyam Sundar S K
  1 sibling, 0 replies; 17+ messages in thread
From: Hans de Goede @ 2026-06-08 16:08 UTC (permalink / raw)
  To: Ilpo Järvinen
  Cc: Shyam Sundar S K, platform-driver-x86, mario.limonciello,
	Sanket.Goswami

Hi Ilpo,

On 8-Jun-26 16:33, Ilpo Järvinen wrote:
> On Mon, 8 Jun 2026, Hans de Goede wrote:
>> On 27-May-26 4:02 PM, Shyam Sundar S K wrote:
>>> Implement the ioctl handler for the util layer character device. This
>>> support adds the actual functionality to populate PMF metrics from the
>>> TA shared memory buffer and return them to userspace.
>>>
>>> The implementation includes:
>>> - amd_pmf_populate_data() to extract metrics from TA shared memory
>>> - amd_pmf_set_ioctl() to handle userspace ioctl requests
>>> - Size negotiation for forward/backward compatibility
>>> - Feature-based population of struct fields
>>> - Export amd_pmf_get_ta_custom_bios_inputs()
>>>
>>> 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/pmf.h  |   1 +
>>>  drivers/platform/x86/amd/pmf/spc.c  |   3 +-
>>>  drivers/platform/x86/amd/pmf/util.c | 105 +++++++++++++++++++++++++++-
>>>  3 files changed, 107 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
>>> index 269c0a4b1cae..752fa5dd2267 100644
>>> --- a/drivers/platform/x86/amd/pmf/pmf.h
>>> +++ b/drivers/platform/x86/amd/pmf/pmf.h
>>> @@ -903,6 +903,7 @@ int amd_pmf_smartpc_apply_bios_output(struct amd_pmf_dev *dev, u32 val, u32 preq
>>>  void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in);
>>>  void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in);
>>>  int amd_pmf_invoke_cmd_enact(struct amd_pmf_dev *dev);
>>> +u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index);
>>>  
>>>  int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid);
>>>  void amd_pmf_tee_deinit(struct amd_pmf_dev *dev);
>>> diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c
>>> index 6e33824ccadc..94355b435a66 100644
>>> --- a/drivers/platform/x86/amd/pmf/spc.c
>>> +++ b/drivers/platform/x86/amd/pmf/spc.c
>>> @@ -18,7 +18,7 @@
>>>  #include "pmf.h"
>>>  
>>>  #ifdef CONFIG_AMD_PMF_DEBUG
>>> -static u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index)
>>> +u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index)
>>>  {
>>>  	switch (index) {
>>>  	case 0 ... 1:
>>> @@ -29,6 +29,7 @@ static u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int
>>>  		return 0;
>>>  	}
>>>  }
>>> +EXPORT_SYMBOL(amd_pmf_get_ta_custom_bios_inputs);
>>>  
>>>  void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
>>>  {
>>> diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
>>> index f8a283192ffe..30fb5c250362 100644
>>> --- a/drivers/platform/x86/amd/pmf/util.c
>>> +++ b/drivers/platform/x86/amd/pmf/util.c
>>> @@ -9,6 +9,7 @@
>>>   *	    Sanket Goswami <Sanket.Goswami@amd.com>
>>>   */
>>>  
>>> +#include <linux/align.h>
>>>  #include <linux/amd-pmf.h>
>>>  #include <linux/miscdevice.h>
>>>  #include <linux/mutex.h>
>>> @@ -19,9 +20,111 @@
>>>  static struct amd_pmf_dev *pmf_dev_handle;
>>>  static DEFINE_MUTEX(pmf_util_lock);
>>>  
>>> +static int amd_pmf_populate_data(struct amd_pmf_dev *pdev, struct amd_pmf_info *info)
>>> +{
>>> +	struct ta_pmf_shared_memory *ta_sm = NULL;
>>> +	struct ta_pmf_enact_table *in = NULL;
>>> +	int idx;
>>> +
>>> +	if (!pdev || !info)
>>> +		return -EINVAL;
>>> +
>>> +	if (!pdev->shbuf)
>>> +		return -EINVAL;
>>> +
>>> +	ta_sm = pdev->shbuf;
>>> +	in = &ta_sm->pmf_input.enact_table;
>>> +
>>> +	/* Set size */
>>> +	info->size = sizeof(*info);
>>> +
>>> +	/* PMF Feature support flags */
>>> +	if (is_apmf_func_supported(pdev, APMF_FUNC_AUTO_MODE))
>>> +		info->features_supported |= AMD_PMF_FEAT_AUTO_MODE;
>>> +	if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR))
>>> +		info->features_supported |= AMD_PMF_FEAT_STATIC_POWER_SLIDER;
>>> +	if (pdev->smart_pc_enabled)
>>> +		info->features_supported |= AMD_PMF_FEAT_POLICY_BUILDER;
>>> +	if (is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_AC))
>>> +		info->features_supported |= AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_AC;
>>> +	if (is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_DC))
>>> +		info->features_supported |= AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_DC;
>>> +
>>> +	/* Device States */
>>> +	info->platform_type = in->ev_info.platform_type;
>>> +	info->laptop_placement = in->ev_info.device_state;
>>> +	info->lid_state = in->ev_info.lid_state;
>>> +	info->user_presence = in->ev_info.user_present;
>>> +	info->slider_position = in->ev_info.power_slider;
>>> +
>>> +	/* Thermal and Power Metrics */
>>> +	info->power_source = in->ev_info.power_source;
>>> +	info->skin_temp = in->ev_info.skin_temperature;
>>> +	info->gfx_busy = in->ev_info.gfx_busy;
>>> +	info->ambient_light = in->ev_info.ambient_light;
>>> +	info->avg_c0_residency = in->ev_info.avg_c0residency;
>>> +	info->max_c0_residency = in->ev_info.max_c0residency;
>>> +	info->socket_power = in->ev_info.socket_power;
>>> +
>>> +	/* Custom BIOS input parameters */
>>> +	for (idx = 0; idx < AMD_PMF_BIOS_PARAMS_MAX; idx++)
>>> +		info->bios_input[idx] = amd_pmf_get_ta_custom_bios_inputs(in, idx);
>>> +
>>> +	/* BIOS output parameters */
>>> +	for (idx = 0; idx < AMD_PMF_BIOS_PARAMS_MAX; idx++)
>>> +		info->bios_output[idx] = pdev->bios_output[idx];
>>> +
>>> +	return 0;
>>> +}
>>> +
>>>  static long amd_pmf_set_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
>>>  {
>>> -	return -ENOTTY;
>>> +	struct amd_pmf_dev *pdev = filp->private_data;
>>> +	void __user *argp = (void __user *)arg;
>>> +	struct amd_pmf_info info = {};
>>> +	size_t copy_size;
>>> +	__u64 user_size;
>>> +	int ret;
>>> +
>>> +	if (cmd != IOCTL_AMD_PMF_POPULATE_DATA)
>>> +		return -ENOTTY;
>>> +
>>> +	/* First read just the size field from userspace */
>>> +	if (copy_from_user(&user_size, argp, sizeof(user_size)))
>>> +		return -EFAULT;
>>> +
>>> +	if (user_size > sizeof(info))
>>> +		return -EINVAL;
>>
>> Why? If the struct ever gets extended and a newer userspace runs on
>> an older kernel this will now trigger. Instead just clamp to
>> sizeof(info) .
> 
> If this is not here, some of the content userspace wanted will not be 
> there so part of the struct member will not be filled. Userspace needs to 
> be extremely careful which fields it can access in such a case.

Yes, but the whole idea of having the size in the struct is to make
it extensible and that also means allowing a newer userspace which
may ask for more info to run on an older kernel.

And yes that means userspace needs to be careful and check the
returned size value when accessing struct members which are added
in a later extension.

> 
>>> +	if (!IS_ALIGNED(user_size, sizeof(__u64)))
>>> +		return -EINVAL;
>>
>> Why ?  I guess on x86_64 this will always be true, but what about
>> i386 ?
> 
> user_size comes from userspace so it could be anything userspace put 
> there and is unrelated to the arch.

Unless the last member is a u64 or pointer the sizeof() may return
a value which is a multipe of 32 bits on i386 (IIRC).

> It just doesn't look useful to copy 
> partial fields if userspace gives a strange user_size.

It is not useful, but it cannot hurt from a kernel pov, so why add
the extra check ?  Normal userspace will never asks for partial
fields. So we only need to worry about attackers and I don't see
how an attacker can abuse a non aligned size.

> Of course it never 
> happens if userspace uses sizeof() to fill the size in.

Right, which is why we only need to worry about bad actors for this.

>> More specifically this simply seems unnecessary and I believe this
>> entire check can be dropped.
>>
>>> +	if (user_size > sizeof(__u64)) {
>>
>> This should be:
>>
>> if (user_size >= (offsetof(struct amd_pmf_info, features_supported) + sizeof(features_from_user))) {
>>
>>> +		__u32 features_from_user = 0;
>>> +
>>> +		if (copy_from_user(&features_from_user, argp + offsetof(struct
>>> +		    amd_pmf_info, features_supported), sizeof(features_from_user)))
>>> +			return -EFAULT;
>>> +
>>> +		/* Reject non-zero values now */
>>> +		if (features_from_user != 0)
>>> +			return -EINVAL;
>>
>> Looking at amd_pmf_populate_data() features_supported is purely a kernel -> user thing,
>> so why read this from userspace at all ?  And why must it be non 0 ?
>>
>> I believe this entire block can be dropped (instead of fixing the if condition).
> 
> Okay. Perhaps you're right and this should not be added.
> 
> My thinking when suggesting this was that they'll eventually come up 
> something that is every expensive to get and then want to indicate it's 
> not required to get it every time. By checking the feature flags right 
> from the start like this, such an extension would be easy to add later.
> 
> And as per the code says, the non-zero feature values lead to -EINVAL, not 
> the other way around.

Ah I see. This still feels like unnecessary complication. All current fields
are read from cached values so not expensive and if we add expensive fields
later userspace can use the user_size to indicate if it wants those or not,
or we could even add a whole new ioctl cmd value for those.

Regards,

Hans




^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v6 3/8] platform/x86/amd/pmf: Add feature discovery support to util interface
  2026-06-08 13:13     ` Ilpo Järvinen
@ 2026-06-09  7:46       ` Shyam Sundar S K
  0 siblings, 0 replies; 17+ messages in thread
From: Shyam Sundar S K @ 2026-06-09  7:46 UTC (permalink / raw)
  To: Ilpo Järvinen, Hans de Goede
  Cc: platform-driver-x86, mario.limonciello, Sanket.Goswami



On 6/8/2026 18:43, Ilpo Järvinen wrote:
> On Mon, 8 Jun 2026, Hans de Goede wrote:
>> On 27-May-26 4:02 PM, 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
>>>
>>> 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>
>>> ---
>>>  include/uapi/linux/amd-pmf.h | 11 +++++++++++
>>>  1 file changed, 11 insertions(+)
>>>
>>> diff --git a/include/uapi/linux/amd-pmf.h b/include/uapi/linux/amd-pmf.h
>>> index d29a4abe1145..9de054cfeee7 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/bits.h>
>>>  #include <linux/ioctl.h>
>>>  #include <linux/types.h>
>>>  
>>> @@ -34,9 +35,19 @@
>>>  
>>>  #define AMD_PMF_BIOS_PARAMS_MAX		10
>>>  
>>> +/* AMD PMF feature flags - bitmask indicating supported features */
>>> +#define AMD_PMF_FEAT_AUTO_MODE			BIT(0)
>>> +#define AMD_PMF_FEAT_STATIC_POWER_SLIDER	BIT(1)
>>> +#define AMD_PMF_FEAT_POLICY_BUILDER		BIT(2)
>>> +#define AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_AC	BIT(3)
>>> +#define AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_DC	BIT(4)
>>> +
>>>  struct amd_pmf_info {
>>>  	__u64 size;
>>>  
>>> +	/* Feature info */
>>> +	__u32 features_supported;
>>> +
>>>  	/* Power and state info */
>>>  	__u32 platform_type;
>>>  	__u32 power_source;
>>
>> You are now changing the userspace ABI between patch 1 and
>> this patch. Please just squash this patch into patch 1.

Ack to the remarks in 1/8 and this one.

> 
> I asked to only create the interface towards the end of the series so 
> there is no real problem from the ordering.
> 

Ilpo, Squashed it in patch1, please check if this sounds good to you.

Thanks,
Shyam

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v6 6/8] platform/x86/amd/pmf: Implement util layer ioctl handler
  2026-06-08 14:33     ` Ilpo Järvinen
  2026-06-08 16:08       ` Hans de Goede
@ 2026-06-09  7:48       ` Shyam Sundar S K
  1 sibling, 0 replies; 17+ messages in thread
From: Shyam Sundar S K @ 2026-06-09  7:48 UTC (permalink / raw)
  To: Ilpo Järvinen, Hans de Goede
  Cc: platform-driver-x86, mario.limonciello, Sanket.Goswami



On 6/8/2026 20:03, Ilpo Järvinen wrote:
> On Mon, 8 Jun 2026, Hans de Goede wrote:
>> On 27-May-26 4:02 PM, Shyam Sundar S K wrote:
>>> Implement the ioctl handler for the util layer character device. This
>>> support adds the actual functionality to populate PMF metrics from the
>>> TA shared memory buffer and return them to userspace.
>>>
>>> The implementation includes:
>>> - amd_pmf_populate_data() to extract metrics from TA shared memory
>>> - amd_pmf_set_ioctl() to handle userspace ioctl requests
>>> - Size negotiation for forward/backward compatibility
>>> - Feature-based population of struct fields
>>> - Export amd_pmf_get_ta_custom_bios_inputs()
>>>
>>> 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/pmf.h  |   1 +
>>>  drivers/platform/x86/amd/pmf/spc.c  |   3 +-
>>>  drivers/platform/x86/amd/pmf/util.c | 105 +++++++++++++++++++++++++++-
>>>  3 files changed, 107 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/platform/x86/amd/pmf/pmf.h b/drivers/platform/x86/amd/pmf/pmf.h
>>> index 269c0a4b1cae..752fa5dd2267 100644
>>> --- a/drivers/platform/x86/amd/pmf/pmf.h
>>> +++ b/drivers/platform/x86/amd/pmf/pmf.h
>>> @@ -903,6 +903,7 @@ int amd_pmf_smartpc_apply_bios_output(struct amd_pmf_dev *dev, u32 val, u32 preq
>>>  void amd_pmf_populate_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in);
>>>  void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in);
>>>  int amd_pmf_invoke_cmd_enact(struct amd_pmf_dev *dev);
>>> +u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index);
>>>  
>>>  int amd_pmf_tee_init(struct amd_pmf_dev *dev, const uuid_t *uuid);
>>>  void amd_pmf_tee_deinit(struct amd_pmf_dev *dev);
>>> diff --git a/drivers/platform/x86/amd/pmf/spc.c b/drivers/platform/x86/amd/pmf/spc.c
>>> index 6e33824ccadc..94355b435a66 100644
>>> --- a/drivers/platform/x86/amd/pmf/spc.c
>>> +++ b/drivers/platform/x86/amd/pmf/spc.c
>>> @@ -18,7 +18,7 @@
>>>  #include "pmf.h"
>>>  
>>>  #ifdef CONFIG_AMD_PMF_DEBUG
>>> -static u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index)
>>> +u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int index)
>>>  {
>>>  	switch (index) {
>>>  	case 0 ... 1:
>>> @@ -29,6 +29,7 @@ static u32 amd_pmf_get_ta_custom_bios_inputs(struct ta_pmf_enact_table *in, int
>>>  		return 0;
>>>  	}
>>>  }
>>> +EXPORT_SYMBOL(amd_pmf_get_ta_custom_bios_inputs);
>>>  
>>>  void amd_pmf_dump_ta_inputs(struct amd_pmf_dev *dev, struct ta_pmf_enact_table *in)
>>>  {
>>> diff --git a/drivers/platform/x86/amd/pmf/util.c b/drivers/platform/x86/amd/pmf/util.c
>>> index f8a283192ffe..30fb5c250362 100644
>>> --- a/drivers/platform/x86/amd/pmf/util.c
>>> +++ b/drivers/platform/x86/amd/pmf/util.c
>>> @@ -9,6 +9,7 @@
>>>   *	    Sanket Goswami <Sanket.Goswami@amd.com>
>>>   */
>>>  
>>> +#include <linux/align.h>
>>>  #include <linux/amd-pmf.h>
>>>  #include <linux/miscdevice.h>
>>>  #include <linux/mutex.h>
>>> @@ -19,9 +20,111 @@
>>>  static struct amd_pmf_dev *pmf_dev_handle;
>>>  static DEFINE_MUTEX(pmf_util_lock);
>>>  
>>> +static int amd_pmf_populate_data(struct amd_pmf_dev *pdev, struct amd_pmf_info *info)
>>> +{
>>> +	struct ta_pmf_shared_memory *ta_sm = NULL;
>>> +	struct ta_pmf_enact_table *in = NULL;
>>> +	int idx;
>>> +
>>> +	if (!pdev || !info)
>>> +		return -EINVAL;
>>> +
>>> +	if (!pdev->shbuf)
>>> +		return -EINVAL;
>>> +
>>> +	ta_sm = pdev->shbuf;
>>> +	in = &ta_sm->pmf_input.enact_table;
>>> +
>>> +	/* Set size */
>>> +	info->size = sizeof(*info);
>>> +
>>> +	/* PMF Feature support flags */
>>> +	if (is_apmf_func_supported(pdev, APMF_FUNC_AUTO_MODE))
>>> +		info->features_supported |= AMD_PMF_FEAT_AUTO_MODE;
>>> +	if (is_apmf_func_supported(pdev, APMF_FUNC_STATIC_SLIDER_GRANULAR))
>>> +		info->features_supported |= AMD_PMF_FEAT_STATIC_POWER_SLIDER;
>>> +	if (pdev->smart_pc_enabled)
>>> +		info->features_supported |= AMD_PMF_FEAT_POLICY_BUILDER;
>>> +	if (is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_AC))
>>> +		info->features_supported |= AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_AC;
>>> +	if (is_apmf_func_supported(pdev, APMF_FUNC_DYN_SLIDER_DC))
>>> +		info->features_supported |= AMD_PMF_FEAT_DYNAMIC_POWER_SLIDER_DC;
>>> +
>>> +	/* Device States */
>>> +	info->platform_type = in->ev_info.platform_type;
>>> +	info->laptop_placement = in->ev_info.device_state;
>>> +	info->lid_state = in->ev_info.lid_state;
>>> +	info->user_presence = in->ev_info.user_present;
>>> +	info->slider_position = in->ev_info.power_slider;
>>> +
>>> +	/* Thermal and Power Metrics */
>>> +	info->power_source = in->ev_info.power_source;
>>> +	info->skin_temp = in->ev_info.skin_temperature;
>>> +	info->gfx_busy = in->ev_info.gfx_busy;
>>> +	info->ambient_light = in->ev_info.ambient_light;
>>> +	info->avg_c0_residency = in->ev_info.avg_c0residency;
>>> +	info->max_c0_residency = in->ev_info.max_c0residency;
>>> +	info->socket_power = in->ev_info.socket_power;
>>> +
>>> +	/* Custom BIOS input parameters */
>>> +	for (idx = 0; idx < AMD_PMF_BIOS_PARAMS_MAX; idx++)
>>> +		info->bios_input[idx] = amd_pmf_get_ta_custom_bios_inputs(in, idx);
>>> +
>>> +	/* BIOS output parameters */
>>> +	for (idx = 0; idx < AMD_PMF_BIOS_PARAMS_MAX; idx++)
>>> +		info->bios_output[idx] = pdev->bios_output[idx];
>>> +
>>> +	return 0;
>>> +}
>>> +
>>>  static long amd_pmf_set_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
>>>  {
>>> -	return -ENOTTY;
>>> +	struct amd_pmf_dev *pdev = filp->private_data;
>>> +	void __user *argp = (void __user *)arg;
>>> +	struct amd_pmf_info info = {};
>>> +	size_t copy_size;
>>> +	__u64 user_size;
>>> +	int ret;
>>> +
>>> +	if (cmd != IOCTL_AMD_PMF_POPULATE_DATA)
>>> +		return -ENOTTY;
>>> +
>>> +	/* First read just the size field from userspace */
>>> +	if (copy_from_user(&user_size, argp, sizeof(user_size)))
>>> +		return -EFAULT;
>>> +
>>> +	if (user_size > sizeof(info))
>>> +		return -EINVAL;
>>
>> Why? If the struct ever gets extended and a newer userspace runs on
>> an older kernel this will now trigger. Instead just clamp to
>> sizeof(info) .
> 
> If this is not here, some of the content userspace wanted will not be 
> there so part of the struct member will not be filled. Userspace needs to 
> be extremely careful which fields it can access in such a case.
> 
>>> +	if (!IS_ALIGNED(user_size, sizeof(__u64)))
>>> +		return -EINVAL;
>>
>> Why ?  I guess on x86_64 this will always be true, but what about
>> i386 ?
> 
> user_size comes from userspace so it could be anything userspace put 
> there and is unrelated to the arch. It just doesn't look useful to copy 
> partial fields if userspace gives a strange user_size. Of course it never 
> happens if userspace uses sizeof() to fill the size in.
> 
>> More specifically this simply seems unnecessary and I believe this
>> entire check can be dropped.
>>
>>> +	if (user_size > sizeof(__u64)) {
>>
>> This should be:
>>
>> if (user_size >= (offsetof(struct amd_pmf_info, features_supported) + sizeof(features_from_user))) {
>>
>>> +		__u32 features_from_user = 0;
>>> +
>>> +		if (copy_from_user(&features_from_user, argp + offsetof(struct
>>> +		    amd_pmf_info, features_supported), sizeof(features_from_user)))
>>> +			return -EFAULT;
>>> +
>>> +		/* Reject non-zero values now */
>>> +		if (features_from_user != 0)
>>> +			return -EINVAL;
>>
>> Looking at amd_pmf_populate_data() features_supported is purely a kernel -> user thing,
>> so why read this from userspace at all ?  And why must it be non 0 ?
>>
>> I believe this entire block can be dropped (instead of fixing the if condition).
> 
> Okay. Perhaps you're right and this should not be added.
> 
> My thinking when suggesting this was that they'll eventually come up 
> something that is every expensive to get and then want to indicate it's 
> not required to get it every time. By checking the feature flags right 
> from the start like this, such an extension would be easy to add later.
> 
> And as per the code says, the non-zero feature values lead to -EINVAL, not 
> the other way around.
> 
> 

Ack to all the comments in this patch. Please review v7 submission.

Thanks,
Shyam

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2026-06-09  7:48 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-27 14:01 [PATCH v6 0/8] platform/x86/amd/pmf: Introduce PMF util layer with userspace interface Shyam Sundar S K
2026-05-27 14:01 ` [PATCH v6 1/8] platform/x86/amd/pmf: Add util layer and userspace character device interface Shyam Sundar S K
2026-06-08  9:36   ` Hans de Goede
2026-05-27 14:01 ` [PATCH v6 2/8] platform/x86/amd/pmf: store BIOS output values for user-space metrics via util IOCTL Shyam Sundar S K
2026-05-27 14:02 ` [PATCH v6 3/8] platform/x86/amd/pmf: Add feature discovery support to util interface Shyam Sundar S K
2026-06-08  9:24   ` Hans de Goede
2026-06-08 13:13     ` Ilpo Järvinen
2026-06-09  7:46       ` Shyam Sundar S K
2026-05-27 14:02 ` [PATCH v6 4/8] platform/x86/amd/pmf: Store commonly used enums in the header file Shyam Sundar S K
2026-05-27 14:02 ` [PATCH v6 5/8] platform/x86/amd/pmf: Move debug helper functions to UAPI header Shyam Sundar S K
2026-05-27 14:02 ` [PATCH v6 6/8] platform/x86/amd/pmf: Implement util layer ioctl handler Shyam Sundar S K
2026-06-08  9:32   ` Hans de Goede
2026-06-08 14:33     ` Ilpo Järvinen
2026-06-08 16:08       ` Hans de Goede
2026-06-09  7:48       ` Shyam Sundar S K
2026-05-27 14:02 ` [PATCH v6 7/8] platform/x86/amd/pmf: Introduce AMD PMF testing tool for driver metrics and features Shyam Sundar S K
2026-05-27 14:02 ` [PATCH v6 8/8] Documentation/ABI: add testing entry for AMD PMF character device interface Shyam Sundar S K

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.