The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH 0/7] EDAC/i10nm: Add RRL support for Intel Granite Rapids server
@ 2025-04-17 15:07 Qiuxu Zhuo
  2025-04-17 15:07 ` [PATCH 1/7] EDAC/skx_common: Fix general protection fault Qiuxu Zhuo
                   ` (7 more replies)
  0 siblings, 8 replies; 13+ messages in thread
From: Qiuxu Zhuo @ 2025-04-17 15:07 UTC (permalink / raw)
  To: Tony Luck
  Cc: Qiuxu Zhuo, Borislav Petkov, James Morse, Mauro Carvalho Chehab,
	Robert Richter, Yi Lai, Feng Xu, Shawn Fan, linux-edac,
	linux-kernel

The RRL (Retry Read error Log) registers provide additional error information
during DDR memory correction. This can assist memory DIMM vendors in isolating
problematic cells within the DIMM and help CSPs predict uncorrectable errors.
This patch series is to add RRL support for Intel Granite Rapids servers and
is structured as follows:

Patch 1-3: Bug fixes and cleanup.

Patch 4-6: Refactor the RRL (Retry Read error Log) code of previous generations
           and prepare for Patch 7.

Patch 7  : Add RRL support for Intel Granite Rapids server.

Qiuxu Zhuo (7):
  EDAC/skx_common: Fix general protection fault
  EDAC/{skx_common,i10nm}: Fix the loss of saved RRL for HBM pseudo channel 0
  EDAC/i10nm: Explicitly set the modes of the RRL register sets
  EDAC/{skx_common,i10nm}: Structure the per-channel RRL registers
  EDAC/{skx_common,i10nm}: Refactor enable_retry_rd_err_log()
  EDAC/{skx_common,i10nm}: Refactor show_retry_rd_err_log()
  EDAC/{skx_common,i10nm}: Add RRL support for Intel Granite Rapids server

 drivers/edac/i10nm_base.c | 477 ++++++++++++++++++++++----------------
 drivers/edac/skx_common.c |   1 +
 drivers/edac/skx_common.h |  61 ++++-
 3 files changed, 330 insertions(+), 209 deletions(-)


base-commit: 8ffd015db85fea3e15a77027fda6c02ced4d2444
-- 
2.43.0


^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH 1/7] EDAC/skx_common: Fix general protection fault
  2025-04-17 15:07 [PATCH 0/7] EDAC/i10nm: Add RRL support for Intel Granite Rapids server Qiuxu Zhuo
@ 2025-04-17 15:07 ` Qiuxu Zhuo
  2025-04-17 15:07 ` [PATCH 2/7] EDAC/{skx_common,i10nm}: Fix the loss of saved RRL for HBM pseudo channel 0 Qiuxu Zhuo
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Qiuxu Zhuo @ 2025-04-17 15:07 UTC (permalink / raw)
  To: Tony Luck
  Cc: Qiuxu Zhuo, Feng Xu, Borislav Petkov, James Morse,
	Mauro Carvalho Chehab, Robert Richter, Yi Lai, Shawn Fan,
	linux-edac, linux-kernel

After loading i10nm_edac (which automatically loads skx_edac_common), if
unload only i10nm_edac, then reload it and perform error injection testing,
a general protection fault may occur:

  mce: [Hardware Error]: Machine check events logged
  Oops: general protection fault ...
  ...
  Workqueue: events mce_gen_pool_process
  RIP: 0010:string+0x53/0xe0
  ...
  Call Trace:
  <TASK>
  ? die_addr+0x37/0x90
  ? exc_general_protection+0x1e7/0x3f0
  ? asm_exc_general_protection+0x26/0x30
  ? string+0x53/0xe0
  vsnprintf+0x23e/0x4c0
  snprintf+0x4d/0x70
  skx_adxl_decode+0x16a/0x330 [skx_edac_common]
  skx_mce_check_error.part.0+0xf8/0x220 [skx_edac_common]
  skx_mce_check_error+0x17/0x20 [skx_edac_common]
  ...

The issue arose was because the variable 'adxl_component_count' (inside
skx_edac_common), which counts the ADXL components, was not reset. During
the reloading of i10nm_edac, the count was incremented by the actual number
of ADXL components again, resulting in a count that was double the real
number of ADXL components. This led to an out-of-bounds reference to the
ADXL component array, causing the general protection fault above.

Fix this issue by resetting the 'adxl_component_count' in adxl_put(),
which is called during the unloading of {skx,i10nm}_edac.

Fixes: 123b15863550 ("EDAC, i10nm: make skx_common.o a separate module")
Reported-by: Feng Xu <feng.f.xu@intel.com>
Tested-by: Feng Xu <feng.f.xu@intel.com>
Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
---
 drivers/edac/skx_common.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/edac/skx_common.c b/drivers/edac/skx_common.c
