Commit f0f3680e authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'linux_next' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac

Pull EDAC fixes from Mauro Carvalho Chehab:
 "A series of EDAC driver fixes.  It also has one core fix at the
  documentation, and a rename patch, fixing the name of the struct that
  contains the rank information."

* 'linux_next' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac:
  edac: rename channel_info to rank_info
  i5400_edac: Avoid calling pci_put_device() twice
  edac: i5100 ack error detection register after each read
  edac: i5100 fix erroneous define for M1Err
  edac: sb_edac: Fix a wrong value setting for the previous value
  edac: sb_edac: Fix a INTERLEAVE_MODE() misuse
  edac: sb_edac: Let the driver depend on PCI_MMCONFIG
  edac: Improve the comments to better describe the memory concepts
  edac/ppc4xx_edac: Fix compilation
  Fix sb_edac compilation with 32 bits kernels
parents 61e5191c a4b4be3f
...@@ -215,7 +215,7 @@ config EDAC_I7300 ...@@ -215,7 +215,7 @@ config EDAC_I7300
config EDAC_SBRIDGE config EDAC_SBRIDGE
tristate "Intel Sandy-Bridge Integrated MC" tristate "Intel Sandy-Bridge Integrated MC"
depends on EDAC_MM_EDAC && PCI && X86_64 && X86_MCE_INTEL depends on EDAC_MM_EDAC && PCI && X86_64 && X86_MCE_INTEL
depends on EXPERIMENTAL depends on PCI_MMCONFIG && EXPERIMENTAL
help help
Support for error detection and correction the Intel Support for error detection and correction the Intel
Sandy Bridge Integrated Memory Controller. Sandy Bridge Integrated Memory Controller.
......
...@@ -39,7 +39,7 @@ static LIST_HEAD(mc_devices); ...@@ -39,7 +39,7 @@ static LIST_HEAD(mc_devices);
#ifdef CONFIG_EDAC_DEBUG #ifdef CONFIG_EDAC_DEBUG
static void edac_mc_dump_channel(struct channel_info *chan) static void edac_mc_dump_channel(struct rank_info *chan)
{ {
debugf4("\tchannel = %p\n", chan); debugf4("\tchannel = %p\n", chan);
debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx); debugf4("\tchannel->chan_idx = %d\n", chan->chan_idx);
...@@ -156,7 +156,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, ...@@ -156,7 +156,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
{ {
struct mem_ctl_info *mci; struct mem_ctl_info *mci;
struct csrow_info *csi, *csrow; struct csrow_info *csi, *csrow;
struct channel_info *chi, *chp, *chan; struct rank_info *chi, *chp, *chan;
void *pvt; void *pvt;
unsigned size; unsigned size;
int row, chn; int row, chn;
...@@ -181,7 +181,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, ...@@ -181,7 +181,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
* rather than an imaginary chunk of memory located at address 0. * rather than an imaginary chunk of memory located at address 0.
*/ */
csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi)); csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi));
chi = (struct channel_info *)(((char *)mci) + ((unsigned long)chi)); chi = (struct rank_info *)(((char *)mci) + ((unsigned long)chi));
pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL; pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL;
/* setup index and various internal pointers */ /* setup index and various internal pointers */
......
...@@ -49,7 +49,7 @@ ...@@ -49,7 +49,7 @@
#define I5100_FERR_NF_MEM_M6ERR_MASK (1 << 6) #define I5100_FERR_NF_MEM_M6ERR_MASK (1 << 6)
#define I5100_FERR_NF_MEM_M5ERR_MASK (1 << 5) #define I5100_FERR_NF_MEM_M5ERR_MASK (1 << 5)
#define I5100_FERR_NF_MEM_M4ERR_MASK (1 << 4) #define I5100_FERR_NF_MEM_M4ERR_MASK (1 << 4)
#define I5100_FERR_NF_MEM_M1ERR_MASK 1 #define I5100_FERR_NF_MEM_M1ERR_MASK (1 << 1)
#define I5100_FERR_NF_MEM_ANY_MASK \ #define I5100_FERR_NF_MEM_ANY_MASK \
(I5100_FERR_NF_MEM_M16ERR_MASK | \ (I5100_FERR_NF_MEM_M16ERR_MASK | \
I5100_FERR_NF_MEM_M15ERR_MASK | \ I5100_FERR_NF_MEM_M15ERR_MASK | \
...@@ -535,23 +535,20 @@ static void i5100_read_log(struct mem_ctl_info *mci, int chan, ...@@ -535,23 +535,20 @@ static void i5100_read_log(struct mem_ctl_info *mci, int chan,
static void i5100_check_error(struct mem_ctl_info *mci) static void i5100_check_error(struct mem_ctl_info *mci)
{ {
struct i5100_priv *priv = mci->pvt_info; struct i5100_priv *priv = mci->pvt_info;
u32 dw; u32 dw, dw2;
pci_read_config_dword(priv->mc, I5100_FERR_NF_MEM, &dw); pci_read_config_dword(priv->mc, I5100_FERR_NF_MEM, &dw);
if (i5100_ferr_nf_mem_any(dw)) { if (i5100_ferr_nf_mem_any(dw)) {
u32 dw2;
pci_read_config_dword(priv->mc, I5100_NERR_NF_MEM, &dw2); pci_read_config_dword(priv->mc, I5100_NERR_NF_MEM, &dw2);
if (dw2)
pci_write_config_dword(priv->mc, I5100_NERR_NF_MEM,
dw2);
pci_write_config_dword(priv->mc, I5100_FERR_NF_MEM, dw);
i5100_read_log(mci, i5100_ferr_nf_mem_chan_indx(dw), i5100_read_log(mci, i5100_ferr_nf_mem_chan_indx(dw),
i5100_ferr_nf_mem_any(dw), i5100_ferr_nf_mem_any(dw),
i5100_nerr_nf_mem_any(dw2)); i5100_nerr_nf_mem_any(dw2));
pci_write_config_dword(priv->mc, I5100_NERR_NF_MEM, dw2);
} }
pci_write_config_dword(priv->mc, I5100_FERR_NF_MEM, dw);
} }
/* The i5100 chipset will scrub the entire memory once, then /* The i5100 chipset will scrub the entire memory once, then
......
...@@ -735,7 +735,7 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx) ...@@ -735,7 +735,7 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx)
/* Attempt to 'get' the MCH register we want */ /* Attempt to 'get' the MCH register we want */
pdev = NULL; pdev = NULL;
while (!pvt->branchmap_werrors || !pvt->fsb_error_regs) { while (1) {
pdev = pci_get_device(PCI_VENDOR_ID_INTEL, pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_5400_ERR, pdev); PCI_DEVICE_ID_INTEL_5400_ERR, pdev);
if (!pdev) { if (!pdev) {
...@@ -743,23 +743,42 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx) ...@@ -743,23 +743,42 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx)
i5400_printk(KERN_ERR, i5400_printk(KERN_ERR,
"'system address,Process Bus' " "'system address,Process Bus' "
"device not found:" "device not found:"
"vendor 0x%x device 0x%x ERR funcs " "vendor 0x%x device 0x%x ERR func 1 "
"(broken BIOS?)\n", "(broken BIOS?)\n",
PCI_VENDOR_ID_INTEL, PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_5400_ERR); PCI_DEVICE_ID_INTEL_5400_ERR);
goto error; return -ENODEV;
} }
/* Store device 16 funcs 1 and 2 */ /* Store device 16 func 1 */
switch (PCI_FUNC(pdev->devfn)) { if (PCI_FUNC(pdev->devfn) == 1)
case 1:
pvt->branchmap_werrors = pdev;
break;
case 2:
pvt->fsb_error_regs = pdev;
break; break;
}
pvt->branchmap_werrors = pdev;
pdev = NULL;
while (1) {
pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_5400_ERR, pdev);
if (!pdev) {
/* End of list, leave */
i5400_printk(KERN_ERR,
"'system address,Process Bus' "
"device not found:"
"vendor 0x%x device 0x%x ERR func 2 "
"(broken BIOS?)\n",
PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_5400_ERR);
pci_dev_put(pvt->branchmap_werrors);
return -ENODEV;
} }
/* Store device 16 func 2 */
if (PCI_FUNC(pdev->devfn) == 2)
break;
} }
pvt->fsb_error_regs = pdev;
debugf1("System Address, processor bus- PCI Bus ID: %s %x:%x\n", debugf1("System Address, processor bus- PCI Bus ID: %s %x:%x\n",
pci_name(pvt->system_address), pci_name(pvt->system_address),
...@@ -778,7 +797,10 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx) ...@@ -778,7 +797,10 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx)
"MC: 'BRANCH 0' device not found:" "MC: 'BRANCH 0' device not found:"
"vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n", "vendor 0x%x device 0x%x Func 0 (broken BIOS?)\n",
PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_FBD0); PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_5400_FBD0);
goto error;
pci_dev_put(pvt->fsb_error_regs);
pci_dev_put(pvt->branchmap_werrors);
return -ENODEV;
} }
/* If this device claims to have more than 2 channels then /* If this device claims to have more than 2 channels then
...@@ -796,14 +818,14 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx) ...@@ -796,14 +818,14 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx)
"(broken BIOS?)\n", "(broken BIOS?)\n",
PCI_VENDOR_ID_INTEL, PCI_VENDOR_ID_INTEL,
PCI_DEVICE_ID_INTEL_5400_FBD1); PCI_DEVICE_ID_INTEL_5400_FBD1);
goto error;
pci_dev_put(pvt->branch_0);
pci_dev_put(pvt->fsb_error_regs);
pci_dev_put(pvt->branchmap_werrors);
return -ENODEV;
} }
return 0; return 0;
error:
i5400_put_devices(mci);
return -ENODEV;
} }
/* /*
......
...@@ -184,7 +184,7 @@ struct ppc4xx_ecc_status { ...@@ -184,7 +184,7 @@ struct ppc4xx_ecc_status {
/* Function Prototypes */ /* Function Prototypes */
static int ppc4xx_edac_probe(struct platform_device *device) static int ppc4xx_edac_probe(struct platform_device *device);
static int ppc4xx_edac_remove(struct platform_device *device); static int ppc4xx_edac_remove(struct platform_device *device);
/* Global Variables */ /* Global Variables */
...@@ -1068,7 +1068,7 @@ ppc4xx_edac_mc_init(struct mem_ctl_info *mci, ...@@ -1068,7 +1068,7 @@ ppc4xx_edac_mc_init(struct mem_ctl_info *mci,
mci->mod_name = PPC4XX_EDAC_MODULE_NAME; mci->mod_name = PPC4XX_EDAC_MODULE_NAME;
mci->mod_ver = PPC4XX_EDAC_MODULE_REVISION; mci->mod_ver = PPC4XX_EDAC_MODULE_REVISION;
mci->ctl_name = match->compatible, mci->ctl_name = ppc4xx_edac_match->compatible,
mci->dev_name = np->full_name; mci->dev_name = np->full_name;
/* Initialize callbacks */ /* Initialize callbacks */
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/mmzone.h> #include <linux/mmzone.h>
#include <linux/smp.h> #include <linux/smp.h>
#include <linux/bitmap.h> #include <linux/bitmap.h>
#include <linux/math64.h>
#include <asm/processor.h> #include <asm/processor.h>
#include <asm/mce.h> #include <asm/mce.h>
...@@ -670,6 +671,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci) ...@@ -670,6 +671,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
u32 reg; u32 reg;
u64 limit, prv = 0; u64 limit, prv = 0;
u64 tmp_mb; u64 tmp_mb;
u32 mb, kb;
u32 rir_way; u32 rir_way;
/* /*
...@@ -682,8 +684,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci) ...@@ -682,8 +684,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
pvt->tolm = GET_TOLM(reg); pvt->tolm = GET_TOLM(reg);
tmp_mb = (1 + pvt->tolm) >> 20; tmp_mb = (1 + pvt->tolm) >> 20;
debugf0("TOLM: %Lu.%03Lu GB (0x%016Lx)\n", mb = div_u64_rem(tmp_mb, 1000, &kb);
tmp_mb / 1000, tmp_mb % 1000, (u64)pvt->tolm); debugf0("TOLM: %u.%03u GB (0x%016Lx)\n",
mb, kb, (u64)pvt->tolm);
/* Address range is already 45:25 */ /* Address range is already 45:25 */
pci_read_config_dword(pvt->pci_sad1, TOHM, pci_read_config_dword(pvt->pci_sad1, TOHM,
...@@ -691,8 +694,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci) ...@@ -691,8 +694,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
pvt->tohm = GET_TOHM(reg); pvt->tohm = GET_TOHM(reg);
tmp_mb = (1 + pvt->tohm) >> 20; tmp_mb = (1 + pvt->tohm) >> 20;
debugf0("TOHM: %Lu.%03Lu GB (0x%016Lx)", mb = div_u64_rem(tmp_mb, 1000, &kb);
tmp_mb / 1000, tmp_mb % 1000, (u64)pvt->tohm); debugf0("TOHM: %u.%03u GB (0x%016Lx)",
mb, kb, (u64)pvt->tohm);
/* /*
* Step 2) Get SAD range and SAD Interleave list * Step 2) Get SAD range and SAD Interleave list
...@@ -714,10 +718,11 @@ static void get_memory_layout(const struct mem_ctl_info *mci) ...@@ -714,10 +718,11 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
break; break;
tmp_mb = (limit + 1) >> 20; tmp_mb = (limit + 1) >> 20;
debugf0("SAD#%d %s up to %Lu.%03Lu GB (0x%016Lx) %s reg=0x%08x\n", mb = div_u64_rem(tmp_mb, 1000, &kb);
debugf0("SAD#%d %s up to %u.%03u GB (0x%016Lx) %s reg=0x%08x\n",
n_sads, n_sads,
get_dram_attr(reg), get_dram_attr(reg),
tmp_mb / 1000, tmp_mb % 1000, mb, kb,
((u64)tmp_mb) << 20L, ((u64)tmp_mb) << 20L,
INTERLEAVE_MODE(reg) ? "Interleave: 8:6" : "Interleave: [8:6]XOR[18:16]", INTERLEAVE_MODE(reg) ? "Interleave: 8:6" : "Interleave: [8:6]XOR[18:16]",
reg); reg);
...@@ -747,8 +752,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci) ...@@ -747,8 +752,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
break; break;
tmp_mb = (limit + 1) >> 20; tmp_mb = (limit + 1) >> 20;
debugf0("TAD#%d: up to %Lu.%03Lu GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n", mb = div_u64_rem(tmp_mb, 1000, &kb);
n_tads, tmp_mb / 1000, tmp_mb % 1000, debugf0("TAD#%d: up to %u.%03u GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n",
n_tads, mb, kb,
((u64)tmp_mb) << 20L, ((u64)tmp_mb) << 20L,
(u32)TAD_SOCK(reg), (u32)TAD_SOCK(reg),
(u32)TAD_CH(reg), (u32)TAD_CH(reg),
...@@ -757,7 +763,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci) ...@@ -757,7 +763,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
(u32)TAD_TGT2(reg), (u32)TAD_TGT2(reg),
(u32)TAD_TGT3(reg), (u32)TAD_TGT3(reg),
reg); reg);
prv = tmp_mb; prv = limit;
} }
/* /*
...@@ -771,9 +777,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci) ...@@ -771,9 +777,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
tad_ch_nilv_offset[j], tad_ch_nilv_offset[j],
&reg); &reg);
tmp_mb = TAD_OFFSET(reg) >> 20; tmp_mb = TAD_OFFSET(reg) >> 20;
debugf0("TAD CH#%d, offset #%d: %Lu.%03Lu GB (0x%016Lx), reg=0x%08x\n", mb = div_u64_rem(tmp_mb, 1000, &kb);
debugf0("TAD CH#%d, offset #%d: %u.%03u GB (0x%016Lx), reg=0x%08x\n",
i, j, i, j,
tmp_mb / 1000, tmp_mb % 1000, mb, kb,
((u64)tmp_mb) << 20L, ((u64)tmp_mb) << 20L,
reg); reg);
} }
...@@ -795,9 +802,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci) ...@@ -795,9 +802,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
tmp_mb = RIR_LIMIT(reg) >> 20; tmp_mb = RIR_LIMIT(reg) >> 20;
rir_way = 1 << RIR_WAY(reg); rir_way = 1 << RIR_WAY(reg);
debugf0("CH#%d RIR#%d, limit: %Lu.%03Lu GB (0x%016Lx), way: %d, reg=0x%08x\n", mb = div_u64_rem(tmp_mb, 1000, &kb);
debugf0("CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n",
i, j, i, j,
tmp_mb / 1000, tmp_mb % 1000, mb, kb,
((u64)tmp_mb) << 20L, ((u64)tmp_mb) << 20L,
rir_way, rir_way,
reg); reg);
...@@ -808,9 +816,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci) ...@@ -808,9 +816,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
&reg); &reg);
tmp_mb = RIR_OFFSET(reg) << 6; tmp_mb = RIR_OFFSET(reg) << 6;
debugf0("CH#%d RIR#%d INTL#%d, offset %Lu.%03Lu GB (0x%016Lx), tgt: %d, reg=0x%08x\n", mb = div_u64_rem(tmp_mb, 1000, &kb);
debugf0("CH#%d RIR#%d INTL#%d, offset %u.%03u GB (0x%016Lx), tgt: %d, reg=0x%08x\n",
i, j, k, i, j, k,
tmp_mb / 1000, tmp_mb % 1000, mb, kb,
((u64)tmp_mb) << 20L, ((u64)tmp_mb) << 20L,
(u32)RIR_RNK_TGT(reg), (u32)RIR_RNK_TGT(reg),
reg); reg);
...@@ -848,6 +857,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -848,6 +857,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
u8 ch_way,sck_way; u8 ch_way,sck_way;
u32 tad_offset; u32 tad_offset;
u32 rir_way; u32 rir_way;
u32 mb, kb;
u64 ch_addr, offset, limit, prv = 0; u64 ch_addr, offset, limit, prv = 0;
...@@ -858,7 +868,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -858,7 +868,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
* range (e. g. VGA addresses). It is unlikely, however, that the * range (e. g. VGA addresses). It is unlikely, however, that the
* memory controller would generate an error on that range. * memory controller would generate an error on that range.
*/ */
if ((addr > (u64) pvt->tolm) && (addr < (1L << 32))) { if ((addr > (u64) pvt->tolm) && (addr < (1LL << 32))) {
sprintf(msg, "Error at TOLM area, on addr 0x%08Lx", addr); sprintf(msg, "Error at TOLM area, on addr 0x%08Lx", addr);
edac_mc_handle_ce_no_info(mci, msg); edac_mc_handle_ce_no_info(mci, msg);
return -EINVAL; return -EINVAL;
...@@ -913,7 +923,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -913,7 +923,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
addr, addr,
limit, limit,
sad_way + 7, sad_way + 7,
INTERLEAVE_MODE(reg) ? "" : "XOR[18:16]"); interleave_mode ? "" : "XOR[18:16]");
if (interleave_mode) if (interleave_mode)
idx = ((addr >> 6) ^ (addr >> 16)) & 7; idx = ((addr >> 6) ^ (addr >> 16)) & 7;
else else
...@@ -1053,7 +1063,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -1053,7 +1063,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
ch_addr = addr & 0x7f; ch_addr = addr & 0x7f;
/* Remove socket wayness and remove 6 bits */ /* Remove socket wayness and remove 6 bits */
addr >>= 6; addr >>= 6;
addr /= sck_xch; addr = div_u64(addr, sck_xch);
#if 0 #if 0
/* Divide by channel way */ /* Divide by channel way */
addr = addr / ch_way; addr = addr / ch_way;
...@@ -1073,10 +1083,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci, ...@@ -1073,10 +1083,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
continue; continue;
limit = RIR_LIMIT(reg); limit = RIR_LIMIT(reg);
mb = div_u64_rem(limit >> 20, 1000, &kb);
debugf0("RIR#%d, limit: %Lu.%03Lu GB (0x%016Lx), way: %d\n", debugf0("RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n",
n_rir, n_rir,
(limit >> 20) / 1000, (limit >> 20) % 1000, mb, kb,
limit, limit,
1 << RIR_WAY(reg)); 1 << RIR_WAY(reg));
if (ch_addr <= limit) if (ch_addr <= limit)
......
...@@ -70,25 +70,64 @@ enum dev_type { ...@@ -70,25 +70,64 @@ enum dev_type {
#define DEV_FLAG_X32 BIT(DEV_X32) #define DEV_FLAG_X32 BIT(DEV_X32)
#define DEV_FLAG_X64 BIT(DEV_X64) #define DEV_FLAG_X64 BIT(DEV_X64)
/* memory types */ /**
* enum mem_type - memory types. For a more detailed reference, please see
* http://en.wikipedia.org/wiki/DRAM
*
* @MEM_EMPTY Empty csrow
* @MEM_RESERVED: Reserved csrow type
* @MEM_UNKNOWN: Unknown csrow type
* @MEM_FPM: FPM - Fast Page Mode, used on systems up to 1995.
* @MEM_EDO: EDO - Extended data out, used on systems up to 1998.
* @MEM_BEDO: BEDO - Burst Extended data out, an EDO variant.
* @MEM_SDR: SDR - Single data rate SDRAM
* http://en.wikipedia.org/wiki/Synchronous_dynamic_random-access_memory
* They use 3 pins for chip select: Pins 0 and 2 are
* for rank 0; pins 1 and 3 are for rank 1, if the memory
* is dual-rank.
* @MEM_RDR: Registered SDR SDRAM
* @MEM_DDR: Double data rate SDRAM
* http://en.wikipedia.org/wiki/DDR_SDRAM
* @MEM_RDDR: Registered Double data rate SDRAM
* This is a variant of the DDR memories.
* A registered memory has a buffer inside it, hiding
* part of the memory details to the memory controller.
* @MEM_RMBS: Rambus DRAM, used on a few Pentium III/IV controllers.
* @MEM_DDR2: DDR2 RAM, as described at JEDEC JESD79-2F.
* Those memories are labed as "PC2-" instead of "PC" to
* differenciate from DDR.
* @MEM_FB_DDR2: Fully-Buffered DDR2, as described at JEDEC Std No. 205
* and JESD206.
* Those memories are accessed per DIMM slot, and not by
* a chip select signal.
* @MEM_RDDR2: Registered DDR2 RAM
* This is a variant of the DDR2 memories.
* @MEM_XDR: Rambus XDR
* It is an evolution of the original RAMBUS memories,
* created to compete with DDR2. Weren't used on any
* x86 arch, but cell_edac PPC memory controller uses it.
* @MEM_DDR3: DDR3 RAM
* @MEM_RDDR3: Registered DDR3 RAM
* This is a variant of the DDR3 memories.
*/
enum mem_type { enum mem_type {
MEM_EMPTY = 0, /* Empty csrow */ MEM_EMPTY = 0,
MEM_RESERVED, /* Reserved csrow type */ MEM_RESERVED,
MEM_UNKNOWN, /* Unknown csrow type */ MEM_UNKNOWN,
MEM_FPM, /* Fast page mode */ MEM_FPM,
MEM_EDO, /* Extended data out */ MEM_EDO,
MEM_BEDO, /* Burst Extended data out */ MEM_BEDO,
MEM_SDR, /* Single data rate SDRAM */ MEM_SDR,
MEM_RDR, /* Registered single data rate SDRAM */ MEM_RDR,
MEM_DDR, /* Double data rate SDRAM */ MEM_DDR,
MEM_RDDR, /* Registered Double data rate SDRAM */ MEM_RDDR,
MEM_RMBS, /* Rambus DRAM */ MEM_RMBS,
MEM_DDR2, /* DDR2 RAM */ MEM_DDR2,
MEM_FB_DDR2, /* fully buffered DDR2 */ MEM_FB_DDR2,
MEM_RDDR2, /* Registered DDR2 RAM */ MEM_RDDR2,
MEM_XDR, /* Rambus XDR */ MEM_XDR,
MEM_DDR3, /* DDR3 RAM */ MEM_DDR3,
MEM_RDDR3, /* Registered DDR3 RAM */ MEM_RDDR3,
}; };
#define MEM_FLAG_EMPTY BIT(MEM_EMPTY) #define MEM_FLAG_EMPTY BIT(MEM_EMPTY)
...@@ -166,8 +205,9 @@ enum scrub_type { ...@@ -166,8 +205,9 @@ enum scrub_type {
#define OP_OFFLINE 0x300 #define OP_OFFLINE 0x300
/* /*
* There are several things to be aware of that aren't at all obvious: * Concepts used at the EDAC subsystem
* *
* There are several things to be aware of that aren't at all obvious:
* *
* SOCKETS, SOCKET SETS, BANKS, ROWS, CHIP-SELECT ROWS, CHANNELS, etc.. * SOCKETS, SOCKET SETS, BANKS, ROWS, CHIP-SELECT ROWS, CHANNELS, etc..
* *
...@@ -176,36 +216,61 @@ enum scrub_type { ...@@ -176,36 +216,61 @@ enum scrub_type {
* creating a common ground for discussion, terms and their definitions * creating a common ground for discussion, terms and their definitions
* will be established. * will be established.
* *
* Memory devices: The individual chip on a memory stick. These devices * Memory devices: The individual DRAM chips on a memory stick. These
* commonly output 4 and 8 bits each. Grouping several * devices commonly output 4 and 8 bits each (x4, x8).
* of these in parallel provides 64 bits which is common * Grouping several of these in parallel provides the
* for a memory stick. * number of bits that the memory controller expects:
* typically 72 bits, in order to provide 64 bits +
* 8 bits of ECC data.
* *
* Memory Stick: A printed circuit board that aggregates multiple * Memory Stick: A printed circuit board that aggregates multiple
* memory devices in parallel. This is the atomic * memory devices in parallel. In general, this is the
* memory component that is purchaseable by Joe consumer * Field Replaceable Unit (FRU) which gets replaced, in
* and loaded into a memory socket. * the case of excessive errors. Most often it is also
* called DIMM (Dual Inline Memory Module).
*
* Memory Socket: A physical connector on the motherboard that accepts
* a single memory stick. Also called as "slot" on several
* datasheets.
* *
* Socket: A physical connector on the motherboard that accepts * Channel: A memory controller channel, responsible to communicate
* a single memory stick. * with a group of DIMMs. Each channel has its own
* independent control (command) and data bus, and can
* be used independently or grouped with other channels.
* *
* Channel: Set of memory devices on a memory stick that must be * Branch: It is typically the highest hierarchy on a
* grouped in parallel with one or more additional * Fully-Buffered DIMM memory controller.
* channels from other memory sticks. This parallel * Typically, it contains two channels.
* grouping of the output from multiple channels are * Two channels at the same branch can be used in single
* necessary for the smallest granularity of memory access. * mode or in lockstep mode.
* Some memory controllers are capable of single channel - * When lockstep is enabled, the cacheline is doubled,
* which means that memory sticks can be loaded * but it generally brings some performance penalty.
* individually. Other memory controllers are only * Also, it is generally not possible to point to just one
* capable of dual channel - which means that memory * memory stick when an error occurs, as the error
* sticks must be loaded as pairs (see "socket set"). * correction code is calculated using two DIMMs instead
* of one. Due to that, it is capable of correcting more
* errors than on single mode.
* *
* Chip-select row: All of the memory devices that are selected together. * Single-channel: The data accessed by the memory controller is contained
* for a single, minimum grain of memory access. * into one dimm only. E. g. if the data is 64 bits-wide,
* This selects all of the parallel memory devices across * the data flows to the CPU using one 64 bits parallel
* all of the parallel channels. Common chip-select rows * access.
* for single channel are 64 bits, for dual channel 128 * Typically used with SDR, DDR, DDR2 and DDR3 memories.
* bits. * FB-DIMM and RAMBUS use a different concept for channel,
* so this concept doesn't apply there.
*
* Double-channel: The data size accessed by the memory controller is
* interlaced into two dimms, accessed at the same time.
* E. g. if the DIMM is 64 bits-wide (72 bits with ECC),
* the data flows to the CPU using a 128 bits parallel
* access.
*
* Chip-select row: This is the name of the DRAM signal used to select the
* DRAM ranks to be accessed. Common chip-select rows for
* single channel are 64 bits, for dual channel 128 bits.
* It may not be visible by the memory controller, as some
* DIMM types have a memory buffer that can hide direct
* access to it from the Memory Controller.
* *
* Single-Ranked stick: A Single-ranked stick has 1 chip-select row of memory. * Single-Ranked stick: A Single-ranked stick has 1 chip-select row of memory.
* Motherboards commonly drive two chip-select pins to * Motherboards commonly drive two chip-select pins to
...@@ -218,8 +283,8 @@ enum scrub_type { ...@@ -218,8 +283,8 @@ enum scrub_type {
* *
* Double-sided stick: DEPRECATED TERM, see Double-Ranked stick. * Double-sided stick: DEPRECATED TERM, see Double-Ranked stick.
* A double-sided stick has two chip-select rows which * A double-sided stick has two chip-select rows which
* access different sets of memory devices. The two * access different sets of memory devices. The two
* rows cannot be accessed concurrently. "Double-sided" * rows cannot be accessed concurrently. "Double-sided"
* is irrespective of the memory devices being mounted * is irrespective of the memory devices being mounted
* on both sides of the memory stick. * on both sides of the memory stick.
* *
...@@ -247,10 +312,22 @@ enum scrub_type { ...@@ -247,10 +312,22 @@ enum scrub_type {
* PS - I enjoyed writing all that about as much as you enjoyed reading it. * PS - I enjoyed writing all that about as much as you enjoyed reading it.
*/ */
struct channel_info { /**
int chan_idx; /* channel index */ * struct rank_info - contains the information for one DIMM rank
u32 ce_count; /* Correctable Errors for this CHANNEL */ *
char label[EDAC_MC_LABEL_LEN + 1]; /* DIMM label on motherboard */ * @chan_idx: channel number where the rank is (typically, 0 or 1)
* @ce_count: number of correctable errors for this rank
* @label: DIMM label. Different ranks for the same DIMM should be
* filled, on userspace, with the same label.
* FIXME: The core currently won't enforce it.
* @csrow: A pointer to the chip select row structure (the parent
* structure). The location of the rank is given by
* the (csrow->csrow_idx, chan_idx) vector.
*/
struct rank_info {
int chan_idx;
u32 ce_count;
char label[EDAC_MC_LABEL_LEN + 1];
struct csrow_info *csrow; /* the parent */ struct csrow_info *csrow; /* the parent */
}; };
...@@ -274,7 +351,7 @@ struct csrow_info { ...@@ -274,7 +351,7 @@ struct csrow_info {
/* channel information for this csrow */ /* channel information for this csrow */
u32 nr_channels; u32 nr_channels;
struct channel_info *channels; struct rank_info *channels;
}; };
struct mcidev_sysfs_group { struct mcidev_sysfs_group {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment