Merge branch 'stable/platform-pci-fixes' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / edac / amd64_edac.c
index 98c0150..4a5ecc5 100644 (file)
@@ -15,9 +15,14 @@ module_param(ecc_enable_override, int, 0644);
 
 static struct msr __percpu *msrs;
 
+/*
+ * 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 amd64_pvt **pvts;
+static struct ecc_settings **ecc_stngs;
 
 /*
  * Address to DRAM bank mapping: see F2x80 for K8 and F2x[1,0]80 for Fam10 and
@@ -72,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},
@@ -146,14 +155,12 @@ static int __amd64_set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate)
        }
 
        scrubval = scrubrates[i].scrubval;
-       if (scrubval)
-               amd64_info("Setting scrub rate bandwidth: %u\n",
-                          scrubrates[i].bandwidth);
-       else
-               amd64_info("Turning scrubbing off.\n");
 
        pci_write_bits32(ctl, K8_SCRCTRL, scrubval, 0x001F);
 
+       if (scrubval)
+               return scrubrates[i].bandwidth;
+
        return 0;
 }
 
@@ -164,11 +171,11 @@ static int amd64_set_scrub_rate(struct mem_ctl_info *mci, u32 bw)
        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->F3, K8_SCRCTRL, &scrubval);
 
@@ -178,13 +185,11 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
 
        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 */
@@ -1204,31 +1209,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->F3, 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->F3, 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->F3, 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->F3, F10_NB_CFG_HIGH, reg);
-}
-
 static u64 f10_get_error_address(struct mem_ctl_info *mci,
                        struct err_regs *info)
 {
@@ -1251,8 +1231,6 @@ static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
 
        /* read the 'raw' DRAM BASE Address register */
        amd64_read_pci_cfg(pvt->F1, low_offset, &low_base);
-
-       /* Read from the ECS data register */
        amd64_read_pci_cfg(pvt->F1, high_offset, &high_base);
 
        /* Extract parts into separate data entries */
@@ -1271,8 +1249,6 @@ static void f10_read_dram_base_limit(struct amd64_pvt *pvt, int dram)
 
        /* read the 'raw' LIMIT registers */
        amd64_read_pci_cfg(pvt->F1, low_offset, &low_limit);
-
-       /* Read from the ECS data register for the HIGH portion */
        amd64_read_pci_cfg(pvt->F1, high_offset, &high_limit);
 
        pvt->dram_DstNode[dram] = (low_limit & 0x7);
@@ -1974,8 +1950,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 */
@@ -2021,8 +1997,7 @@ void amd64_decode_bus_error(int node_id, struct mce *m, u32 nbcfg)
  * 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, u16 f1_id,
-                                           u16 f3_id)
+static int reserve_mc_sibling_devs(struct amd64_pvt *pvt, u16 f1_id, u16 f3_id)
 {
        /* Reserve the ADDRESS MAP Device */
        pvt->F1 = pci_get_related_function(pvt->F2->vendor, f1_id, pvt->F2);
@@ -2052,7 +2027,7 @@ static int amd64_reserve_mc_sibling_devices(struct amd64_pvt *pvt, u16 f1_id,
        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->F1);
        pci_dev_put(pvt->F3);
@@ -2062,7 +2037,7 @@ static void amd64_free_mc_sibling_devices(struct amd64_pvt *pvt)
  * 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;
@@ -2213,21 +2188,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->F3, 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];
@@ -2322,7 +2298,7 @@ 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;
@@ -2332,7 +2308,7 @@ static int amd64_toggle_ecc_err_reporting(struct amd64_pvt *pvt, bool on)
                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);
 
@@ -2342,14 +2318,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;
                }
        }
@@ -2360,87 +2336,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->F3, 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->F3, 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_warn("Error enabling ECC reporting over MCGCTL!\n");
+       value |= mask;
+       pci_write_config_dword(F3, K8_NBCTL, value);
 
-       amd64_read_pci_cfg(pvt->F3, 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_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->F3, K8_NBCFG, value);
+               pci_write_config_dword(F3, K8_NBCFG, value);
 
-               amd64_read_pci_cfg(pvt->F3, K8_NBCFG, &value);
+               amd64_read_pci_cfg(F3, K8_NBCFG, &value);
 
                if (!(value & K8_NBCFG_ECC_ENABLE)) {
                        amd64_warn("Hardware rejected DRAM ECC enable,"
                                   "check memory DIMM configuration.\n");
+                       ret = false;
                } else {
                        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->F3, 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->F3, 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->F3, 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->F3, 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))
+       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"
@@ -2448,33 +2429,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->F3, K8_NBCFG, &value);
+       amd64_read_pci_cfg(F3, K8_NBCFG, &value);
 