index fa5b442b1844..c9ade45c1a99 100644
--- a/drivers/edac/skx_common.c
+++ b/drivers/edac/skx_common.c
@@ -116,6 +116,7 @@ EXPORT_SYMBOL_GPL(skx_adxl_get);
 
 void skx_adxl_put(void)
 {
+	adxl_component_count = 0;
 	kfree(adxl_values);
 	kfree(adxl_msg);
 }
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 2/7] EDAC/{skx_common,i10nm}: Fix the loss of saved RRL for HBM pseudo channel 0
  2025-04-17 15:07 [PATCH 0/7] EDAC/i10nm: Add RRL support for Intel Granite Rapids server Qiuxu Zhuo
  2025-04-17 15:07 ` [PATCH 1/7] EDAC/skx_common: Fix general protection fault Qiuxu Zhuo
@ 2025-04-17 15:07 ` Qiuxu Zhuo
  2025-04-17 15:07 ` [PATCH 3/7] EDAC/i10nm: Explicitly set the modes of the RRL register sets Qiuxu Zhuo
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Qiuxu Zhuo @ 2025-04-17 15:07 UTC (permalink / raw)
  To: Tony Luck
  Cc: Qiuxu Zhuo, Feng Xu, Borislav Petkov, James Morse,
	Mauro Carvalho Chehab, Robert Richter, Yi Lai, Shawn Fan,
	linux-edac, linux-kernel

When enabling the retry_rd_err_log (RRL) feature during the loading of the
i10nm_edac driver with the module parameter retry_rd_err_log=2 (Linux RRL
control mode), the default values of the control bits of RRL are saved so
that they can be restored during the unloading of the driver.

In the current code, the RRL of pseudo channel 1 of HBM overwrites pseudo
channel 0 during the loading of the driver, resulting in the loss of saved
RRL for pseudo channel 0. This causes the RRL of pseudo channel 0 of HBM to
be wrongly restored with the values from pseudo channel 1 when unloading
the driver.

Fix this issue by creating two separate groups of RRL control registers
per channel to save default RRL settings of two {sub-,pseudo-}channels.

Fixes: acd4cf68fefe ("EDAC/i10nm: Retrieve and print retry_rd_err_log registers for HBM")
Tested-by: Feng Xu <feng.f.xu@intel.com>
Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
---
 drivers/edac/i10nm_base.c | 35 +++++++++++++++++++----------------
 drivers/edac/skx_common.h | 11 ++++++++---
 2 files changed, 27 insertions(+), 19 deletions(-)

diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c
index 355a977019e9..355b527d839e 100644
--- a/drivers/edac/i10nm_base.c
+++ b/drivers/edac/i10nm_base.c
@@ -95,7 +95,7 @@ static u32 offsets_demand2_spr[] = {0x22c70, 0x22d80, 0x22f18, 0x22d58, 0x22c64,
 static u32 offsets_demand_spr_hbm0[] = {0x2a54, 0x2a60, 0x2b10, 0x2a58, 0x2a5c, 0x0ee0};
 static u32 offsets_demand_spr_hbm1[] = {0x2e54, 0x2e60, 0x2f10, 0x2e58, 0x2e5c, 0x0fb0};
 
-static void __enable_retry_rd_err_log(struct skx_imc *imc, int chan, bool enable,
+static void __enable_retry_rd_err_log(struct skx_imc *imc, int chan, bool enable, u32 *rrl_ctl,
 				      u32 *offsets_scrub, u32 *offsets_demand,
 				      u32 *offsets_demand2)
 {
@@ -108,10 +108,10 @@ static void __enable_retry_rd_err_log(struct skx_imc *imc, int chan, bool enable
 
 	if (enable) {
 		/* Save default configurations */
-		imc->chan[chan].retry_rd_err_log_s = s;
-		imc->chan[chan].retry_rd_err_log_d = d;
+		rrl_ctl[0] = s;
+		rrl_ctl[1] = d;
 		if (offsets_demand2)
-			imc->chan[chan].retry_rd_err_log_d2 = d2;
+			rrl_ctl[2] = d2;
 
 		s &= ~RETRY_RD_ERR_LOG_NOOVER_UC;
 		s |=  RETRY_RD_ERR_LOG_EN;
@@ -125,25 +125,25 @@ static void __enable_retry_rd_err_log(struct skx_imc *imc, int chan, bool enable
 		}
 	} else {
 		/* Restore default configurations */
-		if (imc->chan[chan].retry_rd_err_log_s & RETRY_RD_ERR_LOG_UC)
+		if (rrl_ctl[0] & RETRY_RD_ERR_LOG_UC)
 			s |=  RETRY_RD_ERR_LOG_UC;
-		if (imc->chan[chan].retry_rd_err_log_s & RETRY_RD_ERR_LOG_NOOVER)
+		if (rrl_ctl[0] & RETRY_RD_ERR_LOG_NOOVER)
 			s |=  RETRY_RD_ERR_LOG_NOOVER;
-		if (!(imc->chan[chan].retry_rd_err_log_s & RETRY_RD_ERR_LOG_EN))
+		if (!(rrl_ctl[0] & RETRY_RD_ERR_LOG_EN))
 			s &= ~RETRY_RD_ERR_LOG_EN;
-		if (imc->chan[chan].retry_rd_err_log_d & RETRY_RD_ERR_LOG_UC)
+		if (rrl_ctl[1] & RETRY_RD_ERR_LOG_UC)
 			d |=  RETRY_RD_ERR_LOG_UC;
-		if (imc->chan[chan].retry_rd_err_log_d & RETRY_RD_ERR_LOG_NOOVER)
+		if (rrl_ctl[1] & RETRY_RD_ERR_LOG_NOOVER)
 			d |=  RETRY_RD_ERR_LOG_NOOVER;
-		if (!(imc->chan[chan].retry_rd_err_log_d & RETRY_RD_ERR_LOG_EN))
+		if (!(rrl_ctl[1] & RETRY_RD_ERR_LOG_EN))
 			d &= ~RETRY_RD_ERR_LOG_EN;
 
 		if (offsets_demand2) {
-			if (imc->chan[chan].retry_rd_err_log_d2 & RETRY_RD_ERR_LOG_UC)
+			if (rrl_ctl[2] & RETRY_RD_ERR_LOG_UC)
 				d2 |=  RETRY_RD_ERR_LOG_UC;
-			if (!(imc->chan[chan].retry_rd_err_log_d2 & RETRY_RD_ERR_LOG_NOOVER))
+			if (!(rrl_ctl[2] & RETRY_RD_ERR_LOG_NOOVER))
 				d2 &=  ~RETRY_RD_ERR_LOG_NOOVER;
-			if (!(imc->chan[chan].retry_rd_err_log_d2 & RETRY_RD_ERR_LOG_EN))
+			if (!(rrl_ctl[2] & RETRY_RD_ERR_LOG_EN))
 				d2 &= ~RETRY_RD_ERR_LOG_EN;
 		}
 	}
@@ -157,6 +157,7 @@ static void __enable_retry_rd_err_log(struct skx_imc *imc, int chan, bool enable
 static void enable_retry_rd_err_log(bool enable)
 {
 	int i, j, imc_num, chan_num;
+	struct skx_channel *chan;
 	struct skx_imc *imc;
 	struct skx_dev *d;
 
@@ -171,8 +172,9 @@ static void enable_retry_rd_err_log(bool enable)
 			if (!imc->mbase)
 				continue;
 
+			chan = d->imc[i].chan;
 			for (j = 0; j < chan_num; j++)
-				__enable_retry_rd_err_log(imc, j, enable,
+				__enable_retry_rd_err_log(imc, j, enable, chan[j].rrl_ctl[0],
 							  res_cfg->offsets_scrub,
 							  res_cfg->offsets_demand,
 							  res_cfg->offsets_demand2);
@@ -186,12 +188,13 @@ static void enable_retry_rd_err_log(bool enable)
 			if (!imc->mbase || !imc->hbm_mc)
 				continue;
 
+			chan = d->imc[i].chan;
 			for (j = 0; j < chan_num; j++) {
-				__enable_retry_rd_err_log(imc, j, enable,
+				__enable_retry_rd_err_log(imc, j, enable, chan[j].rrl_ctl[0],
 							  res_cfg->offsets_scrub_hbm0,
 							  res_cfg->offsets_demand_hbm0,
 							  NULL);
-				__enable_retry_rd_err_log(imc, j, enable,
+				__enable_retry_rd_err_log(imc, j, enable, chan[j].rrl_ctl[1],
 							  res_cfg->offsets_scrub_hbm1,
 							  res_cfg->offsets_demand_hbm1,
 							  NULL);
diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h
index ca5408803f87..5afd425f3b4f 100644
--- a/drivers/edac/skx_common.h
+++ b/drivers/edac/skx_common.h
@@ -79,6 +79,9 @@
  */
 #define MCACOD_EXT_MEM_ERR	0x280
 
+/* Max RRL register sets per {,sub-,pseudo-}channel. */
+#define NUM_RRL_SET		3
+
 /*
  * Each cpu socket contains some pci devices that provide global
  * information, and also some that are local to each of the two
@@ -117,9 +120,11 @@ struct skx_dev {
 		struct skx_channel {
 			struct pci_dev	*cdev;
 			struct pci_dev	*edev;
-			u32 retry_rd_err_log_s;
-			u32 retry_rd_err_log_d;
-			u32 retry_rd_err_log_d2;
+			/*
+			 * Two groups of RRL control registers per channel to save default RRL
+			 * settings of two {sub-,pseudo-}channels in Linux RRL control mode.
+			 */
+			u32 rrl_ctl[2][NUM_RRL_SET];
 			struct skx_dimm {
 				u8 close_pg;
 				u8 bank_xor_enable;
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 3/7] EDAC/i10nm: Explicitly set the modes of the RRL register sets
  2025-04-17 15:07 [PATCH 0/7] EDAC/i10nm: Add RRL support for Intel Granite Rapids server Qiuxu Zhuo
  2025-04-17 15:07 ` [PATCH 1/7] EDAC/skx_common: Fix general protection fault Qiuxu Zhuo
  2025-04-17 15:07 ` [PATCH 2/7] EDAC/{skx_common,i10nm}: Fix the loss of saved RRL for HBM pseudo channel 0 Qiuxu Zhuo
@ 2025-04-17 15:07 ` Qiuxu Zhuo
  2025-04-17 15:07 ` [PATCH 4/7] EDAC/{skx_common,i10nm}: Structure the per-channel RRL registers Qiuxu Zhuo
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Qiuxu Zhuo @ 2025-04-17 15:07 UTC (permalink / raw)
  To: Tony Luck
  Cc: Qiuxu Zhuo, Feng Xu, Borislav Petkov, James Morse,
	Mauro Carvalho Chehab, Robert Richter, Yi Lai, Shawn Fan,
	linux-edac, linux-kernel

The i10nm_edac driver uses the default modes (either patrol scrub read
or on-demand read) of the RRL register sets configured by the BIOS.

Explicitly set the modes during the loading of the i10nm_edac driver with
the module parameter retry_rd_err_log=2.

Tested-by: Feng Xu <feng.f.xu@intel.com>
Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
---
 drivers/edac/i10nm_base.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c
index 355b527d839e..50a16ce0aa22 100644
--- a/drivers/edac/i10nm_base.c
+++ b/drivers/edac/i10nm_base.c
@@ -73,6 +73,7 @@
 #define I10NM_SAD_NM_CACHEABLE(reg)	GET_BITFIELD(reg, 5, 5)
 
 #define RETRY_RD_ERR_LOG_UC		BIT(1)
+#define RETRY_RD_ERR_LOG_EN_PATSPR	BIT(13)
 #define RETRY_RD_ERR_LOG_NOOVER		BIT(14)
 #define RETRY_RD_ERR_LOG_EN		BIT(15)
 #define RETRY_RD_ERR_LOG_NOOVER_UC	(BIT(14) | BIT(1))
@@ -114,12 +115,15 @@ static void __enable_retry_rd_err_log(struct skx_imc *imc, int chan, bool enable
 			rrl_ctl[2] = d2;
 
 		s &= ~RETRY_RD_ERR_LOG_NOOVER_UC;
+		s |=  RETRY_RD_ERR_LOG_EN_PATSPR;
 		s |=  RETRY_RD_ERR_LOG_EN;
 		d &= ~RETRY_RD_ERR_LOG_NOOVER_UC;
+		d &= ~RETRY_RD_ERR_LOG_EN_PATSPR;
 		d |=  RETRY_RD_ERR_LOG_EN;
 
 		if (offsets_demand2) {
 			d2 &= ~RETRY_RD_ERR_LOG_UC;
+			d2 &= ~RETRY_RD_ERR_LOG_EN_PATSPR;
 			d2 |=  RETRY_RD_ERR_LOG_NOOVER;
 			d2 |=  RETRY_RD_ERR_LOG_EN;
 		}
@@ -129,18 +133,24 @@ static void __enable_retry_rd_err_log(struct skx_imc *imc, int chan, bool enable
 			s |=  RETRY_RD_ERR_LOG_UC;
 		if (rrl_ctl[0] & RETRY_RD_ERR_LOG_NOOVER)
 			s |=  RETRY_RD_ERR_LOG_NOOVER;
+		if (!(rrl_ctl[0] & RETRY_RD_ERR_LOG_EN_PATSPR))
+			s &=  ~RETRY_RD_ERR_LOG_EN_PATSPR;
 		if (!(rrl_ctl[0] & RETRY_RD_ERR_LOG_EN))
 			s &= ~RETRY_RD_ERR_LOG_EN;
 		if (rrl_ctl[1] & RETRY_RD_ERR_LOG_UC)
 			d |=  RETRY_RD_ERR_LOG_UC;
 		if (rrl_ctl[1] & RETRY_RD_ERR_LOG_NOOVER)
 			d |=  RETRY_RD_ERR_LOG_NOOVER;
+		if (rrl_ctl[1] & RETRY_RD_ERR_LOG_EN_PATSPR)
+			d |=  RETRY_RD_ERR_LOG_EN_PATSPR;
 		if (!(rrl_ctl[1] & RETRY_RD_ERR_LOG_EN))
 			d &= ~RETRY_RD_ERR_LOG_EN;
 
 		if (offsets_demand2) {
 			if (rrl_ctl[2] & RETRY_RD_ERR_LOG_UC)
 				d2 |=  RETRY_RD_ERR_LOG_UC;
+			if (rrl_ctl[2] & RETRY_RD_ERR_LOG_EN_PATSPR)
+				d2 |=  RETRY_RD_ERR_LOG_EN_PATSPR;
 			if (!(rrl_ctl[2] & RETRY_RD_ERR_LOG_NOOVER))
 				d2 &=  ~RETRY_RD_ERR_LOG_NOOVER;
 			if (!(rrl_ctl[2] & RETRY_RD_ERR_LOG_EN))
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 4/7] EDAC/{skx_common,i10nm}: Structure the per-channel RRL registers
  2025-04-17 15:07 [PATCH 0/7] EDAC/i10nm: Add RRL support for Intel Granite Rapids server Qiuxu Zhuo
                   ` (2 preceding siblings ...)
  2025-04-17 15:07 ` [PATCH 3/7] EDAC/i10nm: Explicitly set the modes of the RRL register sets Qiuxu Zhuo
@ 2025-04-17 15:07 ` Qiuxu Zhuo
  2025-04-17 15:07 ` [PATCH 5/7] EDAC/{skx_common,i10nm}: Refactor enable_retry_rd_err_log() Qiuxu Zhuo
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Qiuxu Zhuo @ 2025-04-17 15:07 UTC (permalink / raw)
  To: Tony Luck
  Cc: Qiuxu Zhuo, Feng Xu, Borislav Petkov, James Morse,
	Mauro Carvalho Chehab, Robert Richter, Yi Lai, Shawn Fan,
	linux-edac, linux-kernel

As the number of RRL (retry_rd_err_log) registers per memory channel
increases, the positions of the RRL control bits and the widths of the
RRL registers vary across different CPU generations. Adding RRL support
for a new CPU requires handling these differences throughout the
RRL-related code.

Structure the offsets, widths, control bit positions, set numbers, modes,
etc., of the per-channel RRL registers and make them configurable to
facilitate easier RRL support for new CPUs.

No functional changes are intended.

Tested-by: Feng Xu <feng.f.xu@intel.com>
Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
---
 drivers/edac/i10nm_base.c | 92 ++++++++++++++++++++++++---------------
 drivers/edac/skx_common.h | 21 +++++----
 2 files changed, 69 insertions(+), 44 deletions(-)

diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c
index 50a16ce0aa22..b47da970510c 100644
--- a/drivers/edac/i10nm_base.c
+++ b/drivers/edac/i10nm_base.c
@@ -86,15 +86,38 @@ static int retry_rd_err_log;
 static int decoding_via_mca;
 static bool mem_cfg_2lm;
 
-static u32 offsets_scrub_icx[]  = {0x22c60, 0x22c54, 0x22c5c, 0x22c58, 0x22c28, 0x20ed8};
-static u32 offsets_scrub_spr[]  = {0x22c60, 0x22c54, 0x22f08, 0x22c58, 0x22c28, 0x20ed8};
-static u32 offsets_scrub_spr_hbm0[]  = {0x2860, 0x2854, 0x2b08, 0x2858, 0x2828, 0x0ed8};
-static u32 offsets_scrub_spr_hbm1[]  = {0x2c60, 0x2c54, 0x2f08, 0x2c58, 0x2c28, 0x0fa8};
-static u32 offsets_demand_icx[] = {0x22e54, 0x22e60, 0x22e64, 0x22e58, 0x22e5c, 0x20ee0};
-static u32 offsets_demand_spr[] = {0x22e54, 0x22e60, 0x22f10, 0x22e58, 0x22e5c, 0x20ee0};
-static u32 offsets_demand2_spr[] = {0x22c70, 0x22d80, 0x22f18, 0x22d58, 0x22c64, 0x20f10};
-static u32 offsets_demand_spr_hbm0[] = {0x2a54, 0x2a60, 0x2b10, 0x2a58, 0x2a5c, 0x0ee0};
-static u32 offsets_demand_spr_hbm1[] = {0x2e54, 0x2e60, 0x2f10, 0x2e58, 0x2e5c, 0x0fb0};
+static struct reg_rrl icx_reg_rrl_ddr = {
+	.set_num = 2,
+	.offsets = {
+		{0x22c60, 0x22c54, 0x22c5c, 0x22c58, 0x22c28, 0x20ed8},
+		{0x22e54, 0x22e60, 0x22e64, 0x22e58, 0x22e5c, 0x20ee0},
+	},
+};
+
+static struct reg_rrl spr_reg_rrl_ddr = {
+	.set_num = 3,
+	.offsets = {
+		{0x22c60, 0x22c54, 0x22f08, 0x22c58, 0x22c28, 0x20ed8},
+		{0x22e54, 0x22e60, 0x22f10, 0x22e58, 0x22e5c, 0x20ee0},
+		{0x22c70, 0x22d80, 0x22f18, 0x22d58, 0x22c64, 0x20f10},
+	},
+};
+
+static struct reg_rrl spr_reg_rrl_hbm_pch0 = {
+	.set_num = 2,
+	.offsets = {
+		{0x2860, 0x2854, 0x2b08, 0x2858, 0x2828, 0x0ed8},
+		{0x2a54, 0x2a60, 0x2b10, 0x2a58, 0x2a5c, 0x0ee0},
+	},
+};
+
+static struct reg_rrl spr_reg_rrl_hbm_pch1 = {
+	.set_num = 2,
+	.offsets = {
+		{0x2c60, 0x2c54, 0x2f08, 0x2c58, 0x2c28, 0x0fa8},
+		{0x2e54, 0x2e60, 0x2f10, 0x2e58, 0x2e5c, 0x0fb0},
+	},
+};
 
 static void __enable_retry_rd_err_log(struct skx_imc *imc, int chan, bool enable, u32 *rrl_ctl,
 				      u32 *offsets_scrub, u32 *offsets_demand,
@@ -185,9 +208,11 @@ static void enable_retry_rd_err_log(bool enable)
 			chan = d->imc[i].chan;
 			for (j = 0; j < chan_num; j++)
 				__enable_retry_rd_err_log(imc, j, enable, chan[j].rrl_ctl[0],
-							  res_cfg->offsets_scrub,
-							  res_cfg->offsets_demand,
-							  res_cfg->offsets_demand2);
+							  res_cfg->reg_rrl_ddr->offsets[0],
+							  res_cfg->reg_rrl_ddr->offsets[1],
+							  res_cfg->reg_rrl_ddr->set_num > 2 ?
+							  res_cfg->reg_rrl_ddr->offsets[2] : NULL);
+
 		}
 
 		imc_num += res_cfg->hbm_imc_num;
@@ -201,12 +226,12 @@ static void enable_retry_rd_err_log(bool enable)
 			chan = d->imc[i].chan;
 			for (j = 0; j < chan_num; j++) {
 				__enable_retry_rd_err_log(imc, j, enable, chan[j].rrl_ctl[0],
-							  res_cfg->offsets_scrub_hbm0,
-							  res_cfg->offsets_demand_hbm0,
+							  res_cfg->reg_rrl_hbm[0]->offsets[0],
+							  res_cfg->reg_rrl_hbm[0]->offsets[1],
 							  NULL);
 				__enable_retry_rd_err_log(imc, j, enable, chan[j].rrl_ctl[1],
-							  res_cfg->offsets_scrub_hbm1,
-							  res_cfg->offsets_demand_hbm1,
+							  res_cfg->reg_rrl_hbm[1]->offsets[0],
+							  res_cfg->reg_rrl_hbm[1]->offsets[1],
 							  NULL);
 			}
 		}
@@ -233,17 +258,18 @@ static void show_retry_rd_err_log(struct decoded_addr *res, char *msg,
 		pch = res->cs & 1;
 
 		if (pch)
-			offsets = scrub_err ? res_cfg->offsets_scrub_hbm1 :
-					      res_cfg->offsets_demand_hbm1;
+			offsets = scrub_err ? res_cfg->reg_rrl_hbm[1]->offsets[0] :
+					      res_cfg->reg_rrl_hbm[1]->offsets[1];
 		else
-			offsets = scrub_err ? res_cfg->offsets_scrub_hbm0 :
-					      res_cfg->offsets_demand_hbm0;
+			offsets = scrub_err ? res_cfg->reg_rrl_hbm[0]->offsets[0] :
+					      res_cfg->reg_rrl_hbm[0]->offsets[1];
 	} else {
 		if (scrub_err) {
-			offsets = res_cfg->offsets_scrub;
+			offsets = res_cfg->reg_rrl_ddr->offsets[0];
 		} else {
-			offsets = res_cfg->offsets_demand;
-			xffsets = res_cfg->offsets_demand2;
+			offsets = res_cfg->reg_rrl_ddr->offsets[1];
+			if (res_cfg->reg_rrl_ddr->set_num > 2)
+				xffsets = res_cfg->reg_rrl_ddr->offsets[2];
 		}
 	}
 
@@ -883,8 +909,7 @@ static struct res_config i10nm_cfg0 = {
 	.ddr_mdev_bdf		= {0, 12, 0},
 	.hbm_mdev_bdf		= {0, 12, 1},
 	.sad_all_offset		= 0x108,
-	.offsets_scrub		= offsets_scrub_icx,
-	.offsets_demand		= offsets_demand_icx,
+	.reg_rrl_ddr		= &icx_reg_rrl_ddr,
 };
 
 static struct res_config i10nm_cfg1 = {
@@ -902,8 +927,7 @@ static struct res_config i10nm_cfg1 = {
 	.ddr_mdev_bdf		= {0, 12, 0},
 	.hbm_mdev_bdf		= {0, 12, 1},
 	.sad_all_offset		= 0x108,
-	.offsets_scrub		= offsets_scrub_icx,
-	.offsets_demand		= offsets_demand_icx,
+	.reg_rrl_ddr		= &icx_reg_rrl_ddr,
 };
 
 static struct res_config spr_cfg = {
@@ -926,13 +950,9 @@ static struct res_config spr_cfg = {
 	.ddr_mdev_bdf		= {0, 12, 0},
 	.hbm_mdev_bdf		= {0, 12, 1},
 	.sad_all_offset		= 0x300,
-	.offsets_scrub		= offsets_scrub_spr,
-	.offsets_scrub_hbm0	= offsets_scrub_spr_hbm0,
-	.offsets_scrub_hbm1	= offsets_scrub_spr_hbm1,
-	.offsets_demand		= offsets_demand_spr,
-	.offsets_demand2	= offsets_demand2_spr,
-	.offsets_demand_hbm0	= offsets_demand_spr_hbm0,
-	.offsets_demand_hbm1	= offsets_demand_spr_hbm1,
+	.reg_rrl_ddr		= &spr_reg_rrl_ddr,
+	.reg_rrl_hbm[0]		= &spr_reg_rrl_hbm_pch0,
+	.reg_rrl_hbm[1]		= &spr_reg_rrl_hbm_pch1,
 };
 
 static struct res_config gnr_cfg = {
@@ -1121,7 +1141,7 @@ static int __init i10nm_init(void)
 	mce_register_decode_chain(&i10nm_mce_dec);
 	skx_setup_debug("i10nm_test");
 
-	if (retry_rd_err_log && res_cfg->offsets_scrub && res_cfg->offsets_demand) {
+	if (retry_rd_err_log && res_cfg->reg_rrl_ddr) {
 		skx_set_decode(i10nm_mc_decode, show_retry_rd_err_log);
 		if (retry_rd_err_log == 2)
 			enable_retry_rd_err_log(true);
@@ -1141,7 +1161,7 @@ static void __exit i10nm_exit(void)
 {
 	edac_dbg(2, "\n");
 
-	if (retry_rd_err_log && res_cfg->offsets_scrub && res_cfg->offsets_demand) {
+	if (retry_rd_err_log && res_cfg->reg_rrl_ddr) {
 		skx_set_decode(NULL, NULL);
 		if (retry_rd_err_log == 2)
 			enable_retry_rd_err_log(false);
diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h
index 5afd425f3b4f..5833fbe7c0fb 100644
--- a/drivers/edac/skx_common.h
+++ b/drivers/edac/skx_common.h
@@ -81,6 +81,15 @@
 
 /* Max RRL register sets per {,sub-,pseudo-}channel. */
 #define NUM_RRL_SET		3
+/* Max RRL registers per set. */
+#define NUM_RRL_REG		6
+
+/* RRL registers per {,sub-,pseudo-}channel. */
+struct reg_rrl {
+	/* RRL register parts. */
+	int set_num;
+	u32 offsets[NUM_RRL_SET][NUM_RRL_REG];
+};
 
 /*
  * Each cpu socket contains some pci devices that provide global
@@ -237,14 +246,10 @@ struct res_config {
 	/* HBM mdev device BDF */
 	struct pci_bdf hbm_mdev_bdf;
 	int sad_all_offset;
-	/* Offsets of retry_rd_err_log registers */
-	u32 *offsets_scrub;
-	u32 *offsets_scrub_hbm0;
-	u32 *offsets_scrub_hbm1;
-	u32 *offsets_demand;
-	u32 *offsets_demand2;
-	u32 *offsets_demand_hbm0;
-	u32 *offsets_demand_hbm1;
+	/* RRL register sets per DDR channel */
+	struct reg_rrl *reg_rrl_ddr;
+	/* RRL register sets per HBM channel */
+	struct reg_rrl *reg_rrl_hbm[2];
 };
 
 typedef int (*get_dimm_config_f)(struct mem_ctl_info *mci,
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 5/7] EDAC/{skx_common,i10nm}: Refactor enable_retry_rd_err_log()
  2025-04-17 15:07 [PATCH 0/7] EDAC/i10nm: Add RRL support for Intel Granite Rapids server Qiuxu Zhuo
                   ` (3 preceding siblings ...)
  2025-04-17 15:07 ` [PATCH 4/7] EDAC/{skx_common,i10nm}: Structure the per-channel RRL registers Qiuxu Zhuo
@ 2025-04-17 15:07 ` Qiuxu Zhuo
  2025-04-17 15:07 ` [PATCH 6/7] EDAC/{skx_common,i10nm}: Refactor show_retry_rd_err_log() Qiuxu Zhuo
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 13+ messages in thread
From: Qiuxu Zhuo @ 2025-04-17 15:07 UTC (permalink / raw)
  To: Tony Luck
  Cc: Qiuxu Zhuo, Feng Xu, Borislav Petkov, James Morse,
	Mauro Carvalho Chehab, Robert Richter, Yi Lai, Shawn Fan,
	linux-edac, linux-kernel

Refactor enable_retry_rd_err_log() using helper functions for both
DDR and HBM, making the RRL control bits configurable instead of
hard-coded. Additionally, explicitly define the four RRL modes for
better readability.

No functional changes intended.

Tested-by: Feng Xu <feng.f.xu@intel.com>
Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
---
 drivers/edac/i10nm_base.c | 233 ++++++++++++++++++++++----------------
 drivers/edac/skx_common.h |  20 ++++
 2 files changed, 154 insertions(+), 99 deletions(-)

diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c
index b47da970510c..2a03db86883c 100644
--- a/drivers/edac/i10nm_base.c
+++ b/drivers/edac/i10nm_base.c
@@ -72,11 +72,6 @@
 #define I10NM_SAD_ENABLE(reg)		GET_BITFIELD(reg, 0, 0)
 #define I10NM_SAD_NM_CACHEABLE(reg)	GET_BITFIELD(reg, 5, 5)
 
-#define RETRY_RD_ERR_LOG_UC		BIT(1)
-#define RETRY_RD_ERR_LOG_EN_PATSPR	BIT(13)
-#define RETRY_RD_ERR_LOG_NOOVER		BIT(14)
-#define RETRY_RD_ERR_LOG_EN		BIT(15)
-#define RETRY_RD_ERR_LOG_NOOVER_UC	(BIT(14) | BIT(1))
 #define RETRY_RD_ERR_LOG_OVER_UC_V	(BIT(2) | BIT(1) | BIT(0))
 
 static struct list_head *i10nm_edac_list;
@@ -88,153 +83,193 @@ static bool mem_cfg_2lm;
 
 static struct reg_rrl icx_reg_rrl_ddr = {
 	.set_num = 2,
+	.modes = {LRE_SCRUB, LRE_DEMAND},
 	.offsets = {
 		{0x22c60, 0x22c54, 0x22c5c, 0x22c58, 0x22c28, 0x20ed8},
 		{0x22e54, 0x22e60, 0x22e64, 0x22e58, 0x22e5c, 0x20ee0},
 	},
+	.widths		= {4, 4, 4, 4, 4, 8},
+	.uc_mask	= BIT(1),
+	.en_patspr_mask	= BIT(13),
+	.noover_mask	= BIT(14),
+	.en_mask	= BIT(15),
 };
 
 static struct reg_rrl spr_reg_rrl_ddr = {
 	.set_num = 3,
+	.modes = {LRE_SCRUB, LRE_DEMAND, FRE_DEMAND},
 	.offsets = {
 		{0x22c60, 0x22c54, 0x22f08, 0x22c58, 0x22c28, 0x20ed8},
 		{0x22e54, 0x22e60, 0x22f10, 0x22e58, 0x22e5c, 0x20ee0},
 		{0x22c70, 0x22d80, 0x22f18, 0x22d58, 0x22c64, 0x20f10},
 	},
+	.widths		= {4, 4, 8, 4, 4, 8},
+	.uc_mask	= BIT(1),
+	.en_patspr_mask	= BIT(13),
+	.noover_mask	= BIT(14),
+	.en_mask	= BIT(15),
 };
 
 static struct reg_rrl spr_reg_rrl_hbm_pch0 = {
 	.set_num = 2,
+	.modes = {LRE_SCRUB, LRE_DEMAND},
 	.offsets = {
 		{0x2860, 0x2854, 0x2b08, 0x2858, 0x2828, 0x0ed8},
 		{0x2a54, 0x2a60, 0x2b10, 0x2a58, 0x2a5c, 0x0ee0},
 	},
+	.widths		= {4, 4, 8, 4, 4, 8},
+	.uc_mask	= BIT(1),
+	.en_patspr_mask	= BIT(13),
+	.noover_mask	= BIT(14),
+	.en_mask	= BIT(15),
 };
 
 static struct reg_rrl spr_reg_rrl_hbm_pch1 = {
 	.set_num = 2,
+	.modes = {LRE_SCRUB, LRE_DEMAND},
 	.offsets = {
 		{0x2c60, 0x2c54, 0x2f08, 0x2c58, 0x2c28, 0x0fa8},
 		{0x2e54, 0x2e60, 0x2f10, 0x2e58, 0x2e5c, 0x0fb0},
 	},
+	.widths		= {4, 4, 8, 4, 4, 8},
+	.uc_mask	= BIT(1),
+	.en_patspr_mask	= BIT(13),
+	.noover_mask	= BIT(14),
+	.en_mask	= BIT(15),
 };
 
-static void __enable_retry_rd_err_log(struct skx_imc *imc, int chan, bool enable, u32 *rrl_ctl,
-				      u32 *offsets_scrub, u32 *offsets_demand,
-				      u32 *offsets_demand2)
+static u64 read_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width)
 {
-	u32 s, d, d2;
+	switch (width) {
+	case 4:
+		return I10NM_GET_REG32(imc, chan, offset);
+	case 8:
+		return I10NM_GET_REG64(imc, chan, offset);
+	default:
+		i10nm_printk(KERN_ERR, "Invalid readd RRL 0x%x width %d\n", offset, width);
+		return 0;
+	}
+}
 
-	s = I10NM_GET_REG32(imc, chan, offsets_scrub[0]);
-	d = I10NM_GET_REG32(imc, chan, offsets_demand[0]);
-	if (offsets_demand2)
-		d2 = I10NM_GET_REG32(imc, chan, offsets_demand2[0]);
+static void write_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width, u64 val)
+{
+	switch (width) {
+	case 4:
+		return I10NM_SET_REG32(imc, chan, offset, (u32)val);
+	default:
+		i10nm_printk(KERN_ERR, "Invalid write RRL 0x%x width %d\n", offset, width);
+	}
+}
+
+static void enable_rrl(struct skx_imc *imc, int chan, struct reg_rrl *rrl,
+		       int rrl_set, bool enable, u32 *rrl_ctl)
+{
+	enum rrl_mode mode = rrl->modes[rrl_set];
+	u32 offset = rrl->offsets[rrl_set][0], v;
+	u8 width = rrl->widths[0];
+	bool first, scrub;
+
+	/* First or last read error. */
+	first = (mode == FRE_SCRUB || mode == FRE_DEMAND);
+	/* Patrol scrub or on-demand read error. */
+	scrub = (mode == FRE_SCRUB || mode == LRE_SCRUB);
+
+	v = read_imc_reg(imc, chan, offset, width);
 
 	if (enable) {
-		/* Save default configurations */
-		rrl_ctl[0] = s;
-		rrl_ctl[1] = d;
-		if (offsets_demand2)
-			rrl_ctl[2] = d2;
+		/* Save default configurations. */
+		*rrl_ctl = v;
+		v &= ~rrl->uc_mask;
 
-		s &= ~RETRY_RD_ERR_LOG_NOOVER_UC;
-		s |=  RETRY_RD_ERR_LOG_EN_PATSPR;
-		s |=  RETRY_RD_ERR_LOG_EN;
-		d &= ~RETRY_RD_ERR_LOG_NOOVER_UC;
-		d &= ~RETRY_RD_ERR_LOG_EN_PATSPR;
-		d |=  RETRY_RD_ERR_LOG_EN;
+		if (first)
+			v |= rrl->noover_mask;
+		else
+			v &= ~rrl->noover_mask;
 
-		if (offsets_demand2) {
-			d2 &= ~RETRY_RD_ERR_LOG_UC;
-			d2 &= ~RETRY_RD_ERR_LOG_EN_PATSPR;
-			d2 |=  RETRY_RD_ERR_LOG_NOOVER;
-			d2 |=  RETRY_RD_ERR_LOG_EN;
-		}
+		if (scrub)
+			v |= rrl->en_patspr_mask;
+		else
+			v &= ~rrl->en_patspr_mask;
+
+		v |= rrl->en_mask;
 	} else {
-		/* Restore default configurations */
-		if (rrl_ctl[0] & RETRY_RD_ERR_LOG_UC)
-			s |=  RETRY_RD_ERR_LOG_UC;
-		if (rrl_ctl[0] & RETRY_RD_ERR_LOG_NOOVER)
-			s |=  RETRY_RD_ERR_LOG_NOOVER;
-		if (!(rrl_ctl[0] & RETRY_RD_ERR_LOG_EN_PATSPR))
-			s &=  ~RETRY_RD_ERR_LOG_EN_PATSPR;
-		if (!(rrl_ctl[0] & RETRY_RD_ERR_LOG_EN))
-			s &= ~RETRY_RD_ERR_LOG_EN;
-		if (rrl_ctl[1] & RETRY_RD_ERR_LOG_UC)
-			d |=  RETRY_RD_ERR_LOG_UC;
-		if (rrl_ctl[1] & RETRY_RD_ERR_LOG_NOOVER)
-			d |=  RETRY_RD_ERR_LOG_NOOVER;
-		if (rrl_ctl[1] & RETRY_RD_ERR_LOG_EN_PATSPR)
-			d |=  RETRY_RD_ERR_LOG_EN_PATSPR;
-		if (!(rrl_ctl[1] & RETRY_RD_ERR_LOG_EN))
-			d &= ~RETRY_RD_ERR_LOG_EN;
-
-		if (offsets_demand2) {
-			if (rrl_ctl[2] & RETRY_RD_ERR_LOG_UC)
-				d2 |=  RETRY_RD_ERR_LOG_UC;
-			if (rrl_ctl[2] & RETRY_RD_ERR_LOG_EN_PATSPR)
-				d2 |=  RETRY_RD_ERR_LOG_EN_PATSPR;
-			if (!(rrl_ctl[2] & RETRY_RD_ERR_LOG_NOOVER))
-				d2 &=  ~RETRY_RD_ERR_LOG_NOOVER;
-			if (!(rrl_ctl[2] & RETRY_RD_ERR_LOG_EN))
-				d2 &= ~RETRY_RD_ERR_LOG_EN;
+		/* Restore default configurations. */
+		if (*rrl_ctl & rrl->uc_mask)
+			v |= rrl->uc_mask;
+
+		if (first) {
+			if (!(*rrl_ctl & rrl->noover_mask))
+				v &= ~rrl->noover_mask;
+		} else {
+			if (*rrl_ctl & rrl->noover_mask)
+				v |= rrl->noover_mask;
+		}
+
+		if (scrub) {
+			if (!(*rrl_ctl & rrl->en_patspr_mask))
+				v &= ~rrl->en_patspr_mask;
+		} else {
+			if (*rrl_ctl & rrl->en_patspr_mask)
+				v |= rrl->en_patspr_mask;
 		}
+
+		if (!(*rrl_ctl & rrl->en_mask))
+			v &= ~rrl->en_mask;
 	}
 
-	I10NM_SET_REG32(imc, chan, offsets_scrub[0], s);
-	I10NM_SET_REG32(imc, chan, offsets_demand[0], d);
-	if (offsets_demand2)
-		I10NM_SET_REG32(imc, chan, offsets_demand2[0], d2);
+	write_imc_reg(imc, chan, offset, width, v);
+}
+
+static void enable_rrls(struct skx_imc *imc, int chan, struct reg_rrl *rrl,
+			bool enable, u32 *rrl_ctl)
+{
+	for (int i = 0; i < rrl->set_num; i++)
+		enable_rrl(imc, chan, rrl, i, enable, rrl_ctl + i);
+}
+
+static void enable_rrls_ddr(struct skx_imc *imc, bool enable)
+{
+	struct reg_rrl *rrl_ddr = res_cfg->reg_rrl_ddr;
+	int i, chan_num = res_cfg->ddr_chan_num;
+	struct skx_channel *chan = imc->chan;
+
+	if (!imc->mbase)
+		return;
+
+	for (i = 0; i < chan_num; i++)
+		enable_rrls(imc, i, rrl_ddr, enable, chan[i].rrl_ctl[0]);
+}
+
+static void enable_rrls_hbm(struct skx_imc *imc, bool enable)
+{
+	struct reg_rrl **rrl_hbm = res_cfg->reg_rrl_hbm;
+	int i, chan_num = res_cfg->hbm_chan_num;
+	struct skx_channel *chan = imc->chan;
+
+	if (!imc->mbase || !imc->hbm_mc || !rrl_hbm[0] || !rrl_hbm[1])
+		return;
+
+	for (i = 0; i < chan_num; i++) {
+		enable_rrls(imc, i, rrl_hbm[0], enable, chan[i].rrl_ctl[0]);
+		enable_rrls(imc, i, rrl_hbm[1], enable, chan[i].rrl_ctl[1]);
+	}
 }
 
 static void enable_retry_rd_err_log(bool enable)
 {
-	int i, j, imc_num, chan_num;
-	struct skx_channel *chan;
-	struct skx_imc *imc;
 	struct skx_dev *d;
+	int i, imc_num;
 
 	edac_dbg(2, "\n");
 
 	list_for_each_entry(d, i10nm_edac_list, list) {
 		imc_num  = res_cfg->ddr_imc_num;
-		chan_num = res_cfg->ddr_chan_num;
-
-		for (i = 0; i < imc_num; i++) {
-			imc = &d->imc[i];
-			if (!imc->mbase)
-				continue;
-
-			chan = d->imc[i].chan;
-			for (j = 0; j < chan_num; j++)
-				__enable_retry_rd_err_log(imc, j, enable, chan[j].rrl_ctl[0],
-							  res_cfg->reg_rrl_ddr->offsets[0],
-							  res_cfg->reg_rrl_ddr->offsets[1],
-							  res_cfg->reg_rrl_ddr->set_num > 2 ?
-							  res_cfg->reg_rrl_ddr->offsets[2] : NULL);
-
-		}
+		for (i = 0; i < imc_num; i++)
+			enable_rrls_ddr(&d->imc[i], enable);
 
 		imc_num += res_cfg->hbm_imc_num;
-		chan_num = res_cfg->hbm_chan_num;
-
-		for (; i < imc_num; i++) {
-			imc = &d->imc[i];
-			if (!imc->mbase || !imc->hbm_mc)
-				continue;
-
-			chan = d->imc[i].chan;
-			for (j = 0; j < chan_num; j++) {
-				__enable_retry_rd_err_log(imc, j, enable, chan[j].rrl_ctl[0],
-							  res_cfg->reg_rrl_hbm[0]->offsets[0],
-							  res_cfg->reg_rrl_hbm[0]->offsets[1],
-							  NULL);
-				__enable_retry_rd_err_log(imc, j, enable, chan[j].rrl_ctl[1],
-							  res_cfg->reg_rrl_hbm[1]->offsets[0],
-							  res_cfg->reg_rrl_hbm[1]->offsets[1],
-							  NULL);
-			}
-		}
+		for (; i < imc_num; i++)
+			enable_rrls_hbm(&d->imc[i], enable);
 	}
 }
 
diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h
index 5833fbe7c0fb..cf3d0aac035a 100644
--- a/drivers/edac/skx_common.h
+++ b/drivers/edac/skx_common.h
@@ -84,11 +84,31 @@
 /* Max RRL registers per set. */
 #define NUM_RRL_REG		6
 
+/* Modes of RRL register set. */
+enum rrl_mode {
+	/* Last read error from patrol scrub. */
+	LRE_SCRUB,
+	/* Last read error from demand. */
+	LRE_DEMAND,
+	/* First read error from patrol scrub. */
+	FRE_SCRUB,
+	/* First read error from demand. */
+	FRE_DEMAND,
+};
+
 /* RRL registers per {,sub-,pseudo-}channel. */
 struct reg_rrl {
 	/* RRL register parts. */
 	int set_num;
+	enum rrl_mode modes[NUM_RRL_SET];
 	u32 offsets[NUM_RRL_SET][NUM_RRL_REG];
+	/* RRL register widths in byte per set. */
+	u8 widths[NUM_RRL_REG];
+	/* RRL control bits of the first register per set. */
+	u32 uc_mask;
+	u32 en_patspr_mask;
+	u32 noover_mask;
+	u32 en_mask;
 };
 
 /*
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 6/7] EDAC/{skx_common,i10nm}: Refactor show_retry_rd_err_log()
  2025-04-17 15:07 [PATCH 0/7] EDAC/i10nm: Add RRL support for Intel Granite Rapids server Qiuxu Zhuo
                   ` (4 preceding siblings ...)
  2025-04-17 15:07 ` [PATCH 5/7] EDAC/{skx_common,i10nm}: Refactor enable_retry_rd_err_log() Qiuxu Zhuo
@ 2025-04-17 15:07 ` Qiuxu Zhuo
  2025-04-17 17:44   ` Luck, Tony
  2025-04-17 15:07 ` [PATCH 7/7] EDAC/{skx_common,i10nm}: Add RRL support for Intel Granite Rapids server Qiuxu Zhuo
  2025-04-18 17:24 ` [PATCH 0/7] EDAC/i10nm: " Luck, Tony
  7 siblings, 1 reply; 13+ messages in thread
From: Qiuxu Zhuo @ 2025-04-17 15:07 UTC (permalink / raw)
  To: Tony Luck
  Cc: Qiuxu Zhuo, Feng Xu, Borislav Petkov, James Morse,
	Mauro Carvalho Chehab, Robert Richter, Yi Lai, Shawn Fan,
	linux-edac, linux-kernel

Make the {valid bit, overwritten status, number} of RRL registers and the
{number, offsets, widths} of per-channel CORRERRCNT registers configurable.
Refactor show_retry_rd_err_log() to use the configurable fields of struct
reg_rrl, making the code more scalable and simpler.

No functional changes intended.

Tested-by: Feng Xu <feng.f.xu@intel.com>
Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
---
 drivers/edac/i10nm_base.c | 158 +++++++++++++++++---------------------
 drivers/edac/skx_common.h |  11 ++-
 2 files changed, 79 insertions(+), 90 deletions(-)

diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c
index 2a03db86883c..aefc448283d3 100644
--- a/drivers/edac/i10nm_base.c
+++ b/drivers/edac/i10nm_base.c
@@ -72,8 +72,6 @@
 #define I10NM_SAD_ENABLE(reg)		GET_BITFIELD(reg, 0, 0)
 #define I10NM_SAD_NM_CACHEABLE(reg)	GET_BITFIELD(reg, 5, 5)
 
-#define RETRY_RD_ERR_LOG_OVER_UC_V	(BIT(2) | BIT(1) | BIT(0))
-
 static struct list_head *i10nm_edac_list;
 
 static struct res_config *res_cfg;
@@ -83,20 +81,28 @@ static bool mem_cfg_2lm;
 
 static struct reg_rrl icx_reg_rrl_ddr = {
 	.set_num = 2,
+	.reg_num = 6,
 	.modes = {LRE_SCRUB, LRE_DEMAND},
 	.offsets = {
 		{0x22c60, 0x22c54, 0x22c5c, 0x22c58, 0x22c28, 0x20ed8},
 		{0x22e54, 0x22e60, 0x22e64, 0x22e58, 0x22e5c, 0x20ee0},
 	},
 	.widths		= {4, 4, 4, 4, 4, 8},
+	.v_mask		= BIT(0),
 	.uc_mask	= BIT(1),
+	.over_mask	= BIT(2),
 	.en_patspr_mask	= BIT(13),
 	.noover_mask	= BIT(14),
 	.en_mask	= BIT(15),
+
+	.cecnt_num	= 4,
+	.cecnt_offsets	= {0x22c18, 0x22c1c, 0x22c20, 0x22c24},
+	.cecnt_widths	= {4, 4, 4, 4},
 };
 
 static struct reg_rrl spr_reg_rrl_ddr = {
 	.set_num = 3,
+	.reg_num = 6,
 	.modes = {LRE_SCRUB, LRE_DEMAND, FRE_DEMAND},
 	.offsets = {
 		{0x22c60, 0x22c54, 0x22f08, 0x22c58, 0x22c28, 0x20ed8},
@@ -104,38 +110,58 @@ static struct reg_rrl spr_reg_rrl_ddr = {
 		{0x22c70, 0x22d80, 0x22f18, 0x22d58, 0x22c64, 0x20f10},
 	},
 	.widths		= {4, 4, 8, 4, 4, 8},
+	.v_mask		= BIT(0),
 	.uc_mask	= BIT(1),
+	.over_mask	= BIT(2),
 	.en_patspr_mask	= BIT(13),
 	.noover_mask	= BIT(14),
 	.en_mask	= BIT(15),
+
+	.cecnt_num	= 4,
+	.cecnt_offsets	= {0x22c18, 0x22c1c, 0x22c20, 0x22c24},
+	.cecnt_widths	= {4, 4, 4, 4},
 };
 
 static struct reg_rrl spr_reg_rrl_hbm_pch0 = {
 	.set_num = 2,
+	.reg_num = 6,
 	.modes = {LRE_SCRUB, LRE_DEMAND},
 	.offsets = {
 		{0x2860, 0x2854, 0x2b08, 0x2858, 0x2828, 0x0ed8},
 		{0x2a54, 0x2a60, 0x2b10, 0x2a58, 0x2a5c, 0x0ee0},
 	},
 	.widths		= {4, 4, 8, 4, 4, 8},
+	.v_mask		= BIT(0),
 	.uc_mask	= BIT(1),
+	.over_mask	= BIT(2),
 	.en_patspr_mask	= BIT(13),
 	.noover_mask	= BIT(14),
 	.en_mask	= BIT(15),
+
+	.cecnt_num	= 4,
+	.cecnt_offsets	= {0x2818, 0x281c, 0x2820, 0x2824},
+	.cecnt_widths	= {4, 4, 4, 4},
 };
 
 static struct reg_rrl spr_reg_rrl_hbm_pch1 = {
 	.set_num = 2,
+	.reg_num = 6,
 	.modes = {LRE_SCRUB, LRE_DEMAND},
 	.offsets = {
 		{0x2c60, 0x2c54, 0x2f08, 0x2c58, 0x2c28, 0x0fa8},
 		{0x2e54, 0x2e60, 0x2f10, 0x2e58, 0x2e5c, 0x0fb0},
 	},
 	.widths		= {4, 4, 8, 4, 4, 8},
+	.v_mask		= BIT(0),
 	.uc_mask	= BIT(1),
+	.over_mask	= BIT(2),
 	.en_patspr_mask	= BIT(13),
 	.noover_mask	= BIT(14),
 	.en_mask	= BIT(15),
+
+	.cecnt_num	= 4,
+	.cecnt_offsets	= {0x2c18, 0x2c1c, 0x2c20, 0x2c24},
+	.cecnt_widths	= {4, 4, 4, 4},
 };
 
 static u64 read_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width)
@@ -276,110 +302,64 @@ static void enable_retry_rd_err_log(bool enable)
 static void show_retry_rd_err_log(struct decoded_addr *res, char *msg,
 				  int len, bool scrub_err)
 {
+	int i, j, n, ch = res->channel, pch = res->cs & 1;
 	struct skx_imc *imc = &res->dev->imc[res->imc];
-	u32 log0, log1, log2, log3, log4;
-	u32 corr0, corr1, corr2, corr3;
-	u32 lxg0, lxg1, lxg3, lxg4;
-	u32 *xffsets = NULL;
-	u64 log2a, log5;
-	u64 lxg2a, lxg5;
-	u32 *offsets;
-	int n, pch;
+	u32 offset, status_mask;
+	struct reg_rrl *rrl;
+	u64 log, corr;
+	bool scrub;
+	u8 width;
 
 	if (!imc->mbase)
 		return;
 
-	if (imc->hbm_mc) {
-		pch = res->cs & 1;
+	rrl = imc->hbm_mc ? res_cfg->reg_rrl_hbm[pch] : res_cfg->reg_rrl_ddr;
 
-		if (pch)
-			offsets = scrub_err ? res_cfg->reg_rrl_hbm[1]->offsets[0] :
-					      res_cfg->reg_rrl_hbm[1]->offsets[1];
-		else
-			offsets = scrub_err ? res_cfg->reg_rrl_hbm[0]->offsets[0] :
-					      res_cfg->reg_rrl_hbm[0]->offsets[1];
-	} else {
-		if (scrub_err) {
-			offsets = res_cfg->reg_rrl_ddr->offsets[0];
-		} else {
-			offsets = res_cfg->reg_rrl_ddr->offsets[1];
-			if (res_cfg->reg_rrl_ddr->set_num > 2)
-				xffsets = res_cfg->reg_rrl_ddr->offsets[2];
-		}
-	}
+	if (!rrl)
+		return;
 
-	log0 = I10NM_GET_REG32(imc, res->channel, offsets[0]);
-	log1 = I10NM_GET_REG32(imc, res->channel, offsets[1]);
-	log3 = I10NM_GET_REG32(imc, res->channel, offsets[3]);
-	log4 = I10NM_GET_REG32(imc, res->channel, offsets[4]);
-	log5 = I10NM_GET_REG64(imc, res->channel, offsets[5]);
+	status_mask = rrl->over_mask | rrl->uc_mask | rrl->v_mask;
 
-	if (xffsets) {
-		lxg0 = I10NM_GET_REG32(imc, res->channel, xffsets[0]);
-		lxg1 = I10NM_GET_REG32(imc, res->channel, xffsets[1]);
-		lxg3 = I10NM_GET_REG32(imc, res->channel, xffsets[3]);
-		lxg4 = I10NM_GET_REG32(imc, res->channel, xffsets[4]);
-		lxg5 = I10NM_GET_REG64(imc, res->channel, xffsets[5]);
-	}
+	n = snprintf(msg, len, " retry_rd_err_log[");
+	for (i = 0; i < rrl->set_num; i++) {
+		scrub = (rrl->modes[i] == FRE_SCRUB || rrl->modes[i] == LRE_SCRUB);
+		if (scrub_err != scrub)
+			continue;
 
-	if (res_cfg->type == SPR) {
-		log2a = I10NM_GET_REG64(imc, res->channel, offsets[2]);
-		n = snprintf(msg, len, " retry_rd_err_log[%.8x %.8x %.16llx %.8x %.8x %.16llx",
-			     log0, log1, log2a, log3, log4, log5);
+		for (j = 0; j < rrl->reg_num && len - n > 0; j++) {
+			offset = rrl->offsets[i][j];
+			width = rrl->widths[j];
+			log = read_imc_reg(imc, ch, offset, width);
 
-		if (len - n > 0) {
-			if (xffsets) {
-				lxg2a = I10NM_GET_REG64(imc, res->channel, xffsets[2]);
-				n += snprintf(msg + n, len - n, " %.8x %.8x %.16llx %.8x %.8x %.16llx]",
-					     lxg0, lxg1, lxg2a, lxg3, lxg4, lxg5);
-			} else {
-				n += snprintf(msg + n, len - n, "]");
-			}
-		}
-	} else {
-		log2 = I10NM_GET_REG32(imc, res->channel, offsets[2]);
-		n = snprintf(msg, len, " retry_rd_err_log[%.8x %.8x %.8x %.8x %.8x %.16llx]",
-			     log0, log1, log2, log3, log4, log5);
-	}
+			if (width == 4)
+				n += snprintf(msg + n, len - n, "%.8llx ", log);
+			else
+				n += snprintf(msg + n, len - n, "%.16llx ", log);
 
-	if (imc->hbm_mc) {
-		if (pch) {
-			corr0 = I10NM_GET_REG32(imc, res->channel, 0x2c18);
-			corr1 = I10NM_GET_REG32(imc, res->channel, 0x2c1c);
-			corr2 = I10NM_GET_REG32(imc, res->channel, 0x2c20);
-			corr3 = I10NM_GET_REG32(imc, res->channel, 0x2c24);
-		} else {
-			corr0 = I10NM_GET_REG32(imc, res->channel, 0x2818);
-			corr1 = I10NM_GET_REG32(imc, res->channel, 0x281c);
-			corr2 = I10NM_GET_REG32(imc, res->channel, 0x2820);
-			corr3 = I10NM_GET_REG32(imc, res->channel, 0x2824);
+			/* Clear RRL status if RRL in Linux control mode. */
+			if (retry_rd_err_log == 2 && !j && (log & status_mask))
+				write_imc_reg(imc, ch, offset, width, log & ~status_mask);
 		}
-	} else {
-		corr0 = I10NM_GET_REG32(imc, res->channel, 0x22c18);
-		corr1 = I10NM_GET_REG32(imc, res->channel, 0x22c1c);
-		corr2 = I10NM_GET_REG32(imc, res->channel, 0x22c20);
-		corr3 = I10NM_GET_REG32(imc, res->channel, 0x22c24);
 	}
 
-	if (len - n > 0)
-		snprintf(msg + n, len - n,
-			 " correrrcnt[%.4x %.4x %.4x %.4x %.4x %.4x %.4x %.4x]",
-			 corr0 & 0xffff, corr0 >> 16,
-			 corr1 & 0xffff, corr1 >> 16,
-			 corr2 & 0xffff, corr2 >> 16,
-			 corr3 & 0xffff, corr3 >> 16);
+	/* Move back one space. */
+	n--;
+	n += snprintf(msg + n, len - n, "]");
 
-	/* Clear status bits */
-	if (retry_rd_err_log == 2) {
-		if (log0 & RETRY_RD_ERR_LOG_OVER_UC_V) {
-			log0 &= ~RETRY_RD_ERR_LOG_OVER_UC_V;
-			I10NM_SET_REG32(imc, res->channel, offsets[0], log0);
-		}
+	if (len - n > 0) {
+		n += snprintf(msg + n, len - n, " correrrcnt[");
+		for (i = 0; i < rrl->cecnt_num && len - n > 0; i++) {
+			offset = rrl->cecnt_offsets[i];
+			width = rrl->cecnt_widths[i];
+			corr = read_imc_reg(imc, ch, offset, width);
 
-		if (xffsets && (lxg0 & RETRY_RD_ERR_LOG_OVER_UC_V)) {
-			lxg0 &= ~RETRY_RD_ERR_LOG_OVER_UC_V;
-			I10NM_SET_REG32(imc, res->channel, xffsets[0], lxg0);
+			n += snprintf(msg + n, len - n, "%.4llx %.4llx ",
+				      corr & 0xffff, corr >> 16);
 		}
+
+		/* Move back one space. */
+		n--;
+		n += snprintf(msg + n, len - n, "]");
 	}
 }
 
diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h
index cf3d0aac035a..8f0f4af2cb27 100644
--- a/drivers/edac/skx_common.h
+++ b/drivers/edac/skx_common.h
@@ -83,6 +83,8 @@
 #define NUM_RRL_SET		3
 /* Max RRL registers per set. */
 #define NUM_RRL_REG		6
+/* Max correctable error count registers. */
+#define NUM_CECNT_REG		4
 
 /* Modes of RRL register set. */
 enum rrl_mode {
@@ -99,16 +101,23 @@ enum rrl_mode {
 /* RRL registers per {,sub-,pseudo-}channel. */
 struct reg_rrl {
 	/* RRL register parts. */
-	int set_num;
+	int set_num, reg_num;
 	enum rrl_mode modes[NUM_RRL_SET];
 	u32 offsets[NUM_RRL_SET][NUM_RRL_REG];
 	/* RRL register widths in byte per set. */
 	u8 widths[NUM_RRL_REG];
 	/* RRL control bits of the first register per set. */
+	u32 v_mask;
 	u32 uc_mask;
+	u32 over_mask;
 	u32 en_patspr_mask;
 	u32 noover_mask;
 	u32 en_mask;
+
+	/* CORRERRCNT register parts. */
+	int cecnt_num;
+	u32 cecnt_offsets[NUM_CECNT_REG];
+	u8 cecnt_widths[NUM_CECNT_REG];
 };
 
 /*
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH 7/7] EDAC/{skx_common,i10nm}: Add RRL support for Intel Granite Rapids server
  2025-04-17 15:07 [PATCH 0/7] EDAC/i10nm: Add RRL support for Intel Granite Rapids server Qiuxu Zhuo
                   ` (5 preceding siblings ...)
  2025-04-17 15:07 ` [PATCH 6/7] EDAC/{skx_common,i10nm}: Refactor show_retry_rd_err_log() Qiuxu Zhuo
@ 2025-04-17 15:07 ` Qiuxu Zhuo
  2025-04-18 17:24 ` [PATCH 0/7] EDAC/i10nm: " Luck, Tony
  7 siblings, 0 replies; 13+ messages in thread
From: Qiuxu Zhuo @ 2025-04-17 15:07 UTC (permalink / raw)
  To: Tony Luck
  Cc: Qiuxu Zhuo, Feng Xu, Borislav Petkov, James Morse,
	Mauro Carvalho Chehab, Robert Richter, Yi Lai, Shawn Fan,
	linux-edac, linux-kernel

Compared to previous generations, Granite Rapids defines the RRL control
bits {en_patspr, noover, en} in different positions, adds an extra RRL set
for the new mode of the first patrol-scrub read error, and extends the
number of CORRERRCNT registers from 4 to 8, encoding one counter per
CORRERRCNT register.

Add a Granite Rapids reg_rrl configuration table and adjust the code to
accommodate the differences mentioned above for RRL support.

Tested-by: Feng Xu <feng.f.xu@intel.com>
Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
---
 drivers/edac/i10nm_base.c | 37 +++++++++++++++++++++++++++++++++++--
 drivers/edac/skx_common.h |  4 ++--
 2 files changed, 37 insertions(+), 4 deletions(-)

diff --git a/drivers/edac/i10nm_base.c b/drivers/edac/i10nm_base.c
index aefc448283d3..8863f1fb4caf 100644
--- a/drivers/edac/i10nm_base.c
+++ b/drivers/edac/i10nm_base.c
@@ -164,6 +164,29 @@ static struct reg_rrl spr_reg_rrl_hbm_pch1 = {
 	.cecnt_widths	= {4, 4, 4, 4},
 };
 
+static struct reg_rrl gnr_reg_rrl_ddr = {
+	.set_num = 4,
+	.reg_num = 6,
+	.modes = {FRE_SCRUB, FRE_DEMAND, LRE_SCRUB, LRE_DEMAND},
+	.offsets = {
+		{0x2f10, 0x2f20, 0x2f30, 0x2f50, 0x2f60, 0xba0},
+		{0x2f14, 0x2f24, 0x2f38, 0x2f54, 0x2f64, 0xba8},
+		{0x2f18, 0x2f28, 0x2f40, 0x2f58, 0x2f68, 0xbb0},
+		{0x2f1c, 0x2f2c, 0x2f48, 0x2f5c, 0x2f6c, 0xbb8},
+	},
+	.widths		= {4, 4, 8, 4, 4, 8},
+	.v_mask		= BIT(0),
+	.uc_mask	= BIT(1),
+	.over_mask	= BIT(2),
+	.en_patspr_mask	= BIT(14),
+	.noover_mask	= BIT(15),
+	.en_mask	= BIT(12),
+
+	.cecnt_num	= 8,
+	.cecnt_offsets	= {0x2c10, 0x2c14, 0x2c18, 0x2c1c, 0x2c20, 0x2c24, 0x2c28, 0x2c2c},
+	.cecnt_widths	= {4, 4, 4, 4, 4, 4, 4, 4},
+};
+
 static u64 read_imc_reg(struct skx_imc *imc, int chan, u32 offset, u8 width)
 {
 	switch (width) {
@@ -353,8 +376,17 @@ static void show_retry_rd_err_log(struct decoded_addr *res, char *msg,
 			width = rrl->cecnt_widths[i];
 			corr = read_imc_reg(imc, ch, offset, width);
 
-			n += snprintf(msg + n, len - n, "%.4llx %.4llx ",
-				      corr & 0xffff, corr >> 16);
+			/* CPUs {ICX,SPR} encode two counters per 4-byte CORRERRCNT register. */
+			if (res_cfg->type <= SPR) {
+				n += snprintf(msg + n, len - n, "%.4llx %.4llx ",
+					      corr & 0xffff, corr >> 16);
+			} else {
+			/* CPUs {GNR} encode one counter per CORRERRCNT register. */
+				if (width == 4)
+					n += snprintf(msg + n, len - n, "%.8llx ", corr);
+				else
+					n += snprintf(msg + n, len - n, "%.16llx ", corr);
+			}
 		}
 
 		/* Move back one space. */
@@ -985,6 +1017,7 @@ static struct res_config gnr_cfg = {
 	.uracu_bdf		= {0, 0, 1},
 	.ddr_mdev_bdf		= {0, 5, 1},
 	.sad_all_offset		= 0x300,
+	.reg_rrl_ddr		= &gnr_reg_rrl_ddr,
 };
 
 static const struct x86_cpu_id i10nm_cpuids[] = {
diff --git a/drivers/edac/skx_common.h b/drivers/edac/skx_common.h
index 8f0f4af2cb27..ec4966f7ea40 100644
--- a/drivers/edac/skx_common.h
+++ b/drivers/edac/skx_common.h
@@ -80,11 +80,11 @@
 #define MCACOD_EXT_MEM_ERR	0x280
 
 /* Max RRL register sets per {,sub-,pseudo-}channel. */
-#define NUM_RRL_SET		3
+#define NUM_RRL_SET		4
 /* Max RRL registers per set. */
 #define NUM_RRL_REG		6
 /* Max correctable error count registers. */
-#define NUM_CECNT_REG		4
+#define NUM_CECNT_REG		8
 
 /* Modes of RRL register set. */
 enum rrl_mode {
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH 6/7] EDAC/{skx_common,i10nm}: Refactor show_retry_rd_err_log()
  2025-04-17 15:07 ` [PATCH 6/7] EDAC/{skx_common,i10nm}: Refactor show_retry_rd_err_log() Qiuxu Zhuo
