amd64_edac: enhance address to DRAM bank mapping
authorBorislav Petkov <borislav.petkov@amd.com>
Wed, 21 Oct 2009 11:44:36 +0000 (13:44 +0200)
committerBorislav Petkov <borislav.petkov@amd.com>
Mon, 7 Dec 2009 18:14:29 +0000 (19:14 +0100)
Add cs mode to cs size mapping tables for DDR2 and DDR3 and F10
and all K8 flavors and remove klugdy table of pseudo values. Add a
low_ops->dbam_to_cs member which is family-specific and replaces
low_ops->dbam_map_to_pages since the pages calculation is a one liner
now.

Further cleanups, while at it:

- shorten family name defines
- align amd64_family_types struct members

Signed-off-by: Borislav Petkov <borislav.petkov@amd.com>
drivers/edac/amd64_edac.c
drivers/edac/amd64_edac.h

index ed9b07a..7e67054 100644 (file)
@@ -19,26 +19,48 @@ static struct mem_ctl_info *mci_lookup[EDAC_MAX_NUMNODES];
 static struct amd64_pvt *pvt_lookup[EDAC_MAX_NUMNODES];
 
 /*
- * See F2x80 for K8 and F2x[1,0]80 for Fam10 and later. The table below is only
- * for DDR2 DRAM mapping.
+ * Address to DRAM bank mapping: see F2x80 for K8 and F2x[1,0]80 for Fam10 and
+ * later.
  */
-u32 revf_quad_ddr2_shift[] = {
-       0,      /* 0000b NULL DIMM (128mb) */
-       28,     /* 0001b 256mb */
-       29,     /* 0010b 512mb */
-       29,     /* 0011b 512mb */
-       29,     /* 0100b 512mb */
-       30,     /* 0101b 1gb */
-       30,     /* 0110b 1gb */
-       31,     /* 0111b 2gb */
-       31,     /* 1000b 2gb */
-       32,     /* 1001b 4gb */
-       32,     /* 1010b 4gb */
-       33,     /* 1011b 8gb */
-       0,      /* 1100b future */
-       0,      /* 1101b future */
-       0,      /* 1110b future */
-       0       /* 1111b future */
+static int ddr2_dbam_revCG[] = {
+                          [0]          = 32,
+                          [1]          = 64,
+                          [2]          = 128,
+                          [3]          = 256,
+                          [4]          = 512,
+                          [5]          = 1024,
+                          [6]          = 2048,
+};
+
+static int ddr2_dbam_revD[] = {
+                          [0]          = 32,
+                          [1]          = 64,
+                          [2 ... 3]    = 128,
+                          [4]          = 256,
+                          [5]          = 512,
+                          [6]          = 256,
+                          [7]          = 512,
+                          [8 ... 9]    = 1024,
+                          [10]         = 2048,
+};
+
+static int ddr2_dbam[] = { [0]         = 128,
+                          [1]          = 256,
+                          [2 ... 4]    = 512,
+                          [5 ... 6]    = 1024,
+                          [7 ... 8]    = 2048,
+                          [9 ... 10]   = 4096,
+                          [11]         = 8192,
+};
+
+static int ddr3_dbam[] = { [0]         = -1,
+                          [1]          = 256,
+                          [2]          = 512,
+                          [3 ... 4]    = -1,
+                          [5 ... 6]    = 1024,
+                          [7 ... 8]    = 2048,
+                          [9 ... 10]   = 4096,
+                          [11] = 8192,
 };
 
 /*
@@ -187,7 +209,7 @@ static int amd64_get_scrub_rate(struct mem_ctl_info *mci, u32 *bw)
 /* Map from a CSROW entry to the mask entry that operates on it */
 static inline u32 amd64_map_to_dcs_mask(struct amd64_pvt *pvt, int csrow)
 {
-       if (boot_cpu_data.x86 == 0xf && pvt->ext_model < OPTERON_CPU_REV_F)
+       if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F)
                return csrow;
        else
                return csrow >> 1;
@@ -435,7 +457,7 @@ int amd64_get_dram_hole_info(struct mem_ctl_info *mci, u64 *hole_base,
        u64 base;
 
        /* only revE and later have the DRAM Hole Address Register */
-       if (boot_cpu_data.x86 == 0xf && pvt->ext_model < OPTERON_CPU_REV_E) {
+       if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_E) {
                debugf1("  revision %d for node %d does not support DHAR\n",
                        pvt->ext_model, pvt->mc_node_id);
                return 1;
@@ -795,7 +817,7 @@ static void amd64_cpu_display_info(struct amd64_pvt *pvt)
                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 >= OPTERON_CPU_REV_F) ?
+                       (pvt->ext_model >= K8_REV_F) ?
                        "Rev F or later" : "Rev E or earlier");
        else
                /* we'll hardly ever ever get here */
@@ -811,7 +833,7 @@ static enum edac_type amd64_determine_edac_cap(struct amd64_pvt *pvt)
        int bit;
        enum dev_type edac_cap = EDAC_FLAG_NONE;
 
-       bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= OPTERON_CPU_REV_F)
+       bit = (boot_cpu_data.x86 > 0xf || pvt->ext_model >= K8_REV_F)
                ? 19
                : 17;
 
