OSDN Git Service

amd64_edac: Simplify scrubrate setting
[android-x86/kernel.git] / drivers / edac / amd64_edac.c
index 1ec0145..0caf05e 100644 (file)
@@ -25,59 +25,12 @@ static struct mem_ctl_info **mcis;
 static struct ecc_settings **ecc_stngs;
 
 /*
- * Address to DRAM bank mapping: see F2x80 for K8 and F2x[1,0]80 for Fam10 and
- * later.
- */
-static int ddr2_dbam_revCG[] = {
-                          [0]          = 32,
-                          [1]          = 64,
-                          [2]          = 128,
-                          [3]          = 256,
-                          [4]          = 512,
-                          [5]          = 1024,
-                          [6]          = 2048,
-};
-
-static int ddr2_dbam_revD[] = {
-                          [0]          = 32,
-                          [1]          = 64,
-                          [2 ... 3]    = 128,
-                          [4]          = 256,
-                          [5]          = 512,
-                          [6]          = 256,
-                          [7]          = 512,
-                          [8 ... 9]    = 1024,
-                          [10]         = 2048,
-};
-
-static int ddr2_dbam[] = { [0]         = 128,
-                          [1]          = 256,
-                          [2 ... 4]    = 512,
-                          [5 ... 6]    = 1024,
-                          [7 ... 8]    = 2048,
-                          [9 ... 10]   = 4096,
-                          [11]         = 8192,
-};
-
-static int ddr3_dbam[] = { [0]         = -1,
-                          [1]          = 256,
-                          [2]          = 512,
-                          [3 ... 4]    = -1,
-                          [5 ... 6]    = 1024,
-                          [7 ... 8]    = 2048,
-                          [9 ... 10]   = 4096,
-                          [11]         = 8192,
-};
-
-/*
  * Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing
  * bandwidth to a valid bit pattern. The 'set' operation finds the 'matching-
  * or higher value'.
  *
  *FIXME: Produce a better mapping/linearisation.
  */
-
-
 struct scrubrate {
        u32 scrubval;           /* bit pattern for scrub rate */
        u32 bandwidth;          /* bandwidth consumed (bytes/sec) */
@@ -240,8 +193,12 @@ static int __amd64_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate)
 static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bw)
 {
        struct amd64_pvt *pvt = mci->pvt_info;
+       u32 min_scrubrate = 0x5;
+
+       if (boot_cpu_data.x86 == 0xf)
+               min_scrubrate = 0x0;
 
-       return __amd64_set_scrub_rate(pvt->F3, bw, pvt->min_scrubrate);
+       return __amd64_set_scrub_rate(pvt->F3, bw, min_scrubrate);
 }
 
 static int amd64_get_scrub_rate(struct mem_ctl_info *mci)
@@ -393,6 +350,9 @@ static void get_cs_base_and_mask(struct amd64_pvt *pvt, int csrow, u8 dct,
 #define for_each_chip_select(i, dct, pvt) \
        for (i = 0; i < pvt->csels[dct].b_cnt; i++)
 
+#define chip_select_base(i, dct, pvt) \
+       pvt->csels[dct].csbases[i]
+
 #define for_each_chip_select_mask(i, dct, pvt) \
        for (i = 0; i < pvt->csels[dct].m_cnt; i++)
 
@@ -788,11 +748,6 @@ static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr)
 
 static int get_channel_from_ecc_syndrome(struct mem_ctl_info *, u16);
 
-static u16 extract_syndrome(struct err_regs *err)
-{
-       return ((err->nbsh >> 15) & 0xff) | ((err->nbsl >> 16) & 0xff00);
-}
-
 /*
  * Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs
  * are ECC capable.
@@ -964,7 +919,7 @@ static int k8_early_channel_count(struct amd64_pvt *pvt)
 
        if (pvt->ext_model >= K8_REV_F)
                /* RevF (NPT) and later */
-               flag = pvt->dclr0 & F10_WIDTH_128;
+               flag = pvt->dclr0 & WIDTH_128;
        else
                /* RevE and earlier */
                flag = pvt->dclr0 & REVE_WIDTH_128;
@@ -975,12 +930,18 @@ static int k8_early_channel_count(struct amd64_pvt *pvt)
        return (flag) ? 2 : 1;
 }
 
