]> git.karo-electronics.de Git - mv-sheeva.git/blobdiff - drivers/edac/amd64_edac.c
Merge tag 'v2.6.38' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[mv-sheeva.git] / drivers / edac / amd64_edac.c
index eca9ba193e94a914aa64740f0b4262b8f7c99b81..23e03554f0d3af68053f1ae56427fbd577217360 100644 (file)
@@ -15,10 +15,14 @@ module_param(ecc_enable_override, int, 0644);
 
 static struct msr __percpu *msrs;
 
-/* Lookup table for all possible MC control instances */
-struct amd64_pvt;
-static struct mem_ctl_info *mci_lookup[EDAC_MAX_NUMNODES];
-static struct amd64_pvt *pvt_lookup[EDAC_MAX_NUMNODES];
+/*
+ * count successfully initialized driver instances for setup_pci_device()
+ */
+static atomic_t drv_instances = ATOMIC_INIT(0);
+
+/* Per-node driver instances */
+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
@@ -62,7 +66,7 @@ static int ddr3_dbam[] = { [0]                = -1,
                           [5 ... 6]    = 1024,
                           [7 ... 8]    = 2048,
                           [9 ... 10]   = 4096,
-                          [11] = 8192,
+                          [11]         = 8192,
 };
 
 /*
@@ -73,7 +77,11 @@ static int ddr3_dbam[] = { [0]               = -1,
  *FIXME: Produce a better mapping/linearisation.
  */
 
-struct scrubrate scrubrates[] = {
+
+struct scrubrate {
+       u32 scrubval;           /* bit pattern for scrub rate */
+       u32 bandwidth;          /* bandwidth consumed (bytes/sec) */
+} scrubrates[] = {
        { 0x01, 1600000000UL},
        { 0x02, 800000000UL},
        { 0x03, 400000000UL},
@@ -117,8 +125,7 @@ struct scrubrate scrubrates[] = {
  * scan the scrub rate mapping table for a close or matching bandwidth value to
  * issue. If requested is too big, then use last maximum value found.
  */
-static int amd64_search_set_scrub_rate(struct pci_dev *ctl, u32 new_bw,
-                                      u32 min_scrubrate)
+static int __amd64_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate)
 {
        u32 scrubval;
        int i;
@@ -134,7 +141,7 @@ static int amd64_search_set_scrub_rate(struct pci_dev *ctl, u32 new_bw,
                 * skip scrub rates which aren't recommended
                 * (see F10 BKDG, F3x58)
                 */
-               if (scrubrates[i].scrubval < min_scrubrate)
+               if (scrubrates[i].scrubval < min_rate)
                        continue;
 
                if (scrubrates[i].bandwidth <= new_bw)
@@ -148,64 +155,41 @@ static int amd64_search_set_scrub_rate(struct pci_dev *ctl, u32 new_bw,
        }
 
        scrubval = scrubrates[i].scrubval;
-       if (scrubval)
-               edac_printk(KERN_DEBUG, EDAC_MC,
-                           "Setting scrub rate bandwidth: %u\n",
-                           scrubrates[i].bandwidth);
-       else
-               edac_printk(KERN_DEBUG, EDAC_MC, "Turning scrubbing off.\n");
 
        pci_write_bits32(ctl, K8_SCRCTRL, scrubval, 0x001F);
 
+       if (scrubval)
+               return scrubrates[i].bandwidth;
+
        return 0;
 }
 
-static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bandwidth)
+static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bw)
 {
        struct amd64_pvt *pvt = mci->pvt_info;
-       u32 min_scrubrate = 0x0;
 
-       switch (boot_cpu_data.x86) {
-       case 0xf:
-               min_scrubrate = K8_MIN_SCRUB_RATE_BITS;
-               break;
-       case 0x10:
-               min_scrubrate = F10_MIN_SCRUB_RATE_BITS;
-               break;
-       case 0x11:
-               min_scrubrate = F11_MIN_SCRUB_RATE_BITS;
-               break;
-
-       default:
-               amd64_printk(KERN_ERR, "Unsupported family!\n");
-               return -EINVAL;
-       }
-       return amd64_search_set_scrub_rate(pvt->misc_f3_ctl, bandwidth,
-                                          min_scrubrate);
+       return __amd64_set_scrub_rate(pvt->F3, bw, pvt->min_scrubrate);
 }
 
-static int amd64_get_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
+static int amd64_get_scrub_rate(struct mem_ctl_info *mci)
 {
        struct amd64_pvt *pvt = mci->pvt_info;
        u32 scrubval = 0;
-       int status = -1, i;
+       int i, retval = -EINVAL;
 
-       amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_SCRCTRL, &scrubval);
+       amd64_read_pci_cfg(pvt->F3, K8_SCRCTRL, &scrubval);
 
        scrubval = scrubval & 0x001F;
 
-       edac_printk(KERN_DEBUG, EDAC_MC,
-                   "pci-read, sdram scrub control value: %d \n", scrubval);
+       amd64_debug("pci-read, sdram scrub control value: %d\n", scrubval);
 
        for (i = 0; i < ARRAY_SIZE(scrubrates); i++) {
                if (scrubrates[i].scrubval == scrubval) {
-                       *bw = scrubrates[i].bandwidth;
-                       status = 0;
+                       retval = scrubrates[i].bandwidth;
                        break;
                }
        }
-
-       return status;
+       return retval;
 }
 
 /* Map from a CSROW entry to the mask entry that operates on it */
@@ -314,9 +298,7 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
        if (unlikely((intlv_en != 0x01) &&
                     (intlv_en != 0x03) &&
                     (intlv_en != 0x07))) {
-               amd64_printk(KERN_WARNING, "junk value of 0x%x extracted from "
-                            "IntlvEn field of DRAM Base Register for node 0: "
-                            "this probably indicates a BIOS bug.\n", intlv_en);
+               amd64_warn("DRAM Base[IntlvEn] junk value: 0x%x, BIOS bug?\n", intlv_en);
                return NULL;
        }
 
@@ -332,11 +314,9 @@ static struct mem_ctl_info *find_mc_by_sys_addr(struct mem_ctl_info *mci,
 
        /* sanity test for sys_addr */
        if (unlikely(!amd64_base_limit_match(pvt, sys_addr, node_id))) {
-               amd64_printk(KERN_WARNING,
-                            "%s(): sys_addr 0x%llx falls outside base/limit "
-                            "address range for node %d with node interleaving "
-                            "enabled.\n",
-                            __func__, sys_addr, node_id);
+               amd64_warn("%s: sys_addr 0x%llx falls outside base/limit address"
+                          "range for node %d with node interleaving enabled.\n",
+                          __func__, sys_addr, node_id);
                return NULL;
        }
 
@@ -788,9 +768,8 @@ static int sys_addr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr)
        csrow = input_addr_to_csrow(mci, sys_addr_to_input_addr(mci, sys_addr));
 
        if (csrow == -1)
-               amd64_mc_printk(mci, KERN_ERR,
-                            "Failed to translate InputAddr to csrow for "
-                            "address 0x%lx\n", (unsigned long)sys_addr);
+               amd64_mc_err(mci, "Failed to translate InputAddr to csrow for "
+                                 "address 0x%lx\n", (unsigned long)sys_addr);
        return csrow;
 }
 
@@ -801,21 +780,6 @@ static u16 extract_syndrome(struct err_regs *err)
        return ((err->nbsh >> 15) & 0xff) | ((err->nbsl >> 16) & 0xff00);
 }
 