@@ -936,7 +958,7 @@ static void amd64_read_dbam_reg(struct amd64_pvt *pvt)
 static void amd64_set_dct_base_and_mask(struct amd64_pvt *pvt)
 {
 
-       if (boot_cpu_data.x86 == 0xf && pvt->ext_model < OPTERON_CPU_REV_F) {
+       if (boot_cpu_data.x86 == 0xf && pvt->ext_model < K8_REV_F) {
                pvt->dcsb_base          = REV_E_DCSB_BASE_BITS;
                pvt->dcsm_mask          = REV_E_DCSM_MASK_BITS;
                pvt->dcs_mask_notused   = REV_E_DCS_NOTUSED_BITS;
@@ -1009,7 +1031,7 @@ static enum mem_type amd64_determine_memory_type(struct amd64_pvt *pvt)
 {
        enum mem_type type;
 
-       if (boot_cpu_data.x86 >= 0x10 || pvt->ext_model >= OPTERON_CPU_REV_F) {
+       if (boot_cpu_data.x86 >= 0x10 || pvt->ext_model >= K8_REV_F) {
                /* Rev F and later */
                type = (pvt->dclr0 & BIT(16)) ? MEM_DDR2 : MEM_RDDR2;
        } else {
@@ -1042,7 +1064,7 @@ static int k8_early_channel_count(struct amd64_pvt *pvt)
        if (err)
                return err;
 
-       if ((boot_cpu_data.x86_model >> 4) >= OPTERON_CPU_REV_F) {
+       if ((boot_cpu_data.x86_model >> 4) >= K8_REV_F) {
                /* RevF (NPT) and later */
                flag = pvt->dclr0 & F10_WIDTH_128;
        } else {
@@ -1158,36 +1180,18 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
        }
 }
 
-/*
- * determrine the number of PAGES in for this DIMM's size based on its DRAM
- * Address Mapping.
- *
- * First step is to calc the number of bits to shift a value of 1 left to
- * indicate show many pages. Start with the DBAM value as the starting bits,
- * then proceed to adjust those shift bits, based on CPU rev and the table.
- * See BKDG on the DBAM
- */
-static int k8_dbam_map_to_pages(struct amd64_pvt *pvt, int dram_map)
+static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, int cs_mode)
 {
-       int nr_pages;
+       int *dbam_map;
 
-       if (pvt->ext_model >= OPTERON_CPU_REV_F) {
-               nr_pages = 1 << (revf_quad_ddr2_shift[dram_map] - PAGE_SHIFT);
-       } else {
-               /*
-                * RevE and less section; this line is tricky. It collapses the
-                * table used by RevD and later to one that matches revisions CG
-                * and earlier.
-                */
-               dram_map -= (pvt->ext_model >= OPTERON_CPU_REV_D) ?
-                               (dram_map > 8 ? 4 : (dram_map > 5 ?
-                               3 : (dram_map > 2 ? 1 : 0))) : 0;
-
-               /* 25 shift is 32MiB minimum DIMM size in RevE and prior */
-               nr_pages = 1 << (dram_map + 25 - PAGE_SHIFT);
-       }
+       if (pvt->ext_model >= K8_REV_F)
+               dbam_map = ddr2_dbam;
+       else if (pvt->ext_model >= K8_REV_D)
+               dbam_map = ddr2_dbam_revD;
+       else
+               dbam_map = ddr2_dbam_revCG;
 
-       return nr_pages;
+       return dbam_map[cs_mode];
 }
 
 /*
@@ -1249,9 +1253,16 @@ err_reg:
 
 }
 
-static int f10_dbam_map_to_pages(struct amd64_pvt *pvt, int dram_map)
+static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, int cs_mode)
 {
-       return 1 << (revf_quad_ddr2_shift[dram_map] - PAGE_SHIFT);
+       int *dbam_map;
+
+       if (pvt->dchr0 & DDR3_MODE || pvt->dchr1 & DDR3_MODE)
+               dbam_map = ddr3_dbam;
+       else
+               dbam_map = ddr2_dbam;
+
+       return dbam_map[cs_mode];
 }
 
 /* Enable extended configuration access via 0xCF8 feature */
@@ -1706,23 +1717,6 @@ static void f10_map_sysaddr_to_csrow(struct mem_ctl_info *mci,
 }
 
 /*
- * Input (@index) is the DBAM DIMM value (1 of 4) used as an index into a shift
- * table (revf_quad_ddr2_shift) which starts at 128MB DIMM size. Index of 0
- * indicates an empty DIMM slot, as reported by Hardware on empty slots.
- *
- * Normalize to 128MB by subracting 27 bit shift.
- */
-static int map_dbam_to_csrow_size(int index)
-{
-       int mega_bytes = 0;
-
-       if (index > 0 && index <= DBAM_MAX_VALUE)
-               mega_bytes = ((128 << (revf_quad_ddr2_shift[index]-27)));
-
-       return mega_bytes;
-}
-
-/*
  * debug routine to display the memory sizes of all logical DIMMs and its
  * CSROWs as well
  */
@@ -1734,7 +1728,7 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt)
 
        if (boot_cpu_data.x86 == 0xf) {
                /* K8 families < revF not supported yet */
-              if (pvt->ext_model < OPTERON_CPU_REV_F)
+              if (pvt->ext_model < K8_REV_F)
                        return;
               else
                       WARN_ON(ctrl != 0);
@@ -1753,11 +1747,11 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt)
 
                size0 = 0;
                if (dcsb[dimm*2] & K8_DCSB_CS_ENABLE)
-                       size0 = map_dbam_to_csrow_size(DBAM_DIMM(dimm, dbam));
+                       size0 = pvt->ops->dbam_to_cs(pvt, DBAM_DIMM(dimm, dbam));
 
                size1 = 0;
                if (dcsb[dimm*2 + 1] & K8_DCSB_CS_ENABLE)
-                       size1 = map_dbam_to_csrow_size(DBAM_DIMM(dimm, dbam));
+                       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, dimm * 2 + 1, size1);
@@ -1780,8 +1774,8 @@ static int f10_probe_valid_hardware(struct amd64_pvt *pvt)
         * If we are on a DDR3 machine, we don't know yet if
         * we support that properly at this time
         */
-       if ((pvt->dchr0 & F10_DCHR_Ddr3Mode) ||
-           (pvt->dchr1 & F10_DCHR_Ddr3Mode)) {
+       if ((pvt->dchr0 & DDR3_MODE) ||
+           (pvt->dchr1 & DDR3_MODE)) {
 
                amd64_printk(KERN_WARNING,
                        "%s() This machine is running with DDR3 memory. "
@@ -1817,11 +1811,11 @@ static struct amd64_family_type amd64_family_types[] = {
                .addr_f1_ctl = PCI_DEVICE_ID_AMD_K8_NB_ADDRMAP,
                .misc_f3_ctl = PCI_DEVICE_ID_AMD_K8_NB_MISC,
                .ops = {
-                       .early_channel_count = k8_early_channel_count,
-                       .get_error_address = k8_get_error_address,
-                       .read_dram_base_limit = k8_read_dram_base_limit,
-                       .map_sysaddr_to_csrow = k8_map_sysaddr_to_csrow,
-                       .dbam_map_to_pages = k8_dbam_map_to_pages,
+                       .early_channel_count    = k8_early_channel_count,
+                       .get_error_address      = k8_get_error_address,
+                       .read_dram_base_limit   = k8_read_dram_base_limit,
+                       .map_sysaddr_to_csrow   = k8_map_sysaddr_to_csrow,
+                       .dbam_to_cs             = k8_dbam_to_chip_select,
                }
        },
        [F10_CPUS] = {
@@ -1829,13 +1823,13 @@ static struct amd64_family_type amd64_family_types[] = {
                .addr_f1_ctl = PCI_DEVICE_ID_AMD_10H_NB_MAP,
                .misc_f3_ctl = PCI_DEVICE_ID_AMD_10H_NB_MISC,
                .ops = {
-                       .probe_valid_hardware = f10_probe_valid_hardware,
-                       .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_map_to_pages = f10_dbam_map_to_pages,
+                       .probe_valid_hardware   = f10_probe_valid_hardware,
+                       .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] = {
@@ -1843,13 +1837,13 @@ static struct amd64_family_type amd64_family_types[] = {
                .addr_f1_ctl = PCI_DEVICE_ID_AMD_11H_NB_MAP,
                .misc_f3_ctl = PCI_DEVICE_ID_AMD_11H_NB_MISC,
                .ops = {
-                       .probe_valid_hardware = f10_probe_valid_hardware,
-                       .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_map_to_pages = f10_dbam_map_to_pages,
+                       .probe_valid_hardware   = f10_probe_valid_hardware,
+                       .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,
                }
        },
 };
@@ -2425,7 +2419,7 @@ static void amd64_read_mc_registers(struct amd64_pvt *pvt)
  */
 static u32 amd64_csrow_nr_pages(int csrow_nr, struct amd64_pvt *pvt)
 {
-       u32 dram_map, nr_pages;
+       u32 cs_mode, nr_pages;
 
        /*
         * The math on this doesn't look right on the surface because x/2*4 can
@@ -2434,9 +2428,9 @@ static u32 amd64_csrow_nr_pages(int csrow_nr, struct amd64_pvt *pvt)
         * number of bits to shift the DBAM register to extract the proper CSROW
         * field.
         */
-       dram_map = (pvt->dbam0 >> ((csrow_nr / 2) * 4)) & 0xF;
+       cs_mode = (pvt->dbam0 >> ((csrow_nr / 2) * 4)) & 0xF;
 
-       nr_pages = pvt->ops->dbam_map_to_pages(pvt, dram_map);
+       nr_pages = pvt->ops->dbam_to_cs(pvt, cs_mode) << (20 - PAGE_SHIFT);
 
        /*
         * If dual channel then double the memory size of single channel.
@@ -2444,7 +2438,7 @@ static u32 amd64_csrow_nr_pages(int csrow_nr, struct amd64_pvt *pvt)
         */
        nr_pages <<= (pvt->channel_count - 1);
 
-       debugf0("  (csrow=%d) DBAM map index= %d\n", csrow_nr, dram_map);
+       debugf0("  (csrow=%d) DBAM map index= %d\n", csrow_nr, cs_mode);
        debugf0("    nr_pages= %u  channel-count = %d\n",
                nr_pages, pvt->channel_count);
 
index 24e2804..f8c187e 100644 (file)
 #define EDAC_MAX_NUMNODES              8
 
 /* Extended Model from CPUID, for CPU Revision numbers */
-#define OPTERON_CPU_LE_REV_C           0
-#define OPTERON_CPU_REV_D              1
-#define OPTERON_CPU_REV_E              2
-
-/* NPT processors have the following Extended Models */
-#define OPTERON_CPU_REV_F              4
-#define OPTERON_CPU_REV_FA             5
+#define K8_REV_D                       1
+#define K8_REV_E                       2
+#define K8_REV_F                       4
 
 /* Hardware limit on ChipSelect rows per MC and processors per system */
 #define MAX_CS_COUNT                   8
 #define F10_DCHR_1                     0x194
 
 #define F10_DCHR_FOUR_RANK_DIMM                BIT(18)
-#define F10_DCHR_Ddr3Mode              BIT(8)
+#define DDR3_MODE                      BIT(8)
 #define F10_DCHR_MblMode               BIT(6)
 
 
@@ -501,7 +497,6 @@ struct scrubrate {
 };
 
 extern struct scrubrate scrubrates[23];
-extern u32 revf_quad_ddr2_shift[16];
 extern const char *tt_msgs[4];
 extern const char *ll_msgs[4];
 extern const char *rrrr_msgs[16];
@@ -531,17 +526,16 @@ extern struct mcidev_sysfs_attribute amd64_dbg_attrs[NUM_DBG_ATTRS],
  * functions and per device encoding/decoding logic.
  */
 struct low_ops {
-       int (*probe_valid_hardware)(struct amd64_pvt *pvt);
-       int (*early_channel_count)(struct amd64_pvt *pvt);
-
-       u64 (*get_error_address)(struct mem_ctl_info *mci,
-                       struct err_regs *info);
-       void (*read_dram_base_limit)(struct amd64_pvt *pvt, int dram);
-       void (*read_dram_ctl_register)(struct amd64_pvt *pvt);
-       void (*map_sysaddr_to_csrow)(struct mem_ctl_info *mci,
-                                       struct err_regs *info,
-                                       u64 SystemAddr);
-       int (*dbam_map_to_pages)(struct amd64_pvt *pvt, int dram_map);
+       int (*probe_valid_hardware)     (struct amd64_pvt *pvt);
+       int (*early_channel_count)      (struct amd64_pvt *pvt);
+
+       u64 (*get_error_address)        (struct mem_ctl_info *mci,
+                                        struct err_regs *info);
+       void (*read_dram_base_limit)    (struct amd64_pvt *pvt, int dram);
+       void (*read_dram_ctl_register)  (struct amd64_pvt *pvt);
+       void (*map_sysaddr_to_csrow)    (struct mem_ctl_info *mci,
+                                        struct err_regs *info, u64 SystemAddr);
+       int (*dbam_to_cs)               (struct amd64_pvt *pvt, int cs_mode);
 };
 
 struct amd64_family_type {