[RFC PATCH 04/10] ras/amd/atl: Add Hygon DF1 address dehash helper

From: Aichun Shi

Date: Fri Apr 03 2026 - 07:04:25 EST


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 <shiaichun@xxxxxxxxxxxxxx>
---
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 += map.o
amd_atl-y += system.o
amd_atl-y += umc.o

+amd_atl-y += hygon/dehash.o
amd_atl-y += hygon/denormalize.o
amd_atl-y += hygon/map.o
amd_atl-y += 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 <shiaichun@xxxxxxxxxxxxxx>
+ */
+
+#include "../internal.h"
+
+static int hygon_df1_ddr5_dehash_addr(struct addr_ctx *ctx)
+{
+ u8 chan_hash_enable = ctx->chan_intlv_hygon.chan_hash_enable;
+ u8 sub_channel = ctx->chan_intlv_hygon.sub_channel;
+ u8 start_bit = ctx->chan_intlv_hygon.start_bit;
+ u8 hashed_bit;
+
+ if (chan_hash_enable) {
+ hashed_bit = (ctx->ret_addr >> 12) ^
+ (ctx->ret_addr >> 21) ^
+ (ctx->ret_addr >> 30) ^
+ sub_channel;
+ hashed_bit &= BIT(0);
+ ctx->ret_addr |= hashed_bit << start_bit;
+ } else {
+ ctx->ret_addr |= sub_channel << start_bit;
+ }
+
+ return 0;
+}
+
+static int hygon_df_2chan_dehash_addr(struct addr_ctx *ctx)
+{
+ u8 hashed_bit;
+ u8 intlv_bit_pos = ctx->map.intlv_bit_pos;
+
+ hashed_bit = (ctx->ret_addr >> 12) ^
+ (ctx->ret_addr >> 18) ^
+ (ctx->ret_addr >> 21) ^
+ (ctx->ret_addr >> 30) ^
+ ctx->coh_st_fabric_id;
+
+ hashed_bit &= BIT(0);
+ if (hashed_bit != ((ctx->ret_addr >> intlv_bit_pos) & BIT(0)))
+ ctx->ret_addr ^= 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 == 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);

/* GUIDs for PRM handlers */
extern const guid_t norm_to_sys_guid;
--
2.47.3