i7core_edac: Add more status functions to EDAC driver
authorMauro Carvalho Chehab <mchehab@redhat.com>
Tue, 23 Jun 2009 01:48:29 +0000 (22:48 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 10 May 2010 14:44:45 +0000 (11:44 -0300)
This patch were co-authored with Aristeu Rozanski.

Signed-off-by: Aristeu Sergio <arozansk@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/edac/i7core_edac.c

index b590f84..da40730 100644 (file)
 
        /* OFFSETS for Devices 4,5 and 6 Function 0 */
 
+#define MC_CHANNEL_DIMM_INIT_PARAMS 0x58
+  #define THREE_DIMMS_PRESENT          (1 << 24)
+  #define SINGLE_QUAD_RANK_PRESENT     (1 << 23)
+  #define QUAD_RANK_PRESENT            (1 << 22)
+  #define REGISTERED_DIMM              (1 << 15)
+
+#define MC_CHANNEL_RANK_PRESENT 0x7c
+  #define RANK_PRESENT_MASK            0xffff
+
 #define MC_CHANNEL_ADDR_MATCH  0xf0
 #define MC_CHANNEL_ERROR_MASK  0xf8
 #define MC_CHANNEL_ERROR_INJECT        0xfc
   #define NO_MASK_CACHELINE    0x00
   #define REPEAT_EN            0x01
 
+       /* OFFSETS for Devices 4,5 and 6 Function 1 */
+#define MC_DOD_CH_DIMM0                0x48
+#define MC_DOD_CH_DIMM1                0x4c
+#define MC_DOD_CH_DIMM2                0x50
+  #define RANKOFFSET_MASK      ((1 << 12) | (1 << 11) | (1 << 10))
+  #define RANKOFFSET(x)                ((x & RANKOFFSET_MASK) >> 10)
+  #define DIMM_PRESENT_MASK    (1 << 9)
+  #define DIMM_PRESENT(x)      (((x) & DIMM_PRESENT_MASK) >> 9)
+  #define NUMBANK_MASK         ((1 << 8) | (1 << 7))
+  #define NUMBANK(x)           (((x) & NUMBANK_MASK) >> 7)
+  #define NUMRANK_MASK         ((1 << 6) | (1 << 5))
+  #define NUMRANK(x)           (((x) & NUMRANK_MASK) >> 5)
+  #define NUMROW_MASK          ((1 << 4) | (1 << 3))
+  #define NUMROW(x)            (((x) & NUMROW_MASK) >> 3)
+  #define NUMCOL_MASK          3
+  #define NUMCOL(x)            ((x) & NUMCOL_MASK)
+
+#define MC_SAG_CH_0    0x80
+#define MC_SAG_CH_1    0x84
+#define MC_SAG_CH_2    0x88
+#define MC_SAG_CH_3    0x8c
+#define MC_SAG_CH_4    0x90
+#define MC_SAG_CH_5    0x94
+#define MC_SAG_CH_6    0x98
+#define MC_SAG_CH_7    0x9c
+
+#define MC_RIR_LIMIT_CH_0      0x40
+#define MC_RIR_LIMIT_CH_1      0x44
+#define MC_RIR_LIMIT_CH_2      0x48
+#define MC_RIR_LIMIT_CH_3      0x4C
+#define MC_RIR_LIMIT_CH_4      0x50
+#define MC_RIR_LIMIT_CH_5      0x54
+#define MC_RIR_LIMIT_CH_6      0x58
+#define MC_RIR_LIMIT_CH_7      0x5C
+#define MC_RIR_LIMIT_MASK      ((1 << 10) - 1)
+
+#define MC_RIR_WAY_CH          0x80
+  #define MC_RIR_WAY_OFFSET_MASK       (((1 << 14) - 1) & ~0x7)
+  #define MC_RIR_WAY_RANK_MASK         0x7
+
 /*
  * i7core structs
  */
@@ -99,11 +148,17 @@ struct i7core_inject {
        int channel, dimm, rank, bank, page, col;
 };
 
+struct i7core_channel {
+       u32 ranks;
+       u32 dimms;
+};
+
 struct i7core_pvt {
        struct pci_dev          *pci_mcr;       /* Dev 3:0 */
        struct pci_dev          *pci_ch[NUM_CHANS][NUM_FUNCS];
        struct i7core_info      info;
        struct i7core_inject    inject;
+       struct i7core_channel   channel[NUM_CHANS];
 };
 
 /* Device name and register DID (Device ID) */
@@ -133,16 +188,12 @@ static struct edac_pci_ctl_info *i7core_pci;
  ****************************************************************************/
 
        /* MC_CONTROL bits */
-#define CH2_ACTIVE(pvt)                ((pvt)->info.mc_control & 1 << 10)
-#define CH1_ACTIVE(pvt)                ((pvt)->info.mc_control & 1 << 9)
-#define CH0_ACTIVE(pvt)                ((pvt)->info.mc_control & 1 << 8)
+#define CH_ACTIVE(pvt, ch)     ((pvt)->info.mc_control & 1 << (8 + ch))
 #define ECCx8(pvt)             ((pvt)->info.mc_control & 1 << 1)
 
        /* MC_STATUS bits */
 #define ECC_ENABLED(pvt)       ((pvt)->info.mc_status & 1 << 3)
-#define CH2_DISABLED(pvt)      ((pvt)->info.mc_status & 1 << 2)
-#define CH1_DISABLED(pvt)      ((pvt)->info.mc_status & 1 << 1)
-#define CH0_DISABLED(pvt)      ((pvt)->info.mc_status & 1 << 0)
+#define CH_DISABLED(pvt, ch)   ((pvt)->info.mc_status & 1 << ch)
 
        /* MC_MAX_DOD read functions */
 static inline int maxnumdimms(struct i7core_pvt *pvt)
@@ -189,19 +240,12 @@ static inline int maxnumcol(struct i7core_pvt *pvt)
 static int get_dimm_config(struct mem_ctl_info *mci)
 {
        struct i7core_pvt *pvt = mci->pvt_info;
+       int i;
 
        pci_read_config_dword(pvt->pci_mcr, MC_CONTROL, &pvt->info.mc_control);
        pci_read_config_dword(pvt->pci_mcr, MC_STATUS, &pvt->info.mc_status);
        pci_read_config_dword(pvt->pci_mcr, MC_MAX_DOD, &pvt->info.max_dod);
 
-       debugf0("Channels  active [%c][%c][%c] - enabled [%c][%c][%c]\n",
-               CH0_ACTIVE(pvt)?'0':'-',
-               CH1_ACTIVE(pvt)?'1':'-',
-               CH2_ACTIVE(pvt)?'2':'-',
-               CH0_DISABLED(pvt)?'-':'0',
-               CH1_DISABLED(pvt)?'-':'1',
-               CH2_DISABLED(pvt)?'-':'2');
-
        if (ECC_ENABLED(pvt))
                debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt)?8:4);
        else
