Merge branch 'mce-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 7 Jan 2011 22:54:03 +0000 (14:54 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 7 Jan 2011 22:54:03 +0000 (14:54 -0800)
* 'mce-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp:
  EDAC, MCE: Fix NB error formatting
  EDAC, MCE: Use BIT_64() to eliminate warnings on 32-bit
  EDAC, MCE: Enable MCE decoding on F15h
  EDAC, MCE: Allow F15h bank 6 MCE injection
  EDAC, MCE: Shorten error report formatting
  EDAC, MCE: Overhaul error fields extraction macros
  EDAC, MCE: Add F15h FP MCE decoder
  EDAC, MCE: Add F15 EX MCE decoder
  EDAC, MCE: Add an F15h NB MCE decoder
  EDAC, MCE: No F15h LS MCE decoder
  EDAC, MCE: Add F15h CU MCE decoder
  EDAC, MCE: Add F15h IC MCE decoder
  EDAC, MCE: Add F15h DC MCE decoder
  EDAC, MCE: Select extended error code mask

1  2 
drivers/edac/amd64_edac.c

@@@ -15,14 -15,10 +15,14 @@@ module_param(ecc_enable_override, int, 
  
  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
@@@ -66,7 -62,7 +66,7 @@@ static int ddr3_dbam[] = { [0]                = -1
                           [5 ... 6]    = 1024,
                           [7 ... 8]    = 2048,
                           [9 ... 10]   = 4096,
 -                         [11] = 8192,
 +                         [11]         = 8192,
  };
  
  /*
   *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},
   * 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;
                 * 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)
        }
  
        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 */
@@@ -298,7 -314,9 +298,7 @@@ static struct mem_ctl_info *find_mc_by_
        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;
        }
  
  
        /* 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;
        }
  
@@@ -768,8 -788,9 +768,8 @@@ static int sys_addr_to_csrow(struct mem
        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;
  }
  
@@@ -780,6 -801,21 +780,6 @@@ static u16 extract_syndrome(struct 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.
@@@ -857,7 -893,8 +857,7 @@@ static void amd64_dump_misc_regs(struc
                return;
        }
  
 -      amd64_printk(KERN_INFO, "using %s syndromes.\n",
 -                   ((pvt->syn_type == 8) ? "x8" : "x4"));
 +      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))
  /* 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);
  }
  
  /*
@@@ -928,8 -965,14 +928,8 @@@ static void amd64_set_dct_base_and_mask
                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;
        }
  }
  
@@@ -944,14 -987,14 +944,14 @@@ static void amd64_read_dct_base_mask(st
  
        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);
  
        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);
        }
  }
  
 -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;
  
                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;
  }
@@@ -1010,16 -1053,17 +1010,16 @@@ static int k8_early_channel_count(struc
  {
        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;
@@@ -1046,14 -1090,14 +1046,14 @@@ static void k8_read_dram_base_limit(str
        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
@@@ -1083,8 -1127,9 +1083,8 @@@ static void k8_map_sysaddr_to_csrow(str
                         * 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;
                }
         */
        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;
@@@ -1174,7 -1220,7 +1174,7 @@@ static int f10_early_channel_count(stru
         * 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++) {
        if (channels > 2)
                channels = 2;
  
 -      debugf0("MCT channel count: %d\n", channels);
 +      amd64_info("MCT channel count: %d\n", channels);
  
        return channels;
  
@@@ -1209,6 -1255,31 +1209,6 @@@ static int f10_dbam_to_chip_select(stru
        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)
  {
@@@ -1230,8 -1301,10 +1230,8 @@@ static void f10_read_dram_base_limit(st
        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);
        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;
  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",
                        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);
  }
  
@@@ -1421,7 -1496,7 +1421,7 @@@ static int f10_lookup_addr_in_dct(u32 i
        int cs_found = -EINVAL;
        int csrow;
  
 -      mci = mci_lookup[nid];
 +      mci = mcis[nid];
        if (!mci)
                return cs_found;
  
@@@ -1663,17 -1738,28 +1663,17 @@@ static void amd64_debug_display_dimm_si
                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,
                }
        },
        [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,
@@@ -1871,7 -1970,8 +1871,7 @@@ static int get_channel_from_ecc_syndrom
                                          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;
        }
  
@@@ -1889,15 -1989,17 +1889,15 @@@ static void amd64_handle_ce(struct mem_
        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);
  }
@@@ -1914,8 -2016,9 +1914,8 @@@ static void amd64_handle_ue(struct mem_
  
        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;
        }
         */
        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;
        }
  
        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);
  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 */
  
  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;
  }
  
  /*
 - * 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;
        } 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);
  
        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 &&
@@@ -2188,22 -2321,21 +2188,22 @@@ static u32 amd64_csrow_nr_pages(int csr
   * 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];
                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",
@@@ -2272,7 -2404,8 +2272,7 @@@ static bool amd64_nb_mce_bank_enabled_o
        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;
        }
  
        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);
  
  
                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;
                }
        }
        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;
 +      }
 +
 +      amd64_read_pci_cfg(F3, K8_NBCTL, &value);
  
 -      /* turn on UECCn and CECCEn bits */
 -      pvt->old_nbctl = value & mask;
 -      pvt->nbctl_mcgctl_saved = 1;
 +      /* turn on UECCEn and CECCEn bits */
 +      s->old_nbctl   = value & mask;
 +      s->nbctl_valid = true;
  
        value |= mask;
 -      pci_write_config_dword(pvt->misc_f3_ctl, K8_NBCTL, value);
 -
 -      if (amd64_toggle_ecc_err_reporting(pvt, ON))
 -              amd64_printk(KERN_WARNING, "Error enabling ECC reporting over "
 -                                         "MCGCTL!\n");
 +      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"
        "'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) +
  
  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;
  
        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 */
  }
  
  /*
 - * 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)) {
                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);
 +err_siblings:
 +      free_mc_sibling_devs(pvt);
  
 -      amd64_free_mc_sibling_devices(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;
  }
  
@@@ -2674,9 -2811,6 +2674,9 @@@ static void __devexit amd64_remove_one_
  {
        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);
  
        pvt = mci->pvt_info;
  
 -      amd64_restore_ecc_error_reporting(pvt);
 +      restore_ecc_error_reporting(s, nid, F3);
  
 -      if (boot_cpu_data.x86 > 0xf)
 -              amd64_teardown(pvt);
 -
 -      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);
@@@ -2717,6 -2851,7 +2717,6 @@@ static const struct pci_device_id amd64
                .subdevice      = PCI_ANY_ID,
                .class          = 0,
                .class_mask     = 0,
 -              .driver_data    = K8_CPUS
        },
        {
                .vendor         = PCI_VENDOR_ID_AMD,
                .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, }
  };
@@@ -2732,12 -2877,12 +2732,12 @@@ MODULE_DEVICE_TABLE(pci, amd64_pci_tabl
  
  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;
        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",
  
  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;
 -
 -              err = amd64_init_2nd_stage(pvt_lookup[nb]);
 -              if (err)
 -                      goto err_2nd_stage;
 +      if (!atomic_read(&drv_instances))
 +              goto err_no_instances;
  
 -              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;
  }
@@@ -2819,12 -2966,6 +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;
 +
        msrs_free(msrs);
        msrs = NULL;
  }