-/* Extract the ERROR ADDRESS for the K8 CPUs */
-static u64 k8_get_error_address(struct mem_ctl_info *mci,
-                               struct err_regs *info)
+/* On F10h and later ErrAddr is MC4_ADDR[47:1] */
+static u64 get_error_address(struct mce *m)
 {
-       return (((u64) (info->nbeah & 0xff)) << 32) +
-                       (info->nbeal & ~0x03);
+       u8 start_bit = 1;
+       u8 end_bit   = 47;
+
+       if (boot_cpu_data.x86 == 0xf) {
+               start_bit = 3;
+               end_bit   = 39;
+       }
+
+       return m->addr & GENMASK(start_bit, end_bit);
 }
 
 static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
@@ -1000,18 +961,16 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
        amd64_read_pci_cfg(pvt->F1, DRAM_LIMIT_HI + off, &pvt->ranges[range].lim.hi);
 }
 
-static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
-                                   struct err_regs *err_info, u64 sys_addr)
+static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
+                                   u16 syndrome)
 {
        struct mem_ctl_info *src_mci;
+       struct amd64_pvt *pvt = mci->pvt_info;
        int channel, csrow;
        u32 page, offset;
-       u16 syndrome;
-
-       syndrome = extract_syndrome(err_info);
 
        /* CHIPKILL enabled */
-       if (err_info->nbcfg & NBCFG_CHIPKILL) {
+       if (pvt->nbcfg & NBCFG_CHIPKILL) {
                channel = get_channel_from_ecc_syndrome(mci, syndrome);
                if (channel < 0) {
                        /*
@@ -1060,18 +1019,41 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
        }
 }
 
-static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, int cs_mode)
+static int ddr2_cs_size(unsigned i, bool dct_width)
 {
-       int *dbam_map;
+       unsigned shift = 0;
 
-       if (pvt->ext_model >= K8_REV_F)
-               dbam_map = ddr2_dbam;
-       else if (pvt->ext_model >= K8_REV_D)
-               dbam_map = ddr2_dbam_revD;
+       if (i <= 2)
+               shift = i;
+       else if (!(i & 0x1))
+               shift = i >> 1;
        else
-               dbam_map = ddr2_dbam_revCG;
+               shift = (i + 1) >> 1;
 
-       return dbam_map[cs_mode];
+       return 128 << (shift + !!dct_width);
+}
+
+static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
+                                 unsigned cs_mode)
+{
+       u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
+
+       if (pvt->ext_model >= K8_REV_F) {
+               WARN_ON(cs_mode > 11);
+               return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
+       }
+       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;
+       }
+       else {
+               WARN_ON(cs_mode > 6);
+               return 32 << cs_mode;
+       }
 }
 
 /*
@@ -1087,7 +1069,7 @@ static int f1x_early_channel_count(struct amd64_pvt *pvt)
        int i, j, channels = 0;
 
        /* On F10h, if we are in 128 bit mode, then we are using 2 channels */
-       if (boot_cpu_data.x86 == 0x10 && (pvt->dclr0 & F10_WIDTH_128))
+       if (boot_cpu_data.x86 == 0x10 && (pvt->dclr0 & WIDTH_128))
                return 2;
 
        /*
@@ -1124,35 +1106,64 @@ static int f1x_early_channel_count(struct amd64_pvt *pvt)
        return channels;
 }
 
-static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, int cs_mode)
+static int ddr3_cs_size(unsigned i, bool dct_width)
 {
-       int *dbam_map;
+       unsigned shift = 0;
+       int cs_size = 0;
 
-       if (pvt->dchr0 & DDR3_MODE || pvt->dchr1 & DDR3_MODE)
-               dbam_map = ddr3_dbam;
+       if (i == 0 || i == 3 || i == 4)
+               cs_size = -1;
+       else if (i <= 2)
+               shift = i;
+       else if (i == 12)
+               shift = 7;
+       else if (!(i & 0x1))
+               shift = i >> 1;
        else
-               dbam_map = ddr2_dbam;
+               shift = (i + 1) >> 1;
+
+       if (cs_size != -1)
+               cs_size = (128 * (1 << !!dct_width)) << shift;
+
+       return cs_size;
+}
+
+static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
+                                  unsigned cs_mode)
+{
+       u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
 
-       return dbam_map[cs_mode];
+       WARN_ON(cs_mode > 11);
+
+       if (pvt->dchr0 & DDR3_MODE || pvt->dchr1 & DDR3_MODE)
+               return ddr3_cs_size(cs_mode, dclr & WIDTH_128);
+       else
+               return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
 }
 
-static u64 f10_get_error_address(struct mem_ctl_info *mci,
-                       struct err_regs *info)
+/*
+ * F15h supports only 64bit DCT interfaces
+ */
+static int f15_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
+                                  unsigned cs_mode)
 {
-       return (((u64) (info->nbeah & 0xffff)) << 32) +
-                       (info->nbeal & ~0x01);
+       WARN_ON(cs_mode > 12);
+
+       return ddr3_cs_size(cs_mode, false);
 }
 
-static void f10_read_dram_ctl_register(struct amd64_pvt *pvt)
+static void read_dram_ctl_register(struct amd64_pvt *pvt)
 {
 
+       if (boot_cpu_data.x86 == 0xf)
+               return;
+
        if (!amd64_read_dct_pci_cfg(pvt, DCT_SEL_LO, &pvt->dct_sel_lo)) {
                debugf0("F2x110 (DCTSelLow): 0x%08x, High range addrs at: 0x%x\n",
                        pvt->dct_sel_lo, dct_sel_baseaddr(pvt));
 
-               debugf0("  mode: %s, All DCTs on: %s\n",
-                       (dct_ganging_enabled(pvt) ? "ganged" : "unganged"),
-                       (dct_dram_enabled(pvt) ? "yes"   : "no"));
+               debugf0("  DCTs operate in %s mode.\n",
+                       (dct_ganging_enabled(pvt) ? "ganged" : "unganged"));
 
                if (!dct_ganging_enabled(pvt))
                        debugf0("  Address range split per DCT: %s\n",
@@ -1176,7 +1187,7 @@ static void f10_read_dram_ctl_register(struct amd64_pvt *pvt)
  * Determine channel (DCT) based on the interleaving mode: F10h BKDG, 2.8.9 Memory
  * Interleaving Modes.
  */
-static u8 f10_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
+static u8 f1x_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
                                bool hi_range_sel, u8 intlv_en)
 {
        u32 dct_sel_high = (pvt->dct_sel_lo >> 1) & 1;
@@ -1214,7 +1225,7 @@ static u8 f10_determine_channel(struct amd64_pvt *pvt, u64 sys_addr,
 }
 
 /* Convert the sys_addr to the normalized DCT address */
-static u64 f10_get_norm_dct_addr(struct amd64_pvt *pvt, int range,
+static u64 f1x_get_norm_dct_addr(struct amd64_pvt *pvt, int range,
                                 u64 sys_addr, bool hi_rng,
                                 u32 dct_sel_base_addr)
 {
@@ -1262,30 +1273,23 @@ static u64 f10_get_norm_dct_addr(struct amd64_pvt *pvt, int range,
        return (sys_addr & GENMASK(6,47)) - (chan_off & GENMASK(23,47));
 }
 
-/* Hack for the time being - Can we get this from BIOS?? */
-#define        CH0SPARE_RANK   0
-#define        CH1SPARE_RANK   1
-
 /*
  * checks if the csrow passed in is marked as SPARED, if so returns the new
  * spare row
  */
 static int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow)
 {
-       u32 swap_done;
-       u32 bad_dram_cs;
+       int tmp_cs;
 
-       /* Depending on channel, isolate respective SPARING info */
-       if (dct) {
-               swap_done = F10_ONLINE_SPARE_SWAPDONE1(pvt->online_spare);
-               bad_dram_cs = F10_ONLINE_SPARE_BADDRAM_CS1(pvt->online_spare);
-               if (swap_done && (csrow == bad_dram_cs))
-                       csrow = CH1SPARE_RANK;
-       } else {
-               swap_done = F10_ONLINE_SPARE_SWAPDONE0(pvt->online_spare);
-               bad_dram_cs = F10_ONLINE_SPARE_BADDRAM_CS0(pvt->online_spare);
-               if (swap_done && (csrow == bad_dram_cs))
-                       csrow = CH0SPARE_RANK;
+       if (online_spare_swap_done(pvt, dct) &&
+           csrow == online_spare_bad_dramcs(pvt, dct)) {
+
+               for_each_chip_select(tmp_cs, dct, pvt) {
+                       if (chip_select_base(tmp_cs, dct, pvt) & 0x2) {
+                               csrow = tmp_cs;
+                               break;
+                       }
+               }
        }
        return csrow;
 }
@@ -1298,7 +1302,7 @@ static int f10_process_possible_spare(struct amd64_pvt *pvt, u8 dct, int csrow)
  *     -EINVAL:  NOT FOUND
  *     0..csrow = Chip-Select Row
  */
-static int f10_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)
+static int f1x_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)
 {
        struct mem_ctl_info *mci;
        struct amd64_pvt *pvt;
@@ -1339,13 +1343,49 @@ static int f10_lookup_addr_in_dct(u64 in_addr, u32 nid, u8 dct)
        return cs_found;
 }
 
+/*
+ * See F2x10C. Non-interleaved graphics framebuffer memory under the 16G is
+ * swapped with a region located at the bottom of memory so that the GPU can use
+ * the interleaved region and thus two channels.
+ */
+static u64 f1x_swap_interleaved_region(struct amd64_pvt *pvt, u64 sys_addr)
+{
+       u32 swap_reg, swap_base, swap_limit, rgn_size, tmp_addr;
+
+       if (boot_cpu_data.x86 == 0x10) {
+               /* only revC3 and revE have that feature */
+               if (boot_cpu_data.x86_model < 4 ||
+                   (boot_cpu_data.x86_model < 0xa &&
+                    boot_cpu_data.x86_mask < 3))
+                       return sys_addr;
+       }
+
+       amd64_read_dct_pci_cfg(pvt, SWAP_INTLV_REG, &swap_reg);
+
+       if (!(swap_reg & 0x1))
+               return sys_addr;
+
+       swap_base       = (swap_reg >> 3) & 0x7f;
+       swap_limit      = (swap_reg >> 11) & 0x7f;
+       rgn_size        = (swap_reg >> 20) & 0x7f;
+       tmp_addr        = sys_addr >> 27;
+
+       if (!(sys_addr >> 34) &&
+           (((tmp_addr >= swap_base) &&
+            (tmp_addr <= swap_limit)) ||
+            (tmp_addr < rgn_size)))
+               return sys_addr ^ (u64)swap_base << 27;
+
+       return sys_addr;
+}
+
 /* For a given @dram_range, check if @sys_addr falls within it. */
-static int f10_match_to_this_node(struct amd64_pvt *pvt, int range,
+static int f1x_match_to_this_node(struct amd64_pvt *pvt, int range,
                                  u64 sys_addr, int *nid, int *chan_sel)
 {
        int cs_found = -EINVAL;
        u64 chan_addr;
-       u32 tmp, dct_sel_base;
+       u32 dct_sel_base;
        u8 channel;
        bool high_range = false;
 
@@ -1356,9 +1396,22 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range,
        debugf1("(range %d) SystemAddr= 0x%llx Limit=0x%llx\n",
                range, sys_addr, get_dram_limit(pvt, range));
 
+       if (dhar_valid(pvt) &&
+           dhar_base(pvt) <= sys_addr &&
+           sys_addr < BIT_64(32)) {
+               amd64_warn("Huh? Address is in the MMIO hole: 0x%016llx\n",
+                           sys_addr);
+               return -EINVAL;
+       }
+
        if (intlv_en &&
-           (intlv_sel != ((sys_addr >> 12) & intlv_en)))
+           (intlv_sel != ((sys_addr >> 12) & intlv_en))) {
+               amd64_warn("Botched intlv bits, en: 0x%x, sel: 0x%x\n",
+                          intlv_en, intlv_sel);
                return -EINVAL;
+       }
+
+       sys_addr = f1x_swap_interleaved_region(pvt, sys_addr);
 
        dct_sel_base = dct_sel_baseaddr(pvt);
 
@@ -1371,31 +1424,39 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range,
           ((sys_addr >> 27) >= (dct_sel_base >> 11)))
                high_range = true;
 
-       channel = f10_determine_channel(pvt, sys_addr, high_range, intlv_en);
+       channel = f1x_determine_channel(pvt, sys_addr, high_range, intlv_en);
 
-       chan_addr = f10_get_norm_dct_addr(pvt, range, sys_addr,
+       chan_addr = f1x_get_norm_dct_addr(pvt, range, sys_addr,
                                          high_range, dct_sel_base);
 
-       /* remove Node ID (in case of node interleaving) */
-       tmp = chan_addr & 0xFC0;
-
-       chan_addr = ((chan_addr >> hweight8(intlv_en)) & GENMASK(12, 47)) | tmp;
+       /* Remove node interleaving, see F1x120 */
+       if (intlv_en)
+               chan_addr = ((chan_addr >> (12 + hweight8(intlv_en))) << 12) |
+                           (chan_addr & 0xfff);
 
-       /* remove channel interleave and hash */
+       /* remove channel interleave */
        if (dct_interleave_enabled(pvt) &&
           !dct_high_range_enabled(pvt) &&
           !dct_ganging_enabled(pvt)) {
-               if (dct_sel_interleave_addr(pvt) != 1)
-                       chan_addr = (chan_addr >> 1) & GENMASK(6, 63);
-               else {
-                       tmp = chan_addr & 0xFC0;
-                       chan_addr = ((chan_addr & GENMASK(14, 63)) >> 1) | tmp;
-               }
+
+               if (dct_sel_interleave_addr(pvt) != 1) {
+                       if (dct_sel_interleave_addr(pvt) == 0x3)
+                               /* hash 9 */
+                               chan_addr = ((chan_addr >> 10) << 9) |
+                                            (chan_addr & 0x1ff);
+                       else
+                               /* A[6] or hash 6 */
+                               chan_addr = ((chan_addr >> 7) << 6) |
+                                            (chan_addr & 0x3f);
+               } else
+                       /* A[12] */
+                       chan_addr = ((chan_addr >> 13) << 12) |
+                                    (chan_addr & 0xfff);
        }
 
-       debugf1("   (ChannelAddrLong=0x%llx)\n", chan_addr);
+       debugf1("   Normalized DCT addr: 0x%llx\n", chan_addr);
 
-       cs_found = f10_lookup_addr_in_dct(chan_addr, node_id, channel);
+       cs_found = f1x_lookup_addr_in_dct(chan_addr, node_id, channel);
 
        if (cs_found >= 0) {
                *nid = node_id;
@@ -1404,7 +1465,7 @@ static int f10_match_to_this_node(struct amd64_pvt *pvt, int range,
        return cs_found;
 }
 
-static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
+static int f1x_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
                                       int *node, int *chan_sel)
 {
        int range, cs_found = -EINVAL;
@@ -1417,7 +1478,7 @@ static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
                if ((get_dram_base(pvt, range)  <= sys_addr) &&
                    (get_dram_limit(pvt, range) >= sys_addr)) {
 
-                       cs_found = f10_match_to_this_node(pvt, range,
+                       cs_found = f1x_match_to_this_node(pvt, range,
                                                          sys_addr, node,
                                                          chan_sel);
                        if (cs_found >= 0)
@@ -1434,16 +1495,14 @@ static int f10_translate_sysaddr_to_cs(struct amd64_pvt *pvt, u64 sys_addr,
  * The @sys_addr is usually an error address received from the hardware
  * (MCX_ADDR).
  */
-static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
-                                    struct err_regs *err_info,
-                                    u64 sys_addr)
+static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
+                                    u16 syndrome)
 {
        struct amd64_pvt *pvt = mci->pvt_info;
        u32 page, offset;
        int nid, csrow, chan = 0;
-       u16 syndrome;
 
-       csrow = f10_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan);
+       csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan);
 
        if (csrow < 0) {
                edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
@@ -1452,8 +1511,6 @@ static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
 
        error_address_to_page_and_offset(sys_addr, &page, &offset);
 
-       syndrome = extract_syndrome(err_info);
-
        /*
         * We need the syndromes for channel detection only when we're
         * ganged. Otherwise @chan should already contain the channel at
@@ -1485,7 +1542,7 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt)
        u32 dbam  = ctrl ? pvt->dbam1 : pvt->dbam0;
 
        if (boot_cpu_data.x86 == 0xf) {
-               if (pvt->dclr0 & F10_WIDTH_128)
+               if (pvt->dclr0 & WIDTH_128)
                        factor = 1;
 
                /* K8 families < revF not supported yet */
@@ -1508,11 +1565,13 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt)
 
                size0 = 0;
                if (dcsb[dimm*2] & DCSB_CS_ENABLE)
-                       size0 = pvt->ops->dbam_to_cs(pvt, DBAM_DIMM(dimm, dbam));
+                       size0 = pvt->ops->dbam_to_cs(pvt, ctrl,
+                                                    DBAM_DIMM(dimm, dbam));
 
                size1 = 0;
                if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE)
-                       size1 = pvt->ops->dbam_to_cs(pvt, DBAM_DIMM(dimm, dbam));
+                       size1 = pvt->ops->dbam_to_cs(pvt, ctrl,
+                                                    DBAM_DIMM(dimm, dbam));
 
                amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
                                dimm * 2,     size0 << factor,
@@ -1527,7 +1586,6 @@ static struct amd64_family_type amd64_family_types[] = {
                .f3_id = PCI_DEVICE_ID_AMD_K8_NB_MISC,
                .ops = {
                        .early_channel_count    = k8_early_channel_count,
-                       .get_error_address      = k8_get_error_address,
                        .map_sysaddr_to_csrow   = k8_map_sysaddr_to_csrow,
                        .dbam_to_cs             = k8_dbam_to_chip_select,
                        .read_dct_pci_cfg       = k8_read_dct_pci_cfg,
@@ -1539,9 +1597,7 @@ static struct amd64_family_type amd64_family_types[] = {
                .f3_id = PCI_DEVICE_ID_AMD_10H_NB_MISC,
                .ops = {
                        .early_channel_count    = f1x_early_channel_count,
-                       .get_error_address      = f10_get_error_address,
-                       .read_dram_ctl_register = f10_read_dram_ctl_register,
-                       .map_sysaddr_to_csrow   = f10_map_sysaddr_to_csrow,
+                       .map_sysaddr_to_csrow   = f1x_map_sysaddr_to_csrow,
                        .dbam_to_cs             = f10_dbam_to_chip_select,
                        .read_dct_pci_cfg       = f10_read_dct_pci_cfg,
                }
@@ -1550,6 +1606,8 @@ static struct amd64_family_type amd64_family_types[] = {
                .ctl_name = "F15h",
                .ops = {
                        .early_channel_count    = f1x_early_channel_count,
+                       .map_sysaddr_to_csrow   = f1x_map_sysaddr_to_csrow,
+                       .dbam_to_cs             = f15_dbam_to_chip_select,
                        .read_dct_pci_cfg       = f15_read_dct_pci_cfg,
                }
        },
@@ -1740,31 +1798,30 @@ static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
  * Handle any Correctable Errors (CEs) that have occurred. Check for valid ERROR
  * ADDRESS and process.
  */
-static void amd64_handle_ce(struct mem_ctl_info *mci,
-                           struct err_regs *info)
+static void amd64_handle_ce(struct mem_ctl_info *mci, struct mce *m)
 {
        struct amd64_pvt *pvt = mci->pvt_info;
        u64 sys_addr;
+       u16 syndrome;
 
        /* Ensure that the Error Address is VALID */
-       if (!(info->nbsh & NBSH_VALID_ERROR_ADDR)) {
+       if (!(m->status & MCI_STATUS_ADDRV)) {
                amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
                edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
                return;
        }
 
-       sys_addr = pvt->ops->get_error_address(mci, info);
+       sys_addr = get_error_address(m);
+       syndrome = extract_syndrome(m->status);
 
        amd64_mc_err(mci, "CE ERROR_ADDRESS= 0x%llx\n", sys_addr);
 
-       pvt->ops->map_sysaddr_to_csrow(mci, info, sys_addr);
+       pvt->ops->map_sysaddr_to_csrow(mci, sys_addr, syndrome);
 }
 
 /* Handle any Un-correctable Errors (UEs) */
-static void amd64_handle_ue(struct mem_ctl_info *mci,
-                           struct err_regs *info)
+static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m)
 {
-       struct amd64_pvt *pvt = mci->pvt_info;
        struct mem_ctl_info *log_mci, *src_mci = NULL;
        int csrow;
        u64 sys_addr;
@@ -1772,13 +1829,13 @@ static void amd64_handle_ue(struct mem_ctl_info *mci,
 
        log_mci = mci;
 
-       if (!(info->nbsh & NBSH_VALID_ERROR_ADDR)) {
+       if (!(m->status & MCI_STATUS_ADDRV)) {
                amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
                edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
                return;
        }
 
-       sys_addr = pvt->ops->get_error_address(mci, info);
+       sys_addr = get_error_address(m);
 
        /*
         * Find out which node the error address belongs to. This may be
@@ -1806,11 +1863,11 @@ static void amd64_handle_ue(struct mem_ctl_info *mci,
 }
 
 static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
-                                           struct err_regs *info)
+                                           struct mce *m)
 {
-       u16 ec = EC(info->nbsl);
-       u8 xec = XEC(info->nbsl, 0x1f);
-       int ecc_type = (info->nbsh >> 13) & 0x3;
+       u16 ec = EC(m->status);
+       u8 xec = XEC(m->status, 0x1f);
+       u8 ecc_type = (m->status >> 45) & 0x3;
 
        /* Bail early out if this was an 'observed' error */
        if (PP(ec) == NBSL_PP_OBS)
@@ -1821,23 +1878,16 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
                return;
 
        if (ecc_type == 2)
-               amd64_handle_ce(mci, info);
+               amd64_handle_ce(mci, m);
        else if (ecc_type == 1)
-               amd64_handle_ue(mci, info);
+               amd64_handle_ue(mci, m);
 }
 
 void amd64_decode_bus_error(int node_id, struct mce *m, u32 nbcfg)
 {
        struct mem_ctl_info *mci = mcis[node_id];
-       struct err_regs regs;
-
-       regs.nbsl  = (u32) m->status;
-       regs.nbsh  = (u32)(m->status >> 32);
-       regs.nbeal = (u32) m->addr;
-       regs.nbeah = (u32)(m->addr >> 32);
-       regs.nbcfg = nbcfg;
 
-       __amd64_decode_bus_error(mci, &regs);
+       __amd64_decode_bus_error(mci, m);
 }
 
 /*
@@ -1907,8 +1957,7 @@ static void read_mc_regs(struct amd64_pvt *pvt)
 
        amd64_read_pci_cfg(pvt->F3, NBCAP, &pvt->nbcap);
 
-       if (pvt->ops->read_dram_ctl_register)
-               pvt->ops->read_dram_ctl_register(pvt);
+       read_dram_ctl_register(pvt);
 
        for (range = 0; range < DRAM_RANGES; range++) {
                u8 rw;
@@ -1998,7 +2047,7 @@ static void read_mc_regs(struct amd64_pvt *pvt)
  *     encompasses
  *
  */
-static u32 amd64_csrow_nr_pages(int csrow_nr, struct amd64_pvt *pvt)
+static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
 {
        u32 cs_mode, nr_pages;
 
@@ -2011,7 +2060,7 @@ static u32 amd64_csrow_nr_pages(int csrow_nr, struct amd64_pvt *pvt)
         */
        cs_mode = (pvt->dbam0 >> ((csrow_nr / 2) * 4)) & 0xF;
 
-       nr_pages = pvt->ops->dbam_to_cs(pvt, cs_mode) << (20 - PAGE_SHIFT);
+       nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode) << (20 - PAGE_SHIFT);
 
        /*
         * If dual channel then double the memory size of single channel.
@@ -2059,7 +2108,7 @@ static int init_csrows(struct mem_ctl_info *mci)
                        i, pvt->mc_node_id);
 
                empty = 0;
-               csrow->nr_pages = amd64_csrow_nr_pages(i, pvt);
+               csrow->nr_pages = amd64_csrow_nr_pages(pvt, 0, i);
                find_csrow_limits(mci, i, &input_addr_min, &input_addr_max);
                sys_addr = input_addr_to_sys_addr(mci, input_addr_min);
                csrow->first_page = (u32) (sys_addr >> PAGE_SHIFT);
@@ -2354,13 +2403,11 @@ static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)
                fam_type                = &amd64_family_types[K8_CPUS];
                pvt->ops                = &amd64_family_types[K8_CPUS].ops;
                pvt->ctl_name           = fam_type->ctl_name;
-               pvt->min_scrubrate      = K8_MIN_SCRUB_RATE_BITS;
                break;
        case 0x10:
                fam_type                = &amd64_family_types[F10_CPUS];
                pvt->ops                = &amd64_family_types[F10_CPUS].ops;
                pvt->ctl_name           = fam_type->ctl_name;
-               pvt->min_scrubrate      = F10_MIN_SCRUB_RATE_BITS;
                break;
 
        default: