EDAC, amd64: Fix channel decode on Fam15hMod60h systems
authorYazen Ghannam <Yazen.Ghannam@amd.com>
Wed, 3 Aug 2016 14:59:15 +0000 (10:59 -0400)
committerBorislav Petkov <bp@suse.de>
Mon, 8 Aug 2016 03:59:42 +0000 (05:59 +0200)
Fam15hMod60h systems are using the channel decode of Fam15hMod30h which
gives incorrect results. Fam15hMod60h systems should use the generic
channel decode method plus a couple more cases.

Signed-off-by: Yazen Ghannam <Yazen.Ghannam@amd.com>
Cc: Aravind Gopalakrishnan <aravindksg.lkml@gmail.com>
Cc: linux-edac <linux-edac@vger.kernel.org>
Link: http://lkml.kernel.org/r/1470236355-30039-1-git-send-email-Yazen.Ghannam@amd.com
Signed-off-by: Borislav Petkov <bp@suse.de>
drivers/edac/amd64_edac.c

index 8c0ec2128907cc6a7cf63a9f6668c86a0cbc8888..da43404dbd0c2f38d1d6fa794d631ba71ad97e44 100644 (file)
@@ -1425,11 +1425,17 @@ static u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
 
                if (intlv_addr & 0x2) {
                        u8 shift = intlv_addr & 0x1 ? 9 : 6;
-                       u32 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) % 2;
+                       u32 temp = hweight_long((u32) ((sys_addr >> 16) & 0x1F)) & 1;
 
                        return ((sys_addr >> shift) & 1) ^ temp;
                }
 
+               if (intlv_addr & 0x4) {
+                       u8 shift = intlv_addr & 0x1 ? 9 : 8;
+
+                       return (sys_addr >> shift) & 1;
+               }
+
                return (sys_addr >> (12 + hweight8(intlv_en))) & 1;
        }
 
@@ -1726,8 +1732,11 @@ static int f15_m30h_match_to_this_node(struct amd64_pvt *pvt, unsigned range,
        if (!(num_dcts_intlv % 2 == 0) || (num_dcts_intlv > 4))
                return -EINVAL;
 
-       channel = f15_m30h_determine_channel(pvt, sys_addr, intlv_en,
-                                            num_dcts_intlv, dct_sel);
+       if (pvt->model >= 0x60)
+               channel = f1x_determine_channel(pvt, sys_addr, false, intlv_en);
+       else
+               channel = f15_m30h_determine_channel(pvt, sys_addr, intlv_en,
+                                                    num_dcts_intlv, dct_sel);
 
        /* Verify we stay within the MAX number of channels allowed */
        if (channel > 3)