amd64_edac: Improve DRAM address mapping
Borislav Petkov [Tue, 18 Jan 2011 18:16:08 +0000 (19:16 +0100)]
Drop static tables which map the bits in F2x80 to a chip select size in
favor of functions doing the mapping with some bit fiddling. Also, add
F15 support.

Signed-off-by: Borislav Petkov <borislav.petkov@amd.com>

drivers/edac/amd64_edac.c
drivers/edac/amd64_edac.h

index b85487d..eb6b6ba 100644 (file)
@@ -25,59 +25,12 @@ static struct mem_ctl_info **mcis;
 static struct ecc_settings **ecc_stngs;
 
 /*
- * Address to DRAM bank mapping: see F2x80 for K8 and F2x[1,0]80 for Fam10 and
- * later.
- */
-static int ddr2_dbam_revCG[] = {
-                          [0]          = 32,
-                          [1]          = 64,
-                          [2]          = 128,
-                          [3]          = 256,
-                          [4]          = 512,
-                          [5]          = 1024,
-                          [6]          = 2048,
-};
-
-static int ddr2_dbam_revD[] = {
-                          [0]          = 32,
-                          [1]          = 64,
-                          [2 ... 3]    = 128,
-                          [4]          = 256,
-                          [5]          = 512,
-                          [6]          = 256,
-                          [7]          = 512,
-                          [8 ... 9]    = 1024,
-                          [10]         = 2048,
-};
-
-static int ddr2_dbam[] = { [0]         = 128,
-                          [1]          = 256,
-                          [2 ... 4]    = 512,
-                          [5 ... 6]    = 1024,
-                          [7 ... 8]    = 2048,
-                          [9 ... 10]   = 4096,
-                          [11]         = 8192,
-};
-
-static int ddr3_dbam[] = { [0]         = -1,
-                          [1]          = 256,
-                          [2]          = 512,
-                          [3 ... 4]    = -1,
-                          [5 ... 6]    = 1024,
-                          [7 ... 8]    = 2048,
-                          [9 ... 10]   = 4096,
-                          [11]         = 8192,
-};
-
-/*
  * Valid scrub rates for the K8 hardware memory scrubber. We map the scrubbing
  * bandwidth to a valid bit pattern. The 'set' operation finds the 'matching-
  * or higher value'.
  *
  *FIXME: Produce a better mapping/linearisation.
  */
-
-
 struct scrubrate {
        u32 scrubval;           /* bit pattern for scrub rate */
        u32 bandwidth;          /* bandwidth consumed (bytes/sec) */
@@ -962,7 +915,7 @@ static int k8_early_channel_count(struct amd64_pvt *pvt)
 
        if (pvt->ext_model >= K8_REV_F)
                /* RevF (NPT) and later */
-               flag = pvt->dclr0 & F10_WIDTH_128;
+               flag = pvt->dclr0 & WIDTH_128;
        else
                /* RevE and earlier */
                flag = pvt->dclr0 & REVE_WIDTH_128;
@@ -1062,18 +1015,41 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
        }
 }
 
-static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, int cs_mode)
+static int ddr2_cs_size(unsigned i, bool dct_width)
 {
-       int *dbam_map;
+       unsigned shift = 0;
 
-       if (pvt->ext_model >= K8_REV_F)
-               dbam_map = ddr2_dbam;
-       else if (pvt->ext_model >= K8_REV_D)
-               dbam_map = ddr2_dbam_revD;
+       if (i <= 2)
+               shift = i;
+       else if (!(i & 0x1))
+               shift = i >> 1;
        else
-               dbam_map = ddr2_dbam_revCG;
+               shift = (i + 1) >> 1;
+
+       return 128 << (shift + !!dct_width);
+}
+
+static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
+                                 unsigned cs_mode)
+{
+       u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
+
+       if (pvt->ext_model >= K8_REV_F) {
+               WARN_ON(cs_mode > 11);
+               return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
+       }
+       else if (pvt->ext_model >= K8_REV_D) {
+               WARN_ON(cs_mode > 10);
 
-       return dbam_map[cs_mode];
+               if (cs_mode == 3 || cs_mode == 8)
+                       return 32 << (cs_mode - 1);
+               else
+                       return 32 << cs_mode;
+       }
+       else {
+               WARN_ON(cs_mode > 6);
+               return 32 << cs_mode;
+       }
 }
 
 /*
@@ -1089,7 +1065,7 @@ static int f1x_early_channel_count(struct amd64_pvt *pvt)
        int i, j, channels = 0;
 
        /* On F10h, if we are in 128 bit mode, then we are using 2 channels */