-       ecc_enabled = !!(value & K8_NBCFG_ECC_ENABLE);
-       amd64_info("DRAM ECC %s.\n", (ecc_enabled ? "enabled" : "disabled"));
+       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_notice("NB MCE bank disabled, "
-                            "set MSR 0x%08x[4] on node %d to enable.\n",
-                            MSR_IA32_MCG_CTL, pvt->mc_node_id);
-
-       if (!ecc_enabled || !nb_mce_en) {
-               if (!ecc_enable_override) {
-                       amd64_notice("%s", ecc_msg);
-                       return -ENODEV;
-               } else {
-                       amd64_warn("Forcing ECC on!\n");
-               }
-       }
+               amd64_notice("NB MCE bank disabled, set MSR "
+                            "0x%08x[4] on node %d to enable.\n",
+                            MSR_IA32_MCG_CTL, nid);
 
-       return 0;
+       if (!ecc_en || !nb_mce_en) {
+               amd64_notice("%s", ecc_msg);
+               return false;
+       }
+       return true;
 }
 
 struct mcidev_sysfs_attribute sysfs_attrs[ARRAY_SIZE(amd64_dbg_attrs) +
@@ -2483,22 +2459,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;
 
@@ -2560,30 +2537,20 @@ static struct amd64_family_type *amd64_per_family_init(struct amd64_pvt *pvt)
        return fam_type;
 }
 
-/*
- * 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.
- */
-static int amd64_probe_one_instance(struct pci_dev *F2)
+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(F2);
+       pvt->mc_node_id = nid;
        pvt->F2 = F2;
 
        ret = -EINVAL;
@@ -2592,78 +2559,36 @@ static int amd64_probe_one_instance(struct pci_dev *F2)
                goto err_free;
 
        ret = -ENODEV;
-       err = amd64_reserve_mc_sibling_devices(pvt, fam_type->f1_id,
-                                               fam_type->f3_id);
+       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
-        */
-       pvts[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;
-       amd64_setup_mci_misc_attributes(mci);
 
-       if (amd64_init_csrows(mci))
+       setup_mci_misc_attrs(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)) {
@@ -2671,40 +2596,37 @@ static int amd64_init_2nd_stage(struct amd64_pvt *pvt)
                goto err_add_mc;
        }
 
-       mcis[node_id] = mci;
-       pvts[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);
+err_siblings:
+       free_mc_sibling_devs(pvt);
 
-       amd64_free_mc_sibling_devices(pvt);
-
-       kfree(pvts[pvt->mc_node_id]);
-       pvts[node_id] = NULL;
+err_free:
+       kfree(pvt);
 
+err_ret:
        return ret;
 }
 
-
-static int __devinit amd64_init_one_instance(struct pci_dev *pdev,
+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;
 
        ret = pci_enable_device(pdev);
@@ -2713,10 +2635,38 @@ static int __devinit amd64_init_one_instance(struct pci_dev *pdev,
                return -EIO;
        }
 
-       ret = amd64_probe_one_instance(pdev);
-       if (ret < 0)
-               amd64_err("Error probing instance: %d\n", get_node_id(pdev));
+       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;
 }
 
@@ -2724,6 +2674,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);
@@ -2732,20 +2685,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;
-       mcis[pvt->mc_node_id] = NULL;
+       mcis[nid] = NULL;
 
        kfree(pvt);
        edac_mc_free(mci);
@@ -2779,12 +2732,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;
@@ -2811,8 +2764,7 @@ 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");
 
@@ -2822,48 +2774,40 @@ static int __init amd64_edac_init(void)
                goto err_ret;
 
        err = -ENOMEM;
-       pvts = kzalloc(amd_nb_num() * sizeof(pvts[0]), GFP_KERNEL);
-       mcis = kzalloc(amd_nb_num() * sizeof(mcis[0]), GFP_KERNEL);
-       if (!(pvts && mcis))
+       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 'pvts[]' 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 < amd_nb_num(); nb++) {
-               if (!pvts[nb])
-                       continue;
+       if (!atomic_read(&drv_instances))
+               goto err_no_instances;
 
-               err = amd64_init_2nd_stage(pvts[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;
 }
@@ -2875,12 +2819,12 @@ static void __exit amd64_edac_exit(void)
 
        pci_unregister_driver(&amd64_pci_driver);
 
+       kfree(ecc_stngs);
+       ecc_stngs = NULL;
+
        kfree(mcis);
        mcis = NULL;
 
-       kfree(pvts);
-       pvts = NULL;
-
        msrs_free(msrs);
        msrs = NULL;
 }