Skip to contentSkip to conversation

amd64_edac: fix size decoding error on K8

PATCH In review Niklas Söderlund 4 participants 9 messages Nov 9, 2011 – Nov 15, 2011

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 amd64_edac: fix size decoding error on K8

Use a lookup table to calculate the size of a chip select. The old method of calculating size return erroneous values for some memory configurations. The lookup table is transcribed from "DRAM CS Address Mapping Register" [1], pages 88-89.

[1] BIOS and Kernel Developer's Guide for the AMD Athlon 64 and AMD

    Opteron Processors - Revision 3.30 - doc #26094 - February 2006
    http://support.amd.com/us/Processor_TechDocs/26094.pdf
---
 drivers/edac/amd64_edac.c |   10 +++++-----
 1 files changed, 5 insertions(+), 5 deletions(-)
drivers/edac/amd64_edac.c +5 -5
index 9a8bebc..396ea76 100644
@@ -1108,6 +1108,10 @@ static int ddr2_cs_size(unsigned i, bool dct_width)
 static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
 				  unsigned cs_mode)
 {
+	static const int rev_de_lookup[] = { 32, 64, 128, 128, 256, 512, 256,
+		512, 1024, 1024, 2048 };
+
+
 	u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
 
 	if (pvt->ext_model >= K8_REV_F) {
@@ -1116,11 +1120,7 @@ static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
 	}
 	else if (pvt->ext_model >= K8_REV_D) {
 		WARN_ON(cs_mode > 10);
-
-		if (cs_mode == 3 || cs_mode == 8)
-			return 32 << (cs_mode - 1);
-		else
-			return 32 << cs_mode;
+		return rev_de_lookup[cs_mode];
 	}
 	else {
 		WARN_ON(cs_mode > 6);
Signature · 1 line
1.7.7.1
#1 lore raw
Quoted 3 lines · Niklas Söderlund

Use a lookup table to calculate the size of a chip select. The old method of calculating size return erroneous values for some memory configurations.

Can you elaborate more on those erroneous values, please?

Thanks.

Signature · 8 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
#2 lore raw
Quoted 9 lines · Borislav Petkov
Quoted 3 lines · Niklas Söderlund

Use a lookup table to calculate the size of a chip select. The old method of calculating size return erroneous values for some memory configurations.

Can you elaborate more on those erroneous values, please?

Thanks.

The decoding table from the documentation:

cs_mode size (mb)
0 32
1 64
2 128
3 128
4 256
5 512
6 256
7 512
8 1024
9 1024
10 2048

The original code:

if (cs_mode == 3 || cs_mode == 8)

	return 32 << (cs_mode - 1);
else
	return 32 << cs_mode;

The code tries to compensate for the irregularity in the decoding table but fails for cs_mode greater or equal to 4. It fails because:

- It do not consider the cumulating effect of reoccurring sizes for all values of cs_mode. It only tries for the special cases and it only succeeds in one.

- It do not consider the out of order values of cs_mode values 4-7: 256, 512, 256, 512.

Best Regards
// Niklas

#3 lore raw

Hi Niklas,

Quoted 25 lines · Niklas Söderlund

The decoding table from the documentation:

cs_mode size (mb)
0 32
1 64
2 128
3 128
4 256
5 512
6 256
7 512
8 1024
9 1024
10 2048

The original code:

if (cs_mode == 3 || cs_mode == 8)

	return 32 << (cs_mode - 1);
else
	return 32 << cs_mode;

The code tries to compensate for the irregularity in the decoding table but fails for cs_mode greater or equal to 4. It fails because:

Quoted 6 lines

- It do not consider the cumulating effect of reoccurring sizes for all values of cs_mode. It only tries for the special cases and it only succeeds in one.

- It do not consider the out of order values of cs_mode values 4-7:
256, 512, 256, 512.

Agreed, thanks for reporting this. However, I removed the static tables at the time because I didn't want to carry unnecessary weight around for no reason (tables were static back then). And I know, they're small but dead weight like that tends to accumulate.

Your approach is ok with creating the lookup table on the stack but how about the following instead - it is much smaller and it is only code, no need for stack memory at all. It should give you the proper mapping, IINM.

--

drivers/edac/amd64_edac.c +4 -4
index c9eee6d33e9a..3702f20d784e 100644
@@ -1132,12 +1132,12 @@ static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
 		return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
 	}
 	else if (pvt->ext_model >= K8_REV_D) {
+		unsigned diff;
 		WARN_ON(cs_mode > 10);
 
-		if (cs_mode == 3 || cs_mode == 8)
-			return 32 << (cs_mode - 1);
-		else
-			return 32 << cs_mode;
+		diff = cs_mode / 3 + (unsigned)(cs_mode > 5);
+
+		return 32 << (cs_mode - diff);
 	}
 	else {
 		WARN_ON(cs_mode > 6);

--

Thanks.

Signature · 8 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
#4 lore raw
Quoted 3 lines · Borislav Petkov

+               diff = cs_mode / 3 + (unsigned)(cs_mode > 5); +
+               return 32 << (cs_mode - diff);

Code is correct - but looks like an entry for an obfuscated C competition. Perhaps
it deserves a comment!

-Tony

#5 lore raw
Quoted 7 lines · Tony Luck
Quoted 3 lines · Borislav Petkov

+               diff = cs_mode / 3 + (unsigned)(cs_mode > 5); +
+               return 32 << (cs_mode - diff);

Code is correct - but looks like an entry for an obfuscated C competition.

I know, right?! Especially casting the boolean to an unsigned int. Yuck! But it is compact the stupid thing.

Quoted 1 line

Perhaps it deserves a comment!

Sure it does, will do.

Thanks.

Signature · 8 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
#6 lore raw

PATCH 1/1 amd64_edac: Fix K8 revD and later chip select sizes

Fix DRAM chip select sizes calculation for K8, revisions D and E.

---

@Niklas: would you please verify this patch fixes your issue?

Thanks.

 drivers/edac/amd64_edac.c |   32 ++++++++++++++++++++++++++++----
 1 files changed, 28 insertions(+), 4 deletions(-)
drivers/edac/amd64_edac.c +28 -4
index c9eee6d..6a83d49 100644
@@ -1132,12 +1132,36 @@ static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
 		return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
 	}
 	else if (pvt->ext_model >= K8_REV_D) {
+		unsigned diff;
 		WARN_ON(cs_mode > 10);
 
-		if (cs_mode == 3 || cs_mode == 8)
-			return 32 << (cs_mode - 1);
-		else
-			return 32 << cs_mode;
+		/*
+		 * the below calculation, besides trying to win an obfuscated C
+		 * contest, maps cs_mode values to DIMM chip select sizes. The
+		 * mappings are:
+		 *
+		 * cs_mode	CS size (mb)
+		 * =======	============
+		 * 0		32
+		 * 1		64
+		 * 2		128
+		 * 3		128
+		 * 4		256
+		 * 5		512
+		 * 6		256
+		 * 7		512
+		 * 8		1024
+		 * 9		1024
+		 * 10		2048
+		 *
+		 * Basically, it calculates a value with which to shift the
+		 * smallest CS size of 32MB.
+		 *
+		 * ddr[23]_cs_size have a similar purpose.
+		 */
+		diff = cs_mode/3 + (unsigned)(cs_mode > 5);
+
+		return 32 << (cs_mode - diff);
 	}
 	else {
 		WARN_ON(cs_mode > 6);
Signature · 11 lines
1.7.8.rc0

-- 
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
#7 lore raw

Re: [PATCH] amd64_edac: Fix K8 revD and later chip select sizes

Quoted 50 lines · Borislav Petkov

Fix DRAM chip select sizes calculation for K8, revisions D and E.

---

@Niklas: would you please verify this patch fixes your issue?

Thanks.

  drivers/edac/amd64_edac.c |   32 ++++++++++++++++++++++++++++----
  1 files changed, 28 insertions(+), 4 deletions(-)
drivers/edac/amd64_edac.c +21 -4
index c9eee6d..6a83d49 100644
@@ -1132,12 +1132,36 @@ static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
  		return ddr2_cs_size(cs_mode, dclr&  WIDTH_128);
  	}
  	else if (pvt->ext_model>= K8_REV_D) {
+		unsigned diff;
  		WARN_ON(cs_mode>  10);
 
-		if (cs_mode == 3 || cs_mode == 8)
-			return 32<<  (cs_mode - 1);
-		else
-			return 32<<  cs_mode;
+		/*
+		 * the below calculation, besides trying to win an obfuscated C
+		 * contest, maps cs_mode values to DIMM chip select sizes. The
+		 * mappings are:
+		 *
+		 * cs_mode	CS size (mb)
+		 * =======	============
+		 * 0		32
+		 * 1		64
+		 * 2		128
+		 * 3		128
+		 * 4		256
+		 * 5		512
+		 * 6		256
+		 * 7		512
+		 * 8		1024
+		 * 9		1024
+		 * 10		2048
+		 *
+		 * Basically, it calculates a value with which to shift the

drivers/edac/amd64_edac.c static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, · line 1167

Quoted 10 lines
drivers/edac/amd64_edac.c +7 -0
+		 * smallest CS size of 32MB.
+		 *
+		 * ddr[23]_cs_size have a similar purpose.
+		 */
+		diff = cs_mode/3 + (unsigned)(cs_mode>  5);
+
+		return 32<<  (cs_mode - diff);
  	}
  	else {
  		WARN_ON(cs_mode>  6);

Hi Borislav,

Yes the patch fixes my problem, but it truly is obfuscated C.

Thanks
// Niklas

#8 lore raw
In reply to Borislav Petkov

Hi Borislav,

Quoted 16 lines · Borislav Petkov

Hi Niklas,

Quoted 7 lines · Niklas Söderlund

The decoding table from the documentation:

<snip>

- It do not consider the out of order values of cs_mode values 4-7:
256, 512, 256, 512.

Agreed, thanks for reporting this. However, I removed the static tables at the time because I didn't want to carry unnecessary weight around for no reason (tables were static back then). And I know, they're small but dead weight like that tends to accumulate.

Quoted 5 lines

Your approach is ok with creating the lookup table on the stack but how about the following instead - it is much smaller and it is only code, no need for stack memory at all. It should give you the proper mapping, IINM.

I have to say that I much prefer Niklas approach, the code below is difficult to understand compared to the table, and seeing as the data sheet contains the table it's much easier for a reader to understand the correspondance.

Cheers,
Nils Carlson

Quoted 39 lines

--

drivers/edac/amd64_edac.c +4 -5
index c9eee6d33e9a..3702f20d784e 100644
@@ -1132,12 +1132,12 @@ static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
 		return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
 	}
 	else if (pvt->ext_model >= K8_REV_D) {
+		unsigned diff;
 		WARN_ON(cs_mode > 10);
 
-		if (cs_mode == 3 || cs_mode == 8)
-			return 32 << (cs_mode - 1);
-		else
-			return 32 << cs_mode;
+		diff = cs_mode / 3 + (unsigned)(cs_mode > 5);
+
+		return 32 << (cs_mode - diff);
 	}
 	else {
 		WARN_ON(cs_mode > 6);
--

Thanks.

Signature · 12 lines
Regards/Gruss,
Boris.

Advanced Micro Devices GmbH
Einsteinring 24, 85609 Dornach
GM: Alberto Bozzo
Reg: Dornach, Landkreis Muenchen
HRB Nr. 43632 WEEE Registernr: 129 19551
--
To unsubscribe from this list: send the line "unsubscribe linux-edac" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html