linux-edac.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Yazen Ghannam <Yazen.Ghannam@amd.com>
To: linux-edac@vger.kernel.org
Cc: Yazen Ghannam <Yazen.Ghannam@amd.com>,
	linux-kernel@vger.kernel.org, tony.luck@intel.com,
	x86@kernel.org, Smita.KoralahalliChannabasappa@amd.com
Subject: [PATCH 25/25] x86/MCE/AMD: Add support for address translation on DF3 systems
Date: Fri,  7 May 2021 15:01:40 -0400	[thread overview]
Message-ID: <20210507190140.18854-26-Yazen.Ghannam@amd.com> (raw)
In-Reply-To: <20210507190140.18854-1-Yazen.Ghannam@amd.com>

From: Yazen Ghannam <yazen.ghannam@amd.com>

DF3-based systems (Rome and later) support new interleaving modes and a
number of bit fields have changed or moved entirely. Add support for
these new modes and fields.

Refactoring should be minimal due to earlier changes, and most updates
will be additions.

Signed-off-by: Yazen Ghannam <yazen.ghannam@amd.com>
---
 arch/x86/kernel/cpu/mce/amd.c | 183 +++++++++++++++++++++++++++++++---
 1 file changed, 171 insertions(+), 12 deletions(-)

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;
 }
 
-- 
2.25.1


  parent reply	other threads:[~2021-05-07 19:04 UTC|newest]

Thread overview: 33+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-05-07 19:01 [PATCH 00/25] AMD MCA Address Translation Updates Yazen Ghannam
2021-05-07 19:01 ` [PATCH 01/25] x86/MCE/AMD: Don't use naked values for DF registers Yazen Ghannam
2021-05-07 19:01 ` [PATCH 02/25] x86/MCE/AMD: Add context struct Yazen Ghannam
2021-05-07 19:01 ` [PATCH 03/25] x86/MCE/AMD: Define functions for DramOffset Yazen Ghannam
2021-05-07 19:01 ` [PATCH 04/25] x86/MCE/AMD: Define function to read DRAM address map registers Yazen Ghannam
2021-05-07 19:01 ` [PATCH 05/25] x86/MCE/AMD: Define function to find interleaving mode Yazen Ghannam
2021-05-07 19:01 ` [PATCH 06/25] x86/MCE/AMD: Define function to denormalize address Yazen Ghannam
2021-05-07 19:01 ` [PATCH 07/25] x86/MCE/AMD: Define function to add DRAM base and hole Yazen Ghannam
2021-05-07 19:01 ` [PATCH 08/25] x86/MCE/AMD: Define function to dehash address Yazen Ghannam
2021-05-07 19:01 ` [PATCH 09/25] x86/MCE/AMD: Define function to check DRAM limit address Yazen Ghannam
2021-05-07 19:01 ` [PATCH 10/25] x86/MCE/AMD: Remove goto statements Yazen Ghannam
2021-05-07 19:01 ` [PATCH 11/25] x86/MCE/AMD: Simplify function parameters Yazen Ghannam
2021-05-07 19:01 ` [PATCH 12/25] x86/MCE/AMD: Define function to get Interleave Address Bit Yazen Ghannam
2021-05-07 19:01 ` [PATCH 13/25] x86/MCE/AMD: Skip denormalization if no interleaving Yazen Ghannam
2021-05-07 19:01 ` [PATCH 14/25] x86/MCE/AMD: Define function to get number of interleaved channels Yazen Ghannam
2021-05-07 19:01 ` [PATCH 15/25] x86/MCE/AMD: Define function to get number of interleaved dies Yazen Ghannam
2021-05-07 19:01 ` [PATCH 16/25] x86/MCE/AMD: Define function to get number of interleaved sockets Yazen Ghannam
2021-05-07 19:01 ` [PATCH 17/25] x86/MCE/AMD: Remove unnecessary assert Yazen Ghannam
2021-05-07 19:01 ` [PATCH 18/25] x86/MCE/AMD: Define function to make space for CS ID Yazen Ghannam
2021-05-07 19:01 ` [PATCH 19/25] x86/MCE/AMD: Define function to calculate " Yazen Ghannam
2021-05-07 19:01 ` [PATCH 20/25] x86/MCE/AMD: Define function to insert CS ID into address Yazen Ghannam
2021-05-07 19:01 ` [PATCH 21/25] x86/MCE/AMD: Define function to get CS Fabric ID Yazen Ghannam
2021-05-07 19:01 ` [PATCH 22/25] x86/MCE/AMD: Define function to find shift and mask values Yazen Ghannam
2021-05-07 19:01 ` [PATCH 23/25] x86/MCE/AMD: Update CS ID calculation to match reference code Yazen Ghannam
2021-05-07 19:01 ` [PATCH 24/25] x86/MCE/AMD: Match hash function to " Yazen Ghannam
2021-05-07 19:01 ` Yazen Ghannam [this message]
2021-05-07 20:32 ` [PATCH 00/25] AMD MCA Address Translation Updates Randy Dunlap
2021-05-11 15:42   ` Yazen Ghannam
2021-05-11 16:13     ` Randy Dunlap
2021-05-11 16:28       ` Borislav Petkov
2021-05-17 12:57 ` Borislav Petkov
2021-05-19  3:52   ` Yazen Ghannam
2021-05-19 14:32     ` Borislav Petkov

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210507190140.18854-26-Yazen.Ghannam@amd.com \
    --to=yazen.ghannam@amd.com \
    --cc=Smita.KoralahalliChannabasappa@amd.com \
    --cc=linux-edac@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=tony.luck@intel.com \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).