On Wed, 25 Mar 2026, Mario Limonciello wrote: > On 3/25/26 08:54, Ilpo Järvinen wrote: > > + Selftest people. > > > > On Sun, 1 Mar 2026, Shyam Sundar S K wrote: > > > > > This tool leverages amd-pmf ioctls exposed via the util layer, allowing > > > validation of its newly integrated util layer and /dev/amdpmf_interface. > > > It includes a user-space test application, test_pmf, designed to interact > > > with the PMF driver and retrieve relevant metrics for the testing and > > > analysis. > > > > > > It provides definitions for test metrics, feature IDs, and device states, > > > and includes tests for various AMD PMF metrics such as power source, skin > > > temperature, battery state, and custom BIOS inputs/outputs. It also > > > enables the testing of PMF metrics data and feature support reporting. > > > > > > Co-developed-by: Sanket Goswami <[email protected]> > > > Signed-off-by: Sanket Goswami <[email protected]> > > > Signed-off-by: Shyam Sundar S K <[email protected]> > > > --- > > > tools/testing/selftests/Makefile | 1 + > > > .../drivers/platform/x86/amd/pmf/Makefile | 8 + > > > .../drivers/platform/x86/amd/pmf/test_pmf.c | 243 ++++++++++++++++++ > > > 3 files changed, 252 insertions(+) > > > create mode 100644 > > > tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile > > > create mode 100644 > > > tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c > > > > Please Cc also selftest people in the next version submission! Maube you > > should also check why your patch sending process did not capture those > > receipient for you. > > > > To me it looks this "tool" doesn't really perform a selftest the way I've > > understood "selftests" work. That is, it doesn't have notion of Pass/Fail > > at all AFAICT. I'm not sure if there are other selftests like this but > > hopefully the selftest people know. > > For a similar "tool" I have it outside of selftests: > > linux/tools/crypto/ccp > > Ilpo, > > Maybe we want a directory structure like this? > > tools/platform/x86/amd
At least to me it looks better than placing a non-selftest tool under selftests/. -- i. > > > diff --git a/tools/testing/selftests/Makefile > > > b/tools/testing/selftests/Makefile > > > index 450f13ba4cca..d850fb09eeb9 100644 > > > --- a/tools/testing/selftests/Makefile > > > +++ b/tools/testing/selftests/Makefile > > > @@ -26,6 +26,7 @@ TARGETS += drivers/net/netconsole > > > TARGETS += drivers/net/team > > > TARGETS += drivers/net/virtio_net > > > TARGETS += drivers/platform/x86/intel/ifs > > > +TARGETS += drivers/platform/x86/amd/pmf > > > TARGETS += dt > > > TARGETS += efivarfs > > > TARGETS += exec > > > diff --git a/tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile > > > b/tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile > > > new file mode 100644 > > > index 000000000000..876424941e83 > > > --- /dev/null > > > +++ b/tools/testing/selftests/drivers/platform/x86/amd/pmf/Makefile > > > @@ -0,0 +1,8 @@ > > > +# SPDX-License-Identifier: GPL-2.0-or-later > > > +CFLAGS += $(KHDR_INCLUDES) > > > + > > > +TEST_GEN_PROGS := test_pmf > > > + > > > +top_srcdir ?=../../../../.. > > > + > > > +include ../../../../../lib.mk > > > diff --git > > > a/tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c > > > b/tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c > > > new file mode 100644 > > > index 000000000000..a040ef01ba90 > > > --- /dev/null > > > +++ b/tools/testing/selftests/drivers/platform/x86/amd/pmf/test_pmf.c > > > @@ -0,0 +1,243 @@ > > > +// SPDX-License-Identifier: GPL-2.0-or-later > > > +/* > > > + * AMD Platform Management Framework Test Tool > > > + * > > > + * Copyright (c) 2026, Advanced Micro Devices, Inc. > > > + * All Rights Reserved. > > > + * > > > + * Authors: Shyam Sundar S K <[email protected]> > > > + * Sanket Goswami <[email protected]> > > > + */ > > > + > > > +#include <errno.h> > > > +#include <fcntl.h> > > > +#include <inttypes.h> > > > +#include <stdbool.h> > > > +#include <stdint.h> > > > +#include <stdio.h> > > > +#include <string.h> > > > +#include <sys/ioctl.h> > > > +#include <unistd.h> > > > +#include <linux/amd-pmf.h> > > > + > > > +#include "../../../../../kselftest.h" > > > + > > > +#define DEVICE_NODE "/dev/amdpmf_interface" > > > + > > > +static int pmf_open_device(void) > > > +{ > > > + int fd; > > > + > > > + fd = open(DEVICE_NODE, O_RDONLY); > > > + if (fd < 0) > > > + fprintf(stderr, "opening PMF Device Node failed: %s\n", > > > strerror(errno)); > > > + > > > + return fd; > > > +} > > > + > > > +/* Helper to run IOCTL_PMF_POPULATE_DATA for one control code and return > > > 0 on success. */ > > > > Reflow this comment to 80 chars. > > > > > +static int pmf_get_fd(int fd, enum pmf_ioctl_id code, struct > > > amd_pmf_ioctl_info *out) > > > +{ > > > + struct amd_pmf_ioctl_info info = {0}; > > > > = {}; should be enough to initialize to default values. > > > > > + int ret; > > > + > > > + if (!out) > > > + return -EINVAL; > > > + > > > + info.control_code = code; > > > + > > > + ret = ioctl(fd, IOCTL_PMF_POPULATE_DATA, &info); > > > + if (ret < 0) > > > + return ret; > > > + > > > + *out = info; > > > + return 0; > > > +} > > > + > > > +static int pmf_get_data(enum pmf_ioctl_id code, struct amd_pmf_ioctl_info > > > *out) > > > +{ > > > + int fd, ret; > > > + > > > + fd = pmf_open_device(); > > > + if (fd < 0) > > > + return fd; > > > + > > > + ret = pmf_get_fd(fd, code, out); > > > + > > > + close(fd); > > > + return ret; > > > +} > > > + > > > +static int pmf_get_feature_status(unsigned int code) > > > +{ > > > + struct amd_pmf_ioctl_info info = {0}; > > > + int ret; > > > + > > > + ret = pmf_get_data(code, &info); > > > + if (ret < 0) > > > + return ret; > > > + > > > + switch (code) { > > > + case IOCTL_FEATURE_AUTO_MODE: > > > + printf("Auto Mode: %-24s\n", info.feature_supported ? "Yes" : > > > "No"); > > > + break; > > > + case IOCTL_FEATURE_STATIC_POWER_SLIDER: > > > + printf("Static Power Slider: %-24s\n", info.feature_supported > > > ? "Yes" : "No"); > > > + break; > > > + case IOCTL_FEATURE_POLICY_BUILDER: > > > + printf("Policy Builder: %s\n", info.feature_supported ? "Yes" > > > : "No"); > > > + break; > > > + case IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_AC: > > > + printf("Dynamic Power Slider AC: %s\n", info.feature_supported > > > ? "Yes" : "No"); > > > + break; > > > + case IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC: > > > + printf("Dynamic Power Slider DC: %s\n", info.feature_supported > > > ? "Yes" : "No"); > > > + break; > > > + default: > > > + return -1; > > > + } > > > + > > > + return 0; > > > +} > > > + > > > +static int pmf_get_device_state(unsigned int code) > > > +{ > > > + struct amd_pmf_ioctl_info info = {0}; > > > + int ret; > > > + > > > + ret = pmf_get_data(code, &info); > > > + if (ret < 0) > > > + return ret; > > > + > > > + switch (code) { > > > + case IOCTL_PLATFORM_TYPE: > > > + printf("Platform Type: %s\n", platform_type_as_str(info.val)); > > > + break; > > > + case IOCTL_LAPTOP_PLACEMENT: > > > + printf("Laptop placement: %s\n", > > > laptop_placement_as_str(info.val)); > > > + break; > > > + case IOCTL_LID_STATE: > > > + printf("Lid State: %s\n", info.val ? "Close" : "Open"); > > > + break; > > > + case IOCTL_USER_PRESENCE: > > > + printf("User Presence: %s\n", info.val ? "Present" : "Away"); > > > + break; > > > + default: > > > + return -1; > > > + } > > > + > > > + return 0; > > > +} > > > + > > > +static int pmf_get_custom_bios_input(unsigned int code) > > > +{ > > > + struct amd_pmf_ioctl_info info = {0}; > > > + int idx, ret; > > > + > > > + ret = pmf_get_data(code, &info); > > > + if (ret < 0) > > > + return ret; > > > + > > > + switch (code) { > > > + case IOCTL_BIOS_INPUT_1 ... IOCTL_BIOS_INPUT_10: > > > + idx = amd_pmf_get_bios_idx(code); > > > + printf("Custom BIOS input%u: %lu\n", idx + 1, > > > (int64_t)info.val); > > > > %lu is for printing unsigned long, not int64_t. > > > > > + break; > > > + default: > > > + return -1; > > > + } > > > + > > > + return 0; > > > +} > > > + > > > +static int pmf_get_bios_output(unsigned int code) > > > +{ > > > + struct amd_pmf_ioctl_info info = {0}; > > > + int idx, ret; > > > + > > > + ret = pmf_get_data(code, &info); > > > + if (ret < 0) > > > + return ret; > > > + > > > + switch (code) { > > > + case IOCTL_BIOS_OUTPUT_1 ... IOCTL_BIOS_OUTPUT_10: > > > + idx = amd_pmf_get_bios_idx(code); > > > + printf("BIOS output%u: %lu\n", idx + 1, (int64_t)info.val); > > > + break; > > > + default: > > > + return -1; > > > + } > > > + > > > + return 0; > > > +} > > > + > > > +static int pmf_get_misc_info(unsigned int code) > > > +{ > > > + struct amd_pmf_ioctl_info info = {0}; > > > + int ret; > > > + > > > + ret = pmf_get_data(code, &info); > > > + if (ret < 0) > > > + return ret; > > > + > > > + switch (code) { > > > + case IOCTL_POWER_SLIDER_POSITION: > > > + printf("Slider Position: %s\n", ta_slider_as_str(info.val)); > > > + break; > > > + case IOCTL_SKIN_TEMP: > > > + printf("Skin Temperature: %lu\n", (int64_t)info.val); > > > + break; > > > + case IOCTL_GFX_WORKLOAD: > > > + printf("GFX Busy: %lu\n", (int64_t)info.val); > > > + break; > > > + case IOCTL_AMBIENT_LIGHT: > > > + printf("Ambient Light: %ld\n", (int64_t)info.val); > > > + break; > > > + case IOCTL_AVG_C0_RES: > > > + printf("Avg C0 Residency: %lu\n", (int64_t)info.val); > > > + break; > > > + case IOCTL_MAX_C0_RES: > > > + printf("Max C0 Residency: %lu\n", (int64_t)info.val); > > > + break; > > > + case IOCTL_SOCKET_POWER: > > > + printf("Socket Power: %lu\n", (int64_t)info.val); > > > > Please think the printf formatting strings and types through. > > > > > + break; > > > + default: > > > + return -1; > > > + } > > > + > > > + return 0; > > > +} > > > + > > > +int main(void) > > > +{ > > > + unsigned int idx; > > > + > > > + printf("Feature Name Supported\n"); > > > + printf("---------------------------------\n"); > > > + for (idx = IOCTL_FEATURE_AUTO_MODE; idx <= > > > IOCTL_FEATURE_DYNAMIC_POWER_SLIDER_DC; idx++) > > > + pmf_get_feature_status(idx); > > > + > > > + printf("\nDevice State\n---------------\n"); > > > + for (idx = IOCTL_PLATFORM_TYPE; idx <= IOCTL_USER_PRESENCE; idx++) > > > + pmf_get_device_state(idx); > > > + > > > + printf("\nCustom BIOS Inputs\n-------------------\n"); > > > + for (idx = IOCTL_BIOS_INPUT_1; idx <= IOCTL_BIOS_INPUT_10; idx++) > > > + pmf_get_custom_bios_input(idx); > > > + > > > + printf("\nBIOS Outputs\n--------------\n"); > > > + for (idx = IOCTL_BIOS_OUTPUT_1; idx <= IOCTL_BIOS_OUTPUT_10; idx++) > > > + pmf_get_bios_output(idx); > > > + > > > + printf("\nMisc\n------\n"); > > > + pmf_get_misc_info(IOCTL_SKIN_TEMP); > > > + pmf_get_misc_info(IOCTL_GFX_WORKLOAD); > > > + pmf_get_misc_info(IOCTL_AMBIENT_LIGHT); > > > + pmf_get_misc_info(IOCTL_AVG_C0_RES); > > > + pmf_get_misc_info(IOCTL_MAX_C0_RES); > > > + pmf_get_misc_info(IOCTL_SOCKET_POWER); > > > + pmf_get_misc_info(IOCTL_POWER_SLIDER_POSITION); > > > + > > > + return 0; > > > +} > > > > > >
