From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5C0F6497392; Fri, 18 Sep 2026 11:34:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=192.198.163.12 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789731250; cv=none; b=fmCWY24hyJnEMbihzL/h7WySq1SOY8TC9TmyUAzuz2f3Ggwnc60Embh8ZvS/oVOZ3XIuoJ8YSuqgkTGVmrZEA3k7mhS+nm068GtqiyqRNLFasG/MnsAfW+oJUJFMIGYIPqtw88S2hROSGVYiOPTO8+h/b1E4D8VnoffxnH6nTKk= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1789731250; c=relaxed/simple; bh=X2rniIQUJfZdtta3aNvqRjrGdFtRDPyyaJvLNKuzETg=; h=From:Date:To:cc:Subject:In-Reply-To:Message-ID:References: MIME-Version:Content-Type; b=WkS4bjcwiYWGwEaMgUYwSrI74s4yGGYosEoiUjnqphdlZENkLJTcnAb9t0/lwv2ybQ+s44mXGNOpchUVrzj/4HqsRVUoL5Hv9kiM9uQM7+iH7+ox60l9Ks+o68GqUhhk7PrqBKwtqCSLQrGwZPJtD4rmX3dm6Rcxn1R513mqGWI= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=pass smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=ZfJNclB4; arc=none smtp.client-ip=192.198.163.12 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="ZfJNclB4" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1789731247; x=1821267247; h=from:date:to:cc:subject:in-reply-to:message-id: references:mime-version; bh=X2rniIQUJfZdtta3aNvqRjrGdFtRDPyyaJvLNKuzETg=; b=ZfJNclB4I4S7VUbinpNHpKMiH770Px/kOhu0PnjKF+HIuh91c9LWV4q4 S+KRzsN4NuGGQYmXqCp5MIzLVzDLTpMqHWG50eCDrIDsn8BQw7CUsgLCN rf93MySpfSZtq6FjqsKQhN2GGyBnuO9UQnsbMin51LWYxvT8z0DJ5By17 eLAmvjLOI3DwFswegzeJM2LKhJnT2zcyTpyxaDMmsuby9BdJG0Mp7FkUp hPCrN/RLpllGZ8vkVfemQTTVsH3krIg/BE9vTIUkad8UG6JIxoDgX3qD2 o78ML8p7TW8/vTaF2WKAtBZJLmMQn0eRIkjhx7I+wmngtzGM617PUL7hH Q==; X-CSE-ConnectionGUID: VuRYIczSSJaHIFCocBHZqg== X-CSE-MsgGUID: TZsjswcZTvCJXAuSOJ0SkA== X-IronPort-AV: E=McAfee;i="6800,10657,11908"; a="94063140" X-IronPort-AV: E=Sophos;i="6.27,108,1787036400"; d="scan'208";a="94063140" Received: from fmviesa012.fm.intel.com ([10.60.135.152]) by fmvoesa106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Sep 2026 04:34:07 -0700 X-CSE-ConnectionGUID: vjxjB2Z1T3a5Z3RiwxktzA== X-CSE-MsgGUID: R76PDIhfSJi5YtPegTVDcQ== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.27,108,1787036400"; d="scan'208";a="2550301" Received: from ijarvine-mobl1.ger.corp.intel.com (HELO localhost) ([10.245.245.223]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 18 Sep 2026 04:34:04 -0700 From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= Date: Fri, 18 Sep 2026 14:34:01 +0300 (EEST) To: Muralidhara M K cc: Mario.Limonciello@amd.com, platform-driver-x86@vger.kernel.org, LKML , Mario Limonciello Subject: Re: [PATCH v5 1/4] platform/x86/amd/hsmp: Add HSMP client support for Family 1Ah In-Reply-To: <20260901045134.2833282-2-muralidhara.mk@amd.com> Message-ID: References: <20260901045134.2833282-1-muralidhara.mk@amd.com> <20260901045134.2833282-2-muralidhara.mk@amd.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII 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 > Reviewed-by: Mario Limonciello (AMD) > --- > 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 > > #include > +#include > +#include > #include > #include > #include > @@ -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 > + > +#include > #include > #include > #include > @@ -17,6 +20,7 @@ > #include > #include > #include > +#include > #include > #include > #include > @@ -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.