@ 2025-04-17 17:44   ` Luck, Tony
  2025-04-18  2:13     ` Zhuo, Qiuxu
  0 siblings, 1 reply; 13+ messages in thread
From: Luck, Tony @ 2025-04-17 17:44 UTC (permalink / raw)
  To: Qiuxu Zhuo
  Cc: Feng Xu, Borislav Petkov, James Morse, Mauro Carvalho Chehab,
	Robert Richter, Yi Lai, Shawn Fan, linux-edac, linux-kernel

On Thu, Apr 17, 2025 at 11:07:23PM +0800, Qiuxu Zhuo wrote:
> +	/* CORRERRCNT register parts. */
> +	int cecnt_num;
> +	u32 cecnt_offsets[NUM_CECNT_REG];
> +	u8 cecnt_widths[NUM_CECNT_REG];

YOu have added this "cecnt_widths" field and code to print in different
formats fo value == 4 ("%.8llx") and not 4 ("%.16llx"). But no CPU
(including Granite Rapids added by next patch) has any values other
than "4".

Is there a mistake in the struct reg_rrl defintions where you intended
to have some "8" values somewhere?

Or is this just for symmetry with the ".widths" you have for the
RRL register (which do have varying widths).

-Tony

^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [PATCH 6/7] EDAC/{skx_common,i10nm}: Refactor show_retry_rd_err_log()
  2025-04-17 17:44   ` Luck, Tony
@ 2025-04-18  2:13     ` Zhuo, Qiuxu
  2025-04-18 15:25       ` Luck, Tony
  0 siblings, 1 reply; 13+ messages in thread
From: Zhuo, Qiuxu @ 2025-04-18  2:13 UTC (permalink / raw)
  To: Luck, Tony
  Cc: Xu, Feng F, Borislav Petkov, James Morse, Mauro Carvalho Chehab,
	Robert Richter, Lai, Yi1, Fan, Shawn, linux-edac@vger.kernel.org,
	linux-kernel@vger.kernel.org

Hi Tony,

> From: Luck, Tony <tony.luck@intel.com>
> [...]
> On Thu, Apr 17, 2025 at 11:07:23PM +0800, Qiuxu Zhuo wrote:
> > +	/* CORRERRCNT register parts. */
> > +	int cecnt_num;
> > +	u32 cecnt_offsets[NUM_CECNT_REG];
> > +	u8 cecnt_widths[NUM_CECNT_REG];
> 
> YOu have added this "cecnt_widths" field and code to print in different
> formats fo value == 4 ("%.8llx") and not 4 ("%.16llx"). But no CPU (including
> Granite Rapids added by next patch) has any values other than "4".
> 
> Is there a mistake in the struct reg_rrl defintions where you intended to
> have some "8" values somewhere?

No, there isn't a mistake 😊.

Currently, all CPUs EDAC supported by {skx,i10nm}_edac indeed just have the 
value "4" for "cecnt_widths". 

> Or is this just for symmetry with the ".widths" you have for the RRL register
> (which do have varying widths).

The upcoming CPU Diamond Rapids [1] will have the value "8" for "cecnt_widths".
This is why I made the "cecnt_widths" field here, intended to easily cover this new 
CPU EDAC support in the future. 

Do you suggest not using the "cecnt_widths" field for now (since it currently only has 
the value 4 and the code appears somewhat redundant) until we add the EDAC support 
for Diamond Rapids in the future? Or we can keep the "cecnt_widths" field?  
Either option is OK to me 😊.
 
[1] https://github.com/torvalds/linux/blob/master/arch/x86/include/asm/intel-family.h#L200

Thanks!
-Qiuxu

^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [PATCH 6/7] EDAC/{skx_common,i10nm}: Refactor show_retry_rd_err_log()
  2025-04-18  2:13     ` Zhuo, Qiuxu
