diff --git a/arch/x86/kernel/cpu/mce/amd.c b/arch/x86/kernel/cpu/mce/amd.c
index b3bfdc42dcaa..a165706c04f1 100644
--- a/arch/x86/kernel/cpu/mce/amd.c
+++ b/arch/x86/kernel/cpu/mce/amd.c
@@ -684,9 +684,11 @@ enum df_reg_names {
 	DRAM_BASE_ADDR_1,
 	DRAM_LIMIT_ADDR_1,
 	DRAM_OFFSET,
+	DF_GLOBAL_CTL,
 
 	/* Function 1 */
 	SYS_FAB_ID_MASK,
+	SYS_FAB_ID_MASK_1,
 };
 
 static struct df_reg df_regs[] = {
@@ -702,18 +704,28 @@ static struct df_reg df_regs[] = {
 	[DRAM_LIMIT_ADDR_1]	=	{0, 0x11C},
 	/* D18F0x1B4 (DramOffset) */
 	[DRAM_OFFSET]		=	{0, 0x1B4},
+	/* D18F0x3F8 (DfGlobalCtrl) */
+	[DF_GLOBAL_CTL]		=	{0, 0x3F8},
 	/* D18F1x208 (SystemFabricIdMask) */
 	[SYS_FAB_ID_MASK]	=	{1, 0x208},
+	/* D18F1x20C (SystemFabricIdMask1) */
+	[SYS_FAB_ID_MASK_1]	=	{1, 0x20C},
 };
 
 enum df_types {
 	DF2,
+	DF3,
 };
 
 /* These are mapped 1:1 to the hardware values. Special cases are set at > 0x20. */
 enum intlv_modes {
 	NONE		= 0x00,
 	NOHASH_2CH	= 0x01,
+	NOHASH_4CH	= 0x03,
+	NOHASH_8CH	= 0x05,
+	HASH_COD4_2CH	= 0x0C,
+	HASH_COD2_4CH	= 0x0D,
+	HASH_COD1_8CH	= 0x0E,
 	DF2_HASH_2CH	= 0x21,
 };
 
@@ -726,6 +738,7 @@ struct addr_ctx {
 	u32 reg_base_addr;
 	u32 reg_limit_addr;
 	u32 reg_fab_id_mask0;
+	u32 reg_fab_id_mask1;
 	u16 nid;
 	u8 umc;
 	u8 map_num;
@@ -737,11 +750,15 @@ struct addr_ctx {
 	u8 cs_fabric_id;
 	u8 die_id_mask;
 	u8 socket_id_mask;
+	u8 node_id_shift;
 	bool hash_enabled;
 };
 
 static enum df_types get_df_type(struct addr_ctx *ctx)
 {
+	if ((ctx->reg_fab_id_mask0 & 0xFF) != 0)
+		return DF3;
+
 	return DF2;
 }
 
@@ -762,8 +779,23 @@ static int get_intlv_mode_df2(struct addr_ctx *ctx)
 	return 0;
 }
 
+static int get_intlv_mode_df3(struct addr_ctx *ctx)
+{
+	ctx->intlv_mode = (ctx->reg_base_addr >> 2) & 0xF;
+
+	if (ctx->intlv_mode == HASH_COD4_2CH ||
+	    ctx->intlv_mode == HASH_COD2_4CH ||
+	    ctx->intlv_mode == HASH_COD1_8CH)
+		ctx->hash_enabled = true;
+
+	return 0;
+}
+
 static int get_intlv_mode(struct addr_ctx *ctx)
 {
+	if (ctx->df_type == DF3)
+		return get_intlv_mode_df3(ctx);
+
 	return get_intlv_mode_df2(ctx);
 }
 
@@ -777,6 +809,9 @@ static int get_dram_offset_reg(struct addr_ctx *ctx)
 
 static u64 get_hi_addr_offset(struct addr_ctx *ctx)
 {
+	if (ctx->df_type == DF3)
+		return (ctx->reg_dram_offset & GENMASK_ULL(31, 12)) << 16;
+
 	return (ctx->reg_dram_offset & GENMASK_ULL(31, 20)) << 8;
 }
 
@@ -823,10 +858,15 @@ static int get_dram_addr_map(struct addr_ctx *ctx)
 
 static int get_intlv_addr_bit(struct addr_ctx *ctx)
 {
-	u8 intlv_addr_sel = (ctx->reg_base_addr >> 8) & 0x7;
+	u8 intlv_addr_sel;
+
+	if (ctx->df_type == DF3)
+		intlv_addr_sel = (ctx->reg_base_addr >> 9) & 0x7;
+	else
+		intlv_addr_sel = (ctx->reg_base_addr >> 8) & 0x7;
 
-	/* {0, 1, 2, 3} map to address bits {8, 9, 10, 11} respectively */
-	if (intlv_addr_sel > 3) {
+	/* {0, 1, 2, 3, 4} map to address bits {8, 9, 10, 11, 12} respectively */
+	if (intlv_addr_sel > 4) {
 		pr_err("%s: Invalid interleave address select %d.\n",
 			__func__, intlv_addr_sel);
 		return -EINVAL;
@@ -845,9 +885,18 @@ static void get_intlv_num_chan(struct addr_ctx *ctx)
 		ctx->intlv_num_chan = 0;
 		break;
 	case NOHASH_2CH:
+	case HASH_COD4_2CH:
 	case DF2_HASH_2CH:
 		ctx->intlv_num_chan = 1;
 		break;
+	case NOHASH_4CH:
+	case HASH_COD2_4CH:
+		ctx->intlv_num_chan = 2;
+		break;
+	case NOHASH_8CH:
+	case HASH_COD1_8CH:
+		ctx->intlv_num_chan = 3;
+		break;
 	default:
 		/* Valid interleaving modes where checked earlier. */
 		break;
@@ -856,12 +905,18 @@ static void get_intlv_num_chan(struct addr_ctx *ctx)
 
 static void get_intlv_num_dies(struct addr_ctx *ctx)
 {
-	ctx->intlv_num_dies  = (ctx->reg_limit_addr >> 10) & 0x3;
+	if (ctx->df_type == DF3)
+		ctx->intlv_num_dies  = (ctx->reg_base_addr >> 6) & 0x3;
+	else
+		ctx->intlv_num_dies  = (ctx->reg_limit_addr >> 10) & 0x3;
 }
 
 static void get_intlv_num_sockets(struct addr_ctx *ctx)
 {
-	ctx->intlv_num_sockets = (ctx->reg_limit_addr >> 8) & 0x1;
+	if (ctx->df_type == DF3)
+		ctx->intlv_num_sockets = (ctx->reg_base_addr >> 8) & 0x1;
+	else
+		ctx->intlv_num_sockets = (ctx->reg_limit_addr >> 8) & 0x1;
 }
 
 static void expand_bits(u8 start_bit, u8 num_bits, u64 *value)
@@ -884,12 +939,22 @@ static void make_space_for_cs_id(struct addr_ctx *ctx)
 
 	switch (ctx->intlv_mode) {
 	case NOHASH_2CH:
+	case NOHASH_4CH:
+	case NOHASH_8CH:
 	case DF2_HASH_2CH:
 		num_intlv_bits = ctx->intlv_num_chan;
 		num_intlv_bits += ctx->intlv_num_dies;
 		num_intlv_bits += ctx->intlv_num_sockets;
 		expand_bits(ctx->intlv_addr_bit, num_intlv_bits, &ctx->ret_addr);
 		break;
+	case HASH_COD4_2CH:
+	case HASH_COD2_4CH:
+	case HASH_COD1_8CH:
+		num_intlv_bits = ctx->intlv_num_chan;
+		num_intlv_bits += ctx->intlv_num_sockets;
+		expand_bits(ctx->intlv_addr_bit, 1, &ctx->ret_addr);
+		if (num_intlv_bits > 1)
+			expand_bits(12, num_intlv_bits - 1, &ctx->ret_addr);
 	default:
 		/* Valid interleaving modes where checked earlier. */
 		break;
@@ -908,29 +973,56 @@ static int get_cs_fabric_id(struct addr_ctx *ctx)
 	return 0;
 }
 
-static void get_masks(struct addr_ctx *ctx)
-{
-	ctx->die_id_mask    = (ctx->reg_fab_id_mask0 >> 8) & 0xFF;
-	ctx->socket_id_mask = (ctx->reg_fab_id_mask0 >> 16) & 0xFF;
-}
-
 static u8 get_die_id_shift(struct addr_ctx *ctx)
 {
+	if (ctx->df_type == DF3)
+		return ctx->node_id_shift;
+
 	return (ctx->reg_fab_id_mask0 >> 24) & 0xF;
 }
 
 static u8 get_socket_id_shift(struct addr_ctx *ctx)
 {
+	if (ctx->df_type == DF3)
+		return ((ctx->reg_fab_id_mask1 >> 8) & 0x3) + ctx->node_id_shift;
+
 	return (ctx->reg_fab_id_mask0 >> 28) & 0xF;
 }
 
+static void get_node_id_shift(struct addr_ctx *ctx)
+{
+	ctx->node_id_shift = ctx->reg_fab_id_mask1 & 0xF;
+}
+
+static void get_masks(struct addr_ctx *ctx)
+{
+	if (ctx->df_type == DF3) {
+		get_node_id_shift(ctx);
+
+		ctx->die_id_mask = (ctx->reg_fab_id_mask1 >> 16) & 0x7;
+		ctx->die_id_mask <<= ctx->node_id_shift;
+
+		ctx->socket_id_mask = (ctx->reg_fab_id_mask1 >> 24) & 0x7;
+		ctx->socket_id_mask <<= ctx->node_id_shift;
+	} else {
+		ctx->die_id_mask    = (ctx->reg_fab_id_mask0 >> 8) & 0xFF;
+		ctx->socket_id_mask = (ctx->reg_fab_id_mask0 >> 16) & 0xFF;
+	}
+}
+
 static u8 get_dst_fabric_id(struct addr_ctx *ctx)
 {
+	if (ctx->df_type == DF3)
+		return ctx->reg_limit_addr & 0x1FF;
+
 	return ctx->reg_limit_addr & 0xFF;
 }
 
 static u8 get_component_id_mask(struct addr_ctx *ctx)
 {
+	if (ctx->df_type == DF3)
+		return ctx->reg_fab_id_mask0 & 0x1FF;
+
 	return (~(ctx->socket_id_mask | ctx->die_id_mask)) & 0xFF;
 }
 
@@ -982,7 +1074,14 @@ static int calculate_cs_id(struct addr_ctx *ctx)
 
 static void insert_cs_id(struct addr_ctx *ctx)
 {
-	ctx->ret_addr |= (ctx->cs_id << ctx->intlv_addr_bit);
+	if (ctx->intlv_mode == HASH_COD4_2CH ||
+	    ctx->intlv_mode == HASH_COD2_4CH ||
+	    ctx->intlv_mode == HASH_COD1_8CH) {
+		ctx->ret_addr |= ((ctx->cs_id & 0x1) << ctx->intlv_addr_bit);
+		ctx->ret_addr |= ((ctx->cs_id & 0xE) << 11);
+	} else {
+		ctx->ret_addr |= (ctx->cs_id << ctx->intlv_addr_bit);
+	}
 }
 
 static int denormalize_addr(struct addr_ctx *ctx)
@@ -1047,11 +1146,67 @@ static int dehash_addr_df2(struct addr_ctx *ctx)
 	return 0;
 }
 
+static int dehash_addr_df3(struct addr_ctx *ctx)
+{
+	u8 hashed_bit, intlv_ctl_64k, intlv_ctl_2M, intlv_ctl_1G;
+	u32 tmp;
+
+	if (amd_df_indirect_read(ctx->nid, df_regs[DF_GLOBAL_CTL], ctx->umc, &tmp))
+		return -EINVAL;
+
+	intlv_ctl_64k = !!((tmp >> 20) & 0x1);
+	intlv_ctl_2M  = !!((tmp >> 21) & 0x1);
+	intlv_ctl_1G  = !!((tmp >> 22) & 0x1);
+
+	hashed_bit =	(ctx->ret_addr >> 14) ^
+			((ctx->ret_addr >> 18) & intlv_ctl_64k) ^
+			((ctx->ret_addr >> 23) & intlv_ctl_2M) ^
+			((ctx->ret_addr >> 32) & intlv_ctl_1G) ^
+			(ctx->ret_addr >> ctx->intlv_addr_bit);
+
+	hashed_bit &= BIT(0);
+
+	if (hashed_bit != ((ctx->ret_addr >> ctx->intlv_addr_bit) & BIT(0)))
+		ctx->ret_addr ^= BIT(ctx->intlv_addr_bit);
+
+	if (ctx->intlv_mode != HASH_COD2_4CH &&
+	    ctx->intlv_mode != HASH_COD1_8CH)
+		return 0;
+
+	hashed_bit =	(ctx->ret_addr >> 12) ^
+			((ctx->ret_addr >> 16) & intlv_ctl_64k) ^
+			((ctx->ret_addr >> 21) & intlv_ctl_2M) ^
+			((ctx->ret_addr >> 30) & intlv_ctl_1G);
+
+	hashed_bit &= BIT(0);
+
+	if (hashed_bit != ((ctx->ret_addr >> 12) & BIT(0)))
+		ctx->ret_addr ^= BIT(12);
+
+	if (ctx->intlv_mode != HASH_COD1_8CH)
+		return 0;
+
+	hashed_bit =	(ctx->ret_addr >> 13) ^
+			((ctx->ret_addr >> 17) & intlv_ctl_64k) ^
+			((ctx->ret_addr >> 22) & intlv_ctl_2M) ^
+			((ctx->ret_addr >> 31) & intlv_ctl_1G);
+
+	hashed_bit &= BIT(0);
+
+	if (hashed_bit != ((ctx->ret_addr >> 13) & BIT(0)))
+		ctx->ret_addr ^= BIT(13);
+
+	return 0;
+}
+
 static int dehash_addr(struct addr_ctx *ctx)
 {
 	if (!ctx->hash_enabled)
 		return 0;
 
+	if (ctx->df_type == DF3)
+		return dehash_addr_df3(ctx);
+
 	return dehash_addr_df2(ctx);
 }
 
@@ -1073,6 +1228,10 @@ static int get_fabric_id_mask_reg(struct addr_ctx *ctx)
 				 ctx->umc, &ctx->reg_fab_id_mask0))
 		return -EINVAL;
 
+	if (amd_df_indirect_read(ctx->nid, df_regs[SYS_FAB_ID_MASK_1],
+				 ctx->umc, &ctx->reg_fab_id_mask1))
+		return -EINVAL;
+
 	return 0;
 }
 
