[PATCH v2 3/4] platform/x86/amd/hsmp: Add ACPI client support for Family 1Ah

From: Muralidhara M K

Date: Fri Jul 31 2026 - 12:56:59 EST


On the Family 1Ah client platforms (Models 80h-8Fh and E0h-E3h) the ACPI
HSMP device (HID AMDI0097) is present but exposes neither a _CRS memory
window nor a _DSD mailbox-offset package, and names its socket
differently.

The missing _CRS decides how the mailbox is reached. On the server it is
an MMIO window that firmware describes in _CRS and the driver maps. The
client supports no such window; its mailbox sits in SMN register space
at the fixed addresses the platform descriptor carries, so reach it with
amd_smn_hsmp_rdwr() for both the reads and the writes the handshake
needs.

Handle the client explicitly:

- hsmp_get_uid(): strip the "ID" prefix only when present, so both
forms are accepted; kstrtou16() still rejects anything else.
- hsmp_parse_acpi_table(): for is_client_platform(), skip _CRS/_DSD and
take the fixed client mailbox addresses from the platform descriptor.
- init_acpi(): treat the interface-version query as non-fatal on the
client and fetch the metric table whatever version was reported.

The client branch publishes sock->dev last with smp_store_release(), as
the server path does: it is the readiness gate the data plane tests with
smp_load_acquire(), so it must not become visible before the accessor and
mailbox offsets it depends on.

Server behaviour is unchanged.

Signed-off-by: Muralidhara M K <muralidhara.mk@xxxxxxx>
---
drivers/platform/x86/amd/hsmp/acpi.c | 77 ++++++++++++++++++++++++----
1 file changed, 68 insertions(+), 9 deletions(-)

diff --git a/drivers/platform/x86/amd/hsmp/acpi.c b/drivers/platform/x86/amd/hsmp/acpi.c
index 8257cd1da48e..80a6ede0f0e0 100644
--- a/drivers/platform/x86/amd/hsmp/acpi.c
+++ b/drivers/platform/x86/amd/hsmp/acpi.c
@@ -10,6 +10,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <asm/amd/hsmp.h>
+#include <asm/amd/node.h>

#include <linux/acpi.h>
#include <linux/array_size.h>
@@ -71,6 +72,26 @@ static int amd_hsmp_acpi_rdwr(struct hsmp_socket *sock, u32 offset,
return 0;
}

+/*
+ * Family 1Ah client platforms (Models 80h-8Fh and E0h-E3h) expose the HSMP
+ * ACPI device (HID AMDI0097, ACPI path \_SB_.TELD) but, unlike server
+ * platforms, the device provides neither a _CRS memory window nor a _DSD
+ * mailbox-offset package.
+ *
+ * That difference is what decides how the mailbox is reached. On the server
+ * the mailbox is an MMIO window: firmware describes it in _CRS, the driver
+ * maps it, and every access lands inside a region firmware has vouched for.
+ * The client has no such window to map, so the mailbox is reached in SMN
+ * register space instead.
+ */
+
+static int amd_hsmp_acpi_smn_rdwr(struct hsmp_socket *sock, u32 offset,
+ u32 *value, bool write)
+{
+ return amd_smn_hsmp_rdwr(sock->sock_ind, sock->mbinfo.base_addr + offset,
+ value, write);
+}
+
/* This is the UUID used for HSMP */
static const guid_t acpi_hsmp_uuid = GUID_INIT(0xb74d619d, 0x5707, 0x48bd,
0xa6, 0x9f, 0x4e, 0xa2,
@@ -89,15 +110,19 @@ static inline int hsmp_get_uid(struct device *dev, u16 *sock_ind)
char *uid;

/*
- * UID (ID00, ID01..IDXX) is used for differentiating sockets,
- * read it and strip the "ID" part of it and convert the remaining
- * bytes to integer.
+ * Server firmware differentiates the sockets with "ID00", "ID01"..
+ * "IDXX", so strip the "ID" before converting the rest. The client
+ * device carries a bare socket number with no prefix to strip, so
+ * only skip one when it is actually there.
*/
uid = acpi_device_uid(ACPI_COMPANION(dev));
- if (!uid || strlen(uid) < 3)
+ if (!uid)
return -EINVAL;

- return kstrtou16(uid + 2, 10, sock_ind);
+ if (!strncmp(uid, "ID", 2))
+ uid += 2;
+
+ return kstrtou16(uid, 10, sock_ind);
}

static acpi_status hsmp_resource(struct acpi_resource *res, void *data)
@@ -240,12 +265,34 @@ static int hsmp_parse_acpi_table(struct device *dev, u16 sock_ind)
int ret;

sock->sock_ind = sock_ind;
- sock->amd_hsmp_rdwr = amd_hsmp_acpi_rdwr;

sema_init(&sock->hsmp_sem, 1);

dev_set_drvdata(dev, sock);

+ /*
+ * On the client platforms the bound ACPI device has no _CRS window to
+ * map, so take the fixed client SMN mailbox addresses from the
+ * platform descriptor and reach them over SMN.
+ */
+ if (is_client_platform()) {
+ sock->amd_hsmp_rdwr = amd_hsmp_acpi_smn_rdwr;
+ sock->mbinfo = *hsmp_pdev->desc->mbinfo;
+ dev_dbg(dev, "Client SMN mailbox at 0x%08x\n",
+ sock->mbinfo.base_addr);
+ /*
+ * Publish sock->dev last, for the same reason as the server
+ * path below: it is the readiness gate for the data plane, so
+ * it must not become visible before the accessor and the
+ * mailbox offsets this socket needs.
+ */
+ smp_store_release(&sock->dev, dev);
+
+ return 0;
+ }
+
+ sock->amd_hsmp_rdwr = amd_hsmp_acpi_rdwr;
+
/* Read MP1 base address from CRS method */
ret = hsmp_read_acpi_crs(dev, sock);
if (ret)
@@ -553,11 +600,23 @@ static int init_acpi(struct device *dev)

ret = hsmp_cache_proto_ver(sock_ind);
if (ret) {
- dev_err(dev, "Failed to read HSMP protocol version\n");
- return ret;
+ /*
+ * Some client SMU builds reject the interface-version query
+ * with "invalid message" even though the mailbox is functional
+ * (the preceding test message succeeds). The client does not
+ * need the version to reach its metric table, so treat this as
+ * non-fatal there.
+ */
+ if (is_client_platform()) {
+ dev_warn(dev,
+ "Interface version query unsupported on client SMU; continuing\n");
+ } else {
+ dev_err(dev, "Failed to read HSMP protocol version\n");
+ return ret;
+ }
}

- if (hsmp_pdev->proto_ver >= HSMP_PROTO_VER6) {
+ if (is_client_platform() || 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