-       if (boot_cpu_data.x86 == 0x10 && (pvt->dclr0 & F10_WIDTH_128))
+       if (boot_cpu_data.x86 == 0x10 && (pvt->dclr0 & WIDTH_128))
                return 2;
 
        /*
@@ -1126,16 +1102,50 @@ static int f1x_early_channel_count(struct amd64_pvt *pvt)
        return channels;
 }
 
-static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, int cs_mode)
+static int ddr3_cs_size(unsigned i, bool dct_width)
+{
+       unsigned shift = 0;
+       int cs_size = 0;
+
+       if (i == 0 || i == 3 || i == 4)
+               cs_size = -1;
+       else if (i <= 2)
+               shift = i;
+       else if (i == 12)
+               shift = 7;
+       else if (!(i & 0x1))
+               shift = i >> 1;
+       else
+               shift = (i + 1) >> 1;
+
+       if (cs_size != -1)
+               cs_size = (128 * (1 << !!dct_width)) << shift;
+
+       return cs_size;
+}
+
+static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
+                                  unsigned cs_mode)
 {
-       int *dbam_map;
+       u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
+
+       WARN_ON(cs_mode > 11);
 
        if (pvt->dchr0 & DDR3_MODE || pvt->dchr1 & DDR3_MODE)
-               dbam_map = ddr3_dbam;
+               return ddr3_cs_size(cs_mode, dclr & WIDTH_128);
        else
-               dbam_map = ddr2_dbam;
+               return ddr2_cs_size(cs_mode, dclr & WIDTH_128);
+}
+
+/*
+ * F15h supports only 64bit DCT interfaces
+ */
+static int f15_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
+                                  unsigned cs_mode)
+{
+       WARN_ON(cs_mode > 12);
 
-       return dbam_map[cs_mode];
+       return ddr3_cs_size(cs_mode, false);
 }
 
 static void read_dram_ctl_register(struct amd64_pvt *pvt)
@@ -1528,7 +1538,7 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt)
        u32 dbam  = ctrl ? pvt->dbam1 : pvt->dbam0;
 
        if (boot_cpu_data.x86 == 0xf) {
-               if (pvt->dclr0 & F10_WIDTH_128)
+               if (pvt->dclr0 & WIDTH_128)
                        factor = 1;
 
                /* K8 families < revF not supported yet */
@@ -1551,11 +1561,13 @@ static void amd64_debug_display_dimm_sizes(int ctrl, struct amd64_pvt *pvt)
 
                size0 = 0;
                if (dcsb[dimm*2] & DCSB_CS_ENABLE)
-                       size0 = pvt->ops->dbam_to_cs(pvt, DBAM_DIMM(dimm, dbam));
+                       size0 = pvt->ops->dbam_to_cs(pvt, ctrl,
+                                                    DBAM_DIMM(dimm, dbam));
 
                size1 = 0;
                if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE)
-                       size1 = pvt->ops->dbam_to_cs(pvt, DBAM_DIMM(dimm, dbam));
+                       size1 = pvt->ops->dbam_to_cs(pvt, ctrl,
+                                                    DBAM_DIMM(dimm, dbam));
 
                amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
                                dimm * 2,     size0 << factor,
@@ -1591,6 +1603,7 @@ static struct amd64_family_type amd64_family_types[] = {
                .ops = {
                        .early_channel_count    = f1x_early_channel_count,
                        .map_sysaddr_to_csrow   = f1x_map_sysaddr_to_csrow,
+                       .dbam_to_cs             = f15_dbam_to_chip_select,
                        .read_dct_pci_cfg       = f15_read_dct_pci_cfg,
                }
        },
@@ -2030,7 +2043,7 @@ static void read_mc_regs(struct amd64_pvt *pvt)
  *     encompasses
  *
  */
-static u32 amd64_csrow_nr_pages(int csrow_nr, struct amd64_pvt *pvt)
+static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
 {
        u32 cs_mode, nr_pages;
 
@@ -2043,7 +2056,7 @@ static u32 amd64_csrow_nr_pages(int csrow_nr, struct amd64_pvt *pvt)
         */
        cs_mode = (pvt->dbam0 >> ((csrow_nr / 2) * 4)) & 0xF;
 
-       nr_pages = pvt->ops->dbam_to_cs(pvt, cs_mode) << (20 - PAGE_SHIFT);
+       nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode) << (20 - PAGE_SHIFT);
 
        /*
         * If dual channel then double the memory size of single channel.
@@ -2091,7 +2104,7 @@ static int init_csrows(struct mem_ctl_info *mci)
                        i, pvt->mc_node_id);
 
                empty = 0;
-               csrow->nr_pages = amd64_csrow_nr_pages(i, pvt);
+               csrow->nr_pages = amd64_csrow_nr_pages(pvt, 0, i);
                find_csrow_limits(mci, i, &input_addr_min, &input_addr_max);
                sys_addr = input_addr_to_sys_addr(mci, input_addr_min);
                csrow->first_page = (u32) (sys_addr >> PAGE_SHIFT);
index e14a8d0..8e431ab 100644 (file)
 #define DCLR0                          0x90
 #define DCLR1                          0x190
 #define REVE_WIDTH_128                 BIT(16)
-#define F10_WIDTH_128                  BIT(11)
+#define WIDTH_128                      BIT(11)
 
 #define DCHR0                          0x94
 #define DCHR1                          0x194
@@ -445,7 +445,7 @@ struct low_ops {
        int (*early_channel_count)      (struct amd64_pvt *pvt);
        void (*map_sysaddr_to_csrow)    (struct mem_ctl_info *mci, u64 sys_addr,
                                         u16 syndrome);
-       int (*dbam_to_cs)               (struct amd64_pvt *pvt, int cs_mode);
+       int (*dbam_to_cs)               (struct amd64_pvt *pvt, u8 dct, unsigned cs_mode);
        int (*read_dct_pci_cfg)         (struct amd64_pvt *pvt, int offset,
                                         u32 *val, const char *func);
 };