提交 87a5af24 编写于 作者: L Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac

Pull EDAC internal API changes from Mauro Carvalho Chehab:
 "This changeset is the first part of a series of patches that fixes the
  EDAC sybsystem.  On this set, it changes the Kernel EDAC API in order
  to properly represent the Intel i3/i5/i7, Xeon 3xxx/5xxx/7xxx, and
  Intel E5-xxxx memory controllers.

  The EDAC core used to assume that:

       - the DRAM chip select pin is directly accessed by the memory
         controller

       - when multiple channels are used, they're all filled with the
         same type of memory.

  None of the above premises is true on Intel memory controllers since
  2002, when RAMBUS and FB-DIMMs were introduced, and Advanced Memory
  Buffer or by some similar technologies hides the direct access to the
  DRAM pins.

  So, the existing drivers for those chipsets had to lie to the EDAC
  core, in general telling that just one channel is filled.  That
  produces some hard to understand error messages like:

       EDAC MC0: CE row 3, channel 0, label "DIMM1": 1 Unknown error(s): memory read error on FATAL area : cpu=0 Err=0008:00c2 (ch=2), addr = 0xad1f73480 => socket=0, Channel=0(mask=2), rank=1

  The location information there (row3 channel 0) is completely bogus:
  it has no physical meaning, and are just some random values that the
  driver uses to talk with the EDAC core.  The error actually happened
  at CPU socket 0, channel 0, slot 1, but this is not reported anywhere,
  as the EDAC core doesn't know anything about the memory layout.  So,
  only advanced users that know how the EDAC driver works and that tests
  their systems to see how DIMMs are mapped can actually benefit for
  such error logs.

  This patch series fixes the error report logic, in order to allow the
  EDAC to expose the memory architecture used by them to the EDAC core.
  So, as the EDAC core now understands how the memory is organized, it
  can provide an useful report:

       EDAC MC0: CE memory read error on DIMM1 (channel:0 slot:1 page:0x364b1b offset:0x600 grain:32 syndrome:0x0 - count:1 area:DRAM err_code:0001:0090 socket:0 channel_mask:1 rank:4)

  The location of the DIMM where the error happened is reported by "MC0"
  (cpu socket #0), at "channel:0 slot:1" location, and matches the
  physical location of the DIMM.

  There are two remaining issues not covered by this patch series:

       - The EDAC sysfs API will still report bogus values.  So,
         userspace tools like edac-utils will still use the bogus data;

       - Add a new tracepoint-based way to get the binary information
         about the errors.

  Those are on a second series of patches (also at -next), but will
  probably miss the train for 3.5, due to the slow review process."

Fix up trivial conflict (due to spelling correction of removed code) in
drivers/edac/edac_device.c

* git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-edac: (42 commits)
  i7core: fix ranks information at the per-channel struct
  i5000: Fix the fatal error handling
  i5100_edac: Fix a warning when compiled with 32 bits
  i82975x_edac: Test nr_pages earlier to save a few CPU cycles
  e752x_edac: provide more info about how DIMMS/ranks are mapped
  i5000_edac: Fix the logic that retrieves memory information
  i5400_edac: improve debug messages to better represent the filled memory
  edac: Cleanup the logs for i7core and sb edac drivers
  edac: Initialize the dimm label with the known information
  edac: Remove the legacy EDAC ABI
  x38_edac: convert driver to use the new edac ABI
  tile_edac: convert driver to use the new edac ABI
  sb_edac: convert driver to use the new edac ABI
  r82600_edac: convert driver to use the new edac ABI
  ppc4xx_edac: convert driver to use the new edac ABI
  pasemi_edac: convert driver to use the new edac ABI
  mv64x60_edac: convert driver to use the new edac ABI
  mpc85xx_edac: convert driver to use the new edac ABI
  i82975x_edac: convert driver to use the new edac ABI
  i82875p_edac: convert driver to use the new edac ABI
  ...
......@@ -715,25 +715,6 @@ static inline u64 input_addr_to_sys_addr(struct mem_ctl_info *mci,
input_addr_to_dram_addr(mci, input_addr));
}
/*
* Find the minimum and maximum InputAddr values that map to the given @csrow.
* Pass back these values in *input_addr_min and *input_addr_max.
*/
static void find_csrow_limits(struct mem_ctl_info *mci, int csrow,
u64 *input_addr_min, u64 *input_addr_max)
{
struct amd64_pvt *pvt;
u64 base, mask;
pvt = mci->pvt_info;
BUG_ON((csrow < 0) || (csrow >= pvt->csels[0].b_cnt));
get_cs_base_and_mask(pvt, csrow, 0, &base, &mask);
*input_addr_min = base & ~mask;
*input_addr_max = base | mask;
}
/* Map the Error address to a PAGE and PAGE OFFSET. */
static inline void error_address_to_page_and_offset(u64 error_address,
u32 *page, u32 *offset)
......@@ -1058,6 +1039,37 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
int channel, csrow;
u32 page, offset;
error_address_to_page_and_offset(sys_addr, &page, &offset);
/*
* Find out which node the error address belongs to. This may be
* different from the node that detected the error.
*/
src_mci = find_mc_by_sys_addr(mci, sys_addr);
if (!src_mci) {
amd64_mc_err(mci, "failed to map error addr 0x%lx to a node\n",
(unsigned long)sys_addr);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
page, offset, syndrome,
-1, -1, -1,
EDAC_MOD_STR,
"failed to map error addr to a node",
NULL);
return;
}
/* Now map the sys_addr to a CSROW */
csrow = sys_addr_to_csrow(src_mci, sys_addr);
if (csrow < 0) {
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
page, offset, syndrome,
-1, -1, -1,
EDAC_MOD_STR,
"failed to map error addr to a csrow",
NULL);
return;
}
/* CHIPKILL enabled */
if (pvt->nbcfg & NBCFG_CHIPKILL) {
channel = get_channel_from_ecc_syndrome(mci, syndrome);
......@@ -1067,9 +1079,15 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
* 2 DIMMs is in error. So we need to ID 'both' of them
* as suspect.
*/
amd64_mc_warn(mci, "unknown syndrome 0x%04x - possible "
"error reporting race\n", syndrome);
edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
amd64_mc_warn(src_mci, "unknown syndrome 0x%04x - "
"possible error reporting race\n",
syndrome);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
page, offset, syndrome,
csrow, -1, -1,
EDAC_MOD_STR,
"unknown syndrome - possible error reporting race",
NULL);
return;
}
} else {
......@@ -1084,28 +1102,10 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
channel = ((sys_addr & BIT(3)) != 0);
}
/*
* Find out which node the error address belongs to. This may be
* different from the node that detected the error.
*/
src_mci = find_mc_by_sys_addr(mci, sys_addr);
if (!src_mci) {
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;
}
/* Now map the sys_addr to a CSROW */
csrow = sys_addr_to_csrow(src_mci, sys_addr);
if (csrow < 0) {
edac_mc_handle_ce_no_info(src_mci, EDAC_MOD_STR);
} else {
error_address_to_page_and_offset(sys_addr, &page, &offset);
edac_mc_handle_ce(src_mci, page, offset, syndrome, csrow,
channel, EDAC_MOD_STR);
}
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, src_mci,
page, offset, syndrome,
csrow, channel, -1,
EDAC_MOD_STR, "", NULL);
}
static int ddr2_cs_size(unsigned i, bool dct_width)
......@@ -1611,15 +1611,20 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
u32 page, offset;
int nid, csrow, chan = 0;
error_address_to_page_and_offset(sys_addr, &page, &offset);
csrow = f1x_translate_sysaddr_to_cs(pvt, sys_addr, &nid, &chan);
if (csrow < 0) {
edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
page, offset, syndrome,
-1, -1, -1,
EDAC_MOD_STR,
"failed to map error addr to a csrow",
NULL);
return;
}
error_address_to_page_and_offset(sys_addr, &page, &offset);
/*
* We need the syndromes for channel detection only when we're
* ganged. Otherwise @chan should already contain the channel at
......@@ -1628,16 +1633,10 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
if (dct_ganging_enabled(pvt))
chan = get_channel_from_ecc_syndrome(mci, syndrome);
if (chan >= 0)
edac_mc_handle_ce(mci, page, offset, syndrome, csrow, chan,
EDAC_MOD_STR);
else
/*
* Channel unknown, report all channels on this CSROW as failed.
*/
for (chan = 0; chan < mci->csrows[csrow].nr_channels; chan++)
edac_mc_handle_ce(mci, page, offset, syndrome,
csrow, chan, EDAC_MOD_STR);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
page, offset, syndrome,
csrow, chan, -1,
EDAC_MOD_STR, "", NULL);
}
/*
......@@ -1918,7 +1917,12 @@ static void amd64_handle_ce(struct mem_ctl_info *mci, struct mce *m)
/* Ensure that the Error Address is VALID */
if (!(m->status & MCI_STATUS_ADDRV)) {
amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
edac_mc_handle_ce_no_info(mci, EDAC_MOD_STR);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
0, 0, 0,
-1, -1, -1,
EDAC_MOD_STR,
"HW has no ERROR_ADDRESS available",
NULL);
return;
}
......@@ -1942,11 +1946,17 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m)
if (!(m->status & MCI_STATUS_ADDRV)) {
amd64_mc_err(mci, "HW has no ERROR_ADDRESS available\n");
edac_mc_handle_ue_no_info(log_mci, EDAC_MOD_STR);
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
0, 0, 0,
-1, -1, -1,
EDAC_MOD_STR,
"HW has no ERROR_ADDRESS available",
NULL);
return;
}
sys_addr = get_error_address(m);
error_address_to_page_and_offset(sys_addr, &page, &offset);
/*
* Find out which node the error address belongs to. This may be
......@@ -1956,7 +1966,11 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m)
if (!src_mci) {
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);
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
page, offset, 0,
-1, -1, -1,
EDAC_MOD_STR,
"ERROR ADDRESS NOT mapped to a MC", NULL);
return;
}
......@@ -1966,10 +1980,17 @@ static void amd64_handle_ue(struct mem_ctl_info *mci, struct mce *m)
if (csrow < 0) {
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);
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
page, offset, 0,
-1, -1, -1,
EDAC_MOD_STR,
"ERROR ADDRESS NOT mapped to CS",
NULL);
} else {
error_address_to_page_and_offset(sys_addr, &page, &offset);
edac_mc_handle_ue(log_mci, page, offset, csrow, EDAC_MOD_STR);
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
page, offset, 0,
csrow, -1, -1,
EDAC_MOD_STR, "", NULL);
}
}
......@@ -2171,7 +2192,7 @@ static u32 amd64_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode) << (20 - PAGE_SHIFT);
debugf0(" (csrow=%d) DBAM map index= %d\n", csrow_nr, cs_mode);
debugf0(" nr_pages= %u channel-count = %d\n",
debugf0(" nr_pages/channel= %u channel-count = %d\n",
nr_pages, pvt->channel_count);
return nr_pages;
......@@ -2185,9 +2206,12 @@ static int init_csrows(struct mem_ctl_info *mci)
{
struct csrow_info *csrow;
struct amd64_pvt *pvt = mci->pvt_info;
u64 input_addr_min, input_addr_max, sys_addr, base, mask;
u64 base, mask;
u32 val;
int i, empty = 1;
int i, j, empty = 1;
enum mem_type mtype;
enum edac_type edac_mode;
int nr_pages = 0;
amd64_read_pci_cfg(pvt->F3, NBCFG, &val);
......@@ -2211,41 +2235,32 @@ static int init_csrows(struct mem_ctl_info *mci)
empty = 0;
if (csrow_enabled(i, 0, pvt))
csrow->nr_pages = amd64_csrow_nr_pages(pvt, 0, i);
nr_pages = amd64_csrow_nr_pages(pvt, 0, i);
if (csrow_enabled(i, 1, pvt))
csrow->nr_pages += amd64_csrow_nr_pages(pvt, 1, 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);
sys_addr = input_addr_to_sys_addr(mci, input_addr_max);
csrow->last_page = (u32) (sys_addr >> PAGE_SHIFT);
nr_pages += amd64_csrow_nr_pages(pvt, 1, i);
get_cs_base_and_mask(pvt, i, 0, &base, &mask);
csrow->page_mask = ~mask;
/* 8 bytes of resolution */
csrow->mtype = amd64_determine_memory_type(pvt, i);
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",
(unsigned long)input_addr_min,
(unsigned long)input_addr_max);
debugf1(" sys_addr: 0x%lx page_mask: 0x%lx\n",
(unsigned long)sys_addr, csrow->page_mask);
debugf1(" nr_pages: %u first_page: 0x%lx "
"last_page: 0x%lx\n",
(unsigned)csrow->nr_pages,
csrow->first_page, csrow->last_page);
debugf1(" nr_pages: %u\n", nr_pages * pvt->channel_count);
/*
* determine whether CHIPKILL or JUST ECC or NO ECC is operating
*/
if (pvt->nbcfg & NBCFG_ECC_ENABLE)
csrow->edac_mode =
(pvt->nbcfg & NBCFG_CHIPKILL) ?
EDAC_S4ECD4ED : EDAC_SECDED;
edac_mode = (pvt->nbcfg & NBCFG_CHIPKILL) ?
EDAC_S4ECD4ED : EDAC_SECDED;
else
csrow->edac_mode = EDAC_NONE;
edac_mode = EDAC_NONE;
for (j = 0; j < pvt->channel_count; j++) {
csrow->channels[j].dimm->mtype = mtype;
csrow->channels[j].dimm->edac_mode = edac_mode;
csrow->channels[j].dimm->nr_pages = nr_pages;
}
}
return empty;
......@@ -2540,6 +2555,7 @@ 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;
struct edac_mc_layer layers[2];
int err = 0, ret;
u8 nid = get_node_id(F2);
......@@ -2574,7 +2590,13 @@ static int amd64_init_one_instance(struct pci_dev *F2)
goto err_siblings;
ret = -ENOMEM;
mci = edac_mc_alloc(0, pvt->csels[0].b_cnt, pvt->channel_count, nid);
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = pvt->csels[0].b_cnt;
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = pvt->channel_count;
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(nid, ARRAY_SIZE(layers), layers, 0);
if (!mci)
goto err_siblings;
......
......@@ -29,7 +29,6 @@
edac_mc_chipset_printk(mci, level, "amd76x", fmt, ##arg)
#define AMD76X_NR_CSROWS 8
#define AMD76X_NR_CHANS 1
#define AMD76X_NR_DIMMS 4
/* AMD 76x register addresses - device 0 function 0 - PCI bridge */
......@@ -146,8 +145,10 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
if (handle_errors) {
row = (info->ecc_mode_status >> 4) & 0xf;
edac_mc_handle_ue(mci, mci->csrows[row].first_page, 0,
row, mci->ctl_name);
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
mci->csrows[row].first_page, 0, 0,
row, 0, -1,
mci->ctl_name, "", NULL);
}
}
......@@ -159,8 +160,10 @@ static int amd76x_process_error_info(struct mem_ctl_info *mci,
if (handle_errors) {
row = info->ecc_mode_status & 0xf;
edac_mc_handle_ce(mci, mci->csrows[row].first_page, 0,
0, row, 0, mci->ctl_name);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
mci->csrows[row].first_page, 0, 0,
row, 0, -1,
mci->ctl_name, "", NULL);
}
}
......@@ -186,11 +189,13 @@ static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
enum edac_type edac_mode)
{
struct csrow_info *csrow;
struct dimm_info *dimm;
u32 mba, mba_base, mba_mask, dms;
int index;
for (index = 0; index < mci->nr_csrows; index++) {
csrow = &mci->csrows[index];
dimm = csrow->channels[0].dimm;
/* find the DRAM Chip Select Base address and mask */
pci_read_config_dword(pdev,
......@@ -203,13 +208,13 @@ static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
mba_mask = ((mba & 0xff80) << 16) | 0x7fffffUL;
pci_read_config_dword(pdev, AMD76X_DRAM_MODE_STATUS, &dms);
csrow->first_page = mba_base >> PAGE_SHIFT;
csrow->nr_pages = (mba_mask + 1) >> PAGE_SHIFT;
csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
dimm->nr_pages = (mba_mask + 1) >> PAGE_SHIFT;
csrow->last_page = csrow->first_page + dimm->nr_pages - 1;
csrow->page_mask = mba_mask >> PAGE_SHIFT;
csrow->grain = csrow->nr_pages << PAGE_SHIFT;
csrow->mtype = MEM_RDDR;
csrow->dtype = ((dms >> index) & 0x1) ? DEV_X4 : DEV_UNKNOWN;
csrow->edac_mode = edac_mode;
dimm->grain = dimm->nr_pages << PAGE_SHIFT;
dimm->mtype = MEM_RDDR;
dimm->dtype = ((dms >> index) & 0x1) ? DEV_X4 : DEV_UNKNOWN;
dimm->edac_mode = edac_mode;
}
}
......@@ -230,7 +235,8 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
EDAC_SECDED,
EDAC_SECDED
};
struct mem_ctl_info *mci = NULL;
struct mem_ctl_info *mci;
struct edac_mc_layer layers[2];
u32 ems;
u32 ems_mode;
struct amd76x_error_info discard;
......@@ -238,11 +244,17 @@ static int amd76x_probe1(struct pci_dev *pdev, int dev_idx)
debugf0("%s()\n", __func__);
pci_read_config_dword(pdev, AMD76X_ECC_MODE_STATUS, &ems);
ems_mode = (ems >> 10) & 0x3;
mci = edac_mc_alloc(0, AMD76X_NR_CSROWS, AMD76X_NR_CHANS, 0);
if (mci == NULL) {
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = AMD76X_NR_CSROWS;
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = 1;
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0);
if (mci == NULL)
return -ENOMEM;
}
debugf0("%s(): mci = %p\n", __func__, mci);
mci->dev = &pdev->dev;
......
......@@ -48,8 +48,9 @@ static void cell_edac_count_ce(struct mem_ctl_info *mci, int chan, u64 ar)
syndrome = (ar & 0x000000001fe00000ul) >> 21;
/* TODO: Decoding of the error address */
edac_mc_handle_ce(mci, csrow->first_page + pfn, offset,
syndrome, 0, chan, "");
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
csrow->first_page + pfn, offset, syndrome,
0, chan, -1, "", "", NULL);
}
static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar)
......@@ -69,7 +70,9 @@ static void cell_edac_count_ue(struct mem_ctl_info *mci, int chan, u64 ar)
offset = address & ~PAGE_MASK;
/* TODO: Decoding of the error address */
edac_mc_handle_ue(mci, csrow->first_page + pfn, offset, 0, "");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
csrow->first_page + pfn, offset, 0,
0, chan, -1, "", "", NULL);
}
static void cell_edac_check(struct mem_ctl_info *mci)
......@@ -124,8 +127,11 @@ static void cell_edac_check(struct mem_ctl_info *mci)
static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
{
struct csrow_info *csrow = &mci->csrows[0];
struct dimm_info *dimm;
struct cell_edac_priv *priv = mci->pvt_info;
struct device_node *np;
int j;
u32 nr_pages;
for (np = NULL;
(np = of_find_node_by_name(np, "memory")) != NULL;) {
......@@ -140,15 +146,20 @@ static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
if (of_node_to_nid(np) != priv->node)
continue;
csrow->first_page = r.start >> PAGE_SHIFT;
csrow->nr_pages = resource_size(&r) >> PAGE_SHIFT;
csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
csrow->mtype = MEM_XDR;
csrow->edac_mode = EDAC_SECDED;
nr_pages = resource_size(&r) >> PAGE_SHIFT;
csrow->last_page = csrow->first_page + nr_pages - 1;
for (j = 0; j < csrow->nr_channels; j++) {
dimm = csrow->channels[j].dimm;
dimm->mtype = MEM_XDR;
dimm->edac_mode = EDAC_SECDED;
dimm->nr_pages = nr_pages / csrow->nr_channels;
}
dev_dbg(mci->dev,
"Initialized on node %d, chanmask=0x%x,"
" first_page=0x%lx, nr_pages=0x%x\n",
priv->node, priv->chanmask,
csrow->first_page, csrow->nr_pages);
csrow->first_page, nr_pages);
break;
}
}
......@@ -157,9 +168,10 @@ static int __devinit cell_edac_probe(struct platform_device *pdev)
{
struct cbe_mic_tm_regs __iomem *regs;
struct mem_ctl_info *mci;
struct edac_mc_layer layers[2];
struct cell_edac_priv *priv;
u64 reg;
int rc, chanmask;
int rc, chanmask, num_chans;
regs = cbe_get_cpu_mic_tm_regs(cbe_node_to_cpu(pdev->id));
if (regs == NULL)
......@@ -184,8 +196,16 @@ static int __devinit cell_edac_probe(struct platform_device *pdev)
in_be64(&regs->mic_fir));
/* Allocate & init EDAC MC data structure */
mci = edac_mc_alloc(sizeof(struct cell_edac_priv), 1,
chanmask == 3 ? 2 : 1, pdev->id);
num_chans = chanmask == 3 ? 2 : 1;
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = 1;
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = num_chans;
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(pdev->id, ARRAY_SIZE(layers), layers,
sizeof(struct cell_edac_priv));
if (mci == NULL)
return -ENOMEM;
priv = mci->pvt_info;
......
......@@ -329,9 +329,10 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci)
{
struct cpc925_mc_pdata *pdata = mci->pvt_info;
struct csrow_info *csrow;
int index;
struct dimm_info *dimm;
int index, j;
u32 mbmr, mbbar, bba;
unsigned long row_size, last_nr_pages = 0;
unsigned long row_size, nr_pages, last_nr_pages = 0;
get_total_mem(pdata);
......@@ -350,36 +351,41 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci)
row_size = bba * (1UL << 28); /* 256M */
csrow->first_page = last_nr_pages;
csrow->nr_pages = row_size >> PAGE_SHIFT;
csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
nr_pages = row_size >> PAGE_SHIFT;
csrow->last_page = csrow->first_page + nr_pages - 1;
last_nr_pages = csrow->last_page + 1;
csrow->mtype = MEM_RDDR;
csrow->edac_mode = EDAC_SECDED;
switch (csrow->nr_channels) {
case 1: /* Single channel */
csrow->grain = 32; /* four-beat burst of 32 bytes */
break;
case 2: /* Dual channel */
default:
csrow->grain = 64; /* four-beat burst of 64 bytes */
break;
}
switch ((mbmr & MBMR_MODE_MASK) >> MBMR_MODE_SHIFT) {
case 6: /* 0110, no way to differentiate X8 VS X16 */
case 5: /* 0101 */
case 8: /* 1000 */
csrow->dtype = DEV_X16;
break;
case 7: /* 0111 */
case 9: /* 1001 */
csrow->dtype = DEV_X8;
break;
default:
csrow->dtype = DEV_UNKNOWN;
break;
for (j = 0; j < csrow->nr_channels; j++) {
dimm = csrow->channels[j].dimm;
dimm->nr_pages = nr_pages / csrow->nr_channels;
dimm->mtype = MEM_RDDR;
dimm->edac_mode = EDAC_SECDED;
switch (csrow->nr_channels) {
case 1: /* Single channel */
dimm->grain = 32; /* four-beat burst of 32 bytes */
break;
case 2: /* Dual channel */
default:
dimm->grain = 64; /* four-beat burst of 64 bytes */
break;
}
switch ((mbmr & MBMR_MODE_MASK) >> MBMR_MODE_SHIFT) {
case 6: /* 0110, no way to differentiate X8 VS X16 */
case 5: /* 0101 */
case 8: /* 1000 */
dimm->dtype = DEV_X16;
break;
case 7: /* 0111 */
case 9: /* 1001 */
dimm->dtype = DEV_X8;
break;
default:
dimm->dtype = DEV_UNKNOWN;
break;
}
}
}
}
......@@ -549,13 +555,18 @@ static void cpc925_mc_check(struct mem_ctl_info *mci)
if (apiexcp & CECC_EXCP_DETECTED) {
cpc925_mc_printk(mci, KERN_INFO, "DRAM CECC Fault\n");
channel = cpc925_mc_find_channel(mci, syndrome);
edac_mc_handle_ce(mci, pfn, offset, syndrome,
csrow, channel, mci->ctl_name);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
pfn, offset, syndrome,
csrow, channel, -1,
mci->ctl_name, "", NULL);
}
if (apiexcp & UECC_EXCP_DETECTED) {
cpc925_mc_printk(mci, KERN_INFO, "DRAM UECC Fault\n");
edac_mc_handle_ue(mci, pfn, offset, csrow, mci->ctl_name);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
pfn, offset, 0,
csrow, -1, -1,
mci->ctl_name, "", NULL);
}
cpc925_mc_printk(mci, KERN_INFO, "Dump registers:\n");
......@@ -927,6 +938,7 @@ static int __devinit cpc925_probe(struct platform_device *pdev)
{
static int edac_mc_idx;
struct mem_ctl_info *mci;
struct edac_mc_layer layers[2];
void __iomem *vbase;
struct cpc925_mc_pdata *pdata;
struct resource *r;
......@@ -962,9 +974,16 @@ static int __devinit cpc925_probe(struct platform_device *pdev)
goto err2;
}
nr_channels = cpc925_mc_get_channels(vbase);
mci = edac_mc_alloc(sizeof(struct cpc925_mc_pdata),
CPC925_NR_CSROWS, nr_channels + 1, edac_mc_idx);
nr_channels = cpc925_mc_get_channels(vbase) + 1;
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = CPC925_NR_CSROWS;
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = nr_channels;
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers,
sizeof(struct cpc925_mc_pdata));
if (!mci) {
cpc925_printk(KERN_ERR, "No memory for mem_ctl_info\n");
res = -ENOMEM;
......
......@@ -4,7 +4,11 @@
* This file may be distributed under the terms of the
* GNU General Public License.
*
* See "enum e752x_chips" below for supported chipsets
* Implement support for the e7520, E7525, e7320 and i3100 memory controllers.
*
* Datasheets:
* http://www.intel.in/content/www/in/en/chipsets/e7525-memory-controller-hub-datasheet.html
* ftp://download.intel.com/design/intarch/datashts/31345803.pdf
*
* Written by Tom Zimmerman
*
......@@ -13,8 +17,6 @@
* Wang Zhenyu at intel.com
* Dave Jiang at mvista.com
*
* $Id: edac_e752x.c,v 1.5.2.11 2005/10/05 00:43:44 dsp_llnl Exp $
*
*/
#include <linux/module.h>
......@@ -187,6 +189,25 @@ enum e752x_chips {
I3100 = 3
};
/*
* Those chips Support single-rank and dual-rank memories only.
*
* On e752x chips, the odd rows are present only on dual-rank memories.
* Dividing the rank by two will provide the dimm#
*
* i3100 MC has a different mapping: it supports only 4 ranks.
*
* The mapping is (from 1 to n):
* slot single-ranked double-ranked
* dimm #1 -> rank #4 NA
* dimm #2 -> rank #3 NA
* dimm #3 -> rank #2 Ranks 2 and 3
* dimm #4 -> rank $1 Ranks 1 and 4
*
* FIXME: The current mapping for i3100 considers that it supports up to 8
* ranks/chanel, but datasheet says that the MC supports only 4 ranks.
*/
struct e752x_pvt {
struct pci_dev *bridge_ck;
struct pci_dev *dev_d0f0;
......@@ -350,8 +371,10 @@ static void do_process_ce(struct mem_ctl_info *mci, u16 error_one,
channel = !(error_one & 1);
/* e752x mc reads 34:6 of the DRAM linear address */
edac_mc_handle_ce(mci, page, offset_in_page(sec1_add << 4),
sec1_syndrome, row, channel, "e752x CE");
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
page, offset_in_page(sec1_add << 4), sec1_syndrome,
row, channel, -1,
"e752x CE", "", NULL);
}
static inline void process_ce(struct mem_ctl_info *mci, u16 error_one,
......@@ -385,9 +408,12 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
edac_mc_find_csrow_by_page(mci, block_page);
/* e752x mc reads 34:6 of the DRAM linear address */
edac_mc_handle_ue(mci, block_page,
offset_in_page(error_2b << 4),
row, "e752x UE from Read");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
block_page,
offset_in_page(error_2b << 4), 0,
row, -1, -1,
"e752x UE from Read", "", NULL);
}
if (error_one & 0x0404) {
error_2b = scrb_add;
......@@ -401,9 +427,11 @@ static void do_process_ue(struct mem_ctl_info *mci, u16 error_one,
edac_mc_find_csrow_by_page(mci, block_page);
/* e752x mc reads 34:6 of the DRAM linear address */
edac_mc_handle_ue(mci, block_page,
offset_in_page(error_2b << 4),
row, "e752x UE from Scruber");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
block_page,
offset_in_page(error_2b << 4), 0,
row, -1, -1,
"e752x UE from Scruber", "", NULL);
}
}
......@@ -426,7 +454,9 @@ static inline void process_ue_no_info_wr(struct mem_ctl_info *mci,
return;
debugf3("%s()\n", __func__);
edac_mc_handle_ue_no_info(mci, "e752x UE log memory write");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
-1, -1, -1,
"e752x UE log memory write", "", NULL);
}
static void do_process_ded_retry(struct mem_ctl_info *mci, u16 error,
......@@ -1044,7 +1074,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
int drc_drbg; /* DRB granularity 0=64mb, 1=128mb */
int drc_ddim; /* DRAM Data Integrity Mode 0=none, 2=edac */
u8 value;
u32 dra, drc, cumul_size;
u32 dra, drc, cumul_size, i, nr_pages;
dra = 0;
for (index = 0; index < 4; index++) {
......@@ -1053,7 +1083,7 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
dra |= dra_reg << (index * 8);
}
pci_read_config_dword(pdev, E752X_DRC, &drc);
drc_chan = dual_channel_active(ddrcsr);
drc_chan = dual_channel_active(ddrcsr) ? 1 : 0;
drc_drbg = drc_chan + 1; /* 128 in dual mode, 64 in single */
drc_ddim = (drc >> 20) & 0x3;
......@@ -1078,26 +1108,33 @@ static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
csrow->first_page = last_cumul_size;
csrow->last_page = cumul_size - 1;
csrow->nr_pages = cumul_size - last_cumul_size;
nr_pages = cumul_size - last_cumul_size;
last_cumul_size = cumul_size;
csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */
csrow->mtype = MEM_RDDR; /* only one type supported */
csrow->dtype = mem_dev ? DEV_X4 : DEV_X8;
/*
* if single channel or x8 devices then SECDED
* if dual channel and x4 then S4ECD4ED
*/
if (drc_ddim) {
if (drc_chan && mem_dev) {
csrow->edac_mode = EDAC_S4ECD4ED;
mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
} else {
csrow->edac_mode = EDAC_SECDED;
mci->edac_cap |= EDAC_FLAG_SECDED;
}
} else
csrow->edac_mode = EDAC_NONE;
for (i = 0; i < csrow->nr_channels; i++) {
struct dimm_info *dimm = csrow->channels[i].dimm;
debugf3("Initializing rank at (%i,%i)\n", index, i);
dimm->nr_pages = nr_pages / csrow->nr_channels;
dimm->grain = 1 << 12; /* 4KiB - resolution of CELOG */
dimm->mtype = MEM_RDDR; /* only one type supported */
dimm->dtype = mem_dev ? DEV_X4 : DEV_X8;
/*
* if single channel or x8 devices then SECDED
* if dual channel and x4 then S4ECD4ED
*/
if (drc_ddim) {
if (drc_chan && mem_dev) {
dimm->edac_mode = EDAC_S4ECD4ED;
mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
} else {
dimm->edac_mode = EDAC_SECDED;
mci->edac_cap |= EDAC_FLAG_SECDED;
}
} else
dimm->edac_mode = EDAC_NONE;
}
}
}
......@@ -1226,6 +1263,7 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
u16 pci_data;
u8 stat8;
struct mem_ctl_info *mci;
struct edac_mc_layer layers[2];
struct e752x_pvt *pvt;
u16 ddrcsr;
int drc_chan; /* Number of channels 0=1chan,1=2chan */
......@@ -1252,11 +1290,15 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx)
/* Dual channel = 1, Single channel = 0 */
drc_chan = dual_channel_active(ddrcsr);
mci = edac_mc_alloc(sizeof(*pvt), E752X_NR_CSROWS, drc_chan + 1, 0);
if (mci == NULL) {
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = E752X_NR_CSROWS;
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = drc_chan + 1;
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt));
if (mci == NULL)
return -ENOMEM;
}
debugf3("%s(): init mci\n", __func__);
mci->mtype_cap = MEM_FLAG_RDDR;
......
......@@ -10,6 +10,9 @@
* Based on work by Dan Hollis <goemon at anime dot net> and others.
* http://www.anime.net/~goemon/linux-ecc/
*
* Datasheet:
* http://www.intel.com/content/www/us/en/chipsets/e7501-chipset-memory-controller-hub-datasheet.html
*
* Contributors:
* Eric Biederman (Linux Networx)
* Tom Zimmerman (Linux Networx)
......@@ -71,7 +74,7 @@
#endif /* PCI_DEVICE_ID_INTEL_7505_1_ERR */
#define E7XXX_NR_CSROWS 8 /* number of csrows */
#define E7XXX_NR_DIMMS 8 /* FIXME - is this correct? */
#define E7XXX_NR_DIMMS 8 /* 2 channels, 4 dimms/channel */
/* E7XXX register addresses - device 0 function 0 */
#define E7XXX_DRB 0x60 /* DRAM row boundary register (8b) */
......@@ -216,13 +219,15 @@ static void process_ce(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
row = edac_mc_find_csrow_by_page(mci, page);
/* convert syndrome to channel */
channel = e7xxx_find_channel(syndrome);
edac_mc_handle_ce(mci, page, 0, syndrome, row, channel, "e7xxx CE");
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, page, 0, syndrome,
row, channel, -1, "e7xxx CE", "", NULL);
}
static void process_ce_no_info(struct mem_ctl_info *mci)
{
debugf3("%s()\n", __func__);
edac_mc_handle_ce_no_info(mci, "e7xxx CE log register overflow");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, -1, -1, -1,
"e7xxx CE log register overflow", "", NULL);
}
static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
......@@ -236,13 +241,17 @@ static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
/* FIXME - should use PAGE_SHIFT */
block_page = error_2b >> 6; /* convert to 4k address */
row = edac_mc_find_csrow_by_page(mci, block_page);
edac_mc_handle_ue(mci, block_page, 0, row, "e7xxx UE");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, block_page, 0, 0,
row, -1, -1, "e7xxx UE", "", NULL);
}
static void process_ue_no_info(struct mem_ctl_info *mci)
{
debugf3("%s()\n", __func__);
edac_mc_handle_ue_no_info(mci, "e7xxx UE log register overflow");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0, -1, -1, -1,
"e7xxx UE log register overflow", "", NULL);
}
static void e7xxx_get_error_info(struct mem_ctl_info *mci,
......@@ -347,11 +356,12 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
int dev_idx, u32 drc)
{
unsigned long last_cumul_size;
int index;
int index, j;
u8 value;
u32 dra, cumul_size;
u32 dra, cumul_size, nr_pages;
int drc_chan, drc_drbg, drc_ddim, mem_dev;
struct csrow_info *csrow;
struct dimm_info *dimm;
pci_read_config_dword(pdev, E7XXX_DRA, &dra);
drc_chan = dual_channel_active(drc, dev_idx);
......@@ -379,26 +389,32 @@ static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
csrow->first_page = last_cumul_size;
csrow->last_page = cumul_size - 1;
csrow->nr_pages = cumul_size - last_cumul_size;
nr_pages = cumul_size - last_cumul_size;
last_cumul_size = cumul_size;
csrow->grain = 1 << 12; /* 4KiB - resolution of CELOG */
csrow->mtype = MEM_RDDR; /* only one type supported */
csrow->dtype = mem_dev ? DEV_X4 : DEV_X8;
/*
* if single channel or x8 devices then SECDED
* if dual channel and x4 then S4ECD4ED
*/
if (drc_ddim) {
if (drc_chan && mem_dev) {
csrow->edac_mode = EDAC_S4ECD4ED;
mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
} else {
csrow->edac_mode = EDAC_SECDED;
mci->edac_cap |= EDAC_FLAG_SECDED;
}
} else
csrow->edac_mode = EDAC_NONE;
for (j = 0; j < drc_chan + 1; j++) {
dimm = csrow->channels[j].dimm;
dimm->nr_pages = nr_pages / (drc_chan + 1);
dimm->grain = 1 << 12; /* 4KiB - resolution of CELOG */
dimm->mtype = MEM_RDDR; /* only one type supported */
dimm->dtype = mem_dev ? DEV_X4 : DEV_X8;
/*
* if single channel or x8 devices then SECDED
* if dual channel and x4 then S4ECD4ED
*/
if (drc_ddim) {
if (drc_chan && mem_dev) {
dimm->edac_mode = EDAC_S4ECD4ED;
mci->edac_cap |= EDAC_FLAG_S4ECD4ED;
} else {
dimm->edac_mode = EDAC_SECDED;
mci->edac_cap |= EDAC_FLAG_SECDED;
}
} else
dimm->edac_mode = EDAC_NONE;
}
}
}
......@@ -406,6 +422,7 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
{
u16 pci_data;
struct mem_ctl_info *mci = NULL;
struct edac_mc_layer layers[2];
struct e7xxx_pvt *pvt = NULL;
u32 drc;
int drc_chan;
......@@ -416,8 +433,21 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
pci_read_config_dword(pdev, E7XXX_DRC, &drc);
drc_chan = dual_channel_active(drc, dev_idx);
mci = edac_mc_alloc(sizeof(*pvt), E7XXX_NR_CSROWS, drc_chan + 1, 0);
/*
* According with the datasheet, this device has a maximum of
* 4 DIMMS per channel, either single-rank or dual-rank. So, the
* total amount of dimms is 8 (E7XXX_NR_DIMMS).
* That means that the DIMM is mapped as CSROWs, and the channel
* will map the rank. So, an error to either channel should be
* attributed to the same dimm.
*/
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = E7XXX_NR_CSROWS;
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = drc_chan + 1;
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt));
if (mci == NULL)
return -ENOMEM;
......
......@@ -447,8 +447,10 @@ static inline void pci_write_bits32(struct pci_dev *pdev, int offset,
#endif /* CONFIG_PCI */
extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
unsigned nr_chans, int edac_index);
struct mem_ctl_info *edac_mc_alloc(unsigned mc_num,
unsigned n_layers,
struct edac_mc_layer *layers,
unsigned sz_pvt);
extern int edac_mc_add_mc(struct mem_ctl_info *mci);
extern void edac_mc_free(struct mem_ctl_info *mci);
extern struct mem_ctl_info *edac_mc_find(int idx);
......@@ -456,35 +458,17 @@ extern struct mem_ctl_info *find_mci_by_dev(struct device *dev);
extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev);
extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci,
unsigned long page);
/*
* The no info errors are used when error overflows are reported.
* There are a limited number of error logging registers that can
* be exausted. When all registers are exhausted and an additional
* error occurs then an error overflow register records that an
* error occurred and the type of error, but doesn't have any
* further information. The ce/ue versions make for cleaner
* reporting logic and function interface - reduces conditional
* statement clutter and extra function arguments.
*/
extern void edac_mc_handle_ce(struct mem_ctl_info *mci,
unsigned long page_frame_number,
unsigned long offset_in_page,
unsigned long syndrome, int row, int channel,
const char *msg);
extern void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci,
const char *msg);
extern void edac_mc_handle_ue(struct mem_ctl_info *mci,
unsigned long page_frame_number,
unsigned long offset_in_page, int row,
const char *msg);
extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci,
const char *msg);
extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, unsigned int csrow,
unsigned int channel0, unsigned int channel1,
char *msg);
extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, unsigned int csrow,
unsigned int channel, char *msg);
void edac_mc_handle_error(const enum hw_event_mc_err_type type,
struct mem_ctl_info *mci,
const unsigned long page_frame_number,
const unsigned long offset_in_page,
const unsigned long syndrome,
const int layer0,
const int layer1,
const int layer2,
const char *msg,
const char *other_detail,
const void *mcelog);
/*
* edac_device APIs
......@@ -496,6 +480,7 @@ extern void edac_device_handle_ue(struct edac_device_ctl_info *edac_dev,
extern void edac_device_handle_ce(struct edac_device_ctl_info *edac_dev,
int inst_nr, int block_nr, const char *msg);
extern int edac_device_alloc_index(void);
extern const char *edac_layer_name[];
/*
* edac_pci APIs
......
......@@ -79,7 +79,7 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
unsigned total_size;
unsigned count;
unsigned instance, block, attr;
void *pvt;
void *pvt, *p;
int err;
debugf4("%s() instances=%d blocks=%d\n",
......@@ -92,35 +92,30 @@ struct edac_device_ctl_info *edac_device_alloc_ctl_info(
* to be at least as stringent as what the compiler would
* provide if we could simply hardcode everything into a single struct.
*/
dev_ctl = (struct edac_device_ctl_info *)NULL;
p = NULL;
dev_ctl = edac_align_ptr(&p, sizeof(*dev_ctl), 1);
/* Calc the 'end' offset past end of ONE ctl_info structure
* which will become the start of the 'instance' array
*/
dev_inst = edac_align_ptr(&dev_ctl[1], sizeof(*dev_inst));
dev_inst = edac_align_ptr(&p, sizeof(*dev_inst), nr_instances);
/* Calc the 'end' offset past the instance array within the ctl_info
* which will become the start of the block array
*/
dev_blk = edac_align_ptr(&dev_inst[nr_instances], sizeof(*dev_blk));
count = nr_instances * nr_blocks;
dev_blk = edac_align_ptr(&p, sizeof(*dev_blk), count);
/* Calc the 'end' offset past the dev_blk array
* which will become the start of the attrib array, if any.
*/
count = nr_instances * nr_blocks;
dev_attrib = edac_align_ptr(&dev_blk[count], sizeof(*dev_attrib));
/* Check for case of when an attribute array is specified */
if (nr_attrib > 0) {
/* calc how many nr_attrib we need */
/* calc how many nr_attrib we need */
if (nr_attrib > 0)
count *= nr_attrib;
dev_attrib = edac_align_ptr(&p, sizeof(*dev_attrib), count);
/* Calc the 'end' offset past the attributes array */
pvt = edac_align_ptr(&dev_attrib[count], sz_private);
} else {
/* no attribute array specified */
pvt = edac_align_ptr(dev_attrib, sz_private);
}
/* Calc the 'end' offset past the attributes array */
pvt = edac_align_ptr(&p, sz_private, 1);
/* 'pvt' now points to where the private data area is.
* At this point 'pvt' (like dev_inst,dev_blk and dev_attrib)
......
此差异已折叠。
......@@ -144,25 +144,31 @@ static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data,
static ssize_t csrow_size_show(struct csrow_info *csrow, char *data,
int private)
{
return sprintf(data, "%u\n", PAGES_TO_MiB(csrow->nr_pages));
int i;
u32 nr_pages = 0;
for (i = 0; i < csrow->nr_channels; i++)
nr_pages += csrow->channels[i].dimm->nr_pages;
return sprintf(data, "%u\n", PAGES_TO_MiB(nr_pages));
}
static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data,
int private)
{
return sprintf(data, "%s\n", mem_types[csrow->mtype]);
return sprintf(data, "%s\n", mem_types[csrow->channels[0].dimm->mtype]);
}
static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data,
int private)
{
return sprintf(data, "%s\n", dev_types[csrow->dtype]);
return sprintf(data, "%s\n", dev_types[csrow->channels[0].dimm->dtype]);
}
static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data,
int private)
{
return sprintf(data, "%s\n", edac_caps[csrow->edac_mode]);
return sprintf(data, "%s\n", edac_caps[csrow->channels[0].dimm->edac_mode]);
}
/* show/store functions for DIMM Label attributes */
......@@ -170,11 +176,11 @@ static ssize_t channel_dimm_label_show(struct csrow_info *csrow,
char *data, int channel)
{
/* if field has not been initialized, there is nothing to send */
if (!csrow->channels[channel].label[0])
if (!csrow->channels[channel].dimm->label[0])
return 0;
return snprintf(data, EDAC_MC_LABEL_LEN, "%s\n",
csrow->channels[channel].label);
csrow->channels[channel].dimm->label);
}
static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
......@@ -184,8 +190,8 @@ static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
ssize_t max_size = 0;
max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1);
strncpy(csrow->channels[channel].label, data, max_size);
csrow->channels[channel].label[max_size] = '\0';
strncpy(csrow->channels[channel].dimm->label, data, max_size);
csrow->channels[channel].dimm->label[max_size] = '\0';
return max_size;
}
......@@ -419,8 +425,8 @@ static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
mci->ue_noinfo_count = 0;
mci->ce_noinfo_count = 0;
mci->ue_count = 0;
mci->ce_count = 0;
mci->ue_mc = 0;
mci->ce_mc = 0;
for (row = 0; row < mci->nr_csrows; row++) {
struct csrow_info *ri = &mci->csrows[row];
......@@ -489,12 +495,12 @@ static ssize_t mci_sdram_scrub_rate_show(struct mem_ctl_info *mci, char *data)
/* default attribute files for the MCI object */
static ssize_t mci_ue_count_show(struct mem_ctl_info *mci, char *data)
{
return sprintf(data, "%d\n", mci->ue_count);
return sprintf(data, "%d\n", mci->ue_mc);
}
static ssize_t mci_ce_count_show(struct mem_ctl_info *mci, char *data)
{
return sprintf(data, "%d\n", mci->ce_count);
return sprintf(data, "%d\n", mci->ce_mc);
}
static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data)
......@@ -519,16 +525,16 @@ static ssize_t mci_ctl_name_show(struct mem_ctl_info *mci, char *data)
static ssize_t mci_size_mb_show(struct mem_ctl_info *mci, char *data)
{
int total_pages, csrow_idx;
int total_pages = 0, csrow_idx, j;
for (total_pages = csrow_idx = 0; csrow_idx < mci->nr_csrows;
csrow_idx++) {
for (csrow_idx = 0; csrow_idx < mci->nr_csrows; csrow_idx++) {
struct csrow_info *csrow = &mci->csrows[csrow_idx];
if (!csrow->nr_pages)
continue;
for (j = 0; j < csrow->nr_channels; j++) {
struct dimm_info *dimm = csrow->channels[j].dimm;
total_pages += csrow->nr_pages;
total_pages += dimm->nr_pages;
}
}
return sprintf(data, "%u\n", PAGES_TO_MiB(total_pages));
......@@ -900,7 +906,7 @@ static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci,
*/
int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
{
int i;
int i, j;
int err;
struct csrow_info *csrow;
struct kobject *kobj_mci = &mci->edac_mci_kobj;
......@@ -934,10 +940,13 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
/* Make directories for each CSROW object under the mc<id> kobject
*/
for (i = 0; i < mci->nr_csrows; i++) {
int nr_pages = 0;
csrow = &mci->csrows[i];
for (j = 0; j < csrow->nr_channels; j++)
nr_pages += csrow->channels[j].dimm->nr_pages;
/* Only expose populated CSROWs */
if (csrow->nr_pages > 0) {
if (nr_pages > 0) {
err = edac_create_csrow_object(mci, csrow, i);
if (err) {
debugf1("%s() failure: create csrow %d obj\n",
......@@ -949,12 +958,15 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
return 0;
/* CSROW error: backout what has already been registered, */
fail1:
for (i--; i >= 0; i--) {
if (csrow->nr_pages > 0) {
int nr_pages = 0;
csrow = &mci->csrows[i];
for (j = 0; j < csrow->nr_channels; j++)
nr_pages += csrow->channels[j].dimm->nr_pages;
if (nr_pages > 0)
kobject_put(&mci->csrows[i].kobj);
}
}
/* remove the mci instance's attributes, if any */
......@@ -973,14 +985,20 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
*/
void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
{
int i;
struct csrow_info *csrow;
int i, j;
debugf0("%s()\n", __func__);
/* remove all csrow kobjects */
debugf4("%s() unregister this mci kobj\n", __func__);
for (i = 0; i < mci->nr_csrows; i++) {
if (mci->csrows[i].nr_pages > 0) {
int nr_pages = 0;
csrow = &mci->csrows[i];
for (j = 0; j < csrow->nr_channels; j++)
nr_pages += csrow->channels[j].dimm->nr_pages;
if (nr_pages > 0) {
debugf0("%s() unreg csrow-%d\n", __func__, i);
kobject_put(&mci->csrows[i].kobj);
}
......
......@@ -50,7 +50,7 @@ extern void edac_device_reset_delay_period(struct edac_device_ctl_info
*edac_dev, unsigned long value);
extern void edac_mc_reset_delay_period(int value);
extern void *edac_align_ptr(void *ptr, unsigned size);
extern void *edac_align_ptr(void **p, unsigned size, int n_elems);
/*
* EDAC PCI functions
......
......@@ -42,13 +42,13 @@ struct edac_pci_ctl_info *edac_pci_alloc_ctl_info(unsigned int sz_pvt,
const char *edac_pci_name)
{
struct edac_pci_ctl_info *pci;
void *pvt;
void *p = NULL, *pvt;
unsigned int size;
debugf1("%s()\n", __func__);
pci = (struct edac_pci_ctl_info *)0;
pvt = edac_align_ptr(&pci[1], sz_pvt);
pci = edac_align_ptr(&p, sizeof(*pci), 1);
pvt = edac_align_ptr(&p, 1, sz_pvt);
size = ((unsigned long)pvt) + sz_pvt;
/* Alloc the needed control struct memory */
......
......@@ -245,7 +245,9 @@ static int i3000_process_error_info(struct mem_ctl_info *mci,
return 1;
if ((info->errsts ^ info->errsts2) & I3000_ERRSTS_BITS) {
edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
-1, -1, -1,
"UE overwrote CE", "", NULL);
info->errsts = info->errsts2;
}
......@@ -256,10 +258,15 @@ static int i3000_process_error_info(struct mem_ctl_info *mci,
row = edac_mc_find_csrow_by_page(mci, pfn);
if (info->errsts & I3000_ERRSTS_UE)
edac_mc_handle_ue(mci, pfn, offset, row, "i3000 UE");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
pfn, offset, 0,
row, -1, -1,
"i3000 UE", "", NULL);
else
edac_mc_handle_ce(mci, pfn, offset, info->derrsyn, row,
multi_chan ? channel : 0, "i3000 CE");
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
pfn, offset, info->derrsyn,
row, multi_chan ? channel : 0, -1,
"i3000 CE", "", NULL);
return 1;
}
......@@ -304,9 +311,10 @@ static int i3000_is_interleaved(const unsigned char *c0dra,
static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
{
int rc;
int i;
int i, j;
struct mem_ctl_info *mci = NULL;
unsigned long last_cumul_size;
struct edac_mc_layer layers[2];
unsigned long last_cumul_size, nr_pages;
int interleaved, nr_channels;
unsigned char dra[I3000_RANKS / 2], drb[I3000_RANKS];
unsigned char *c0dra = dra, *c1dra = &dra[I3000_RANKS_PER_CHANNEL / 2];
......@@ -347,7 +355,14 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
*/
interleaved = i3000_is_interleaved(c0dra, c1dra, c0drb, c1drb);
nr_channels = interleaved ? 2 : 1;
mci = edac_mc_alloc(0, I3000_RANKS / nr_channels, nr_channels, 0);
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = I3000_RANKS / nr_channels;
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = nr_channels;
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0);
if (!mci)
return -ENOMEM;
......@@ -386,19 +401,23 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
cumul_size <<= 1;
debugf3("MC: %s(): (%d) cumul_size 0x%x\n",
__func__, i, cumul_size);
if (cumul_size == last_cumul_size) {
csrow->mtype = MEM_EMPTY;
if (cumul_size == last_cumul_size)
continue;
}
csrow->first_page = last_cumul_size;
csrow->last_page = cumul_size - 1;
csrow->nr_pages = cumul_size - last_cumul_size;
nr_pages = cumul_size - last_cumul_size;
last_cumul_size = cumul_size;
csrow->grain = I3000_DEAP_GRAIN;
csrow->mtype = MEM_DDR2;
csrow->dtype = DEV_UNKNOWN;
csrow->edac_mode = EDAC_UNKNOWN;
for (j = 0; j < nr_channels; j++) {
struct dimm_info *dimm = csrow->channels[j].dimm;
dimm->nr_pages = nr_pages / nr_channels;
dimm->grain = I3000_DEAP_GRAIN;
dimm->mtype = MEM_DDR2;
dimm->dtype = DEV_UNKNOWN;
dimm->edac_mode = EDAC_UNKNOWN;
}
}
/*
......
......@@ -23,6 +23,7 @@
#define PCI_DEVICE_ID_INTEL_3200_HB 0x29f0
#define I3200_DIMMS 4
#define I3200_RANKS 8
#define I3200_RANKS_PER_CHANNEL 4
#define I3200_CHANNELS 2
......@@ -217,21 +218,25 @@ static void i3200_process_error_info(struct mem_ctl_info *mci,
return;
if ((info->errsts ^ info->errsts2) & I3200_ERRSTS_BITS) {
edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
-1, -1, -1, "UE overwrote CE", "", NULL);
info->errsts = info->errsts2;
}
for (channel = 0; channel < nr_channels; channel++) {
log = info->eccerrlog[channel];
if (log & I3200_ECCERRLOG_UE) {
edac_mc_handle_ue(mci, 0, 0,
eccerrlog_row(channel, log),
"i3200 UE");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
0, 0, 0,
eccerrlog_row(channel, log),
-1, -1,
"i3000 UE", "", NULL);
} else if (log & I3200_ECCERRLOG_CE) {
edac_mc_handle_ce(mci, 0, 0,
eccerrlog_syndrome(log),
eccerrlog_row(channel, log), 0,
"i3200 CE");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
0, 0, eccerrlog_syndrome(log),
eccerrlog_row(channel, log),
-1, -1,
"i3000 UE", "", NULL);
}
}
}
......@@ -319,9 +324,9 @@ static unsigned long drb_to_nr_pages(
static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
{
int rc;
int i;
int i, j;
struct mem_ctl_info *mci = NULL;
unsigned long last_page;
struct edac_mc_layer layers[2];
u16 drbs[I3200_CHANNELS][I3200_RANKS_PER_CHANNEL];
bool stacked;
void __iomem *window;
......@@ -336,8 +341,14 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
i3200_get_drbs(window, drbs);
nr_channels = how_many_channels(pdev);
mci = edac_mc_alloc(sizeof(struct i3200_priv), I3200_RANKS,
nr_channels, 0);
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = I3200_DIMMS;
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = nr_channels;
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
sizeof(struct i3200_priv));
if (!mci)
return -ENOMEM;
......@@ -366,7 +377,6 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
* cumulative; the last one will contain the total memory
* contained in all ranks.
*/
last_page = -1UL;
for (i = 0; i < mci->nr_csrows; i++) {
unsigned long nr_pages;
struct csrow_info *csrow = &mci->csrows[i];
......@@ -375,20 +385,18 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
i / I3200_RANKS_PER_CHANNEL,
i % I3200_RANKS_PER_CHANNEL);
if (nr_pages == 0) {
csrow->mtype = MEM_EMPTY;
if (nr_pages == 0)
continue;
}
csrow->first_page = last_page + 1;
last_page += nr_pages;
csrow->last_page = last_page;
csrow->nr_pages = nr_pages;
for (j = 0; j < nr_channels; j++) {
struct dimm_info *dimm = csrow->channels[j].dimm;
csrow->grain = nr_pages << PAGE_SHIFT;
csrow->mtype = MEM_DDR2;
csrow->dtype = DEV_UNKNOWN;
csrow->edac_mode = EDAC_UNKNOWN;
dimm->nr_pages = nr_pages / nr_channels;
dimm->grain = nr_pages << PAGE_SHIFT;
dimm->mtype = MEM_DDR2;
dimm->dtype = DEV_UNKNOWN;
dimm->edac_mode = EDAC_UNKNOWN;
}
}
i3200_clear_error_info(mci);
......
......@@ -270,7 +270,8 @@
#define MTR3 0x8C
#define NUM_MTRS 4
#define CHANNELS_PER_BRANCH (2)
#define CHANNELS_PER_BRANCH 2
#define MAX_BRANCHES 2
/* Defines to extract the vaious fields from the
* MTRx - Memory Technology Registers
......@@ -473,7 +474,6 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
char msg[EDAC_MC_LABEL_LEN + 1 + 160];
char *specific = NULL;
u32 allErrors;
int branch;
int channel;
int bank;
int rank;
......@@ -485,8 +485,7 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
if (!allErrors)
return; /* if no error, return now */
branch = EXTRACT_FBDCHAN_INDX(info->ferr_fat_fbd);
channel = branch;
channel = EXTRACT_FBDCHAN_INDX(info->ferr_fat_fbd);
/* Use the NON-Recoverable macros to extract data */
bank = NREC_BANK(info->nrecmema);
......@@ -495,9 +494,9 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
ras = NREC_RAS(info->nrecmemb);
cas = NREC_CAS(info->nrecmemb);
debugf0("\t\tCSROW= %d Channels= %d,%d (Branch= %d "
"DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
rank, channel, channel + 1, branch >> 1, bank,
debugf0("\t\tCSROW= %d Channel= %d "
"(DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
rank, channel, bank,
rdwr ? "Write" : "Read", ras, cas);
/* Only 1 bit will be on */
......@@ -533,13 +532,14 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
/* Form out message */
snprintf(msg, sizeof(msg),
"(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d CAS=%d "
"FATAL Err=0x%x (%s))",
branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas,
allErrors, specific);
"Bank=%d RAS=%d CAS=%d FATAL Err=0x%x (%s)",
bank, ras, cas, allErrors, specific);
/* Call the helper to output message */
edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg);
edac_mc_handle_error(HW_EVENT_ERR_FATAL, mci, 0, 0, 0,
channel >> 1, channel & 1, rank,
rdwr ? "Write error" : "Read error",
msg, NULL);
}
/*
......@@ -633,13 +633,14 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
/* Form out message */
snprintf(msg, sizeof(msg),
"(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d "
"CAS=%d, UE Err=0x%x (%s))",
branch >> 1, bank, rdwr ? "Write" : "Read", ras, cas,
ue_errors, specific);
"Rank=%d Bank=%d RAS=%d CAS=%d, UE Err=0x%x (%s)",
rank, bank, ras, cas, ue_errors, specific);
/* Call the helper to output message */
edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg);
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
channel >> 1, -1, rank,
rdwr ? "Write error" : "Read error",
msg, NULL);
}
/* Check correctable errors */
......@@ -685,13 +686,16 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
/* Form out message */
snprintf(msg, sizeof(msg),
"(Branch=%d DRAM-Bank=%d RDWR=%s RAS=%d "
"Rank=%d Bank=%d RDWR=%s RAS=%d "
"CAS=%d, CE Err=0x%x (%s))", branch >> 1, bank,
rdwr ? "Write" : "Read", ras, cas, ce_errors,
specific);
/* Call the helper to output message */
edac_mc_handle_fbd_ce(mci, rank, channel, msg);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0,
channel >> 1, channel % 2, rank,
rdwr ? "Write error" : "Read error",
msg, NULL);
}
if (!misc_messages)
......@@ -731,11 +735,12 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
/* Form out message */
snprintf(msg, sizeof(msg),
"(Branch=%d Err=%#x (%s))", branch >> 1,
misc_errors, specific);
"Err=%#x (%s)", misc_errors, specific);
/* Call the helper to output message */
edac_mc_handle_fbd_ce(mci, 0, 0, msg);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0,
branch >> 1, -1, -1,
"Misc error", msg, NULL);
}
}
......@@ -956,14 +961,14 @@ static int determine_amb_present_reg(struct i5000_pvt *pvt, int channel)
*
* return the proper MTR register as determine by the csrow and channel desired
*/
static int determine_mtr(struct i5000_pvt *pvt, int csrow, int channel)
static int determine_mtr(struct i5000_pvt *pvt, int slot, int channel)
{
int mtr;
if (channel < CHANNELS_PER_BRANCH)
mtr = pvt->b0_mtr[csrow >> 1];
mtr = pvt->b0_mtr[slot];
else
mtr = pvt->b1_mtr[csrow >> 1];
mtr = pvt->b1_mtr[slot];
return mtr;
}
......@@ -988,37 +993,34 @@ static void decode_mtr(int slot_row, u16 mtr)
debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
}
static void handle_channel(struct i5000_pvt *pvt, int csrow, int channel,
static void handle_channel(struct i5000_pvt *pvt, int slot, int channel,
struct i5000_dimm_info *dinfo)
{
int mtr;
int amb_present_reg;
int addrBits;
mtr = determine_mtr(pvt, csrow, channel);
mtr = determine_mtr(pvt, slot, channel);
if (MTR_DIMMS_PRESENT(mtr)) {
amb_present_reg = determine_amb_present_reg(pvt, channel);
/* Determine if there is a DIMM present in this DIMM slot */
if (amb_present_reg & (1 << (csrow >> 1))) {
/* Determine if there is a DIMM present in this DIMM slot */
if (amb_present_reg) {
dinfo->dual_rank = MTR_DIMM_RANK(mtr);
if (!((dinfo->dual_rank == 0) &&
((csrow & 0x1) == 0x1))) {
/* Start with the number of bits for a Bank
* on the DRAM */
addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr);
/* Add thenumber of ROW bits */
addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr);
/* add the number of COLUMN bits */
addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr);
addrBits += 6; /* add 64 bits per DIMM */
addrBits -= 20; /* divide by 2^^20 */
addrBits -= 3; /* 8 bits per bytes */
dinfo->megabytes = 1 << addrBits;
}
/* Start with the number of bits for a Bank
* on the DRAM */
addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr);
/* Add the number of ROW bits */
addrBits += MTR_DIMM_ROWS_ADDR_BITS(mtr);
/* add the number of COLUMN bits */
addrBits += MTR_DIMM_COLS_ADDR_BITS(mtr);
addrBits += 6; /* add 64 bits per DIMM */
addrBits -= 20; /* divide by 2^^20 */
addrBits -= 3; /* 8 bits per bytes */
dinfo->megabytes = 1 << addrBits;
}
}
}
......@@ -1032,10 +1034,9 @@ static void handle_channel(struct i5000_pvt *pvt, int csrow, int channel,
static void calculate_dimm_size(struct i5000_pvt *pvt)
{
struct i5000_dimm_info *dinfo;
int csrow, max_csrows;
int slot, channel, branch;
char *p, *mem_buffer;
int space, n;
int channel;
/* ================= Generate some debug output ================= */
space = PAGE_SIZE;
......@@ -1046,22 +1047,17 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
return;
}
n = snprintf(p, space, "\n");
p += n;
space -= n;
/* Scan all the actual CSROWS (which is # of DIMMS * 2)
/* Scan all the actual slots
* and calculate the information for each DIMM
* Start with the highest csrow first, to display it first
* and work toward the 0th csrow
* Start with the highest slot first, to display it first
* and work toward the 0th slot
*/
max_csrows = pvt->maxdimmperch * 2;
for (csrow = max_csrows - 1; csrow >= 0; csrow--) {
for (slot = pvt->maxdimmperch - 1; slot >= 0; slot--) {
/* on an odd csrow, first output a 'boundary' marker,
/* on an odd slot, first output a 'boundary' marker,
* then reset the message buffer */
if (csrow & 0x1) {
n = snprintf(p, space, "---------------------------"
if (slot & 0x1) {
n = snprintf(p, space, "--------------------------"
"--------------------------------");
p += n;
space -= n;
......@@ -1069,30 +1065,39 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
p = mem_buffer;
space = PAGE_SIZE;
}
n = snprintf(p, space, "csrow %2d ", csrow);
n = snprintf(p, space, "slot %2d ", slot);
p += n;
space -= n;
for (channel = 0; channel < pvt->maxch; channel++) {
dinfo = &pvt->dimm_info[csrow][channel];
handle_channel(pvt, csrow, channel, dinfo);
n = snprintf(p, space, "%4d MB | ", dinfo->megabytes);
dinfo = &pvt->dimm_info[slot][channel];
handle_channel(pvt, slot, channel, dinfo);
if (dinfo->megabytes)
n = snprintf(p, space, "%4d MB %dR| ",
dinfo->megabytes, dinfo->dual_rank + 1);
else
n = snprintf(p, space, "%4d MB | ", 0);
p += n;
space -= n;
}
n = snprintf(p, space, "\n");
p += n;
space -= n;
debugf2("%s\n", mem_buffer);
p = mem_buffer;
space = PAGE_SIZE;
}
/* Output the last bottom 'boundary' marker */
n = snprintf(p, space, "---------------------------"
"--------------------------------\n");
n = snprintf(p, space, "--------------------------"
"--------------------------------");
p += n;
space -= n;
debugf2("%s\n", mem_buffer);
p = mem_buffer;
space = PAGE_SIZE;
/* now output the 'channel' labels */
n = snprintf(p, space, " ");
n = snprintf(p, space, " ");
p += n;
space -= n;
for (channel = 0; channel < pvt->maxch; channel++) {
......@@ -1100,9 +1105,17 @@ static void calculate_dimm_size(struct i5000_pvt *pvt)
p += n;
space -= n;
}
n = snprintf(p, space, "\n");
debugf2("%s\n", mem_buffer);
p = mem_buffer;
space = PAGE_SIZE;
n = snprintf(p, space, " ");
p += n;
space -= n;
for (branch = 0; branch < MAX_BRANCHES; branch++) {
n = snprintf(p, space, " branch %d | ", branch);
p += n;
space -= n;
}
/* output the last message and free buffer */
debugf2("%s\n", mem_buffer);
......@@ -1235,13 +1248,13 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci)
static int i5000_init_csrows(struct mem_ctl_info *mci)
{
struct i5000_pvt *pvt;
struct csrow_info *p_csrow;
struct dimm_info *dimm;
int empty, channel_count;
int max_csrows;
int mtr, mtr1;
int mtr;
int csrow_megs;
int channel;
int csrow;
int slot;
pvt = mci->pvt_info;
......@@ -1250,43 +1263,40 @@ static int i5000_init_csrows(struct mem_ctl_info *mci)
empty = 1; /* Assume NO memory */
for (csrow = 0; csrow < max_csrows; csrow++) {
p_csrow = &mci->csrows[csrow];
p_csrow->csrow_idx = csrow;
/* use branch 0 for the basis */
mtr = pvt->b0_mtr[csrow >> 1];
mtr1 = pvt->b1_mtr[csrow >> 1];
/* if no DIMMS on this row, continue */
if (!MTR_DIMMS_PRESENT(mtr) && !MTR_DIMMS_PRESENT(mtr1))
continue;
/*
* FIXME: The memory layout used to map slot/channel into the
* real memory architecture is weird: branch+slot are "csrows"
* and channel is channel. That required an extra array (dimm_info)
* to map the dimms. A good cleanup would be to remove this array,
* and do a loop here with branch, channel, slot
*/
for (slot = 0; slot < max_csrows; slot++) {
for (channel = 0; channel < pvt->maxch; channel++) {
/* FAKE OUT VALUES, FIXME */
p_csrow->first_page = 0 + csrow * 20;
p_csrow->last_page = 9 + csrow * 20;
p_csrow->page_mask = 0xFFF;
mtr = determine_mtr(pvt, slot, channel);
p_csrow->grain = 8;
if (!MTR_DIMMS_PRESENT(mtr))
continue;
csrow_megs = 0;
for (channel = 0; channel < pvt->maxch; channel++) {
csrow_megs += pvt->dimm_info[csrow][channel].megabytes;
}
dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers,
channel / MAX_BRANCHES,
channel % MAX_BRANCHES, slot);
p_csrow->nr_pages = csrow_megs << 8;
csrow_megs = pvt->dimm_info[slot][channel].megabytes;
dimm->grain = 8;
/* Assume DDR2 for now */
p_csrow->mtype = MEM_FB_DDR2;
/* Assume DDR2 for now */
dimm->mtype = MEM_FB_DDR2;
/* ask what device type on this row */
if (MTR_DRAM_WIDTH(mtr))
p_csrow->dtype = DEV_X8;
else
p_csrow->dtype = DEV_X4;
/* ask what device type on this row */
if (MTR_DRAM_WIDTH(mtr))
dimm->dtype = DEV_X8;
else
dimm->dtype = DEV_X4;
p_csrow->edac_mode = EDAC_S8ECD8ED;
dimm->edac_mode = EDAC_S8ECD8ED;
dimm->nr_pages = csrow_megs << 8;
}
empty = 0;
}
......@@ -1317,7 +1327,7 @@ static void i5000_enable_error_reporting(struct mem_ctl_info *mci)
}
/*
* i5000_get_dimm_and_channel_counts(pdev, &num_csrows, &num_channels)
* i5000_get_dimm_and_channel_counts(pdev, &nr_csrows, &num_channels)
*
* ask the device how many channels are present and how many CSROWS
* as well
......@@ -1332,7 +1342,7 @@ static void i5000_get_dimm_and_channel_counts(struct pci_dev *pdev,
* supported on this memory controller
*/
pci_read_config_byte(pdev, MAXDIMMPERCH, &value);
*num_dimms_per_channel = (int)value *2;
*num_dimms_per_channel = (int)value;
pci_read_config_byte(pdev, MAXCH, &value);
*num_channels = (int)value;
......@@ -1348,10 +1358,10 @@ static void i5000_get_dimm_and_channel_counts(struct pci_dev *pdev,
static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
{
struct mem_ctl_info *mci;
struct edac_mc_layer layers[3];
struct i5000_pvt *pvt;
int num_channels;
int num_dimms_per_channel;
int num_csrows;
debugf0("MC: %s: %s(), pdev bus %u dev=0x%x fn=0x%x\n",
__FILE__, __func__,
......@@ -1377,14 +1387,22 @@ static int i5000_probe1(struct pci_dev *pdev, int dev_idx)
*/
i5000_get_dimm_and_channel_counts(pdev, &num_dimms_per_channel,
&num_channels);
num_csrows = num_dimms_per_channel * 2;
debugf0("MC: %s(): Number of - Channels= %d DIMMS= %d CSROWS= %d\n",
__func__, num_channels, num_dimms_per_channel, num_csrows);
debugf0("MC: %s(): Number of Branches=2 Channels= %d DIMMS= %d\n",
__func__, num_channels, num_dimms_per_channel);
/* allocate a new MC control structure */
mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0);
layers[0].type = EDAC_MC_LAYER_BRANCH;
layers[0].size = MAX_BRANCHES;
layers[0].is_virt_csrow = false;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = num_channels / MAX_BRANCHES;
layers[1].is_virt_csrow = false;
layers[2].type = EDAC_MC_LAYER_SLOT;
layers[2].size = num_dimms_per_channel;
layers[2].is_virt_csrow = true;
mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt));
if (mci == NULL)
return -ENOMEM;
......
......@@ -14,6 +14,11 @@
* rows for each respective channel are laid out one after another,
* the first half belonging to channel 0, the second half belonging
* to channel 1.
*
* This driver is for DDR2 DIMMs, and it uses chip select to select among the
* several ranks. However, instead of showing memories as ranks, it outputs
* them as DIMM's. An internal table creates the association between ranks
* and DIMM's.
*/
#include <linux/module.h>
#include <linux/init.h>
......@@ -410,14 +415,6 @@ static int i5100_csrow_to_chan(const struct mem_ctl_info *mci, int csrow)
return csrow / priv->ranksperchan;
}
static unsigned i5100_rank_to_csrow(const struct mem_ctl_info *mci,
int chan, int rank)
{
const struct i5100_priv *priv = mci->pvt_info;
return chan * priv->ranksperchan + rank;
}
static void i5100_handle_ce(struct mem_ctl_info *mci,
int chan,
unsigned bank,
......@@ -427,17 +424,17 @@ static void i5100_handle_ce(struct mem_ctl_info *mci,
unsigned ras,
const char *msg)
{
const int csrow = i5100_rank_to_csrow(mci, chan, rank);
char detail[80];
printk(KERN_ERR
"CE chan %d, bank %u, rank %u, syndrome 0x%lx, "
"cas %u, ras %u, csrow %u, label \"%s\": %s\n",
chan, bank, rank, syndrome, cas, ras,
csrow, mci->csrows[csrow].channels[0].label, msg);
/* Form out message */
snprintf(detail, sizeof(detail),
"bank %u, cas %u, ras %u\n",
bank, cas, ras);
mci->ce_count++;
mci->csrows[csrow].ce_count++;
mci->csrows[csrow].channels[0].ce_count++;
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
0, 0, syndrome,
chan, rank, -1,
msg, detail, NULL);
}
static void i5100_handle_ue(struct mem_ctl_info *mci,
......@@ -449,16 +446,17 @@ static void i5100_handle_ue(struct mem_ctl_info *mci,
unsigned ras,
const char *msg)
{
const int csrow = i5100_rank_to_csrow(mci, chan, rank);
char detail[80];
printk(KERN_ERR
"UE chan %d, bank %u, rank %u, syndrome 0x%lx, "
"cas %u, ras %u, csrow %u, label \"%s\": %s\n",
chan, bank, rank, syndrome, cas, ras,
csrow, mci->csrows[csrow].channels[0].label, msg);
/* Form out message */
snprintf(detail, sizeof(detail),
"bank %u, cas %u, ras %u\n",
bank, cas, ras);
mci->ue_count++;
mci->csrows[csrow].ue_count++;
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
0, 0, syndrome,
chan, rank, -1,
msg, detail, NULL);
}
static void i5100_read_log(struct mem_ctl_info *mci, int chan,
......@@ -835,10 +833,10 @@ static void __devinit i5100_init_interleaving(struct pci_dev *pdev,
static void __devinit i5100_init_csrows(struct mem_ctl_info *mci)
{
int i;
unsigned long total_pages = 0UL;
struct i5100_priv *priv = mci->pvt_info;
for (i = 0; i < mci->nr_csrows; i++) {
for (i = 0; i < mci->tot_dimms; i++) {
struct dimm_info *dimm;
const unsigned long npages = i5100_npages(mci, i);
const unsigned chan = i5100_csrow_to_chan(mci, i);
const unsigned rank = i5100_csrow_to_rank(mci, i);
......@@ -846,33 +844,23 @@ static void __devinit i5100_init_csrows(struct mem_ctl_info *mci)
if (!npages)
continue;
/*
* FIXME: these two are totally bogus -- I don't see how to
* map them correctly to this structure...
*/
mci->csrows[i].first_page = total_pages;
mci->csrows[i].last_page = total_pages + npages - 1;
mci->csrows[i].page_mask = 0UL;
mci->csrows[i].nr_pages = npages;
mci->csrows[i].grain = 32;
mci->csrows[i].csrow_idx = i;
mci->csrows[i].dtype =
(priv->mtr[chan][rank].width == 4) ? DEV_X4 : DEV_X8;
mci->csrows[i].ue_count = 0;
mci->csrows[i].ce_count = 0;
mci->csrows[i].mtype = MEM_RDDR2;
mci->csrows[i].edac_mode = EDAC_SECDED;
mci->csrows[i].mci = mci;
mci->csrows[i].nr_channels = 1;
mci->csrows[i].channels[0].chan_idx = 0;
mci->csrows[i].channels[0].ce_count = 0;
mci->csrows[i].channels[0].csrow = mci->csrows + i;
snprintf(mci->csrows[i].channels[0].label,
sizeof(mci->csrows[i].channels[0].label),
"DIMM%u", i5100_rank_to_slot(mci, chan, rank));
total_pages += npages;
dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers,
chan, rank, 0);
dimm->nr_pages = npages;
if (npages) {
dimm->grain = 32;
dimm->dtype = (priv->mtr[chan][rank].width == 4) ?
DEV_X4 : DEV_X8;
dimm->mtype = MEM_RDDR2;
dimm->edac_mode = EDAC_SECDED;
snprintf(dimm->label, sizeof(dimm->label),
"DIMM%u",
i5100_rank_to_slot(mci, chan, rank));
}
debugf2("dimm channel %d, rank %d, size %ld\n",
chan, rank, (long)PAGES_TO_MiB(npages));
}
}
......@@ -881,6 +869,7 @@ static int __devinit i5100_init_one(struct pci_dev *pdev,
{
int rc;
struct mem_ctl_info *mci;
struct edac_mc_layer layers[2];
struct i5100_priv *priv;
struct pci_dev *ch0mm, *ch1mm;
int ret = 0;
......@@ -941,7 +930,14 @@ static int __devinit i5100_init_one(struct pci_dev *pdev,
goto bail_ch1;
}
mci = edac_mc_alloc(sizeof(*priv), ranksperch * 2, 1, 0);
layers[0].type = EDAC_MC_LAYER_CHANNEL;
layers[0].size = 2;
layers[0].is_virt_csrow = false;
layers[1].type = EDAC_MC_LAYER_SLOT;
layers[1].size = ranksperch;
layers[1].is_virt_csrow = true;
mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
sizeof(*priv));
if (!mci) {
ret = -ENOMEM;
goto bail_disable_ch1;
......
......@@ -18,6 +18,10 @@
* Intel 5400 Chipset Memory Controller Hub (MCH) - Datasheet
* http://developer.intel.com/design/chipsets/datashts/313070.htm
*
* This Memory Controller manages DDR2 FB-DIMMs. It has 2 branches, each with
* 2 channels operating in lockstep no-mirror mode. Each channel can have up to
* 4 dimm's, each with up to 8GB.
*
*/
#include <linux/module.h>
......@@ -44,12 +48,10 @@
edac_mc_chipset_printk(mci, level, "i5400", fmt, ##arg)
/* Limits for i5400 */
#define NUM_MTRS_PER_BRANCH 4
#define MAX_BRANCHES 2
#define CHANNELS_PER_BRANCH 2
#define MAX_DIMMS_PER_CHANNEL NUM_MTRS_PER_BRANCH
#define MAX_CHANNELS 4
/* max possible csrows per channel */
#define MAX_CSROWS (MAX_DIMMS_PER_CHANNEL)
#define DIMMS_PER_CHANNEL 4
#define MAX_CHANNELS (MAX_BRANCHES * CHANNELS_PER_BRANCH)
/* Device 16,
* Function 0: System Address
......@@ -347,16 +349,16 @@ struct i5400_pvt {
u16 mir0, mir1;
u16 b0_mtr[NUM_MTRS_PER_BRANCH]; /* Memory Technlogy Reg */
u16 b0_mtr[DIMMS_PER_CHANNEL]; /* Memory Technlogy Reg */
u16 b0_ambpresent0; /* Branch 0, Channel 0 */
u16 b0_ambpresent1; /* Brnach 0, Channel 1 */
u16 b1_mtr[NUM_MTRS_PER_BRANCH]; /* Memory Technlogy Reg */
u16 b1_mtr[DIMMS_PER_CHANNEL]; /* Memory Technlogy Reg */
u16 b1_ambpresent0; /* Branch 1, Channel 8 */
u16 b1_ambpresent1; /* Branch 1, Channel 1 */
/* DIMM information matrix, allocating architecture maximums */
struct i5400_dimm_info dimm_info[MAX_CSROWS][MAX_CHANNELS];
struct i5400_dimm_info dimm_info[DIMMS_PER_CHANNEL][MAX_CHANNELS];
/* Actual values for this controller */
int maxch; /* Max channels */
......@@ -532,13 +534,15 @@ static void i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci,
int ras, cas;
int errnum;
char *type = NULL;
enum hw_event_mc_err_type tp_event = HW_EVENT_ERR_UNCORRECTED;
if (!allErrors)
return; /* if no error, return now */
if (allErrors & ERROR_FAT_MASK)
if (allErrors & ERROR_FAT_MASK) {
type = "FATAL";
else if (allErrors & FERR_NF_UNCORRECTABLE)
tp_event = HW_EVENT_ERR_FATAL;
} else if (allErrors & FERR_NF_UNCORRECTABLE)
type = "NON-FATAL uncorrected";
else
type = "NON-FATAL recoverable";
......@@ -556,7 +560,7 @@ static void i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci,
ras = nrec_ras(info);
cas = nrec_cas(info);
debugf0("\t\tCSROW= %d Channels= %d,%d (Branch= %d "
debugf0("\t\tDIMM= %d Channels= %d,%d (Branch= %d "
"DRAM Bank= %d Buffer ID = %d rdwr= %s ras= %d cas= %d)\n",
rank, channel, channel + 1, branch >> 1, bank,
buf_id, rdwr_str(rdwr), ras, cas);
......@@ -566,13 +570,13 @@ static void i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci,
/* Form out message */
snprintf(msg, sizeof(msg),
"%s (Branch=%d DRAM-Bank=%d Buffer ID = %d RDWR=%s "
"RAS=%d CAS=%d %s Err=0x%lx (%s))",
type, branch >> 1, bank, buf_id, rdwr_str(rdwr), ras, cas,
type, allErrors, error_name[errnum]);
"Bank=%d Buffer ID = %d RAS=%d CAS=%d Err=0x%lx (%s)",
bank, buf_id, ras, cas, allErrors, error_name[errnum]);
/* Call the helper to output message */
edac_mc_handle_fbd_ue(mci, rank, channel, channel + 1, msg);
edac_mc_handle_error(tp_event, mci, 0, 0, 0,
branch >> 1, -1, rank,
rdwr ? "Write error" : "Read error",
msg, NULL);
}
/*
......@@ -630,7 +634,7 @@ static void i5400_process_nonfatal_error_info(struct mem_ctl_info *mci,
/* Only 1 bit will be on */
errnum = find_first_bit(&allErrors, ARRAY_SIZE(error_name));
debugf0("\t\tCSROW= %d Channel= %d (Branch %d "
debugf0("\t\tDIMM= %d Channel= %d (Branch %d "
"DRAM Bank= %d rdwr= %s ras= %d cas= %d)\n",
rank, channel, branch >> 1, bank,
rdwr_str(rdwr), ras, cas);
......@@ -642,8 +646,10 @@ static void i5400_process_nonfatal_error_info(struct mem_ctl_info *mci,
branch >> 1, bank, rdwr_str(rdwr), ras, cas,
allErrors, error_name[errnum]);
/* Call the helper to output message */
edac_mc_handle_fbd_ce(mci, rank, channel, msg);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0,
branch >> 1, channel % 2, rank,
rdwr ? "Write error" : "Read error",
msg, NULL);
return;
}
......@@ -831,8 +837,8 @@ static int i5400_get_devices(struct mem_ctl_info *mci, int dev_idx)
/*
* determine_amb_present
*
* the information is contained in NUM_MTRS_PER_BRANCH different
* registers determining which of the NUM_MTRS_PER_BRANCH requires
* the information is contained in DIMMS_PER_CHANNEL different
* registers determining which of the DIMMS_PER_CHANNEL requires
* knowing which channel is in question
*
* 2 branches, each with 2 channels
......@@ -861,11 +867,11 @@ static int determine_amb_present_reg(struct i5400_pvt *pvt, int channel)
}
/*
* determine_mtr(pvt, csrow, channel)
* determine_mtr(pvt, dimm, channel)
*
* return the proper MTR register as determine by the csrow and desired channel
* return the proper MTR register as determine by the dimm and desired channel
*/
static int determine_mtr(struct i5400_pvt *pvt, int csrow, int channel)
static int determine_mtr(struct i5400_pvt *pvt, int dimm, int channel)
{
int mtr;
int n;
......@@ -873,11 +879,11 @@ static int determine_mtr(struct i5400_pvt *pvt, int csrow, int channel)
/* There is one MTR for each slot pair of FB-DIMMs,
Each slot pair may be at branch 0 or branch 1.
*/
n = csrow;
n = dimm;
if (n >= NUM_MTRS_PER_BRANCH) {
debugf0("ERROR: trying to access an invalid csrow: %d\n",
csrow);
if (n >= DIMMS_PER_CHANNEL) {
debugf0("ERROR: trying to access an invalid dimm: %d\n",
dimm);
return 0;
}
......@@ -913,19 +919,19 @@ static void decode_mtr(int slot_row, u16 mtr)
debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
}
static void handle_channel(struct i5400_pvt *pvt, int csrow, int channel,
static void handle_channel(struct i5400_pvt *pvt, int dimm, int channel,
struct i5400_dimm_info *dinfo)
{
int mtr;
int amb_present_reg;
int addrBits;
mtr = determine_mtr(pvt, csrow, channel);
mtr = determine_mtr(pvt, dimm, channel);
if (MTR_DIMMS_PRESENT(mtr)) {
amb_present_reg = determine_amb_present_reg(pvt, channel);
/* Determine if there is a DIMM present in this DIMM slot */
if (amb_present_reg & (1 << csrow)) {
if (amb_present_reg & (1 << dimm)) {
/* Start with the number of bits for a Bank
* on the DRAM */
addrBits = MTR_DRAM_BANKS_ADDR_BITS(mtr);
......@@ -954,10 +960,10 @@ static void handle_channel(struct i5400_pvt *pvt, int csrow, int channel,
static void calculate_dimm_size(struct i5400_pvt *pvt)
{
struct i5400_dimm_info *dinfo;
int csrow, max_csrows;
int dimm, max_dimms;
char *p, *mem_buffer;
int space, n;
int channel;
int channel, branch;
/* ================= Generate some debug output ================= */
space = PAGE_SIZE;
......@@ -968,32 +974,32 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
return;
}
/* Scan all the actual CSROWS
/* Scan all the actual DIMMS
* and calculate the information for each DIMM
* Start with the highest csrow first, to display it first
* and work toward the 0th csrow
* Start with the highest dimm first, to display it first
* and work toward the 0th dimm
*/
max_csrows = pvt->maxdimmperch;
for (csrow = max_csrows - 1; csrow >= 0; csrow--) {
max_dimms = pvt->maxdimmperch;
for (dimm = max_dimms - 1; dimm >= 0; dimm--) {
/* on an odd csrow, first output a 'boundary' marker,
/* on an odd dimm, first output a 'boundary' marker,
* then reset the message buffer */
if (csrow & 0x1) {
if (dimm & 0x1) {
n = snprintf(p, space, "---------------------------"
"--------------------------------");
"-------------------------------");
p += n;
space -= n;
debugf2("%s\n", mem_buffer);
p = mem_buffer;
space = PAGE_SIZE;
}
n = snprintf(p, space, "csrow %2d ", csrow);
n = snprintf(p, space, "dimm %2d ", dimm);
p += n;
space -= n;
for (channel = 0; channel < pvt->maxch; channel++) {
dinfo = &pvt->dimm_info[csrow][channel];
handle_channel(pvt, csrow, channel, dinfo);
dinfo = &pvt->dimm_info[dimm][channel];
handle_channel(pvt, dimm, channel, dinfo);
n = snprintf(p, space, "%4d MB | ", dinfo->megabytes);
p += n;
space -= n;
......@@ -1005,7 +1011,7 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
/* Output the last bottom 'boundary' marker */
n = snprintf(p, space, "---------------------------"
"--------------------------------");
"-------------------------------");
p += n;
space -= n;
debugf2("%s\n", mem_buffer);
......@@ -1013,7 +1019,7 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
space = PAGE_SIZE;
/* now output the 'channel' labels */
n = snprintf(p, space, " ");
n = snprintf(p, space, " ");
p += n;
space -= n;
for (channel = 0; channel < pvt->maxch; channel++) {
......@@ -1022,6 +1028,19 @@ static void calculate_dimm_size(struct i5400_pvt *pvt)
space -= n;
}
space -= n;
debugf2("%s\n", mem_buffer);
p = mem_buffer;
space = PAGE_SIZE;
n = snprintf(p, space, " ");
p += n;
for (branch = 0; branch < MAX_BRANCHES; branch++) {
n = snprintf(p, space, " branch %d | ", branch);
p += n;
space -= n;
}
/* output the last message and free buffer */
debugf2("%s\n", mem_buffer);
kfree(mem_buffer);
......@@ -1080,7 +1099,7 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
debugf2("MIR1: limit= 0x%x WAY1= %u WAY0= %x\n", limit, way1, way0);
/* Get the set of MTR[0-3] regs by each branch */
for (slot_row = 0; slot_row < NUM_MTRS_PER_BRANCH; slot_row++) {
for (slot_row = 0; slot_row < DIMMS_PER_CHANNEL; slot_row++) {
int where = MTR0 + (slot_row * sizeof(u16));
/* Branch 0 set of MTR registers */
......@@ -1105,7 +1124,7 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
/* Read and dump branch 0's MTRs */
debugf2("\nMemory Technology Registers:\n");
debugf2(" Branch 0:\n");
for (slot_row = 0; slot_row < NUM_MTRS_PER_BRANCH; slot_row++)
for (slot_row = 0; slot_row < DIMMS_PER_CHANNEL; slot_row++)
decode_mtr(slot_row, pvt->b0_mtr[slot_row]);
pci_read_config_word(pvt->branch_0, AMBPRESENT_0,
......@@ -1122,7 +1141,7 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
} else {
/* Read and dump branch 1's MTRs */
debugf2(" Branch 1:\n");
for (slot_row = 0; slot_row < NUM_MTRS_PER_BRANCH; slot_row++)
for (slot_row = 0; slot_row < DIMMS_PER_CHANNEL; slot_row++)
decode_mtr(slot_row, pvt->b1_mtr[slot_row]);
pci_read_config_word(pvt->branch_1, AMBPRESENT_0,
......@@ -1141,7 +1160,7 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
}
/*
* i5400_init_csrows Initialize the 'csrows' table within
* i5400_init_dimms Initialize the 'dimms' table within
* the mci control structure with the
* addressing of memory.
*
......@@ -1149,64 +1168,68 @@ static void i5400_get_mc_regs(struct mem_ctl_info *mci)
* 0 success
* 1 no actual memory found on this MC
*/
static int i5400_init_csrows(struct mem_ctl_info *mci)
static int i5400_init_dimms(struct mem_ctl_info *mci)
{
struct i5400_pvt *pvt;
struct csrow_info *p_csrow;
int empty, channel_count;
int max_csrows;
struct dimm_info *dimm;
int ndimms, channel_count;
int max_dimms;
int mtr;
int csrow_megs;
int channel;
int csrow;
int size_mb;
int channel, slot;
pvt = mci->pvt_info;
channel_count = pvt->maxch;
max_csrows = pvt->maxdimmperch;
max_dimms = pvt->maxdimmperch;
empty = 1; /* Assume NO memory */
ndimms = 0;
for (csrow = 0; csrow < max_csrows; csrow++) {
p_csrow = &mci->csrows[csrow];
p_csrow->csrow_idx = csrow;
/* use branch 0 for the basis */
mtr = determine_mtr(pvt, csrow, 0);
/* if no DIMMS on this row, continue */
if (!MTR_DIMMS_PRESENT(mtr))
continue;
/* FAKE OUT VALUES, FIXME */
p_csrow->first_page = 0 + csrow * 20;
p_csrow->last_page = 9 + csrow * 20;
p_csrow->page_mask = 0xFFF;
p_csrow->grain = 8;
csrow_megs = 0;
for (channel = 0; channel < pvt->maxch; channel++)
csrow_megs += pvt->dimm_info[csrow][channel].megabytes;
p_csrow->nr_pages = csrow_megs << 8;
/* Assume DDR2 for now */
p_csrow->mtype = MEM_FB_DDR2;
/* ask what device type on this row */
if (MTR_DRAM_WIDTH(mtr))
p_csrow->dtype = DEV_X8;
else
p_csrow->dtype = DEV_X4;
p_csrow->edac_mode = EDAC_S8ECD8ED;
empty = 0;
/*
* FIXME: remove pvt->dimm_info[slot][channel] and use the 3
* layers here.
*/
for (channel = 0; channel < mci->layers[0].size * mci->layers[1].size;
channel++) {
for (slot = 0; slot < mci->layers[2].size; slot++) {
mtr = determine_mtr(pvt, slot, channel);
/* if no DIMMS on this slot, continue */
if (!MTR_DIMMS_PRESENT(mtr))
continue;
dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers,
channel / 2, channel % 2, slot);
size_mb = pvt->dimm_info[slot][channel].megabytes;
debugf2("%s: dimm%zd (branch %d channel %d slot %d): %d.%03d GB\n",
__func__, dimm - mci->dimms,
channel / 2, channel % 2, slot,
size_mb / 1000, size_mb % 1000);
dimm->nr_pages = size_mb << 8;
dimm->grain = 8;
dimm->dtype = MTR_DRAM_WIDTH(mtr) ? DEV_X8 : DEV_X4;
dimm->mtype = MEM_FB_DDR2;
/*
* The eccc mechanism is SDDC (aka SECC), with
* is similar to Chipkill.
*/
dimm->edac_mode = MTR_DRAM_WIDTH(mtr) ?
EDAC_S8ECD8ED : EDAC_S4ECD4ED;
ndimms++;
}
}
return empty;
/*
* When just one memory is provided, it should be at location (0,0,0).
* With such single-DIMM mode, the SDCC algorithm degrades to SECDEC+.
*/
if (ndimms == 1)
mci->dimms[0].edac_mode = EDAC_SECDED;
return (ndimms == 0);
}
/*
......@@ -1242,9 +1265,7 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
{
struct mem_ctl_info *mci;
struct i5400_pvt *pvt;
int num_channels;
int num_dimms_per_channel;
int num_csrows;
struct edac_mc_layer layers[3];
if (dev_idx >= ARRAY_SIZE(i5400_devs))
return -EINVAL;
......@@ -1258,23 +1279,21 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
if (PCI_FUNC(pdev->devfn) != 0)
return -ENODEV;
/* As we don't have a motherboard identification routine to determine
* actual number of slots/dimms per channel, we thus utilize the
* resource as specified by the chipset. Thus, we might have
* have more DIMMs per channel than actually on the mobo, but this
* allows the driver to support up to the chipset max, without
* some fancy mobo determination.
/*
* allocate a new MC control structure
*
* This drivers uses the DIMM slot as "csrow" and the rest as "channel".
*/
num_dimms_per_channel = MAX_DIMMS_PER_CHANNEL;
num_channels = MAX_CHANNELS;
num_csrows = num_dimms_per_channel;
debugf0("MC: %s(): Number of - Channels= %d DIMMS= %d CSROWS= %d\n",
__func__, num_channels, num_dimms_per_channel, num_csrows);
/* allocate a new MC control structure */
mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0);
layers[0].type = EDAC_MC_LAYER_BRANCH;
layers[0].size = MAX_BRANCHES;
layers[0].is_virt_csrow = false;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = CHANNELS_PER_BRANCH;
layers[1].is_virt_csrow = false;
layers[2].type = EDAC_MC_LAYER_SLOT;
layers[2].size = DIMMS_PER_CHANNEL;
layers[2].is_virt_csrow = true;
mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt));
if (mci == NULL)
return -ENOMEM;
......@@ -1284,8 +1303,8 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
pvt = mci->pvt_info;
pvt->system_address = pdev; /* Record this device in our private */
pvt->maxch = num_channels;
pvt->maxdimmperch = num_dimms_per_channel;
pvt->maxch = MAX_CHANNELS;
pvt->maxdimmperch = DIMMS_PER_CHANNEL;
/* 'get' the pci devices we want to reserve for our use */
if (i5400_get_devices(mci, dev_idx))
......@@ -1307,13 +1326,13 @@ static int i5400_probe1(struct pci_dev *pdev, int dev_idx)
/* Set the function pointer to an actual operation function */
mci->edac_check = i5400_check_error;
/* initialize the MC control structure 'csrows' table
/* initialize the MC control structure 'dimms' table
* with the mapping and control information */
if (i5400_init_csrows(mci)) {
if (i5400_init_dimms(mci)) {
debugf0("MC: Setting mci->edac_cap to EDAC_FLAG_NONE\n"
" because i5400_init_csrows() returned nonzero "
" because i5400_init_dimms() returned nonzero "
"value\n");
mci->edac_cap = EDAC_FLAG_NONE; /* no csrows found */
mci->edac_cap = EDAC_FLAG_NONE; /* no dimms found */
} else {
debugf1("MC: Enable error reporting now\n");
i5400_enable_error_reporting(mci);
......
......@@ -464,17 +464,14 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
FERR_FAT_FBD, error_reg);
snprintf(pvt->tmp_prt_buffer, PAGE_SIZE,
"FATAL (Branch=%d DRAM-Bank=%d %s "
"RAS=%d CAS=%d Err=0x%lx (%s))",
branch, bank,
is_wr ? "RDWR" : "RD",
ras, cas,
errors, specific);
/* Call the helper to output message */
edac_mc_handle_fbd_ue(mci, rank, branch << 1,
(branch << 1) + 1,
pvt->tmp_prt_buffer);
"Bank=%d RAS=%d CAS=%d Err=0x%lx (%s))",
bank, ras, cas, errors, specific);
edac_mc_handle_error(HW_EVENT_ERR_FATAL, mci, 0, 0, 0,
branch, -1, rank,
is_wr ? "Write error" : "Read error",
pvt->tmp_prt_buffer, NULL);
}
/* read in the 1st NON-FATAL error register */
......@@ -513,23 +510,14 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
/* Form out message */
snprintf(pvt->tmp_prt_buffer, PAGE_SIZE,
"Corrected error (Branch=%d, Channel %d), "
" DRAM-Bank=%d %s "
"RAS=%d CAS=%d, CE Err=0x%lx, Syndrome=0x%08x(%s))",
branch, channel,
bank,
is_wr ? "RDWR" : "RD",
ras, cas,
errors, syndrome, specific);
/*
* Call the helper to output message
* NOTE: Errors are reported per-branch, and not per-channel
* Currently, we don't know how to identify the right
* channel.
*/
edac_mc_handle_fbd_ce(mci, rank, channel,
pvt->tmp_prt_buffer);
"DRAM-Bank=%d RAS=%d CAS=%d, Err=0x%lx (%s))",
bank, ras, cas, errors, specific);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0,
syndrome,
branch >> 1, channel % 2, rank,
is_wr ? "Write error" : "Read error",
pvt->tmp_prt_buffer, NULL);
}
return;
}
......@@ -617,8 +605,7 @@ static void i7300_enable_error_reporting(struct mem_ctl_info *mci)
static int decode_mtr(struct i7300_pvt *pvt,
int slot, int ch, int branch,
struct i7300_dimm_info *dinfo,
struct csrow_info *p_csrow,
u32 *nr_pages)
struct dimm_info *dimm)
{
int mtr, ans, addrBits, channel;
......@@ -650,7 +637,6 @@ static int decode_mtr(struct i7300_pvt *pvt,
addrBits -= 3; /* 8 bits per bytes */
dinfo->megabytes = 1 << addrBits;
*nr_pages = dinfo->megabytes << 8;
debugf2("\t\tWIDTH: x%d\n", MTR_DRAM_WIDTH(mtr));
......@@ -663,11 +649,6 @@ static int decode_mtr(struct i7300_pvt *pvt,
debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
debugf2("\t\tSIZE: %d MB\n", dinfo->megabytes);
p_csrow->grain = 8;
p_csrow->mtype = MEM_FB_DDR2;
p_csrow->csrow_idx = slot;
p_csrow->page_mask = 0;
/*
* The type of error detection actually depends of the
* mode of operation. When it is just one single memory chip, at
......@@ -677,15 +658,18 @@ static int decode_mtr(struct i7300_pvt *pvt,
* See datasheet Sections 7.3.6 to 7.3.8
*/
dimm->nr_pages = MiB_TO_PAGES(dinfo->megabytes);
dimm->grain = 8;
dimm->mtype = MEM_FB_DDR2;
if (IS_SINGLE_MODE(pvt->mc_settings_a)) {
p_csrow->edac_mode = EDAC_SECDED;
dimm->edac_mode = EDAC_SECDED;
debugf2("\t\tECC code is 8-byte-over-32-byte SECDED+ code\n");
} else {
debugf2("\t\tECC code is on Lockstep mode\n");
if (MTR_DRAM_WIDTH(mtr) == 8)
p_csrow->edac_mode = EDAC_S8ECD8ED;
dimm->edac_mode = EDAC_S8ECD8ED;
else
p_csrow->edac_mode = EDAC_S4ECD4ED;
dimm->edac_mode = EDAC_S4ECD4ED;
}
/* ask what device type on this row */
......@@ -694,9 +678,9 @@ static int decode_mtr(struct i7300_pvt *pvt,
IS_SCRBALGO_ENHANCED(pvt->mc_settings) ?
"enhanced" : "normal");
p_csrow->dtype = DEV_X8;
dimm->dtype = DEV_X8;
} else
p_csrow->dtype = DEV_X4;
dimm->dtype = DEV_X4;
return mtr;
}
......@@ -774,11 +758,10 @@ static int i7300_init_csrows(struct mem_ctl_info *mci)
{
struct i7300_pvt *pvt;
struct i7300_dimm_info *dinfo;
struct csrow_info *p_csrow;
int rc = -ENODEV;
int mtr;
int ch, branch, slot, channel;
u32 last_page = 0, nr_pages;
struct dimm_info *dimm;
pvt = mci->pvt_info;
......@@ -809,25 +792,23 @@ static int i7300_init_csrows(struct mem_ctl_info *mci)
pci_read_config_word(pvt->pci_dev_2x_0_fbd_branch[branch],
where,
&pvt->mtr[slot][branch]);
for (ch = 0; ch < MAX_BRANCHES; ch++) {
for (ch = 0; ch < MAX_CH_PER_BRANCH; ch++) {
int channel = to_channel(ch, branch);
dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms,
mci->n_layers, branch, ch, slot);
dinfo = &pvt->dimm_info[slot][channel];
p_csrow = &mci->csrows[slot];
mtr = decode_mtr(pvt, slot, ch, branch,
dinfo, p_csrow, &nr_pages);
dinfo, dimm);
/* if no DIMMS on this row, continue */
if (!MTR_DIMMS_PRESENT(mtr))
continue;
/* Update per_csrow memory count */
p_csrow->nr_pages += nr_pages;
p_csrow->first_page = last_page;
last_page += nr_pages;
p_csrow->last_page = last_page;
rc = 0;
}
}
}
......@@ -1042,10 +1023,8 @@ static int __devinit i7300_init_one(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct mem_ctl_info *mci;
struct edac_mc_layer layers[3];
struct i7300_pvt *pvt;
int num_channels;
int num_dimms_per_channel;
int num_csrows;
int rc;
/* wake up device */
......@@ -1062,23 +1041,17 @@ static int __devinit i7300_init_one(struct pci_dev *pdev,
if (PCI_FUNC(pdev->devfn) != 0)
return -ENODEV;
/* As we don't have a motherboard identification routine to determine
* actual number of slots/dimms per channel, we thus utilize the
* resource as specified by the chipset. Thus, we might have
* have more DIMMs per channel than actually on the mobo, but this
* allows the driver to support up to the chipset max, without
* some fancy mobo determination.
*/
num_dimms_per_channel = MAX_SLOTS;
num_channels = MAX_CHANNELS;
num_csrows = MAX_SLOTS * MAX_CHANNELS;
debugf0("MC: %s(): Number of - Channels= %d DIMMS= %d CSROWS= %d\n",
__func__, num_channels, num_dimms_per_channel, num_csrows);
/* allocate a new MC control structure */
mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0);
layers[0].type = EDAC_MC_LAYER_BRANCH;
layers[0].size = MAX_BRANCHES;
layers[0].is_virt_csrow = false;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = MAX_CH_PER_BRANCH;
layers[1].is_virt_csrow = true;
layers[2].type = EDAC_MC_LAYER_SLOT;
layers[2].size = MAX_SLOTS;
layers[2].is_virt_csrow = true;
mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt));
if (mci == NULL)
return -ENOMEM;
......
......@@ -221,7 +221,9 @@ struct i7core_inject {
};
struct i7core_channel {
u32 ranks;
bool is_3dimms_present;
bool is_single_4rank;
bool has_4rank;
u32 dimms;
};
......@@ -257,7 +259,6 @@ struct i7core_pvt {
struct i7core_channel channel[NUM_CHANS];
int ce_count_available;
int csrow_map[NUM_CHANS][MAX_DIMMS];
/* ECC corrected errors counts per udimm */
unsigned long udimm_ce_count[MAX_DIMMS];
......@@ -492,116 +493,15 @@ static void free_i7core_dev(struct i7core_dev *i7core_dev)
/****************************************************************************
Memory check routines
****************************************************************************/
static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot,
unsigned func)
{
struct i7core_dev *i7core_dev = get_i7core_dev(socket);
int i;
if (!i7core_dev)
return NULL;
for (i = 0; i < i7core_dev->n_devs; i++) {
if (!i7core_dev->pdev[i])
continue;
if (PCI_SLOT(i7core_dev->pdev[i]->devfn) == slot &&
PCI_FUNC(i7core_dev->pdev[i]->devfn) == func) {
return i7core_dev->pdev[i];
}
}
return NULL;
}
/**
* i7core_get_active_channels() - gets the number of channels and csrows
* @socket: Quick Path Interconnect socket
* @channels: Number of channels that will be returned
* @csrows: Number of csrows found
*
* Since EDAC core needs to know in advance the number of available channels
* and csrows, in order to allocate memory for csrows/channels, it is needed
* to run two similar steps. At the first step, implemented on this function,
* it checks the number of csrows/channels present at one socket.
* this is used in order to properly allocate the size of mci components.
*
* It should be noticed that none of the current available datasheets explain
* or even mention how csrows are seen by the memory controller. So, we need
* to add a fake description for csrows.
* So, this driver is attributing one DIMM memory for one csrow.
*/
static int i7core_get_active_channels(const u8 socket, unsigned *channels,
unsigned *csrows)
{
struct pci_dev *pdev = NULL;
int i, j;
u32 status, control;
*channels = 0;
*csrows = 0;
pdev = get_pdev_slot_func(socket, 3, 0);
if (!pdev) {
i7core_printk(KERN_ERR, "Couldn't find socket %d fn 3.0!!!\n",
socket);
return -ENODEV;
}
/* Device 3 function 0 reads */
pci_read_config_dword(pdev, MC_STATUS, &status);
pci_read_config_dword(pdev, MC_CONTROL, &control);
for (i = 0; i < NUM_CHANS; i++) {
u32 dimm_dod[3];
/* Check if the channel is active */
if (!(control & (1 << (8 + i))))
continue;
/* Check if the channel is disabled */
if (status & (1 << i))
continue;
pdev = get_pdev_slot_func(socket, i + 4, 1);
if (!pdev) {
i7core_printk(KERN_ERR, "Couldn't find socket %d "
"fn %d.%d!!!\n",
socket, i + 4, 1);
return -ENODEV;
}
/* Devices 4-6 function 1 */
pci_read_config_dword(pdev,
MC_DOD_CH_DIMM0, &dimm_dod[0]);
pci_read_config_dword(pdev,
MC_DOD_CH_DIMM1, &dimm_dod[1]);
pci_read_config_dword(pdev,
MC_DOD_CH_DIMM2, &dimm_dod[2]);
(*channels)++;
for (j = 0; j < 3; j++) {
if (!DIMM_PRESENT(dimm_dod[j]))
continue;
(*csrows)++;
}
}
debugf0("Number of active channels on socket %d: %d\n",
socket, *channels);
return 0;
}
static int get_dimm_config(const struct mem_ctl_info *mci)
static int get_dimm_config(struct mem_ctl_info *mci)
{
struct i7core_pvt *pvt = mci->pvt_info;
struct csrow_info *csr;
struct pci_dev *pdev;
int i, j;
int csrow = 0;
unsigned long last_page = 0;
enum edac_type mode;
enum mem_type mtype;
struct dimm_info *dimm;
/* Get data from the MC register, function 0 */
pdev = pvt->pci_mcr[0];
......@@ -657,21 +557,20 @@ static int get_dimm_config(const struct mem_ctl_info *mci)
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].is_3dimms_present = true;
if (data & SINGLE_QUAD_RANK_PRESENT)
pvt->channel[i].is_single_4rank = true;
if (data & QUAD_RANK_PRESENT)
pvt->channel[i].has_4rank = true;
if (data & REGISTERED_DIMM)
mtype = MEM_RDDR3;
else
mtype = MEM_DDR3;
#if 0
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;
#endif
/* Devices 4-6 function 1 */
pci_read_config_dword(pvt->pci_ch[i][1],
......@@ -682,11 +581,13 @@ static int get_dimm_config(const struct mem_ctl_info *mci)
MC_DOD_CH_DIMM2, &dimm_dod[2]);
debugf0("Ch%d phy rd%d, wr%d (0x%08x): "
"%d ranks, %cDIMMs\n",
"%s%s%s%cDIMMs\n",
i,
RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i),
data,
pvt->channel[i].ranks,
pvt->channel[i].is_3dimms_present ? "3DIMMS " : "",
pvt->channel[i].is_3dimms_present ? "SINGLE_4R " : "",
pvt->channel[i].has_4rank ? "HAS_4R " : "",
(data & REGISTERED_DIMM) ? 'R' : 'U');
for (j = 0; j < 3; j++) {
......@@ -696,6 +597,8 @@ static int get_dimm_config(const struct mem_ctl_info *mci)
if (!DIMM_PRESENT(dimm_dod[j]))
continue;
dimm = EDAC_DIMM_PTR(mci->layers, mci->dimms, mci->n_layers,
i, j, 0);
banks = numbank(MC_DOD_NUMBANK(dimm_dod[j]));
ranks = numrank(MC_DOD_NUMRANK(dimm_dod[j]));
rows = numrow(MC_DOD_NUMROW(dimm_dod[j]));
......@@ -704,8 +607,6 @@ static int get_dimm_config(const struct mem_ctl_info *mci)
/* DDR3 has 8 I/O banks */
size = (rows * cols * banks * ranks) >> (20 - 3);
pvt->channel[i].dimms++;
debugf0("\tdimm %d %d Mb offset: %x, "
"bank: %d, rank: %d, row: %#x, col: %#x\n",
j, size,
......@@ -714,44 +615,28 @@ static int get_dimm_config(const struct mem_ctl_info *mci)
npages = MiB_TO_PAGES(size);
csr = &mci->csrows[csrow];
csr->first_page = last_page + 1;
last_page += npages;
csr->last_page = last_page;
csr->nr_pages = npages;
csr->page_mask = 0;
csr->grain = 8;
csr->csrow_idx = csrow;
csr->nr_channels = 1;
csr->channels[0].chan_idx = i;
csr->channels[0].ce_count = 0;
pvt->csrow_map[i][j] = csrow;
dimm->nr_pages = npages;
switch (banks) {
case 4:
csr->dtype = DEV_X4;
dimm->dtype = DEV_X4;
break;
case 8:
csr->dtype = DEV_X8;
dimm->dtype = DEV_X8;
break;
case 16:
csr->dtype = DEV_X16;
dimm->dtype = DEV_X16;
break;
default:
csr->dtype = DEV_UNKNOWN;
dimm->dtype = DEV_UNKNOWN;
}
csr->edac_mode = mode;
csr->mtype = mtype;
snprintf(csr->channels[0].label,
sizeof(csr->channels[0].label),
"CPU#%uChannel#%u_DIMM#%u",
pvt->i7core_dev->socket, i, j);
csrow++;
snprintf(dimm->label, sizeof(dimm->label),
"CPU#%uChannel#%u_DIMM#%u",
pvt->i7core_dev->socket, i, j);
dimm->grain = 8;
dimm->edac_mode = mode;
dimm->mtype = mtype;
}
pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]);
......@@ -1567,22 +1452,16 @@ static int mci_bind_devs(struct mem_ctl_info *mci,
/****************************************************************************
Error check routines
****************************************************************************/
static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci,
static void i7core_rdimm_update_errcount(struct mem_ctl_info *mci,
const int chan,
const int dimm,
const int add)
{
char *msg;
struct i7core_pvt *pvt = mci->pvt_info;
int row = pvt->csrow_map[chan][dimm], i;
int i;
for (i = 0; i < add; i++) {
msg = kasprintf(GFP_KERNEL, "Corrected error "
"(Socket=%d channel=%d dimm=%d)",
pvt->i7core_dev->socket, chan, dimm);
edac_mc_handle_fbd_ce(mci, row, 0, msg);
kfree (msg);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0,
chan, dimm, -1, "error", "", NULL);
}
}
......@@ -1623,11 +1502,11 @@ static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci,
/*updated the edac core */
if (add0 != 0)
i7core_rdimm_update_csrow(mci, chan, 0, add0);
i7core_rdimm_update_errcount(mci, chan, 0, add0);
if (add1 != 0)
i7core_rdimm_update_csrow(mci, chan, 1, add1);
i7core_rdimm_update_errcount(mci, chan, 1, add1);
if (add2 != 0)
i7core_rdimm_update_csrow(mci, chan, 2, add2);
i7core_rdimm_update_errcount(mci, chan, 2, add2);
}
......@@ -1747,20 +1626,30 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
const struct mce *m)
{
struct i7core_pvt *pvt = mci->pvt_info;
char *type, *optype, *err, *msg;
char *type, *optype, *err, msg[80];
enum hw_event_mc_err_type tp_event;
unsigned long error = m->status & 0x1ff0000l;
bool uncorrected_error = m->mcgstatus & 1ll << 61;
bool ripv = m->mcgstatus & 1;
u32 optypenum = (m->status >> 4) & 0x07;
u32 core_err_cnt = (m->status >> 38) & 0x7fff;
u32 dimm = (m->misc >> 16) & 0x3;
u32 channel = (m->misc >> 18) & 0x3;
u32 syndrome = m->misc >> 32;
u32 errnum = find_first_bit(&error, 32);
int csrow;
if (m->mcgstatus & 1)
type = "FATAL";
else
type = "NON_FATAL";
if (uncorrected_error) {
if (ripv) {
type = "FATAL";
tp_event = HW_EVENT_ERR_FATAL;
} else {
type = "NON_FATAL";
tp_event = HW_EVENT_ERR_UNCORRECTED;
}
} else {
type = "CORRECTED";
tp_event = HW_EVENT_ERR_CORRECTED;
}
switch (optypenum) {
case 0:
......@@ -1815,27 +1704,20 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
err = "unknown";
}
/* FIXME: should convert addr into bank and rank information */
msg = kasprintf(GFP_ATOMIC,
"%s (addr = 0x%08llx, cpu=%d, Dimm=%d, Channel=%d, "
"syndrome=0x%08x, count=%d, Err=%08llx:%08llx (%s: %s))\n",
type, (long long) m->addr, m->cpu, dimm, channel,
syndrome, core_err_cnt, (long long)m->status,
(long long)m->misc, optype, err);
debugf0("%s", msg);
csrow = pvt->csrow_map[channel][dimm];
snprintf(msg, sizeof(msg), "count=%d %s", core_err_cnt, optype);
/* Call the helper to output message */
if (m->mcgstatus & 1)
edac_mc_handle_fbd_ue(mci, csrow, 0,
0 /* FIXME: should be channel here */, msg);
else if (!pvt->is_registered)
edac_mc_handle_fbd_ce(mci, csrow,
0 /* FIXME: should be channel here */, msg);
kfree(msg);
/*
* Call the helper to output message
* FIXME: what to do if core_err_cnt > 1? Currently, it generates
* only one event
*/
if (uncorrected_error || !pvt->is_registered)
edac_mc_handle_error(tp_event, mci,
m->addr >> PAGE_SHIFT,
m->addr & ~PAGE_MASK,
syndrome,
channel, dimm, -1,
err, msg, m);
}
/*
......@@ -2252,15 +2134,19 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev)
{
struct mem_ctl_info *mci;
struct i7core_pvt *pvt;
int rc, channels, csrows;
/* Check the number of active and not disabled channels */
rc = i7core_get_active_channels(i7core_dev->socket, &channels, &csrows);
if (unlikely(rc < 0))
return rc;
int rc;
struct edac_mc_layer layers[2];
/* allocate a new MC control structure */
mci = edac_mc_alloc(sizeof(*pvt), csrows, channels, i7core_dev->socket);
layers[0].type = EDAC_MC_LAYER_CHANNEL;
layers[0].size = NUM_CHANS;
layers[0].is_virt_csrow = false;
layers[1].type = EDAC_MC_LAYER_SLOT;
layers[1].size = MAX_DIMMS;
layers[1].is_virt_csrow = true;
mci = edac_mc_alloc(i7core_dev->socket, ARRAY_SIZE(layers), layers,
sizeof(*pvt));
if (unlikely(!mci))
return -ENOMEM;
......
......@@ -12,7 +12,7 @@
* 440GX fix by Jason Uhlenkott <juhlenko@akamai.com>.
*
* Written with reference to 82443BX Host Bridge Datasheet:
* http://download.intel.com/design/chipsets/datashts/29063301.pdf
* http://download.intel.com/design/chipsets/datashts/29063301.pdf
* references to this document given in [].
*
* This module doesn't support the 440LX, but it may be possible to
......@@ -156,19 +156,19 @@ static int i82443bxgx_edacmc_process_error_info(struct mem_ctl_info *mci,
if (info->eap & I82443BXGX_EAP_OFFSET_SBE) {
error_found = 1;
if (handle_errors)
edac_mc_handle_ce(mci, page, pageoffset,
/* 440BX/GX don't make syndrome information
* available */
0, edac_mc_find_csrow_by_page(mci, page), 0,
mci->ctl_name);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
page, pageoffset, 0,
edac_mc_find_csrow_by_page(mci, page),
0, -1, mci->ctl_name, "", NULL);
}
if (info->eap & I82443BXGX_EAP_OFFSET_MBE) {
error_found = 1;
if (handle_errors)
edac_mc_handle_ue(mci, page, pageoffset,
edac_mc_find_csrow_by_page(mci, page),
mci->ctl_name);
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
page, pageoffset, 0,
edac_mc_find_csrow_by_page(mci, page),
0, -1, mci->ctl_name, "", NULL);
}
return error_found;
......@@ -189,6 +189,7 @@ static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
enum mem_type mtype)
{
struct csrow_info *csrow;
struct dimm_info *dimm;
int index;
u8 drbar, dramc;
u32 row_base, row_high_limit, row_high_limit_last;
......@@ -197,6 +198,8 @@ static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
row_high_limit_last = 0;
for (index = 0; index < mci->nr_csrows; index++) {
csrow = &mci->csrows[index];
dimm = csrow->channels[0].dimm;
pci_read_config_byte(pdev, I82443BXGX_DRB + index, &drbar);
debugf1("MC%d: %s: %s() Row=%d DRB = %#0x\n",
mci->mc_idx, __FILE__, __func__, index, drbar);
......@@ -217,14 +220,14 @@ static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
row_base = row_high_limit_last;
csrow->first_page = row_base >> PAGE_SHIFT;
csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1;
csrow->nr_pages = csrow->last_page - csrow->first_page + 1;
dimm->nr_pages = csrow->last_page - csrow->first_page + 1;
/* EAP reports in 4kilobyte granularity [61] */
csrow->grain = 1 << 12;
csrow->mtype = mtype;
dimm->grain = 1 << 12;
dimm->mtype = mtype;
/* I don't think 440BX can tell you device type? FIXME? */
csrow->dtype = DEV_UNKNOWN;
dimm->dtype = DEV_UNKNOWN;
/* Mode is global to all rows on 440BX */
csrow->edac_mode = edac_mode;
dimm->edac_mode = edac_mode;
row_high_limit_last = row_high_limit;
}
}
......@@ -232,6 +235,7 @@ static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
{
struct mem_ctl_info *mci;
struct edac_mc_layer layers[2];
u8 dramc;
u32 nbxcfg, ecc_mode;
enum mem_type mtype;
......@@ -245,8 +249,13 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
if (pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg))
return -EIO;
mci = edac_mc_alloc(0, I82443BXGX_NR_CSROWS, I82443BXGX_NR_CHANS, 0);
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = I82443BXGX_NR_CSROWS;
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = I82443BXGX_NR_CHANS;
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0);
if (mci == NULL)
return -ENOMEM;
......
......@@ -99,6 +99,7 @@ static int i82860_process_error_info(struct mem_ctl_info *mci,
struct i82860_error_info *info,
int handle_errors)
{
struct dimm_info *dimm;
int row;
if (!(info->errsts2 & 0x0003))
......@@ -108,18 +109,25 @@ static int i82860_process_error_info(struct mem_ctl_info *mci,
return 1;
if ((info->errsts ^ info->errsts2) & 0x0003) {
edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
-1, -1, -1, "UE overwrote CE", "", NULL);
info->errsts = info->errsts2;
}
info->eap >>= PAGE_SHIFT;
row = edac_mc_find_csrow_by_page(mci, info->eap);
dimm = mci->csrows[row].channels[0].dimm;
if (info->errsts & 0x0002)
edac_mc_handle_ue(mci, info->eap, 0, row, "i82860 UE");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
info->eap, 0, 0,
dimm->location[0], dimm->location[1], -1,
"i82860 UE", "", NULL);
else
edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row, 0,
"i82860 UE");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
info->eap, 0, info->derrsyn,
dimm->location[0], dimm->location[1], -1,
"i82860 CE", "", NULL);
return 1;
}
......@@ -140,6 +148,7 @@ static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
u16 value;
u32 cumul_size;
struct csrow_info *csrow;
struct dimm_info *dimm;
int index;
pci_read_config_word(pdev, I82860_MCHCFG, &mchcfg_ddim);
......@@ -153,6 +162,8 @@ static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
*/
for (index = 0; index < mci->nr_csrows; index++) {
csrow = &mci->csrows[index];
dimm = csrow->channels[0].dimm;
pci_read_config_word(pdev, I82860_GBA + index * 2, &value);
cumul_size = (value & I82860_GBA_MASK) <<
(I82860_GBA_SHIFT - PAGE_SHIFT);
......@@ -164,30 +175,38 @@ static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
csrow->first_page = last_cumul_size;
csrow->last_page = cumul_size - 1;
csrow->nr_pages = cumul_size - last_cumul_size;
dimm->nr_pages = cumul_size - last_cumul_size;
last_cumul_size = cumul_size;
csrow->grain = 1 << 12; /* I82860_EAP has 4KiB reolution */
csrow->mtype = MEM_RMBS;
csrow->dtype = DEV_UNKNOWN;
csrow->edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE;
dimm->grain = 1 << 12; /* I82860_EAP has 4KiB reolution */
dimm->mtype = MEM_RMBS;
dimm->dtype = DEV_UNKNOWN;
dimm->edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE;
}
}
static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
{
struct mem_ctl_info *mci;
struct edac_mc_layer layers[2];
struct i82860_error_info discard;
/* RDRAM has channels but these don't map onto the abstractions that
edac uses.
The device groups from the GRA registers seem to map reasonably
well onto the notion of a chip select row.
There are 16 GRA registers and since the name is associated with
the channel and the GRA registers map to physical devices so we are
going to make 1 channel for group.
/*
* RDRAM has channels but these don't map onto the csrow abstraction.
* According with the datasheet, there are 2 Rambus channels, supporting
* up to 16 direct RDRAM devices.
* The device groups from the GRA registers seem to map reasonably
* well onto the notion of a chip select row.
* There are 16 GRA registers and since the name is associated with
* the channel and the GRA registers map to physical devices so we are
* going to make 1 channel for group.
*/
mci = edac_mc_alloc(0, 16, 1, 0);
layers[0].type = EDAC_MC_LAYER_CHANNEL;
layers[0].size = 2;
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_SLOT;
layers[1].size = 8;
layers[1].is_virt_csrow = true;
mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0);
if (!mci)
return -ENOMEM;
......
......@@ -38,7 +38,8 @@
#endif /* PCI_DEVICE_ID_INTEL_82875_6 */
/* four csrows in dual channel, eight in single channel */
#define I82875P_NR_CSROWS(nr_chans) (8/(nr_chans))
#define I82875P_NR_DIMMS 8
#define I82875P_NR_CSROWS(nr_chans) (I82875P_NR_DIMMS / (nr_chans))
/* Intel 82875p register addresses - device 0 function 0 - DRAM Controller */
#define I82875P_EAP 0x58 /* Error Address Pointer (32b)
......@@ -235,7 +236,9 @@ static int i82875p_process_error_info(struct mem_ctl_info *mci,
return 1;
if ((info->errsts ^ info->errsts2) & 0x0081) {
edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
-1, -1, -1,
"UE overwrote CE", "", NULL);
info->errsts = info->errsts2;
}
......@@ -243,11 +246,15 @@ static int i82875p_process_error_info(struct mem_ctl_info *mci,
row = edac_mc_find_csrow_by_page(mci, info->eap);
if (info->errsts & 0x0080)
edac_mc_handle_ue(mci, info->eap, 0, row, "i82875p UE");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
info->eap, 0, 0,
row, -1, -1,
"i82875p UE", "", NULL);
else
edac_mc_handle_ce(mci, info->eap, 0, info->derrsyn, row,
multi_chan ? (info->des & 0x1) : 0,
"i82875p CE");
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
info->eap, 0, info->derrsyn,
row, multi_chan ? (info->des & 0x1) : 0,
-1, "i82875p CE", "", NULL);
return 1;
}
......@@ -342,11 +349,13 @@ static void i82875p_init_csrows(struct mem_ctl_info *mci,
void __iomem * ovrfl_window, u32 drc)
{
struct csrow_info *csrow;
struct dimm_info *dimm;
unsigned nr_chans = dual_channel_active(drc) + 1;
unsigned long last_cumul_size;
u8 value;
u32 drc_ddim; /* DRAM Data Integrity Mode 0=none,2=edac */
u32 cumul_size;
int index;
u32 cumul_size, nr_pages;
int index, j;
drc_ddim = (drc >> 18) & 0x1;
last_cumul_size = 0;
......@@ -369,12 +378,18 @@ static void i82875p_init_csrows(struct mem_ctl_info *mci,
csrow->first_page = last_cumul_size;
csrow->last_page = cumul_size - 1;
csrow->nr_pages = cumul_size - last_cumul_size;
nr_pages = cumul_size - last_cumul_size;
last_cumul_size = cumul_size;
csrow->grain = 1 << 12; /* I82875P_EAP has 4KiB reolution */
csrow->mtype = MEM_DDR;
csrow->dtype = DEV_UNKNOWN;
csrow->edac_mode = drc_ddim ? EDAC_SECDED : EDAC_NONE;
for (j = 0; j < nr_chans; j++) {
dimm = csrow->channels[j].dimm;
dimm->nr_pages = nr_pages / nr_chans;
dimm->grain = 1 << 12; /* I82875P_EAP has 4KiB reolution */
dimm->mtype = MEM_DDR;
dimm->dtype = DEV_UNKNOWN;
dimm->edac_mode = drc_ddim ? EDAC_SECDED : EDAC_NONE;
}
}
}
......@@ -382,6 +397,7 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
{
int rc = -ENODEV;
struct mem_ctl_info *mci;
struct edac_mc_layer layers[2];
struct i82875p_pvt *pvt;
struct pci_dev *ovrfl_pdev;
void __iomem *ovrfl_window;
......@@ -397,9 +413,14 @@ static int i82875p_probe1(struct pci_dev *pdev, int dev_idx)
return -ENODEV;
drc = readl(ovrfl_window + I82875P_DRC);
nr_chans = dual_channel_active(drc) + 1;
mci = edac_mc_alloc(sizeof(*pvt), I82875P_NR_CSROWS(nr_chans),
nr_chans, 0);
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = I82875P_NR_CSROWS(nr_chans);
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = nr_chans;
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt));
if (!mci) {
rc = -ENOMEM;
goto fail0;
......
......@@ -29,7 +29,8 @@
#define PCI_DEVICE_ID_INTEL_82975_0 0x277c
#endif /* PCI_DEVICE_ID_INTEL_82975_0 */
#define I82975X_NR_CSROWS(nr_chans) (8/(nr_chans))
#define I82975X_NR_DIMMS 8
#define I82975X_NR_CSROWS(nr_chans) (I82975X_NR_DIMMS / (nr_chans))
/* Intel 82975X register addresses - device 0 function 0 - DRAM Controller */
#define I82975X_EAP 0x58 /* Dram Error Address Pointer (32b)
......@@ -287,7 +288,8 @@ static int i82975x_process_error_info(struct mem_ctl_info *mci,
return 1;
if ((info->errsts ^ info->errsts2) & 0x0003) {
edac_mc_handle_ce_no_info(mci, "UE overwrote CE");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
-1, -1, -1, "UE overwrote CE", "", NULL);
info->errsts = info->errsts2;
}
......@@ -309,13 +311,18 @@ static int i82975x_process_error_info(struct mem_ctl_info *mci,
chan = (mci->csrows[row].nr_channels == 1) ? 0 : info->eap & 1;
offst = info->eap
& ((1 << PAGE_SHIFT) -
(1 << mci->csrows[row].grain));
(1 << mci->csrows[row].channels[chan].dimm->grain));
if (info->errsts & 0x0002)
edac_mc_handle_ue(mci, page, offst , row, "i82975x UE");
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
page, offst, 0,
row, -1, -1,
"i82975x UE", "", NULL);
else
edac_mc_handle_ce(mci, page, offst, info->derrsyn, row,
chan, "i82975x CE");
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
page, offst, info->derrsyn,
row, chan ? chan : 0, -1,
"i82975x CE", "", NULL);
return 1;
}
......@@ -370,8 +377,10 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
struct csrow_info *csrow;
unsigned long last_cumul_size;
u8 value;
u32 cumul_size;
u32 cumul_size, nr_pages;
int index, chan;
struct dimm_info *dimm;
enum dev_type dtype;
last_cumul_size = 0;
......@@ -400,28 +409,33 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
debugf3("%s(): (%d) cumul_size 0x%x\n", __func__, index,
cumul_size);
nr_pages = cumul_size - last_cumul_size;
if (!nr_pages)
continue;
/*
* Initialise dram labels
* index values:
* [0-7] for single-channel; i.e. csrow->nr_channels = 1
* [0-3] for dual-channel; i.e. csrow->nr_channels = 2
*/
for (chan = 0; chan < csrow->nr_channels; chan++)
strncpy(csrow->channels[chan].label,
dtype = i82975x_dram_type(mch_window, index);
for (chan = 0; chan < csrow->nr_channels; chan++) {
dimm = mci->csrows[index].channels[chan].dimm;
dimm->nr_pages = nr_pages / csrow->nr_channels;
strncpy(csrow->channels[chan].dimm->label,
labels[(index >> 1) + (chan * 2)],
EDAC_MC_LABEL_LEN);
if (cumul_size == last_cumul_size)
continue; /* not populated */
dimm->grain = 1 << 7; /* 128Byte cache-line resolution */
dimm->dtype = i82975x_dram_type(mch_window, index);
dimm->mtype = MEM_DDR2; /* I82975x supports only DDR2 */
dimm->edac_mode = EDAC_SECDED; /* only supported */
}
csrow->first_page = last_cumul_size;
csrow->last_page = cumul_size - 1;
csrow->nr_pages = cumul_size - last_cumul_size;
last_cumul_size = cumul_size;
csrow->grain = 1 << 7; /* 128Byte cache-line resolution */
csrow->mtype = MEM_DDR2; /* I82975x supports only DDR2 */
csrow->dtype = i82975x_dram_type(mch_window, index);
csrow->edac_mode = EDAC_SECDED; /* only supported */
}
}
......@@ -463,6 +477,7 @@ static int i82975x_probe1(struct pci_dev *pdev, int dev_idx)
{
int rc = -ENODEV;
struct mem_ctl_info *mci;
struct edac_mc_layer layers[2];
struct i82975x_pvt *pvt;
void __iomem *mch_window;
u32 mchbar;
......@@ -531,8 +546,13 @@ static int i82975x_probe1(struct pci_dev *pdev, int dev_idx)
chans = dual_channel_active(mch_window) + 1;
/* assuming only one controller, index thus is 0 */
mci = edac_mc_alloc(sizeof(*pvt), I82975X_NR_CSROWS(chans),
chans, 0);
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = I82975X_NR_DIMMS;
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = I82975X_NR_CSROWS(chans);
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, sizeof(*pvt));
if (!mci) {
rc = -ENOMEM;
goto fail1;
......
......@@ -854,12 +854,16 @@ static void mpc85xx_mc_check(struct mem_ctl_info *mci)
mpc85xx_mc_printk(mci, KERN_ERR, "PFN out of range!\n");
if (err_detect & DDR_EDE_SBE)
edac_mc_handle_ce(mci, pfn, err_addr & ~PAGE_MASK,
syndrome, row_index, 0, mci->ctl_name);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
pfn, err_addr & ~PAGE_MASK, syndrome,
row_index, 0, -1,
mci->ctl_name, "", NULL);
if (err_detect & DDR_EDE_MBE)
edac_mc_handle_ue(mci, pfn, err_addr & ~PAGE_MASK,
row_index, mci->ctl_name);
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
pfn, err_addr & ~PAGE_MASK, syndrome,
row_index, 0, -1,
mci->ctl_name, "", NULL);
out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect);
}
......@@ -883,6 +887,7 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
{
struct mpc85xx_mc_pdata *pdata = mci->pvt_info;
struct csrow_info *csrow;
struct dimm_info *dimm;
u32 sdram_ctl;
u32 sdtype;
enum mem_type mtype;
......@@ -929,6 +934,8 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
u32 end;
csrow = &mci->csrows[index];
dimm = csrow->channels[0].dimm;
cs_bnds = in_be32(pdata->mc_vbase + MPC85XX_MC_CS_BNDS_0 +
(index * MPC85XX_MC_CS_BNDS_OFS));
......@@ -944,19 +951,21 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
csrow->first_page = start;
csrow->last_page = end;
csrow->nr_pages = end + 1 - start;
csrow->grain = 8;
csrow->mtype = mtype;
csrow->dtype = DEV_UNKNOWN;
dimm->nr_pages = end + 1 - start;
dimm->grain = 8;
dimm->mtype = mtype;
dimm->dtype = DEV_UNKNOWN;
if (sdram_ctl & DSC_X32_EN)
csrow->dtype = DEV_X32;
csrow->edac_mode = EDAC_SECDED;
dimm->dtype = DEV_X32;
dimm->edac_mode = EDAC_SECDED;
}
}
static int __devinit mpc85xx_mc_err_probe(struct platform_device *op)
{
struct mem_ctl_info *mci;
struct edac_mc_layer layers[2];
struct mpc85xx_mc_pdata *pdata;
struct resource r;
u32 sdram_ctl;
......@@ -965,7 +974,13 @@ static int __devinit mpc85xx_mc_err_probe(struct platform_device *op)
if (!devres_open_group(&op->dev, mpc85xx_mc_err_probe, GFP_KERNEL))
return -ENOMEM;
mci = edac_mc_alloc(sizeof(*pdata), 4, 1, edac_mc_idx);
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = 4;
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = 1;
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), sizeof(*pdata));
if (!mci) {
devres_release_group(&op->dev, mpc85xx_mc_err_probe);
return -ENOMEM;
......
......@@ -611,12 +611,17 @@ static void mv64x60_mc_check(struct mem_ctl_info *mci)
/* first bit clear in ECC Err Reg, 1 bit error, correctable by HW */
if (!(reg & 0x1))
edac_mc_handle_ce(mci, err_addr >> PAGE_SHIFT,
err_addr & PAGE_MASK, syndrome, 0, 0,
mci->ctl_name);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
err_addr >> PAGE_SHIFT,
err_addr & PAGE_MASK, syndrome,
0, 0, -1,
mci->ctl_name, "", NULL);
else /* 2 bit error, UE */
edac_mc_handle_ue(mci, err_addr >> PAGE_SHIFT,
err_addr & PAGE_MASK, 0, mci->ctl_name);
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
err_addr >> PAGE_SHIFT,
err_addr & PAGE_MASK, 0,
0, 0, -1,
mci->ctl_name, "", NULL);
/* clear the error */
out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR, 0);
......@@ -656,6 +661,8 @@ static void mv64x60_init_csrows(struct mem_ctl_info *mci,
struct mv64x60_mc_pdata *pdata)
{
struct csrow_info *csrow;
struct dimm_info *dimm;
u32 devtype;
u32 ctl;
......@@ -664,35 +671,36 @@ static void mv64x60_init_csrows(struct mem_ctl_info *mci,
ctl = in_le32(pdata->mc_vbase + MV64X60_SDRAM_CONFIG);
csrow = &mci->csrows[0];
csrow->first_page = 0;
csrow->nr_pages = pdata->total_mem >> PAGE_SHIFT;
csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
csrow->grain = 8;
dimm = csrow->channels[0].dimm;
dimm->nr_pages = pdata->total_mem >> PAGE_SHIFT;
dimm->grain = 8;
csrow->mtype = (ctl & MV64X60_SDRAM_REGISTERED) ? MEM_RDDR : MEM_DDR;
dimm->mtype = (ctl & MV64X60_SDRAM_REGISTERED) ? MEM_RDDR : MEM_DDR;
devtype = (ctl >> 20) & 0x3;
switch (devtype) {
case 0x0:
csrow->dtype = DEV_X32;
dimm->dtype = DEV_X32;
break;
case 0x2: /* could be X8 too, but no way to tell */
csrow->dtype = DEV_X16;
dimm->dtype = DEV_X16;
break;
case 0x3:
csrow->dtype = DEV_X4;
dimm->dtype = DEV_X4;
break;
default:
csrow->dtype = DEV_UNKNOWN;
dimm->dtype = DEV_UNKNOWN;
break;
}
csrow->edac_mode = EDAC_SECDED;
dimm->edac_mode = EDAC_SECDED;
}
static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev)
{
struct mem_ctl_info *mci;
struct edac_mc_layer layers[2];
struct mv64x60_mc_pdata *pdata;
struct resource *r;
u32 ctl;
......@@ -701,7 +709,14 @@ static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev)
if (!devres_open_group(&pdev->dev, mv64x60_mc_err_probe, GFP_KERNEL))
return -ENOMEM;
mci = edac_mc_alloc(sizeof(struct mv64x60_mc_pdata), 1, 1, edac_mc_idx);
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = 1;
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = 1;
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers,
sizeof(struct mv64x60_mc_pdata));
if (!mci) {
printk(KERN_ERR "%s: No memory for CPU err\n", __func__);
devres_release_group(&pdev->dev, mv64x60_mc_err_probe);
......
......@@ -110,15 +110,16 @@ static void pasemi_edac_process_error_info(struct mem_ctl_info *mci, u32 errsta)
/* uncorrectable/multi-bit errors */
if (errsta & (MCDEBUG_ERRSTA_MBE_STATUS |
MCDEBUG_ERRSTA_RFL_STATUS)) {
edac_mc_handle_ue(mci, mci->csrows[cs].first_page, 0,
cs, mci->ctl_name);
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
mci->csrows[cs].first_page, 0, 0,
cs, 0, -1, mci->ctl_name, "", NULL);
}
/* correctable/single-bit errors */
if (errsta & MCDEBUG_ERRSTA_SBE_STATUS) {
edac_mc_handle_ce(mci, mci->csrows[cs].first_page, 0,
0, cs, 0, mci->ctl_name);
}
if (errsta & MCDEBUG_ERRSTA_SBE_STATUS)
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
mci->csrows[cs].first_page, 0, 0,
cs, 0, -1, mci->ctl_name, "", NULL);
}
static void pasemi_edac_check(struct mem_ctl_info *mci)
......@@ -135,11 +136,13 @@ static int pasemi_edac_init_csrows(struct mem_ctl_info *mci,
enum edac_type edac_mode)
{
struct csrow_info *csrow;
struct dimm_info *dimm;
u32 rankcfg;
int index;
for (index = 0; index < mci->nr_csrows; index++) {
csrow = &mci->csrows[index];
dimm = csrow->channels[0].dimm;
pci_read_config_dword(pdev,
MCDRAM_RANKCFG + (index * 12),
......@@ -151,20 +154,20 @@ static int pasemi_edac_init_csrows(struct mem_ctl_info *mci,
switch ((rankcfg & MCDRAM_RANKCFG_TYPE_SIZE_M) >>
MCDRAM_RANKCFG_TYPE_SIZE_S) {
case 0:
csrow->nr_pages = 128 << (20 - PAGE_SHIFT);
dimm->nr_pages = 128 << (20 - PAGE_SHIFT);
break;
case 1:
csrow->nr_pages = 256 << (20 - PAGE_SHIFT);
dimm->nr_pages = 256 << (20 - PAGE_SHIFT);
break;
case 2:
case 3:
csrow->nr_pages = 512 << (20 - PAGE_SHIFT);
dimm->nr_pages = 512 << (20 - PAGE_SHIFT);
break;
case 4:
csrow->nr_pages = 1024 << (20 - PAGE_SHIFT);
dimm->nr_pages = 1024 << (20 - PAGE_SHIFT);
break;
case 5:
csrow->nr_pages = 2048 << (20 - PAGE_SHIFT);
dimm->nr_pages = 2048 << (20 - PAGE_SHIFT);
break;
default:
edac_mc_printk(mci, KERN_ERR,
......@@ -174,13 +177,13 @@ static int pasemi_edac_init_csrows(struct mem_ctl_info *mci,
}
csrow->first_page = last_page_in_mmc;
csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
last_page_in_mmc += csrow->nr_pages;
csrow->last_page = csrow->first_page + dimm->nr_pages - 1;
last_page_in_mmc += dimm->nr_pages;
csrow->page_mask = 0;
csrow->grain = PASEMI_EDAC_ERROR_GRAIN;
csrow->mtype = MEM_DDR;
csrow->dtype = DEV_UNKNOWN;
csrow->edac_mode = edac_mode;
dimm->grain = PASEMI_EDAC_ERROR_GRAIN;
dimm->mtype = MEM_DDR;
dimm->dtype = DEV_UNKNOWN;
dimm->edac_mode = edac_mode;
}
return 0;
}
......@@ -189,6 +192,7 @@ static int __devinit pasemi_edac_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct mem_ctl_info *mci = NULL;
struct edac_mc_layer layers[2];
u32 errctl1, errcor, scrub, mcen;
pci_read_config_dword(pdev, MCCFG_MCEN, &mcen);
......@@ -205,9 +209,14 @@ static int __devinit pasemi_edac_probe(struct pci_dev *pdev,
MCDEBUG_ERRCTL1_RFL_LOG_EN;
pci_write_config_dword(pdev, MCDEBUG_ERRCTL1, errctl1);
mci = edac_mc_alloc(0, PASEMI_EDAC_NR_CSROWS, PASEMI_EDAC_NR_CHANS,
system_mmc_id++);
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = PASEMI_EDAC_NR_CSROWS;
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = PASEMI_EDAC_NR_CHANS;
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(system_mmc_id++, ARRAY_SIZE(layers), layers,
0);
if (mci == NULL)
return -ENOMEM;
......
......@@ -727,7 +727,10 @@ ppc4xx_edac_handle_ce(struct mem_ctl_info *mci,
for (row = 0; row < mci->nr_csrows; row++)
if (ppc4xx_edac_check_bank_error(status, row))
edac_mc_handle_ce_no_info(mci, message);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
0, 0, 0,
row, 0, -1,
message, "", NULL);
}
/**
......@@ -755,7 +758,10 @@ ppc4xx_edac_handle_ue(struct mem_ctl_info *mci,
for (row = 0; row < mci->nr_csrows; row++)
if (ppc4xx_edac_check_bank_error(status, row))
edac_mc_handle_ue(mci, page, offset, row, message);
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
page, offset, 0,
row, 0, -1,
message, "", NULL);
}
/**
......@@ -895,9 +901,8 @@ ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1)
enum mem_type mtype;
enum dev_type dtype;
enum edac_type edac_mode;
int row;
u32 mbxcf, size;
static u32 ppc4xx_last_page;
int row, j;
u32 mbxcf, size, nr_pages;
/* Establish the memory type and width */
......@@ -948,7 +953,7 @@ ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1)
case SDRAM_MBCF_SZ_2GB:
case SDRAM_MBCF_SZ_4GB:
case SDRAM_MBCF_SZ_8GB:
csi->nr_pages = SDRAM_MBCF_SZ_TO_PAGES(size);
nr_pages = SDRAM_MBCF_SZ_TO_PAGES(size);
break;
default:
ppc4xx_edac_mc_printk(KERN_ERR, mci,
......@@ -959,10 +964,6 @@ ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1)
goto done;
}
csi->first_page = ppc4xx_last_page;
csi->last_page = csi->first_page + csi->nr_pages - 1;
csi->page_mask = 0;
/*
* It's unclear exactly what grain should be set to
* here. The SDRAM_ECCES register allows resolution of
......@@ -975,15 +976,17 @@ ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1)
* possible values would be the PLB width (16), the
* page size (PAGE_SIZE) or the memory width (2 or 4).
*/
for (j = 0; j < csi->nr_channels; j++) {
struct dimm_info *dimm = csi->channels[j].dimm;
csi->grain = 1;
csi->mtype = mtype;
csi->dtype = dtype;
dimm->nr_pages = nr_pages / csi->nr_channels;
dimm->grain = 1;
csi->edac_mode = edac_mode;
dimm->mtype = mtype;
dimm->dtype = dtype;
ppc4xx_last_page += csi->nr_pages;
dimm->edac_mode = edac_mode;
}
}
done:
......@@ -1236,6 +1239,7 @@ static int __devinit ppc4xx_edac_probe(struct platform_device *op)
dcr_host_t dcr_host;
const struct device_node *np = op->dev.of_node;
struct mem_ctl_info *mci = NULL;
struct edac_mc_layer layers[2];
static int ppc4xx_edac_instance;
/*
......@@ -1281,12 +1285,14 @@ static int __devinit ppc4xx_edac_probe(struct platform_device *op)
* controller instance and perform the appropriate
* initialization.
*/
mci = edac_mc_alloc(sizeof(struct ppc4xx_edac_pdata),
ppc4xx_edac_nr_csrows,
ppc4xx_edac_nr_chans,
ppc4xx_edac_instance);
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = ppc4xx_edac_nr_csrows;
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = ppc4xx_edac_nr_chans;
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(ppc4xx_edac_instance, ARRAY_SIZE(layers), layers,
sizeof(struct ppc4xx_edac_pdata));
if (mci == NULL) {
ppc4xx_edac_printk(KERN_ERR, "%s: "
"Failed to allocate EDAC MC instance!\n",
......
......@@ -179,10 +179,11 @@ static int r82600_process_error_info(struct mem_ctl_info *mci,
error_found = 1;
if (handle_errors)
edac_mc_handle_ce(mci, page, 0, /* not avail */
syndrome,
edac_mc_find_csrow_by_page(mci, page),
0, mci->ctl_name);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
page, 0, syndrome,
edac_mc_find_csrow_by_page(mci, page),
0, -1,
mci->ctl_name, "", NULL);
}
if (info->eapr & BIT(1)) { /* UE? */
......@@ -190,9 +191,11 @@ static int r82600_process_error_info(struct mem_ctl_info *mci,
if (handle_errors)
/* 82600 doesn't give enough info */
edac_mc_handle_ue(mci, page, 0,
edac_mc_find_csrow_by_page(mci, page),
mci->ctl_name);
edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
page, 0, 0,
edac_mc_find_csrow_by_page(mci, page),
0, -1,
mci->ctl_name, "", NULL);
}
return error_found;
......@@ -216,6 +219,7 @@ static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
u8 dramcr)
{
struct csrow_info *csrow;
struct dimm_info *dimm;
int index;
u8 drbar; /* SDRAM Row Boundary Address Register */
u32 row_high_limit, row_high_limit_last;
......@@ -227,6 +231,7 @@ static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
for (index = 0; index < mci->nr_csrows; index++) {
csrow = &mci->csrows[index];
dimm = csrow->channels[0].dimm;
/* find the DRAM Chip Select Base address and mask */
pci_read_config_byte(pdev, R82600_DRBA + index, &drbar);
......@@ -247,16 +252,17 @@ static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
csrow->first_page = row_base >> PAGE_SHIFT;
csrow->last_page = (row_high_limit >> PAGE_SHIFT) - 1;
csrow->nr_pages = csrow->last_page - csrow->first_page + 1;
dimm->nr_pages = csrow->last_page - csrow->first_page + 1;
/* Error address is top 19 bits - so granularity is *
* 14 bits */
csrow->grain = 1 << 14;
csrow->mtype = reg_sdram ? MEM_RDDR : MEM_DDR;
dimm->grain = 1 << 14;
dimm->mtype = reg_sdram ? MEM_RDDR : MEM_DDR;
/* FIXME - check that this is unknowable with this chipset */
csrow->dtype = DEV_UNKNOWN;
dimm->dtype = DEV_UNKNOWN;
/* Mode is global on 82600 */
csrow->edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE;
dimm->edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE;
row_high_limit_last = row_high_limit;
}
}
......@@ -264,6 +270,7 @@ static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
{
struct mem_ctl_info *mci;
struct edac_mc_layer layers[2];
u8 dramcr;
u32 eapr;
u32 scrub_disabled;
......@@ -278,8 +285,13 @@ static int r82600_probe1(struct pci_dev *pdev, int dev_idx)
debugf2("%s(): sdram refresh rate = %#0x\n", __func__,
sdram_refresh_rate);
debugf2("%s(): DRAMC register = %#0x\n", __func__, dramcr);
mci = edac_mc_alloc(0, R82600_NR_CSROWS, R82600_NR_CHANS, 0);
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = R82600_NR_CSROWS;
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = R82600_NR_CHANS;
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, 0);
if (mci == NULL)
return -ENOMEM;
......
此差异已折叠。
......@@ -71,7 +71,10 @@ static void tile_edac_check(struct mem_ctl_info *mci)
if (mem_error.sbe_count != priv->ce_count) {
dev_dbg(mci->dev, "ECC CE err on node %d\n", priv->node);
priv->ce_count = mem_error.sbe_count;
edac_mc_handle_ce(mci, 0, 0, 0, 0, 0, mci->ctl_name);
edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
0, 0, 0,
0, 0, -1,
mci->ctl_name, "", NULL);
}
}
......@@ -84,6 +87,7 @@ static int __devinit tile_edac_init_csrows(struct mem_ctl_info *mci)
struct csrow_info *csrow = &mci->csrows[0];
struct tile_edac_priv *priv = mci->pvt_info;
struct mshim_mem_info mem_info;
struct dimm_info *dimm = csrow->channels[0].dimm;
if (hv_dev_pread(priv->hv_devhdl, 0, (HV_VirtAddr)&mem_info,
sizeof(struct mshim_mem_info), MSHIM_MEM_INFO_OFF) !=
......@@ -93,27 +97,25 @@ static int __devinit tile_edac_init_csrows(struct mem_ctl_info *mci)
}
if (mem_info.mem_ecc)
csrow->edac_mode = EDAC_SECDED;
dimm->edac_mode = EDAC_SECDED;
else
csrow->edac_mode = EDAC_NONE;
dimm->edac_mode = EDAC_NONE;
switch (mem_info.mem_type) {
case DDR2:
csrow->mtype = MEM_DDR2;
dimm->mtype = MEM_DDR2;
break;
case DDR3:
csrow->mtype = MEM_DDR3;
dimm->mtype = MEM_DDR3;
break;
default:
return -1;
}
csrow->first_page = 0;
csrow->nr_pages = mem_info.mem_size >> PAGE_SHIFT;
csrow->last_page = csrow->first_page + csrow->nr_pages - 1;
csrow->grain = TILE_EDAC_ERROR_GRAIN;
csrow->dtype = DEV_UNKNOWN;
dimm->nr_pages = mem_info.mem_size >> PAGE_SHIFT;
dimm->grain = TILE_EDAC_ERROR_GRAIN;
dimm->dtype = DEV_UNKNOWN;
return 0;
}
......@@ -123,6 +125,7 @@ static int __devinit tile_edac_mc_probe(struct platform_device *pdev)
char hv_file[32];
int hv_devhdl;
struct mem_ctl_info *mci;
struct edac_mc_layer layers[2];
struct tile_edac_priv *priv;
int rc;
......@@ -132,8 +135,14 @@ static int __devinit tile_edac_mc_probe(struct platform_device *pdev)
return -EINVAL;
/* A TILE MC has a single channel and one chip-select row. */
mci = edac_mc_alloc(sizeof(struct tile_edac_priv),
TILE_EDAC_NR_CSROWS, TILE_EDAC_NR_CHANS, pdev->id);
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
layers[0].size = TILE_EDAC_NR_CSROWS;
layers[0].is_virt_csrow = true;
layers[1].type = EDAC_MC_LAYER_CHANNEL;
layers[1].size = TILE_EDAC_NR_CHANS;
layers[1].is_virt_csrow = false;
mci = edac_mc_alloc(pdev->id, ARRAY_SIZE(layers), layers,
sizeof(struct tile_edac_priv));
if (mci == NULL)
return -ENOMEM;
priv = mci->pvt_info;
......
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册