@ 2025-04-18 15:25       ` Luck, Tony
  2025-04-19  2:32         ` Zhuo, Qiuxu
  0 siblings, 1 reply; 13+ messages in thread
From: Luck, Tony @ 2025-04-18 15:25 UTC (permalink / raw)
  To: Zhuo, Qiuxu
  Cc: Xu, Feng F, Borislav Petkov, James Morse, Mauro Carvalho Chehab,
	Robert Richter, Lai, Yi1, Fan, Shawn, linux-edac@vger.kernel.org,
	linux-kernel@vger.kernel.org

> > Is there a mistake in the struct reg_rrl defintions where you intended to
> > have some "8" values somewhere?
>
> No, there isn't a mistake 😊.
>
> Currently, all CPUs EDAC supported by {skx,i10nm}_edac indeed just have the
> value "4" for "cecnt_widths".
>
> > Or is this just for symmetry with the ".widths" you have for the RRL register
> > (which do have varying widths).
>
> The upcoming CPU Diamond Rapids [1] will have the value "8" for "cecnt_widths".
> This is why I made the "cecnt_widths" field here, intended to easily cover this new
> CPU EDAC support in the future.
>
> Do you suggest not using the "cecnt_widths" field for now (since it currently only has
> the value 4 and the code appears somewhat redundant) until we add the EDAC support
> for Diamond Rapids in the future? Or we can keep the "cecnt_widths" field?

The general process is to avoid adding code/infrastructure for future use (as sometimes
that future never comes). But I have high hopes that Diamond Rapids will appear on
time. So I'll leave the cecnt_widths code in place. It's not much code.

> Either option is OK to me 😊.
>
> [1] https://github.com/torvalds/linux/blob/master/arch/x86/include/asm/intel-family.h#L200

-Tony

^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [PATCH 0/7] EDAC/i10nm: Add RRL support for Intel Granite Rapids server
  2025-04-17 15:07 [PATCH 0/7] EDAC/i10nm: Add RRL support for Intel Granite Rapids server Qiuxu Zhuo
                   ` (6 preceding siblings ...)
  2025-04-17 15:07 ` [PATCH 7/7] EDAC/{skx_common,i10nm}: Add RRL support for Intel Granite Rapids server Qiuxu Zhuo
@ 2025-04-18 17:24 ` Luck, Tony
  7 siblings, 0 replies; 13+ messages in thread
From: Luck, Tony @ 2025-04-18 17:24 UTC (permalink / raw)
  To: Zhuo, Qiuxu
  Cc: Borislav Petkov, James Morse, Mauro Carvalho Chehab,
	Robert Richter, Lai, Yi1, Xu, Feng F, Fan, Shawn,
	linux-edac@vger.kernel.org, linux-kernel@vger.kernel.org

> The RRL (Retry Read error Log) registers provide additional error information
> during DDR memory correction. This can assist memory DIMM vendors in isolating
> problematic cells within the DIMM and help CSPs predict uncorrectable errors.
> This patch series is to add RRL support for Intel Granite Rapids servers and
> is structured as follows:
>
> Patch 1-3: Bug fixes and cleanup.
>
> Patch 4-6: Refactor the RRL (Retry Read error Log) code of previous generations
>            and prepare for Patch 7.
>
> Patch 7  : Add RRL support for Intel Granite Rapids server.

Applied to edac-drivers branch of RAS tree for next merge window.

Thanks

-Tony

^ permalink raw reply	[flat|nested] 13+ messages in thread

* RE: [PATCH 6/7] EDAC/{skx_common,i10nm}: Refactor show_retry_rd_err_log()
  2025-04-18 15:25       ` Luck, Tony