-static void amd64_cpu_display_info(struct amd64_pvt *pvt)
-{
-       if (boot_cpu_data.x86 == 0x11)
-               edac_printk(KERN_DEBUG, EDAC_MC, "F11h CPU detected\n");
-       else if (boot_cpu_data.x86 == 0x10)
-               edac_printk(KERN_DEBUG, EDAC_MC, "F10h CPU detected\n");
-       else if (boot_cpu_data.x86 == 0xf)
-               edac_printk(KERN_DEBUG, EDAC_MC, "%s detected\n",
-                       (pvt->ext_model >= K8_REV_F) ?
-                       "Rev F or later" : "Rev E or earlier");
-       else
-               /* we'll hardly ever ever get here */
-               edac_printk(KERN_ERR, EDAC_MC, "Unknown cpu!\n");
-}
-
 /*
  * Determine if the DIMMs have ECC enabled. ECC is enabled ONLY if all the DIMMs
  * are ECC capable.
@@ -862,8 +826,6 @@ static void amd64_dump_dramcfg_low(u32 dclr, int chan)
 /* Display and decode various NB registers for debug purposes. */
 static void amd64_dump_misc_regs(struct amd64_pvt *pvt)
 {
-       int ganged;
-
        debugf1("F3xE8 (NB Cap): 0x%08x\n", pvt->nbcap);
 
        debugf1("  NB two channel DRAM capable: %s\n",
@@ -887,38 +849,28 @@ static void amd64_dump_misc_regs(struct amd64_pvt *pvt)
        debugf1("  DramHoleValid: %s\n",
                (pvt->dhar & DHAR_VALID) ? "yes" : "no");
 
+       amd64_debug_display_dimm_sizes(0, pvt);
+
        /* everything below this point is Fam10h and above */
-       if (boot_cpu_data.x86 == 0xf) {
-               amd64_debug_display_dimm_sizes(0, pvt);
+       if (boot_cpu_data.x86 == 0xf)
                return;
-       }
 
-       amd64_printk(KERN_INFO, "using %s syndromes.\n",
-                    ((pvt->syn_type == 8) ? "x8" : "x4"));
+       amd64_debug_display_dimm_sizes(1, pvt);
+
+       amd64_info("using %s syndromes.\n", ((pvt->syn_type == 8) ? "x8" : "x4"));
 
        /* Only if NOT ganged does dclr1 have valid info */
        if (!dct_ganging_enabled(pvt))
                amd64_dump_dramcfg_low(pvt->dclr1, 1);
-
-       /*
-        * Determine if ganged and then dump memory sizes for first controller,
-        * and if NOT ganged dump info for 2nd controller.
-        */
-       ganged = dct_ganging_enabled(pvt);
-
-       amd64_debug_display_dimm_sizes(0, pvt);
-
-       if (!ganged)
-               amd64_debug_display_dimm_sizes(1, pvt);
 }
 
 /* Read in both of DBAM registers */
 static void amd64_read_dbam_reg(struct amd64_pvt *pvt)
 {
-       amd64_read_pci_cfg(pvt->dram_f2_ctl, DBAM0, &pvt->dbam0);
+       amd64_read_pci_cfg(pvt->F2, DBAM0, &pvt->dbam0);
 
        if (boot_cpu_data.x86 >= 0x10)
-               amd64_read_pci_cfg(pvt->dram_f2_ctl, DBAM1, &pvt->dbam1);
+               amd64_read_pci_cfg(pvt->F2, DBAM1, &pvt->dbam1);
 }
 
 /*
@@ -965,14 +917,8 @@ static void amd64_set_dct_base_and_mask(struct amd64_pvt *pvt)
                pvt->dcsm_mask          = REV_F_F1Xh_DCSM_MASK_BITS;
                pvt->dcs_mask_notused   = REV_F_F1Xh_DCS_NOTUSED_BITS;
                pvt->dcs_shift          = REV_F_F1Xh_DCS_SHIFT;
-
-               if (boot_cpu_data.x86 == 0x11) {
-                       pvt->cs_count = 4;
-                       pvt->num_dcsm = 2;
-               } else {
-                       pvt->cs_count = 8;
-                       pvt->num_dcsm = 4;
-               }
+               pvt->cs_count           = 8;
+               pvt->num_dcsm           = 4;
        }
 }
 
@@ -987,14 +933,14 @@ static void amd64_read_dct_base_mask(struct amd64_pvt *pvt)
 
        for (cs = 0; cs < pvt->cs_count; cs++) {
                reg = K8_DCSB0 + (cs * 4);
-               if (!amd64_read_pci_cfg(pvt->dram_f2_ctl, reg, &pvt->dcsb0[cs]))
+               if (!amd64_read_pci_cfg(pvt->F2, reg, &pvt->dcsb0[cs]))
                        debugf0("  DCSB0[%d]=0x%08x reg: F2x%x\n",
                                cs, pvt->dcsb0[cs], reg);
 
                /* If DCT are NOT ganged, then read in DCT1's base */
                if (boot_cpu_data.x86 >= 0x10 && !dct_ganging_enabled(pvt)) {
                        reg = F10_DCSB1 + (cs * 4);
-                       if (!amd64_read_pci_cfg(pvt->dram_f2_ctl, reg,
+                       if (!amd64_read_pci_cfg(pvt->F2, reg,
                                                &pvt->dcsb1[cs]))
                                debugf0("  DCSB1[%d]=0x%08x reg: F2x%x\n",
                                        cs, pvt->dcsb1[cs], reg);
@@ -1005,14 +951,14 @@ static void amd64_read_dct_base_mask(struct amd64_pvt *pvt)
 
        for (cs = 0; cs < pvt->num_dcsm; cs++) {
                reg = K8_DCSM0 + (cs * 4);
-               if (!amd64_read_pci_cfg(pvt->dram_f2_ctl, reg, &pvt->dcsm0[cs]))
+               if (!amd64_read_pci_cfg(pvt->F2, reg, &pvt->dcsm0[cs]))
                        debugf0("    DCSM0[%d]=0x%08x reg: F2x%x\n",
                                cs, pvt->dcsm0[cs], reg);
 
                /* If DCT are NOT ganged, then read in DCT1's mask */
                if (boot_cpu_data.x86 >= 0x10 && !dct_ganging_enabled(pvt)) {
                        reg = F10_DCSM1 + (cs * 4);
-                       if (!amd64_read_pci_cfg(pvt->dram_f2_ctl, reg,
+                       if (!amd64_read_pci_cfg(pvt->F2, reg,
                                                &pvt->dcsm1[cs]))
                                debugf0("    DCSM1[%d]=0x%08x reg: F2x%x\n",
                                        cs, pvt->dcsm1[cs], reg);
@@ -1022,7 +968,7 @@ static void amd64_read_dct_base_mask(struct amd64_pvt *pvt)
        }
 }
 
-static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt)
+static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt, int cs)
 {
        enum mem_type type;
 
@@ -1035,7 +981,7 @@ static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt)
                type = (pvt->dclr0 & BIT(18)) ? MEM_DDR : MEM_RDDR;
        }
 
-       debugf1("  Memory type is: %s\n", edac_mem_types[type]);
+       amd64_info("CS%d: %s\n", cs, edac_mem_types[type]);
 
        return type;
 }
@@ -1053,17 +999,16 @@ static int k8_early_channel_count(struct amd64_pvt *pvt)
 {
        int flag, err = 0;
 
-       err = amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCLR_0, &pvt->dclr0);
+       err = amd64_read_pci_cfg(pvt->F2, F10_DCLR_0, &pvt->dclr0);
        if (err)
                return err;
 
-       if ((boot_cpu_data.x86_model >> 4) >= K8_REV_F) {
+       if (pvt->ext_model >= K8_REV_F)
                /* RevF (NPT) and later */
                flag = pvt->dclr0 & F10_WIDTH_128;
-       } else {
+       else
                /* RevE and earlier */
                flag = pvt->dclr0 & REVE_WIDTH_128;
-       }
 
        /* not used */
        pvt->dclr1 = 0;
@@ -1090,14 +1035,14 @@ static void k8_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
        u32 low;
        u32 off = dram << 3;    /* 8 bytes between DRAM entries */
 
-       amd64_read_pci_cfg(pvt->addr_f1_ctl, K8_DRAM_BASE_LOW + off, &low);
+       amd64_read_pci_cfg(pvt->F1, K8_DRAM_BASE_LOW + off, &low);
 
        /* Extract parts into separate data entries */
        pvt->dram_base[dram] = ((u64) low & 0xFFFF0000) << 8;
        pvt->dram_IntlvEn[dram] = (low >> 8) & 0x7;
        pvt->dram_rw_en[dram] = (low & 0x3);
 
-       amd64_read_pci_cfg(pvt->addr_f1_ctl, K8_DRAM_LIMIT_LOW + off, &low);
+       amd64_read_pci_cfg(pvt->F1, K8_DRAM_LIMIT_LOW + off, &low);
 
        /*
         * Extract parts into separate data entries. Limit is the HIGHEST memory
@@ -1127,9 +1072,8 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
                         * 2 DIMMs is in error. So we need to ID 'both' of them
                         * as suspect.
                         */
-                       amd64_mc_printk(mci, KERN_WARNING,
-                                       "unknown syndrome 0x%04x - possible "
-                                       "error reporting race\n", syndrome);
+                       amd64_mc_warn(mci, "unknown syndrome 0x%04x - possible "
+                                          "error reporting race\n", syndrome);
                        edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
                        return;
                }
@@ -1151,8 +1095,7 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
         */
        src_mci = find_mc_by_sys_addr(mci, sys_addr);
        if (!src_mci) {
-               amd64_mc_printk(mci, KERN_ERR,
-                            "failed to map error address 0x%lx to a node\n",
+               amd64_mc_err(mci, "failed to map error addr 0x%lx to a node\n",
                             (unsigned long)sys_addr);
                edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
                return;
@@ -1220,7 +1163,7 @@ static int f10_early_channel_count(struct amd64_pvt *pvt)
         * both controllers since DIMMs can be placed in either one.
         */
        for (i = 0; i < ARRAY_SIZE(dbams); i++) {
-               if (amd64_read_pci_cfg(pvt->dram_f2_ctl, dbams[i], &dbam))
+               if (amd64_read_pci_cfg(pvt->F2, dbams[i], &dbam))
                        goto err_reg;
 
                for (j = 0; j < 4; j++) {
@@ -1234,7 +1177,7 @@ static int f10_early_channel_count(struct amd64_pvt *pvt)
        if (channels > 2)
                channels = 2;
 
-       debugf0("MCT channel count: %d\n", channels);
+       amd64_info("MCT channel count: %d\n", channels);
 
        return channels;
 
@@ -1255,31 +1198,6 @@ static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, int cs_mode)
        return dbam_map[cs_mode];
 }
 
-/* Enable extended configuration access via 0xCF8 feature */
-static void amd64_setup(struct amd64_pvt *pvt)
-{
-       u32 reg;
-
-       amd64_read_pci_cfg(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, &reg);
-
-       pvt->flags.cf8_extcfg = !!(reg & F10_NB_CFG_LOW_ENABLE_EXT_CFG);
-       reg |= F10_NB_CFG_LOW_ENABLE_EXT_CFG;
-       pci_write_config_dword(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, reg);
-}
-
-/* Restore the extended configuration access via 0xCF8 feature */
-static void amd64_teardown(struct amd64_pvt *pvt)
-{
-       u32 reg;
-
-       amd64_read_pci_cfg(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, &reg);
-
-       reg &= ~F10_NB_CFG_LOW_ENABLE_EXT_CFG;
-       if (pvt->flags.cf8_extcfg)
-               reg |= F10_NB_CFG_LOW_ENABLE_EXT_CFG;
-       pci_write_config_dword(pvt->misc_f3_ctl, F10_NB_CFG_HIGH, reg);
-}
-
 static u64 f10_get_error_address(struct mem_ctl_info *mci,
                        struct err_regs *info)
 {
@@ -1301,10 +1219,8 @@ static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
        high_offset = F10_DRAM_BASE_HIGH + (dram << 3);
 
        /* read the 'raw' DRAM BASE Address register */
-       amd64_read_pci_cfg(pvt->addr_f1_ctl, low_offset, &low_base);
-
-       /* Read from the ECS data register */
-       amd64_read_pci_cfg(pvt->addr_f1_ctl, high_offset, &high_base);
+       amd64_read_pci_cfg(pvt->F1, low_offset, &low_base);
+       amd64_read_pci_cfg(pvt->F1, high_offset, &high_base);
 
        /* Extract parts into separate data entries */
        pvt->dram_rw_en[dram] = (low_base & 0x3);
@@ -1321,10 +1237,8 @@ static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
        high_offset = F10_DRAM_LIMIT_HIGH + (dram << 3);
 
        /* read the 'raw' LIMIT registers */
-       amd64_read_pci_cfg(pvt->addr_f1_ctl, low_offset, &low_limit);
-
-       /* Read from the ECS data register for the HIGH portion */
-       amd64_read_pci_cfg(pvt->addr_f1_ctl, high_offset, &high_limit);
+       amd64_read_pci_cfg(pvt->F1, low_offset, &low_limit);
+       amd64_read_pci_cfg(pvt->F1, high_offset, &high_limit);
 
        pvt->dram_DstNode[dram] = (low_limit & 0x7);
        pvt->dram_IntlvSel[dram] = (low_limit >> 8) & 0x7;
@@ -1341,7 +1255,7 @@ static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
 static void f10_read_dram_ctl_register(struct amd64_pvt *pvt)
 {
 
-       if (!amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCTL_SEL_LOW,
+       if (!amd64_read_pci_cfg(pvt->F2, F10_DCTL_SEL_LOW,
                                &pvt->dram_ctl_select_low)) {
                debugf0("F2x110 (DCTL Sel. Low): 0x%08x, "
                        "High range addresses at: 0x%x\n",
@@ -1367,7 +1281,7 @@ static void f10_read_dram_ctl_register(struct amd64_pvt *pvt)
                        dct_sel_interleave_addr(pvt));
        }
 
-       amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCTL_SEL_HIGH,
+       amd64_read_pci_cfg(pvt->F2, F10_DCTL_SEL_HIGH,
                           &pvt->dram_ctl_select_high);
 }
 
@@ -1496,7 +1410,7 @@ static int f10_lookup_addr_in_dct(u32 in_addr, u32 nid, u32 cs)
        int cs_found = -EINVAL;
        int csrow;
 
-       mci = mci_lookup[nid];
+       mci = mcis[nid];
        if (!mci)
                return cs_found;
 
@@ -1719,11 +1633,10 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt)
                       WARN_ON(ctrl != 0);
        }
 
-       debugf1("F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n",
-               ctrl, ctrl ? pvt->dbam1 : pvt->dbam0);
+       dbam = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dbam1 : pvt->dbam0;
+       dcsb = (ctrl && !dct_ganging_enabled(pvt)) ? pvt->dcsb1 : pvt->dcsb0;
 
-       dbam = ctrl ? pvt->dbam1 : pvt->dbam0;
-       dcsb = ctrl ? pvt->dcsb1 : pvt->dcsb0;
+       debugf1("F2x%d80 (DRAM Bank Address Mapping): 0x%08x\n", ctrl, dbam);
 
        edac_printk(KERN_DEBUG, EDAC_MC, "DCT%d chip selects:\n", ctrl);
 
@@ -1738,28 +1651,17 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt)
                if (dcsb[dimm*2 + 1] & K8_DCSB_CS_ENABLE)
                        size1 = pvt->ops->dbam_to_cs(pvt, DBAM_DIMM(dimm, dbam));
 
-               edac_printk(KERN_DEBUG, EDAC_MC, " %d: %5dMB %d: %5dMB\n",
-                           dimm * 2,     size0 << factor,
-                           dimm * 2 + 1, size1 << factor);
+               amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
+                               dimm * 2,     size0 << factor,
+                               dimm * 2 + 1, size1 << factor);
        }
 }
 
-/*
- * There currently are 3 types type of MC devices for AMD Athlon/Opterons
- * (as per PCI DEVICE_IDs):
- *
- * Family K8: That is the Athlon64 and Opteron CPUs. They all have the same PCI
- * DEVICE ID, even though there is differences between the different Revisions
- * (CG,D,E,F).
- *
- * Family F10h and F11h.
- *
- */
 static struct amd64_family_type amd64_family_types[] = {
        [K8_CPUS] = {
-               .ctl_name = "RevF",
-               .addr_f1_ctl = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP,
-               .misc_f3_ctl = PCI_DEVICE_ID_AMD_K8_NB_MISC,
+               .ctl_name = "K8",
+               .f1_id = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP,
+               .f3_id = PCI_DEVICE_ID_AMD_K8_NB_MISC,
                .ops = {
                        .early_channel_count    = k8_early_channel_count,
                        .get_error_address      = k8_get_error_address,
@@ -1769,22 +1671,9 @@ static struct amd64_family_type amd64_family_types[] = {
                }
        },
        [F10_CPUS] = {
-               .ctl_name = "Family 10h",
-               .addr_f1_ctl = PCI_DEVICE_ID_AMD_10H_NB_MAP,
-               .misc_f3_ctl = PCI_DEVICE_ID_AMD_10H_NB_MISC,
-               .ops = {
-                       .early_channel_count    = f10_early_channel_count,
-                       .get_error_address      = f10_get_error_address,
-                       .read_dram_base_limit   = f10_read_dram_base_limit,
-                       .read_dram_ctl_register = f10_read_dram_ctl_register,
-                       .map_sysaddr_to_csrow   = f10_map_sysaddr_to_csrow,
-                       .dbam_to_cs             = f10_dbam_to_chip_select,
-               }
-       },
-       [F11_CPUS] = {
-               .ctl_name = "Family 11h",
-               .addr_f1_ctl = PCI_DEVICE_ID_AMD_11H_NB_MAP,
-               .misc_f3_ctl = PCI_DEVICE_ID_AMD_11H_NB_MISC,
+               .ctl_name = "F10h",
+               .f1_id = PCI_DEVICE_ID_AMD_10H_NB_MAP,
+               .f3_id = PCI_DEVICE_ID_AMD_10H_NB_MISC,
                .ops = {
                        .early_channel_count    = f10_early_channel_count,
                        .get_error_address      = f10_get_error_address,
@@ -1970,8 +1859,7 @@ static int get_channel_from_ecc_syndrome(struct mem_ctl_info *mci, u16 syndrome)
                                          ARRAY_SIZE(x4_vectors),
                                          pvt->syn_type);
        else {
-               amd64_printk(KERN_WARNING, "%s: Illegal syndrome type: %u\n",
-                                          __func__, pvt->syn_type);
+               amd64_warn("Illegal syndrome type: %u\n", pvt->syn_type);
                return err_sym;
        }
 
@@ -1989,17 +1877,15 @@ static void amd64_handle_ce(struct mem_ctl_info *mci,
        u64 sys_addr;
 
        /* Ensure that the Error Address is VALID */
-       if ((info->nbsh & K8_NBSH_VALID_ERROR_ADDR) == 0) {
-               amd64_mc_printk(mci, KERN_ERR,
-                       "HW has no ERROR_ADDRESS available\n");
+       if (!(info->nbsh & K8_NBSH_VALID_ERROR_ADDR)) {
+               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);
 
-       amd64_mc_printk(mci, KERN_ERR,
-               "CE ERROR_ADDRESS= 0x%llx\n", sys_addr);
+       amd64_mc_err(mci, "CE ERROR_ADDRESS= 0x%llx\n", sys_addr);
 
        pvt->ops->map_sysaddr_to_csrow(mci, info, sys_addr);
 }
@@ -2016,9 +1902,8 @@ static void amd64_handle_ue(struct mem_ctl_info *mci,
 
        log_mci = mci;
 
-       if ((info->nbsh & K8_NBSH_VALID_ERROR_ADDR) == 0) {
-               amd64_mc_printk(mci, KERN_CRIT,
-                       "HW has no ERROR_ADDRESS available\n");
+       if (!(info->nbsh & K8_NBSH_VALID_ERROR_ADDR)) {
+               amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
                edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
                return;
        }
@@ -2031,9 +1916,8 @@ static void amd64_handle_ue(struct mem_ctl_info *mci,
         */
        src_mci = find_mc_by_sys_addr(mci, sys_addr);
        if (!src_mci) {
-               amd64_mc_printk(mci, KERN_CRIT,
-                       "ERROR ADDRESS (0x%lx) value NOT mapped to a MC\n",
-                       (unsigned long)sys_addr);
+               amd64_mc_err(mci, "ERROR ADDRESS (0x%lx) NOT mapped to a MC\n",
+                                 (unsigned long)sys_addr);
                edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
                return;
        }
@@ -2042,9 +1926,8 @@ static void amd64_handle_ue(struct mem_ctl_info *mci,
 
        csrow = sys_addr_to_csrow(log_mci, sys_addr);
        if (csrow < 0) {
-               amd64_mc_printk(mci, KERN_CRIT,
-                       "ERROR_ADDRESS (0x%lx) value NOT mapped to 'csrow'\n",
-                       (unsigned long)sys_addr);
+               amd64_mc_err(mci, "ERROR_ADDRESS (0x%lx) NOT mapped to CS\n",
+                                 (unsigned long)sys_addr);
                edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
        } else {
                error_address_to_page_and_offset(sys_addr, &page, &offset);
@@ -2055,8 +1938,8 @@ 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)
 {
-       u32 ec  = ERROR_CODE(info->nbsl);
-       u32 xec = EXT_ERROR_CODE(info->nbsl);
+       u16 ec = EC(info->nbsl);
+       u8 xec = XEC(info->nbsl, 0x1f);
        int ecc_type = (info->nbsh >> 13) & 0x3;
 
        /* Bail early out if this was an 'observed' error */
@@ -2075,7 +1958,7 @@ static inline void __amd64_decode_bus_error(struct mem_ctl_info *mci,
 
 void amd64_decode_bus_error(int node_id, struct mce *m, u32 nbcfg)
 {
-       struct mem_ctl_info *mci = mci_lookup[node_id];
+       struct mem_ctl_info *mci = mcis[node_id];
        struct err_regs regs;
 
        regs.nbsl  = (u32) m->status;
@@ -2099,75 +1982,50 @@ void amd64_decode_bus_error(int node_id, struct mce *m, u32 nbcfg)
 }
 
 /*
- * Input:
- *     1) struct amd64_pvt which contains pvt->dram_f2_ctl pointer
- *     2) AMD Family index value
- *
- * Ouput:
- *     Upon return of 0, the following filled in:
- *
- *             struct pvt->addr_f1_ctl
- *             struct pvt->misc_f3_ctl
- *
- *     Filled in with related device funcitions of 'dram_f2_ctl'
- *     These devices are "reserved" via the pci_get_device()
- *
- *     Upon return of 1 (error status):
- *
- *             Nothing reserved
+ * Use pvt->F2 which contains the F2 CPU PCI device to get the related
+ * F1 (AddrMap) and F3 (Misc) devices. Return negative value on error.
  */
-static int amd64_reserve_mc_sibling_devices(struct amd64_pvt *pvt, int mc_idx)
+static int reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 f1_id, u16 f3_id)
 {
-       const struct amd64_family_type *amd64_dev = &amd64_family_types[mc_idx];
-
        /* Reserve the ADDRESS MAP Device */
-       pvt->addr_f1_ctl = pci_get_related_function(pvt->dram_f2_ctl->vendor,
-                                                   amd64_dev->addr_f1_ctl,
-                                                   pvt->dram_f2_ctl);
-
-       if (!pvt->addr_f1_ctl) {
-               amd64_printk(KERN_ERR, "error address map device not found: "
-                            "vendor %x device 0x%x (broken BIOS?)\n",
-                            PCI_VENDOR_ID_AMD, amd64_dev->addr_f1_ctl);
-               return 1;
+       pvt->F1 = pci_get_related_function(pvt->F2->vendor, f1_id, pvt->F2);
+       if (!pvt->F1) {
+               amd64_err("error address map device not found: "
+                         "vendor %x device 0x%x (broken BIOS?)\n",
+                         PCI_VENDOR_ID_AMD, f1_id);
+               return -ENODEV;
        }
 
        /* Reserve the MISC Device */
-       pvt->misc_f3_ctl = pci_get_related_function(pvt->dram_f2_ctl->vendor,
-                                                   amd64_dev->misc_f3_ctl,
-                                                   pvt->dram_f2_ctl);
+       pvt->F3 = pci_get_related_function(pvt->F2->vendor, f3_id, pvt->F2);
+       if (!pvt->F3) {
+               pci_dev_put(pvt->F1);
+               pvt->F1 = NULL;
 
-       if (!pvt->misc_f3_ctl) {
-               pci_dev_put(pvt->addr_f1_ctl);
-               pvt->addr_f1_ctl = NULL;
+               amd64_err("error F3 device not found: "
+                         "vendor %x device 0x%x (broken BIOS?)\n",
+                         PCI_VENDOR_ID_AMD, f3_id);
 
-               amd64_printk(KERN_ERR, "error miscellaneous device not found: "
-                            "vendor %x device 0x%x (broken BIOS?)\n",
-                            PCI_VENDOR_ID_AMD, amd64_dev->misc_f3_ctl);
-               return 1;
+               return -ENODEV;
        }
-
-       debugf1("    Addr Map device PCI Bus ID:\t%s\n",
-               pci_name(pvt->addr_f1_ctl));
-       debugf1("    DRAM MEM-CTL PCI Bus ID:\t%s\n",
-               pci_name(pvt->dram_f2_ctl));
-       debugf1("    Misc device PCI Bus ID:\t%s\n",
-               pci_name(pvt->misc_f3_ctl));
+       debugf1("F1: %s\n", pci_name(pvt->F1));
+       debugf1("F2: %s\n", pci_name(pvt->F2));
+       debugf1("F3: %s\n", pci_name(pvt->F3));
 
        return 0;
 }
 
-static void amd64_free_mc_sibling_devices(struct amd64_pvt *pvt)
+static void free_mc_sibling_devs(struct amd64_pvt *pvt)
 {
-       pci_dev_put(pvt->addr_f1_ctl);
-       pci_dev_put(pvt->misc_f3_ctl);
+       pci_dev_put(pvt->F1);
+       pci_dev_put(pvt->F3);
 }
 
 /*
  * Retrieve the hardware registers of the memory controller (this includes the
  * 'Address Map' and 'Misc' device regs)
  */
-static void amd64_read_mc_registers(struct amd64_pvt *pvt)
+static void read_mc_regs(struct amd64_pvt *pvt)
 {
        u64 msr_val;
        u32 tmp;
@@ -2188,9 +2046,7 @@ static void amd64_read_mc_registers(struct amd64_pvt *pvt)
        } else
                debugf0("  TOP_MEM2 disabled.\n");
 
-       amd64_cpu_display_info(pvt);
-
-       amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCAP, &pvt->nbcap);
+       amd64_read_pci_cfg(pvt->F3, K8_NBCAP, &pvt->nbcap);
 
        if (pvt->ops->read_dram_ctl_register)
                pvt->ops->read_dram_ctl_register(pvt);
@@ -2227,21 +2083,20 @@ static void amd64_read_mc_registers(struct amd64_pvt *pvt)
 
        amd64_read_dct_base_mask(pvt);
 
-       amd64_read_pci_cfg(pvt->addr_f1_ctl, K8_DHAR, &pvt->dhar);
+       amd64_read_pci_cfg(pvt->F1, K8_DHAR, &pvt->dhar);
        amd64_read_dbam_reg(pvt);
 
-       amd64_read_pci_cfg(pvt->misc_f3_ctl,
-                          F10_ONLINE_SPARE, &pvt->online_spare);
+       amd64_read_pci_cfg(pvt->F3, F10_ONLINE_SPARE, &pvt->online_spare);
 
-       amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCLR_0, &pvt->dclr0);
-       amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCHR_0, &pvt->dchr0);
+       amd64_read_pci_cfg(pvt->F2, F10_DCLR_0, &pvt->dclr0);
+       amd64_read_pci_cfg(pvt->F2, F10_DCHR_0, &pvt->dchr0);
 
        if (boot_cpu_data.x86 >= 0x10) {
                if (!dct_ganging_enabled(pvt)) {
-                       amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCLR_1, &pvt->dclr1);
-                       amd64_read_pci_cfg(pvt->dram_f2_ctl, F10_DCHR_1, &pvt->dchr1);
+                       amd64_read_pci_cfg(pvt->F2, F10_DCLR_1, &pvt->dclr1);
+                       amd64_read_pci_cfg(pvt->F2, F10_DCHR_1, &pvt->dchr1);
                }
-               amd64_read_pci_cfg(pvt->misc_f3_ctl, EXT_NB_MCA_CFG, &tmp);
+               amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp);
        }
 
        if (boot_cpu_data.x86 == 0x10 &&
@@ -2321,21 +2176,22 @@ static u32 amd64_csrow_nr_pages(int csrow_nr, struct amd64_pvt *pvt)
  * Initialize the array of csrow attribute instances, based on the values
  * from pci config hardware registers.
  */
-static int amd64_init_csrows(struct mem_ctl_info *mci)
+static int init_csrows(struct mem_ctl_info *mci)
 {
        struct csrow_info *csrow;
-       struct amd64_pvt *pvt;
+       struct amd64_pvt *pvt = mci->pvt_info;
        u64 input_addr_min, input_addr_max, sys_addr;
+       u32 val;
        int i, empty = 1;
 
-       pvt = mci->pvt_info;
+       amd64_read_pci_cfg(pvt->F3, K8_NBCFG, &val);
 
-       amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCFG, &pvt->nbcfg);
+       pvt->nbcfg = val;
+       pvt->ctl_error_info.nbcfg = val;
 
-       debugf0("NBCFG= 0x%x  CHIPKILL= %s DRAM ECC= %s\n", pvt->nbcfg,
-               (pvt->nbcfg & K8_NBCFG_CHIPKILL) ? "Enabled" : "Disabled",
-               (pvt->nbcfg & K8_NBCFG_ECC_ENABLE) ? "Enabled" : "Disabled"
-               );
+       debugf0("node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
+               pvt->mc_node_id, val,
+               !!(val & K8_NBCFG_CHIPKILL), !!(val & K8_NBCFG_ECC_ENABLE));
 
        for (i = 0; i < pvt->cs_count; i++) {
                csrow = &mci->csrows[i];
@@ -2359,7 +2215,7 @@ static int amd64_init_csrows(struct mem_ctl_info *mci)
                csrow->page_mask = ~mask_from_dct_mask(pvt, i);
                /* 8 bytes of resolution */
 
-               csrow->mtype = amd64_determine_memory_type(pvt);
+               csrow->mtype = amd64_determine_memory_type(pvt, i);
 
                debugf1("  for MC node %d csrow %d:\n", pvt->mc_node_id, i);
                debugf1("    input_addr_min: 0x%lx input_addr_max: 0x%lx\n",
@@ -2404,8 +2260,7 @@ static bool amd64_nb_mce_bank_enabled_on_node(int nid)
        bool ret = false;
 
        if (!zalloc_cpumask_var(&mask, GFP_KERNEL)) {
-               amd64_printk(KERN_WARNING, "%s: error allocating mask\n",
-                            __func__);
+               amd64_warn("%s: Error allocating mask\n", __func__);
                return false;
        }
 
@@ -2431,18 +2286,17 @@ out:
        return ret;
 }
 
-static int amd64_toggle_ecc_err_reporting(struct amd64_pvt *pvt, bool on)
+static int toggle_ecc_err_reporting(struct ecc_settings *s, u8 nid, bool on)
 {
        cpumask_var_t cmask;
        int cpu;
 
        if (!zalloc_cpumask_var(&cmask, GFP_KERNEL)) {
-               amd64_printk(KERN_WARNING, "%s: error allocating mask\n",
-                            __func__);
+               amd64_warn("%s: error allocating mask\n", __func__);
                return false;
        }
 
-       get_cpus_on_this_dct_cpumask(cmask, pvt->mc_node_id);
+       get_cpus_on_this_dct_cpumask(cmask, nid);
 
        rdmsr_on_cpus(cmask, MSR_IA32_MCG_CTL, msrs);
 
@@ -2452,14 +2306,14 @@ static int amd64_toggle_ecc_err_reporting(struct amd64_pvt *pvt, bool on)
 
                if (on) {
                        if (reg->l & K8_MSR_MCGCTL_NBE)
-                               pvt->flags.nb_mce_enable = 1;
+                               s->flags.nb_mce_enable = 1;
 
                        reg->l |= K8_MSR_MCGCTL_NBE;
                } else {
                        /*
                         * Turn off NB MCE reporting only when it was off before
                         */
-                       if (!pvt->flags.nb_mce_enable)
+                       if (!s->flags.nb_mce_enable)
                                reg->l &= ~K8_MSR_MCGCTL_NBE;
                }
        }
@@ -2470,92 +2324,92 @@ static int amd64_toggle_ecc_err_reporting(struct amd64_pvt *pvt, bool on)
        return 0;
 }
 
-static void amd64_enable_ecc_error_reporting(struct mem_ctl_info *mci)
+static bool enable_ecc_error_reporting(struct ecc_settings *s, u8 nid,
+                                      struct pci_dev *F3)
 {
-       struct amd64_pvt *pvt = mci->pvt_info;
+       bool ret = true;
        u32 value, mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn;
 
-       amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCTL, &value);
+       if (toggle_ecc_err_reporting(s, nid, ON)) {
+               amd64_warn("Error enabling ECC reporting over MCGCTL!\n");
+               return false;
+       }
 
-       /* turn on UECCn and CECCEn bits */
-       pvt->old_nbctl = value & mask;
-       pvt->nbctl_mcgctl_saved = 1;
+       amd64_read_pci_cfg(F3, K8_NBCTL, &value);
 
-       value |= mask;
-       pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value);
+       /* turn on UECCEn and CECCEn bits */
+       s->old_nbctl   = value & mask;
+       s->nbctl_valid = true;
 
-       if (amd64_toggle_ecc_err_reporting(pvt, ON))
-               amd64_printk(KERN_WARNING, "Error enabling ECC reporting over "
-                                          "MCGCTL!\n");
+       value |= mask;
+       pci_write_config_dword(F3, K8_NBCTL, value);
 
-       amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCFG, &value);
+       amd64_read_pci_cfg(F3, K8_NBCFG, &value);
 
-       debugf0("NBCFG(1)= 0x%x  CHIPKILL= %s ECC_ENABLE= %s\n", value,
-               (value & K8_NBCFG_CHIPKILL) ? "Enabled" : "Disabled",
-               (value & K8_NBCFG_ECC_ENABLE) ? "Enabled" : "Disabled");
+       debugf0("1: node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
+               nid, value,
+               !!(value & K8_NBCFG_CHIPKILL), !!(value & K8_NBCFG_ECC_ENABLE));
 
        if (!(value & K8_NBCFG_ECC_ENABLE)) {
-               amd64_printk(KERN_WARNING,
-                       "This node reports that DRAM ECC is "
-                       "currently Disabled; ENABLING now\n");
+               amd64_warn("DRAM ECC disabled on this node, enabling...\n");
 
-               pvt->flags.nb_ecc_prev = 0;
+               s->flags.nb_ecc_prev = 0;
 
                /* Attempt to turn on DRAM ECC Enable */
                value |= K8_NBCFG_ECC_ENABLE;
-               pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCFG, value);
+               pci_write_config_dword(F3, K8_NBCFG, value);
 
-               amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCFG, &value);
+               amd64_read_pci_cfg(F3, K8_NBCFG, &value);
 
                if (!(value & K8_NBCFG_ECC_ENABLE)) {
-                       amd64_printk(KERN_WARNING,
-                               "Hardware rejects Enabling DRAM ECC checking\n"
-                               "Check memory DIMM configuration\n");
+                       amd64_warn("Hardware rejected DRAM ECC enable,"
+                                  "check memory DIMM configuration.\n");
+                       ret = false;
                } else {
-                       amd64_printk(KERN_DEBUG,
-                               "Hardware accepted DRAM ECC Enable\n");
+                       amd64_info("Hardware accepted DRAM ECC Enable\n");
                }
        } else {
-               pvt->flags.nb_ecc_prev = 1;
+               s->flags.nb_ecc_prev = 1;
        }
 
-       debugf0("NBCFG(2)= 0x%x  CHIPKILL= %s ECC_ENABLE= %s\n", value,
-               (value & K8_NBCFG_CHIPKILL) ? "Enabled" : "Disabled",
-               (value & K8_NBCFG_ECC_ENABLE) ? "Enabled" : "Disabled");
+       debugf0("2: node %d, NBCFG=0x%08x[ChipKillEccCap: %d|DramEccEn: %d]\n",
+               nid, value,
+               !!(value & K8_NBCFG_CHIPKILL), !!(value & K8_NBCFG_ECC_ENABLE));
 
-       pvt->ctl_error_info.nbcfg = value;
+       return ret;
 }
 
-static void amd64_restore_ecc_error_reporting(struct amd64_pvt *pvt)
+static void restore_ecc_error_reporting(struct ecc_settings *s, u8 nid,
+                                       struct pci_dev *F3)
 {
        u32 value, mask = K8_NBCTL_CECCEn | K8_NBCTL_UECCEn;
 
-       if (!pvt->nbctl_mcgctl_saved)
+       if (!s->nbctl_valid)
                return;
 
-       amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCTL, &value);
+       amd64_read_pci_cfg(F3, K8_NBCTL, &value);
        value &= ~mask;
-       value |= pvt->old_nbctl;
+       value |= s->old_nbctl;
 
-       pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value);
+       pci_write_config_dword(F3, K8_NBCTL, value);
 
-       /* restore previous BIOS DRAM ECC "off" setting which we force-enabled */
-       if (!pvt->flags.nb_ecc_prev) {
-               amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCFG, &value);
+       /* restore previous BIOS DRAM ECC "off" setting we force-enabled */
+       if (!s->flags.nb_ecc_prev) {
+               amd64_read_pci_cfg(F3, K8_NBCFG, &value);
                value &= ~K8_NBCFG_ECC_ENABLE;
-               pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCFG, value);
+               pci_write_config_dword(F3, K8_NBCFG, value);
        }
 
        /* restore the NB Enable MCGCTL bit */