@@ -213,6 +257,38 @@ static int get_dimm_config(struct mem_ctl_info *mci)
        debugf0("DOD Maximum rows x colums = 0x%x x 0x%x\n",
                maxnumrow(pvt), maxnumcol(pvt));
 
+       debugf0("Memory channel configuration:\n");
+
+       for (i = 0; i < NUM_CHANS; i++) {
+               u32 data;
+
+               if (!CH_ACTIVE(pvt, i)) {
+                       debugf0("Channel %i is not active\n", i);
+                       continue;
+               }
+               if (CH_DISABLED(pvt, i)) {
+                       debugf0("Channel %i is disabled\n", i);
+                       continue;
+               }
+
+               pci_read_config_dword(pvt->pci_ch[i][0],
+                               MC_CHANNEL_DIMM_INIT_PARAMS, &data);
+
+               pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT)? 4 : 2;
+
+               if (data & THREE_DIMMS_PRESENT)
+                       pvt->channel[i].dimms = 3;
+               else if (data & SINGLE_QUAD_RANK_PRESENT)
+                       pvt->channel[i].dimms = 1;
+               else
+                       pvt->channel[i].dimms = 2;
+
+               debugf0("Channel %d (0x%08x): %d ranks, %d dimms "
+                       "(%sregistered)\n", i, data,
+                       pvt->channel[i].ranks, pvt->channel[i].dimms,
+                       (data & REGISTERED_DIMM)? "" : "un" );
+       }
+
        return 0;
 }
 
@@ -489,7 +565,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci,
        if (pvt->inject.dimm < 0)
                mask |= 1l << 41;
        else {
-               if (maxnumdimms(pvt) > 2)
+               if (pvt->channel[pvt->inject.channel].dimms > 2)
                        mask |= (pvt->inject.dimm & 0x3l) << 35;
                else
                        mask |= (pvt->inject.dimm & 0x1l) << 36;
@@ -499,7 +575,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci,
        if (pvt->inject.rank < 0)
                mask |= 1l << 40;
        else {
-               if (maxnumdimms(pvt) > 2)
+               if (pvt->channel[pvt->inject.channel].dimms > 2)
                        mask |= (pvt->inject.rank & 0x1l) << 34;
                else
                        mask |= (pvt->inject.rank & 0x3l) << 34;
@@ -646,9 +722,6 @@ static int i7core_get_devices(struct mem_ctl_info *mci, int dev_idx)
        }
        pvt->pci_mcr=pdev;
 
-       /* Get dimm basic config */
-       get_dimm_config(mci);
-
        /* Retrieve all needed functions at MTR channel controllers */
        for (i = 0; i < NUM_CHANS; i++) {
                pdev = NULL;
@@ -672,6 +745,9 @@ static int i7core_get_devices(struct mem_ctl_info *mci, int dev_idx)
        }
        i7core_printk(KERN_INFO, "Driver loaded.\n");
 
+       /* Get dimm basic config */
+       get_dimm_config(mci);
+
        return 0;
 }