@ 2025-04-19  2:32         ` Zhuo, Qiuxu
  0 siblings, 0 replies; 13+ messages in thread
From: Zhuo, Qiuxu @ 2025-04-19  2:32 UTC (permalink / raw)
  To: Luck, Tony
  Cc: Xu, Feng F, Borislav Petkov, James Morse, Mauro Carvalho Chehab,
	Robert Richter, Lai, Yi1, Fan, Shawn, linux-edac@vger.kernel.org,
	linux-kernel@vger.kernel.org

> From: Luck, Tony <tony.luck@intel.com>
> [...]
> > Do you suggest not using the "cecnt_widths" field for now (since it
> > currently only has the value 4 and the code appears somewhat
> > redundant) until we add the EDAC support for Diamond Rapids in the
> future? Or we can keep the "cecnt_widths" field?
> 
> The general process is to avoid adding code/infrastructure for future use (as
> sometimes that future never comes). But I have high hopes that Diamond
> Rapids will appear on time. So I'll leave the cecnt_widths code in place. It's
> not much code.
> 

OK, got it. Thanks for reminding me of the process.

-Qiuxu

^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2025-04-19  2:32 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-04-17 15:07 [PATCH 0/7] EDAC/i10nm: Add RRL support for Intel Granite Rapids server Qiuxu Zhuo
2025-04-17 15:07 ` [PATCH 1/7] EDAC/skx_common: Fix general protection fault Qiuxu Zhuo
2025-04-17 15:07 ` [PATCH 2/7] EDAC/{skx_common,i10nm}: Fix the loss of saved RRL for HBM pseudo channel 0 Qiuxu Zhuo
2025-04-17 15:07 ` [PATCH 3/7] EDAC/i10nm: Explicitly set the modes of the RRL register sets Qiuxu Zhuo
2025-04-17 15:07 ` [PATCH 4/7] EDAC/{skx_common,i10nm}: Structure the per-channel RRL registers Qiuxu Zhuo
2025-04-17 15:07 ` [PATCH 5/7] EDAC/{skx_common,i10nm}: Refactor enable_retry_rd_err_log() Qiuxu Zhuo
2025-04-17 15:07 ` [PATCH 6/7] EDAC/{skx_common,i10nm}: Refactor show_retry_rd_err_log() Qiuxu Zhuo
2025-04-17 17:44   ` Luck, Tony
2025-04-18  2:13     ` Zhuo, Qiuxu
2025-04-18 15:25       ` Luck, Tony
2025-04-19  2:32         ` Zhuo, Qiuxu
2025-04-17 15:07 ` [PATCH 7/7] EDAC/{skx_common,i10nm}: Add RRL support for Intel Granite Rapids server Qiuxu Zhuo
2025-04-18 17:24 ` [PATCH 0/7] EDAC/i10nm: " Luck, Tony

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox