From nobody Sun Jun 14 14:29:41 2026 Received: from out28-106.mail.aliyun.com (out28-106.mail.aliyun.com [115.124.28.106]) (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 AE8AF3A963B; Fri, 3 Apr 2026 11:03:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.106 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775214223; cv=none; b=tXN9O54SqULxzmZOSgIUH7gYcxChOFSuNs7wUQ06CMX6dn8cTSkClSCfo8hx3CEXnE6IXg6yOTtmNrP3RtaImlFn4GzGsClSBx64dTZ9lsmOqCUu2TMxIEjsmYEgpaSAn4VA2i2qPkWq095l83E22ZdouNMajaQeQVB42VNo748= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775214223; c=relaxed/simple; bh=wU6MqaJwmh508BLS+CsAdfsXSKdEuFevdmHj327TAZk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZWaIiw/8F7rZJBomvYIQEeS6eIID0NWOZsRpY9i/jzIzTlA4C9mnc+BMPsDFt7E8WIauJ95gy3rI0G1iOHRXll3+F93rzUvmmSyaVmCEi2zQxUpzmJiibwjSsV/kDBEgiw6XqAnanYQsJF/oWc4QZ23kchK6p1axmS43pHbZUaA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=115.124.28.106 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436269|-1;CH=blue;DM=|OVERLOAD|false|;DS=CONTINUE|ham_alarm|0.00181366-0.00227821-0.995908;FP=10767401068509611067|2|1|2|0|-1|-1|-1;HT=maildocker-contentspam033037071049;MF=shiaichun@open-hieco.net;NM=1;PH=DS;RN=5;RT=5;SR=0;TI=SMTPD_---.h4TkLIY_1775213879; Received: from localhost.localdomain(mailfrom:shiaichun@open-hieco.net fp:SMTPD_---.h4TkLIY_1775213879 cluster:ay29) by smtp.aliyun-inc.com; Fri, 03 Apr 2026 18:58:10 +0800 From: Aichun Shi To: yazen.ghannam@amd.com Cc: tglx@linutronix.de, linux-edac@vger.kernel.org, linux-kernel@vger.kernel.org, shiaichun@open-hieco.net Subject: [RFC PATCH 01/10] ras/amd/atl: Add Hygon DF1 Data Fabric system information helper Date: Fri, 3 Apr 2026 18:57:25 +0800 Message-ID: <7b3526bf4782aaa9ee691bddc6cb131836f15369.1775213147.git.shiaichun@open-hieco.net> X-Mailer: git-send-email 2.47.3 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add Hygon Family 0x18 model 0x4/0x5 (Hygon DF1) support as the start. Add Hygon DF1 Data Fabric system information that Hygon address translation function depends on later. Prepare hygon_get_df_system_info() to be called by amd_atl_init() later. - Add hygon/reg_fields.h for Hygon-specific register field definitions with Hygon DF1 System Fabric ID Mask defined first. - Add hygon/system.c for Hygon-specific implementation similar to system.c for AMD. - Add HYGON_DF1 to enum df_revisions in internal.h. - Add hygon_determine_df_rev() to detect models 0x4/0x5 as Hygon DF1 and get system information. - Use get_dram_hole_base() and dump_df_cfg() shared from system.c and exported in internal.h to avoid duplicate code. - Build hygon/system.c from the Makefile as an amd_atl object. Signed-off-by: Aichun Shi --- drivers/ras/amd/atl/Makefile | 2 + drivers/ras/amd/atl/hygon/reg_fields.h | 60 +++++++++++++++++++++ drivers/ras/amd/atl/hygon/system.c | 73 ++++++++++++++++++++++++++ drivers/ras/amd/atl/internal.h | 7 +++ drivers/ras/amd/atl/system.c | 4 +- 5 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 drivers/ras/amd/atl/hygon/reg_fields.h create mode 100644 drivers/ras/amd/atl/hygon/system.c diff --git a/drivers/ras/amd/atl/Makefile b/drivers/ras/amd/atl/Makefile index b56892c0c0d9..3716fe068eb6 100644 --- a/drivers/ras/amd/atl/Makefile +++ b/drivers/ras/amd/atl/Makefile @@ -15,6 +15,8 @@ amd_atl-y +=3D map.o amd_atl-y +=3D system.o amd_atl-y +=3D umc.o =20 +amd_atl-y +=3D hygon/system.o + amd_atl-$(CONFIG_AMD_ATL_PRM) +=3D prm.o =20 obj-$(CONFIG_AMD_ATL) +=3D amd_atl.o diff --git a/drivers/ras/amd/atl/hygon/reg_fields.h b/drivers/ras/amd/atl/h= ygon/reg_fields.h new file mode 100644 index 000000000000..2c1193639c6c --- /dev/null +++ b/drivers/ras/amd/atl/hygon/reg_fields.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * AMD Address Translation Library + * + * reg_fields.h : Register field definitions for Hygon + * + * Author: AichunShi + */ + +/* + * Die ID Mask + * + * Access type: Broadcast + * + * Register + * Rev Fieldname Bits + * + * D18F1x208 [System Fabric ID Mask] + * HYGON_DF1 DieIdMask [9:0] + */ +#define HYGON_DF1_DIE_ID_MASK GENMASK(9, 0) + +/* + * Die ID Shift + * + * Access type: Broadcast + * + * Register + * Rev Fieldname Bits + * + * D18F1x208 [System Fabric ID Mask] + * HYGON_DF1 DieIdShift [15:12] + */ +#define HYGON_DF1_DIE_ID_SHIFT GENMASK(15, 12) + +/* + * Socket ID Mask + * + * Access type: Broadcast + * + * Register + * Rev Fieldname Bits + * + * D18F1x208 [System Fabric ID Mask] + * HYGON_DF1 SocketIdMask [25:16] + */ +#define HYGON_DF1_SOCKET_ID_MASK GENMASK(25, 16) + +/* + * Socket ID Shift + * + * Access type: Broadcast + * + * Register + * Rev Fieldname Bits + * + * D18F1x208 [System Fabric ID Mask] + * HYGON_DF1 SocketIdShift [31:28] + */ +#define HYGON_DF1_SOCKET_ID_SHIFT GENMASK(31, 28) diff --git a/drivers/ras/amd/atl/hygon/system.c b/drivers/ras/amd/atl/hygon= /system.c new file mode 100644 index 000000000000..2a149cfc34c1 --- /dev/null +++ b/drivers/ras/amd/atl/hygon/system.c @@ -0,0 +1,73 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD Address Translation Library + * + * system.c : Functions to read and save system-wide data for Hygon + * + * Author: AichunShi + */ + +#include "../internal.h" + +static void hygon_df_get_masks_shifts(u32 mask0) +{ + switch (df_cfg.rev) { + case HYGON_DF1: + df_cfg.socket_id_shift =3D FIELD_GET(HYGON_DF1_SOCKET_ID_SHIFT, mask0); + df_cfg.socket_id_mask =3D FIELD_GET(HYGON_DF1_SOCKET_ID_MASK, mask0); + df_cfg.die_id_shift =3D FIELD_GET(HYGON_DF1_DIE_ID_SHIFT, mask0); + df_cfg.die_id_mask =3D FIELD_GET(HYGON_DF1_DIE_ID_MASK, mask0); + break; + default: + atl_debug_on_bad_df_rev(); + return; + } +} + +static int hygon_determine_df_rev(void) +{ + u32 fabric_id_mask0; + + if (boot_cpu_data.x86_model =3D=3D 0x4 || boot_cpu_data.x86_model =3D=3D = 0x5) + df_cfg.rev =3D HYGON_DF1; + + /* Read D18F1x208 (SystemFabricIdMask). */ + if (df_indirect_read_broadcast(0, 1, 0x208, &fabric_id_mask0)) + return -EINVAL; + + hygon_df_get_masks_shifts(fabric_id_mask0); + + return 0; +} + +static void hygon_get_num_maps(void) +{ + switch (df_cfg.rev) { + case HYGON_DF1: + df_cfg.num_coh_st_maps =3D 2; + break; + default: + atl_debug_on_bad_df_rev(); + } +} + +int hygon_get_df_system_info(void) +{ + int ret; + + ret =3D hygon_determine_df_rev(); + if (ret) { + pr_warn("Failed to determine DF Revision"); + df_cfg.rev =3D UNKNOWN; + return ret; + } + + hygon_get_num_maps(); + + if (get_dram_hole_base()) + pr_warn("Failed to read DRAM hole base"); + + dump_df_cfg(); + + return 0; +} diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h index 82a56d9c2be1..19651cf9e978 100644 --- a/drivers/ras/amd/atl/internal.h +++ b/drivers/ras/amd/atl/internal.h @@ -21,6 +21,7 @@ #include =20 #include "reg_fields.h" +#include "hygon/reg_fields.h" =20 #undef pr_fmt #define pr_fmt(fmt) "amd_atl: " fmt @@ -42,6 +43,7 @@ =20 enum df_revisions { UNKNOWN, + HYGON_DF1, DF2, DF3, DF3p5, @@ -284,6 +286,11 @@ unsigned long convert_umc_mca_addr_to_sys_addr(struct = atl_err *err); u64 add_base_and_hole(struct addr_ctx *ctx, u64 addr); u64 remove_base_and_hole(struct addr_ctx *ctx, u64 addr); =20 +int get_dram_hole_base(void); +void dump_df_cfg(void); + +int hygon_get_df_system_info(void); + /* GUIDs for PRM handlers */ extern const guid_t norm_to_sys_guid; =20 diff --git a/drivers/ras/amd/atl/system.c b/drivers/ras/amd/atl/system.c index 812a30e21d3a..eb420978febb 100644 --- a/drivers/ras/amd/atl/system.c +++ b/drivers/ras/amd/atl/system.c @@ -231,7 +231,7 @@ static int determine_df_rev(void) return 0; } =20 -static int get_dram_hole_base(void) +int get_dram_hole_base(void) { u8 func =3D 0; =20 @@ -274,7 +274,7 @@ static void apply_node_id_shift(void) df_cfg.socket_id_shift +=3D df_cfg.node_id_shift; } =20 -static void dump_df_cfg(void) +void dump_df_cfg(void) { pr_debug("rev=3D0x%x", df_cfg.rev); =20 --=20 2.47.3 From nobody Sun Jun 14 14:29:41 2026 Received: from out28-133.mail.aliyun.com (out28-133.mail.aliyun.com [115.124.28.133]) (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 0AA373932D0; Fri, 3 Apr 2026 10:58:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.133 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775213915; cv=none; b=uvZxYi4ZhX0DDYyjwA7EWrtUdrGpJUavFUWCyPVycIfSfxl6ZJOoA5XdPgrmq6oTbKgXLhF0JFLJJ2jVkM/2/mTWyBymEChn4n8Q5PEK6DdrLqchA/cmGU323j24SdFsY+Nwx5W+aZgVe6Wrp9yeB/DoM91aMtRX56APoZiAtwY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775213915; c=relaxed/simple; bh=vKEtvJWeZd+iTcHyIOw/LB6//erbk/gUhfCeJ5WvTQk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=E1E7FlpEfdu8/Y4O8weJBt6BLoZwALPByEu5NbsOP2PWjYrQEXW9juYPeEnRMpjXwq845M/psYufpt6lbll8/NwpvGVxKuqSFluuRvhi4a705fMW+O8hcnsbxcs+Z9wJYIkF7WjvoS5RMk9WI+hrdVeBA5ebOfw/QJGpfNtS5Ds= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=115.124.28.133 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436259|-1;CH=blue;DM=|OVERLOAD|false|;DS=CONTINUE|ham_system_inform|0.00256868-0.000312611-0.997119;FP=1039342476406293715|2|1|2|0|-1|-1|-1;HT=maildocker-contentspam033037025160;MF=shiaichun@open-hieco.net;NM=1;PH=DS;RN=5;RT=5;SR=0;TI=SMTPD_---.h4TkLSq_1775213890; Received: from localhost.localdomain(mailfrom:shiaichun@open-hieco.net fp:SMTPD_---.h4TkLSq_1775213890 cluster:ay29) by smtp.aliyun-inc.com; Fri, 03 Apr 2026 18:58:19 +0800 From: Aichun Shi To: yazen.ghannam@amd.com Cc: tglx@linutronix.de, linux-edac@vger.kernel.org, linux-kernel@vger.kernel.org, shiaichun@open-hieco.net Subject: [RFC PATCH 02/10] ras/amd/atl: Add Hygon DF1 DRAM address map decoding helper Date: Fri, 3 Apr 2026 18:57:26 +0800 Message-ID: <92b2f7493f7cbd6273050af4814de6c0923678d3.1775213147.git.shiaichun@open-hieco.net> X-Mailer: git-send-email 2.47.3 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add Hygon DF1 DRAM address map decoding function that Hygon address translation pipeline depends on later. Prepare hygon_get_address_map() to be called by hygon/core.c later. - Add struct hygon_chan_intlv in addr_ctx and HYGON_DF1_3CHAN in enum intlv_modes to internal.h for Hygon DF1 three-channel interleave mode. - Add hygon/map.c for Hygon-specific implementation similar to map.c for AMD. - Get the coherent-station fabric ID, handle normalized offsets, read Hygon DF1 specific channel interleave state, and derive global interleave metadata (modes, bit positions, die/socket/channel counts). - Use df2_get_dram_addr_map(), valid_map(), and dump_address_map() shared from map.c and exported in internal.h to avoid duplicate code. - Build hygon/map.c from the Makefile as an amd_atl object. Signed-off-by: Aichun Shi --- drivers/ras/amd/atl/Makefile | 1 + drivers/ras/amd/atl/hygon/map.c | 337 +++++++++++++++++++++++++ drivers/ras/amd/atl/hygon/reg_fields.h | 78 ++++++ drivers/ras/amd/atl/internal.h | 17 ++ drivers/ras/amd/atl/map.c | 6 +- 5 files changed, 436 insertions(+), 3 deletions(-) create mode 100644 drivers/ras/amd/atl/hygon/map.c diff --git a/drivers/ras/amd/atl/Makefile b/drivers/ras/amd/atl/Makefile index 3716fe068eb6..105c11015f4c 100644 --- a/drivers/ras/amd/atl/Makefile +++ b/drivers/ras/amd/atl/Makefile @@ -15,6 +15,7 @@ amd_atl-y +=3D map.o amd_atl-y +=3D system.o amd_atl-y +=3D umc.o =20 +amd_atl-y +=3D hygon/map.o amd_atl-y +=3D hygon/system.o =20 amd_atl-$(CONFIG_AMD_ATL_PRM) +=3D prm.o diff --git a/drivers/ras/amd/atl/hygon/map.c b/drivers/ras/amd/atl/hygon/ma= p.c new file mode 100644 index 000000000000..2194c10ff587 --- /dev/null +++ b/drivers/ras/amd/atl/hygon/map.c @@ -0,0 +1,337 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD Address Translation Library + * + * map.c : Functions to read and decode DRAM address maps for Hygon + * + * Author: AichunShi + */ + +#include "../internal.h" + +static int hygon_df_get_intlv_mode(struct addr_ctx *ctx) +{ + ctx->map.intlv_mode =3D FIELD_GET(HYGON_DF1_INTLV_NUM_CHAN, ctx->map.base= ); + + if (df_cfg.rev =3D=3D HYGON_DF1 && ctx->map.intlv_mode =3D=3D 2) + ctx->map.intlv_mode =3D HYGON_DF1_3CHAN; + + if (ctx->map.intlv_mode =3D=3D 8) + ctx->map.intlv_mode =3D DF2_2CHAN_HASH; + + if (ctx->map.intlv_mode !=3D NONE && + ctx->map.intlv_mode !=3D NOHASH_2CHAN && + ctx->map.intlv_mode !=3D HYGON_DF1_3CHAN && + ctx->map.intlv_mode !=3D NOHASH_4CHAN && + ctx->map.intlv_mode !=3D NOHASH_8CHAN && + ctx->map.intlv_mode !=3D NOHASH_16CHAN && + ctx->map.intlv_mode !=3D DF2_2CHAN_HASH) + return -EINVAL; + + return 0; +} + +static u64 hygon_get_hi_addr_offset(u32 reg_dram_offset) +{ + u8 shift =3D DF_DRAM_BASE_LIMIT_LSB; + u64 hi_addr_offset; + + switch (df_cfg.rev) { + case HYGON_DF1: + hi_addr_offset =3D FIELD_GET(HYGON_DF1_HI_ADDR_OFFSET, reg_dram_offset); + break; + default: + hi_addr_offset =3D 0; + atl_debug_on_bad_df_rev(); + } + + return hi_addr_offset << shift; +} + +/* + * Returns: 0 if offset is disabled. + * 1 if offset is enabled. + * -EINVAL on error. + */ +static int hygon_get_dram_offset(struct addr_ctx *ctx, u64 *norm_offset) +{ + u32 reg_dram_offset; + u8 map_num; + + /* Should not be called for map 0. */ + if (!ctx->map.num) { + atl_debug(ctx, "Trying to find DRAM offset for map 0"); + return -EINVAL; + } + + /* + * DramOffset registers don't exist for map 0, so the base register + * actually refers to map 1. + * Adjust the map_num for the register offsets. + */ + map_num =3D ctx->map.num - 1; + + if (df_cfg.rev >=3D HYGON_DF1) { + /* Read D18F0x214 (DramOffset) */ + if (df_indirect_read_instance(ctx->node_id, 0, 0x214 + (4 * map_num), + ctx->inst_id, ®_dram_offset)) + return -EINVAL; + } else { + return -EINVAL; + } + + if (!FIELD_GET(DF_HI_ADDR_OFFSET_EN, reg_dram_offset)) + return 0; + + *norm_offset =3D hygon_get_hi_addr_offset(reg_dram_offset); + + return 1; +} + +#define HYGON_DF1_CHAN_ADDR_SEL BIT(24) +#define HYGON_DF1_CHAN_HASH_ENABLE BIT(23) +#define HYGON_DF1_DDR5_ENABLE BIT(19) +static int hygon_df1_get_dram_addr_map(struct addr_ctx *ctx) +{ + if (df2_get_dram_addr_map(ctx)) + return -EINVAL; + + /* Read D18F2x48 */ + if (df_indirect_read_instance(ctx->node_id, 2, 0x48, + ctx->inst_id, &ctx->map.intlv)) + return -EINVAL; + + ctx->chan_intlv_hygon.chan_addr_sel =3D + FIELD_GET(HYGON_DF1_CHAN_ADDR_SEL, ctx->map.intlv); + ctx->chan_intlv_hygon.chan_hash_enable =3D + FIELD_GET(HYGON_DF1_CHAN_HASH_ENABLE, ctx->map.intlv); + ctx->chan_intlv_hygon.ddr5_enable =3D + FIELD_GET(HYGON_DF1_DDR5_ENABLE, ctx->map.intlv); + + if (ctx->chan_intlv_hygon.ddr5_enable) { + u64 low_addr, high_addr; + + ctx->chan_intlv_hygon.start_bit =3D ctx->chan_intlv_hygon.chan_addr_sel = ? 8 : 7; + low_addr =3D ctx->ret_addr & GENMASK_ULL(ctx->chan_intlv_hygon.start_bit= - 1, 0); + high_addr =3D (ctx->ret_addr & GENMASK_ULL(63, ctx->chan_intlv_hygon.sta= rt_bit)) << 1; + ctx->ret_addr =3D high_addr | low_addr; + } + + return 0; +} + +static int hygon_get_dram_addr_map(struct addr_ctx *ctx) +{ + switch (df_cfg.rev) { + case HYGON_DF1: return hygon_df1_get_dram_addr_map(ctx); + default: + atl_debug_on_bad_df_rev(); + return -EINVAL; + } +} + +static int hygon_get_coh_st_fabric_id(struct addr_ctx *ctx) +{ + u32 reg; + + /* Read D18F0x50 (FabricBlockInstanceInformation3). */ + if (df_indirect_read_instance(ctx->node_id, 0, 0x50, ctx->inst_id, ®)) + return -EINVAL; + + switch (df_cfg.rev) { + case HYGON_DF1: + ctx->coh_st_fabric_id =3D FIELD_GET(HYGON_DF1_COH_ST_FABRIC_ID, reg); + break; + default: + atl_debug_on_bad_df_rev(); + return -EINVAL; + } + + return 0; +} + +static int hygon_find_normalized_offset(struct addr_ctx *ctx, u64 *norm_of= fset) +{ + u64 last_offset =3D 0; + int ret; + + for (ctx->map.num =3D 1; ctx->map.num < df_cfg.num_coh_st_maps; ctx->map.= num++) { + ret =3D hygon_get_dram_offset(ctx, norm_offset); + if (ret < 0) + return ret; + + /* Continue search if this map's offset is not enabled. */ + if (!ret) + continue; + + /* Enabled offsets should never be 0. */ + if (*norm_offset =3D=3D 0) { + atl_debug(ctx, "Enabled map %u offset is 0", ctx->map.num); + return -EINVAL; + } + + /* Offsets should always increase from one map to the next. */ + if (*norm_offset <=3D last_offset) { + atl_debug(ctx, "Map %u offset (0x%016llx) <=3D previous (0x%016llx)", + ctx->map.num, *norm_offset, last_offset); + return -EINVAL; + } + + /* Match if this map's offset is less than the current calculated addres= s. */ + if (ctx->ret_addr >=3D *norm_offset) + break; + + last_offset =3D *norm_offset; + } + + /* + * Finished search without finding a match. + * Reset to map 0 and no offset. + */ + if (ctx->map.num >=3D df_cfg.num_coh_st_maps) { + ctx->map.num =3D 0; + *norm_offset =3D 0; + } + + return 0; +} + +static int hygon_get_address_map_common(struct addr_ctx *ctx) +{ + u64 norm_offset =3D 0; + + if (hygon_get_coh_st_fabric_id(ctx)) + return -EINVAL; + + if (hygon_find_normalized_offset(ctx, &norm_offset)) + return -EINVAL; + + ctx->ret_addr -=3D norm_offset; + + if (hygon_get_dram_addr_map(ctx)) + return -EINVAL; + + if (!valid_map(ctx)) + return -EINVAL; + + return 0; +} + +static u8 hygon_get_num_intlv_chan(struct addr_ctx *ctx) +{ + switch (ctx->map.intlv_mode) { + case NONE: + return 1; + case NOHASH_2CHAN: + return 2; + case HYGON_DF1_3CHAN: + return 3; + case NOHASH_4CHAN: + return 4; + case NOHASH_8CHAN: + return 8; + case NOHASH_16CHAN: + return 16; + case NOHASH_32CHAN: + return 32; + default: + atl_debug_on_bad_intlv_mode(ctx); + return 0; + } +} + +static void hygon_calculate_intlv_bits(struct addr_ctx *ctx) +{ + ctx->map.num_intlv_chan =3D hygon_get_num_intlv_chan(ctx); + + ctx->map.total_intlv_chan =3D ctx->map.num_intlv_chan; + ctx->map.total_intlv_chan *=3D ctx->map.num_intlv_dies; + ctx->map.total_intlv_chan *=3D ctx->map.num_intlv_sockets; + + /* + * Get the number of bits needed to cover this many channels. + * order_base_2() rounds up automatically. + */ + ctx->map.total_intlv_bits =3D order_base_2(ctx->map.total_intlv_chan); +} + +static u8 hygon_get_intlv_bit_pos(struct addr_ctx *ctx) +{ + u8 addr_sel =3D 0; + + switch (df_cfg.rev) { + case HYGON_DF1: + addr_sel =3D FIELD_GET(HYGON_DF1_INTLV_ADDR_SEL, ctx->map.base); + break; + default: + atl_debug_on_bad_df_rev(); + break; + } + + /* Add '8' to get the 'interleave bit position'. */ + return addr_sel + 8; +} + +static u8 hygon_get_num_intlv_dies(struct addr_ctx *ctx) +{ + u8 dies =3D 0; + + switch (df_cfg.rev) { + case HYGON_DF1: + dies =3D FIELD_GET(HYGON_DF1_INTLV_NUM_DIES, ctx->map.limit); + break; + default: + atl_debug_on_bad_df_rev(); + break; + } + + /* Register value is log2, e.g. 0 -> 1 die, 1 -> 2 dies, etc. */ + return 1 << dies; +} + +static u8 hygon_get_num_intlv_sockets(struct addr_ctx *ctx) +{ + u8 sockets =3D 0; + + switch (df_cfg.rev) { + case HYGON_DF1: + sockets =3D FIELD_GET(HYGON_DF1_INTLV_NUM_SOCKETS, ctx->map.base); + break; + default: + atl_debug_on_bad_df_rev(); + break; + } + + /* Register value is log2, e.g. 0 -> 1 sockets, 1 -> 2 sockets, etc. */ + return 1 << sockets; +} + +static int hygon_get_global_map_data(struct addr_ctx *ctx) +{ + if (hygon_df_get_intlv_mode(ctx)) + return -EINVAL; + + ctx->map.intlv_bit_pos =3D hygon_get_intlv_bit_pos(ctx); + ctx->map.num_intlv_dies =3D hygon_get_num_intlv_dies(ctx); + ctx->map.num_intlv_sockets =3D hygon_get_num_intlv_sockets(ctx); + hygon_calculate_intlv_bits(ctx); + + return 0; +} + +int hygon_get_address_map(struct addr_ctx *ctx) +{ + int ret; + + ret =3D hygon_get_address_map_common(ctx); + if (ret) + return ret; + + ret =3D hygon_get_global_map_data(ctx); + if (ret) + return ret; + + dump_address_map(&ctx->map); + + return ret; +} diff --git a/drivers/ras/amd/atl/hygon/reg_fields.h b/drivers/ras/amd/atl/h= ygon/reg_fields.h index 2c1193639c6c..44b24593175d 100644 --- a/drivers/ras/amd/atl/hygon/reg_fields.h +++ b/drivers/ras/amd/atl/hygon/reg_fields.h @@ -7,6 +7,84 @@ * Author: AichunShi */ =20 +/* + * Coherent Station Fabric ID + * + * Access type: Instance + * + * Register + * Rev Fieldname Bits + * + * D18F0x50 [Fabric Block Instance Information 3] + * HYGON_DF1 BlockFabricId [17:8] + */ +#define HYGON_DF1_COH_ST_FABRIC_ID GENMASK(17, 8) + +/* + * Interleave Number of Sockets + * + * Access type: Instance + * + * Register + * Rev Fieldname Bits + * + * D18F0x110 [DRAM Base Address] + * HYGON_DF1 IntLvNumSockets [3:2] + */ +#define HYGON_DF1_INTLV_NUM_SOCKETS GENMASK(3, 2) + +/* + * Interleave Number of Channels + * + * Access type: Instance + * + * Register + * Rev Fieldname Bits + * + * D18F0x110 [DRAM Base Address] + * HYGON_DF1 IntLvNumChan [7:4] + */ +#define HYGON_DF1_INTLV_NUM_CHAN GENMASK(7, 4) + +/* + * Interleave Address Select + * + * Access type: Instance + * + * Register + * Rev Fieldname Bits + * + * D18F0x110 [DRAM Base Address] + * HYGON_DF1 IntLvAddrSel [10:8] + */ +#define HYGON_DF1_INTLV_ADDR_SEL GENMASK(10, 8) + +/* + * Interleave Number of Dies + * + * Access type: Instance + * + * Register + * Rev Fieldname Bits + * + * D18F0x114 [DRAM Limit Address] + * HYGON_DF1 IntLvNumDies [11:10] + */ +#define HYGON_DF1_INTLV_NUM_DIES GENMASK(11, 10) + +/* + * High Address Offset + * + * Access type: Instance + * + * Register + * Rev Fieldname Bits + * + * D18F0x214 [DRAM Offset] + * HYGON_DF1 HiAddrOffset [31:19] + */ +#define HYGON_DF1_HI_ADDR_OFFSET GENMASK(31, 19) + /* * Die ID Mask * diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h index 19651cf9e978..d149ec6e7da9 100644 --- a/drivers/ras/amd/atl/internal.h +++ b/drivers/ras/amd/atl/internal.h @@ -55,6 +55,7 @@ enum df_revisions { enum intlv_modes { NONE =3D 0x00, NOHASH_2CHAN =3D 0x01, + HYGON_DF1_3CHAN =3D 0x02, NOHASH_4CHAN =3D 0x03, NOHASH_8CHAN =3D 0x05, DF3_6CHAN =3D 0x06, @@ -246,6 +247,14 @@ struct addr_ctx_inputs { u8 coh_st_inst_id; }; =20 +struct hygon_chan_intlv { + u8 sub_channel; + u8 chan_addr_sel; + u8 chan_hash_enable; + u8 ddr5_enable; + u8 start_bit; +}; + struct addr_ctx { u64 ret_addr; =20 @@ -266,6 +275,9 @@ struct addr_ctx { * System-wide ID that includes 'node' bits. */ u16 coh_st_fabric_id; + + /* Hygon Channel Interleave */ + struct hygon_chan_intlv chan_intlv_hygon; }; =20 int df_indirect_read_instance(u16 node, u8 func, u16 reg, u8 instance_id, = u32 *lo); @@ -289,7 +301,12 @@ u64 remove_base_and_hole(struct addr_ctx *ctx, u64 add= r); int get_dram_hole_base(void); void dump_df_cfg(void); =20 +int df2_get_dram_addr_map(struct addr_ctx *ctx); +bool valid_map(struct addr_ctx *ctx); +void dump_address_map(struct dram_addr_map *map); + int hygon_get_df_system_info(void); +int hygon_get_address_map(struct addr_ctx *ctx); =20 /* GUIDs for PRM handlers */ extern const guid_t norm_to_sys_guid; diff --git a/drivers/ras/amd/atl/map.c b/drivers/ras/amd/atl/map.c index 24a05af747d5..acfd0a636160 100644 --- a/drivers/ras/amd/atl/map.c +++ b/drivers/ras/amd/atl/map.c @@ -209,7 +209,7 @@ static int df3_6ch_get_dram_addr_map(struct addr_ctx *c= tx) return 0; } =20 -static int df2_get_dram_addr_map(struct addr_ctx *ctx) +int df2_get_dram_addr_map(struct addr_ctx *ctx) { /* Read D18F0x110 (DramBaseAddress). */ if (df_indirect_read_instance(ctx->node_id, 0, 0x110 + (8 * ctx->map.num), @@ -441,7 +441,7 @@ static int find_normalized_offset(struct addr_ctx *ctx,= u64 *norm_offset) return 0; } =20 -static bool valid_map(struct addr_ctx *ctx) +bool valid_map(struct addr_ctx *ctx) { if (df_cfg.rev >=3D DF4) return FIELD_GET(DF_ADDR_RANGE_VAL, ctx->map.ctl); @@ -735,7 +735,7 @@ static int validate_address_map(struct addr_ctx *ctx) return -EINVAL; } =20 -static void dump_address_map(struct dram_addr_map *map) +void dump_address_map(struct dram_addr_map *map) { u8 i; =20 --=20 2.47.3 From nobody Sun Jun 14 14:29:41 2026 Received: from out28-113.mail.aliyun.com (out28-113.mail.aliyun.com [115.124.28.113]) (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 42B423AA512; Fri, 3 Apr 2026 10:58:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.113 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775213920; cv=none; b=gTDNnlez8MbeoC7KXYCWOywr4NCQu72i1uywhp1AX5aTgW2MmcBCt1KI1O6Qhw/ilgBHFJgtXxJdSRSzwz5dYmXVFJAD6NKK+coyrimmJXdWetKwG/gpOOZIdUl86/jd9SPpacvBNln3MkhsAnbHOKedpRqvveCKFAPnnDj/aKk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775213920; c=relaxed/simple; bh=tO4K+DXyn0MTmwKkc76aMBuN2zvakrVdA5moPAeOgZs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=PtA7AekzXQCDd/QQVr4QpwaVbJKVKIK2R40XhRhS1mUCOHDh64YBviAXWDzgA9xreRNSyX0FySWg5pe7v/Hl9EyuQwFZmCIAFCDCIe1vn0tvG2V1S/PFshF9jnjTB4Q3BKGQSpfpV7/rb3RMERucyQm802GELhvji2pWPGgXUQU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=115.124.28.113 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436259|-1;CH=blue;DM=|OVERLOAD|false|;DS=CONTINUE|ham_system_inform|0.0313017-0.00313976-0.965559;FP=6578752146713166939|2|1|2|0|-1|-1|-1;HT=maildocker-contentspam033037071049;MF=shiaichun@open-hieco.net;NM=1;PH=DS;RN=5;RT=5;SR=0;TI=SMTPD_---.h4TkLbQ_1775213900; Received: from localhost.localdomain(mailfrom:shiaichun@open-hieco.net fp:SMTPD_---.h4TkLbQ_1775213900 cluster:ay29) by smtp.aliyun-inc.com; Fri, 03 Apr 2026 18:58:29 +0800 From: Aichun Shi To: yazen.ghannam@amd.com Cc: tglx@linutronix.de, linux-edac@vger.kernel.org, linux-kernel@vger.kernel.org, shiaichun@open-hieco.net Subject: [RFC PATCH 03/10] ras/amd/atl: Add Hygon DF1 normalized address denormalization helper Date: Fri, 3 Apr 2026 18:57:27 +0800 Message-ID: <25e9501e2f6d36802e5efe982e8af975a47f4652.1775213147.git.shiaichun@open-hieco.net> X-Mailer: git-send-email 2.47.3 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add Hygon DF1 normalized address denormalization function that Hygon address translation pipeline depends on later. Prepare hygon_denormalize_address() to be called by hygon/core.c later. - Add hygon/denormalize.c for Hygon-specific implementation similar to denormalize.c for AMD. - Add hygon_denormalize_address() to handle non-hashed and hashed interleave modes, including the Hygon DF1 three-channel interleave mode. - Use make_space_for_coh_st_id_at_intlv_bit() and insert_coh_st_id_at_intlv_bit() shared from denormalize.c and exported in internal.h to avoid duplicate code. - Build hygon/denormalize.c from the Makefile as an amd_atl object. Signed-off-by: Aichun Shi --- drivers/ras/amd/atl/Makefile | 1 + drivers/ras/amd/atl/denormalize.c | 4 +- drivers/ras/amd/atl/hygon/denormalize.c | 176 ++++++++++++++++++++++++ drivers/ras/amd/atl/hygon/reg_fields.h | 13 ++ drivers/ras/amd/atl/internal.h | 4 + 5 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 drivers/ras/amd/atl/hygon/denormalize.c diff --git a/drivers/ras/amd/atl/Makefile b/drivers/ras/amd/atl/Makefile index 105c11015f4c..c4e01f3ecc7b 100644 --- a/drivers/ras/amd/atl/Makefile +++ b/drivers/ras/amd/atl/Makefile @@ -15,6 +15,7 @@ amd_atl-y +=3D map.o amd_atl-y +=3D system.o amd_atl-y +=3D umc.o =20 +amd_atl-y +=3D hygon/denormalize.o amd_atl-y +=3D hygon/map.o amd_atl-y +=3D hygon/system.o =20 diff --git a/drivers/ras/amd/atl/denormalize.c b/drivers/ras/amd/atl/denorm= alize.c index d45ce753e636..cf58cfa7ab3a 100644 --- a/drivers/ras/amd/atl/denormalize.c +++ b/drivers/ras/amd/atl/denormalize.c @@ -41,7 +41,7 @@ static u16 get_dst_fabric_id(struct addr_ctx *ctx) * expanded address bits: [20+n : n+p][n+p-1 : p][p-1 : 0] * [23 : 11][10 : 8][7 : 0] */ -static u64 make_space_for_coh_st_id_at_intlv_bit(struct addr_ctx *ctx) +u64 make_space_for_coh_st_id_at_intlv_bit(struct addr_ctx *ctx) { return expand_bits(ctx->map.intlv_bit_pos, ctx->map.total_intlv_bits, @@ -320,7 +320,7 @@ static u16 calculate_coh_st_id(struct addr_ctx *ctx) } } =20 -static u64 insert_coh_st_id_at_intlv_bit(struct addr_ctx *ctx, u64 denorm_= addr, u16 coh_st_id) +u64 insert_coh_st_id_at_intlv_bit(struct addr_ctx *ctx, u64 denorm_addr, u= 16 coh_st_id) { return denorm_addr | (coh_st_id << ctx->map.intlv_bit_pos); } diff --git a/drivers/ras/amd/atl/hygon/denormalize.c b/drivers/ras/amd/atl/= hygon/denormalize.c new file mode 100644 index 000000000000..d189799bd183 --- /dev/null +++ b/drivers/ras/amd/atl/hygon/denormalize.c @@ -0,0 +1,176 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD Address Translation Library + * + * denormalize.c : Functions to account for interleaving bits for Hygon + * + * Author: AichunShi + */ + +#include "../internal.h" + +static u16 hygon_get_dst_fabric_id(struct addr_ctx *ctx) +{ + switch (df_cfg.rev) { + case HYGON_DF1: + return FIELD_GET(HYGON_DF1_DST_FABRIC_ID, ctx->map.limit); + default: + atl_debug_on_bad_df_rev(); + return 0; + } +} + +static u64 hygon_make_space_for_coh_st_id_df1_3chan(struct addr_ctx *ctx) +{ + return ctx->ret_addr & GENMASK_ULL(ctx->map.intlv_bit_pos - 1, 0); +} + +static u64 hygon_make_space_for_coh_st_id(struct addr_ctx *ctx) +{ + switch (ctx->map.intlv_mode) { + case NOHASH_2CHAN: + case NOHASH_4CHAN: + case NOHASH_8CHAN: + case NOHASH_16CHAN: + case NOHASH_32CHAN: + case DF2_2CHAN_HASH: + return make_space_for_coh_st_id_at_intlv_bit(ctx); + + case HYGON_DF1_3CHAN: + return hygon_make_space_for_coh_st_id_df1_3chan(ctx); + + default: + atl_debug_on_bad_intlv_mode(ctx); + return ~0ULL; + } +} + +static u16 hygon_get_coh_st_id_df(struct addr_ctx *ctx) +{ + u8 num_socket_intlv_bits =3D ilog2(ctx->map.num_intlv_sockets); + u8 num_die_intlv_bits =3D ilog2(ctx->map.num_intlv_dies); + u16 coh_st_id =3D ctx->coh_st_fabric_id; + u16 mask; + u8 intlv_bit_pos =3D ctx->map.intlv_bit_pos; + u8 num_intlv_bits =3D order_base_2(ctx->map.num_intlv_chan); + + if (ctx->map.intlv_mode =3D=3D HYGON_DF1_3CHAN) { + u8 cs_offset; + u16 dst_fabric_id =3D hygon_get_dst_fabric_id(ctx); + u64 temp_addr_x; + + cs_offset =3D (ctx->coh_st_fabric_id & 0x3) - (dst_fabric_id & 0x3); + if (cs_offset > 3) { + atl_debug(ctx, + "Invalid cs_offset: 0x%x coh_st_fabric_id: 0x%x dst_fabric_id: 0x%x.= \n", + cs_offset, ctx->coh_st_fabric_id, dst_fabric_id); + return ~0; + } + + temp_addr_x =3D (ctx->ret_addr & GENMASK_ULL(63, intlv_bit_pos)) >> + intlv_bit_pos; + temp_addr_x =3D temp_addr_x * 3 + cs_offset; + ctx->ret_addr =3D temp_addr_x; + + coh_st_id =3D temp_addr_x & GENMASK_ULL(num_intlv_bits - 1, 0); + } else { + mask =3D GENMASK(num_intlv_bits - 1, 0); + coh_st_id &=3D mask; + } + + /* Die interleave bits */ + if (num_die_intlv_bits) { + u16 die_bits; + + mask =3D GENMASK(num_die_intlv_bits - 1, 0); + die_bits =3D ctx->coh_st_fabric_id & df_cfg.die_id_mask; + die_bits >>=3D df_cfg.die_id_shift; + die_bits -=3D 4; + + coh_st_id |=3D (die_bits & mask) << num_intlv_bits; + num_intlv_bits +=3D num_die_intlv_bits; + } + + /* Socket interleave bits */ + if (num_socket_intlv_bits) { + u16 socket_bits; + + mask =3D GENMASK(num_socket_intlv_bits - 1, 0); + socket_bits =3D ctx->coh_st_fabric_id & df_cfg.socket_id_mask; + socket_bits >>=3D df_cfg.socket_id_shift; + + coh_st_id |=3D (socket_bits & mask) << num_intlv_bits; + } + + ctx->coh_st_fabric_id =3D coh_st_id; + + return coh_st_id; +} + +static u16 hygon_calculate_coh_st_id(struct addr_ctx *ctx) +{ + switch (ctx->map.intlv_mode) { + case NOHASH_2CHAN: + case HYGON_DF1_3CHAN: + case NOHASH_4CHAN: + case NOHASH_8CHAN: + case NOHASH_16CHAN: + case NOHASH_32CHAN: + case DF2_2CHAN_HASH: + return hygon_get_coh_st_id_df(ctx); + + default: + atl_debug_on_bad_intlv_mode(ctx); + return ~0; + } +} + +static u64 hygon_insert_coh_st_id_df1_3chan(struct addr_ctx *ctx, u64 deno= rm_addr, u16 coh_st_id) +{ + u8 num_intlv_bits_chan =3D order_base_2(ctx->map.num_intlv_chan); + u64 temp_addr =3D ((ctx->ret_addr >> num_intlv_bits_chan) << num_intlv_bi= ts_chan) | coh_st_id; + + return denorm_addr | (temp_addr << ctx->map.intlv_bit_pos); +} + +static u64 hygon_insert_coh_st_id(struct addr_ctx *ctx, u64 denorm_addr, u= 16 coh_st_id) +{ + switch (ctx->map.intlv_mode) { + case NOHASH_2CHAN: + case NOHASH_4CHAN: + case NOHASH_8CHAN: + case NOHASH_16CHAN: + case NOHASH_32CHAN: + case DF2_2CHAN_HASH: + return insert_coh_st_id_at_intlv_bit(ctx, denorm_addr, coh_st_id); + + case HYGON_DF1_3CHAN: + return hygon_insert_coh_st_id_df1_3chan(ctx, denorm_addr, coh_st_id); + + default: + atl_debug_on_bad_intlv_mode(ctx); + return ~0ULL; + } +} + +static int hygon_denorm_addr_common(struct addr_ctx *ctx) +{ + u64 denorm_addr; + u16 coh_st_id; + + denorm_addr =3D hygon_make_space_for_coh_st_id(ctx); + coh_st_id =3D hygon_calculate_coh_st_id(ctx); + ctx->ret_addr =3D hygon_insert_coh_st_id(ctx, denorm_addr, coh_st_id); + return 0; +} + +int hygon_denormalize_address(struct addr_ctx *ctx) +{ + switch (ctx->map.intlv_mode) { + case NONE: + return 0; + + default: + return hygon_denorm_addr_common(ctx); + } +} diff --git a/drivers/ras/amd/atl/hygon/reg_fields.h b/drivers/ras/amd/atl/h= ygon/reg_fields.h index 44b24593175d..69be2d5d2240 100644 --- a/drivers/ras/amd/atl/hygon/reg_fields.h +++ b/drivers/ras/amd/atl/hygon/reg_fields.h @@ -59,6 +59,19 @@ */ #define HYGON_DF1_INTLV_ADDR_SEL GENMASK(10, 8) =20 +/* + * Destination Fabric ID + * + * Access type: Instance + * + * Register + * Rev Fieldname Bits + * + * D18F0x114 [DRAM Limit Address] + * HYGON_DF1 DstFabricID [9:0] + */ +#define HYGON_DF1_DST_FABRIC_ID GENMASK(9, 0) + /* * Interleave Number of Dies * diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h index d149ec6e7da9..8f9fe6710c1e 100644 --- a/drivers/ras/amd/atl/internal.h +++ b/drivers/ras/amd/atl/internal.h @@ -305,8 +305,12 @@ int df2_get_dram_addr_map(struct addr_ctx *ctx); bool valid_map(struct addr_ctx *ctx); void dump_address_map(struct dram_addr_map *map); =20 +u64 make_space_for_coh_st_id_at_intlv_bit(struct addr_ctx *ctx); +u64 insert_coh_st_id_at_intlv_bit(struct addr_ctx *ctx, u64 denorm_addr, u= 16 coh_st_id); + int hygon_get_df_system_info(void); int hygon_get_address_map(struct addr_ctx *ctx); +int hygon_denormalize_address(struct addr_ctx *ctx); =20 /* GUIDs for PRM handlers */ extern const guid_t norm_to_sys_guid; --=20 2.47.3 From nobody Sun Jun 14 14:29:41 2026 Received: from out28-113.mail.aliyun.com (out28-113.mail.aliyun.com [115.124.28.113]) (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 5BA0A267B05; Fri, 3 Apr 2026 11:04:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.113 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775214243; cv=none; b=QLgKKTDHNE0wKV/1UucCmTWFljY+azzzH+TAejRHebLgDIXHo3vvJlnUZFEYGbwpuStnJWcoDBjEB0rdQCVsnwxZtPJd+Rm9sUB5I4w7NZ3HT2EYfvK+Y3H20dCbdG2cFnICxcLaSKfnfW+46ZLyZzPxNFh8Em4tIHVvL2yhlpE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775214243; c=relaxed/simple; bh=Es0cueEljL2OyVCzvBtkXmjT+3qSCTYXBLPDUNT0644=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Vm29OzXl105a0tvlrctEiBhmlQ7/Al1ofdcB0pb69aRSs/R2eeqjD/q4Gwg/sIlgxPmQ73W2GxFSKG4oz4vaywere2tf6H5gznSlGo/G4zs5ereB80VwT3JXCqqR0ALK+0J/+yn+Uj5DgSYmlxGrLbWaIHeKAvrQudLVOmwhj+I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=115.124.28.113 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436261|-1;CH=blue;DM=|OVERLOAD|false|;DS=CONTINUE|ham_system_inform|0.00392541-0.000608637-0.995466;FP=12325593758985700569|2|1|2|0|-1|-1|-1;HT=maildocker-contentspam033037032089;MF=shiaichun@open-hieco.net;NM=1;PH=DS;RN=5;RT=5;SR=0;TI=SMTPD_---.h4TkLit_1775213909; Received: from localhost.localdomain(mailfrom:shiaichun@open-hieco.net fp:SMTPD_---.h4TkLit_1775213909 cluster:ay29) by smtp.aliyun-inc.com; Fri, 03 Apr 2026 18:58:37 +0800 From: Aichun Shi To: yazen.ghannam@amd.com Cc: tglx@linutronix.de, linux-edac@vger.kernel.org, linux-kernel@vger.kernel.org, shiaichun@open-hieco.net Subject: [RFC PATCH 04/10] ras/amd/atl: Add Hygon DF1 address dehash helper Date: Fri, 3 Apr 2026 18:57:28 +0800 Message-ID: <06e367a5b3d33f4dbbf8dc2274d5bcaeeb31a839.1775213147.git.shiaichun@open-hieco.net> X-Mailer: git-send-email 2.47.3 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add Hygon DF1 address dehash function that Hygon address translation pipeline depends on later. Prepare hygon_dehash_address() to be called by hygon/core.c later. - Add hygon/dehash.c for Hygon-specific implementation similar to dehash.c for AMD. - Add hygon_dehash_address() to do address dehashing where the DRAM map uses hashed interleave modes for Hygon DF1 including two-channel hash interleave mode and DDR5 case. - Build hygon/dehash.c from the Makefile as an amd_atl object. Signed-off-by: Aichun Shi --- drivers/ras/amd/atl/Makefile | 1 + drivers/ras/amd/atl/hygon/dehash.c | 77 ++++++++++++++++++++++++++++++ drivers/ras/amd/atl/internal.h | 1 + 3 files changed, 79 insertions(+) create mode 100644 drivers/ras/amd/atl/hygon/dehash.c diff --git a/drivers/ras/amd/atl/Makefile b/drivers/ras/amd/atl/Makefile index c4e01f3ecc7b..fc12013de21f 100644 --- a/drivers/ras/amd/atl/Makefile +++ b/drivers/ras/amd/atl/Makefile @@ -15,6 +15,7 @@ amd_atl-y +=3D map.o amd_atl-y +=3D system.o amd_atl-y +=3D umc.o =20 +amd_atl-y +=3D hygon/dehash.o amd_atl-y +=3D hygon/denormalize.o amd_atl-y +=3D hygon/map.o amd_atl-y +=3D hygon/system.o diff --git a/drivers/ras/amd/atl/hygon/dehash.c b/drivers/ras/amd/atl/hygon= /dehash.c new file mode 100644 index 000000000000..43f1bdea1eeb --- /dev/null +++ b/drivers/ras/amd/atl/hygon/dehash.c @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD Address Translation Library + * + * dehash.c : Functions to account for hashing bits for Hygon + * + * Author: AichunShi + */ + +#include "../internal.h" + +static int hygon_df1_ddr5_dehash_addr(struct addr_ctx *ctx) +{ + u8 chan_hash_enable =3D ctx->chan_intlv_hygon.chan_hash_enable; + u8 sub_channel =3D ctx->chan_intlv_hygon.sub_channel; + u8 start_bit =3D ctx->chan_intlv_hygon.start_bit; + u8 hashed_bit; + + if (chan_hash_enable) { + hashed_bit =3D (ctx->ret_addr >> 12) ^ + (ctx->ret_addr >> 21) ^ + (ctx->ret_addr >> 30) ^ + sub_channel; + hashed_bit &=3D BIT(0); + ctx->ret_addr |=3D hashed_bit << start_bit; + } else { + ctx->ret_addr |=3D sub_channel << start_bit; + } + + return 0; +} + +static int hygon_df_2chan_dehash_addr(struct addr_ctx *ctx) +{ + u8 hashed_bit; + u8 intlv_bit_pos =3D ctx->map.intlv_bit_pos; + + hashed_bit =3D (ctx->ret_addr >> 12) ^ + (ctx->ret_addr >> 18) ^ + (ctx->ret_addr >> 21) ^ + (ctx->ret_addr >> 30) ^ + ctx->coh_st_fabric_id; + + hashed_bit &=3D BIT(0); + if (hashed_bit !=3D ((ctx->ret_addr >> intlv_bit_pos) & BIT(0))) + ctx->ret_addr ^=3D BIT(intlv_bit_pos); + + return 0; +} + +int hygon_dehash_address(struct addr_ctx *ctx) +{ + switch (ctx->map.intlv_mode) { + /* No hashing cases. */ + case NONE: + case NOHASH_2CHAN: + case HYGON_DF1_3CHAN: + case NOHASH_4CHAN: + case NOHASH_8CHAN: + case NOHASH_16CHAN: + case NOHASH_32CHAN: + break; + + case DF2_2CHAN_HASH: + hygon_df_2chan_dehash_addr(ctx); + break; + + default: + atl_debug_on_bad_intlv_mode(ctx); + return -EINVAL; + } + + if (df_cfg.rev =3D=3D HYGON_DF1 && ctx->chan_intlv_hygon.ddr5_enable) + hygon_df1_ddr5_dehash_addr(ctx); + + return 0; +} diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h index 8f9fe6710c1e..a5624599c91e 100644 --- a/drivers/ras/amd/atl/internal.h +++ b/drivers/ras/amd/atl/internal.h @@ -311,6 +311,7 @@ u64 insert_coh_st_id_at_intlv_bit(struct addr_ctx *ctx,= u64 denorm_addr, u16 coh int hygon_get_df_system_info(void); int hygon_get_address_map(struct addr_ctx *ctx); int hygon_denormalize_address(struct addr_ctx *ctx); +int hygon_dehash_address(struct addr_ctx *ctx); =20 /* GUIDs for PRM handlers */ extern const guid_t norm_to_sys_guid; --=20 2.47.3 From nobody Sun Jun 14 14:29:41 2026 Received: from out198-44.us.a.mail.aliyun.com (out198-44.us.a.mail.aliyun.com [47.90.198.44]) (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 9B05C3ACEF2; Fri, 3 Apr 2026 10:59:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=47.90.198.44 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775213947; cv=none; b=ThjgNxKtGiwo2Hs39L5aDkgf0Qo5NWwUumYBzmaLtueJMVSQL9MevwoyFWxW84lkw9DPOKLivUyueLOjFU1SFnNuhSd6WYup8QHXakZKkNH6dtH/MfQhkcnQDoxTv0NzrGDSUuZFpo1tR7WK/SCq7OiYEUx2TKDEA3uyj4akIrU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775213947; c=relaxed/simple; bh=VRbthcdA5e2exvyu/nlSfrFp0Xtjo/C0Atge+rtqcIU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bfRBGoWEjX6QdhwONj5QkbeExgapJLMm5+CuUDjb53dQWGsJNHo8uQGgN+dBAsfnjPZCSXOOhmPuGXlwGsXP10SYyboyX197nYi4V7nacylbYVAEP05phOykXFQui6ckaRjrW9AAe9IxoSYBTPVWrvnynbu5zl8BBvpPTQzX3uI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=47.90.198.44 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436259|-1;CH=blue;DM=|OVERLOAD|false|;DS=CONTINUE|ham_system_inform|0.00301659-0.000348675-0.996635;FP=9963226918574573311|2|1|2|0|-1|-1|-1;HT=maildocker-contentspam033032023038;MF=shiaichun@open-hieco.net;NM=1;PH=DS;RN=5;RT=5;SR=0;TI=SMTPD_---.h4TkLpR_1775213917; Received: from localhost.localdomain(mailfrom:shiaichun@open-hieco.net fp:SMTPD_---.h4TkLpR_1775213917 cluster:ay29) by smtp.aliyun-inc.com; Fri, 03 Apr 2026 18:58:44 +0800 From: Aichun Shi To: yazen.ghannam@amd.com Cc: tglx@linutronix.de, linux-edac@vger.kernel.org, linux-kernel@vger.kernel.org, shiaichun@open-hieco.net Subject: [RFC PATCH 05/10] ras/amd/atl: Add Hygon DF1 normalized-to-system address translation Date: Fri, 3 Apr 2026 18:57:29 +0800 Message-ID: X-Mailer: git-send-email 2.47.3 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Translate a normalized UMC MCA address into a system physical address for Hygon DF1 with the following pipeline. Pipeline: - Initialize address context with socket, die, coherent-station instance, sub-channel, and normalized address. - Enforce legacy hole requirements when the map enables the hole without a configured hole base. - Run Hygon DRAM map decoding, denormalization, DRAM base plus legacy hole, dehash, and DRAM limit checks. Prepare hygon_norm_to_sys_addr() to be called by hygon/umc.c later. - Add hygon/core.c for Hygon-specific implementation similar to core.c for AMD. - Call hygon_get_address_map(), hygon_denormalize_address(), hygon_dehash_address() prepared previously in hygon/map.c, hygon/denormalize.c and hygon/dehash.c. - Use legacy hole_en() and addr_over_limit() shared from core.c and exported in internal.h to avoid duplicate code. - Build hygon/core.c from the Makefile as an amd_atl object. Signed-off-by: Aichun Shi --- drivers/ras/amd/atl/Makefile | 1 + drivers/ras/amd/atl/core.c | 4 +-- drivers/ras/amd/atl/hygon/core.c | 52 ++++++++++++++++++++++++++++++++ drivers/ras/amd/atl/internal.h | 6 ++++ 4 files changed, 61 insertions(+), 2 deletions(-) create mode 100644 drivers/ras/amd/atl/hygon/core.c diff --git a/drivers/ras/amd/atl/Makefile b/drivers/ras/amd/atl/Makefile index fc12013de21f..0a42f2cbabc4 100644 --- a/drivers/ras/amd/atl/Makefile +++ b/drivers/ras/amd/atl/Makefile @@ -15,6 +15,7 @@ amd_atl-y +=3D map.o amd_atl-y +=3D system.o amd_atl-y +=3D umc.o =20 +amd_atl-y +=3D hygon/core.o amd_atl-y +=3D hygon/dehash.o amd_atl-y +=3D hygon/denormalize.o amd_atl-y +=3D hygon/map.o diff --git a/drivers/ras/amd/atl/core.c b/drivers/ras/amd/atl/core.c index 0f7cd6dab0b0..b7083588b46e 100644 --- a/drivers/ras/amd/atl/core.c +++ b/drivers/ras/amd/atl/core.c @@ -17,7 +17,7 @@ =20 struct df_config df_cfg __read_mostly; =20 -static int addr_over_limit(struct addr_ctx *ctx) +int addr_over_limit(struct addr_ctx *ctx) { u64 dram_limit_addr; =20 @@ -39,7 +39,7 @@ static int addr_over_limit(struct addr_ctx *ctx) return 0; } =20 -static bool legacy_hole_en(struct addr_ctx *ctx) +bool legacy_hole_en(struct addr_ctx *ctx) { u32 reg =3D ctx->map.base; =20 diff --git a/drivers/ras/amd/atl/hygon/core.c b/drivers/ras/amd/atl/hygon/c= ore.c new file mode 100644 index 000000000000..ef064e61805b --- /dev/null +++ b/drivers/ras/amd/atl/hygon/core.c @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD Address Translation Library + * + * core.c : Base translation functions for Hygon + * + * Author: AichunShi + */ + +#include "../internal.h" + +unsigned long hygon_norm_to_sys_addr(u8 socket_id, u8 die_id, u8 coh_st_in= st_id, + u8 sub_channel, unsigned long addr) +{ + struct addr_ctx ctx; + + if (df_cfg.rev =3D=3D UNKNOWN) + return -EINVAL; + + memset(&ctx, 0, sizeof(ctx)); + + /* Start from the normalized address */ + ctx.ret_addr =3D addr; + ctx.node_id =3D die_id; + ctx.inst_id =3D coh_st_inst_id; + + ctx.inputs.norm_addr =3D addr; + ctx.inputs.socket_id =3D socket_id; + ctx.inputs.die_id =3D die_id; + ctx.inputs.coh_st_inst_id =3D coh_st_inst_id; + + ctx.chan_intlv_hygon.sub_channel =3D sub_channel; + + if (legacy_hole_en(&ctx) && !df_cfg.dram_hole_base) + return -EINVAL; + + if (hygon_get_address_map(&ctx)) + return -EINVAL; + + if (hygon_denormalize_address(&ctx)) + return -EINVAL; + + ctx.ret_addr =3D add_base_and_hole(&ctx, ctx.ret_addr); + + if (hygon_dehash_address(&ctx)) + return -EINVAL; + + if (addr_over_limit(&ctx)) + return -EINVAL; + + return ctx.ret_addr; +} diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h index a5624599c91e..f943cc33f82e 100644 --- a/drivers/ras/amd/atl/internal.h +++ b/drivers/ras/amd/atl/internal.h @@ -297,6 +297,8 @@ unsigned long convert_umc_mca_addr_to_sys_addr(struct a= tl_err *err); =20 u64 add_base_and_hole(struct addr_ctx *ctx, u64 addr); u64 remove_base_and_hole(struct addr_ctx *ctx, u64 addr); +bool legacy_hole_en(struct addr_ctx *ctx); +int addr_over_limit(struct addr_ctx *ctx); =20 int get_dram_hole_base(void); void dump_df_cfg(void); @@ -313,6 +315,10 @@ int hygon_get_address_map(struct addr_ctx *ctx); int hygon_denormalize_address(struct addr_ctx *ctx); int hygon_dehash_address(struct addr_ctx *ctx); =20 +unsigned long hygon_norm_to_sys_addr(u8 socket_id, u8 die_id, u8 coh_st_in= st_id, + u8 sub_channel, unsigned long addr); +unsigned long hygon_convert_umc_mca_addr_to_sys_addr(struct atl_err *err); + /* GUIDs for PRM handlers */ extern const guid_t norm_to_sys_guid; =20 --=20 2.47.3 From nobody Sun Jun 14 14:29:41 2026 Received: from out28-112.mail.aliyun.com (out28-112.mail.aliyun.com [115.124.28.112]) (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 9DE9D38837A; Fri, 3 Apr 2026 11:04:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.112 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775214263; cv=none; b=BClAQjg7TIpKd7/AFwnkX/CAY1ZkSQCS4C0zGmNd7bC42TuvZq/HpUn17+W2TcBlebFyLXwpVxlLaiY/fpWiBPE6s+nf3tfv6aucATNPyajG25g1mqQDxFe2Yf5mrpg8IZNUt/Z4B6aYiUO6QZQ1/wxR7ihkJWa4+Ix+zZYn4qU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775214263; c=relaxed/simple; bh=E6Y9H5TY61Dpvvtfw9KcdVpP+hn2qdNrNPx6jK5A3CE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=fJCyduPOrx0AO06nNtzW3MstSSXW8BBZIdt5bjs5FfcwolRJBZhZxvP3GPo0hlHpjJkZW8kaKNND1aj/jxcMrgj6wX10n54JIkeLrQeSv9Rfn1FcfoER6OTi4ESpVlIOCuwE7PbqXodkRK6sRB+l6aWXh6ftcMc4E7S+baLSxME= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=115.124.28.112 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07437016|-1;CH=blue;DM=|OVERLOAD|false|;DS=CONTINUE|ham_alarm|0.00255781-0.000254814-0.997187;FP=13694441896984677563|0|0|0|0|-1|-1|-1;HT=maildocker-contentspam033068016216;MF=shiaichun@open-hieco.net;NM=1;PH=DS;RN=5;RT=5;SR=0;TI=SMTPD_---.h4TkLum_1775213925; Received: from localhost.localdomain(mailfrom:shiaichun@open-hieco.net fp:SMTPD_---.h4TkLum_1775213925 cluster:ay29) by smtp.aliyun-inc.com; Fri, 03 Apr 2026 18:58:51 +0800 From: Aichun Shi To: yazen.ghannam@amd.com Cc: tglx@linutronix.de, linux-edac@vger.kernel.org, linux-kernel@vger.kernel.org, shiaichun@open-hieco.net Subject: [RFC PATCH 06/10] ras/amd/atl: Add Hygon UMC MCA to system address conversion support Date: Fri, 3 Apr 2026 18:57:30 +0800 Message-ID: X-Mailer: git-send-email 2.47.3 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Prepare hygon_convert_umc_mca_addr_to_sys_addr() to be registered by amd_atl_register_decoder() in amd_atl_init() later. - Add hygon/umc.c for Hygon-specific implementation similar to umc.c for AMD. - Add hygon_convert_umc_mca_addr_to_sys_addr() to call hygon_norm_to_sys_addr() to do the address translation process. - Build hygon/umc.c from the Makefile as an amd_atl object. Signed-off-by: Aichun Shi --- drivers/ras/amd/atl/Makefile | 1 + drivers/ras/amd/atl/hygon/umc.c | 46 +++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 drivers/ras/amd/atl/hygon/umc.c diff --git a/drivers/ras/amd/atl/Makefile b/drivers/ras/amd/atl/Makefile index 0a42f2cbabc4..9d65e215b87a 100644 --- a/drivers/ras/amd/atl/Makefile +++ b/drivers/ras/amd/atl/Makefile @@ -20,6 +20,7 @@ amd_atl-y +=3D hygon/dehash.o amd_atl-y +=3D hygon/denormalize.o amd_atl-y +=3D hygon/map.o amd_atl-y +=3D hygon/system.o +amd_atl-y +=3D hygon/umc.o =20 amd_atl-$(CONFIG_AMD_ATL_PRM) +=3D prm.o =20 diff --git a/drivers/ras/amd/atl/hygon/umc.c b/drivers/ras/amd/atl/hygon/um= c.c new file mode 100644 index 000000000000..e2339db3f575 --- /dev/null +++ b/drivers/ras/amd/atl/hygon/umc.c @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD Address Translation Library + * + * umc.c : Unified Memory Controller (UMC) topology helpers for Hygon + * + * Author: AichunShi + */ + +#include "../internal.h" + +static u8 hygon_get_die_id(struct atl_err *err) +{ + /* + * For Hygon CPUs, amd_node_id can be non-contiguous, so get the Die + * ID from the logical Die ID. + */ + return topology_logical_die_id(err->cpu); +} + +#define HYGON_IPID_SUB_CHANNEL_MASK BIT(13) +static u8 hygon_get_ipid_sub_channel(struct atl_err *err) +{ + return FIELD_GET(HYGON_IPID_SUB_CHANNEL_MASK, err->ipid); +} + +#define HYGON_UMC_CHANNEL_NUM GENMASK(23, 20) +static u8 hygon_get_coh_st_inst_id(struct atl_err *err) +{ + return FIELD_GET(HYGON_UMC_CHANNEL_NUM, err->ipid); +} + +unsigned long hygon_convert_umc_mca_addr_to_sys_addr(struct atl_err *err) +{ + u8 socket_id =3D topology_physical_package_id(err->cpu); + u8 coh_st_inst_id =3D hygon_get_coh_st_inst_id(err); + u8 die_id =3D hygon_get_die_id(err); + + pr_debug("socket_id=3D0x%x die_id=3D0x%x coh_st_inst_id=3D0x%x addr=3D0x%= 016llx", + socket_id, die_id, coh_st_inst_id, err->addr); + + u8 sub_channel =3D hygon_get_ipid_sub_channel(err); + + return hygon_norm_to_sys_addr(socket_id, die_id, coh_st_inst_id, + sub_channel, err->addr); +} --=20 2.47.3 From nobody Sun Jun 14 14:29:41 2026 Received: from out28-91.mail.aliyun.com (out28-91.mail.aliyun.com [115.124.28.91]) (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 4BF71386438; Fri, 3 Apr 2026 10:59:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.91 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775213953; cv=none; b=nYNqpGalJJRUIP7JNahGB0TjUSOwVrSMBqVTEMerSiwH/kpe0pSHIr7B4BHcrrBqfJSrogJt7tdEI6u/RgY95zlhaxOZppzk9lTMYIRVbjomVYKrqqa377j05oZwVk7GI/3kjTscxd8hfFNLmQfib+A7GHTWmVfBeJlynQsVjaw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775213953; c=relaxed/simple; bh=gEhL5KulDygzndxRO9gtRXHU1BzW0yqupQvoTGGx/MI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=mW6yfFY81PyANTY2Mms8qya6kOpbFVVYelhOLI/SsNfIQc9NLE6poyTnThczqOTusoHhmj6jI/fhUq3LUgmNS7QTYmb/0ZhETYCBHJ8mckv0vA3t2PKrdDx0f//5/zdYwEj+rO06KDfH6G94diF6vbmYOrJRpxVvffL3/sRD/3s= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=115.124.28.91 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07447811|-1;CH=blue;DM=|OVERLOAD|false|;DS=CONTINUE|ham_alarm|0.00179982-0.000323617-0.997877;FP=8082075515846643263|2|1|2|0|-1|-1|-1;HT=maildocker-contentspam033037028158;MF=shiaichun@open-hieco.net;NM=1;PH=DS;RN=5;RT=5;SR=0;TI=SMTPD_---.h4TkM.c_1775213932; Received: from localhost.localdomain(mailfrom:shiaichun@open-hieco.net fp:SMTPD_---.h4TkM.c_1775213932 cluster:ay29) by smtp.aliyun-inc.com; Fri, 03 Apr 2026 18:58:58 +0800 From: Aichun Shi To: yazen.ghannam@amd.com Cc: tglx@linutronix.de, linux-edac@vger.kernel.org, linux-kernel@vger.kernel.org, shiaichun@open-hieco.net Subject: [RFC PATCH 07/10] ras/amd/atl: Add Hygon DF discovery and MCA decode at initialization Date: Fri, 3 Apr 2026 18:57:31 +0800 Message-ID: X-Mailer: git-send-email 2.47.3 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add node number bounds, Data Fabric discovery and UMC MCA to system address decoder for Hygon while keeping the AMD path unchanged. Address translation function is exported by amd_convert_umc_mca_addr_to_sys_addr() and used by users such as EDAC. - Add Hygon node number support in amd_atl_init(), amd_atl_exit() and __df_indirect_read(). - Call hygon_get_df_system_info() to get Hygon-specific Data Fabric system information. - Register hygon_convert_umc_mca_addr_to_sys_addr() as the address translation decoder for Hygon. Signed-off-by: Aichun Shi --- drivers/ras/amd/atl/access.c | 9 ++++++++- drivers/ras/amd/atl/core.c | 21 ++++++++++++++++++--- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/drivers/ras/amd/atl/access.c b/drivers/ras/amd/atl/access.c index c2334f8f9add..6d75bcb930d4 100644 --- a/drivers/ras/amd/atl/access.c +++ b/drivers/ras/amd/atl/access.c @@ -68,9 +68,16 @@ static int __df_indirect_read(u16 node, u8 func, u16 reg= , u8 instance_id, u32 *l struct pci_dev *F4; int err =3D -ENODEV; u32 ficaa =3D 0; + u16 num_nodes; + bool is_hygon =3D boot_cpu_data.x86_vendor =3D=3D X86_VENDOR_HYGON; =20 node =3D get_accessible_node(node); - if (node >=3D amd_nb_num()) { + if (is_hygon) + num_nodes =3D amd_num_nodes(); + else + num_nodes =3D amd_nb_num(); + + if (node >=3D num_nodes) { pr_debug("Node %u is out of bounds\n", node); goto out; } diff --git a/drivers/ras/amd/atl/core.c b/drivers/ras/amd/atl/core.c index b7083588b46e..bbbbff4d43a3 100644 --- a/drivers/ras/amd/atl/core.c +++ b/drivers/ras/amd/atl/core.c @@ -195,22 +195,37 @@ MODULE_DEVICE_TABLE(x86cpu, amd_atl_cpuids); static int __init amd_atl_init(void) { int ret; + u16 num_nodes; + bool is_hygon =3D boot_cpu_data.x86_vendor =3D=3D X86_VENDOR_HYGON; =20 if (!x86_match_cpu(amd_atl_cpuids)) return -ENODEV; =20 - if (!amd_nb_num()) + if (is_hygon) + num_nodes =3D amd_num_nodes(); + else + num_nodes =3D amd_nb_num(); + + if (!num_nodes) return -ENODEV; =20 check_for_legacy_df_access(); =20 - ret =3D get_df_system_info(); + if (is_hygon) + ret =3D hygon_get_df_system_info(); + else + ret =3D get_df_system_info(); + if (ret) return ret; =20 /* Increment this module's recount so that it can't be easily unloaded. */ __module_get(THIS_MODULE); - amd_atl_register_decoder(convert_umc_mca_addr_to_sys_addr); + + if (is_hygon) + amd_atl_register_decoder(hygon_convert_umc_mca_addr_to_sys_addr); + else + amd_atl_register_decoder(convert_umc_mca_addr_to_sys_addr); =20 pr_info("AMD Address Translation Library initialized\n"); return 0; --=20 2.47.3 From nobody Sun Jun 14 14:29:41 2026 Received: from out28-111.mail.aliyun.com (out28-111.mail.aliyun.com [115.124.28.111]) (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 643AC3AB29C; Fri, 3 Apr 2026 10:59:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.111 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775213957; cv=none; b=Ax+uxMxfPytSF+Ohjp0rxKf/7IyibmQGWknDcU16kJcRzNFtwCKdQ7Dp7LnCgIAnAAwuU988Lh4dQKKnSkZnLOwIZUv+rg1m+H+94OTfpGhdXMgzhbN5gOJfMrdXZ/bG7Va/yMCE/fPAF+jOAS0LEXyJjB8/oD58voNyp2ESNiY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775213957; c=relaxed/simple; bh=Meyf+KhWGfkBzxAl3COHv8EoR2naTQ4BN35cNm12C/o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hBOi3vL3JnmprK6QFpBw2WMBjU5GR9vb0KO9n8859sBgjFsuRiaF+jVC0OFZlKjpGJdwkPQ25A6cCGP084ORr9D5rS3EQtB4SBcU4TztXKggishWeH1x2+Bbk00qpzx6pwxYRcC5AW9zVDleXs1OqIaWjmD+XulK13KNhef9Imo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=115.124.28.111 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436259|-1;CH=blue;DM=|OVERLOAD|false|;DS=CONTINUE|ham_alarm|0.00259096-0.000165939-0.997243;FP=2264602773296106514|2|1|2|0|-1|-1|-1;HT=maildocker-contentspam033032027189;MF=shiaichun@open-hieco.net;NM=1;PH=DS;RN=5;RT=5;SR=0;TI=SMTPD_---.h4TkM4p_1775213938; Received: from localhost.localdomain(mailfrom:shiaichun@open-hieco.net fp:SMTPD_---.h4TkM4p_1775213938 cluster:ay29) by smtp.aliyun-inc.com; Fri, 03 Apr 2026 18:59:04 +0800 From: Aichun Shi To: yazen.ghannam@amd.com Cc: tglx@linutronix.de, linux-edac@vger.kernel.org, linux-kernel@vger.kernel.org, shiaichun@open-hieco.net Subject: [RFC PATCH 08/10] ras/amd/atl: Add Hygon DF2 address translation support Date: Fri, 3 Apr 2026 18:57:32 +0800 Message-ID: <5f7d3a38bf4785ff84e7611e19c192a4361b65a8.1775213147.git.shiaichun@open-hieco.net> X-Mailer: git-send-email 2.47.3 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Extend address translation support for Hygon Family 0x18 model 0x6/0x8 (Hygon DF2). System detection: - Add register field definitions for Hygon DF2 in hygon/reg_fields.h. - Add HYGON_DF2 to enum df_revisions and interleave mode HYGON_DF2_4CHAN_HASH for four-channel hash for Hygon DF2 in internal.h. - Discover Hygon DF2 socket/die mask widths and shifts; detect model 0x6/0x8 as Hygon DF2. DRAM map: - Add hygon_df2_get_dram_addr_map(): use shared AMD DF2 DRAM base/limit via df2_get_dram_addr_map(), and read Hygon-specific interleave fields. - Map Hygon-specific HYGON_DF2_4CHAN_HASH interleave mode instead of the AMD DF2 two-channel hash mode. - Get die/socket interleave count for Hygon DF2. Denormalize/dehash: - Get coherent-station fabric ID for Hygon DF2 including HYGON_DF2_4CHAN_HASH case. - Add hygon_df2_4chan_dehash_addr() to support dehash function for HYGON_DF2_4CHAN_HASH interleave mode. UMC: - Form the coherent-station instance ID from the channel field and sub-channel bit from MCA IPID to match Hygon DF2 UMC addressing. Signed-off-by: Aichun Shi --- drivers/ras/amd/atl/hygon/dehash.c | 23 +++++++++++++++++ drivers/ras/amd/atl/hygon/denormalize.c | 3 +++ drivers/ras/amd/atl/hygon/map.c | 33 +++++++++++++++++++++++-- drivers/ras/amd/atl/hygon/reg_fields.h | 18 ++++++++++++++ drivers/ras/amd/atl/hygon/system.c | 9 +++++++ drivers/ras/amd/atl/hygon/umc.c | 8 +++++- drivers/ras/amd/atl/internal.h | 2 ++ 7 files changed, 93 insertions(+), 3 deletions(-) diff --git a/drivers/ras/amd/atl/hygon/dehash.c b/drivers/ras/amd/atl/hygon= /dehash.c index 43f1bdea1eeb..e0546ea70900 100644 --- a/drivers/ras/amd/atl/hygon/dehash.c +++ b/drivers/ras/amd/atl/hygon/dehash.c @@ -48,6 +48,25 @@ static int hygon_df_2chan_dehash_addr(struct addr_ctx *c= tx) return 0; } =20 +static int hygon_df2_4chan_dehash_addr(struct addr_ctx *ctx) +{ + u8 hashed_bit; + u8 intlv_bit_pos =3D ctx->map.intlv_bit_pos; + + hashed_bit =3D (ctx->ret_addr >> 12) ^ + (ctx->ret_addr >> 18) ^ + (ctx->ret_addr >> 21) ^ + (ctx->ret_addr >> 30) ^ + ctx->coh_st_fabric_id; + + hashed_bit &=3D 0x3; + if (hashed_bit !=3D ((ctx->ret_addr >> intlv_bit_pos) & 0x3)) + ctx->ret_addr =3D (ctx->ret_addr & ~((u64)3 << intlv_bit_pos)) | + (hashed_bit << intlv_bit_pos); + + return 0; +} + int hygon_dehash_address(struct addr_ctx *ctx) { switch (ctx->map.intlv_mode) { @@ -65,6 +84,10 @@ int hygon_dehash_address(struct addr_ctx *ctx) hygon_df_2chan_dehash_addr(ctx); break; =20 + case HYGON_DF2_4CHAN_HASH: + hygon_df2_4chan_dehash_addr(ctx); + break; + default: atl_debug_on_bad_intlv_mode(ctx); return -EINVAL; diff --git a/drivers/ras/amd/atl/hygon/denormalize.c b/drivers/ras/amd/atl/= hygon/denormalize.c index d189799bd183..82c5982893ba 100644 --- a/drivers/ras/amd/atl/hygon/denormalize.c +++ b/drivers/ras/amd/atl/hygon/denormalize.c @@ -14,6 +14,8 @@ static u16 hygon_get_dst_fabric_id(struct addr_ctx *ctx) switch (df_cfg.rev) { case HYGON_DF1: return FIELD_GET(HYGON_DF1_DST_FABRIC_ID, ctx->map.limit); + case HYGON_DF2: + return FIELD_GET(HYGON_DF2_DST_FABRIC_ID, ctx->map.limit); default: atl_debug_on_bad_df_rev(); return 0; @@ -117,6 +119,7 @@ static u16 hygon_calculate_coh_st_id(struct addr_ctx *c= tx) case NOHASH_16CHAN: case NOHASH_32CHAN: case DF2_2CHAN_HASH: + case HYGON_DF2_4CHAN_HASH: return hygon_get_coh_st_id_df(ctx); =20 default: diff --git a/drivers/ras/amd/atl/hygon/map.c b/drivers/ras/amd/atl/hygon/ma= p.c index 2194c10ff587..b0c05532b744 100644 --- a/drivers/ras/amd/atl/hygon/map.c +++ b/drivers/ras/amd/atl/hygon/map.c @@ -16,8 +16,12 @@ static int hygon_df_get_intlv_mode(struct addr_ctx *ctx) if (df_cfg.rev =3D=3D HYGON_DF1 && ctx->map.intlv_mode =3D=3D 2) ctx->map.intlv_mode =3D HYGON_DF1_3CHAN; =20 - if (ctx->map.intlv_mode =3D=3D 8) - ctx->map.intlv_mode =3D DF2_2CHAN_HASH; + if (ctx->map.intlv_mode =3D=3D 8) { + if (df_cfg.rev =3D=3D HYGON_DF2) + ctx->map.intlv_mode =3D HYGON_DF2_4CHAN_HASH; + else + ctx->map.intlv_mode =3D DF2_2CHAN_HASH; + } =20 if (ctx->map.intlv_mode !=3D NONE && ctx->map.intlv_mode !=3D NOHASH_2CHAN && @@ -25,6 +29,7 @@ static int hygon_df_get_intlv_mode(struct addr_ctx *ctx) ctx->map.intlv_mode !=3D NOHASH_4CHAN && ctx->map.intlv_mode !=3D NOHASH_8CHAN && ctx->map.intlv_mode !=3D NOHASH_16CHAN && + ctx->map.intlv_mode !=3D HYGON_DF2_4CHAN_HASH && ctx->map.intlv_mode !=3D DF2_2CHAN_HASH) return -EINVAL; =20 @@ -38,6 +43,7 @@ static u64 hygon_get_hi_addr_offset(u32 reg_dram_offset) =20 switch (df_cfg.rev) { case HYGON_DF1: + case HYGON_DF2: hi_addr_offset =3D FIELD_GET(HYGON_DF1_HI_ADDR_OFFSET, reg_dram_offset); break; default: @@ -120,10 +126,24 @@ static int hygon_df1_get_dram_addr_map(struct addr_ct= x *ctx) return 0; } =20 +static int hygon_df2_get_dram_addr_map(struct addr_ctx *ctx) +{ + if (df2_get_dram_addr_map(ctx)) + return -EINVAL; + + /* Read D18F0x60 */ + if (df_indirect_read_instance(ctx->node_id, 0, 0x60, + ctx->inst_id, &ctx->map.intlv)) + return -EINVAL; + + return 0; +} + static int hygon_get_dram_addr_map(struct addr_ctx *ctx) { switch (df_cfg.rev) { case HYGON_DF1: return hygon_df1_get_dram_addr_map(ctx); + case HYGON_DF2: return hygon_df2_get_dram_addr_map(ctx); default: atl_debug_on_bad_df_rev(); return -EINVAL; @@ -142,6 +162,9 @@ static int hygon_get_coh_st_fabric_id(struct addr_ctx *= ctx) case HYGON_DF1: ctx->coh_st_fabric_id =3D FIELD_GET(HYGON_DF1_COH_ST_FABRIC_ID, reg); break; + case HYGON_DF2: + ctx->coh_st_fabric_id =3D FIELD_GET(HYGON_DF2_COH_ST_FABRIC_ID, reg); + break; default: atl_debug_on_bad_df_rev(); return -EINVAL; @@ -226,6 +249,7 @@ static u8 hygon_get_num_intlv_chan(struct addr_ctx *ctx) return 2; case HYGON_DF1_3CHAN: return 3; + case HYGON_DF2_4CHAN_HASH: case NOHASH_4CHAN: return 4; case NOHASH_8CHAN: @@ -261,6 +285,7 @@ static u8 hygon_get_intlv_bit_pos(struct addr_ctx *ctx) =20 switch (df_cfg.rev) { case HYGON_DF1: + case HYGON_DF2: addr_sel =3D FIELD_GET(HYGON_DF1_INTLV_ADDR_SEL, ctx->map.base); break; default: @@ -280,6 +305,9 @@ static u8 hygon_get_num_intlv_dies(struct addr_ctx *ctx) case HYGON_DF1: dies =3D FIELD_GET(HYGON_DF1_INTLV_NUM_DIES, ctx->map.limit); break; + case HYGON_DF2: + dies =3D FIELD_GET(HYGON_DF2_INTLV_NUM_DIES, ctx->map.intlv); + break; default: atl_debug_on_bad_df_rev(); break; @@ -295,6 +323,7 @@ static u8 hygon_get_num_intlv_sockets(struct addr_ctx *= ctx) =20 switch (df_cfg.rev) { case HYGON_DF1: + case HYGON_DF2: sockets =3D FIELD_GET(HYGON_DF1_INTLV_NUM_SOCKETS, ctx->map.base); break; default: diff --git a/drivers/ras/amd/atl/hygon/reg_fields.h b/drivers/ras/amd/atl/h= ygon/reg_fields.h index 69be2d5d2240..eaf1d628fd0e 100644 --- a/drivers/ras/amd/atl/hygon/reg_fields.h +++ b/drivers/ras/amd/atl/hygon/reg_fields.h @@ -17,8 +17,10 @@ * * D18F0x50 [Fabric Block Instance Information 3] * HYGON_DF1 BlockFabricId [17:8] + * HYGON_DF2 BlockFabricId [18:8] */ #define HYGON_DF1_COH_ST_FABRIC_ID GENMASK(17, 8) +#define HYGON_DF2_COH_ST_FABRIC_ID GENMASK(18, 8) =20 /* * Interleave Number of Sockets @@ -30,6 +32,7 @@ * * D18F0x110 [DRAM Base Address] * HYGON_DF1 IntLvNumSockets [3:2] + * HYGON_DF2 IntLvNumSockets [3:2] */ #define HYGON_DF1_INTLV_NUM_SOCKETS GENMASK(3, 2) =20 @@ -43,6 +46,7 @@ * * D18F0x110 [DRAM Base Address] * HYGON_DF1 IntLvNumChan [7:4] + * HYGON_DF2 IntLvNumChan [7:4] */ #define HYGON_DF1_INTLV_NUM_CHAN GENMASK(7, 4) =20 @@ -56,6 +60,7 @@ * * D18F0x110 [DRAM Base Address] * HYGON_DF1 IntLvAddrSel [10:8] + * HYGON_DF2 IntLvAddrSel [10:8] */ #define HYGON_DF1_INTLV_ADDR_SEL GENMASK(10, 8) =20 @@ -69,8 +74,10 @@ * * D18F0x114 [DRAM Limit Address] * HYGON_DF1 DstFabricID [9:0] + * HYGON_DF2 DstFabricID [10:0] */ #define HYGON_DF1_DST_FABRIC_ID GENMASK(9, 0) +#define HYGON_DF2_DST_FABRIC_ID GENMASK(10, 0) =20 /* * Interleave Number of Dies @@ -82,8 +89,12 @@ * * D18F0x114 [DRAM Limit Address] * HYGON_DF1 IntLvNumDies [11:10] + * + * D18F0x60 + * HYGON_DF2 IntLvNumDies [1:0] */ #define HYGON_DF1_INTLV_NUM_DIES GENMASK(11, 10) +#define HYGON_DF2_INTLV_NUM_DIES GENMASK(1, 0) =20 /* * High Address Offset @@ -95,6 +106,7 @@ * * D18F0x214 [DRAM Offset] * HYGON_DF1 HiAddrOffset [31:19] + * HYGON_DF2 HiAddrOffset [31:19] */ #define HYGON_DF1_HI_ADDR_OFFSET GENMASK(31, 19) =20 @@ -108,8 +120,10 @@ * * D18F1x208 [System Fabric ID Mask] * HYGON_DF1 DieIdMask [9:0] + * HYGON_DF2 DieIdMask [10:0] */ #define HYGON_DF1_DIE_ID_MASK GENMASK(9, 0) +#define HYGON_DF2_DIE_ID_MASK GENMASK(10, 0) =20 /* * Die ID Shift @@ -121,6 +135,7 @@ * * D18F1x208 [System Fabric ID Mask] * HYGON_DF1 DieIdShift [15:12] + * HYGON_DF2 DieIdShift [15:12] */ #define HYGON_DF1_DIE_ID_SHIFT GENMASK(15, 12) =20 @@ -134,8 +149,10 @@ * * D18F1x208 [System Fabric ID Mask] * HYGON_DF1 SocketIdMask [25:16] + * HYGON_DF2 SocketIdMask [26:16] */ #define HYGON_DF1_SOCKET_ID_MASK GENMASK(25, 16) +#define HYGON_DF2_SOCKET_ID_MASK GENMASK(26, 16) =20 /* * Socket ID Shift @@ -147,5 +164,6 @@ * * D18F1x208 [System Fabric ID Mask] * HYGON_DF1 SocketIdShift [31:28] + * HYGON_DF2 SocketIdShift [31:28] */ #define HYGON_DF1_SOCKET_ID_SHIFT GENMASK(31, 28) diff --git a/drivers/ras/amd/atl/hygon/system.c b/drivers/ras/amd/atl/hygon= /system.c index 2a149cfc34c1..a06a39bc4527 100644 --- a/drivers/ras/amd/atl/hygon/system.c +++ b/drivers/ras/amd/atl/hygon/system.c @@ -18,6 +18,12 @@ static void hygon_df_get_masks_shifts(u32 mask0) df_cfg.die_id_shift =3D FIELD_GET(HYGON_DF1_DIE_ID_SHIFT, mask0); df_cfg.die_id_mask =3D FIELD_GET(HYGON_DF1_DIE_ID_MASK, mask0); break; + case HYGON_DF2: + df_cfg.socket_id_shift =3D FIELD_GET(HYGON_DF1_SOCKET_ID_SHIFT, mask0); + df_cfg.socket_id_mask =3D FIELD_GET(HYGON_DF2_SOCKET_ID_MASK, mask0); + df_cfg.die_id_shift =3D FIELD_GET(HYGON_DF1_DIE_ID_SHIFT, mask0); + df_cfg.die_id_mask =3D FIELD_GET(HYGON_DF2_DIE_ID_MASK, mask0); + break; default: atl_debug_on_bad_df_rev(); return; @@ -30,6 +36,8 @@ static int hygon_determine_df_rev(void) =20 if (boot_cpu_data.x86_model =3D=3D 0x4 || boot_cpu_data.x86_model =3D=3D = 0x5) df_cfg.rev =3D HYGON_DF1; + else if (boot_cpu_data.x86_model =3D=3D 0x6 || boot_cpu_data.x86_model = =3D=3D 0x8) + df_cfg.rev =3D HYGON_DF2; =20 /* Read D18F1x208 (SystemFabricIdMask). */ if (df_indirect_read_broadcast(0, 1, 0x208, &fabric_id_mask0)) @@ -44,6 +52,7 @@ static void hygon_get_num_maps(void) { switch (df_cfg.rev) { case HYGON_DF1: + case HYGON_DF2: df_cfg.num_coh_st_maps =3D 2; break; default: diff --git a/drivers/ras/amd/atl/hygon/umc.c b/drivers/ras/amd/atl/hygon/um= c.c index e2339db3f575..b912dbdebee4 100644 --- a/drivers/ras/amd/atl/hygon/umc.c +++ b/drivers/ras/amd/atl/hygon/umc.c @@ -27,7 +27,13 @@ static u8 hygon_get_ipid_sub_channel(struct atl_err *err) #define HYGON_UMC_CHANNEL_NUM GENMASK(23, 20) static u8 hygon_get_coh_st_inst_id(struct atl_err *err) { - return FIELD_GET(HYGON_UMC_CHANNEL_NUM, err->ipid); + u8 sub_channel =3D hygon_get_ipid_sub_channel(err); + u8 coh_st_inst_id =3D FIELD_GET(HYGON_UMC_CHANNEL_NUM, err->ipid); + + if (df_cfg.rev =3D=3D HYGON_DF2) + coh_st_inst_id =3D (coh_st_inst_id << 1) + sub_channel; + + return coh_st_inst_id; } =20 unsigned long hygon_convert_umc_mca_addr_to_sys_addr(struct atl_err *err) diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h index f943cc33f82e..c368559ca2ae 100644 --- a/drivers/ras/amd/atl/internal.h +++ b/drivers/ras/amd/atl/internal.h @@ -44,6 +44,7 @@ enum df_revisions { UNKNOWN, HYGON_DF1, + HYGON_DF2, DF2, DF3, DF3p5, @@ -61,6 +62,7 @@ enum intlv_modes { DF3_6CHAN =3D 0x06, NOHASH_16CHAN =3D 0x07, NOHASH_32CHAN =3D 0x08, + HYGON_DF2_4CHAN_HASH =3D 0x09, DF3_COD4_2CHAN_HASH =3D 0x0C, DF3_COD2_4CHAN_HASH =3D 0x0D, DF3_COD1_8CHAN_HASH =3D 0x0E, --=20 2.47.3 From nobody Sun Jun 14 14:29:41 2026 Received: from out28-134.mail.aliyun.com (out28-134.mail.aliyun.com [115.124.28.134]) (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 6B07E386438; Fri, 3 Apr 2026 10:59:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.134 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775213963; cv=none; b=ZqrrULInpMmtRBTjy1zVTQwhz9gE+Zl3LPOwFNR/ydQHxHem0l/VGWYPZ7nDjzNgEG+IX/VSaAGljObkuoWxgaspPNDlgo8cyzT1rBaEU6+N7pWE/+vXOC9Ve79n8VNw8UoA39zZgyGRcV7V+5Oi7aDY+vyYXR5pXvNmkD0/s4s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775213963; c=relaxed/simple; bh=km5TsRbaEVjjodmY3mgKPt10XvjdWR6u+uljfeWnDS4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=WpXx4/Gzn+SGw5BhM2XnoC8VgEV/0QRzLwrrKwJa3ee8adnKPwEJEEOO2pkxlxVzFQM5rhjzZ4G2TCDK2mHcQoVoDeszV1INe2uR4Q8JDPknP11QAbHh63KpTtL0sOfTE1guIO/9Oj4dAraIUu6+hteklwI/WziE6kZTi+1aKqc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=115.124.28.134 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436351|-1;CH=blue;DM=|OVERLOAD|false|;DS=CONTINUE|ham_alarm|0.00393754-0.0092153-0.986847;FP=535220511822433307|2|1|2|0|-1|-1|-1;HT=maildocker-contentspam033037025160;MF=shiaichun@open-hieco.net;NM=1;PH=DS;RN=5;RT=5;SR=0;TI=SMTPD_---.h4TkMBV_1775213945; Received: from localhost.localdomain(mailfrom:shiaichun@open-hieco.net fp:SMTPD_---.h4TkMBV_1775213945 cluster:ay29) by smtp.aliyun-inc.com; Fri, 03 Apr 2026 18:59:09 +0800 From: Aichun Shi To: yazen.ghannam@amd.com Cc: tglx@linutronix.de, linux-edac@vger.kernel.org, linux-kernel@vger.kernel.org, shiaichun@open-hieco.net Subject: [RFC PATCH 09/10] ras/amd/atl: Add Hygon DF3 address translation support Date: Fri, 3 Apr 2026 18:57:33 +0800 Message-ID: <3807bef375665273b8096c075d84ca22cfeca02d.1775213147.git.shiaichun@open-hieco.net> X-Mailer: git-send-email 2.47.3 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Extend address translation support for Hygon Family 0x18 model 0x7 (Hygon DF3). System detection: - Add register field definitions for Hygon DF3 in hygon/reg_fields.h. - Add HYGON_DF3 to enum df_revisions in internal.h. - Discover Hygon DF3 socket/die mask widths and shifts; detect model 0x7 as Hygon DF3. DRAM map: - Use shared AMD DF2 DRAM base/limit via df2_get_dram_addr_map(). - Map Hygon-specific HYGON_DF2_4CHAN_HASH interleave mode for Hygon DF3. - Get die/socket interleave count for Hygon DF3. - Get DRAM offset and high address offset for Hygon DF3. Denormalize: - Get destination fabric ID for Hygon DF3. Signed-off-by: Aichun Shi --- drivers/ras/amd/atl/hygon/denormalize.c | 2 ++ drivers/ras/amd/atl/hygon/map.c | 21 +++++++++++++++++++-- drivers/ras/amd/atl/hygon/reg_fields.h | 22 ++++++++++++++++++++++ drivers/ras/amd/atl/hygon/system.c | 9 +++++++++ drivers/ras/amd/atl/internal.h | 1 + 5 files changed, 53 insertions(+), 2 deletions(-) diff --git a/drivers/ras/amd/atl/hygon/denormalize.c b/drivers/ras/amd/atl/= hygon/denormalize.c index 82c5982893ba..6e882a6b7b55 100644 --- a/drivers/ras/amd/atl/hygon/denormalize.c +++ b/drivers/ras/amd/atl/hygon/denormalize.c @@ -16,6 +16,8 @@ static u16 hygon_get_dst_fabric_id(struct addr_ctx *ctx) return FIELD_GET(HYGON_DF1_DST_FABRIC_ID, ctx->map.limit); case HYGON_DF2: return FIELD_GET(HYGON_DF2_DST_FABRIC_ID, ctx->map.limit); + case HYGON_DF3: + return FIELD_GET(HYGON_DF3_DST_FABRIC_ID, ctx->map.limit); default: atl_debug_on_bad_df_rev(); return 0; diff --git a/drivers/ras/amd/atl/hygon/map.c b/drivers/ras/amd/atl/hygon/ma= p.c index b0c05532b744..2a3d962be083 100644 --- a/drivers/ras/amd/atl/hygon/map.c +++ b/drivers/ras/amd/atl/hygon/map.c @@ -17,7 +17,7 @@ static int hygon_df_get_intlv_mode(struct addr_ctx *ctx) ctx->map.intlv_mode =3D HYGON_DF1_3CHAN; =20 if (ctx->map.intlv_mode =3D=3D 8) { - if (df_cfg.rev =3D=3D HYGON_DF2) + if (df_cfg.rev =3D=3D HYGON_DF2 || df_cfg.rev =3D=3D HYGON_DF3) ctx->map.intlv_mode =3D HYGON_DF2_4CHAN_HASH; else ctx->map.intlv_mode =3D DF2_2CHAN_HASH; @@ -46,6 +46,9 @@ static u64 hygon_get_hi_addr_offset(u32 reg_dram_offset) case HYGON_DF2: hi_addr_offset =3D FIELD_GET(HYGON_DF1_HI_ADDR_OFFSET, reg_dram_offset); break; + case HYGON_DF3: + hi_addr_offset =3D FIELD_GET(HYGON_DF3_HI_ADDR_OFFSET, reg_dram_offset); + break; default: hi_addr_offset =3D 0; atl_debug_on_bad_df_rev(); @@ -77,7 +80,12 @@ static int hygon_get_dram_offset(struct addr_ctx *ctx, u= 64 *norm_offset) */ map_num =3D ctx->map.num - 1; =20 - if (df_cfg.rev >=3D HYGON_DF1) { + if (df_cfg.rev >=3D HYGON_DF3) { + /* Read D18F0x1B4 (DramOffset) */ + if (df_indirect_read_instance(ctx->node_id, 0, 0x1B4 + (4 * map_num), + ctx->inst_id, ®_dram_offset)) + return -EINVAL; + } else if (df_cfg.rev >=3D HYGON_DF1) { /* Read D18F0x214 (DramOffset) */ if (df_indirect_read_instance(ctx->node_id, 0, 0x214 + (4 * map_num), ctx->inst_id, ®_dram_offset)) @@ -144,6 +152,7 @@ static int hygon_get_dram_addr_map(struct addr_ctx *ctx) switch (df_cfg.rev) { case HYGON_DF1: return hygon_df1_get_dram_addr_map(ctx); case HYGON_DF2: return hygon_df2_get_dram_addr_map(ctx); + case HYGON_DF3: return df2_get_dram_addr_map(ctx); default: atl_debug_on_bad_df_rev(); return -EINVAL; @@ -165,6 +174,9 @@ static int hygon_get_coh_st_fabric_id(struct addr_ctx *= ctx) case HYGON_DF2: ctx->coh_st_fabric_id =3D FIELD_GET(HYGON_DF2_COH_ST_FABRIC_ID, reg); break; + case HYGON_DF3: + ctx->coh_st_fabric_id =3D FIELD_GET(HYGON_DF3_COH_ST_FABRIC_ID, reg); + break; default: atl_debug_on_bad_df_rev(); return -EINVAL; @@ -286,6 +298,7 @@ static u8 hygon_get_intlv_bit_pos(struct addr_ctx *ctx) switch (df_cfg.rev) { case HYGON_DF1: case HYGON_DF2: + case HYGON_DF3: addr_sel =3D FIELD_GET(HYGON_DF1_INTLV_ADDR_SEL, ctx->map.base); break; default: @@ -303,6 +316,7 @@ static u8 hygon_get_num_intlv_dies(struct addr_ctx *ctx) =20 switch (df_cfg.rev) { case HYGON_DF1: + case HYGON_DF3: dies =3D FIELD_GET(HYGON_DF1_INTLV_NUM_DIES, ctx->map.limit); break; case HYGON_DF2: @@ -326,6 +340,9 @@ static u8 hygon_get_num_intlv_sockets(struct addr_ctx *= ctx) case HYGON_DF2: sockets =3D FIELD_GET(HYGON_DF1_INTLV_NUM_SOCKETS, ctx->map.base); break; + case HYGON_DF3: + sockets =3D FIELD_GET(HYGON_DF3_INTLV_NUM_SOCKETS, ctx->map.limit); + break; default: atl_debug_on_bad_df_rev(); break; diff --git a/drivers/ras/amd/atl/hygon/reg_fields.h b/drivers/ras/amd/atl/h= ygon/reg_fields.h index eaf1d628fd0e..1ee9980d7834 100644 --- a/drivers/ras/amd/atl/hygon/reg_fields.h +++ b/drivers/ras/amd/atl/hygon/reg_fields.h @@ -18,9 +18,11 @@ * D18F0x50 [Fabric Block Instance Information 3] * HYGON_DF1 BlockFabricId [17:8] * HYGON_DF2 BlockFabricId [18:8] + * HYGON_DF3 BlockFabricId [15:8] */ #define HYGON_DF1_COH_ST_FABRIC_ID GENMASK(17, 8) #define HYGON_DF2_COH_ST_FABRIC_ID GENMASK(18, 8) +#define HYGON_DF3_COH_ST_FABRIC_ID GENMASK(15, 8) =20 /* * Interleave Number of Sockets @@ -33,8 +35,12 @@ * D18F0x110 [DRAM Base Address] * HYGON_DF1 IntLvNumSockets [3:2] * HYGON_DF2 IntLvNumSockets [3:2] + * + * D18F0x114 [DRAM Limit Address] + * HYGON_DF3 IntLvNumSockets [8] */ #define HYGON_DF1_INTLV_NUM_SOCKETS GENMASK(3, 2) +#define HYGON_DF3_INTLV_NUM_SOCKETS BIT(8) =20 /* * Interleave Number of Channels @@ -47,6 +53,7 @@ * D18F0x110 [DRAM Base Address] * HYGON_DF1 IntLvNumChan [7:4] * HYGON_DF2 IntLvNumChan [7:4] + * HYGON_DF3 IntLvNumChan [7:4] */ #define HYGON_DF1_INTLV_NUM_CHAN GENMASK(7, 4) =20 @@ -61,6 +68,7 @@ * D18F0x110 [DRAM Base Address] * HYGON_DF1 IntLvAddrSel [10:8] * HYGON_DF2 IntLvAddrSel [10:8] + * HYGON_DF3 IntLvAddrSel [10:8] */ #define HYGON_DF1_INTLV_ADDR_SEL GENMASK(10, 8) =20 @@ -75,9 +83,11 @@ * D18F0x114 [DRAM Limit Address] * HYGON_DF1 DstFabricID [9:0] * HYGON_DF2 DstFabricID [10:0] + * HYGON_DF3 DstFabricID [7:0] */ #define HYGON_DF1_DST_FABRIC_ID GENMASK(9, 0) #define HYGON_DF2_DST_FABRIC_ID GENMASK(10, 0) +#define HYGON_DF3_DST_FABRIC_ID GENMASK(7, 0) =20 /* * Interleave Number of Dies @@ -89,6 +99,7 @@ * * D18F0x114 [DRAM Limit Address] * HYGON_DF1 IntLvNumDies [11:10] + * HYGON_DF3 IntLvNumDies [11:10] * * D18F0x60 * HYGON_DF2 IntLvNumDies [1:0] @@ -107,8 +118,12 @@ * D18F0x214 [DRAM Offset] * HYGON_DF1 HiAddrOffset [31:19] * HYGON_DF2 HiAddrOffset [31:19] + * + * D18F0x1B4 [DRAM Offset] + * HYGON_DF3 HiAddrOffset [31:20] */ #define HYGON_DF1_HI_ADDR_OFFSET GENMASK(31, 19) +#define HYGON_DF3_HI_ADDR_OFFSET GENMASK(31, 20) =20 /* * Die ID Mask @@ -121,9 +136,11 @@ * D18F1x208 [System Fabric ID Mask] * HYGON_DF1 DieIdMask [9:0] * HYGON_DF2 DieIdMask [10:0] + * HYGON_DF3 DieIdMask [15:8] */ #define HYGON_DF1_DIE_ID_MASK GENMASK(9, 0) #define HYGON_DF2_DIE_ID_MASK GENMASK(10, 0) +#define HYGON_DF3_DIE_ID_MASK GENMASK(15, 8) =20 /* * Die ID Shift @@ -136,8 +153,10 @@ * D18F1x208 [System Fabric ID Mask] * HYGON_DF1 DieIdShift [15:12] * HYGON_DF2 DieIdShift [15:12] + * HYGON_DF3 DieIdShift [27:24] */ #define HYGON_DF1_DIE_ID_SHIFT GENMASK(15, 12) +#define HYGON_DF3_DIE_ID_SHIFT GENMASK(27, 24) =20 /* * Socket ID Mask @@ -150,9 +169,11 @@ * D18F1x208 [System Fabric ID Mask] * HYGON_DF1 SocketIdMask [25:16] * HYGON_DF2 SocketIdMask [26:16] + * HYGON_DF3 SocketIdMask [23:16] */ #define HYGON_DF1_SOCKET_ID_MASK GENMASK(25, 16) #define HYGON_DF2_SOCKET_ID_MASK GENMASK(26, 16) +#define HYGON_DF3_SOCKET_ID_MASK GENMASK(23, 16) =20 /* * Socket ID Shift @@ -165,5 +186,6 @@ * D18F1x208 [System Fabric ID Mask] * HYGON_DF1 SocketIdShift [31:28] * HYGON_DF2 SocketIdShift [31:28] + * HYGON_DF3 SocketIdShift [31:28] */ #define HYGON_DF1_SOCKET_ID_SHIFT GENMASK(31, 28) diff --git a/drivers/ras/amd/atl/hygon/system.c b/drivers/ras/amd/atl/hygon= /system.c index a06a39bc4527..f3ca6f58d00f 100644 --- a/drivers/ras/amd/atl/hygon/system.c +++ b/drivers/ras/amd/atl/hygon/system.c @@ -24,6 +24,12 @@ static void hygon_df_get_masks_shifts(u32 mask0) df_cfg.die_id_shift =3D FIELD_GET(HYGON_DF1_DIE_ID_SHIFT, mask0); df_cfg.die_id_mask =3D FIELD_GET(HYGON_DF2_DIE_ID_MASK, mask0); break; + case HYGON_DF3: + df_cfg.socket_id_shift =3D FIELD_GET(HYGON_DF1_SOCKET_ID_SHIFT, mask0); + df_cfg.socket_id_mask =3D FIELD_GET(HYGON_DF3_SOCKET_ID_MASK, mask0); + df_cfg.die_id_shift =3D FIELD_GET(HYGON_DF3_DIE_ID_SHIFT, mask0); + df_cfg.die_id_mask =3D FIELD_GET(HYGON_DF3_DIE_ID_MASK, mask0); + break; default: atl_debug_on_bad_df_rev(); return; @@ -38,6 +44,8 @@ static int hygon_determine_df_rev(void) df_cfg.rev =3D HYGON_DF1; else if (boot_cpu_data.x86_model =3D=3D 0x6 || boot_cpu_data.x86_model = =3D=3D 0x8) df_cfg.rev =3D HYGON_DF2; + else if (boot_cpu_data.x86_model =3D=3D 0x7) + df_cfg.rev =3D HYGON_DF3; =20 /* Read D18F1x208 (SystemFabricIdMask). */ if (df_indirect_read_broadcast(0, 1, 0x208, &fabric_id_mask0)) @@ -53,6 +61,7 @@ static void hygon_get_num_maps(void) switch (df_cfg.rev) { case HYGON_DF1: case HYGON_DF2: + case HYGON_DF3: df_cfg.num_coh_st_maps =3D 2; break; default: diff --git a/drivers/ras/amd/atl/internal.h b/drivers/ras/amd/atl/internal.h index c368559ca2ae..5e95d598c89e 100644 --- a/drivers/ras/amd/atl/internal.h +++ b/drivers/ras/amd/atl/internal.h @@ -45,6 +45,7 @@ enum df_revisions { UNKNOWN, HYGON_DF1, HYGON_DF2, + HYGON_DF3, DF2, DF3, DF3p5, --=20 2.47.3 From nobody Sun Jun 14 14:29:41 2026 Received: from out28-130.mail.aliyun.com (out28-130.mail.aliyun.com [115.124.28.130]) (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 5FEC23AC0F3; Fri, 3 Apr 2026 10:59:24 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=115.124.28.130 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775213966; cv=none; b=bsO482f4VyHMt3UcSxqUxwSXCN+lwCmGylUvyJ1zk4mOfVUw49HYGSX5ZA6eZAiTccgRI2ivZ3VCUAm1QV14NPuU6w7aL1oB4DfjQTIE1xER7YFVnOKbPoVFlaQVBbEse5uxV6IX5CJPPjagu9Jl19P0RwPyYCoHx8FbeSAS5aw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775213966; c=relaxed/simple; bh=jEH4NupTqcoh5OSDDBOiPw08baMwrRUn25spgOJSjmk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TraAePCa48f7ndsSGf3bz4d9GLhZNuu5sHv594aMJpgvsoL5C8n/LtzrB1hTB0wL6t2wxk1AOs/h9cxu2Xo95RUrVoIEv9xMb5o9VUuFthKNjh3RuvtRqyplokrWLbXgJDALAQJkrxDDjb/Ki+H5v1obBpSsFO40LcImOSA7mVg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net; spf=pass smtp.mailfrom=open-hieco.net; arc=none smtp.client-ip=115.124.28.130 Authentication-Results: smtp.subspace.kernel.org; dmarc=none (p=none dis=none) header.from=open-hieco.net Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=open-hieco.net X-Alimail-AntiSpam: AC=CONTINUE;BC=0.07436259|-1;CH=blue;DM=|OVERLOAD|false|;DS=CONTINUE|ham_alarm|0.0137167-0.000863066-0.98542;FP=1959462715561411799|0|0|0|0|-1|-1|-1;HT=maildocker-contentspam033037017159;MF=shiaichun@open-hieco.net;NM=1;PH=DS;RN=5;RT=5;SR=0;TI=SMTPD_---.h4TkMGF_1775213950; Received: from localhost.localdomain(mailfrom:shiaichun@open-hieco.net fp:SMTPD_---.h4TkMGF_1775213950 cluster:ay29) by smtp.aliyun-inc.com; Fri, 03 Apr 2026 18:59:15 +0800 From: Aichun Shi To: yazen.ghannam@amd.com Cc: tglx@linutronix.de, linux-edac@vger.kernel.org, linux-kernel@vger.kernel.org, shiaichun@open-hieco.net Subject: [RFC PATCH 10/10] EDAC/amd64: Add Hygon Family 0x18 models 0x4-0x8 support Date: Fri, 3 Apr 2026 18:57:34 +0800 Message-ID: X-Mailer: git-send-email 2.47.3 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add UMC base support for Hygon Family 0x18 models 0x4-0x8. Add error channel fields from MCA IPID for Hygon. Add distinct memory-controller counts for Hygon models 0x4/0x5. Add Hygon node number support in amd64_edac_init() and amd64_edac_exit(). Signed-off-by: Aichun Shi --- drivers/edac/amd64_edac.c | 68 ++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index 8908ab881c85..4a24cf28e543 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -4,6 +4,7 @@ #include "amd64_edac.h" #include #include +#include =20 static struct edac_pci_ctl_info *pci_ctl; =20 @@ -98,6 +99,29 @@ int __amd64_write_pci_cfg_dword(struct pci_dev *pdev, in= t offset, return pcibios_err_to_errno(err); } =20 +static u32 get_umc_base_addr(struct amd64_pvt *pvt, u8 channel) +{ + if (hygon_f18h_m4h()) { + struct pci_dev *dev =3D node_to_amd_nb(pvt->mc_node_id)->misc; + u8 df_id; + + hygon_get_dfid(dev, &df_id); + + return get_umc_base(channel) + (0x80000000 + (0x10000000 * (df_id - 4))); + } + + return get_umc_base(channel); +} + +static u16 get_num_nodes(void) +{ + if (boot_cpu_data.x86_vendor =3D=3D X86_VENDOR_HYGON && + boot_cpu_data.x86 =3D=3D 0x18) + return amd_num_nodes(); + + return amd_nb_num(); +} + /* * Select DCT to which PCI cfg accesses are routed */ @@ -1452,12 +1476,15 @@ static void umc_read_base_mask(struct amd64_pvt *pv= t) u32 mask_reg, mask_reg_sec; u32 *base, *base_sec; u32 *mask, *mask_sec; + u32 umc_base; int cs, umc; u32 tmp; =20 for_each_umc(umc) { - umc_base_reg =3D get_umc_base(umc) + UMCCH_BASE_ADDR; - umc_base_reg_sec =3D get_umc_base(umc) + UMCCH_BASE_ADDR_SEC; + umc_base =3D get_umc_base_addr(pvt, umc); + + umc_base_reg =3D umc_base + UMCCH_BASE_ADDR; + umc_base_reg_sec =3D umc_base + UMCCH_BASE_ADDR_SEC; =20 for_each_chip_select(cs, umc, pvt) { base =3D &pvt->csels[umc].csbases[cs]; @@ -1479,8 +1506,8 @@ static void umc_read_base_mask(struct amd64_pvt *pvt) } } =20 - umc_mask_reg =3D get_umc_base(umc) + UMCCH_ADDR_MASK; - umc_mask_reg_sec =3D get_umc_base(umc) + get_umc_reg(pvt, UMCCH_ADDR_MAS= K_SEC); + umc_mask_reg =3D umc_base + UMCCH_ADDR_MASK; + umc_mask_reg_sec =3D umc_base + get_umc_reg(pvt, UMCCH_ADDR_MASK_SEC); =20 for_each_chip_select_mask(cs, umc, pvt) { mask =3D &pvt->csels[umc].csmasks[cs]; @@ -1567,7 +1594,8 @@ static void umc_determine_memory_type(struct amd64_pv= t *pvt) * Check if the system supports the "DDR Type" field in UMC Config * and has DDR5 DIMMs in use. */ - if (pvt->flags.zn_regs_v2 && ((umc->umc_cfg & GENMASK(2, 0)) =3D=3D 0x1)= ) { + if ((pvt->flags.zn_regs_v2 || hygon_f18h_m4h()) && + ((umc->umc_cfg & GENMASK(2, 0)) =3D=3D 0x1)) { if (umc->dimm_cfg & BIT(5)) umc->dram_type =3D MEM_LRDDR5; else if (umc->dimm_cfg & BIT(4)) @@ -2801,7 +2829,11 @@ static inline void decode_bus_error(int node_id, str= uct mce *m) */ static void umc_get_err_info(struct mce *m, struct err_info *err) { - err->channel =3D (m->ipid & GENMASK(31, 0)) >> 20; + if (boot_cpu_data.x86_vendor =3D=3D X86_VENDOR_HYGON && + boot_cpu_data.x86 =3D=3D 0x18) + err->channel =3D FIELD_GET(GENMASK(23, 20), m->ipid); + else + err->channel =3D FIELD_GET(GENMASK(31, 20), m->ipid); err->csrow =3D m->synd & 0x7; } =20 @@ -2922,8 +2954,7 @@ static void umc_read_mc_regs(struct amd64_pvt *pvt) =20 /* Read registers from each UMC */ for_each_umc(i) { - - umc_base =3D get_umc_base(i); + umc_base =3D get_umc_base_addr(pvt, i); umc =3D &pvt->umc[i]; =20 if (!amd_smn_read(nid, umc_base + get_umc_reg(pvt, UMCCH_DIMM_CFG), &tmp= )) @@ -3841,6 +3872,16 @@ static int per_family_init(struct amd64_pvt *pvt) break; =20 case 0x18: + switch (pvt->model) { + case 0x4: + pvt->max_mcs =3D 3; + break; + case 0x5: + pvt->max_mcs =3D 1; + break; + default: + break; + } break; =20 case 0x19: @@ -4128,6 +4169,7 @@ static int __init amd64_edac_init(void) { const char *owner; int err =3D -ENODEV; + u16 node_num; int i; =20 if (ghes_get_devices()) @@ -4140,13 +4182,15 @@ static int __init amd64_edac_init(void) if (!x86_match_cpu(amd64_cpuids)) return -ENODEV; =20 - if (!amd_nb_num()) + node_num =3D get_num_nodes(); + + if (!node_num) return -ENODEV; =20 opstate_init(); =20 err =3D -ENOMEM; - ecc_stngs =3D kzalloc_objs(ecc_stngs[0], amd_nb_num()); + ecc_stngs =3D kzalloc_objs(ecc_stngs[0], node_num); if (!ecc_stngs) goto err_free; =20 @@ -4154,7 +4198,7 @@ static int __init amd64_edac_init(void) if (!msrs) goto err_free; =20 - for (i =3D 0; i < amd_nb_num(); i++) { + for (i =3D 0; i < node_num; i++) { err =3D probe_one_instance(i); if (err) { /* unwind properly */ @@ -4210,7 +4254,7 @@ static void __exit amd64_edac_exit(void) else amd_unregister_ecc_decoder(decode_bus_error); =20 - for (i =3D 0; i < amd_nb_num(); i++) + for (i =3D 0; i < get_num_nodes(); i++) remove_one_instance(i); =20 kfree(ecc_stngs); --=20 2.47.3