-       if (amd64_toggle_ecc_err_reporting(pvt, OFF))
-               amd64_printk(KERN_WARNING, "Error restoring NB MCGCTL settings!\n");
+       if (toggle_ecc_err_reporting(s, nid, OFF))
+               amd64_warn("Error restoring NB MCGCTL settings!\n");
 }
 
 /*
- * EDAC requires that the BIOS have ECC enabled before taking over the
- * processing of ECC errors. This is because the BIOS can properly initialize
- * the memory system completely. A command line option allows to force-enable
- * hardware ECC later in amd64_enable_ecc_error_reporting().
+ * EDAC requires that the BIOS have ECC enabled before
+ * taking over the processing of ECC errors. A command line
+ * option allows to force-enable hardware ECC later in
+ * enable_ecc_error_reporting().
  */
 static const char *ecc_msg =
        "ECC disabled in the BIOS or no ECC capability, module will not load.\n"
@@ -2563,38 +2417,28 @@ static const char *ecc_msg =
        "'ecc_enable_override'.\n"
        " (Note that use of the override may cause unknown side effects.)\n";
 
-static int amd64_check_ecc_enabled(struct amd64_pvt *pvt)
+static bool ecc_enabled(struct pci_dev *F3, u8 nid)
 {
        u32 value;
-       u8 ecc_enabled = 0;
+       u8 ecc_en = 0;
        bool nb_mce_en = false;
 
-       amd64_read_pci_cfg(pvt->misc_f3_ctl, K8_NBCFG, &value);
+       amd64_read_pci_cfg(F3, K8_NBCFG, &value);
 
-       ecc_enabled = !!(value & K8_NBCFG_ECC_ENABLE);
-       if (!ecc_enabled)
-               amd64_printk(KERN_NOTICE, "This node reports that Memory ECC "
-                            "is currently disabled, set F3x%x[22] (%s).\n",
-                            K8_NBCFG, pci_name(pvt->misc_f3_ctl));
-       else
-               amd64_printk(KERN_INFO, "ECC is enabled by BIOS.\n");
+       ecc_en = !!(value & K8_NBCFG_ECC_ENABLE);
+       amd64_info("DRAM ECC %s.\n", (ecc_en ? "enabled" : "disabled"));
 
-       nb_mce_en = amd64_nb_mce_bank_enabled_on_node(pvt->mc_node_id);
+       nb_mce_en = amd64_nb_mce_bank_enabled_on_node(nid);
        if (!nb_mce_en)
-               amd64_printk(KERN_NOTICE, "NB MCE bank disabled, set MSR "
+               amd64_notice("NB MCE bank disabled, set MSR "
                             "0x%08x[4] on node %d to enable.\n",
-                            MSR_IA32_MCG_CTL, pvt->mc_node_id);
+                            MSR_IA32_MCG_CTL, nid);
 
-       if (!ecc_enabled || !nb_mce_en) {
-               if (!ecc_enable_override) {
-                       amd64_printk(KERN_NOTICE, "%s", ecc_msg);
-                       return -ENODEV;
-               } else {
-                       amd64_printk(KERN_WARNING, "Forcing ECC checking on!\n");
-               }
+       if (!ecc_en || !nb_mce_en) {
+               amd64_notice("%s", ecc_msg);
+               return false;
        }
-
-       return 0;
+       return true;
 }
 
 struct mcidev_sysfs_attribute sysfs_attrs[ARRAY_SIZE(amd64_dbg_attrs) +
@@ -2603,22 +2447,23 @@ struct mcidev_sysfs_attribute sysfs_attrs[ARRAY_SIZE(amd64_dbg_attrs) +
 
 struct mcidev_sysfs_attribute terminator = { .attr = { .name = NULL } };
 
-static void amd64_set_mc_sysfs_attributes(struct mem_ctl_info *mci)
+static void set_mc_sysfs_attrs(struct mem_ctl_info *mci)
 {
        unsigned int i = 0, j = 0;
 
        for (; i < ARRAY_SIZE(amd64_dbg_attrs); i++)
                sysfs_attrs[i] = amd64_dbg_attrs[i];
 
-       for (j = 0; j < ARRAY_SIZE(amd64_inj_attrs); j++, i++)
-               sysfs_attrs[i] = amd64_inj_attrs[j];
+       if (boot_cpu_data.x86 >= 0x10)
+               for (j = 0; j < ARRAY_SIZE(amd64_inj_attrs); j++, i++)
+                       sysfs_attrs[i] = amd64_inj_attrs[j];
 
        sysfs_attrs[i] = terminator;
 
        mci->mc_driver_sysfs_attributes = sysfs_attrs;
 }
 
-static void amd64_setup_mci_misc_attributes(struct mem_ctl_info *mci)
+static void setup_mci_misc_attrs(struct mem_ctl_info *mci)
 {
        struct amd64_pvt *pvt = mci->pvt_info;
 
@@ -2634,8 +2479,8 @@ static void amd64_setup_mci_misc_attributes(struct mem_ctl_info *mci)
        mci->edac_cap           = amd64_determine_edac_cap(pvt);
        mci->mod_name           = EDAC_MOD_STR;
        mci->mod_ver            = EDAC_AMD64_VERSION;
-       mci->ctl_name           = get_amd_family_name(pvt->mc_type_index);
-       mci->dev_name           = pci_name(pvt->dram_f2_ctl);
+       mci->ctl_name           = pvt->ctl_name;
+       mci->dev_name           = pci_name(pvt->F2);
        mci->ctl_page_to_phys   = NULL;
 
        /* memory scrubber interface */
@@ -2644,111 +2489,94 @@ static void amd64_setup_mci_misc_attributes(struct mem_ctl_info *mci)
 }
 
 /*
- * Init stuff for this DRAM Controller device.
- *
- * Due to a hardware feature on Fam10h CPUs, the Enable Extended Configuration
- * Space feature MUST be enabled on ALL Processors prior to actually reading
- * from the ECS registers. Since the loading of the module can occur on any
- * 'core', and cores don't 'see' all the other processors ECS data when the
- * others are NOT enabled. Our solution is to first enable ECS access in this
- * routine on all processors, gather some data in a amd64_pvt structure and
- * later come back in a finish-setup function to perform that final
- * initialization. See also amd64_init_2nd_stage() for that.
+ * returns a pointer to the family descriptor on success, NULL otherwise.
  */
-static int amd64_probe_one_instance(struct pci_dev *dram_f2_ctl,
-                                   int mc_type_index)
+static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)
+{
+       u8 fam = boot_cpu_data.x86;
+       struct amd64_family_type *fam_type = NULL;
+
+       switch (fam) {
+       case 0xf:
+               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:
+               amd64_err("Unsupported family!\n");
+               return NULL;
+       }
+
+       pvt->ext_model = boot_cpu_data.x86_model >> 4;
+
+       amd64_info("%s %sdetected (node %d).\n", pvt->ctl_name,
+                    (fam == 0xf ?
+                               (pvt->ext_model >= K8_REV_F  ? "revF or later "
+                                                            : "revE or earlier ")
+                                : ""), pvt->mc_node_id);
+       return fam_type;
+}
+
+static int amd64_init_one_instance(struct pci_dev *F2)
 {
        struct amd64_pvt *pvt = NULL;
+       struct amd64_family_type *fam_type = NULL;
+       struct mem_ctl_info *mci = NULL;
        int err = 0, ret;
+       u8 nid = get_node_id(F2);
 
        ret = -ENOMEM;
        pvt = kzalloc(sizeof(struct amd64_pvt), GFP_KERNEL);
        if (!pvt)
-               goto err_exit;
+               goto err_ret;
 
-       pvt->mc_node_id = get_node_id(dram_f2_ctl);
+       pvt->mc_node_id = nid;
+       pvt->F2 = F2;
 
-       pvt->dram_f2_ctl        = dram_f2_ctl;
-       pvt->ext_model          = boot_cpu_data.x86_model >> 4;
-       pvt->mc_type_index      = mc_type_index;
-       pvt->ops                = family_ops(mc_type_index);
+       ret = -EINVAL;
+       fam_type = amd64_per_family_init(pvt);
+       if (!fam_type)
+               goto err_free;
 
-       /*
-        * We have the dram_f2_ctl device as an argument, now go reserve its
-        * sibling devices from the PCI system.
-        */
        ret = -ENODEV;
-       err = amd64_reserve_mc_sibling_devices(pvt, mc_type_index);
+       err = reserve_mc_sibling_devs(pvt, fam_type->f1_id, fam_type->f3_id);
        if (err)
                goto err_free;
 
-       ret = -EINVAL;
-       err = amd64_check_ecc_enabled(pvt);
-       if (err)
-               goto err_put;
-
-       /*
-        * Key operation here: setup of HW prior to performing ops on it. Some
-        * setup is required to access ECS data. After this is performed, the
-        * 'teardown' function must be called upon error and normal exit paths.
-        */
-       if (boot_cpu_data.x86 >= 0x10)
-               amd64_setup(pvt);
-
-       /*
-        * Save the pointer to the private data for use in 2nd initialization
-        * stage
-        */
-       pvt_lookup[pvt->mc_node_id] = pvt;
-
-       return 0;
-
-err_put:
-       amd64_free_mc_sibling_devices(pvt);
-
-err_free:
-       kfree(pvt);
-
-err_exit:
-       return ret;
-}
-
-/*
- * This is the finishing stage of the init code. Needs to be performed after all
- * MCs' hardware have been prepped for accessing extended config space.
- */
-static int amd64_init_2nd_stage(struct amd64_pvt *pvt)
-{
-       int node_id = pvt->mc_node_id;
-       struct mem_ctl_info *mci;
-       int ret = -ENODEV;
-
-       amd64_read_mc_registers(pvt);
+       read_mc_regs(pvt);
 
        /*
         * We need to determine how many memory channels there are. Then use
         * that information for calculating the size of the dynamic instance
-        * tables in the 'mci' structure
+        * tables in the 'mci' structure.
         */
+       ret = -EINVAL;
        pvt->channel_count = pvt->ops->early_channel_count(pvt);
        if (pvt->channel_count < 0)
-               goto err_exit;
+               goto err_siblings;
 
        ret = -ENOMEM;
-       mci = edac_mc_alloc(0, pvt->cs_count, pvt->channel_count, node_id);
+       mci = edac_mc_alloc(0, pvt->cs_count, pvt->channel_count, nid);
        if (!mci)
-               goto err_exit;
+               goto err_siblings;
 
        mci->pvt_info = pvt;
+       mci->dev = &pvt->F2->dev;
 
-       mci->dev = &pvt->dram_f2_ctl->dev;
-       amd64_setup_mci_misc_attributes(mci);
+       setup_mci_misc_attrs(mci);
 
-       if (amd64_init_csrows(mci))
+       if (init_csrows(mci))
                mci->edac_cap = EDAC_FLAG_NONE;
 
-       amd64_enable_ecc_error_reporting(mci);
-       amd64_set_mc_sysfs_attributes(mci);
+       set_mc_sysfs_attrs(mci);
 
        ret = -ENODEV;
        if (edac_mc_add_mc(mci)) {
@@ -2756,54 +2584,77 @@ static int amd64_init_2nd_stage(struct amd64_pvt *pvt)
                goto err_add_mc;
        }
 
-       mci_lookup[node_id] = mci;
-       pvt_lookup[node_id] = NULL;
-
        /* register stuff with EDAC MCE */
        if (report_gart_errors)
                amd_report_gart_errors(true);
 
        amd_register_ecc_decoder(amd64_decode_bus_error);
 
+       mcis[nid] = mci;
+
+       atomic_inc(&drv_instances);
+
        return 0;
 
 err_add_mc:
        edac_mc_free(mci);
 
-err_exit:
-       debugf0("failure to init 2nd stage: ret=%d\n", ret);
-
-       amd64_restore_ecc_error_reporting(pvt);
-
-       if (boot_cpu_data.x86 > 0xf)
-               amd64_teardown(pvt);
-
-       amd64_free_mc_sibling_devices(pvt);
+err_siblings:
+       free_mc_sibling_devs(pvt);
 
-       kfree(pvt_lookup[pvt->mc_node_id]);
-       pvt_lookup[node_id] = NULL;
+err_free:
+       kfree(pvt);
 
+err_ret:
        return ret;
 }
 
-
-static int __devinit amd64_init_one_instance(struct pci_dev *pdev,
-                                const struct pci_device_id *mc_type)
+static int __devinit amd64_probe_one_instance(struct pci_dev *pdev,
+                                            const struct pci_device_id *mc_type)
 {
+       u8 nid = get_node_id(pdev);
+       struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
+       struct ecc_settings *s;
        int ret = 0;
 
-       debugf0("(MC node=%d,mc_type='%s')\n", get_node_id(pdev),
-               get_amd_family_name(mc_type->driver_data));
-
        ret = pci_enable_device(pdev);
-       if (ret < 0)
-               ret = -EIO;
-       else
-               ret = amd64_probe_one_instance(pdev, mc_type->driver_data);
-
-       if (ret < 0)
+       if (ret < 0) {
                debugf0("ret=%d\n", ret);
+               return -EIO;
+       }
+
+       ret = -ENOMEM;
+       s = kzalloc(sizeof(struct ecc_settings), GFP_KERNEL);
+       if (!s)
+               goto err_out;
+
+       ecc_stngs[nid] = s;
+
+       if (!ecc_enabled(F3, nid)) {
+               ret = -ENODEV;
+
+               if (!ecc_enable_override)
+                       goto err_enable;
+
+               amd64_warn("Forcing ECC on!\n");
 
+               if (!enable_ecc_error_reporting(s, nid, F3))
+                       goto err_enable;
+       }
+
+       ret = amd64_init_one_instance(pdev);
+       if (ret < 0) {
+               amd64_err("Error probing instance: %d\n", nid);
+               restore_ecc_error_reporting(s, nid, F3);
+       }
+
+       return ret;
+
+err_enable:
+       kfree(s);
+       ecc_stngs[nid] = NULL;
+
+err_out:
        return ret;
 }
 
@@ -2811,6 +2662,9 @@ static void __devexit amd64_remove_one_instance(struct pci_dev *pdev)
 {
        struct mem_ctl_info *mci;
        struct amd64_pvt *pvt;
+       u8 nid = get_node_id(pdev);
+       struct pci_dev *F3 = node_to_amd_nb(nid)->misc;
+       struct ecc_settings *s = ecc_stngs[nid];
 
        /* Remove from EDAC CORE tracking list */
        mci = edac_mc_del_mc(&pdev->dev);
@@ -2819,20 +2673,20 @@ static void __devexit amd64_remove_one_instance(struct pci_dev *pdev)
 
        pvt = mci->pvt_info;
 
-       amd64_restore_ecc_error_reporting(pvt);
-
-       if (boot_cpu_data.x86 > 0xf)
-               amd64_teardown(pvt);
+       restore_ecc_error_reporting(s, nid, F3);
 
-       amd64_free_mc_sibling_devices(pvt);
+       free_mc_sibling_devs(pvt);
 
        /* unregister from EDAC MCE */
        amd_report_gart_errors(false);
        amd_unregister_ecc_decoder(amd64_decode_bus_error);
 
+       kfree(ecc_stngs[nid]);
+       ecc_stngs[nid] = NULL;
+
        /* Free the EDAC CORE resources */
        mci->pvt_info = NULL;
-       mci_lookup[pvt->mc_node_id] = NULL;
+       mcis[nid] = NULL;
 
        kfree(pvt);
        edac_mc_free(mci);
@@ -2851,7 +2705,6 @@ static const struct pci_device_id amd64_pci_table[] __devinitdata = {
                .subdevice      = PCI_ANY_ID,
                .class          = 0,
                .class_mask     = 0,
-               .driver_data    = K8_CPUS
        },
        {
                .vendor         = PCI_VENDOR_ID_AMD,
@@ -2860,16 +2713,6 @@ static const struct pci_device_id amd64_pci_table[] __devinitdata = {
                .subdevice      = PCI_ANY_ID,
                .class          = 0,
                .class_mask     = 0,
-               .driver_data    = F10_CPUS
-       },
-       {
-               .vendor         = PCI_VENDOR_ID_AMD,
-               .device         = PCI_DEVICE_ID_AMD_11H_NB_DRAM,
-               .subvendor      = PCI_ANY_ID,
-               .subdevice      = PCI_ANY_ID,
-               .class          = 0,
-               .class_mask     = 0,
-               .driver_data    = F11_CPUS
        },
        {0, }
 };
@@ -2877,12 +2720,12 @@ MODULE_DEVICE_TABLE(pci, amd64_pci_table);
 
 static struct pci_driver amd64_pci_driver = {
        .name           = EDAC_MOD_STR,
-       .probe          = amd64_init_one_instance,
+       .probe          = amd64_probe_one_instance,
        .remove         = __devexit_p(amd64_remove_one_instance),
        .id_table       = amd64_pci_table,
 };
 
-static void amd64_setup_pci_device(void)
+static void setup_pci_device(void)
 {
        struct mem_ctl_info *mci;
        struct amd64_pvt *pvt;
@@ -2890,13 +2733,12 @@ static void amd64_setup_pci_device(void)
        if (amd64_ctl_pci)
                return;
 
-       mci = mci_lookup[0];
+       mci = mcis[0];
        if (mci) {
 
                pvt = mci->pvt_info;
                amd64_ctl_pci =
-                       edac_pci_create_generic_ctl(&pvt->dram_f2_ctl->dev,
-                                                   EDAC_MOD_STR);
+                       edac_pci_create_generic_ctl(&pvt->F2->dev, EDAC_MOD_STR);
 
                if (!amd64_ctl_pci) {
                        pr_warning("%s(): Unable to create PCI control\n",
@@ -2910,51 +2752,50 @@ static void amd64_setup_pci_device(void)
 
 static int __init amd64_edac_init(void)
 {
-       int nb, err = -ENODEV;
-       bool load_ok = false;
+       int err = -ENODEV;
 
        edac_printk(KERN_INFO, EDAC_MOD_STR, EDAC_AMD64_VERSION "\n");
 
        opstate_init();
 
-       if (cache_k8_northbridges() < 0)
+       if (amd_cache_northbridges() < 0)
+               goto err_ret;
+
+       err = -ENOMEM;
+       mcis      = kzalloc(amd_nb_num() * sizeof(mcis[0]), GFP_KERNEL);
+       ecc_stngs = kzalloc(amd_nb_num() * sizeof(ecc_stngs[0]), GFP_KERNEL);
+       if (!(mcis && ecc_stngs))
                goto err_ret;
 
        msrs = msrs_alloc();
        if (!msrs)
-               goto err_ret;
+               goto err_free;
 
        err = pci_register_driver(&amd64_pci_driver);
        if (err)
                goto err_pci;
 
-       /*
-        * At this point, the array 'pvt_lookup[]' contains pointers to alloc'd
-        * amd64_pvt structs. These will be used in the 2nd stage init function
-        * to finish initialization of the MC instances.
-        */
        err = -ENODEV;
-       for (nb = 0; nb < k8_northbridges.num; nb++) {
-               if (!pvt_lookup[nb])
-                       continue;
+       if (!atomic_read(&drv_instances))
+               goto err_no_instances;
 
-               err = amd64_init_2nd_stage(pvt_lookup[nb]);
-               if (err)
-                       goto err_2nd_stage;
-
-               load_ok = true;
-       }
-
-       if (load_ok) {
-               amd64_setup_pci_device();
-               return 0;
-       }
+       setup_pci_device();
+       return 0;
 
-err_2nd_stage:
+err_no_instances:
        pci_unregister_driver(&amd64_pci_driver);
+
 err_pci:
        msrs_free(msrs);
        msrs = NULL;
+
+err_free:
+       kfree(mcis);
+       mcis = NULL;
+
+       kfree(ecc_stngs);
+       ecc_stngs = NULL;
+
 err_ret:
        return err;
 }
@@ -2966,6 +2807,12 @@ static void __exit amd64_edac_exit(void)
 
        pci_unregister_driver(&amd64_pci_driver);
 
+       kfree(ecc_stngs);
+       ecc_stngs = NULL;
+
+       kfree(mcis);
+       mcis = NULL;
+
        msrs_free(msrs);
        msrs = NULL;
 }