amd64_edac: fix size decoding error on K8
Subsystems (2)
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
@@ -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
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
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
Hi Niklas,
Quoted 25 lines · Niklas Söderlund
The decoding table from the documentation:
cs_modesize (mb)
0 32
1 64
2 128
3 128
4 256
5 512
6 256
7 512
8 1024
9 1024
10 2048The 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_modegreater 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_modevalues 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
@@ -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
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
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
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
@@ -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
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.
Reported-by Niklas Söderlund<[email protected]Signed-off-by Borislav Petkov<[email protected]>---
@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@@ -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
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_modevalues 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@@ -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