* [PATCH v5 0/4] platform/x86/amd/hsmp: Family 1Ah client support
@ 2026-09-01 4:51 Muralidhara M K
2026-09-01 4:51 ` [PATCH v5 1/4] platform/x86/amd/hsmp: Add HSMP client support for Family 1Ah Muralidhara M K
` (4 more replies)
0 siblings, 5 replies; 10+ messages in thread
From: Muralidhara M K @ 2026-09-01 4:51 UTC (permalink / raw)
To: ilpo.jarvinen, Mario.Limonciello
Cc: platform-driver-x86, linux-kernel, Muralidhara M K
This series enables the HSMP driver on the Family 1Ah client platforms,
Models 80h-8Fh and E0h-E3h.
The client parts drive a different mailbox from the server HSMP
interface, but the latest BIOS describes it through ACPI _CRS/_DSD the
same way a server socket's mailbox is described, and the parts speak
the Ryzen Master SMC message set instead of the server message IDs.
Patches 1-3 teach the driver the message set and let the client reach
its mailbox through the existing _CRS/_DSD-driven MMIO path, leaving
server behaviour unchanged, and patch 4 includes the telemetry table
those parts return. Only the ACPI driver probes them.
Changes in v5:
- Patch 3: hsmp_pdev->proto_ver holds the Ryzen Master SMC interface
version on client platforms, a separate numbering space from the
server protocol versions in enum hsmp_proto_versions.
Changes in v4:
- SMU now answers the interface version query on client platforms,
so hsmp_desc_client.proto_ver_msg goes back to
HSMP_CLIENT_GET_INTERFACE_VER instead of
HSMP_CLIENT_GET_METRICS_TABLE_VER. Patch 3 is back down to just
the ACPI metric-table-DRAM-base change, since that was the only
other thing it did.
Changes in v3:
- is_client_platform() now tells client and server apart through the
ACPI-reported PM profile (FADT preferred_profile) instead of a
hardcoded Family 1Ah model range, the same signal amd-pstate
already keys off of. Future client generations are recognised as
long as firmware reports the right PM profile, with no driver
update needed.
- hsmp_desc() now resolves the running platform's descriptor once and
caches the pointer behind READ_ONCE()/WRITE_ONCE() instead of
recomputing it on every call. Concurrent first callers are benign,
since every one of them computes and stores that same pointer, so
the pair only needs to keep the load/store from being torn or
reordered by the compiler, not order it against anything else.
- The client message enum in amd_hsmp.h is now documented with
kernel-doc, one @member entry per message describing its inputs
and outputs, rather than a block comment plus a same-line comment
per enumerator. Noted there that not every platform supports every
message and that an unsupported one returns -ENOMSG.
- Patch 4: the Telemetry Table RM layout moved out of the .rst and
into amd_hsmp.h as real kernel-doc'd struct/enum declarations,
giving userspace one authoritative definition of the byte layout.
The .rst now just points at struct hsmp_telemetry_table_rm. The
structs are now also packed to a 4-byte boundary to match
firmware's actual layout, and the trailing NPU/PMF counters and
spare padding firmware carries after the overclocking fields are
no longer missing. Verified field-by-field against AMD's internal
metrics table header and end-to-end against a live snapshot off
Family 1Ah client hardware.
Each patch builds individually and is clean under checkpatch.pl.
Muralidhara M K (4):
platform/x86/amd/hsmp: Add HSMP client support for Family 1Ah
platform/x86/amd/hsmp: Route metric table through the client messages
platform/x86/amd/hsmp: Add ACPI client support for Family 1Ah
platform/x86/amd/hsmp: Document and expose client telemetry table in
UAPI
Documentation/arch/x86/amd_hsmp.rst | 24 +-
arch/x86/include/uapi/asm/amd_hsmp.h | 407 +++++++++++++++++++++++++++
drivers/platform/x86/amd/hsmp/acpi.c | 3 +-
drivers/platform/x86/amd/hsmp/hsmp.c | 269 +++++++++++++++---
drivers/platform/x86/amd/hsmp/hsmp.h | 27 ++
5 files changed, 696 insertions(+), 34 deletions(-)
base-commit: 08dbfad3f5040f5bdb6c529da20d6d4e81fefd72
--
2.34.1
^ permalink raw reply [flat|nested] 10+ messages in thread* [PATCH v5 1/4] platform/x86/amd/hsmp: Add HSMP client support for Family 1Ah 2026-09-01 4:51 [PATCH v5 0/4] platform/x86/amd/hsmp: Family 1Ah client support Muralidhara M K @ 2026-09-01 4:51 ` Muralidhara M K 2026-09-18 11:34 ` Ilpo Järvinen 2026-09-18 11:46 ` Ilpo Järvinen 2026-09-01 4:51 ` [PATCH v5 2/4] platform/x86/amd/hsmp: Route metric table through the client messages Muralidhara M K ` (3 subsequent siblings) 4 siblings, 2 replies; 10+ messages in thread From: Muralidhara M K @ 2026-09-01 4:51 UTC (permalink / raw) To: ilpo.jarvinen, Mario.Limonciello Cc: platform-driver-x86, linux-kernel, Muralidhara M K, Mario Limonciello Enable the HSMP driver on the Family 1Ah client platforms, Models 80h-8Fh and E0h-E3h. These parts speak the Ryzen Master SMC (RMSMC) message set instead of the server HSMP messages, but describe their mailbox via ACPI _CRS/_DSD the same way a server socket does, so only the ACPI driver needs to probe them. Add the client message set to the UAPI header and its descriptor table to the driver. struct hsmp_plat_desc picks the right table and driver-issued message IDs once per boot based on the ACPI-reported PM profile, which tells client and server apart without pinning the driver to a fixed set of family/model ranges. Document the client models in amd_hsmp.rst. Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com> Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org> --- Documentation/arch/x86/amd_hsmp.rst | 10 +- arch/x86/include/uapi/asm/amd_hsmp.h | 135 ++++++++++++++ drivers/platform/x86/amd/hsmp/hsmp.c | 255 ++++++++++++++++++++++++--- drivers/platform/x86/amd/hsmp/hsmp.h | 27 +++ 4 files changed, 398 insertions(+), 29 deletions(-) diff --git a/Documentation/arch/x86/amd_hsmp.rst b/Documentation/arch/x86/amd_hsmp.rst index fa1fc240e212..b95f09945193 100644 --- a/Documentation/arch/x86/amd_hsmp.rst +++ b/Documentation/arch/x86/amd_hsmp.rst @@ -8,6 +8,13 @@ Newer Fam19h(model 0x00-0x1f, 0x30-0x3f, 0x90-0x9f, 0xa0-0xaf), Fam1Ah(model 0x00-0x1f) EPYC server line of processors from AMD support system management functionality via HSMP (Host System Management Port). +The Fam1Ah(model 0x80-0x8f, 0xe0-0xe3) client line of processors is +supported as well. Those models share one mailbox and speak the Ryzen +Master SMC message set instead of the server HSMP message set, so the +message IDs accepted on them are the HSMP_CLIENT_* ones listed in +arch/x86/include/uapi/asm/amd_hsmp.h. The character device and ioctl +interface described below are the same. + The Host System Management Port (HSMP) is an interface to provide OS-level software with access to system management functions via a set of mailbox registers. @@ -17,7 +24,8 @@ More details on the interface can be found in chapter Eg: https://docs.amd.com/v/u/en-US/55898_B1_pub_0_50 -HSMP interface is supported on EPYC line of server CPUs and MI300A (APU). +HSMP interface is supported on EPYC line of server CPUs, MI300A (APU) and +the Fam1Ah client models listed above. HSMP device diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h index eda336bfd3e9..00ca7855ca00 100644 --- a/arch/x86/include/uapi/asm/amd_hsmp.h +++ b/arch/x86/include/uapi/asm/amd_hsmp.h @@ -664,4 +664,139 @@ struct hsmp_telemetry_data { #define HSMP_IOCTL_GET_TELEMETRY_DATA \ _IOW(HSMP_BASE_IOCTL_NR, 1, struct hsmp_telemetry_data) +/** + * enum hsmp_client_message_ids - Ryzen Master SMC (RMSMC) message IDs + * @HSMP_CLIENT_TEST: 01h. Test message. input: args[0] = xx. output: + * args[0] = xx + 1. + * @HSMP_CLIENT_GET_SMU_VER: 02h. Get MP1 firmware version. output: + * args[0] = MP1 firmware version. + * @HSMP_CLIENT_GET_INTERFACE_VER: 03h. Get interface version. output: + * args[0] = interface version. + * @HSMP_CLIENT_GET_METRICS_TABLE_VER: 04h. Get metrics table version. + * output: args[0] = metrics table version. + * @HSMP_CLIENT_GET_METRICS_TABLE: 05h. Get metrics table. No arguments. + * Success means firmware has written the metrics table to the DRAM + * address reported by @HSMP_CLIENT_GET_METRICS_TABLE_DRAM_ADDR. + * @HSMP_CLIENT_GET_METRICS_TABLE_DRAM_ADDR: 06h. Get metrics table DRAM + * address. output: args[0] = address[31:0], args[1] = address[63:32], + * args[2] = table size in bytes. + * @HSMP_CLIENT_SET_CORE_PSM_MARGIN: 07h. Set core voltage margin. input: + * args[0] = ApicId[31:16] + margin in mV[15:0]. + * @HSMP_CLIENT_SET_ALL_CORE_PSM_MARGIN: 08h. Set voltage margin for all + * cores. input: args[0] = margin in mV[15:0]. + * @HSMP_CLIENT_SET_FAST_PPT_LIMIT: 09h. Set APU fast PPT limit. input: + * args[0] = limit in mW. + * @HSMP_CLIENT_SET_VRM_VDD_CURRENT_LIMIT: 0Ah. Set VDDCR_VDD TDC. input: + * args[0] = limit in mA. + * @HSMP_CLIENT_SET_VRM_VDD_MAX_CURRENT_LIMIT: 0Bh. Set VDDCR_VDD EDC. + * input: args[0] = limit in mA. + * @HSMP_CLIENT_SET_TJ_MAX: 0Ch. Set maximum junction temperature. input: + * args[0] = temperature in degrees C. + * @HSMP_CLIENT_SET_FIT_LIMIT_SCALAR: 0Dh. Set failures-in-time limit + * scalar. input: args[0] = scalar (0 to 100). + * @HSMP_CLIENT_ENABLE_OVERCLOCKING: 0Eh. Enable overclocking. No + * arguments. + * @HSMP_CLIENT_DISABLE_OVERCLOCKING: 0Fh. Disable overclocking. No + * arguments. + * @HSMP_CLIENT_SET_OVERCLOCK_FREQ_ALL_CORES: 10h. Set all-core overclock + * frequency. input: args[0] = frequency in MHz[15:0]. + * @HSMP_CLIENT_SET_OVERCLOCK_FREQ_PER_CORE: 11h. Set per-core overclock + * frequency. input: args[0] = ApicId[31:16] + frequency in MHz[15:0]. + * @HSMP_CLIENT_SET_OVERCLOCK_VID: 12h. Set overclock VID. input: + * args[0] = voltage in mV[15:0]. + * @HSMP_CLIENT_SET_FCLK_OVERCLOCK_ON_THE_FLY: 13h. Set FCLK overclock on + * the fly. input: args[0] = FCLK in MHz[15:0]. + * @HSMP_CLIENT_GET_CORE_PERF_ORDER: 14h. Get core performance order. + * input: args[0] = ApicId[15:0]. output: args[0] = frequency in + * MHz[15:0]. + * @HSMP_CLIENT_SET_SUSTAINED_POWER_LIMIT: 15h. Set SOC sustained power + * limit. input: args[0] = limit in mW. + * @HSMP_CLIENT_SET_SLOW_PPT_LIMIT: 16h. Set APU slow PPT limit. input: + * args[0] = limit in mW. + * @HSMP_CLIENT_SET_VRM_GFX_MAX_CURRENT_LIMIT: 17h. Set VDDCR_GFX EDC. + * input: args[0] = limit in mA. + * @HSMP_CLIENT_SET_VRM_SOC_CURRENT_LIMIT: 18h. Set VDDCR_SOC TDC. input: + * args[0] = limit in mA. + * @HSMP_CLIENT_SET_FAST_SPM_LIMIT: 19h. Set fast SPM limit. input: + * args[0] = limit in mW. + * @HSMP_CLIENT_SET_SLOW_SPM_LIMIT: 1Ah. Set slow SPM limit. input: + * args[0] = limit in mW. + * @HSMP_CLIENT_GET_CORE_PSM_MARGIN: 1Bh. Get core voltage margin. input: + * args[0] = ApicId[15:0]. output: args[0] = margin in mV[15:0]. + * @HSMP_CLIENT_GET_GFX_PSM_MARGIN: 1Ch. Get graphics voltage margin. + * output: args[0] = margin in mV[15:0]. + * @HSMP_CLIENT_SPARE_0X1D: 1Dh. Reserved. + * @HSMP_CLIENT_SPARE_0X1E: 1Eh. Reserved. + * @HSMP_CLIENT_SPARE_0X1F: 1Fh. Reserved. + * @HSMP_CLIENT_SPARE_0X20: 20h. Reserved. + * @HSMP_CLIENT_SET_GFXCLK_OVERDRIVE_BY_FREQ_VID: 21h. Set GfxClk + * overdrive by frequency/VID. input: args[0] = frequency in + * MHz[31:16] + voltage in mV[15:0]. + * @HSMP_CLIENT_DISABLE_GFXCLK_OVERDRIVE: 22h. Disable GfxClk overdrive. + * No arguments. + * @HSMP_CLIENT_SET_GFX_PSM_MARGIN: 23h. Set graphics voltage margin. + * input: args[0] = margin in mV[15:0]. + * @HSMP_CLIENT_SET_CCLK_FMAX_OFFSET: 24h. Set CCLK Fmax offset. input: + * args[0] = maximum frequency in MHz[15:0]. + * @HSMP_CLIENT_SET_CORE_POWER_LIMIT_OFFSET: 25h. Set core power limit + * offset. input: args[0] = limit in mW. + * @HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND: 26h. Add extra core PSM + * guardband. input: args[0] = voltage in mV[15:0]. + * @HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND_GFX: 27h. Add extra graphics PSM + * guardband. input: args[0] = voltage in mV[15:0]. + * @HSMP_CLIENT_SET_GFXCLK_FMAX: 28h. Set GfxClk Fmax. input: args[0] = + * maximum frequency in MHz[15:0]. + * @HSMP_CLIENT_MSG_ID_MAX: Number of message IDs, not a valid ID itself. + * + * Message IDs accepted on the Family 1Ah client platforms, Models 80h-8Fh + * and E0h-E3h. These parts drive one mailbox and speak the Ryzen Master + * SMC message set instead of the server HSMP message set enumerated in + * &enum hsmp_message_ids. Not all platforms support all messages; consult + * the supported list of messages in the HSMP chapter of the respective + * family/model PPR. Unsupported messages return -ENOMSG. + */ +enum hsmp_client_message_ids { + HSMP_CLIENT_TEST = 1, + HSMP_CLIENT_GET_SMU_VER, + HSMP_CLIENT_GET_INTERFACE_VER, + HSMP_CLIENT_GET_METRICS_TABLE_VER, + HSMP_CLIENT_GET_METRICS_TABLE, + HSMP_CLIENT_GET_METRICS_TABLE_DRAM_ADDR, + HSMP_CLIENT_SET_CORE_PSM_MARGIN, + HSMP_CLIENT_SET_ALL_CORE_PSM_MARGIN, + HSMP_CLIENT_SET_FAST_PPT_LIMIT, + HSMP_CLIENT_SET_VRM_VDD_CURRENT_LIMIT, + HSMP_CLIENT_SET_VRM_VDD_MAX_CURRENT_LIMIT, + HSMP_CLIENT_SET_TJ_MAX, + HSMP_CLIENT_SET_FIT_LIMIT_SCALAR, + HSMP_CLIENT_ENABLE_OVERCLOCKING, + HSMP_CLIENT_DISABLE_OVERCLOCKING, + HSMP_CLIENT_SET_OVERCLOCK_FREQ_ALL_CORES, + HSMP_CLIENT_SET_OVERCLOCK_FREQ_PER_CORE, + HSMP_CLIENT_SET_OVERCLOCK_VID, + HSMP_CLIENT_SET_FCLK_OVERCLOCK_ON_THE_FLY, + HSMP_CLIENT_GET_CORE_PERF_ORDER, + HSMP_CLIENT_SET_SUSTAINED_POWER_LIMIT, + HSMP_CLIENT_SET_SLOW_PPT_LIMIT, + HSMP_CLIENT_SET_VRM_GFX_MAX_CURRENT_LIMIT, + HSMP_CLIENT_SET_VRM_SOC_CURRENT_LIMIT, + HSMP_CLIENT_SET_FAST_SPM_LIMIT, + HSMP_CLIENT_SET_SLOW_SPM_LIMIT, + HSMP_CLIENT_GET_CORE_PSM_MARGIN, + HSMP_CLIENT_GET_GFX_PSM_MARGIN, + HSMP_CLIENT_SPARE_0X1D, + HSMP_CLIENT_SPARE_0X1E, + HSMP_CLIENT_SPARE_0X1F, + HSMP_CLIENT_SPARE_0X20, + HSMP_CLIENT_SET_GFXCLK_OVERDRIVE_BY_FREQ_VID, + HSMP_CLIENT_DISABLE_GFXCLK_OVERDRIVE, + HSMP_CLIENT_SET_GFX_PSM_MARGIN, + HSMP_CLIENT_SET_CCLK_FMAX_OFFSET, + HSMP_CLIENT_SET_CORE_POWER_LIMIT_OFFSET, + HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND, + HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND_GFX, + HSMP_CLIENT_SET_GFXCLK_FMAX, + HSMP_CLIENT_MSG_ID_MAX, +}; + #endif /*_ASM_X86_AMD_HSMP_H_*/ diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c index 5e123a4ecea9..e8fac2d299f3 100644 --- a/drivers/platform/x86/amd/hsmp/hsmp.c +++ b/drivers/platform/x86/amd/hsmp/hsmp.c @@ -10,6 +10,8 @@ #include <asm/amd/hsmp.h> #include <linux/acpi.h> +#include <linux/array_size.h> +#include <linux/build_bug.h> #include <linux/cleanup.h> #include <linux/delay.h> #include <linux/device.h> @@ -45,8 +47,197 @@ */ #define CHECK_GET_BIT BIT(31) +/* Indexed by enum hsmp_client_message_ids; see there for per-message details */ +static const struct hsmp_msg_desc hsmp_client_msg_desc_table[] = { + /* RESERVED */ + {0, 0, HSMP_RSVD}, + + /* HSMP_CLIENT_TEST */ + {1, 1, HSMP_GET}, + + /* HSMP_CLIENT_GET_SMU_VER */ + {0, 1, HSMP_GET}, + + /* HSMP_CLIENT_GET_INTERFACE_VER */ + {0, 1, HSMP_GET}, + + /* HSMP_CLIENT_GET_METRICS_TABLE_VER */ + {0, 1, HSMP_GET}, + + /* HSMP_CLIENT_GET_METRICS_TABLE */ + {0, 0, HSMP_GET}, + + /* HSMP_CLIENT_GET_METRICS_TABLE_DRAM_ADDR */ + {0, 3, HSMP_GET}, + + /* HSMP_CLIENT_SET_CORE_PSM_MARGIN */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_ALL_CORE_PSM_MARGIN */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_FAST_PPT_LIMIT */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_VRM_VDD_CURRENT_LIMIT */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_VRM_VDD_MAX_CURRENT_LIMIT */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_TJ_MAX */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_FIT_LIMIT_SCALAR */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_ENABLE_OVERCLOCKING */ + {0, 0, HSMP_SET}, + + /* HSMP_CLIENT_DISABLE_OVERCLOCKING */ + {0, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_OVERCLOCK_FREQ_ALL_CORES */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_OVERCLOCK_FREQ_PER_CORE */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_OVERCLOCK_VID */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_FCLK_OVERCLOCK_ON_THE_FLY */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_GET_CORE_PERF_ORDER */ + {1, 1, HSMP_GET}, + + /* HSMP_CLIENT_SET_SUSTAINED_POWER_LIMIT */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_SLOW_PPT_LIMIT */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_VRM_GFX_MAX_CURRENT_LIMIT */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_VRM_SOC_CURRENT_LIMIT */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_FAST_SPM_LIMIT */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_SLOW_SPM_LIMIT */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_GET_CORE_PSM_MARGIN */ + {1, 1, HSMP_GET}, + + /* HSMP_CLIENT_GET_GFX_PSM_MARGIN */ + {0, 1, HSMP_GET}, + + /* HSMP_CLIENT_SPARE_0X1D */ + {0, 0, HSMP_RSVD}, + + /* HSMP_CLIENT_SPARE_0X1E */ + {0, 0, HSMP_RSVD}, + + /* HSMP_CLIENT_SPARE_0X1F */ + {0, 0, HSMP_RSVD}, + + /* HSMP_CLIENT_SPARE_0X20 */ + {0, 0, HSMP_RSVD}, + + /* HSMP_CLIENT_SET_GFXCLK_OVERDRIVE_BY_FREQ_VID */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_DISABLE_GFXCLK_OVERDRIVE */ + {0, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_GFX_PSM_MARGIN */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_CCLK_FMAX_OFFSET */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_CORE_POWER_LIMIT_OFFSET */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND_GFX */ + {1, 0, HSMP_SET}, + + /* HSMP_CLIENT_SET_GFXCLK_FMAX */ + {1, 0, HSMP_SET}, +}; + +/* Catch a table left out of sync with its enum at build time */ +static_assert(ARRAY_SIZE(hsmp_msg_desc_table) == HSMP_MSG_ID_MAX); +static_assert(ARRAY_SIZE(hsmp_client_msg_desc_table) == HSMP_CLIENT_MSG_ID_MAX); + +/* Per-platform message set: which table to use, and driver-issued msg IDs */ +struct hsmp_plat_desc { + const struct hsmp_msg_desc *msg_desc; + u32 num_msgs; + u32 test_msg; + u32 proto_ver_msg; +}; + +static const struct hsmp_plat_desc hsmp_desc_server = { + .msg_desc = hsmp_msg_desc_table, + .num_msgs = HSMP_MSG_ID_MAX, + .test_msg = HSMP_TEST, + .proto_ver_msg = HSMP_GET_PROTO_VER, +}; + +/* The client drives a different mailbox with the Ryzen Master SMC message set */ +static const struct hsmp_plat_desc hsmp_desc_client = { + .msg_desc = hsmp_client_msg_desc_table, + .num_msgs = HSMP_CLIENT_MSG_ID_MAX, + .test_msg = HSMP_CLIENT_TEST, + .proto_ver_msg = HSMP_CLIENT_GET_INTERFACE_VER, +}; + static struct hsmp_plat_device hsmp_pdev; +/* + * Resolved on first use and cached, since is_client_platform() always + * settles on the same descriptor once booted. Concurrent first callers are + * benign: every one of them computes and stores that same pointer, so + * READ_ONCE()/WRITE_ONCE() only need to keep the access from being torn or + * reordered by the compiler, not order it against anything else. + */ +static const struct hsmp_plat_desc *hsmp_desc_cache; + +static inline const struct hsmp_plat_desc *hsmp_desc(void) +{ + const struct hsmp_plat_desc *desc = READ_ONCE(hsmp_desc_cache); + + if (likely(desc)) + return desc; + + desc = is_client_platform() ? &hsmp_desc_client : &hsmp_desc_server; + WRITE_ONCE(hsmp_desc_cache, desc); + + return desc; +} + +/* Returns NULL if msg_id is out of range or reserved for this platform */ +static inline const struct hsmp_msg_desc *get_msg_desc(u32 msg_id) +{ + const struct hsmp_plat_desc *desc = hsmp_desc(); + + if (msg_id >= desc->num_msgs) + return NULL; + + if (desc->msg_desc[msg_id].type == HSMP_RSVD) + return NULL; + + return &desc->msg_desc[msg_id]; +} + /* * Gates the AMD HSMP data plane against socket bring-up and teardown. * @@ -184,30 +375,29 @@ static int __hsmp_send_message(struct hsmp_socket *sock, struct hsmp_message *ms static int validate_message(struct hsmp_message *msg) { - /* msg_id against valid range of message IDs */ - if (msg->msg_id < HSMP_TEST || msg->msg_id >= HSMP_MSG_ID_MAX) - return -ENOMSG; + const struct hsmp_msg_desc *desc; - /* msg_id is a reserved message ID */ - if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_RSVD) + /* Unknown or reserved message ID for this platform */ + desc = get_msg_desc(msg->msg_id); + if (!desc) return -ENOMSG; /* * num_args passed by user should match the num_args specified in * message description table. */ - if (msg->num_args != hsmp_msg_desc_table[msg->msg_id].num_args) + if (msg->num_args != desc->num_args) return -EINVAL; /* * As the HSMP protocol evolves, newer platforms may define more * response arguments for existing messages. Use an upper-bound * check so that older userspace callers requesting fewer response - * words than what the current hsmp_msg_desc_table[] defines are - * still accepted, while rejecting requests that exceed the - * hardware capability. + * words than what the current descriptor table defines are still + * accepted, while rejecting requests that exceed the hardware + * capability. */ - if (msg->response_sz > hsmp_msg_desc_table[msg->msg_id].response_sz) + if (msg->response_sz > desc->response_sz) return -EINVAL; return 0; @@ -316,7 +506,7 @@ int hsmp_test(u16 sock_ind, u32 value) * Test the hsmp port by performing TEST command. The test message * takes one argument and returns the value of that argument + 1. */ - msg.msg_id = HSMP_TEST; + msg.msg_id = hsmp_desc()->test_msg; msg.num_args = 1; msg.response_sz = 1; msg.args[0] = value; @@ -338,12 +528,12 @@ int hsmp_test(u16 sock_ind, u32 value) } EXPORT_SYMBOL_NS_GPL(hsmp_test, "AMD_HSMP"); -static bool is_get_msg(struct hsmp_message *msg) +static bool is_get_msg(const struct hsmp_msg_desc *desc, struct hsmp_message *msg) { - if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_GET) + if (desc->type == HSMP_GET) return true; - if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_SET_GET && + if (desc->type == HSMP_SET_GET && (msg->args[0] & CHECK_GET_BIT)) return true; @@ -354,6 +544,8 @@ static long hsmp_ioctl_msg(struct file *fp, unsigned long arg) { int __user *arguser = (int __user *)arg; struct hsmp_message msg = { 0 }; + const struct hsmp_plat_desc *plat_desc = hsmp_desc(); + const struct hsmp_msg_desc *desc; int ret; if (copy_struct_from_user(&msg, sizeof(msg), arguser, sizeof(struct hsmp_message))) @@ -361,23 +553,25 @@ static long hsmp_ioctl_msg(struct file *fp, unsigned long arg) /* * Check msg_id is within the range of supported msg ids - * i.e within the array bounds of hsmp_msg_desc_table + * i.e within the array bounds of the platform's descriptor table */ - if (msg.msg_id < HSMP_TEST || msg.msg_id >= HSMP_MSG_ID_MAX) + if (msg.msg_id < plat_desc->test_msg || msg.msg_id >= plat_desc->num_msgs) return -ENOMSG; /* * Sanitize the user-controlled msg_id against speculative * execution. The bounds check above retires the out-of-range * case with -ENOMSG, but a mispredicted branch can still let the - * CPU speculatively use msg_id as an index into - * hsmp_msg_desc_table[] (here and in validate_message() / - * is_get_msg() called downstream via hsmp_send_message()), and - * pull arbitrary kernel memory into the cache (Spectre v1, - * CVE-2017-5753). Clamp once into msg.msg_id so every downstream - * dereference sees the sanitized value. + * CPU speculatively use msg_id as an index into the message + * descriptor table, here and again in validate_message() called + * downstream via hsmp_send_message(). */ - msg.msg_id = array_index_nospec(msg.msg_id, HSMP_MSG_ID_MAX); + msg.msg_id = array_index_nospec(msg.msg_id, plat_desc->num_msgs); + + /* Rejects the reserved IDs the table describes as such */ + desc = get_msg_desc(msg.msg_id); + if (!desc) + return -ENOMSG; switch (fp->f_mode & (FMODE_WRITE | FMODE_READ)) { case FMODE_WRITE: @@ -385,7 +579,7 @@ static long hsmp_ioctl_msg(struct file *fp, unsigned long arg) * Device is opened in O_WRONLY mode * Execute only set/configure commands */ - if (is_get_msg(&msg)) + if (is_get_msg(desc, &msg)) return -EPERM; break; case FMODE_READ: @@ -393,7 +587,7 @@ static long hsmp_ioctl_msg(struct file *fp, unsigned long arg) * Device is opened in O_RDONLY mode * Execute only get/monitor commands */ - if (!is_get_msg(&msg)) + if (!is_get_msg(desc, &msg)) return -EPERM; break; case FMODE_READ | FMODE_WRITE: @@ -410,7 +604,7 @@ static long hsmp_ioctl_msg(struct file *fp, unsigned long arg) if (ret) return ret; - if (hsmp_msg_desc_table[msg.msg_id].response_sz > 0) { + if (desc->response_sz > 0) { /* Copy results back to user for get/monitor commands */ if (copy_to_user(arguser, &msg, sizeof(struct hsmp_message))) return -EFAULT; @@ -685,11 +879,16 @@ EXPORT_SYMBOL_NS_GPL(hsmp_get_tbl_dram_base, "AMD_HSMP"); int hsmp_cache_proto_ver(u16 sock_ind) { struct hsmp_message msg = { 0 }; + const struct hsmp_msg_desc *desc; int ret; - msg.msg_id = HSMP_GET_PROTO_VER; + msg.msg_id = hsmp_desc()->proto_ver_msg; + desc = get_msg_desc(msg.msg_id); + if (WARN_ON(!desc)) + return -ENOMSG; + msg.sock_ind = sock_ind; - msg.response_sz = hsmp_msg_desc_table[HSMP_GET_PROTO_VER].response_sz; + msg.response_sz = desc->response_sz; ret = hsmp_send_message_locked(&msg); if (!ret) diff --git a/drivers/platform/x86/amd/hsmp/hsmp.h b/drivers/platform/x86/amd/hsmp/hsmp.h index 8dbff16a87b1..890cfb664829 100644 --- a/drivers/platform/x86/amd/hsmp/hsmp.h +++ b/drivers/platform/x86/amd/hsmp/hsmp.h @@ -10,6 +10,9 @@ #ifndef HSMP_H #define HSMP_H +#include <asm/amd/hsmp.h> + +#include <linux/acpi.h> #include <linux/compiler_types.h> #include <linux/device.h> #include <linux/hwmon.h> @@ -17,6 +20,7 @@ #include <linux/miscdevice.h> #include <linux/mutex.h> #include <linux/pci.h> +#include <linux/processor.h> #include <linux/rwsem.h> #include <linux/semaphore.h> #include <linux/sysfs.h> @@ -32,6 +36,29 @@ #define DRIVER_VERSION "2.6" +/* + * Family/model ranges need a driver update every generation and miss new + * client parts until then. The ACPI-reported PM profile does not: it says + * what kind of system this is regardless of which CPU is in it. + */ +static inline bool is_client_platform(void) +{ + if (!IS_ENABLED(CONFIG_ACPI)) + return false; + + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) + return false; + + switch (acpi_gbl_FADT.preferred_profile) { + case PM_DESKTOP: + case PM_MOBILE: + case PM_TABLET: + return true; + default: + return false; + } +} + struct hsmp_mbaddr_info { u32 base_addr; u32 msg_id_off; -- 2.34.1 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v5 1/4] platform/x86/amd/hsmp: Add HSMP client support for Family 1Ah 2026-09-01 4:51 ` [PATCH v5 1/4] platform/x86/amd/hsmp: Add HSMP client support for Family 1Ah Muralidhara M K @ 2026-09-18 11:34 ` Ilpo Järvinen 2026-09-18 11:46 ` Ilpo Järvinen 1 sibling, 0 replies; 10+ messages in thread From: Ilpo Järvinen @ 2026-09-18 11:34 UTC (permalink / raw) To: Muralidhara M K Cc: Mario.Limonciello, platform-driver-x86, LKML, Mario Limonciello On Tue, 1 Sep 2026, Muralidhara M K wrote: > Enable the HSMP driver on the Family 1Ah client platforms, Models > 80h-8Fh and E0h-E3h. These parts speak the Ryzen Master SMC (RMSMC) > message set instead of the server HSMP messages, but describe their > mailbox via ACPI _CRS/_DSD the same way a server socket does, so only > the ACPI driver needs to probe them. > > Add the client message set to the UAPI header and its descriptor > table to the driver. struct hsmp_plat_desc picks the right table and > driver-issued message IDs once per boot based on the ACPI-reported PM > profile, which tells client and server apart without pinning the > driver to a fixed set of family/model ranges. Document the client > models in amd_hsmp.rst. > > Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com> > Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org> > --- > Documentation/arch/x86/amd_hsmp.rst | 10 +- > arch/x86/include/uapi/asm/amd_hsmp.h | 135 ++++++++++++++ > drivers/platform/x86/amd/hsmp/hsmp.c | 255 ++++++++++++++++++++++++--- > drivers/platform/x86/amd/hsmp/hsmp.h | 27 +++ > 4 files changed, 398 insertions(+), 29 deletions(-) > > diff --git a/Documentation/arch/x86/amd_hsmp.rst b/Documentation/arch/x86/amd_hsmp.rst > index fa1fc240e212..b95f09945193 100644 > --- a/Documentation/arch/x86/amd_hsmp.rst > +++ b/Documentation/arch/x86/amd_hsmp.rst > @@ -8,6 +8,13 @@ Newer Fam19h(model 0x00-0x1f, 0x30-0x3f, 0x90-0x9f, 0xa0-0xaf), > Fam1Ah(model 0x00-0x1f) EPYC server line of processors from AMD support > system management functionality via HSMP (Host System Management Port). > > +The Fam1Ah(model 0x80-0x8f, 0xe0-0xe3) client line of processors is > +supported as well. Those models share one mailbox and speak the Ryzen > +Master SMC message set instead of the server HSMP message set, so the > +message IDs accepted on them are the HSMP_CLIENT_* ones listed in > +arch/x86/include/uapi/asm/amd_hsmp.h. The character device and ioctl > +interface described below are the same. > + > The Host System Management Port (HSMP) is an interface to provide > OS-level software with access to system management functions via a > set of mailbox registers. > @@ -17,7 +24,8 @@ More details on the interface can be found in chapter > Eg: https://docs.amd.com/v/u/en-US/55898_B1_pub_0_50 > > > -HSMP interface is supported on EPYC line of server CPUs and MI300A (APU). > +HSMP interface is supported on EPYC line of server CPUs, MI300A (APU) and > +the Fam1Ah client models listed above. > > > HSMP device > diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h > index eda336bfd3e9..00ca7855ca00 100644 > --- a/arch/x86/include/uapi/asm/amd_hsmp.h > +++ b/arch/x86/include/uapi/asm/amd_hsmp.h > @@ -664,4 +664,139 @@ struct hsmp_telemetry_data { > #define HSMP_IOCTL_GET_TELEMETRY_DATA \ > _IOW(HSMP_BASE_IOCTL_NR, 1, struct hsmp_telemetry_data) > > +/** > + * enum hsmp_client_message_ids - Ryzen Master SMC (RMSMC) message IDs > + * @HSMP_CLIENT_TEST: 01h. Test message. input: args[0] = xx. output: > + * args[0] = xx + 1. > + * @HSMP_CLIENT_GET_SMU_VER: 02h. Get MP1 firmware version. output: > + * args[0] = MP1 firmware version. > + * @HSMP_CLIENT_GET_INTERFACE_VER: 03h. Get interface version. output: > + * args[0] = interface version. > + * @HSMP_CLIENT_GET_METRICS_TABLE_VER: 04h. Get metrics table version. > + * output: args[0] = metrics table version. > + * @HSMP_CLIENT_GET_METRICS_TABLE: 05h. Get metrics table. No arguments. > + * Success means firmware has written the metrics table to the DRAM > + * address reported by @HSMP_CLIENT_GET_METRICS_TABLE_DRAM_ADDR. > + * @HSMP_CLIENT_GET_METRICS_TABLE_DRAM_ADDR: 06h. Get metrics table DRAM > + * address. output: args[0] = address[31:0], args[1] = address[63:32], > + * args[2] = table size in bytes. > + * @HSMP_CLIENT_SET_CORE_PSM_MARGIN: 07h. Set core voltage margin. input: > + * args[0] = ApicId[31:16] + margin in mV[15:0]. > + * @HSMP_CLIENT_SET_ALL_CORE_PSM_MARGIN: 08h. Set voltage margin for all > + * cores. input: args[0] = margin in mV[15:0]. > + * @HSMP_CLIENT_SET_FAST_PPT_LIMIT: 09h. Set APU fast PPT limit. input: > + * args[0] = limit in mW. > + * @HSMP_CLIENT_SET_VRM_VDD_CURRENT_LIMIT: 0Ah. Set VDDCR_VDD TDC. input: > + * args[0] = limit in mA. > + * @HSMP_CLIENT_SET_VRM_VDD_MAX_CURRENT_LIMIT: 0Bh. Set VDDCR_VDD EDC. > + * input: args[0] = limit in mA. > + * @HSMP_CLIENT_SET_TJ_MAX: 0Ch. Set maximum junction temperature. input: > + * args[0] = temperature in degrees C. > + * @HSMP_CLIENT_SET_FIT_LIMIT_SCALAR: 0Dh. Set failures-in-time limit > + * scalar. input: args[0] = scalar (0 to 100). > + * @HSMP_CLIENT_ENABLE_OVERCLOCKING: 0Eh. Enable overclocking. No > + * arguments. > + * @HSMP_CLIENT_DISABLE_OVERCLOCKING: 0Fh. Disable overclocking. No > + * arguments. > + * @HSMP_CLIENT_SET_OVERCLOCK_FREQ_ALL_CORES: 10h. Set all-core overclock > + * frequency. input: args[0] = frequency in MHz[15:0]. > + * @HSMP_CLIENT_SET_OVERCLOCK_FREQ_PER_CORE: 11h. Set per-core overclock > + * frequency. input: args[0] = ApicId[31:16] + frequency in MHz[15:0]. > + * @HSMP_CLIENT_SET_OVERCLOCK_VID: 12h. Set overclock VID. input: > + * args[0] = voltage in mV[15:0]. > + * @HSMP_CLIENT_SET_FCLK_OVERCLOCK_ON_THE_FLY: 13h. Set FCLK overclock on > + * the fly. input: args[0] = FCLK in MHz[15:0]. > + * @HSMP_CLIENT_GET_CORE_PERF_ORDER: 14h. Get core performance order. > + * input: args[0] = ApicId[15:0]. output: args[0] = frequency in > + * MHz[15:0]. > + * @HSMP_CLIENT_SET_SUSTAINED_POWER_LIMIT: 15h. Set SOC sustained power > + * limit. input: args[0] = limit in mW. > + * @HSMP_CLIENT_SET_SLOW_PPT_LIMIT: 16h. Set APU slow PPT limit. input: > + * args[0] = limit in mW. > + * @HSMP_CLIENT_SET_VRM_GFX_MAX_CURRENT_LIMIT: 17h. Set VDDCR_GFX EDC. > + * input: args[0] = limit in mA. > + * @HSMP_CLIENT_SET_VRM_SOC_CURRENT_LIMIT: 18h. Set VDDCR_SOC TDC. input: > + * args[0] = limit in mA. > + * @HSMP_CLIENT_SET_FAST_SPM_LIMIT: 19h. Set fast SPM limit. input: > + * args[0] = limit in mW. > + * @HSMP_CLIENT_SET_SLOW_SPM_LIMIT: 1Ah. Set slow SPM limit. input: > + * args[0] = limit in mW. > + * @HSMP_CLIENT_GET_CORE_PSM_MARGIN: 1Bh. Get core voltage margin. input: > + * args[0] = ApicId[15:0]. output: args[0] = margin in mV[15:0]. > + * @HSMP_CLIENT_GET_GFX_PSM_MARGIN: 1Ch. Get graphics voltage margin. > + * output: args[0] = margin in mV[15:0]. > + * @HSMP_CLIENT_SPARE_0X1D: 1Dh. Reserved. > + * @HSMP_CLIENT_SPARE_0X1E: 1Eh. Reserved. > + * @HSMP_CLIENT_SPARE_0X1F: 1Fh. Reserved. > + * @HSMP_CLIENT_SPARE_0X20: 20h. Reserved. > + * @HSMP_CLIENT_SET_GFXCLK_OVERDRIVE_BY_FREQ_VID: 21h. Set GfxClk > + * overdrive by frequency/VID. input: args[0] = frequency in > + * MHz[31:16] + voltage in mV[15:0]. > + * @HSMP_CLIENT_DISABLE_GFXCLK_OVERDRIVE: 22h. Disable GfxClk overdrive. > + * No arguments. > + * @HSMP_CLIENT_SET_GFX_PSM_MARGIN: 23h. Set graphics voltage margin. > + * input: args[0] = margin in mV[15:0]. > + * @HSMP_CLIENT_SET_CCLK_FMAX_OFFSET: 24h. Set CCLK Fmax offset. input: > + * args[0] = maximum frequency in MHz[15:0]. > + * @HSMP_CLIENT_SET_CORE_POWER_LIMIT_OFFSET: 25h. Set core power limit > + * offset. input: args[0] = limit in mW. > + * @HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND: 26h. Add extra core PSM > + * guardband. input: args[0] = voltage in mV[15:0]. > + * @HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND_GFX: 27h. Add extra graphics PSM > + * guardband. input: args[0] = voltage in mV[15:0]. > + * @HSMP_CLIENT_SET_GFXCLK_FMAX: 28h. Set GfxClk Fmax. input: args[0] = > + * maximum frequency in MHz[15:0]. > + * @HSMP_CLIENT_MSG_ID_MAX: Number of message IDs, not a valid ID itself. > + * > + * Message IDs accepted on the Family 1Ah client platforms, Models 80h-8Fh > + * and E0h-E3h. These parts drive one mailbox and speak the Ryzen Master > + * SMC message set instead of the server HSMP message set enumerated in > + * &enum hsmp_message_ids. Not all platforms support all messages; consult > + * the supported list of messages in the HSMP chapter of the respective > + * family/model PPR. Unsupported messages return -ENOMSG. > + */ > +enum hsmp_client_message_ids { > + HSMP_CLIENT_TEST = 1, > + HSMP_CLIENT_GET_SMU_VER, > + HSMP_CLIENT_GET_INTERFACE_VER, > + HSMP_CLIENT_GET_METRICS_TABLE_VER, > + HSMP_CLIENT_GET_METRICS_TABLE, > + HSMP_CLIENT_GET_METRICS_TABLE_DRAM_ADDR, > + HSMP_CLIENT_SET_CORE_PSM_MARGIN, > + HSMP_CLIENT_SET_ALL_CORE_PSM_MARGIN, > + HSMP_CLIENT_SET_FAST_PPT_LIMIT, > + HSMP_CLIENT_SET_VRM_VDD_CURRENT_LIMIT, > + HSMP_CLIENT_SET_VRM_VDD_MAX_CURRENT_LIMIT, > + HSMP_CLIENT_SET_TJ_MAX, > + HSMP_CLIENT_SET_FIT_LIMIT_SCALAR, > + HSMP_CLIENT_ENABLE_OVERCLOCKING, > + HSMP_CLIENT_DISABLE_OVERCLOCKING, > + HSMP_CLIENT_SET_OVERCLOCK_FREQ_ALL_CORES, > + HSMP_CLIENT_SET_OVERCLOCK_FREQ_PER_CORE, > + HSMP_CLIENT_SET_OVERCLOCK_VID, > + HSMP_CLIENT_SET_FCLK_OVERCLOCK_ON_THE_FLY, > + HSMP_CLIENT_GET_CORE_PERF_ORDER, > + HSMP_CLIENT_SET_SUSTAINED_POWER_LIMIT, > + HSMP_CLIENT_SET_SLOW_PPT_LIMIT, > + HSMP_CLIENT_SET_VRM_GFX_MAX_CURRENT_LIMIT, > + HSMP_CLIENT_SET_VRM_SOC_CURRENT_LIMIT, > + HSMP_CLIENT_SET_FAST_SPM_LIMIT, > + HSMP_CLIENT_SET_SLOW_SPM_LIMIT, > + HSMP_CLIENT_GET_CORE_PSM_MARGIN, > + HSMP_CLIENT_GET_GFX_PSM_MARGIN, > + HSMP_CLIENT_SPARE_0X1D, > + HSMP_CLIENT_SPARE_0X1E, > + HSMP_CLIENT_SPARE_0X1F, > + HSMP_CLIENT_SPARE_0X20, > + HSMP_CLIENT_SET_GFXCLK_OVERDRIVE_BY_FREQ_VID, > + HSMP_CLIENT_DISABLE_GFXCLK_OVERDRIVE, > + HSMP_CLIENT_SET_GFX_PSM_MARGIN, > + HSMP_CLIENT_SET_CCLK_FMAX_OFFSET, > + HSMP_CLIENT_SET_CORE_POWER_LIMIT_OFFSET, > + HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND, > + HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND_GFX, > + HSMP_CLIENT_SET_GFXCLK_FMAX, > + HSMP_CLIENT_MSG_ID_MAX, > +}; > + > #endif /*_ASM_X86_AMD_HSMP_H_*/ > diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c > index 5e123a4ecea9..e8fac2d299f3 100644 > --- a/drivers/platform/x86/amd/hsmp/hsmp.c > +++ b/drivers/platform/x86/amd/hsmp/hsmp.c > @@ -10,6 +10,8 @@ > #include <asm/amd/hsmp.h> > > #include <linux/acpi.h> > +#include <linux/array_size.h> > +#include <linux/build_bug.h> > #include <linux/cleanup.h> > #include <linux/delay.h> > #include <linux/device.h> > @@ -45,8 +47,197 @@ > */ > #define CHECK_GET_BIT BIT(31) > > +/* Indexed by enum hsmp_client_message_ids; see there for per-message details */ > +static const struct hsmp_msg_desc hsmp_client_msg_desc_table[] = { > + /* RESERVED */ > + {0, 0, HSMP_RSVD}, > + > + /* HSMP_CLIENT_TEST */ > + {1, 1, HSMP_GET}, > + > + /* HSMP_CLIENT_GET_SMU_VER */ > + {0, 1, HSMP_GET}, > + > + /* HSMP_CLIENT_GET_INTERFACE_VER */ > + {0, 1, HSMP_GET}, > + > + /* HSMP_CLIENT_GET_METRICS_TABLE_VER */ > + {0, 1, HSMP_GET}, > + > + /* HSMP_CLIENT_GET_METRICS_TABLE */ > + {0, 0, HSMP_GET}, > + > + /* HSMP_CLIENT_GET_METRICS_TABLE_DRAM_ADDR */ > + {0, 3, HSMP_GET}, > + > + /* HSMP_CLIENT_SET_CORE_PSM_MARGIN */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_ALL_CORE_PSM_MARGIN */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_FAST_PPT_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_VRM_VDD_CURRENT_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_VRM_VDD_MAX_CURRENT_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_TJ_MAX */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_FIT_LIMIT_SCALAR */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_ENABLE_OVERCLOCKING */ > + {0, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_DISABLE_OVERCLOCKING */ > + {0, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_OVERCLOCK_FREQ_ALL_CORES */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_OVERCLOCK_FREQ_PER_CORE */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_OVERCLOCK_VID */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_FCLK_OVERCLOCK_ON_THE_FLY */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_GET_CORE_PERF_ORDER */ > + {1, 1, HSMP_GET}, > + > + /* HSMP_CLIENT_SET_SUSTAINED_POWER_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_SLOW_PPT_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_VRM_GFX_MAX_CURRENT_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_VRM_SOC_CURRENT_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_FAST_SPM_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_SLOW_SPM_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_GET_CORE_PSM_MARGIN */ > + {1, 1, HSMP_GET}, > + > + /* HSMP_CLIENT_GET_GFX_PSM_MARGIN */ > + {0, 1, HSMP_GET}, > + > + /* HSMP_CLIENT_SPARE_0X1D */ > + {0, 0, HSMP_RSVD}, > + > + /* HSMP_CLIENT_SPARE_0X1E */ > + {0, 0, HSMP_RSVD}, > + > + /* HSMP_CLIENT_SPARE_0X1F */ > + {0, 0, HSMP_RSVD}, > + > + /* HSMP_CLIENT_SPARE_0X20 */ > + {0, 0, HSMP_RSVD}, > + > + /* HSMP_CLIENT_SET_GFXCLK_OVERDRIVE_BY_FREQ_VID */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_DISABLE_GFXCLK_OVERDRIVE */ > + {0, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_GFX_PSM_MARGIN */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_CCLK_FMAX_OFFSET */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_CORE_POWER_LIMIT_OFFSET */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND_GFX */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_GFXCLK_FMAX */ > + {1, 0, HSMP_SET}, > +}; > + > +/* Catch a table left out of sync with its enum at build time */ > +static_assert(ARRAY_SIZE(hsmp_msg_desc_table) == HSMP_MSG_ID_MAX); > +static_assert(ARRAY_SIZE(hsmp_client_msg_desc_table) == HSMP_CLIENT_MSG_ID_MAX); > + > +/* Per-platform message set: which table to use, and driver-issued msg IDs */ > +struct hsmp_plat_desc { > + const struct hsmp_msg_desc *msg_desc; > + u32 num_msgs; > + u32 test_msg; > + u32 proto_ver_msg; > +}; > + > +static const struct hsmp_plat_desc hsmp_desc_server = { > + .msg_desc = hsmp_msg_desc_table, > + .num_msgs = HSMP_MSG_ID_MAX, > + .test_msg = HSMP_TEST, > + .proto_ver_msg = HSMP_GET_PROTO_VER, > +}; > + > +/* The client drives a different mailbox with the Ryzen Master SMC message set */ > +static const struct hsmp_plat_desc hsmp_desc_client = { > + .msg_desc = hsmp_client_msg_desc_table, > + .num_msgs = HSMP_CLIENT_MSG_ID_MAX, > + .test_msg = HSMP_CLIENT_TEST, > + .proto_ver_msg = HSMP_CLIENT_GET_INTERFACE_VER, > +}; > + > static struct hsmp_plat_device hsmp_pdev; > > +/* > + * Resolved on first use and cached, since is_client_platform() always > + * settles on the same descriptor once booted. Concurrent first callers are > + * benign: every one of them computes and stores that same pointer, so > + * READ_ONCE()/WRITE_ONCE() only need to keep the access from being torn or > + * reordered by the compiler, not order it against anything else. > + */ > +static const struct hsmp_plat_desc *hsmp_desc_cache; > + > +static inline const struct hsmp_plat_desc *hsmp_desc(void) In C files, please drop inline from anything non-trivial and let the compiler decide if it inlines or not. > +{ > + const struct hsmp_plat_desc *desc = READ_ONCE(hsmp_desc_cache); > + > + if (likely(desc)) Add include. > + return desc; > + > + desc = is_client_platform() ? &hsmp_desc_client : &hsmp_desc_server; > + WRITE_ONCE(hsmp_desc_cache, desc); Add include. > + > + return desc; > +} > + > +/* Returns NULL if msg_id is out of range or reserved for this platform */ > +static inline const struct hsmp_msg_desc *get_msg_desc(u32 msg_id) > +{ > + const struct hsmp_plat_desc *desc = hsmp_desc(); > + > + if (msg_id >= desc->num_msgs) > + return NULL; > + > + if (desc->msg_desc[msg_id].type == HSMP_RSVD) > + return NULL; > + > + return &desc->msg_desc[msg_id]; > +} > + > /* > * Gates the AMD HSMP data plane against socket bring-up and teardown. > * > @@ -184,30 +375,29 @@ static int __hsmp_send_message(struct hsmp_socket *sock, struct hsmp_message *ms > > static int validate_message(struct hsmp_message *msg) > { > - /* msg_id against valid range of message IDs */ > - if (msg->msg_id < HSMP_TEST || msg->msg_id >= HSMP_MSG_ID_MAX) > - return -ENOMSG; > + const struct hsmp_msg_desc *desc; > > - /* msg_id is a reserved message ID */ > - if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_RSVD) > + /* Unknown or reserved message ID for this platform */ > + desc = get_msg_desc(msg->msg_id); > + if (!desc) > return -ENOMSG; > > /* > * num_args passed by user should match the num_args specified in > * message description table. > */ > - if (msg->num_args != hsmp_msg_desc_table[msg->msg_id].num_args) > + if (msg->num_args != desc->num_args) > return -EINVAL; > > /* > * As the HSMP protocol evolves, newer platforms may define more > * response arguments for existing messages. Use an upper-bound > * check so that older userspace callers requesting fewer response > - * words than what the current hsmp_msg_desc_table[] defines are > - * still accepted, while rejecting requests that exceed the > - * hardware capability. > + * words than what the current descriptor table defines are still > + * accepted, while rejecting requests that exceed the hardware > + * capability. > */ > - if (msg->response_sz > hsmp_msg_desc_table[msg->msg_id].response_sz) > + if (msg->response_sz > desc->response_sz) > return -EINVAL; > > return 0; > @@ -316,7 +506,7 @@ int hsmp_test(u16 sock_ind, u32 value) > * Test the hsmp port by performing TEST command. The test message > * takes one argument and returns the value of that argument + 1. > */ > - msg.msg_id = HSMP_TEST; > + msg.msg_id = hsmp_desc()->test_msg; > msg.num_args = 1; > msg.response_sz = 1; > msg.args[0] = value; > @@ -338,12 +528,12 @@ int hsmp_test(u16 sock_ind, u32 value) > } > EXPORT_SYMBOL_NS_GPL(hsmp_test, "AMD_HSMP"); > > -static bool is_get_msg(struct hsmp_message *msg) > +static bool is_get_msg(const struct hsmp_msg_desc *desc, struct hsmp_message *msg) > { > - if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_GET) > + if (desc->type == HSMP_GET) > return true; > > - if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_SET_GET && > + if (desc->type == HSMP_SET_GET && > (msg->args[0] & CHECK_GET_BIT)) Should fit to one line now? (Heh, I was going to say this is open-coding coding is_get_msg() before realizing it's the very thing :-)). > return true; > > @@ -354,6 +544,8 @@ static long hsmp_ioctl_msg(struct file *fp, unsigned long arg) > { > int __user *arguser = (int __user *)arg; > struct hsmp_message msg = { 0 }; > + const struct hsmp_plat_desc *plat_desc = hsmp_desc(); > + const struct hsmp_msg_desc *desc; > int ret; > > if (copy_struct_from_user(&msg, sizeof(msg), arguser, sizeof(struct hsmp_message))) > @@ -361,23 +553,25 @@ static long hsmp_ioctl_msg(struct file *fp, unsigned long arg) > > /* > * Check msg_id is within the range of supported msg ids > - * i.e within the array bounds of hsmp_msg_desc_table > + * i.e within the array bounds of the platform's descriptor table > */ > - if (msg.msg_id < HSMP_TEST || msg.msg_id >= HSMP_MSG_ID_MAX) > + if (msg.msg_id < plat_desc->test_msg || msg.msg_id >= plat_desc->num_msgs) > return -ENOMSG; > > /* > * Sanitize the user-controlled msg_id against speculative > * execution. The bounds check above retires the out-of-range > * case with -ENOMSG, but a mispredicted branch can still let the > - * CPU speculatively use msg_id as an index into > - * hsmp_msg_desc_table[] (here and in validate_message() / > - * is_get_msg() called downstream via hsmp_send_message()), and > - * pull arbitrary kernel memory into the cache (Spectre v1, > - * CVE-2017-5753). Clamp once into msg.msg_id so every downstream > - * dereference sees the sanitized value. > + * CPU speculatively use msg_id as an index into the message > + * descriptor table, here and again in validate_message() called > + * downstream via hsmp_send_message(). > */ > - msg.msg_id = array_index_nospec(msg.msg_id, HSMP_MSG_ID_MAX); > + msg.msg_id = array_index_nospec(msg.msg_id, plat_desc->num_msgs); > + > + /* Rejects the reserved IDs the table describes as such */ > + desc = get_msg_desc(msg.msg_id); > + if (!desc) > + return -ENOMSG; > > switch (fp->f_mode & (FMODE_WRITE | FMODE_READ)) { > case FMODE_WRITE: > @@ -385,7 +579,7 @@ static long hsmp_ioctl_msg(struct file *fp, unsigned long arg) > * Device is opened in O_WRONLY mode > * Execute only set/configure commands > */ > - if (is_get_msg(&msg)) > + if (is_get_msg(desc, &msg)) > return -EPERM; > break; > case FMODE_READ: > @@ -393,7 +587,7 @@ static long hsmp_ioctl_msg(struct file *fp, unsigned long arg) > * Device is opened in O_RDONLY mode > * Execute only get/monitor commands > */ > - if (!is_get_msg(&msg)) > + if (!is_get_msg(desc, &msg)) > return -EPERM; > break; > case FMODE_READ | FMODE_WRITE: > @@ -410,7 +604,7 @@ static long hsmp_ioctl_msg(struct file *fp, unsigned long arg) > if (ret) > return ret; > > - if (hsmp_msg_desc_table[msg.msg_id].response_sz > 0) { > + if (desc->response_sz > 0) { > /* Copy results back to user for get/monitor commands */ > if (copy_to_user(arguser, &msg, sizeof(struct hsmp_message))) > return -EFAULT; > @@ -685,11 +879,16 @@ EXPORT_SYMBOL_NS_GPL(hsmp_get_tbl_dram_base, "AMD_HSMP"); > int hsmp_cache_proto_ver(u16 sock_ind) > { > struct hsmp_message msg = { 0 }; > + const struct hsmp_msg_desc *desc; > int ret; > > - msg.msg_id = HSMP_GET_PROTO_VER; > + msg.msg_id = hsmp_desc()->proto_ver_msg; > + desc = get_msg_desc(msg.msg_id); > + if (WARN_ON(!desc)) > + return -ENOMSG; > + > msg.sock_ind = sock_ind; > - msg.response_sz = hsmp_msg_desc_table[HSMP_GET_PROTO_VER].response_sz; > + msg.response_sz = desc->response_sz; > > ret = hsmp_send_message_locked(&msg); > if (!ret) > diff --git a/drivers/platform/x86/amd/hsmp/hsmp.h b/drivers/platform/x86/amd/hsmp/hsmp.h > index 8dbff16a87b1..890cfb664829 100644 > --- a/drivers/platform/x86/amd/hsmp/hsmp.h > +++ b/drivers/platform/x86/amd/hsmp/hsmp.h > @@ -10,6 +10,9 @@ > #ifndef HSMP_H > #define HSMP_H > > +#include <asm/amd/hsmp.h> > + > +#include <linux/acpi.h> > #include <linux/compiler_types.h> > #include <linux/device.h> > #include <linux/hwmon.h> > @@ -17,6 +20,7 @@ > #include <linux/miscdevice.h> > #include <linux/mutex.h> > #include <linux/pci.h> > +#include <linux/processor.h> > #include <linux/rwsem.h> > #include <linux/semaphore.h> > #include <linux/sysfs.h> > @@ -32,6 +36,29 @@ > > #define DRIVER_VERSION "2.6" > > +/* > + * Family/model ranges need a driver update every generation and miss new > + * client parts until then. The ACPI-reported PM profile does not: it says > + * what kind of system this is regardless of which CPU is in it. > + */ > +static inline bool is_client_platform(void) > +{ > + if (!IS_ENABLED(CONFIG_ACPI)) > + return false; > + > + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) > + return false; > + > + switch (acpi_gbl_FADT.preferred_profile) { > + case PM_DESKTOP: > + case PM_MOBILE: > + case PM_TABLET: > + return true; > + default: > + return false; > + } > +} > + > struct hsmp_mbaddr_info { > u32 base_addr; > u32 msg_id_off; > -- i. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v5 1/4] platform/x86/amd/hsmp: Add HSMP client support for Family 1Ah 2026-09-01 4:51 ` [PATCH v5 1/4] platform/x86/amd/hsmp: Add HSMP client support for Family 1Ah Muralidhara M K 2026-09-18 11:34 ` Ilpo Järvinen @ 2026-09-18 11:46 ` Ilpo Järvinen 1 sibling, 0 replies; 10+ messages in thread From: Ilpo Järvinen @ 2026-09-18 11:46 UTC (permalink / raw) To: Muralidhara M K Cc: Mario.Limonciello, platform-driver-x86, LKML, Mario Limonciello On Tue, 1 Sep 2026, Muralidhara M K wrote: > Enable the HSMP driver on the Family 1Ah client platforms, Models > 80h-8Fh and E0h-E3h. These parts speak the Ryzen Master SMC (RMSMC) > message set instead of the server HSMP messages, but describe their > mailbox via ACPI _CRS/_DSD the same way a server socket does, so only > the ACPI driver needs to probe them. > > Add the client message set to the UAPI header and its descriptor > table to the driver. struct hsmp_plat_desc picks the right table and > driver-issued message IDs once per boot based on the ACPI-reported PM > profile, which tells client and server apart without pinning the > driver to a fixed set of family/model ranges. Document the client > models in amd_hsmp.rst. > > Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com> > Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org> Sashiko claims wrong interface (client/server) msgs can be issued on a platform with the other interface (from hwmon code and some other cases). Please check if that's legit or not. -- i. > --- > Documentation/arch/x86/amd_hsmp.rst | 10 +- > arch/x86/include/uapi/asm/amd_hsmp.h | 135 ++++++++++++++ > drivers/platform/x86/amd/hsmp/hsmp.c | 255 ++++++++++++++++++++++++--- > drivers/platform/x86/amd/hsmp/hsmp.h | 27 +++ > 4 files changed, 398 insertions(+), 29 deletions(-) > > diff --git a/Documentation/arch/x86/amd_hsmp.rst b/Documentation/arch/x86/amd_hsmp.rst > index fa1fc240e212..b95f09945193 100644 > --- a/Documentation/arch/x86/amd_hsmp.rst > +++ b/Documentation/arch/x86/amd_hsmp.rst > @@ -8,6 +8,13 @@ Newer Fam19h(model 0x00-0x1f, 0x30-0x3f, 0x90-0x9f, 0xa0-0xaf), > Fam1Ah(model 0x00-0x1f) EPYC server line of processors from AMD support > system management functionality via HSMP (Host System Management Port). > > +The Fam1Ah(model 0x80-0x8f, 0xe0-0xe3) client line of processors is > +supported as well. Those models share one mailbox and speak the Ryzen > +Master SMC message set instead of the server HSMP message set, so the > +message IDs accepted on them are the HSMP_CLIENT_* ones listed in > +arch/x86/include/uapi/asm/amd_hsmp.h. The character device and ioctl > +interface described below are the same. > + > The Host System Management Port (HSMP) is an interface to provide > OS-level software with access to system management functions via a > set of mailbox registers. > @@ -17,7 +24,8 @@ More details on the interface can be found in chapter > Eg: https://docs.amd.com/v/u/en-US/55898_B1_pub_0_50 > > > -HSMP interface is supported on EPYC line of server CPUs and MI300A (APU). > +HSMP interface is supported on EPYC line of server CPUs, MI300A (APU) and > +the Fam1Ah client models listed above. > > > HSMP device > diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h > index eda336bfd3e9..00ca7855ca00 100644 > --- a/arch/x86/include/uapi/asm/amd_hsmp.h > +++ b/arch/x86/include/uapi/asm/amd_hsmp.h > @@ -664,4 +664,139 @@ struct hsmp_telemetry_data { > #define HSMP_IOCTL_GET_TELEMETRY_DATA \ > _IOW(HSMP_BASE_IOCTL_NR, 1, struct hsmp_telemetry_data) > > +/** > + * enum hsmp_client_message_ids - Ryzen Master SMC (RMSMC) message IDs > + * @HSMP_CLIENT_TEST: 01h. Test message. input: args[0] = xx. output: > + * args[0] = xx + 1. > + * @HSMP_CLIENT_GET_SMU_VER: 02h. Get MP1 firmware version. output: > + * args[0] = MP1 firmware version. > + * @HSMP_CLIENT_GET_INTERFACE_VER: 03h. Get interface version. output: > + * args[0] = interface version. > + * @HSMP_CLIENT_GET_METRICS_TABLE_VER: 04h. Get metrics table version. > + * output: args[0] = metrics table version. > + * @HSMP_CLIENT_GET_METRICS_TABLE: 05h. Get metrics table. No arguments. > + * Success means firmware has written the metrics table to the DRAM > + * address reported by @HSMP_CLIENT_GET_METRICS_TABLE_DRAM_ADDR. > + * @HSMP_CLIENT_GET_METRICS_TABLE_DRAM_ADDR: 06h. Get metrics table DRAM > + * address. output: args[0] = address[31:0], args[1] = address[63:32], > + * args[2] = table size in bytes. > + * @HSMP_CLIENT_SET_CORE_PSM_MARGIN: 07h. Set core voltage margin. input: > + * args[0] = ApicId[31:16] + margin in mV[15:0]. > + * @HSMP_CLIENT_SET_ALL_CORE_PSM_MARGIN: 08h. Set voltage margin for all > + * cores. input: args[0] = margin in mV[15:0]. > + * @HSMP_CLIENT_SET_FAST_PPT_LIMIT: 09h. Set APU fast PPT limit. input: > + * args[0] = limit in mW. > + * @HSMP_CLIENT_SET_VRM_VDD_CURRENT_LIMIT: 0Ah. Set VDDCR_VDD TDC. input: > + * args[0] = limit in mA. > + * @HSMP_CLIENT_SET_VRM_VDD_MAX_CURRENT_LIMIT: 0Bh. Set VDDCR_VDD EDC. > + * input: args[0] = limit in mA. > + * @HSMP_CLIENT_SET_TJ_MAX: 0Ch. Set maximum junction temperature. input: > + * args[0] = temperature in degrees C. > + * @HSMP_CLIENT_SET_FIT_LIMIT_SCALAR: 0Dh. Set failures-in-time limit > + * scalar. input: args[0] = scalar (0 to 100). > + * @HSMP_CLIENT_ENABLE_OVERCLOCKING: 0Eh. Enable overclocking. No > + * arguments. > + * @HSMP_CLIENT_DISABLE_OVERCLOCKING: 0Fh. Disable overclocking. No > + * arguments. > + * @HSMP_CLIENT_SET_OVERCLOCK_FREQ_ALL_CORES: 10h. Set all-core overclock > + * frequency. input: args[0] = frequency in MHz[15:0]. > + * @HSMP_CLIENT_SET_OVERCLOCK_FREQ_PER_CORE: 11h. Set per-core overclock > + * frequency. input: args[0] = ApicId[31:16] + frequency in MHz[15:0]. > + * @HSMP_CLIENT_SET_OVERCLOCK_VID: 12h. Set overclock VID. input: > + * args[0] = voltage in mV[15:0]. > + * @HSMP_CLIENT_SET_FCLK_OVERCLOCK_ON_THE_FLY: 13h. Set FCLK overclock on > + * the fly. input: args[0] = FCLK in MHz[15:0]. > + * @HSMP_CLIENT_GET_CORE_PERF_ORDER: 14h. Get core performance order. > + * input: args[0] = ApicId[15:0]. output: args[0] = frequency in > + * MHz[15:0]. > + * @HSMP_CLIENT_SET_SUSTAINED_POWER_LIMIT: 15h. Set SOC sustained power > + * limit. input: args[0] = limit in mW. > + * @HSMP_CLIENT_SET_SLOW_PPT_LIMIT: 16h. Set APU slow PPT limit. input: > + * args[0] = limit in mW. > + * @HSMP_CLIENT_SET_VRM_GFX_MAX_CURRENT_LIMIT: 17h. Set VDDCR_GFX EDC. > + * input: args[0] = limit in mA. > + * @HSMP_CLIENT_SET_VRM_SOC_CURRENT_LIMIT: 18h. Set VDDCR_SOC TDC. input: > + * args[0] = limit in mA. > + * @HSMP_CLIENT_SET_FAST_SPM_LIMIT: 19h. Set fast SPM limit. input: > + * args[0] = limit in mW. > + * @HSMP_CLIENT_SET_SLOW_SPM_LIMIT: 1Ah. Set slow SPM limit. input: > + * args[0] = limit in mW. > + * @HSMP_CLIENT_GET_CORE_PSM_MARGIN: 1Bh. Get core voltage margin. input: > + * args[0] = ApicId[15:0]. output: args[0] = margin in mV[15:0]. > + * @HSMP_CLIENT_GET_GFX_PSM_MARGIN: 1Ch. Get graphics voltage margin. > + * output: args[0] = margin in mV[15:0]. > + * @HSMP_CLIENT_SPARE_0X1D: 1Dh. Reserved. > + * @HSMP_CLIENT_SPARE_0X1E: 1Eh. Reserved. > + * @HSMP_CLIENT_SPARE_0X1F: 1Fh. Reserved. > + * @HSMP_CLIENT_SPARE_0X20: 20h. Reserved. > + * @HSMP_CLIENT_SET_GFXCLK_OVERDRIVE_BY_FREQ_VID: 21h. Set GfxClk > + * overdrive by frequency/VID. input: args[0] = frequency in > + * MHz[31:16] + voltage in mV[15:0]. > + * @HSMP_CLIENT_DISABLE_GFXCLK_OVERDRIVE: 22h. Disable GfxClk overdrive. > + * No arguments. > + * @HSMP_CLIENT_SET_GFX_PSM_MARGIN: 23h. Set graphics voltage margin. > + * input: args[0] = margin in mV[15:0]. > + * @HSMP_CLIENT_SET_CCLK_FMAX_OFFSET: 24h. Set CCLK Fmax offset. input: > + * args[0] = maximum frequency in MHz[15:0]. > + * @HSMP_CLIENT_SET_CORE_POWER_LIMIT_OFFSET: 25h. Set core power limit > + * offset. input: args[0] = limit in mW. > + * @HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND: 26h. Add extra core PSM > + * guardband. input: args[0] = voltage in mV[15:0]. > + * @HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND_GFX: 27h. Add extra graphics PSM > + * guardband. input: args[0] = voltage in mV[15:0]. > + * @HSMP_CLIENT_SET_GFXCLK_FMAX: 28h. Set GfxClk Fmax. input: args[0] = > + * maximum frequency in MHz[15:0]. > + * @HSMP_CLIENT_MSG_ID_MAX: Number of message IDs, not a valid ID itself. > + * > + * Message IDs accepted on the Family 1Ah client platforms, Models 80h-8Fh > + * and E0h-E3h. These parts drive one mailbox and speak the Ryzen Master > + * SMC message set instead of the server HSMP message set enumerated in > + * &enum hsmp_message_ids. Not all platforms support all messages; consult > + * the supported list of messages in the HSMP chapter of the respective > + * family/model PPR. Unsupported messages return -ENOMSG. > + */ > +enum hsmp_client_message_ids { > + HSMP_CLIENT_TEST = 1, > + HSMP_CLIENT_GET_SMU_VER, > + HSMP_CLIENT_GET_INTERFACE_VER, > + HSMP_CLIENT_GET_METRICS_TABLE_VER, > + HSMP_CLIENT_GET_METRICS_TABLE, > + HSMP_CLIENT_GET_METRICS_TABLE_DRAM_ADDR, > + HSMP_CLIENT_SET_CORE_PSM_MARGIN, > + HSMP_CLIENT_SET_ALL_CORE_PSM_MARGIN, > + HSMP_CLIENT_SET_FAST_PPT_LIMIT, > + HSMP_CLIENT_SET_VRM_VDD_CURRENT_LIMIT, > + HSMP_CLIENT_SET_VRM_VDD_MAX_CURRENT_LIMIT, > + HSMP_CLIENT_SET_TJ_MAX, > + HSMP_CLIENT_SET_FIT_LIMIT_SCALAR, > + HSMP_CLIENT_ENABLE_OVERCLOCKING, > + HSMP_CLIENT_DISABLE_OVERCLOCKING, > + HSMP_CLIENT_SET_OVERCLOCK_FREQ_ALL_CORES, > + HSMP_CLIENT_SET_OVERCLOCK_FREQ_PER_CORE, > + HSMP_CLIENT_SET_OVERCLOCK_VID, > + HSMP_CLIENT_SET_FCLK_OVERCLOCK_ON_THE_FLY, > + HSMP_CLIENT_GET_CORE_PERF_ORDER, > + HSMP_CLIENT_SET_SUSTAINED_POWER_LIMIT, > + HSMP_CLIENT_SET_SLOW_PPT_LIMIT, > + HSMP_CLIENT_SET_VRM_GFX_MAX_CURRENT_LIMIT, > + HSMP_CLIENT_SET_VRM_SOC_CURRENT_LIMIT, > + HSMP_CLIENT_SET_FAST_SPM_LIMIT, > + HSMP_CLIENT_SET_SLOW_SPM_LIMIT, > + HSMP_CLIENT_GET_CORE_PSM_MARGIN, > + HSMP_CLIENT_GET_GFX_PSM_MARGIN, > + HSMP_CLIENT_SPARE_0X1D, > + HSMP_CLIENT_SPARE_0X1E, > + HSMP_CLIENT_SPARE_0X1F, > + HSMP_CLIENT_SPARE_0X20, > + HSMP_CLIENT_SET_GFXCLK_OVERDRIVE_BY_FREQ_VID, > + HSMP_CLIENT_DISABLE_GFXCLK_OVERDRIVE, > + HSMP_CLIENT_SET_GFX_PSM_MARGIN, > + HSMP_CLIENT_SET_CCLK_FMAX_OFFSET, > + HSMP_CLIENT_SET_CORE_POWER_LIMIT_OFFSET, > + HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND, > + HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND_GFX, > + HSMP_CLIENT_SET_GFXCLK_FMAX, > + HSMP_CLIENT_MSG_ID_MAX, > +}; > + > #endif /*_ASM_X86_AMD_HSMP_H_*/ > diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c > index 5e123a4ecea9..e8fac2d299f3 100644 > --- a/drivers/platform/x86/amd/hsmp/hsmp.c > +++ b/drivers/platform/x86/amd/hsmp/hsmp.c > @@ -10,6 +10,8 @@ > #include <asm/amd/hsmp.h> > > #include <linux/acpi.h> > +#include <linux/array_size.h> > +#include <linux/build_bug.h> > #include <linux/cleanup.h> > #include <linux/delay.h> > #include <linux/device.h> > @@ -45,8 +47,197 @@ > */ > #define CHECK_GET_BIT BIT(31) > > +/* Indexed by enum hsmp_client_message_ids; see there for per-message details */ > +static const struct hsmp_msg_desc hsmp_client_msg_desc_table[] = { > + /* RESERVED */ > + {0, 0, HSMP_RSVD}, > + > + /* HSMP_CLIENT_TEST */ > + {1, 1, HSMP_GET}, > + > + /* HSMP_CLIENT_GET_SMU_VER */ > + {0, 1, HSMP_GET}, > + > + /* HSMP_CLIENT_GET_INTERFACE_VER */ > + {0, 1, HSMP_GET}, > + > + /* HSMP_CLIENT_GET_METRICS_TABLE_VER */ > + {0, 1, HSMP_GET}, > + > + /* HSMP_CLIENT_GET_METRICS_TABLE */ > + {0, 0, HSMP_GET}, > + > + /* HSMP_CLIENT_GET_METRICS_TABLE_DRAM_ADDR */ > + {0, 3, HSMP_GET}, > + > + /* HSMP_CLIENT_SET_CORE_PSM_MARGIN */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_ALL_CORE_PSM_MARGIN */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_FAST_PPT_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_VRM_VDD_CURRENT_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_VRM_VDD_MAX_CURRENT_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_TJ_MAX */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_FIT_LIMIT_SCALAR */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_ENABLE_OVERCLOCKING */ > + {0, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_DISABLE_OVERCLOCKING */ > + {0, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_OVERCLOCK_FREQ_ALL_CORES */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_OVERCLOCK_FREQ_PER_CORE */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_OVERCLOCK_VID */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_FCLK_OVERCLOCK_ON_THE_FLY */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_GET_CORE_PERF_ORDER */ > + {1, 1, HSMP_GET}, > + > + /* HSMP_CLIENT_SET_SUSTAINED_POWER_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_SLOW_PPT_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_VRM_GFX_MAX_CURRENT_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_VRM_SOC_CURRENT_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_FAST_SPM_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_SLOW_SPM_LIMIT */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_GET_CORE_PSM_MARGIN */ > + {1, 1, HSMP_GET}, > + > + /* HSMP_CLIENT_GET_GFX_PSM_MARGIN */ > + {0, 1, HSMP_GET}, > + > + /* HSMP_CLIENT_SPARE_0X1D */ > + {0, 0, HSMP_RSVD}, > + > + /* HSMP_CLIENT_SPARE_0X1E */ > + {0, 0, HSMP_RSVD}, > + > + /* HSMP_CLIENT_SPARE_0X1F */ > + {0, 0, HSMP_RSVD}, > + > + /* HSMP_CLIENT_SPARE_0X20 */ > + {0, 0, HSMP_RSVD}, > + > + /* HSMP_CLIENT_SET_GFXCLK_OVERDRIVE_BY_FREQ_VID */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_DISABLE_GFXCLK_OVERDRIVE */ > + {0, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_GFX_PSM_MARGIN */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_CCLK_FMAX_OFFSET */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_CORE_POWER_LIMIT_OFFSET */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_ADD_EXTRA_PSM_GUARDBAND_GFX */ > + {1, 0, HSMP_SET}, > + > + /* HSMP_CLIENT_SET_GFXCLK_FMAX */ > + {1, 0, HSMP_SET}, > +}; > + > +/* Catch a table left out of sync with its enum at build time */ > +static_assert(ARRAY_SIZE(hsmp_msg_desc_table) == HSMP_MSG_ID_MAX); > +static_assert(ARRAY_SIZE(hsmp_client_msg_desc_table) == HSMP_CLIENT_MSG_ID_MAX); > + > +/* Per-platform message set: which table to use, and driver-issued msg IDs */ > +struct hsmp_plat_desc { > + const struct hsmp_msg_desc *msg_desc; > + u32 num_msgs; > + u32 test_msg; > + u32 proto_ver_msg; > +}; > + > +static const struct hsmp_plat_desc hsmp_desc_server = { > + .msg_desc = hsmp_msg_desc_table, > + .num_msgs = HSMP_MSG_ID_MAX, > + .test_msg = HSMP_TEST, > + .proto_ver_msg = HSMP_GET_PROTO_VER, > +}; > + > +/* The client drives a different mailbox with the Ryzen Master SMC message set */ > +static const struct hsmp_plat_desc hsmp_desc_client = { > + .msg_desc = hsmp_client_msg_desc_table, > + .num_msgs = HSMP_CLIENT_MSG_ID_MAX, > + .test_msg = HSMP_CLIENT_TEST, > + .proto_ver_msg = HSMP_CLIENT_GET_INTERFACE_VER, > +}; > + > static struct hsmp_plat_device hsmp_pdev; > > +/* > + * Resolved on first use and cached, since is_client_platform() always > + * settles on the same descriptor once booted. Concurrent first callers are > + * benign: every one of them computes and stores that same pointer, so > + * READ_ONCE()/WRITE_ONCE() only need to keep the access from being torn or > + * reordered by the compiler, not order it against anything else. > + */ > +static const struct hsmp_plat_desc *hsmp_desc_cache; > + > +static inline const struct hsmp_plat_desc *hsmp_desc(void) > +{ > + const struct hsmp_plat_desc *desc = READ_ONCE(hsmp_desc_cache); > + > + if (likely(desc)) > + return desc; > + > + desc = is_client_platform() ? &hsmp_desc_client : &hsmp_desc_server; > + WRITE_ONCE(hsmp_desc_cache, desc); > + > + return desc; > +} > + > +/* Returns NULL if msg_id is out of range or reserved for this platform */ > +static inline const struct hsmp_msg_desc *get_msg_desc(u32 msg_id) > +{ > + const struct hsmp_plat_desc *desc = hsmp_desc(); > + > + if (msg_id >= desc->num_msgs) > + return NULL; > + > + if (desc->msg_desc[msg_id].type == HSMP_RSVD) > + return NULL; > + > + return &desc->msg_desc[msg_id]; > +} > + > /* > * Gates the AMD HSMP data plane against socket bring-up and teardown. > * > @@ -184,30 +375,29 @@ static int __hsmp_send_message(struct hsmp_socket *sock, struct hsmp_message *ms > > static int validate_message(struct hsmp_message *msg) > { > - /* msg_id against valid range of message IDs */ > - if (msg->msg_id < HSMP_TEST || msg->msg_id >= HSMP_MSG_ID_MAX) > - return -ENOMSG; > + const struct hsmp_msg_desc *desc; > > - /* msg_id is a reserved message ID */ > - if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_RSVD) > + /* Unknown or reserved message ID for this platform */ > + desc = get_msg_desc(msg->msg_id); > + if (!desc) > return -ENOMSG; > > /* > * num_args passed by user should match the num_args specified in > * message description table. > */ > - if (msg->num_args != hsmp_msg_desc_table[msg->msg_id].num_args) > + if (msg->num_args != desc->num_args) > return -EINVAL; > > /* > * As the HSMP protocol evolves, newer platforms may define more > * response arguments for existing messages. Use an upper-bound > * check so that older userspace callers requesting fewer response > - * words than what the current hsmp_msg_desc_table[] defines are > - * still accepted, while rejecting requests that exceed the > - * hardware capability. > + * words than what the current descriptor table defines are still > + * accepted, while rejecting requests that exceed the hardware > + * capability. > */ > - if (msg->response_sz > hsmp_msg_desc_table[msg->msg_id].response_sz) > + if (msg->response_sz > desc->response_sz) > return -EINVAL; > > return 0; > @@ -316,7 +506,7 @@ int hsmp_test(u16 sock_ind, u32 value) > * Test the hsmp port by performing TEST command. The test message > * takes one argument and returns the value of that argument + 1. > */ > - msg.msg_id = HSMP_TEST; > + msg.msg_id = hsmp_desc()->test_msg; > msg.num_args = 1; > msg.response_sz = 1; > msg.args[0] = value; > @@ -338,12 +528,12 @@ int hsmp_test(u16 sock_ind, u32 value) > } > EXPORT_SYMBOL_NS_GPL(hsmp_test, "AMD_HSMP"); > > -static bool is_get_msg(struct hsmp_message *msg) > +static bool is_get_msg(const struct hsmp_msg_desc *desc, struct hsmp_message *msg) > { > - if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_GET) > + if (desc->type == HSMP_GET) > return true; > > - if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_SET_GET && > + if (desc->type == HSMP_SET_GET && > (msg->args[0] & CHECK_GET_BIT)) > return true; > > @@ -354,6 +544,8 @@ static long hsmp_ioctl_msg(struct file *fp, unsigned long arg) > { > int __user *arguser = (int __user *)arg; > struct hsmp_message msg = { 0 }; > + const struct hsmp_plat_desc *plat_desc = hsmp_desc(); > + const struct hsmp_msg_desc *desc; > int ret; > > if (copy_struct_from_user(&msg, sizeof(msg), arguser, sizeof(struct hsmp_message))) > @@ -361,23 +553,25 @@ static long hsmp_ioctl_msg(struct file *fp, unsigned long arg) > > /* > * Check msg_id is within the range of supported msg ids > - * i.e within the array bounds of hsmp_msg_desc_table > + * i.e within the array bounds of the platform's descriptor table > */ > - if (msg.msg_id < HSMP_TEST || msg.msg_id >= HSMP_MSG_ID_MAX) > + if (msg.msg_id < plat_desc->test_msg || msg.msg_id >= plat_desc->num_msgs) > return -ENOMSG; > > /* > * Sanitize the user-controlled msg_id against speculative > * execution. The bounds check above retires the out-of-range > * case with -ENOMSG, but a mispredicted branch can still let the > - * CPU speculatively use msg_id as an index into > - * hsmp_msg_desc_table[] (here and in validate_message() / > - * is_get_msg() called downstream via hsmp_send_message()), and > - * pull arbitrary kernel memory into the cache (Spectre v1, > - * CVE-2017-5753). Clamp once into msg.msg_id so every downstream > - * dereference sees the sanitized value. > + * CPU speculatively use msg_id as an index into the message > + * descriptor table, here and again in validate_message() called > + * downstream via hsmp_send_message(). > */ > - msg.msg_id = array_index_nospec(msg.msg_id, HSMP_MSG_ID_MAX); > + msg.msg_id = array_index_nospec(msg.msg_id, plat_desc->num_msgs); > + > + /* Rejects the reserved IDs the table describes as such */ > + desc = get_msg_desc(msg.msg_id); > + if (!desc) > + return -ENOMSG; > > switch (fp->f_mode & (FMODE_WRITE | FMODE_READ)) { > case FMODE_WRITE: > @@ -385,7 +579,7 @@ static long hsmp_ioctl_msg(struct file *fp, unsigned long arg) > * Device is opened in O_WRONLY mode > * Execute only set/configure commands > */ > - if (is_get_msg(&msg)) > + if (is_get_msg(desc, &msg)) > return -EPERM; > break; > case FMODE_READ: > @@ -393,7 +587,7 @@ static long hsmp_ioctl_msg(struct file *fp, unsigned long arg) > * Device is opened in O_RDONLY mode > * Execute only get/monitor commands > */ > - if (!is_get_msg(&msg)) > + if (!is_get_msg(desc, &msg)) > return -EPERM; > break; > case FMODE_READ | FMODE_WRITE: > @@ -410,7 +604,7 @@ static long hsmp_ioctl_msg(struct file *fp, unsigned long arg) > if (ret) > return ret; > > - if (hsmp_msg_desc_table[msg.msg_id].response_sz > 0) { > + if (desc->response_sz > 0) { > /* Copy results back to user for get/monitor commands */ > if (copy_to_user(arguser, &msg, sizeof(struct hsmp_message))) > return -EFAULT; > @@ -685,11 +879,16 @@ EXPORT_SYMBOL_NS_GPL(hsmp_get_tbl_dram_base, "AMD_HSMP"); > int hsmp_cache_proto_ver(u16 sock_ind) > { > struct hsmp_message msg = { 0 }; > + const struct hsmp_msg_desc *desc; > int ret; > > - msg.msg_id = HSMP_GET_PROTO_VER; > + msg.msg_id = hsmp_desc()->proto_ver_msg; > + desc = get_msg_desc(msg.msg_id); > + if (WARN_ON(!desc)) > + return -ENOMSG; > + > msg.sock_ind = sock_ind; > - msg.response_sz = hsmp_msg_desc_table[HSMP_GET_PROTO_VER].response_sz; > + msg.response_sz = desc->response_sz; > > ret = hsmp_send_message_locked(&msg); > if (!ret) > diff --git a/drivers/platform/x86/amd/hsmp/hsmp.h b/drivers/platform/x86/amd/hsmp/hsmp.h > index 8dbff16a87b1..890cfb664829 100644 > --- a/drivers/platform/x86/amd/hsmp/hsmp.h > +++ b/drivers/platform/x86/amd/hsmp/hsmp.h > @@ -10,6 +10,9 @@ > #ifndef HSMP_H > #define HSMP_H > > +#include <asm/amd/hsmp.h> > + > +#include <linux/acpi.h> > #include <linux/compiler_types.h> > #include <linux/device.h> > #include <linux/hwmon.h> > @@ -17,6 +20,7 @@ > #include <linux/miscdevice.h> > #include <linux/mutex.h> > #include <linux/pci.h> > +#include <linux/processor.h> > #include <linux/rwsem.h> > #include <linux/semaphore.h> > #include <linux/sysfs.h> > @@ -32,6 +36,29 @@ > > #define DRIVER_VERSION "2.6" > > +/* > + * Family/model ranges need a driver update every generation and miss new > + * client parts until then. The ACPI-reported PM profile does not: it says > + * what kind of system this is regardless of which CPU is in it. > + */ > +static inline bool is_client_platform(void) > +{ > + if (!IS_ENABLED(CONFIG_ACPI)) > + return false; > + > + if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD) > + return false; > + > + switch (acpi_gbl_FADT.preferred_profile) { > + case PM_DESKTOP: > + case PM_MOBILE: > + case PM_TABLET: > + return true; > + default: > + return false; > + } > +} > + > struct hsmp_mbaddr_info { > u32 base_addr; > u32 msg_id_off; > ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v5 2/4] platform/x86/amd/hsmp: Route metric table through the client messages 2026-09-01 4:51 [PATCH v5 0/4] platform/x86/amd/hsmp: Family 1Ah client support Muralidhara M K 2026-09-01 4:51 ` [PATCH v5 1/4] platform/x86/amd/hsmp: Add HSMP client support for Family 1Ah Muralidhara M K @ 2026-09-01 4:51 ` Muralidhara M K 2026-09-01 4:51 ` [PATCH v5 3/4] platform/x86/amd/hsmp: Add ACPI client support for Family 1Ah Muralidhara M K ` (2 subsequent siblings) 4 siblings, 0 replies; 10+ messages in thread From: Muralidhara M K @ 2026-09-01 4:51 UTC (permalink / raw) To: ilpo.jarvinen, Mario.Limonciello Cc: platform-driver-x86, linux-kernel, Muralidhara M K, Mario Limonciello Wire the client metric table and metrics DRAM address messages into the metric table read path for the Family 1Ah client platforms. The client reaches its metric table through the Ryzen Master SMC message set, so add the two message IDs to struct hsmp_plat_desc and have hsmp_metric_tbl_read_locked() and hsmp_get_tbl_dram_base() take them from there. Unlike the test and version queries, these two are numbered differently in the two sets (24h/25h server vs 05h/06h client), so they must come from the descriptor rather than a shared constant. Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com> Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org> --- drivers/platform/x86/amd/hsmp/hsmp.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/platform/x86/amd/hsmp/hsmp.c b/drivers/platform/x86/amd/hsmp/hsmp.c index e8fac2d299f3..60889c1b1099 100644 --- a/drivers/platform/x86/amd/hsmp/hsmp.c +++ b/drivers/platform/x86/amd/hsmp/hsmp.c @@ -183,6 +183,8 @@ struct hsmp_plat_desc { u32 num_msgs; u32 test_msg; u32 proto_ver_msg; + u32 metric_tbl_msg; + u32 metric_dram_msg; }; static const struct hsmp_plat_desc hsmp_desc_server = { @@ -190,6 +192,8 @@ static const struct hsmp_plat_desc hsmp_desc_server = { .num_msgs = HSMP_MSG_ID_MAX, .test_msg = HSMP_TEST, .proto_ver_msg = HSMP_GET_PROTO_VER, + .metric_tbl_msg = HSMP_GET_METRIC_TABLE, + .metric_dram_msg = HSMP_GET_METRIC_TABLE_DRAM_ADDR, }; /* The client drives a different mailbox with the Ryzen Master SMC message set */ @@ -198,6 +202,8 @@ static const struct hsmp_plat_desc hsmp_desc_client = { .num_msgs = HSMP_CLIENT_MSG_ID_MAX, .test_msg = HSMP_CLIENT_TEST, .proto_ver_msg = HSMP_CLIENT_GET_INTERFACE_VER, + .metric_tbl_msg = HSMP_CLIENT_GET_METRICS_TABLE, + .metric_dram_msg = HSMP_CLIENT_GET_METRICS_TABLE_DRAM_ADDR, }; static struct hsmp_plat_device hsmp_pdev; @@ -759,11 +765,11 @@ static ssize_t hsmp_metric_tbl_read_locked(struct hsmp_socket *sock, char *buf, return -EINVAL; } - msg.msg_id = HSMP_GET_METRIC_TABLE; + msg.msg_id = hsmp_desc()->metric_tbl_msg; msg.sock_ind = sock->sock_ind; /* - * HSMP_GET_METRIC_TABLE makes firmware refill this socket's shared + * The metric table message makes firmware refill this socket's shared * metric DRAM region, which is then copied out below. Hold the * per-socket lock across the fill-and-copy so concurrent readers of the * same socket cannot return a torn snapshot. @@ -829,8 +835,8 @@ int hsmp_get_tbl_dram_base(u16 sock_ind) int ret; msg.sock_ind = sock_ind; - msg.response_sz = hsmp_msg_desc_table[HSMP_GET_METRIC_TABLE_DRAM_ADDR].response_sz; - msg.msg_id = HSMP_GET_METRIC_TABLE_DRAM_ADDR; + msg.msg_id = hsmp_desc()->metric_dram_msg; + msg.response_sz = get_msg_desc(msg.msg_id)->response_sz; ret = hsmp_send_message_locked(&msg); if (ret) -- 2.34.1 ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v5 3/4] platform/x86/amd/hsmp: Add ACPI client support for Family 1Ah 2026-09-01 4:51 [PATCH v5 0/4] platform/x86/amd/hsmp: Family 1Ah client support Muralidhara M K 2026-09-01 4:51 ` [PATCH v5 1/4] platform/x86/amd/hsmp: Add HSMP client support for Family 1Ah Muralidhara M K 2026-09-01 4:51 ` [PATCH v5 2/4] platform/x86/amd/hsmp: Route metric table through the client messages Muralidhara M K @ 2026-09-01 4:51 ` Muralidhara M K 2026-09-18 11:39 ` Ilpo Järvinen 2026-09-18 11:43 ` Ilpo Järvinen 2026-09-01 4:51 ` [PATCH v5 4/4] platform/x86/amd/hsmp: Document and expose client telemetry table in UAPI Muralidhara M K 2026-09-01 12:24 ` [PATCH v5 0/4] platform/x86/amd/hsmp: Family 1Ah client support Mario Limonciello 4 siblings, 2 replies; 10+ messages in thread From: Muralidhara M K @ 2026-09-01 4:51 UTC (permalink / raw) To: ilpo.jarvinen, Mario.Limonciello Cc: platform-driver-x86, linux-kernel, Muralidhara M K, Mario Limonciello The ACPI HSMP device (HID AMDI0097) on the Family 1Ah client platforms (Models 80h-8Fh and E0h-E3h) describes its mailbox the same way server platforms already do, via _CRS/_DSD, so hsmp_parse_acpi_table() and hsmp_get_uid() need no client-specific handling. Client platforms don't report a server protocol version, so also gate the metric table DRAM base lookup on is_client_platform() alongside the existing proto_ver check, so client platforms get their metric table base initialized too. hsmp_pdev->proto_ver holds the Ryzen Master SMC interface version on client platforms, a separate numbering space from the server protocol versions in enum hsmp_proto_versions, so gate on it using its own RYZEN_MASTER_PROTO_VER1 rather than assuming every client platform is ready for the metric table lookup regardless of interface version. Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com> Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org> --- arch/x86/include/uapi/asm/amd_hsmp.h | 9 +++++++++ drivers/platform/x86/amd/hsmp/acpi.c | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h index 00ca7855ca00..3e1b7cbe0f04 100644 --- a/arch/x86/include/uapi/asm/amd_hsmp.h +++ b/arch/x86/include/uapi/asm/amd_hsmp.h @@ -95,6 +95,15 @@ enum hsmp_proto_versions { HSMP_PROTO_VER7 }; +/* + * The Ryzen Master SMC interface versions its own way, reported by + * HSMP_CLIENT_GET_INTERFACE_VER. It is a separate numbering space from + * enum hsmp_proto_versions above, which only applies to the server set. + */ +enum ryzen_master_proto_versions { + RYZEN_MASTER_PROTO_VER1 = 1, +}; + struct hsmp_msg_desc { int num_args; int response_sz; diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c index 8257cd1da48e..43d746546536 100644 --- a/drivers/platform/x86/amd/hsmp/acpi.c +++ b/drivers/platform/x86/amd/hsmp/acpi.c @@ -557,7 +557,8 @@ static int init_acpi(struct device *dev) return ret; } - if (hsmp_pdev->proto_ver >= HSMP_PROTO_VER6) { + if ((is_client_platform() && hsmp_pdev->proto_ver >= RYZEN_MASTER_PROTO_VER1) || + hsmp_pdev->proto_ver >= HSMP_PROTO_VER6) { ret = hsmp_get_tbl_dram_base(sock_ind); if (ret) dev_info(dev, "Failed to init metric table\n"); -- 2.34.1 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v5 3/4] platform/x86/amd/hsmp: Add ACPI client support for Family 1Ah 2026-09-01 4:51 ` [PATCH v5 3/4] platform/x86/amd/hsmp: Add ACPI client support for Family 1Ah Muralidhara M K @ 2026-09-18 11:39 ` Ilpo Järvinen 2026-09-18 11:43 ` Ilpo Järvinen 1 sibling, 0 replies; 10+ messages in thread From: Ilpo Järvinen @ 2026-09-18 11:39 UTC (permalink / raw) To: Muralidhara M K Cc: Mario.Limonciello, platform-driver-x86, LKML, Mario Limonciello On Tue, 1 Sep 2026, Muralidhara M K wrote: > The ACPI HSMP device (HID AMDI0097) on the Family 1Ah client platforms > (Models 80h-8Fh and E0h-E3h) describes its mailbox the same way server > platforms already do, via _CRS/_DSD, so hsmp_parse_acpi_table() and > hsmp_get_uid() need no client-specific handling. > > Client platforms don't report a server protocol version, so also gate > the metric table DRAM base lookup on is_client_platform() alongside > the existing proto_ver check, so client platforms get their metric > table base initialized too. > > hsmp_pdev->proto_ver holds the Ryzen Master SMC interface version on > client platforms, a separate numbering space from the server protocol > versions in enum hsmp_proto_versions, so gate on it using its own > RYZEN_MASTER_PROTO_VER1 rather than assuming every client platform is > ready for the metric table lookup regardless of interface version. > > Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com> > Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org> > --- > arch/x86/include/uapi/asm/amd_hsmp.h | 9 +++++++++ > drivers/platform/x86/amd/hsmp/acpi.c | 3 ++- > 2 files changed, 11 insertions(+), 1 deletion(-) > > diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h > index 00ca7855ca00..3e1b7cbe0f04 100644 > --- a/arch/x86/include/uapi/asm/amd_hsmp.h > +++ b/arch/x86/include/uapi/asm/amd_hsmp.h > @@ -95,6 +95,15 @@ enum hsmp_proto_versions { > HSMP_PROTO_VER7 > }; > > +/* > + * The Ryzen Master SMC interface versions its own way, reported by > + * HSMP_CLIENT_GET_INTERFACE_VER. It is a separate numbering space from > + * enum hsmp_proto_versions above, which only applies to the server set. > + */ > +enum ryzen_master_proto_versions { > + RYZEN_MASTER_PROTO_VER1 = 1, > +}; > + > struct hsmp_msg_desc { > int num_args; > int response_sz; > diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c > index 8257cd1da48e..43d746546536 100644 > --- a/drivers/platform/x86/amd/hsmp/acpi.c > +++ b/drivers/platform/x86/amd/hsmp/acpi.c > @@ -557,7 +557,8 @@ static int init_acpi(struct device *dev) > return ret; > } > > - if (hsmp_pdev->proto_ver >= HSMP_PROTO_VER6) { > + if ((is_client_platform() && hsmp_pdev->proto_ver >= RYZEN_MASTER_PROTO_VER1) || > + hsmp_pdev->proto_ver >= HSMP_PROTO_VER6) { > ret = hsmp_get_tbl_dram_base(sock_ind); > if (ret) > dev_info(dev, "Failed to init metric table\n"); > Somehow it feels like the patches are in wrong order if you add this condition last in the series? I didn't spend my time on figuring every out but the key question is if one builds kernel with only patches 1 or 1+2 applied, does something break which is fixed only after this patch 3 is applied? -- i. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v5 3/4] platform/x86/amd/hsmp: Add ACPI client support for Family 1Ah 2026-09-01 4:51 ` [PATCH v5 3/4] platform/x86/amd/hsmp: Add ACPI client support for Family 1Ah Muralidhara M K 2026-09-18 11:39 ` Ilpo Järvinen @ 2026-09-18 11:43 ` Ilpo Järvinen 1 sibling, 0 replies; 10+ messages in thread From: Ilpo Järvinen @ 2026-09-18 11:43 UTC (permalink / raw) To: Muralidhara M K Cc: Mario.Limonciello, platform-driver-x86, LKML, Mario Limonciello On Tue, 1 Sep 2026, Muralidhara M K wrote: > The ACPI HSMP device (HID AMDI0097) on the Family 1Ah client platforms > (Models 80h-8Fh and E0h-E3h) describes its mailbox the same way server > platforms already do, via _CRS/_DSD, so hsmp_parse_acpi_table() and > hsmp_get_uid() need no client-specific handling. > > Client platforms don't report a server protocol version, so also gate > the metric table DRAM base lookup on is_client_platform() alongside > the existing proto_ver check, so client platforms get their metric > table base initialized too. > > hsmp_pdev->proto_ver holds the Ryzen Master SMC interface version on > client platforms, a separate numbering space from the server protocol > versions in enum hsmp_proto_versions, so gate on it using its own > RYZEN_MASTER_PROTO_VER1 rather than assuming every client platform is > ready for the metric table lookup regardless of interface version. > > Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com> > Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org> > --- > arch/x86/include/uapi/asm/amd_hsmp.h | 9 +++++++++ > drivers/platform/x86/amd/hsmp/acpi.c | 3 ++- > 2 files changed, 11 insertions(+), 1 deletion(-) > > diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h > index 00ca7855ca00..3e1b7cbe0f04 100644 > --- a/arch/x86/include/uapi/asm/amd_hsmp.h > +++ b/arch/x86/include/uapi/asm/amd_hsmp.h > @@ -95,6 +95,15 @@ enum hsmp_proto_versions { > HSMP_PROTO_VER7 > }; > > +/* > + * The Ryzen Master SMC interface versions its own way, reported by > + * HSMP_CLIENT_GET_INTERFACE_VER. It is a separate numbering space from > + * enum hsmp_proto_versions above, which only applies to the server set. > + */ > +enum ryzen_master_proto_versions { > + RYZEN_MASTER_PROTO_VER1 = 1, > +}; > + > struct hsmp_msg_desc { > int num_args; > int response_sz; > diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c > index 8257cd1da48e..43d746546536 100644 > --- a/drivers/platform/x86/amd/hsmp/acpi.c > +++ b/drivers/platform/x86/amd/hsmp/acpi.c > @@ -557,7 +557,8 @@ static int init_acpi(struct device *dev) > return ret; > } > > - if (hsmp_pdev->proto_ver >= HSMP_PROTO_VER6) { > + if ((is_client_platform() && hsmp_pdev->proto_ver >= RYZEN_MASTER_PROTO_VER1) || > + hsmp_pdev->proto_ver >= HSMP_PROTO_VER6) { sashiko also warns that !is_client_platform() is not done for the second part of the check, which may eventually lead to spurious matches on the second check on a client platform. -- i. ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v5 4/4] platform/x86/amd/hsmp: Document and expose client telemetry table in UAPI 2026-09-01 4:51 [PATCH v5 0/4] platform/x86/amd/hsmp: Family 1Ah client support Muralidhara M K ` (2 preceding siblings ...) 2026-09-01 4:51 ` [PATCH v5 3/4] platform/x86/amd/hsmp: Add ACPI client support for Family 1Ah Muralidhara M K @ 2026-09-01 4:51 ` Muralidhara M K 2026-09-01 12:24 ` [PATCH v5 0/4] platform/x86/amd/hsmp: Family 1Ah client support Mario Limonciello 4 siblings, 0 replies; 10+ messages in thread From: Muralidhara M K @ 2026-09-01 4:51 UTC (permalink / raw) To: ilpo.jarvinen, Mario.Limonciello Cc: platform-driver-x86, linux-kernel, Muralidhara M K, Mario Limonciello The client models return the Ryzen Master SMC telemetry table, which the driver copies out without interpreting. Add the Telemetry Table RM layout, reported as table version 5 by HSMP_CLIENT_GET_METRICS_TABLE_VER, as struct declarations in the UAPI header, so userspace has one authoritative, kernel-doc'd definition of the byte layout instead of decoding it by hand. Point amd_hsmp.rst at struct hsmp_telemetry_table_rm rather than duplicating the layout in prose. The Public PPR for the model in use remains the reference for units and encodings, which are firmware defined. Signed-off-by: Muralidhara M K <muralidhara.mk@amd.com> Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org> --- Documentation/arch/x86/amd_hsmp.rst | 14 ++ arch/x86/include/uapi/asm/amd_hsmp.h | 263 +++++++++++++++++++++++++++ 2 files changed, 277 insertions(+) diff --git a/Documentation/arch/x86/amd_hsmp.rst b/Documentation/arch/x86/amd_hsmp.rst index b95f09945193..c483c68dcfad 100644 --- a/Documentation/arch/x86/amd_hsmp.rst +++ b/Documentation/arch/x86/amd_hsmp.rst @@ -221,9 +221,23 @@ The following IOCTLs are defined: ``sizeof(struct hsmp_metric_table)``. Later version metrics table layout is documented in the Public PPR. + The Family 1Ah client models carry their own telemetry table instead, + described in `Family 1Ah client telemetry table`_ below. + The ioctl would return a non-zero on failure; you can read errno to see what happened. The transaction returns 0 on success. +Family 1Ah client telemetry table +================================= +On the Family 1Ah client models, ``HSMP_CLIENT_GET_METRICS_TABLE`` (05h) +returns the Ryzen Master SMC telemetry table, table version 5 as +reported by ``HSMP_CLIENT_GET_METRICS_TABLE_VER`` (04h). This is the +Telemetry Table RM layout, defined as ``struct hsmp_telemetry_table_rm`` +in amd_hsmp.h. The driver copies the table out without interpreting it. + +See the telemetry table chapter of the AMD Public PPR for the model in +use for the units and encodings of its fields. + More details on the interface and message definitions can be found in chapter "7 Host System Management Port (HSMP)" of the respective family/model PPR eg: https://docs.amd.com/v/u/en-US/55898_B1_pub_0_50 diff --git a/arch/x86/include/uapi/asm/amd_hsmp.h b/arch/x86/include/uapi/asm/amd_hsmp.h index 3e1b7cbe0f04..907acb93c456 100644 --- a/arch/x86/include/uapi/asm/amd_hsmp.h +++ b/arch/x86/include/uapi/asm/amd_hsmp.h @@ -808,4 +808,267 @@ enum hsmp_client_message_ids { HSMP_CLIENT_MSG_ID_MAX, }; +#define HSMP_TELEMETRY_RM_MAX_CCX 4 +#define HSMP_TELEMETRY_RM_CORES_PER_CCX 12 +#define HSMP_TELEMETRY_RM_FREQ_TABLE_SIZE 8 +#define HSMP_TELEMETRY_RM_NPU_BUSY_DOMAINS 3 +#define HSMP_TELEMETRY_RM_OC_DOMAINS 5 +#define HSMP_TELEMETRY_RM_OC_SUBDOMAINS 5 +#define HSMP_TELEMETRY_RM_OC_GUARDBANDS 3 + +/* + * Firmware lays out this table packed to a 4-byte boundary, so __u64 + * members here only need 4-byte alignment rather than the usual 8. Without + * this, the compiler's natural 8-byte alignment would insert padding + * firmware never put there, shifting every field after the first + * misaligned __u64 off its real offset. + */ +#pragma pack(push, 4) + +/* + * struct hsmp_telemetry_table_rm_iod - I/O die counters for RM telemetry. + * + * Accumulator (*_acc) fields are monotonic counters; consumers derive + * deltas across two snapshots and normalise by accumulation_counter. + */ +struct hsmp_telemetry_table_rm_iod { + __u32 accumulation_counter; + + /* SET VOLTAGES */ + __u64 vddcr_set_voltage; + __u64 vddcr_soc_set_voltage; + __u64 vddcr_npu_set_voltage; + __u64 vddcr_lp_set_voltage; + __u64 vddcr_gfx_set_voltage; + __u64 vdd_misc_set_voltage; + + /* TELEMETRY VOLTAGES */ + __u64 vddcr_telemetry_voltage; + __u64 vddcr_soc_telemetry_voltage; + __u64 vddcr_npu_telemetry_voltage; + __u64 vddcr_lp_telemetry_voltage; + __u64 vddcr_gfx_telemetry_voltage; + __u64 vdd_misc_telemetry_voltage; + + /* TELEMETRY POWERS */ + __u64 vddcr_telemetry_power; + __u64 vddcr_soc_telemetry_power; + __u64 vddcr_npu_telemetry_power; + __u64 vddcr_lp_telemetry_power; + __u64 vddcr_gfx_telemetry_power; + __u64 vdd_misc_telemetry_power; + + /* THROTTLERS - FAST PPT */ + __u32 fppt_fused_limit; + __u32 fppt_max_irm_limit; + __u32 fppt_max_pbo_limit; + __u32 fppt_limit; + __u64 fppt_value_acc; + __u32 fppt_residency_acc; + + /* THROTTLERS - SLOW PPT */ + __u32 sppt_fused_limit; + __u32 sppt_max_irm_limit; + __u32 sppt_max_pbo_limit; + __u32 sppt_limit; + __u64 sppt_value_acc; + __u32 sppt_residency_acc; + + /* THROTTLERS - SPL */ + __u32 spl_fused_limit; + __u32 spl_max_irm_limit; + __u32 spl_max_pbo_limit; + __u32 spl_limit; + __u64 spl_value_acc; + __u32 spl_residency_acc; + + /* THROTTLERS - TDC VDDCR */ + __u32 tdc_vddcr_fused_limit; + __u32 tdc_vddcr_max_irm_limit; + __u32 tdc_vddcr_max_pbo_limit; + __u32 tdc_vddcr_limit; + __u64 tdc_vddcr_value_acc; + __u32 tdc_vddcr_residency_acc; + + /* THROTTLERS - TDC VDDCR SOC */ + __u32 tdc_vddcr_soc_fused_limit; + __u32 tdc_vddcr_soc_max_irm_limit; + __u32 tdc_vddcr_soc_max_pbo_limit; + __u32 tdc_vddcr_soc_limit; + __u64 tdc_vddcr_soc_value_acc; + __u32 tdc_vddcr_soc_residency_acc; + + /* THROTTLERS - TDC VDDCR NPU */ + __u32 tdc_vddcr_npu_fused_limit; + __u32 tdc_vddcr_npu_max_irm_limit; + __u32 tdc_vddcr_npu_max_pbo_limit; + __u32 tdc_vddcr_npu_limit; + __u64 tdc_vddcr_npu_value_acc; + __u32 tdc_vddcr_npu_residency_acc; + + /* THROTTLERS - TDC VDDCR LP */ + __u32 tdc_vddcr_lp_fused_limit; + __u32 tdc_vddcr_lp_max_irm_limit; + __u32 tdc_vddcr_lp_max_pbo_limit; + __u32 tdc_vddcr_lp_limit; + __u64 tdc_vddcr_lp_value_acc; + __u32 tdc_vddcr_lp_residency_acc; + + /* THROTTLERS - TDC VDDCR GFX */ + __u32 tdc_vddcr_gfx_fused_limit; + __u32 tdc_vddcr_gfx_max_irm_limit; + __u32 tdc_vddcr_gfx_max_pbo_limit; + __u32 tdc_vddcr_gfx_limit; + __u64 tdc_vddcr_gfx_value_acc; + __u32 tdc_vddcr_gfx_residency_acc; + + /* THROTTLERS - EDC VDDCR */ + __u32 edc_vddcr_fused_limit; + __u32 edc_vddcr_max_irm_limit; + __u32 edc_vddcr_max_pbo_limit; + __u32 edc_vddcr_limit; + + /* THROTTLERS - THERMAL */ + __u32 thm_fused_limit; + __u32 thm_limit; + __u64 thm_value_acc; + __u32 thm_residency_acc; + __u32 prochot_residency_acc; + __u64 gfx_temp_acc; + __u64 soc_temp_acc; + __u32 p3t_fused_limit; + __u64 p3t_value_acc; + + /* POWER */ + __u64 system_power_acc; + __u64 apu_power_acc; + __u64 dgpu_power_acc; + __u64 npu_power_acc; + + /* FREQUENCIES */ + __u64 fclk_freq_eff_acc; + __u64 memclk_freq_eff_acc; + __u64 lclk_freq_eff_acc; + __u64 gfxclk_freq_eff_acc; + __u64 socclk_freq_eff_acc; + __u64 vclk_freq_eff_acc; + __u64 vpeclk_freq_eff_acc; + __u64 aieclk_freq_eff_acc; + __u64 npuhclk_freq_eff_acc; + + /* BANDWIDTH */ + __u64 dram_read_bandwidth; + __u64 dram_write_bandwidth; + + /* ACTIVITY MONITORS */ + __u64 gfx_busy_acc; + __u64 vcn_busy_acc; + __u64 npu_busy_acc[HSMP_TELEMETRY_RM_NPU_BUSY_DOMAINS]; + + /* STT (Skin Temperature Tracking) */ + __u32 stt_min_limit; + __u64 stt_apu_hot_spot_temp_acc; + __u64 stt_hs2_hot_spot_temp_acc; + __u32 stt_apu_temp_limit; + __u64 stt_apu_skin_temp_acc; + + /* RESIDENCIES - per-CCX CPU off */ + __u64 cpu_off_residency[HSMP_TELEMETRY_RM_MAX_CCX]; + + /* DF P-STATES */ + __u32 fclk_freq_table[HSMP_TELEMETRY_RM_FREQ_TABLE_SIZE]; + __u32 uclk_freq_table[HSMP_TELEMETRY_RM_FREQ_TABLE_SIZE]; + __u32 ddr_rate_table[HSMP_TELEMETRY_RM_FREQ_TABLE_SIZE]; + __u8 df_pstate_source[HSMP_TELEMETRY_RM_FREQ_TABLE_SIZE]; + + /* SYSTEM */ + __u8 gfx_disabled; + __u8 spare2[3]; + __u32 gfxclk_fmax; + __u8 cclk_core_fuse_enable[HSMP_TELEMETRY_RM_MAX_CCX][HSMP_TELEMETRY_RM_CORES_PER_CCX]; + __u8 cclk_core_enabled[HSMP_TELEMETRY_RM_MAX_CCX][HSMP_TELEMETRY_RM_CORES_PER_CCX]; + __u32 cclk_fmax[HSMP_TELEMETRY_RM_MAX_CCX][HSMP_TELEMETRY_RM_CORES_PER_CCX]; + + /* OVERCLOCK CAPABLE */ + __u8 cpu_precise_and_direct_oc_capable; + __u8 gfx_precise_and_direct_oc_capable; + __u8 pbo_basic_oc_capable; + __u8 pbo_advanced_oc_capable; + __u8 pbo_nitro_oc_capable; + __u8 memory_and_fabric_oc_capable; + __u8 misc_oc_capable; + __u8 extreme_cold_oc_capable; + __u8 down_config_control_capable; + __u8 spare0[3]; + + /* OVERCLOCK STATUS */ + __u32 fit_limit_scalar; + __u8 ln2_enabled; + __u8 cpu_precise_and_direct_oc_enabled; + __u8 gfx_precise_and_direct_oc_enabled; + __u8 spare1[2]; + __s8 psm_guardband[HSMP_TELEMETRY_RM_OC_DOMAINS] + [HSMP_TELEMETRY_RM_OC_SUBDOMAINS] + [HSMP_TELEMETRY_RM_OC_GUARDBANDS]; + __s32 core_power_limit_offset; + __u32 max_freq_offset[HSMP_TELEMETRY_RM_OC_DOMAINS]; + + __u64 npu_temp_acc; + __u64 df_pstate_residency_acc[HSMP_TELEMETRY_RM_FREQ_TABLE_SIZE]; + __u32 cclk_fboost; + + /* PMF */ + __u32 pmf_fast_apu_ppt_limit; + __u64 pmf_fast_apu_ppt_value_acc; + __u32 pmf_fast_apu_ppt_residency_acc; + + __u32 pmf_slow_apu_ppt_limit; + __u64 pmf_slow_apu_ppt_value_acc; + __u32 pmf_slow_apu_ppt_residency_acc; + + __u32 pmf_fast_spm_limit; + __u64 pmf_fast_spm_value_acc; + __u32 pmf_fast_spm_residency_acc; + + __u32 pmf_slow_spm_limit; + __u64 pmf_slow_spm_value_acc; + __u32 pmf_slow_spm_residency_acc; + + __u32 spare3[5]; +}; + +/* + * struct hsmp_telemetry_table_rm_ccx - Per-CCX core counters for RM telemetry. + * + * Arrays are sized for the maximum cores per CCX; use the + * cclk_core_enabled[] mask in struct hsmp_telemetry_table_rm_iod to tell + * which entries are valid. + */ +struct hsmp_telemetry_table_rm_ccx { + __u64 core_c0[HSMP_TELEMETRY_RM_CORES_PER_CCX]; + __u64 core_cc6[HSMP_TELEMETRY_RM_CORES_PER_CCX]; + __u64 core_freq[HSMP_TELEMETRY_RM_CORES_PER_CCX]; + __u64 core_freq_eff[HSMP_TELEMETRY_RM_CORES_PER_CCX]; + __u64 core_temp[HSMP_TELEMETRY_RM_CORES_PER_CCX]; + __u64 core_power[HSMP_TELEMETRY_RM_CORES_PER_CCX]; +}; + +/** + * struct hsmp_telemetry_table_rm - Top-level RM telemetry table. + * @iod: I/O die counters and per-rail/per-throttler/SYSTEM telemetry. + * @ccx: Per-CCX core counters, one entry per CCX. + * + * Layout of the table returned by HSMP_CLIENT_GET_METRICS_TABLE on the + * Family 1Ah client (Models 80h-8Fh and E0h-E3h), reported as table + * version 5 by HSMP_CLIENT_GET_METRICS_TABLE_VER. Units are + * firmware-defined; see the AMD HSMP/Ryzen Master SMC spec. Spare + * fields are firmware padding and must be preserved. + */ +struct hsmp_telemetry_table_rm { + struct hsmp_telemetry_table_rm_iod iod; + struct hsmp_telemetry_table_rm_ccx ccx[HSMP_TELEMETRY_RM_MAX_CCX]; +}; + +#pragma pack(pop) + #endif /*_ASM_X86_AMD_HSMP_H_*/ -- 2.34.1 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v5 0/4] platform/x86/amd/hsmp: Family 1Ah client support 2026-09-01 4:51 [PATCH v5 0/4] platform/x86/amd/hsmp: Family 1Ah client support Muralidhara M K ` (3 preceding siblings ...) 2026-09-01 4:51 ` [PATCH v5 4/4] platform/x86/amd/hsmp: Document and expose client telemetry table in UAPI Muralidhara M K @ 2026-09-01 12:24 ` Mario Limonciello 4 siblings, 0 replies; 10+ messages in thread From: Mario Limonciello @ 2026-09-01 12:24 UTC (permalink / raw) To: Muralidhara M K, ilpo.jarvinen; +Cc: platform-driver-x86, linux-kernel On 8/31/26 23:51, Muralidhara M K wrote: > This series enables the HSMP driver on the Family 1Ah client platforms, > Models 80h-8Fh and E0h-E3h. > > The client parts drive a different mailbox from the server HSMP > interface, but the latest BIOS describes it through ACPI _CRS/_DSD the > same way a server socket's mailbox is described, and the parts speak > the Ryzen Master SMC message set instead of the server message IDs. > Patches 1-3 teach the driver the message set and let the client reach > its mailbox through the existing _CRS/_DSD-driven MMIO path, leaving > server behaviour unchanged, and patch 4 includes the telemetry table > those parts return. Only the ACPI driver probes them. > > Changes in v5: > > - Patch 3: hsmp_pdev->proto_ver holds the Ryzen Master SMC interface > version on client platforms, a separate numbering space from the > server protocol versions in enum hsmp_proto_versions. Thanks for this change. My tags are still valid. > > Changes in v4: > > - SMU now answers the interface version query on client platforms, > so hsmp_desc_client.proto_ver_msg goes back to > HSMP_CLIENT_GET_INTERFACE_VER instead of > HSMP_CLIENT_GET_METRICS_TABLE_VER. Patch 3 is back down to just > the ACPI metric-table-DRAM-base change, since that was the only > other thing it did. > > Changes in v3: > > - is_client_platform() now tells client and server apart through the > ACPI-reported PM profile (FADT preferred_profile) instead of a > hardcoded Family 1Ah model range, the same signal amd-pstate > already keys off of. Future client generations are recognised as > long as firmware reports the right PM profile, with no driver > update needed. > - hsmp_desc() now resolves the running platform's descriptor once and > caches the pointer behind READ_ONCE()/WRITE_ONCE() instead of > recomputing it on every call. Concurrent first callers are benign, > since every one of them computes and stores that same pointer, so > the pair only needs to keep the load/store from being torn or > reordered by the compiler, not order it against anything else. > - The client message enum in amd_hsmp.h is now documented with > kernel-doc, one @member entry per message describing its inputs > and outputs, rather than a block comment plus a same-line comment > per enumerator. Noted there that not every platform supports every > message and that an unsupported one returns -ENOMSG. > - Patch 4: the Telemetry Table RM layout moved out of the .rst and > into amd_hsmp.h as real kernel-doc'd struct/enum declarations, > giving userspace one authoritative definition of the byte layout. > The .rst now just points at struct hsmp_telemetry_table_rm. The > structs are now also packed to a 4-byte boundary to match > firmware's actual layout, and the trailing NPU/PMF counters and > spare padding firmware carries after the overclocking fields are > no longer missing. Verified field-by-field against AMD's internal > metrics table header and end-to-end against a live snapshot off > Family 1Ah client hardware. > > Each patch builds individually and is clean under checkpatch.pl. > > Muralidhara M K (4): > platform/x86/amd/hsmp: Add HSMP client support for Family 1Ah > platform/x86/amd/hsmp: Route metric table through the client messages > platform/x86/amd/hsmp: Add ACPI client support for Family 1Ah > platform/x86/amd/hsmp: Document and expose client telemetry table in > UAPI > > Documentation/arch/x86/amd_hsmp.rst | 24 +- > arch/x86/include/uapi/asm/amd_hsmp.h | 407 +++++++++++++++++++++++++++ > drivers/platform/x86/amd/hsmp/acpi.c | 3 +- > drivers/platform/x86/amd/hsmp/hsmp.c | 269 +++++++++++++++--- > drivers/platform/x86/amd/hsmp/hsmp.h | 27 ++ > 5 files changed, 696 insertions(+), 34 deletions(-) > > > base-commit: 08dbfad3f5040f5bdb6c529da20d6d4e81fefd72 ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-09-18 11:46 UTC | newest] Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-09-01 4:51 [PATCH v5 0/4] platform/x86/amd/hsmp: Family 1Ah client support Muralidhara M K 2026-09-01 4:51 ` [PATCH v5 1/4] platform/x86/amd/hsmp: Add HSMP client support for Family 1Ah Muralidhara M K 2026-09-18 11:34 ` Ilpo Järvinen 2026-09-18 11:46 ` Ilpo Järvinen 2026-09-01 4:51 ` [PATCH v5 2/4] platform/x86/amd/hsmp: Route metric table through the client messages Muralidhara M K 2026-09-01 4:51 ` [PATCH v5 3/4] platform/x86/amd/hsmp: Add ACPI client support for Family 1Ah Muralidhara M K 2026-09-18 11:39 ` Ilpo Järvinen 2026-09-18 11:43 ` Ilpo Järvinen 2026-09-01 4:51 ` [PATCH v5 4/4] platform/x86/amd/hsmp: Document and expose client telemetry table in UAPI Muralidhara M K 2026-09-01 12:24 ` [PATCH v5 0/4] platform/x86/amd/hsmp: Family 1Ah client support Mario Limonciello
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®