lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1328832090-9166-20-git-send-email-mchehab@redhat.com>
Date:	Thu,  9 Feb 2012 22:01:18 -0200
From:	Mauro Carvalho Chehab <mchehab@...hat.com>
To:	unlisted-recipients:; (no To-header on input)
Cc:	Mauro Carvalho Chehab <mchehab@...hat.com>,
	Linux Edac Mailing List <linux-edac@...r.kernel.org>,
	Linux Kernel Mailing List <linux-kernel@...r.kernel.org>
Subject: [PATCH v3 19/31] edac: rework memory layer hierarchy description

The old way of allocating data were confusing. It were
also introducing a miss-concept with regards to "channel",
when csrows are used.

Instead, use a more generic approach: breaks the memory
controller into layers. Drivers are free to describe the
layers any way they want, in order to match the memory
architecture.

Signed-off-by: Mauro Carvalho Chehab <mchehab@...hat.com>
---
 drivers/edac/amd64_edac.c       |  108 +++----
 drivers/edac/amd76x_edac.c      |   35 ++-
 drivers/edac/cell_edac.c        |   31 +-
 drivers/edac/cpc925_edac.c      |   26 +-
 drivers/edac/e752x_edac.c       |   44 ++--
 drivers/edac/e7xxx_edac.c       |   37 +--
 drivers/edac/edac_core.h        |   54 +---
 drivers/edac/edac_mc.c          |  684 +++++++++++++++------------------------
 drivers/edac/edac_mc_sysfs.c    |   93 +++---
 drivers/edac/i3000_edac.c       |   34 +-
 drivers/edac/i3200_edac.c       |   36 +-
 drivers/edac/i5000_edac.c       |   48 ++--
 drivers/edac/i5100_edac.c       |   26 +-
 drivers/edac/i5400_edac.c       |   49 ++--
 drivers/edac/i7300_edac.c       |   46 +--
 drivers/edac/i7core_edac.c      |  168 ++---------
 drivers/edac/i82443bxgx_edac.c  |   28 +-
 drivers/edac/i82860_edac.c      |   36 +--
 drivers/edac/i82875p_edac.c     |   35 +-
 drivers/edac/i82975x_edac.c     |   33 +-
 drivers/edac/mpc85xx_edac.c     |   26 +-
 drivers/edac/mv64x60_edac.c     |   26 +-
 drivers/edac/pasemi_edac.c      |   25 +-
 drivers/edac/ppc4xx_edac.c      |   34 +-
 drivers/edac/r82600_edac.c      |   33 +-
 drivers/edac/sb_edac.c          |   94 ++-----
 drivers/edac/tile_edac.c        |   18 +-
 drivers/edac/x38_edac.c         |   37 ++-
 include/linux/edac.h            |  122 ++++----
 include/trace/events/hw_event.h |   27 +--
 30 files changed, 838 insertions(+), 1255 deletions(-)

diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 139e774..1b374b5 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -1049,24 +1049,24 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 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,
-				     HW_EVENT_SCOPE_MC, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 				     page, offset, syndrome,
-				     -1, -1, -1, -1, -1,
+				     -1, -1, -1,
 				     EDAC_MOD_STR,
-				     "failed to map error addr to a node");
+				     "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,
-				     HW_EVENT_SCOPE_MC, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 				     page, offset, syndrome,
-				     -1, -1, -1, -1, -1,
+				     -1, -1, -1,
 				     EDAC_MOD_STR,
-				     "failed to map error addr to a csrow");
+				     "failed to map error addr to a csrow",
+				     NULL);
 		return;
 	}
 
@@ -1082,12 +1082,12 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
 			amd64_mc_warn(src_mci, "unknown syndrome 0x%04x - "
 				      "possible error reporting race\n",
 				      syndrome);
-			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED,
-					     HW_EVENT_SCOPE_MC_CSROW, mci,
+			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 					     page, offset, syndrome,
-					     -1, -1, -1, csrow, -1,
+					     csrow, -1, -1,
 					     EDAC_MOD_STR,
-					     "unknown syndrome - possible error reporting race");
+					     "unknown syndrome - possible error reporting race",
+					     NULL);
 			return;
 		}
 	} else {
@@ -1102,11 +1102,10 @@ static void k8_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
 		channel = ((sys_addr & BIT(3)) != 0);
 	}
 
-	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED,
-			     HW_EVENT_SCOPE_MC_CSROW_CHANNEL, src_mci,
+	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, src_mci,
 			     page, offset, syndrome,
-			     -1, -1, -1, csrow, channel,
-			     EDAC_MOD_STR, "");
+			     csrow, channel, -1,
+			     EDAC_MOD_STR, "", NULL);
 }
 
 static int ddr2_cs_size(unsigned i, bool dct_width)
@@ -1587,19 +1586,18 @@ static void f1x_map_sysaddr_to_csrow(struct mem_ctl_info *mci, u64 sys_addr,
 	struct amd64_pvt *pvt = mci->pvt_info;
 	u32 page, offset;
 	int nid, csrow, chan = 0;
-	enum hw_event_error_scope scope;
 
 	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_error(HW_EVENT_ERR_CORRECTED,
-				     HW_EVENT_SCOPE_MC, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 				     page, offset, syndrome,
-				     -1, -1, -1, -1, -1,
+				     -1, -1, -1,
 				     EDAC_MOD_STR,
-				     "failed to map error addr to a csrow");
+				     "failed to map error addr to a csrow",
+				     NULL);
 		return;
 	}
 
@@ -1611,22 +1609,16 @@ 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);
 
-	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED,
-				HW_EVENT_SCOPE_MC, mci,
+	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 				page, offset, syndrome,
-				-1, -1, -1, -1, -1,
+				-1, -1, -1,
 				EDAC_MOD_STR,
-				"failed to map error addr to a csrow");
-	if (chan >= 0)
-		scope = HW_EVENT_SCOPE_MC_CSROW_CHANNEL;
-	else
-		scope = HW_EVENT_SCOPE_MC_CSROW;
+				"failed to map error addr to a csrow", NULL);
 
-	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED,
-				HW_EVENT_SCOPE_MC, mci,
+	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 				page, offset, syndrome,
-				-1, -1, -1, csrow, chan,
-				EDAC_MOD_STR, "");
+				csrow, chan, -1,
+				EDAC_MOD_STR, "", NULL);
 }
 
 /*
@@ -1907,12 +1899,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_error(HW_EVENT_ERR_CORRECTED,
-				     HW_EVENT_SCOPE_MC, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 				     0, 0, 0,
-				     -1, -1, -1, -1, -1,
+				     -1, -1, -1,
 				     EDAC_MOD_STR,
-				     "HW has no ERROR_ADDRESS available");
+				     "HW has no ERROR_ADDRESS available",
+				     NULL);
 		return;
 	}
 
@@ -1936,12 +1928,12 @@ 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_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 				     0, 0, 0,
-				     -1, -1, -1, -1, -1,
+				     -1, -1, -1,
 				     EDAC_MOD_STR,
-				     "HW has no ERROR_ADDRESS available");
+				     "HW has no ERROR_ADDRESS available",
+				     NULL);
 		return;
 	}
 
@@ -1956,12 +1948,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_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 				     page, offset, 0,
-				     -1, -1, -1, -1, -1,
+				     -1, -1, -1,
 				     EDAC_MOD_STR,
-				     "ERROR ADDRESS NOT mapped to a MC");
+				     "ERROR ADDRESS NOT mapped to a MC", NULL);
 		return;
 	}
 
@@ -1971,18 +1962,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_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 				     page, offset, 0,
-				     -1, -1, -1, -1, -1,
+				     -1, -1, -1,
 				     EDAC_MOD_STR,
-				     "ERROR ADDRESS NOT mapped to CS");
+				     "ERROR ADDRESS NOT mapped to CS",
+				     NULL);
 	} else {
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC_CSROW, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 				     page, offset, 0,
-				     -1, -1, -1, csrow, -1,
-				     EDAC_MOD_STR, "");
+				     csrow, -1, -1,
+				     EDAC_MOD_STR, "", NULL);
 	}
 }
 
@@ -2542,6 +2532,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);
 
@@ -2576,10 +2567,13 @@ static int amd64_init_one_instance(struct pci_dev *F2)
 		goto err_siblings;
 
 	ret = -ENOMEM;
-	/* FIXME: Assuming one DIMM per csrow channel */
-	mci = edac_mc_alloc(nid, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    0, 0, pvt->csels[0].b_cnt * pvt->channel_count,
-			    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_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = pvt->channel_count;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(nid, ARRAY_SIZE(layers), layers, false, 0);
 	if (!mci)
 		goto err_siblings;
 
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c
index 7e6bbf8..4f3e54a 100644
--- a/drivers/edac/amd76x_edac.c
+++ b/drivers/edac/amd76x_edac.c
@@ -145,12 +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_error(HW_EVENT_ERR_UNCORRECTED,
-					     HW_EVENT_SCOPE_MC_CSROW_CHANNEL,
-					     mci, mci->csrows[row].first_page,
-					     0, 0,
-					     -1, -1, row, row, 0,
-					     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);
 		}
 	}
 
@@ -162,12 +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_error(HW_EVENT_ERR_CORRECTED,
-					     HW_EVENT_SCOPE_MC_CSROW_CHANNEL,
-					     mci, mci->csrows[row].first_page,
-					     0, 0,
-					     -1, -1, row, 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);
 		}
 	}
 
@@ -239,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;
@@ -247,9 +244,15 @@ 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, EDAC_ALLOC_FILL_MCCHANNEL_IS_CSROW,
-			    0, 0, AMD76X_NR_CSROWS,
-			    AMD76X_NR_CSROWS, 1, 0);
+
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = AMD76X_NR_CSROWS;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = 1;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, false, 0);
+
 	if (mci == NULL)
 		return -ENOMEM;
 
diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c
index abe06a4..39616a3 100644
--- a/drivers/edac/cell_edac.c
+++ b/drivers/edac/cell_edac.c
@@ -48,11 +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_error(HW_EVENT_ERR_CORRECTED,
-				HW_EVENT_SCOPE_MC_CSROW_CHANNEL, mci,
-				csrow->first_page + pfn, offset, syndrome,
-				-1, -1, -1, 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)
@@ -72,11 +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_error(HW_EVENT_ERR_UNCORRECTED,
-				HW_EVENT_SCOPE_MC_CSROW_CHANNEL, mci,
-				csrow->first_page + pfn, offset, 0,
-				-1, -1, -1, 0, chan,
-				"", "");
+	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)
@@ -163,7 +159,7 @@ static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
 			"Initialized on node %d, chanmask=0x%x,"
 			" first_page=0x%lx, nr_pages=0x%x\n",
 			priv->node, priv->chanmask,
-			csrow->first_page, dimm->nr_pages);
+			csrow->first_page, nr_pages);
 		break;
 	}
 }
@@ -172,6 +168,7 @@ 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, num_chans;
@@ -200,9 +197,15 @@ static int __devinit cell_edac_probe(struct platform_device *pdev)
 
 	/* Allocate & init EDAC MC data structure */
 	num_chans = chanmask == 3 ? 2 : 1;
-	mci = edac_mc_alloc(pdev->id, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    0, 0, num_chans,
-			    1, num_chans, sizeof(struct cell_edac_priv));
+
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = 1;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = num_chans;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(pdev->id, ARRAY_SIZE(layers), layers, false,
+			    sizeof(struct cell_edac_priv));
 	if (mci == NULL)
 		return -ENOMEM;
 	priv = mci->pvt_info;
diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c
index 4a25b92..eb6297d 100644
--- a/drivers/edac/cpc925_edac.c
+++ b/drivers/edac/cpc925_edac.c
@@ -555,20 +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_error(HW_EVENT_ERR_CORRECTED,
-				     HW_EVENT_SCOPE_MC_CSROW_CHANNEL, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 				     pfn, offset, syndrome,
-				     -1, -1, -1, csrow, channel,
-				     mci->ctl_name, "");
+				     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_error(HW_EVENT_ERR_CORRECTED,
-				     HW_EVENT_SCOPE_MC_CSROW, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 				     pfn, offset, 0,
-				     -1, -1, -1, csrow, -1,
-				     mci->ctl_name, "");
+				     csrow, -1, -1,
+				     mci->ctl_name, "", NULL);
 	}
 
 	cpc925_mc_printk(mci, KERN_INFO, "Dump registers:\n");
@@ -940,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;
@@ -976,9 +975,14 @@ static int __devinit cpc925_probe(struct platform_device *pdev)
 	}
 
 	nr_channels = cpc925_mc_get_channels(vbase) + 1;
-	mci = edac_mc_alloc(edac_mc_idx, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    0, 0, CPC925_NR_CSROWS * nr_channels,
-			    CPC925_NR_CSROWS, nr_channels,
+
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = CPC925_NR_CSROWS;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = nr_channels;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers, false,
 			    sizeof(struct cpc925_mc_pdata));
 	if (!mci) {
 		cpc925_printk(KERN_ERR, "No memory for mem_ctl_info\n");
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 813d965..1acce46 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
@@ -353,11 +353,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_error(HW_EVENT_ERR_CORRECTED,
-			     HW_EVENT_SCOPE_MC, mci,
+	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 			     page, offset_in_page(sec1_add << 4), sec1_syndrome,
-			     -1, -1, -1, row, channel,
-			     "e752x CE", "");
+			     row, channel, -1,
+			     "e752x CE", "", NULL);
 }
 
 static inline void process_ce(struct mem_ctl_info *mci, u16 error_one,
@@ -391,12 +390,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_error(HW_EVENT_ERR_UNCORRECTED,
-					HW_EVENT_SCOPE_MC_CSROW, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 					block_page,
 					offset_in_page(error_2b << 4), 0,
-					-1, -1, -1, row, -1,
-					"e752x UE from Read", "");
+					 row, -1, -1,
+					"e752x UE from Read", "", NULL);
 
 	}
 	if (error_one & 0x0404) {
@@ -411,12 +409,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_error(HW_EVENT_ERR_UNCORRECTED,
-					HW_EVENT_SCOPE_MC_CSROW, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 					block_page,
 					offset_in_page(error_2b << 4), 0,
-					-1, -1, -1, row, -1,
-					"e752x UE from Scruber", "");
+					row, -1, -1,
+					"e752x UE from Scruber", "", NULL);
 	}
 }
 
@@ -439,10 +436,9 @@ static inline void process_ue_no_info_wr(struct mem_ctl_info *mci,
 		return;
 
 	debugf3("%s()\n", __func__);
-	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-			     HW_EVENT_SCOPE_MC, mci, 0, 0, 0,
-			     -1, -1, -1, -1, -1,
-			     "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,
@@ -1248,6 +1244,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 */
@@ -1274,13 +1271,16 @@ 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(0, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    0, 0, E752X_NR_CSROWS * (drc_chan + 1),
-			    E752X_NR_CSROWS, drc_chan + 1, sizeof(*pvt));
-
-	if (mci == NULL) {
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = E752X_NR_CSROWS;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = drc_chan + 1;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
+			    false, sizeof(*pvt));
+	if (mci == NULL)
 		return -ENOMEM;
-	}
 
 	debugf3("%s(): init mci\n", __func__);
 	mci->mtype_cap = MEM_FLAG_RDDR;
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c
index 01f64d3..f59dc0c 100644
--- a/drivers/edac/e7xxx_edac.c
+++ b/drivers/edac/e7xxx_edac.c
@@ -219,20 +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_error(HW_EVENT_ERR_CORRECTED,
-			     HW_EVENT_SCOPE_MC_CSROW_CHANNEL, mci,
-			     page, 0, syndrome,
-			     -1, -1, -1, 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_error(HW_EVENT_ERR_UNCORRECTED,
-			     HW_EVENT_SCOPE_MC, mci, 0, 0, 0,
-			     -1, -1, -1, -1, -1,
-			     "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)
@@ -247,20 +242,16 @@ static void process_ue(struct mem_ctl_info *mci, struct e7xxx_error_info *info)
 	block_page = error_2b >> 6;	/* convert to 4k address */
 	row = edac_mc_find_csrow_by_page(mci, block_page);
 
-	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-			     HW_EVENT_SCOPE_MC_CSROW, mci, block_page, 0, 0,
-			     -1, -1, -1, row, -1,
-			     "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_error(HW_EVENT_ERR_UNCORRECTED,
-			     HW_EVENT_SCOPE_MC, mci, 0, 0, 0,
-			     -1, -1, -1, -1, -1,
-			     "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,
@@ -431,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;
@@ -449,10 +441,13 @@ static int e7xxx_probe1(struct pci_dev *pdev, int dev_idx)
 	 * will map the rank. So, an error to either channel should be
 	 * attributed to the same dimm.
 	 */
-	mci = edac_mc_alloc(0, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    0, 0, E7XXX_NR_DIMMS,
-			    E7XXX_NR_CSROWS, drc_chan + 1, sizeof(*pvt));
-
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = E7XXX_NR_CSROWS;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = drc_chan + 1;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, false, sizeof(*pvt));
 	if (mci == NULL)
 		return -ENOMEM;
 
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index e4961fd..1d421d3 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
@@ -448,35 +448,10 @@ static inline void pci_write_bits32(struct pci_dev *pdev, int offset,
 
 #endif				/* CONFIG_PCI */
 
-/**
- * enum edac_alloc_fill_strategy - Controls the way csrows/cschannels are mapped
- * @EDAC_ALLOC_FILL_CSROW_CSCHANNEL:	csrows are rows, cschannels are channel.
- *					This is the default and should be used
- *					when the memory controller is able to
- *					see csrows/cschannels. The dimms are
- *					associated with cschannels.
- * @EDAC_ALLOC_FILL_MCCHANNEL_IS_CSROW:	mc_branch/mc_channel are mapped as
- *					cschannel. DIMMs inside each channel are
- *					mapped as csrows. Most FBDIMMs drivers
- *					use this model.
- *@...C_ALLOC_FILL_PRIV:		The driver uses its own mapping model.
- *					So, the core will leave the csrows
- *					struct unitialized, leaving to the
- *					driver the task of filling it.
- */
-enum edac_alloc_fill_strategy {
-	EDAC_ALLOC_FILL_CSROW_CSCHANNEL = 0,
-	EDAC_ALLOC_FILL_MCCHANNEL_IS_CSROW,
-	EDAC_ALLOC_FILL_PRIV,
-};
-
-struct mem_ctl_info *edac_mc_alloc(int edac_index,
-				   enum edac_alloc_fill_strategy fill_strategy,
-				   unsigned num_branch,
-				   unsigned num_channel,
-				   unsigned num_dimm,
-				   unsigned nr_csrows,
-				   unsigned num_cschans,
+struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
+				   unsigned n_layers,
+				   struct edac_mc_layer *layers,
+				   bool rev_order,
 				   unsigned sz_pvt);
 extern int edac_mc_add_mc(struct mem_ctl_info *mci);
 extern void edac_mc_free(struct mem_ctl_info *mci);
@@ -485,19 +460,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);
-void edac_mc_handle_error(enum hw_event_mc_err_type type,
-			  enum hw_event_error_scope scope,
+void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  struct mem_ctl_info *mci,
-			  unsigned long page_frame_number,
-			  unsigned long offset_in_page,
-			  unsigned long syndrome,
-			  int mc_branch,
-			  int mc_channel,
-			  int mc_dimm_number,
-			  int csrow,
-			  int cschannel,
+			  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 char *other_detail,
+			  const void *mcelog);
 
 /*
  * edac_device APIs
@@ -509,6 +482,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
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index 55760bc..6e8faf3 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -53,13 +53,18 @@ static void edac_mc_dump_channel(struct csrow_channel_info *chan)
 
 static void edac_mc_dump_dimm(struct dimm_info *dimm)
 {
+	int i;
+
 	debugf4("\tdimm = %p\n", dimm);
 	debugf4("\tdimm->label = '%s'\n", dimm->label);
 	debugf4("\tdimm->nr_pages = 0x%x\n", dimm->nr_pages);
-	debugf4("\tdimm location %d.%d.%d.%d.%d\n",
-		dimm->mc_branch, dimm->mc_channel,
-		dimm->mc_dimm_number,
-		dimm->csrow, dimm->cschannel);
+	debugf4("\tdimm location ");
+	for (i = 0; i < dimm->mci->n_layers; i++) {
+		printk(KERN_CONT "%d", dimm->location[i]);
+		if (i < dimm->mci->n_layers - 1)
+			printk(KERN_CONT ".");
+	}
+	printk(KERN_CONT "\n");
 	debugf4("\tdimm->grain = %d\n", dimm->grain);
 	debugf4("\tdimm->nr_pages = 0x%x\n", dimm->nr_pages);
 }
@@ -160,52 +165,25 @@ void *edac_align_ptr(void **p, unsigned size, int quant)
 /**
  * edac_mc_alloc: Allocate and partially fills a struct mem_ctl_info structure
  * @edac_index:		Memory controller number
- * @fill_strategy:	csrow/cschannel filling strategy
- * @num_branch:		Number of memory controller branches
- * @num_channel:	Number of memory controller channels
- * @num_dimm:		Number of dimms per memory controller channel
- * @num_csrows:		Number of CWROWS accessed via the memory controller
- * @num_cschannel:	Number of csrows channels
+ * @n_layers:		Number of layers at the MC hierarchy
+ * layers:		Describes each layer as seen by the Memory Controller
+ * @rev_order:		Fills csrows/cs channels at the reverse order
  * @size_pvt:		size of private storage needed
  *
- * This routine supports 3 modes of DIMM mapping:
- *	1) the ones that accesses DRAM's via some bus interface (FB-DIMM
- * and RAMBUS memory controllers) or that don't have chip select view
- *
- * In this case, a branch is generally a group of 2 channels, used generally
- * in  parallel to provide 128 bits data.
- *
- * In the case of FB-DIMMs, the dimm is addressed via the SPD Address
- * input selection, used by the AMB to select the DIMM. The MC channel
- * corresponds to the Memory controller channel bus used to see a series
- * of FB-DIMM's.
- *
- * num_branch, num_channel and num_dimm should point to the real
- *	parameters of the memory controller.
- *
- * The total number of dimms is num_branch * num_channel * num_dimm
- *
- * According with JEDEC No. 205, up to 8 FB-DIMMs are possible per channel. Of
- * course, controllers may have a lower limit.
+ * FIXME: rev_order seems to be uneeded. On all places, it is marked as false.
+ * Tests are required, but if this is the case, this field can just be dropped.
  *
- * num_csrows/num_cschannel should point to the emulated parameters.
- * The total number of cschannels (num_csrows * num_cschannel) should be a
- * multiple of the total number dimms, e. g:
- *  factor = (num_csrows * num_cschannel)/(num_branch * num_channel * num_dimm)
- * should be an integer (typically: it is 1 or num_cschannel)
+ * FIXME: drivers handle multi-rank memories on different ways: on some
+ * drivers, one multi-rank memory is mapped as one DIMM, while, on others,
+ * a single multi-rank DIMM would be mapped into several "dimms".
  *
- *	2) The MC uses CSROWS/CS CHANNELS to directly select a DRAM chip.
- * One dimm chip exists on every cs channel, for single-rank memories.
- *	num_branch and num_channel should be 0
- *	num_dimm should be the total number of dimms
- *	num_csrows * num_cschannel should be equal to num_dimm
+ * Non-csrow based drivers (like FB-DIMM and RAMBUS ones) will likely report
+ * such DIMMS properly, but the CSROWS-based ones will likely do the wrong
+ * thing, as two chip select values are used for dual-rank memories (and 4, for
+ * quad-rank ones). I suspect that this issue could be solved inside the EDAC
+ * core for SDRAM memories, but it requires further study at JEDEC JESD 21C.
  *
- *	3)The MC uses CSROWS/CS CHANNELS. One dimm chip exists on every
- * csrow. The cs channel is used to indicate the defective chip(s) inside
- * the memory stick.
- *	num_branch and num_channel should be 0
- *	num_dimm should be the total number of dimms
- *	num_csrows should be equal to num_dimm
+ * In summary, solving this issue is not easy, as it requires a lot of testing.
  *
  * Everything is kmalloc'ed as one big chunk - more efficient.
  * Only can be used if all structures have the same lifetime - otherwise
@@ -217,87 +195,64 @@ void *edac_align_ptr(void **p, unsigned size, int quant)
  *	NULL allocation failed
  *	struct mem_ctl_info pointer
  */
-struct mem_ctl_info *edac_mc_alloc(int edac_index,
-				   enum edac_alloc_fill_strategy fill_strategy,
-				   unsigned num_branch,
-				   unsigned num_channel,
-				   unsigned num_dimm,
-				   unsigned num_csrows,
-				   unsigned num_cschannel,
+struct mem_ctl_info *edac_mc_alloc(unsigned edac_index,
+				   unsigned n_layers,
+				   struct edac_mc_layer *layers,
+				   bool rev_order,
 				   unsigned sz_pvt)
 {
 	void *ptr;
 	struct mem_ctl_info *mci;
+	struct edac_mc_layer *lay;
 	struct csrow_info *csi, *csr;
 	struct csrow_channel_info *chi, *chp, *chan;
 	struct dimm_info *dimm;
-	u32 *ce_branch, *ce_channel, *ce_dimm, *ce_csrow, *ce_cschannel;
-	u32 *ue_branch, *ue_channel, *ue_dimm, *ue_csrow, *ue_cschannel;
+	u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
 	void *pvt;
-	unsigned size, tot_dimms, count, dimm_div;
-	int i;
+	unsigned size, tot_dimms, count, per_layer_count[EDAC_MAX_LAYERS];
+	unsigned tot_csrows, tot_cschannels;
+	int i, j;
 	int err;
-	int mc_branch, mc_channel, mc_dimm_number, csrow, cschannel;
 	int row, chn;
 
+	BUG_ON(n_layers > EDAC_MAX_LAYERS);
 	/*
-	 * While we expect that non-pertinent values will be filled with
-	 * 0, in order to provide a way for this routine to detect if the
-	 * EDAC is emulating the old sysfs API, we can't actually accept
-	 * 0, as otherwise, a multiply by 0 whould hapen.
+	 * Calculate the total amount of dimms and csrows/cschannels while
+	 * in the old API emulation mode
 	 */
-	if (num_branch <= 0)
-		num_branch = 1;
-	if (num_channel <= 0)
-		num_channel = 1;
-	if (num_dimm <= 0)
-		num_dimm = 1;
-	if (num_csrows <= 0)
-		num_csrows = 1;
-	if (num_cschannel <= 0)
-		num_cschannel = 1;
-
-	tot_dimms = num_branch * num_channel * num_dimm;
-	dimm_div = (num_csrows * num_cschannel) / tot_dimms;
-	if (dimm_div == 0) {
-		printk(KERN_ERR "%s: dimm_div is wrong: tot_channels/tot_dimms = %d/%d < 1\n",
-			__func__, num_csrows * num_cschannel, tot_dimms);
-		dimm_div = 1;
+	tot_dimms = 1;
+	tot_cschannels = 1;
+	tot_csrows = 1;
+	for (i = 0; i < n_layers; i++) {
+		tot_dimms *= layers[i].size;
+		if (layers[i].is_csrow)
+			tot_csrows *= layers[i].size;
+		else
+			tot_cschannels *= layers[i].size;
 	}
-	/* FIXME: change it to debug2() at the final version */
 
 	/* Figure out the offsets of the various items from the start of an mc
 	 * structure.  We want the alignment of each item to be at least as
 	 * stringent as what the compiler would provide if we could simply
 	 * hardcode everything into a single struct.
 	 */
-	ptr = NULL;
+	ptr = 0;
 	mci = edac_align_ptr(&ptr, sizeof(*mci), 1);
-	csi = edac_align_ptr(&ptr, sizeof(*csi), num_csrows);
-	chi = edac_align_ptr(&ptr, sizeof(*chi), num_csrows * num_cschannel);
+	lay = edac_align_ptr(&ptr, sizeof(*lay), n_layers);
+	csi = edac_align_ptr(&ptr, sizeof(*csi), tot_csrows);
+	chi = edac_align_ptr(&ptr, sizeof(*chi), tot_csrows * tot_cschannels);
 	dimm = edac_align_ptr(&ptr, sizeof(*dimm), tot_dimms);
-
-	count = num_branch;
-	ue_branch = edac_align_ptr(&ptr, sizeof(*ce_branch), count);
-	ce_branch = edac_align_ptr(&ptr, sizeof(*ce_branch), count);
-	count *= num_channel;
-	ue_channel = edac_align_ptr(&ptr, sizeof(*ce_channel), count);
-	ce_channel = edac_align_ptr(&ptr, sizeof(*ce_channel), count);
-	count *= num_dimm;
-	ue_dimm = edac_align_ptr(&ptr, sizeof(*ce_dimm), count * num_dimm);
-	ce_dimm = edac_align_ptr(&ptr, sizeof(*ce_dimm), count * num_dimm);
-
-	count = num_csrows;
-	ue_csrow = edac_align_ptr(&ptr, sizeof(*ce_dimm), count);
-	ce_csrow = edac_align_ptr(&ptr, sizeof(*ce_dimm), count);
-	count *= num_cschannel;
-	ue_cschannel = edac_align_ptr(&ptr, sizeof(*ce_dimm), count);
-	ce_cschannel = edac_align_ptr(&ptr, sizeof(*ce_dimm), count);
-
+	count = 1;
+	for (i = 0; i < n_layers; i++) {
+		count *= layers[i].size;
+		ce_per_layer[i] = edac_align_ptr(&ptr, sizeof(unsigned), count);
+		ue_per_layer[i] = edac_align_ptr(&ptr, sizeof(unsigned), count);
+	}
 	pvt = edac_align_ptr(&ptr, sz_pvt, 1);
 	size = ((unsigned long)pvt) + sz_pvt;
 
-	debugf1("%s(): allocating %u bytes for mci data\n", __func__, size);
+	debugf1("%s(): allocating %u bytes for mci data (%d dimms, %d csrows/channels)\n",
+		__func__, size, tot_dimms, tot_csrows * tot_cschannels);
 	mci = kzalloc(size, GFP_KERNEL);
 	if (mci == NULL)
 		return NULL;
@@ -305,131 +260,97 @@ struct mem_ctl_info *edac_mc_alloc(int edac_index,
 	/* Adjust pointers so they point within the memory we just allocated
 	 * rather than an imaginary chunk of memory located at address 0.
 	 */
+	lay = (struct edac_mc_layer *)(((char *)mci) + ((unsigned long)lay));
 	csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi));
 	chi = (struct csrow_channel_info *)(((char *)mci) + ((unsigned long)chi));
 	dimm = (struct dimm_info *)(((char *)mci) + ((unsigned long)dimm));
+	for (i = 0; i < n_layers; i++) {
+		mci->ce_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ce_per_layer[i]));
+		mci->ue_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ue_per_layer[i]));
+	}
 	pvt = sz_pvt ? (((char *)mci) + ((unsigned long)pvt)) : NULL;
 
 	/* setup index and various internal pointers */
 	mci->mc_idx = edac_index;
 	mci->csrows = csi;
 	mci->dimms  = dimm;
-	mci->pvt_info = pvt;
-
 	mci->tot_dimms = tot_dimms;
-	mci->num_branch = num_branch;
-	mci->num_channel = num_channel;
-	mci->num_dimm = num_dimm;
-	mci->num_csrows = num_csrows;
-	mci->num_cschannel = num_cschannel;
+	mci->pvt_info = pvt;
+	mci->n_layers = n_layers;
+	mci->layers = lay;
+	memcpy(mci->layers, layers, sizeof(*lay) * n_layers);
+	mci->num_csrows = tot_csrows;
+	mci->num_cschannel = tot_cschannels;
 
 	/*
-	 * Fills the dimm struct
+	 * Fills the csrow struct
 	 */
-	mc_branch = (num_branch > 0) ? 0 : -1;
-	mc_channel = (num_channel > 0) ? 0 : -1;
-	mc_dimm_number = (num_dimm > 0) ? 0 : -1;
-	if (!num_channel && !num_branch) {
-		csrow = (num_csrows > 0) ? 0 : -1;
-		cschannel = (num_cschannel > 0) ? 0 : -1;
-	} else {
-		csrow = -1;
-		cschannel = -1;
+	for (row = 0; row < tot_csrows; row++) {
+		csr = &csi[row];
+		csr->csrow_idx = row;
+		csr->mci = mci;
+		csr->nr_channels = tot_cschannels;
+		chp = &chi[row * tot_cschannels];
+		csr->channels = chp;
+
+		for (chn = 0; chn < tot_cschannels; chn++) {
+			chan = &chp[chn];
+			chan->chan_idx = chn;
+			chan->csrow = csr;
+		}
 	}
 
+	/*
+	 * Fills the dimm struct
+	 */
+	memset(&per_layer_count, 0, sizeof(per_layer_count));
+	row = 0;
+	chn = 0;
 	debugf4("%s: initializing %d dimms\n", __func__, tot_dimms);
 	for (i = 0; i < tot_dimms; i++) {
+		debugf4("%s: dimm%d: row %d, chan %d\n", __func__,
+			i, row, chn);
+		chan = &csi[row].channels[chn];
 		dimm = &mci->dimms[i];
-
-		dimm->mc_branch = mc_branch;
-		dimm->mc_channel = mc_channel;
-		dimm->mc_dimm_number = mc_dimm_number;
-		dimm->csrow = csrow;
-		dimm->cschannel = cschannel;
-
-		/*
-		 * Increment the location
-		 * On csrow-emulated devices, csrow/cschannel should be -1
-		 */
-		if (!num_channel && !num_branch) {
-			if (num_cschannel) {
-				cschannel = (cschannel + 1) % num_cschannel;
-				if (cschannel)
-					continue;
+		dimm->mci = mci;
+
+		/* Copy DIMM location */
+		for (j = 0; j < n_layers; j++)
+			dimm->location[j] = per_layer_count[j];
+
+		/* Link it to the csrows old API data */
+		chan->dimm = dimm;
+		dimm->csrow = row;
+		dimm->cschannel = chn;
+
+		/* Increment csrow location */
+		if (!rev_order) {
+			for (j = n_layers - 1; j >= 0; j--)
+				if (!layers[j].is_csrow)
+					break;
+			chn++;
+			if (chn == tot_cschannels) {
+				chn = 0;
+				row++;
 			}
-			if (num_csrows) {
-				csrow = (csrow + 1) % num_csrows;
-				if (csrow)
-					continue;
+		} else {
+			for (j = n_layers - 1; j >= 0; j--)
+				if (layers[j].is_csrow)
+					break;
+			row++;
+			if (row == tot_csrows) {
+				row = 0;
+				chn++;
 			}
 		}
-		if (num_dimm) {
-			mc_dimm_number = (mc_dimm_number + 1) % num_dimm;
-			if (mc_dimm_number)
-				continue;
-		}
-		if (num_channel) {
-			mc_channel = (mc_channel + 1) % num_channel;
-			if (mc_channel)
-				continue;
-		}
-		if (num_branch) {
-			mc_branch = (mc_branch + 1) % num_branch;
-			if (mc_branch)
-				continue;
-		}
-	}
 
-	/*
-	 * Fills the csrows struct
-	 *
-	 * NOTE: there are two possible memory arrangements here:
-	 *
-	 *
-	 */
-	switch (fill_strategy) {
-	case EDAC_ALLOC_FILL_CSROW_CSCHANNEL:
-		for (row = 0; row < num_csrows; row++) {
-			csr = &csi[row];
-			csr->csrow_idx = row;
-			csr->mci = mci;
-			csr->nr_channels = num_cschannel;
-			chp = &chi[row * num_cschannel];
-			csr->channels = chp;
-
-			for (chn = 0; chn < num_cschannel; chn++) {
-				int dimm_idx = (chn + row * num_cschannel) /
-						dimm_div;
-				debugf4("%s: csrow(%d,%d) = dimm%d\n",
-					__func__, row, chn, dimm_idx);
-				chan = &chp[chn];
-				chan->chan_idx = chn;
-				chan->csrow = csr;
-				chan->dimm = &dimm[dimm_idx];
-			}
+		/* Increment dimm location */
+		for (j = n_layers - 1; j >= 0; j--) {
+			per_layer_count[j]++;
+			if (per_layer_count[j] < layers[j].size)
+				break;
+			per_layer_count[j] = 0;
 		}
-	case EDAC_ALLOC_FILL_MCCHANNEL_IS_CSROW:
-		for (row = 0; row < num_csrows; row++) {
-			csr = &csi[row];
-			csr->csrow_idx = row;
-			csr->mci = mci;
-			csr->nr_channels = num_cschannel;
-			chp = &chi[row * num_cschannel];
-			csr->channels = chp;
-
-			for (chn = 0; chn < num_cschannel; chn++) {
-				int dimm_idx = (chn * num_cschannel + row) /
-						dimm_div;
-				debugf4("%s: csrow(%d,%d) = dimm%d\n",
-					__func__, row, chn, dimm_idx);
-				chan = &chp[chn];
-				chan->chan_idx = chn;
-				chan->csrow = csr;
-				chan->dimm = &dimm[dimm_idx];
-			}
-		}
-	case EDAC_ALLOC_FILL_PRIV:
-		break;
 	}
 
 	mci->op_state = OP_ALLOC;
@@ -886,9 +807,9 @@ int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
 			csrow->page_mask);
 
 		if ((page >= csrow->first_page) &&
-		(page <= csrow->last_page) &&
-		((page & csrow->page_mask) ==
-		(csrow->first_page & csrow->page_mask))) {
+		    (page <= csrow->last_page) &&
+		    ((page & csrow->page_mask) ==
+		    (csrow->first_page & csrow->page_mask))) {
 			row = i;
 			break;
 		}
@@ -903,221 +824,110 @@ int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
 }
 EXPORT_SYMBOL_GPL(edac_mc_find_csrow_by_page);
 
-void edac_increment_ce_error(enum hw_event_error_scope scope,
-			     struct mem_ctl_info *mci,
-			     int mc_branch,
-			     int mc_channel,
-			     int mc_dimm_number,
-			     int csrow,
-			     int cschannel)
-{
-	int index;
+const char *edac_layer_name[] = {
+	[EDAC_MC_LAYER_BRANCH] = "branch",
+	[EDAC_MC_LAYER_CHANNEL] = "channel",
+	[EDAC_MC_LAYER_SLOT] = "slot",
+	[EDAC_MC_LAYER_CHIP_SELECT] = "csrow",
+};
+EXPORT_SYMBOL_GPL(edac_layer_name);
 
-	mci->err.ce_mc++;
+static void edac_increment_ce_error(struct mem_ctl_info *mci,
+				    bool enable_filter,
+				    unsigned pos[EDAC_MAX_LAYERS])
+{
+	int i, index = 0;
 
-	if (scope == HW_EVENT_SCOPE_MC) {
-		mci->ce_noinfo_count = 0;
-		return;
-	}
+	mci->ce_mc++;
 
-	index = 0;
-	if (mc_branch >= 0) {
-		index = mc_branch;
-		mci->err.ce_branch[index]++;
-	}
-	if (scope == HW_EVENT_SCOPE_MC_BRANCH)
+	if (!enable_filter) {
+		mci->ce_noinfo_count++;
 		return;
-	index *= mci->num_branch;
-
-	if (mc_channel >= 0) {
-		index += mc_channel;
-		mci->err.ce_channel[index]++;
 	}
-	if (scope == HW_EVENT_SCOPE_MC_CHANNEL)
-		return;
-	index *= mci->num_channel;
 
-	if (mc_dimm_number >= 0) {
-		index += mc_dimm_number;
-		mci->err.ce_dimm[index]++;
-	}
-	if (scope == HW_EVENT_SCOPE_MC_DIMM)
-		return;
-	index *= mci->num_dimm;
-
-	if (csrow >= 0) {
-		index += csrow;
-		mci->err.ce_csrow[csrow]++;
-	}
-	if (scope == HW_EVENT_SCOPE_MC_CSROW_CHANNEL)
-		return;
-	index *= mci->num_csrows;
-
-	if (cschannel >= 0) {
-		index += cschannel;
-		mci->err.ce_cschannel[index]++;
+	for (i = 0; i <= mci->n_layers; i++) {
+		if (pos[i] < 0)
+			break;
+		index += pos[i];
+		mci->ce_per_layer[i][index]++;
+		index *= mci->layers[i].size;
 	}
 }
 
-void edac_increment_ue_error(enum hw_event_error_scope scope,
-			     struct mem_ctl_info *mci,
-			     int mc_branch,
-			     int mc_channel,
-			     int mc_dimm_number,
-			     int csrow,
-			     int cschannel)
+static void edac_increment_ue_error(struct mem_ctl_info *mci,
+				    bool enable_filter,
+				    unsigned pos[EDAC_MAX_LAYERS])
 {
-	int index;
-
-	mci->err.ue_mc++;
+	int i, index = 0;
 
-	if (scope == HW_EVENT_SCOPE_MC) {
-		mci->ue_noinfo_count = 0;
-		return;
-	}
+	mci->ue_mc++;
 
-	index = 0;
-	if (mc_branch >= 0) {
-		index = mc_branch;
-		mci->err.ue_branch[index]++;
-	}
-	if (scope == HW_EVENT_SCOPE_MC_BRANCH)
+	if (!enable_filter) {
+		mci->ce_noinfo_count++;
 		return;
-	index *= mci->num_branch;
-
-	if (mc_channel >= 0) {
-		index += mc_channel;
-		mci->err.ue_channel[index]++;
 	}
-	if (scope == HW_EVENT_SCOPE_MC_CHANNEL)
-		return;
-	index *= mci->num_channel;
 
-	if (mc_dimm_number >= 0) {
-		index += mc_dimm_number;
-		mci->err.ue_dimm[index]++;
-	}
-	if (scope == HW_EVENT_SCOPE_MC_DIMM)
-		return;
-	index *= mci->num_dimm;
-
-	if (csrow >= 0) {
-		index += csrow;
-		mci->err.ue_csrow[csrow]++;
-	}
-	if (scope == HW_EVENT_SCOPE_MC_CSROW_CHANNEL)
-		return;
-	index *= mci->num_csrows;
-
-	if (cschannel >= 0) {
-		index += cschannel;
-		mci->err.ue_cschannel[index]++;
+	for (i = 0; i <= mci->n_layers; i++) {
+		if (pos[i] < 0)
+			break;
+		index += pos[i];
+		mci->ue_per_layer[i][index]++;
+		index *= mci->layers[i].size;
 	}
 }
 
-void edac_mc_handle_error(enum hw_event_mc_err_type type,
-			  enum hw_event_error_scope scope,
+void edac_mc_handle_error(const enum hw_event_mc_err_type type,
 			  struct mem_ctl_info *mci,
-			  unsigned long page_frame_number,
-			  unsigned long offset_in_page,
-			  unsigned long syndrome,
-			  int mc_branch,
-			  int mc_channel,
-			  int mc_dimm_number,
-			  int csrow,
-			  int cschannel,
+			  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 char *other_detail,
+			  const void *mcelog)
 {
 	unsigned long remapped_page;
-	/* FIXME: too much for stack. Move it to some pre-alocated area */
+	/* FIXME: too much for stack: move it to some pre-alocated area */
 	char detail[80 + strlen(other_detail)];
 	char label[(EDAC_MC_LABEL_LEN + 2) * mci->tot_dimms], *p;
 	char location[80];
+	int row = -1, chan = -1;
+	int pos[EDAC_MAX_LAYERS] = { layer0, layer1, layer2 };
 	int i;
 	u32 grain;
+	bool enable_filter = false;
 
 	debugf3("MC%d: %s()\n", mci->mc_idx, __func__);
 
 	/* Check if the event report is consistent */
-	if ((scope == HW_EVENT_SCOPE_MC_CSROW_CHANNEL) &&
-	    (cschannel >= mci->num_cschannel)) {
-		trace_mc_out_of_range(mci, "CE", "cs channel", cschannel,
-					0, mci->num_cschannel);
-		edac_mc_printk(mci, KERN_ERR,
-				"INTERNAL ERROR: cs channel out of range (%d >= %d)\n",
-				cschannel, mci->num_cschannel);
-		if (type == HW_EVENT_ERR_CORRECTED)
-			mci->err.ce_mc++;
-		else
-			mci->err.ue_mc++;
-		return;
-	} else {
-		cschannel = -1;
-	}
-
-	if ((scope <= HW_EVENT_SCOPE_MC_CSROW) &&
-	    (csrow >= mci->num_csrows)) {
-		trace_mc_out_of_range(mci, "CE", "csrow", csrow,
-					0, mci->num_csrows);
-		edac_mc_printk(mci, KERN_ERR,
-				"INTERNAL ERROR: csrow out of range (%d >= %d)\n",
-				csrow, mci->num_csrows);
-		if (type == HW_EVENT_ERR_CORRECTED)
-			mci->err.ce_mc++;
-		else
-			mci->err.ue_mc++;
-		return;
-	} else {
-		csrow = -1;
-	}
-
-	if ((scope <= HW_EVENT_SCOPE_MC_CSROW) &&
-	    (mc_dimm_number >= mci->num_dimm)) {
-		trace_mc_out_of_range(mci, "CE", "dimm_number",
-					mc_dimm_number, 0, mci->num_dimm);
-		edac_mc_printk(mci, KERN_ERR,
-				"INTERNAL ERROR: dimm_number out of range (%d >= %d)\n",
-				mc_dimm_number, mci->num_dimm);
-		if (type == HW_EVENT_ERR_CORRECTED)
-			mci->err.ce_mc++;
-		else
-			mci->err.ue_mc++;
-		return;
-	} else {
-		mc_dimm_number = -1;
-	}
-
-	if ((scope <= HW_EVENT_SCOPE_MC_CHANNEL) &&
-	    (mc_channel >= mci->num_dimm)) {
-		trace_mc_out_of_range(mci, "CE", "mc_channel",
-					mc_channel, 0, mci->num_dimm);
-		edac_mc_printk(mci, KERN_ERR,
-				"INTERNAL ERROR: mc_channel out of range (%d >= %d)\n",
-				mc_channel, mci->num_dimm);
-		if (type == HW_EVENT_ERR_CORRECTED)
-			mci->err.ce_mc++;
-		else
-			mci->err.ue_mc++;
-		return;
-	} else {
-		mc_channel = -1;
-	}
-
-	if ((scope <= HW_EVENT_SCOPE_MC_BRANCH) &&
-	    (mc_branch >= mci->num_branch)) {
-		trace_mc_out_of_range(mci, "CE", "branch",
-					mc_branch, 0, mci->num_branch);
-		edac_mc_printk(mci, KERN_ERR,
-				"INTERNAL ERROR: mc_branch out of range (%d >= %d)\n",
-				mc_branch, mci->num_branch);
-		if (type == HW_EVENT_ERR_CORRECTED)
-			mci->err.ce_mc++;
-		else
-			mci->err.ue_mc++;
-		return;
-	} else {
-		mc_branch = -1;
+	for (i = 0; i < mci->n_layers; i++) {
+		if (pos[i] >= mci->layers[i].size) {
+			if (type == HW_EVENT_ERR_CORRECTED) {
+				p = "CE";
+				mci->ce_mc++;
+			} else {
+				p = "UE";
+				mci->ue_mc++;
+			}
+			trace_mc_out_of_range(mci, p,
+					edac_layer_name[mci->layers[i].type],
+					pos[i], 0, mci->layers[i].size);
+			edac_mc_printk(mci, KERN_ERR,
+				       "INTERNAL ERROR: %s value is out of range (%d >= %d)\n",
+				       edac_layer_name[mci->layers[i].type],
+				       pos[i], mci->layers[i].size);
+			/*
+			 * Instead of just returning it, let's use what's
+			 * known about the error. The increment routines and
+			 * the DIMM filter logic will do the right thing by
+			 * pointing the likely damaged DIMMs.
+			 */
+			pos[i] = -1;
+		}
+		if (pos[i] > 0)
+			enable_filter = true;
 	}
 
 	/*
@@ -1134,50 +944,70 @@ void edac_mc_handle_error(enum hw_event_mc_err_type type,
 	 */
 	grain = 0;
 	p = label;
+	*p = '\0';
 	for (i = 0; i < mci->tot_dimms; i++) {
 		struct dimm_info *dimm = &mci->dimms[i];
 
-		if (mc_branch >= 0 && mc_branch != dimm->mc_branch)
+		if (layer0 >= 0 && layer0 != dimm->location[0])
 			continue;
-
-		if (mc_channel >= 0 && mc_channel != dimm->mc_channel)
+		if (layer1 >= 0 && layer1 != dimm->location[1])
 			continue;
-
-		if (mc_dimm_number >= 0 &&
-		    mc_dimm_number != dimm->mc_dimm_number)
-			continue;
-
-		if (csrow >= 0 && csrow != dimm->csrow)
-			continue;
-		if (cschannel >= 0 && cschannel != dimm->cschannel)
+		if (layer2 >= 0 && layer2 != dimm->location[2])
 			continue;
 
 		if (dimm->grain > grain)
 			grain = dimm->grain;
 
-		strcpy(p, dimm->label);
-		p[strlen(p)] = ' ';
-		p = p + strlen(p);
+		/*
+		 * If the error is memory-controller wide, there's no sense
+		 * on seeking for the affected DIMMs, as everything may be
+		 * affected.
+		 */
+		if (enable_filter) {
+			strcpy(p, dimm->label);
+			p[strlen(p)] = ' ';
+			p = p + strlen(p);
+			*p = '\0';
+
+			/*
+			 * get csrow/channel of the dimm, in order to allow
+			 * incrementing the compat API counters
+			 */
+			if (mci->layers[i].is_csrow) {
+				if (row == -1)
+					row = dimm->csrow;
+				else if (row >= 0 && row != dimm->csrow)
+					row = -2;
+			} else {
+				if (chan == -1)
+					chan = dimm->cschannel;
+				else if (chan >= 0 && chan != dimm->cschannel)
+					chan = -2;
+			}
+		}
+	}
+	if (!enable_filter) {
+		p = "any memory";
+	} else {
+		if (type == HW_EVENT_ERR_CORRECTED) {
+			if (row >= 0)
+				mci->csrows[row].ce_count++;
+			if (chan >= 0)
+				mci->csrows[row].channels[chan].ce_count++;
+		} else
+			if (row >= 0)
+				mci->csrows[row].ue_count++;
 	}
-	p[strlen(p)] = '\0';
 
 	/* Fill the RAM location data */
 	p = location;
-	if (mc_branch >= 0)
-		p += sprintf(p, "branch %d ", mc_branch);
-
-	if (mc_channel >= 0)
-		p += sprintf(p, "channel %d ", mc_channel);
-
-	if (mc_dimm_number >= 0)
-		p += sprintf(p, "dimm %d ", mc_dimm_number);
-
-	if (csrow >= 0)
-		p += sprintf(p, "csrow %d ", csrow);
-
-	if (cschannel >= 0)
-		p += sprintf(p, "cs_channel %d ", cschannel);
-
+	for (i = 0; i <= mci->n_layers; i++) {
+		if (pos[i] < 0)
+			continue;
+		p += sprintf(p, "%s %d ",
+			     edac_layer_name[mci->layers[i].type],
+			     pos[i]);
+	}
 
 	/* Memory type dependent details about the error */
 	if (type == HW_EVENT_ERR_CORRECTED)
@@ -1190,19 +1020,16 @@ void edac_mc_handle_error(enum hw_event_mc_err_type type,
 			"page 0x%lx offset 0x%lx grain %d\n",
 			page_frame_number, offset_in_page, grain);
 
-	trace_mc_error(type, mci->mc_idx, msg, label, mc_branch, mc_channel,
-		       mc_dimm_number, csrow, cschannel,
+	trace_mc_error(type, mci->mc_idx, msg, label, location,
 		       detail, other_detail);
 
 	if (type == HW_EVENT_ERR_CORRECTED) {
 		if (edac_mc_get_log_ce())
 			edac_mc_printk(mci, KERN_WARNING,
-				       "CE %s label \"%s\" (location: %d.%d.%d.%d.%d %s %s)\n",
-				       msg, label, mc_branch, mc_channel,
-				       mc_dimm_number, csrow, cschannel,
+				       "CE %s label \"%s\" (%s %s %s)\n",
+				       msg, label, location,
 				       detail, other_detail);
-		edac_increment_ce_error(scope, mci, mc_branch, mc_channel,
-					mc_dimm_number, csrow, cschannel);
+		edac_increment_ce_error(mci,enable_filter, pos);
 
 		if (mci->scrub_mode & SCRUB_SW_SRC) {
 			/*
@@ -1233,8 +1060,7 @@ void edac_mc_handle_error(enum hw_event_mc_err_type type,
 			panic("UE %s label \"%s\" (%s %s %s)\n",
 			      msg, label, location, detail, other_detail);
 
-		edac_increment_ue_error(scope, mci, mc_branch, mc_channel,
-					mc_dimm_number, csrow, cschannel);
+		edac_increment_ue_error(mci,enable_filter, pos);
 	}
 }
 EXPORT_SYMBOL_GPL(edac_mc_handle_error);
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index a6f611f..245c588 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -132,17 +132,13 @@ static const char *edac_caps[] = {
 static ssize_t csrow_ue_count_show(struct csrow_info *csrow, char *data,
 				int private)
 {
-	struct mem_ctl_info *mci = csrow->mci;
-
-	return sprintf(data, "%u\n", mci->err.ue_csrow[csrow->csrow_idx]);
+	return sprintf(data, "%u\n", csrow->ue_count);
 }
 
 static ssize_t csrow_ce_count_show(struct csrow_info *csrow, char *data,
 				int private)
 {
-	struct mem_ctl_info *mci = csrow->mci;
-
-	return sprintf(data, "%u\n", mci->err.ce_csrow[csrow->csrow_idx]);
+	return sprintf(data, "%u\n", csrow->ce_count);
 }
 
 static ssize_t csrow_size_show(struct csrow_info *csrow, char *data,
@@ -209,10 +205,7 @@ static ssize_t channel_dimm_label_store(struct csrow_info *csrow,
 static ssize_t channel_ce_count_show(struct csrow_info *csrow,
 				char *data, int channel)
 {
-	struct mem_ctl_info *mci = csrow->mci;
-	int index = csrow->csrow_idx * mci->num_cschannel + channel;
-
-	return sprintf(data, "%u\n", mci->err.ce_cschannel[index]);
+	return sprintf(data, "%u\n", csrow->channels[channel].ce_count);
 }
 
 /* csrow specific attribute structure */
@@ -478,22 +471,15 @@ static const struct sysfs_ops dimmfs_ops = {
 /* show/store functions for DIMM Label attributes */
 static ssize_t dimmdev_location_show(struct dimm_info *dimm, char *data)
 {
+	struct mem_ctl_info *mci = dimm->mci;
+	int i;
 	char *p = data;
 
-	if (dimm->mc_branch >= 0)
-		p += sprintf(p, "branch %d ", dimm->mc_branch);
-
-	if (dimm->mc_channel >= 0)
-		p += sprintf(p, "channel %d ", dimm->mc_channel);
-
-	if (dimm->mc_dimm_number >= 0)
-		p += sprintf(p, "dimm %d ", dimm->mc_dimm_number);
-
-	if (dimm->csrow >= 0)
-		p += sprintf(p, "csrow %d ", dimm->csrow);
-
-	if (dimm->cschannel >= 0)
-		p += sprintf(p, "cs_channel %d ", dimm->cschannel);
+	for (i = 0; i <= mci->n_layers; i++) {
+		p += sprintf(p, "%s %d ",
+			     edac_layer_name[mci->layers[i].type],
+			     dimm->location[i]);
+	}
 
 	return p - data;
 }
@@ -621,27 +607,29 @@ err_out:
 static ssize_t mci_reset_counters_store(struct mem_ctl_info *mci,
 					const char *data, size_t count)
 {
-	int num;
-	mci->err.ue_mc = 0;
-	mci->err.ce_mc = 0;
+	int cnt, row, chan, i;
+	mci->ue_mc = 0;
+	mci->ce_mc = 0;
 	mci->ue_noinfo_count = 0;
 	mci->ce_noinfo_count = 0;
 
-	num = mci->num_branch;
-	memset(mci->err.ue_branch, 0, num);
-	memset(mci->err.ce_branch, 0, num);
-	num *= mci->num_channel;
-	memset(mci->err.ue_channel, 0, num);
-	memset(mci->err.ce_channel, 0, num);
-	num *= mci->num_dimm;
-	memset(mci->err.ue_dimm, 0, num);
-	memset(mci->err.ce_dimm, 0, num);
-	num *= mci->num_csrows;
-	memset(mci->err.ue_csrow, 0, num);
-	memset(mci->err.ce_csrow, 0, num);
-	num *= mci->num_cschannel;
-	memset(mci->err.ue_cschannel, 0, num);
-	memset(mci->err.ce_cschannel, 0, num);
+
+	for (row = 0; row < mci->num_csrows; row++) {
+		struct csrow_info *ri = &mci->csrows[row];
+
+		ri->ue_count = 0;
+		ri->ce_count = 0;
+
+		for (chan = 0; chan < ri->nr_channels; chan++)
+			ri->channels[chan].ce_count = 0;
+	}
+
+	cnt = 1;
+	for (i = 0; i < mci->n_layers; i++) {
+		cnt *= mci->layers[i].size;
+		memset(mci->ce_per_layer[i], 0, cnt);
+		memset(mci->ue_per_layer[i], 0, cnt);
+	}
 
 	mci->start_time = jiffies;
 	return count;
@@ -700,12 +688,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->err.ue_mc);
+	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->err.ce_mc);
+	return sprintf(data, "%d\n", mci->ce_mc);
 }
 
 static ssize_t mci_ce_noinfo_show(struct mem_ctl_info *mci, char *data)
@@ -1172,11 +1160,18 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
 		/* Only expose populated DIMMs */
 		if (dimm->nr_pages == 0)
 			continue;
-
-		debugf1("%s creating dimm%d, located at %d.%d.%d.%d.%d\n",
-			__func__, j, dimm->mc_branch, dimm->mc_channel,
-			dimm->mc_dimm_number, dimm->csrow, dimm->cschannel);
-
+#ifdef CONFIG_EDAC_DEBUG
+		debugf1("%s creating dimm%d, located at ",
+			__func__, j);
+		if (edac_debug_level >= 1) {
+			int lay;
+			for (lay = 0; lay < mci->n_layers; lay++)
+				printk(KERN_CONT "%s %d ",
+					edac_layer_name[mci->layers[lay].type],
+					dimm->location[lay]);
+			printk(KERN_CONT "\n");
+		}
+#endif
 		err = edac_create_dimm_object(mci, dimm, j);
 		if (err) {
 			debugf1("%s() failure: create dimm %d obj\n",
diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c
index 77c06af..c366002 100644
--- a/drivers/edac/i3000_edac.c
+++ b/drivers/edac/i3000_edac.c
@@ -245,10 +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_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC, mci, 0, 0, 0,
-				     -1, -1, -1, -1, -1,
-				     "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;
 	}
 
@@ -259,18 +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_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC_CSROW, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 				     pfn, offset, 0,
-				     -1, -1, -1, row, -1,
-				     "i3000 UE", "");
+				     row, -1, -1,
+				     "i3000 UE", "", NULL);
 	else
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED,
-				     HW_EVENT_SCOPE_MC_CSROW_CHANNEL, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 				     pfn, offset, info->derrsyn,
-				     -1, -1, -1, row,
-				     multi_chan ? channel : 0,
-				     "i3000 CE", "");
+				     row, multi_chan ? channel : 0, -1,
+				     "i3000 CE", "", NULL);
 
 	return 1;
 }
@@ -317,6 +313,7 @@ static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
 	int rc;
 	int i, j;
 	struct mem_ctl_info *mci = NULL;
+	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];
@@ -359,10 +356,13 @@ 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, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    -1, -1, I3000_RANKS,
-			    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_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = nr_channels;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, false, 0);
 	if (!mci)
 		return -ENOMEM;
 
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c
index 6f04a50..1233435 100644
--- a/drivers/edac/i3200_edac.c
+++ b/drivers/edac/i3200_edac.c
@@ -229,29 +229,25 @@ static void i3200_process_error_info(struct mem_ctl_info *mci,
 		return;
 
 	if ((info->errsts ^ info->errsts2) & I3200_ERRSTS_BITS) {
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC, mci, 0, 0, 0,
-				     -1, -1, -1, -1, -1,
-				     "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_error(HW_EVENT_ERR_UNCORRECTED,
-					     HW_EVENT_SCOPE_MC_CSROW, mci,
+			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 					     0, 0, 0,
-					     -1, -1, -1,
-					     eccerrlog_row(channel, log), -1,
-					     "i3000 UE", "");
+					     eccerrlog_row(channel, log),
+					     -1, -1,
+					     "i3000 UE", "", NULL);
 		} else if (log & I3200_ECCERRLOG_CE) {
-			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-					     HW_EVENT_SCOPE_MC_CSROW, mci,
+			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 					     0, 0, eccerrlog_syndrome(log),
-					     -1, -1, -1,
-					     eccerrlog_row(channel, log), -1,
-					     "i3000 UE", "");
+					     eccerrlog_row(channel, log),
+					     -1, -1,
+					     "i3000 UE", "", NULL);
 		}
 	}
 }
@@ -341,6 +337,7 @@ static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
 	int rc;
 	int i, j;
 	struct mem_ctl_info *mci = NULL;
+	struct edac_mc_layer layers[2];
 	u16 drbs[I3200_CHANNELS][I3200_RANKS_PER_CHANNEL];
 	bool stacked;
 	void __iomem *window;
@@ -355,10 +352,13 @@ 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(0, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    -1, -1, I3200_DIMMS,
-			    I3200_RANKS, nr_channels,
-			    0);
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = I3200_DIMMS;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = nr_channels;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, false, 0);
 	if (!mci)
 		return -ENOMEM;
 
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
index 5fec235..564fe09 100644
--- a/drivers/edac/i5000_edac.c
+++ b/drivers/edac/i5000_edac.c
@@ -537,11 +537,10 @@ static void i5000_process_fatal_error_info(struct mem_ctl_info *mci,
 		 bank, ras, cas, allErrors, specific);
 
 	/* Call the helper to output message */
-	edac_mc_handle_error(HW_EVENT_ERR_FATAL,
-			     HW_EVENT_SCOPE_MC_BRANCH, mci, 0, 0, 0,
-			     branch >> 1, -1, rank, -1, -1,
+	edac_mc_handle_error(HW_EVENT_ERR_FATAL, mci, 0, 0, 0,
+			     branch >> 1, -1, rank,
 			     rdwr ? "Write error" : "Read error",
-			     msg);
+			     msg, NULL);
 }
 
 /*
@@ -639,11 +638,10 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
 			 rank, bank, ras, cas, ue_errors, specific);
 
 		/* Call the helper to output message */
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-				HW_EVENT_SCOPE_MC_BRANCH, mci, 0, 0, 0,
-				channel >> 1, -1, rank, -1, -1,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci, 0, 0, 0,
+				channel >> 1, -1, rank,
 				rdwr ? "Write error" : "Read error",
-				msg);
+				msg, NULL);
 	}
 
 	/* Check correctable errors */
@@ -695,11 +693,10 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
 			 specific);
 
 		/* Call the helper to output message */
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED,
-				HW_EVENT_SCOPE_MC_CHANNEL, mci, 0, 0, 0,
-				channel >> 1, channel % 2, rank, -1, -1,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0,
+				channel >> 1, channel % 2, rank,
 				rdwr ? "Write error" : "Read error",
-				msg);
+				msg, NULL);
 	}
 
 	if (!misc_messages)
@@ -742,10 +739,9 @@ static void i5000_process_nonfatal_error_info(struct mem_ctl_info *mci,
 			 "Err=%#x (%s)", misc_errors, specific);
 
 		/* Call the helper to output message */
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED,
-				HW_EVENT_SCOPE_MC_BRANCH, mci, 0, 0, 0,
-				branch >> 1, -1, -1, -1, -1,
-				"Misc error", msg);
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0,
+				branch >> 1, -1, -1,
+				"Misc error", msg, NULL);
 	}
 }
 
@@ -1357,10 +1353,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__,
@@ -1386,15 +1382,21 @@ 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(0, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    2, num_channels, num_dimms_per_channel,
-			    num_csrows, num_channels, sizeof(*pvt));
+	layers[0].type = EDAC_MC_LAYER_BRANCH;
+	layers[0].size = 2;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = num_channels;
+	layers[1].is_csrow = false;
+	layers[2].type = EDAC_MC_LAYER_SLOT;
+	layers[2].size = num_dimms_per_channel;
+	layers[2].is_csrow = true;
+	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, false, sizeof(*pvt));
 
 	if (mci == NULL)
 		return -ENOMEM;
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c
index 24b03b8..d594170 100644
--- a/drivers/edac/i5100_edac.c
+++ b/drivers/edac/i5100_edac.c
@@ -426,11 +426,10 @@ static void i5100_handle_ce(struct mem_ctl_info *mci,
 		 "bank %u, cas %u, ras %u\n",
 		 bank, cas, ras);
 
-	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED,
-			     HW_EVENT_SCOPE_MC_DIMM, mci,
+	edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 			     0, 0, syndrome,
-			     0, chan, rank, -1, -1,
-			     msg, detail);
+			     chan, rank, -1,
+			     msg, detail, NULL);
 }
 
 static void i5100_handle_ue(struct mem_ctl_info *mci,
@@ -449,11 +448,10 @@ static void i5100_handle_ue(struct mem_ctl_info *mci,
 		 "bank %u, cas %u, ras %u\n",
 		 bank, cas, ras);
 
-	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-			     HW_EVENT_SCOPE_MC_DIMM, mci,
+	edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 			     0, 0, syndrome,
-			     0, chan, rank, -1, -1,
-			     msg, detail);
+			     chan, rank, -1,
+			     msg, detail, NULL);
 }
 
 static void i5100_read_log(struct mem_ctl_info *mci, int chan,
@@ -864,6 +862,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;
@@ -924,9 +923,14 @@ static int __devinit i5100_init_one(struct pci_dev *pdev,
 		goto bail_ch1;
 	}
 
-	mci = edac_mc_alloc(0, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    1, 2, ranksperch,
-			    ranksperch * 2, 1, sizeof(*priv));
+	layers[0].type = EDAC_MC_LAYER_CHANNEL;
+	layers[0].size = 2;
+	layers[0].is_csrow = false;
+	layers[1].type = EDAC_MC_LAYER_SLOT;
+	layers[1].size = ranksperch;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
+			    false, sizeof(*priv));
 	if (!mci) {
 		ret = -ENOMEM;
 		goto bail_disable_ch1;
diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c
index c7455da..681e97a 100644
--- a/drivers/edac/i5400_edac.c
+++ b/drivers/edac/i5400_edac.c
@@ -571,11 +571,10 @@ static void i5400_proccess_non_recoverable_info(struct mem_ctl_info *mci,
 		 "Bank=%d Buffer ID = %d RAS=%d CAS=%d Err=0x%lx (%s)",
 		 bank, buf_id, ras, cas, allErrors, error_name[errnum]);
 
-	edac_mc_handle_error(tp_event,
-			     HW_EVENT_SCOPE_MC_BRANCH, mci, 0, 0, 0,
-			     branch >> 1, -1, rank, -1, -1,
+	edac_mc_handle_error(tp_event, mci, 0, 0, 0,
+			     branch >> 1, -1, rank,
 			     rdwr ? "Write error" : "Read error",
-			     msg);
+			     msg, NULL);
 }
 
 /*
@@ -645,11 +644,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]);
 
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED,
-				     HW_EVENT_SCOPE_MC_BRANCH, mci, 0, 0, 0,
-				     branch >> 1, channel % 2, rank, -1, -1,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0,
+				     branch >> 1, channel % 2, rank,
 				     rdwr ? "Write error" : "Read error",
-				     msg);
+				     msg, NULL);
 
 		return;
 	}
@@ -1208,9 +1206,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;
@@ -1224,24 +1220,17 @@ 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.
-	 */
-	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(0, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    2, num_channels, num_dimms_per_channel,
-			    num_csrows, num_channels, sizeof(*pvt));
+	layers[0].type = EDAC_MC_LAYER_BRANCH;
+	layers[0].size = 2;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = MAX_CHANNELS;
+	layers[1].is_csrow = false;
+	layers[2].type = EDAC_MC_LAYER_SLOT;
+	layers[2].size = MAX_DIMMS_PER_CHANNEL;
+	layers[2].is_csrow = true;
+	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, false, sizeof(*pvt));
 
 	if (mci == NULL)
 		return -ENOMEM;
@@ -1252,8 +1241,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 = MAX_DIMMS_PER_CHANNEL;
 
 	/* 'get' the pci devices we want to reserve for our use */
 	if (i5400_get_devices(mci, dev_idx))
diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c
index 33f9ac2..7b9c848 100644
--- a/drivers/edac/i7300_edac.c
+++ b/drivers/edac/i7300_edac.c
@@ -467,11 +467,10 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
 			 "Bank=%d RAS=%d CAS=%d Err=0x%lx (%s))",
 			 bank, ras, cas, errors, specific);
 
-		edac_mc_handle_error(HW_EVENT_ERR_FATAL,
-				     HW_EVENT_SCOPE_MC_BRANCH, mci, 0, 0, 0,
-				     branch, -1, rank, -1, -1,
+		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);
+				     pvt->tmp_prt_buffer, NULL);
 
 	}
 
@@ -514,12 +513,11 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci)
 			 "DRAM-Bank=%d RAS=%d CAS=%d, Err=0x%lx (%s))",
 			 bank, ras, cas, errors, specific);
 
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED,
-				     HW_EVENT_SCOPE_MC_BRANCH, mci, 0, 0,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0,
 				     syndrome,
-				     branch >> 1, channel % 2, rank, -1, -1,
+				     branch >> 1, channel % 2, rank,
 				     is_wr ? "Write error" : "Read error",
-				     pvt->tmp_prt_buffer);
+				     pvt->tmp_prt_buffer, NULL);
 	}
 	return;
 }
@@ -1027,10 +1025,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 */
@@ -1047,25 +1043,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(0, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    MAX_BRANCHES, num_channels / MAX_BRANCHES,
-			    num_dimms_per_channel,
-			    num_csrows, num_channels, sizeof(*pvt));
+	layers[0].type = EDAC_MC_LAYER_BRANCH;
+	layers[0].size = MAX_BRANCHES;
+	layers[0].is_csrow = false;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = MAX_CHANNELS;
+	layers[1].is_csrow = true;
+	layers[2].type = EDAC_MC_LAYER_SLOT;
+	layers[2].size = MAX_SLOTS;
+	layers[2].is_csrow = true;
+	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, false, sizeof(*pvt));
 
 	if (mci == NULL)
 		return -ENOMEM;
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index f63c0f4..ce75892 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
@@ -257,7 +257,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,113 +491,12 @@ 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(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, cschannel = 0;
 	enum edac_type mode;
 	enum mem_type mtype;
 
@@ -712,16 +610,6 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 
 			npages = MiB_TO_PAGES(size);
 
-			pvt->csrow_map[i][j] = csrow;
-
-			csr = &mci->csrows[csrow];
-			csr->channels[cschannel].dimm = dimm;
-			cschannel++;
-			if (cschannel >= MAX_DIMMS) {
-				cschannel = 0;
-				csrow++;
-			}
-
 			dimm->nr_pages = npages;
 
 			switch (banks) {
@@ -744,7 +632,6 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 			dimm->grain = 8;
 			dimm->edac_mode = mode;
 			dimm->mtype = mtype;
-			csrow++;
 		}
 
 		pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]);
@@ -763,17 +650,6 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 				(value[j] & ((1 << 24) - 1)));
 	}
 
-	/* Clears the unused data */
-	while (csrow < NUM_CHANS && cschannel < MAX_DIMMS) {
-		csr = &mci->csrows[csrow];
-		csr->channels[cschannel].dimm = NULL;
-		cschannel++;
-		if (cschannel >= MAX_DIMMS) {
-			cschannel = 0;
-			csrow++;
-		}
-	}
-
 	return 0;
 }
 
@@ -1571,7 +1447,7 @@ error:
 /****************************************************************************
 			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)
@@ -1579,11 +1455,8 @@ static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci,
 	int i;
 
 	for (i = 0; i < add; i++) {
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED,
-				     HW_EVENT_SCOPE_MC_DIMM, mci,
-				     0, 0, 0,
-				     0, chan, dimm, -1, -1,
-				     "error", "");
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci, 0, 0, 0,
+				     chan, dimm, -1, "error", "", NULL);
 	}
 }
 
@@ -1624,11 +1497,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);
 
 }
 
@@ -1759,7 +1632,6 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
 	u32 channel = (m->misc >> 18) & 0x3;
 	u32 syndrome = m->misc >> 32;
 	u32 errnum = find_first_bit(&error, 32);
-	int csrow;
 
 	if (uncorrected_error) {
 		if (ripv) {
@@ -1832,21 +1704,18 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci,
 		(long long) m->addr, m->cpu, core_err_cnt,
 		(long long)m->status, (long long)m->misc, optype, err);
 
-	csrow = pvt->csrow_map[channel][dimm];
-
 	/*
 	 * 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,
-				     HW_EVENT_SCOPE_MC_DIMM, mci,
+		edac_mc_handle_error(tp_event, mci,
 				     m->addr >> PAGE_SHIFT,
 				     m->addr & ~PAGE_MASK,
 				     syndrome,
-				     0, channel, dimm, -1, -1,
-				     err, msg);
+				     channel, dimm, -1,
+				     err, msg, m);
 
 	kfree(msg);
 }
@@ -2265,18 +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(EDAC_ALLOC_FILL_PRIV, i7core_dev->socket,
-			    1, NUM_CHANS, MAX_DIMMS,
-			    MAX_DIMMS, NUM_CHANS, sizeof(*pvt));
+	layers[0].type = EDAC_MC_LAYER_CHANNEL;
+	layers[0].size = NUM_CHANS;
+	layers[0].is_csrow = false;
+	layers[1].type = EDAC_MC_LAYER_SLOT;
+	layers[1].size = MAX_DIMMS;
+	layers[1].is_csrow = true;
+	mci = edac_mc_alloc(i7core_dev->socket, ARRAY_SIZE(layers), layers,
+			    false, sizeof(*pvt));
 	if (unlikely(!mci))
 		return -ENOMEM;
 
diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c
index 0992549..09d39c0 100644
--- a/drivers/edac/i82443bxgx_edac.c
+++ b/drivers/edac/i82443bxgx_edac.c
@@ -156,23 +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_error(HW_EVENT_ERR_CORRECTED,
-					     HW_EVENT_SCOPE_MC_CSROW_CHANNEL,
-					     mci, page, pageoffset, 0,
-					     -1, -1, -1,
+			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+					     page, pageoffset, 0,
 					     edac_mc_find_csrow_by_page(mci, page),
-					     0, mci->ctl_name, 0);
+					     0, -1, mci->ctl_name, "", NULL);
 	}
 
 	if (info->eap & I82443BXGX_EAP_OFFSET_MBE) {
 		error_found = 1;
 		if (handle_errors)
-			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-					     HW_EVENT_SCOPE_MC_CSROW_CHANNEL,
-					     mci, page, pageoffset, 0,
-					     -1, -1, -1,
+			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+					     page, pageoffset, 0,
 					     edac_mc_find_csrow_by_page(mci, page),
-					     0, mci->ctl_name, 0);
+					     0, -1, mci->ctl_name, "", NULL);
 	}
 
 	return error_found;
@@ -239,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;
@@ -252,10 +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, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    0, 0, I82443BXGX_NR_CSROWS,
-			    I82443BXGX_NR_CSROWS, I82443BXGX_NR_CHANS, 0);
-
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = I82443BXGX_NR_CSROWS;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = I82443BXGX_NR_CHANS;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, false, 0);
 	if (mci == NULL)
 		return -ENOMEM;
 
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c
index 3ab8a7a..85ed3a6 100644
--- a/drivers/edac/i82860_edac.c
+++ b/drivers/edac/i82860_edac.c
@@ -109,10 +109,8 @@ static int i82860_process_error_info(struct mem_ctl_info *mci,
 		return 1;
 
 	if ((info->errsts ^ info->errsts2) & 0x0003) {
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC, mci, 0, 0, 0,
-				     -1, -1, -1, -1, -1,
-				     "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;
 	}
 
@@ -121,19 +119,15 @@ static int i82860_process_error_info(struct mem_ctl_info *mci,
 	dimm = mci->csrows[row].channels[0].dimm;
 
 	if (info->errsts & 0x0002)
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC_DIMM, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 				     info->eap, 0, 0,
-				     dimm->mc_branch, dimm->mc_channel,
-				     dimm->mc_dimm_number, -1, -1,
-				     "i82860 UE", "");
+				     dimm->location[0], dimm->location[1], -1,
+				     "i82860 UE", "", NULL);
 	else
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC_DIMM, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 				     info->eap, 0, info->derrsyn,
-				     dimm->mc_branch, dimm->mc_channel,
-				     dimm->mc_dimm_number, -1, -1,
-				     "i82860 CE", "");
+				     dimm->location[0], dimm->location[1], -1,
+				     "i82860 CE", "", NULL);
 
 	return 1;
 }
@@ -193,6 +187,7 @@ static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
 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;
 
 	/*
@@ -205,12 +200,13 @@ static int i82860_probe1(struct pci_dev *pdev, int dev_idx)
 	 * 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, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    1, 2 /* channels */, 8 /* sticks per channel */,
-			    16, 1,
-			    0);
-
+	layers[0].type = EDAC_MC_LAYER_CHANNEL;
+	layers[0].size = 2;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_SLOT;
+	layers[1].size = 8;
+	layers[1].is_csrow = true;
+	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, false, 0);
 	if (!mci)
 		return -ENOMEM;
 
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index 74afaba..471b26a 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
@@ -236,10 +236,9 @@ static int i82875p_process_error_info(struct mem_ctl_info *mci,
 		return 1;
 
 	if ((info->errsts ^ info->errsts2) & 0x0081) {
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC, mci, 0, 0, 0,
-				     -1, -1, -1, -1, -1,
-				     "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;
 	}
 
@@ -247,18 +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_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC_CSROW, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 				     info->eap, 0, 0,
-				     -1, -1, -1, row, -1,
-				     "i82875p UE", "");
+				     row, -1, -1,
+				     "i82875p UE", "", NULL);
 	else
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED,
-				     HW_EVENT_SCOPE_MC_CSROW_CHANNEL, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 				     info->eap, 0, info->derrsyn,
-				     -1, -1, -1, row,
-				     multi_chan ? (info->des & 0x1) : 0,
-				     "i82875p CE", "");
+				     row, multi_chan ? (info->des & 0x1) : 0,
+				     -1, "i82875p CE", "", NULL);
 
 	return 1;
 }
@@ -401,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;
@@ -416,10 +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(0, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    -1, -1, I82875P_NR_DIMMS,
-			    I82875P_NR_CSROWS(nr_chans), nr_chans,
-			    sizeof(*pvt));
+
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = I82875P_NR_CSROWS(nr_chans);
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = nr_chans;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, false, sizeof(*pvt));
 	if (!mci) {
 		rc = -ENOMEM;
 		goto fail0;
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
index 33feeba..c0a683a 100644
--- a/drivers/edac/i82975x_edac.c
+++ b/drivers/edac/i82975x_edac.c
@@ -290,10 +290,8 @@ static int i82975x_process_error_info(struct mem_ctl_info *mci,
 		return 1;
 
 	if ((info->errsts ^ info->errsts2) & 0x0003) {
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC, mci, 0, 0, 0,
-				     -1, -1, -1, -1, -1,
-				     "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;
 	}
 
@@ -307,18 +305,15 @@ static int i82975x_process_error_info(struct mem_ctl_info *mci,
 	row = edac_mc_find_csrow_by_page(mci, page);
 
 	if (info->errsts & 0x0002)
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC_CSROW, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 				     page, offst, 0,
-				     -1, -1, -1, row, -1,
-				     "i82975x UE", "");
+				     row, -1, -1,
+				     "i82975x UE", "", NULL);
 	else
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED,
-				     HW_EVENT_SCOPE_MC_CSROW_CHANNEL, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 				     page, offst, info->derrsyn,
-				     -1, -1, -1, row,
-				     multi_chan ? chan : 0,
-				     "i82975x CE", "");
+				     row, multi_chan ? chan : 0, -1,
+				     "i82975x CE", "", NULL);
 
 	return 1;
 }
@@ -476,6 +471,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;
@@ -544,10 +540,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(0, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    -1, -1, I82975X_NR_DIMMS,
-			    I82975X_NR_CSROWS(chans), chans,
-			    sizeof(*pvt));
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = I82975X_NR_DIMMS;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = I82975X_NR_CSROWS(chans);
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, false, sizeof(*pvt));
 	if (!mci) {
 		rc = -ENOMEM;
 		goto fail1;
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index f7c3a67..d074b71 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -854,18 +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_error(HW_EVENT_ERR_CORRECTED,
-				     HW_EVENT_SCOPE_MC_CSROW_CHANNEL, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 				     pfn, err_addr & ~PAGE_MASK, syndrome,
-				     -1, -1, -1, row_index, 0,
-				     mci->ctl_name, "");
+				     row_index, 0, -1,
+				     mci->ctl_name, "", NULL);
 
 	if (err_detect & DDR_EDE_MBE)
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC_CSROW_CHANNEL, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 				     pfn, err_addr & ~PAGE_MASK, syndrome,
-				     -1, -1, -1, row_index, 0,
-				     mci->ctl_name, "");
+				     row_index, 0, -1,
+				     mci->ctl_name, "", NULL);
 
 	out_be32(pdata->mc_vbase + MPC85XX_MC_ERR_DETECT, err_detect);
 }
@@ -967,6 +965,7 @@ static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
 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;
@@ -975,8 +974,14 @@ 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(edac_mc_idx, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    0, 0, 4, 4, 1, sizeof(*pdata));
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = 4;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = 1;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers, false,
+			    sizeof(*pdata));
 	if (!mci) {
 		devres_release_group(&op->dev, mpc85xx_mc_err_probe);
 		return -ENOMEM;
@@ -1165,7 +1170,6 @@ static void __init mpc85xx_mc_clear_rfxe(void *data)
 static int __init mpc85xx_mc_init(void)
 {
 	int res = 0;
-	u32 pvr = 0;
 
 	printk(KERN_INFO "Freescale(R) MPC85xx EDAC driver, "
 	       "(C) 2006 Montavista Software\n");
diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c
index 96a675a..a32e9b6 100644
--- a/drivers/edac/mv64x60_edac.c
+++ b/drivers/edac/mv64x60_edac.c
@@ -611,19 +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_error(HW_EVENT_ERR_CORRECTED,
-				     HW_EVENT_SCOPE_MC_CSROW_CHANNEL, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 				     err_addr >> PAGE_SHIFT,
 				     err_addr & PAGE_MASK, syndrome,
-				     -1, -1, -1, 0, 0,
-				     mci->ctl_name, "");
+				     0, 0, -1,
+				     mci->ctl_name, "", NULL);
 	else	/* 2 bit error, UE */
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC_CSROW_CHANNEL, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 				     err_addr >> PAGE_SHIFT,
 				     err_addr & PAGE_MASK, 0,
-				     -1, -1, -1, 0, 0,
-				     mci->ctl_name, "");
+				     0, 0, -1,
+				     mci->ctl_name, "", NULL);
 
 	/* clear the error */
 	out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ADDR, 0);
@@ -702,6 +700,7 @@ static void mv64x60_init_csrows(struct mem_ctl_info *mci,
 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;
@@ -710,9 +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(edac_mc_idx, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    0, 0, 1,
-			    1, 1, sizeof(struct mv64x60_mc_pdata));
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = 1;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = 1;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(edac_mc_idx, ARRAY_SIZE(layers), layers, false,
+			    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);
diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c
index 0d0a545..2959db6 100644
--- a/drivers/edac/pasemi_edac.c
+++ b/drivers/edac/pasemi_edac.c
@@ -110,20 +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_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC_CSROW_CHANNEL, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 				     mci->csrows[cs].first_page, 0, 0,
-				     -1, -1, -1, cs, 0,
-				     mci->ctl_name, "");
+				     cs, 0, -1, mci->ctl_name, "", NULL);
 	}
 
 	/* correctable/single-bit errors */
 	if (errsta & MCDEBUG_ERRSTA_SBE_STATUS)
-		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED,
-				     HW_EVENT_SCOPE_MC_CSROW_CHANNEL, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 				     mci->csrows[cs].first_page, 0, 0,
-				     -1, -1, -1, cs, 0,
-				     mci->ctl_name, "");
+				     cs, 0, -1, mci->ctl_name, "", NULL);
 }
 
 static void pasemi_edac_check(struct mem_ctl_info *mci)
@@ -196,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);
@@ -212,10 +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(system_mmc_id++, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    0, 0, PASEMI_EDAC_NR_CSROWS,
-			    PASEMI_EDAC_NR_CSROWS, PASEMI_EDAC_NR_CHANS, 0);
-
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = PASEMI_EDAC_NR_CSROWS;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = PASEMI_EDAC_NR_CHANS;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(system_mmc_id++, ARRAY_SIZE(layers), layers, false,
+			    0);
 	if (mci == NULL)
 		return -ENOMEM;
 
diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c
index 2e393cb..89ffc39 100644
--- a/drivers/edac/ppc4xx_edac.c
+++ b/drivers/edac/ppc4xx_edac.c
@@ -214,7 +214,7 @@ static struct platform_driver ppc4xx_edac_driver = {
  * TODO: The row and channel parameters likely need to be dynamically
  * set based on the aforementioned variant controller realizations.
  */
-static const unsigned ppc4xx_edac_num_csrows = 2;
+static const unsigned ppc4xx_edac_nr_csrows = 2;
 static const unsigned ppc4xx_edac_nr_chans = 1;
 
 /*
@@ -727,10 +727,10 @@ ppc4xx_edac_handle_ce(struct mem_ctl_info *mci,
 
 	for (row = 0; row < mci->num_csrows; row++)
 		if (ppc4xx_edac_check_bank_error(status, row))
-			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED,
-					     HW_EVENT_SCOPE_MC, mci, 0, 0, 0,
-					     -1, -1, -1, -1, -1,
-					     message, "");
+			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+					     0, 0, 0,
+					     row, 0, -1,
+					     message, "", NULL);
 }
 
 /**
@@ -758,11 +758,10 @@ ppc4xx_edac_handle_ue(struct mem_ctl_info *mci,
 
 	for (row = 0; row < mci->num_csrows; row++)
 		if (ppc4xx_edac_check_bank_error(status, row))
-			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-					     HW_EVENT_SCOPE_MC, mci,
+			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 					     page, offset, 0,
-					     -1, -1, -1, -1, -1,
-					     message, "");
+					     row, 0, -1,
+					     message, "", NULL);
 }
 
 /**
@@ -1240,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;
 
 	/*
@@ -1285,14 +1285,14 @@ static int __devinit ppc4xx_edac_probe(struct platform_device *op)
 	 * controller instance and perform the appropriate
 	 * initialization.
 	 */
-
-	mci = edac_mc_alloc(ppc4xx_edac_instance,
-			    EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    0, 0, ppc4xx_edac_num_csrows * ppc4xx_edac_nr_chans,
-			    ppc4xx_edac_num_csrows,
-			    ppc4xx_edac_nr_chans,
-			    sizeof(struct ppc4xx_edac_pdata));
-
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = ppc4xx_edac_nr_csrows;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = ppc4xx_edac_nr_chans;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(ppc4xx_edac_instance, ARRAY_SIZE(layers), layers,
+			    false, sizeof(struct ppc4xx_edac_pdata));
 	if (mci == NULL) {
 		ppc4xx_edac_printk(KERN_ERR, "%s: "
 				   "Failed to allocate EDAC MC instance!\n",
diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c
index 214bc48..f820c14 100644
--- a/drivers/edac/r82600_edac.c
+++ b/drivers/edac/r82600_edac.c
@@ -179,13 +179,11 @@ static int r82600_process_error_info(struct mem_ctl_info *mci,
 		error_found = 1;
 
 		if (handle_errors)
-			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED,
-					     HW_EVENT_SCOPE_MC_CSROW_CHANNEL,
-					     mci, page, 0, syndrome,
-					     -1, -1, -1,
+			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+					     page, 0, syndrome,
 					     edac_mc_find_csrow_by_page(mci, page),
-					     0,
-					     mci->ctl_name, "");
+					     0, -1,
+					     mci->ctl_name, "", NULL);
 	}
 
 	if (info->eapr & BIT(1)) {	/* UE? */
@@ -193,13 +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_error(HW_EVENT_ERR_UNCORRECTED,
-					     HW_EVENT_SCOPE_MC_CSROW_CHANNEL,
-					     mci, page, 0, 0,
-					     -1, -1, -1,
+			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+					     page, 0, 0,
 					     edac_mc_find_csrow_by_page(mci, page),
-					     0,
-					     mci->ctl_name, "");
+					     0, -1,
+					     mci->ctl_name, "", NULL);
 	}
 
 	return error_found;
@@ -274,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;
@@ -288,11 +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, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    -1, -1, R82600_NR_DIMMS,
-			    R82600_NR_CSROWS, R82600_NR_CHANS,
-			    0);
-
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = R82600_NR_CSROWS;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = R82600_NR_CHANS;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, false, 0);
 	if (mci == NULL)
 		return -ENOMEM;
 
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 5df6ade..4745c94 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -313,8 +313,6 @@ struct sbridge_pvt {
 	struct sbridge_info	info;
 	struct sbridge_channel	channel[NUM_CHANNELS];
 
-	int 			csrow_map[NUM_CHANNELS][MAX_DIMMS];
-
 	/* Memory type detection */
 	bool			is_mirrored, is_lockstep, is_close_pg;
 
@@ -486,29 +484,14 @@ static struct pci_dev *get_pdev_slot_func(u8 bus, unsigned slot,
 }
 
 /**
- * sbridge_get_active_channels() - gets the number of channels and csrows
+ * check_if_ecc_is_active() - Checks if ECC is active
  * bus:		Device bus
- * @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, identified
- * by the associated PCI bus.
- * this is used in order to properly allocate the size of mci components.
- * Note: one csrow is one dimm.
  */
-static int sbridge_get_active_channels(const u8 bus, unsigned *channels,
-				      unsigned *csrows)
+static int check_if_ecc_is_active(const u8 bus)
 {
 	struct pci_dev *pdev = NULL;
-	int i, j;
 	u32 mcmtr;
 
-	*channels = 0;
-	*csrows = 0;
-
 	pdev = get_pdev_slot_func(bus, 15, 0);
 	if (!pdev) {
 		sbridge_printk(KERN_ERR, "Couldn't find PCI device "
@@ -522,41 +505,13 @@ static int sbridge_get_active_channels(const u8 bus, unsigned *channels,
 		sbridge_printk(KERN_ERR, "ECC is disabled. Aborting\n");
 		return -ENODEV;
 	}
-
-	for (i = 0; i < NUM_CHANNELS; i++) {
-		u32 mtr;
-
-		/* Device 15 functions 2 - 5  */
-		pdev = get_pdev_slot_func(bus, 15, 2 + i);
-		if (!pdev) {
-			sbridge_printk(KERN_ERR, "Couldn't find PCI device "
-						 "%2x.%02d.%d!!!\n",
-						 bus, 15, 2 + i);
-			return -ENODEV;
-		}
-		(*channels)++;
-
-		for (j = 0; j < ARRAY_SIZE(mtr_regs); j++) {
-			pci_read_config_dword(pdev, mtr_regs[j], &mtr);
-			debugf1("Bus#%02x channel #%d  MTR%d = %x\n", bus, i, j, mtr);
-			if (IS_DIMM_PRESENT(mtr))
-				(*csrows)++;
-		}
-	}
-
-	debugf0("Number of active channels: %d, number of active dimms: %d\n",
-		*channels, *csrows);
-
 	return 0;
 }
 
 static int get_dimm_config(struct mem_ctl_info *mci)
 {
 	struct sbridge_pvt *pvt = mci->pvt_info;
-	struct csrow_info *csr;
 	int i, j, banks, ranks, rows, cols, size, npages;
-	int csrow = 0;
-	unsigned long last_page = 0;
 	u32 reg;
 	enum edac_type mode;
 	enum mem_type mtype;
@@ -635,16 +590,6 @@ static int get_dimm_config(struct mem_ctl_info *mci)
 					size, npages,
 					banks, ranks, rows, cols);
 
-				/*
-				 * Fake stuff. This controller doesn't see
-				 * csrows.
-				 */
-				csr = &mci->csrows[csrow];
-				pvt->csrow_map[i][j] = csrow;
-				last_page += npages;
-				csrow++;
-
-				csr->channels[0].dimm = dimm;
 				dimm->nr_pages = npages;
 				dimm->grain = 32;
 				dimm->dtype = (banks == 8) ? DEV_X8 : DEV_X4;
@@ -1397,7 +1342,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
 	u32 optypenum = GET_BITFIELD(m->status, 4, 6);
 	long channel_mask, first_channel;
 	u8  rank, socket;
-	int csrow, rc, dimm;
+	int rc, dimm;
 	char *area_type = "Unknown";
 
 	if (uncorrected_error) {
@@ -1470,8 +1415,6 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
 	else
 		dimm = 2;
 
-	csrow = pvt->csrow_map[first_channel][dimm];
-
 	if (uncorrected_error && recoverable)
 		recoverable_msg = " recoverable";
 	else
@@ -1501,17 +1444,15 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci,
 	/* FIXME: need support for channel mask */
 
 	/* Call the helper to output message */
-	edac_mc_handle_error(tp_event,
-			     HW_EVENT_SCOPE_MC_DIMM, mci,
+	edac_mc_handle_error(tp_event, mci,
 			     m->addr >> PAGE_SHIFT, m->addr & ~PAGE_MASK, 0,
-			     0, channel, dimm, -1, -1,
-			     optype, msg);
+			     channel, dimm, -1,
+			     optype, msg, m);
 	return;
 err_parsing:
-	edac_mc_handle_error(tp_event,
-			     HW_EVENT_SCOPE_MC, mci, 0, 0, 0,
-			     -1, -1, -1, -1, -1,
-			     msg, "");
+	edac_mc_handle_error(tp_event, mci, 0, 0, 0,
+			     -1, -1, -1,
+			     msg, "", m);
 
 }
 
@@ -1674,18 +1615,25 @@ static void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev)
 static int sbridge_register_mci(struct sbridge_dev *sbridge_dev)
 {
 	struct mem_ctl_info *mci;
+	struct edac_mc_layer layers[2];
 	struct sbridge_pvt *pvt;
-	int rc, channels, dimms;
+	int rc;
 
 	/* Check the number of active and not disabled channels */
-	rc = sbridge_get_active_channels(sbridge_dev->bus, &channels, &dimms);
+	rc = check_if_ecc_is_active(sbridge_dev->bus);
 	if (unlikely(rc < 0))
 		return rc;
 
 	/* allocate a new MC control structure */
-	mci = edac_mc_alloc(0, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    1, channels, dimms,
-			    dimms, channels, sizeof(*pvt));
+	layers[0].type = EDAC_MC_LAYER_CHANNEL;
+	layers[0].size = NUM_CHANNELS;
+	layers[0].is_csrow = false;
+	layers[1].type = EDAC_MC_LAYER_SLOT;
+	layers[1].size = MAX_DIMMS;
+	layers[1].is_csrow = true;
+	mci = edac_mc_alloc(sbridge_dev->mc, ARRAY_SIZE(layers), layers,
+			    false, sizeof(*pvt));
+
 	if (unlikely(!mci))
 		return -ENOMEM;
 
diff --git a/drivers/edac/tile_edac.c b/drivers/edac/tile_edac.c
index 19ac19e..9a91826 100644
--- a/drivers/edac/tile_edac.c
+++ b/drivers/edac/tile_edac.c
@@ -71,11 +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_error(HW_EVENT_ERR_CORRECTED,
-				     HW_EVENT_SCOPE_MC_CSROW_CHANNEL, mci,
+		edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 				     0, 0, 0,
-				     -1, -1, -1, 0, 0,
-				     mci->ctl_name, "");
+				     0, 0, -1,
+				     mci->ctl_name, "", NULL);
 	}
 }
 
@@ -126,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;
 
@@ -135,9 +135,13 @@ 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(pdev->id, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    0, 0, TILE_EDAC_NR_CSROWS,
-			    TILE_EDAC_NR_CSROWS, TILE_EDAC_NR_CHANS,
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = TILE_EDAC_NR_CSROWS;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = TILE_EDAC_NR_CHANS;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, false,
 			    sizeof(struct tile_edac_priv));
 	if (mci == NULL)
 		return -ENOMEM;
diff --git a/drivers/edac/x38_edac.c b/drivers/edac/x38_edac.c
index 27cf304..5f3c57f 100644
--- a/drivers/edac/x38_edac.c
+++ b/drivers/edac/x38_edac.c
@@ -215,29 +215,26 @@ static void x38_process_error_info(struct mem_ctl_info *mci,
 		return;
 
 	if ((info->errsts ^ info->errsts2) & X38_ERRSTS_BITS) {
-		edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-				     HW_EVENT_SCOPE_MC, mci, 0, 0, 0,
-				     -1, -1, -1, -1, -1,
-				     "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 < x38_channel_num; channel++) {
 		log = info->eccerrlog[channel];
 		if (log & X38_ECCERRLOG_UE) {
-			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED,
-					     HW_EVENT_SCOPE_MC_CSROW, mci,
+			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
 					     0, 0, 0,
-					     -1, -1, -1,
-					     eccerrlog_row(channel, log), -1,
-					     "x38 UE", "");
+					     eccerrlog_row(channel, log),
+					     -1, -1,
+					     "x38 UE", "", NULL);
 		} else if (log & X38_ECCERRLOG_CE) {
-			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED,
-					     HW_EVENT_SCOPE_MC_CSROW, mci,
+			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
 					     0, 0, eccerrlog_syndrome(log),
-					     -1, -1, -1,
-					     eccerrlog_row(channel, log), -1,
-					     "x38 CE", "");
+					     eccerrlog_row(channel, log),
+					     -1, -1,
+					     "x38 CE", "", NULL);
 		}
 	}
 }
@@ -329,6 +326,7 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx)
 	int rc;
 	int i, j;
 	struct mem_ctl_info *mci = NULL;
+	struct edac_mc_layer layers[2];
 	u16 drbs[X38_CHANNELS][X38_RANKS_PER_CHANNEL];
 	bool stacked;
 	void __iomem *window;
@@ -344,10 +342,13 @@ static int x38_probe1(struct pci_dev *pdev, int dev_idx)
 	how_many_channel(pdev);
 
 	/* FIXME: unconventional pvt_info usage */
-	mci = edac_mc_alloc(0, EDAC_ALLOC_FILL_CSROW_CSCHANNEL,
-			    -1, -1, X38_RANKS,
-			    X38_RANKS, x38_channel_num,
-			    0);
+	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+	layers[0].size = X38_RANKS;
+	layers[0].is_csrow = true;
+	layers[1].type = EDAC_MC_LAYER_CHANNEL;
+	layers[1].size = x38_channel_num;
+	layers[1].is_csrow = false;
+	mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers, false, 0);
 	if (!mci)
 		return -ENOMEM;
 
diff --git a/include/linux/edac.h b/include/linux/edac.h
index 1d707f4..4d84e40 100644
--- a/include/linux/edac.h
+++ b/include/linux/edac.h
@@ -206,41 +206,6 @@ enum hw_event_mc_err_type {
 };
 
 /**
- * enum hw_event_error_scope - escope of a memory error
- *
- * @HW_EVENT_ERR_MC:		error can be anywhere inside the MC
- * @HW_EVENT_SCOPE_MC_BRANCH:	error can be on any DIMM inside the branch
- * @HW_EVENT_SCOPE_MC_CHANNEL:	error can be on any DIMM inside the MC channel
- * @HW_EVENT_SCOPE_MC_DIMM:	error is on a specific DIMM
- * @HW_EVENT_SCOPE_MC_CSROW:	error can be on any DIMM inside the csrow
- * @HW_EVENT_SCOPE_MC_CSROW_CHANNEL: error is on a CSROW channel
- *
- * Depending on the error detection algorithm, the memory topology and even
- * the MC capabilities, some errors can't be attributed to just one DIMM, but
- * to a group of memory sockets. Depending on where the error occurs, the
- * EDAC core will increment the corresponding error count for that entity,
- * and the upper entities. For example, assuming a system with 1 memory
- * controller 2 branches, 2 MC channels and 4 DIMMS on it, if an error
- * happens at channel 0, the error counts for channel 0, for branch 0 and
- * for the memory controller 0 will be incremented. The DIMM error counts won't
- * be incremented, as, in this example, the driver can't be 100% sure on what
- * memory the error actually occurred.
- *
- * The order here is important, as edac_mc_handle_error() will use it, in order
- * to check what parameters will be used. The smallest number should be
- * the hole memory controller, and the last one should be the more
- * fine-grained detail, e. g.: DIMM.
- */
-enum hw_event_error_scope {
-	HW_EVENT_SCOPE_MC,
-	HW_EVENT_SCOPE_MC_BRANCH,
-	HW_EVENT_SCOPE_MC_CHANNEL,
-	HW_EVENT_SCOPE_MC_DIMM,
-	HW_EVENT_SCOPE_MC_CSROW,
-	HW_EVENT_SCOPE_MC_CSROW_CHANNEL,
-};
-
-/**
  * enum mem_type - Type of the memory stick
  *
  * @MEM_EMPTY		Empty csrow
@@ -423,16 +388,51 @@ enum scrub_type {
 #define OP_RUNNING_POLL_INTR	0x203
 #define OP_OFFLINE		0x300
 
+/**
+ * enum edac_mc_layer - memory controller hierarchy layer
+ *
+ * @EDAC_MC_LAYER_BRANCH:	memory layer is named "branch"
+ * @EDAC_MC_LAYER_CHANNEL:	memory layer is named "channel"
+ * @EDAC_MC_LAYER_SLOT:		memory layer is named "slot"
+ * @EDAC_MC_LAYER_CHIP_SELECT:	memory layer is named "chip select"
+ *
+ * This enum is used by the drivers to tell edac_mc_sysfs what name should
+ * be used when describing a memory stick location.
+ */
+enum edac_mc_layer_type {
+	EDAC_MC_LAYER_BRANCH,
+	EDAC_MC_LAYER_CHANNEL,
+	EDAC_MC_LAYER_SLOT,
+	EDAC_MC_LAYER_CHIP_SELECT,
+};
+
+/**
+ * struct edac_mc_layer - describes the memory controller hierarchy
+ * @layer:		layer type
+ * @size:maximum size of the layer
+ * @is_csrow:		This layer is part of the "csrow" when old API
+ *			compatibility mode is enabled. Otherwise, it is
+ *			a channel
+ */
+struct edac_mc_layer {
+	enum edac_mc_layer_type	type;
+	unsigned 		size;
+	bool			is_csrow;
+};
+
+/*
+ * Maximum number of layers used by the memory controller to uniquelly
+ * identify a single memory stick.
+ * NOTE: change it also requires changing edac_mc_handle_error()
+ */
+#define EDAC_MAX_LAYERS		3
+
 /* FIXME: add the proper per-location error counts */
 struct dimm_info {
 	char label[EDAC_MC_LABEL_LEN + 1];	/* DIMM label on motherboard */
 
 	/* Memory location data */
-	int mc_branch;
-	int mc_channel;
-	int mc_dimm_number;
-	int csrow;
-	int cschannel;
+	unsigned location[EDAC_MAX_LAYERS];
 
 	struct kobject kobj;		/* sysfs kobject for this csrow */
 	struct mem_ctl_info *mci;	/* the parent */
@@ -442,13 +442,17 @@ struct dimm_info {
 	enum mem_type mtype;	/* memory dimm type */
 	enum edac_type edac_mode;	/* EDAC mode for this dimm */
 
-	u32 nr_pages;			/* number of pages in csrow */
+	u32 nr_pages;			/* number of pages on this dimm */
+
+	unsigned csrow, cschannel;	/* Points to the old API data */
 };
 
 struct csrow_channel_info {
 	int chan_idx;		/* channel index */
 	struct dimm_info *dimm;
 	struct csrow_info *csrow;	/* the parent */
+
+	u32 ce_count;		/* Correctable Errors for this csrow */
 };
 
 struct csrow_info {
@@ -460,6 +464,9 @@ struct csrow_info {
 	unsigned long page_mask;	/* used for interleaving -
 					 * 0UL for non intlv */
 
+	u32 ue_count;		/* Uncorrectable Errors for this csrow */
+	u32 ce_count;		/* Correctable Errors for this csrow */
+
 	struct mem_ctl_info *mci;	/* the parent */
 
 	struct kobject kobj;	/* sysfs kobject for this csrow */
@@ -497,22 +504,9 @@ struct mcidev_sysfs_attribute {
         ssize_t (*store)(struct mem_ctl_info *, const char *,size_t);
 };
 
-/*
- * Error counters for all possible memory arrangements
- */
-struct error_counts {
-	u32 ce_mc;
-	u32 *ce_branch;
-	u32 *ce_channel;
-	u32 *ce_dimm;
-	u32 *ce_csrow;
-	u32 *ce_cschannel;
-	u32 ue_mc;
-	u32 *ue_branch;
-	u32 *ue_channel;
-	u32 *ue_dimm;
-	u32 *ue_csrow;
-	u32 *ue_cschannel;
+struct edac_hierarchy {
+	char		*name;
+	unsigned	nr;
 };
 
 /* MEMORY controller information structure
@@ -560,14 +554,11 @@ struct mem_ctl_info {
 					   unsigned long page);
 	int mc_idx;
 	struct csrow_info *csrows;
+	unsigned num_csrows, num_cschannel;
 
-	/* Number of allocated memory location data */
-	unsigned num_branch;
-	unsigned num_channel;
-	unsigned num_dimm;
-	unsigned num_csrows;
-	unsigned num_cschannel;
-
+	/* Memory Controller hierarchy */
+	unsigned n_layers;
+	struct edac_mc_layer *layers;
 	/*
 	 * DIMM info. Will eventually remove the entire csrows_info some day
 	 */
@@ -589,8 +580,9 @@ struct mem_ctl_info {
 	unsigned long start_time;	/* mci load start time (in jiffies) */
 
 	/* drivers shouldn't access this struct directly */
-	struct error_counts err;
 	unsigned ce_noinfo_count, ue_noinfo_count;
+	unsigned ce_mc, ue_mc;
+	u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
 
 	struct completion complete;
 
diff --git a/include/trace/events/hw_event.h b/include/trace/events/hw_event.h
index cbec44a..4c455c1 100644
--- a/include/trace/events/hw_event.h
+++ b/include/trace/events/hw_event.h
@@ -58,54 +58,41 @@ TRACE_EVENT(mc_error,
 		 const unsigned int mc_index,
 		 const char *msg,
 		 const char *label,
-		 const int branch,
-		 const int channel,
-		 const int dimm,
-		 const int csrow,
-		 const int cschannel,
+		 const char *location,
 		 const char *detail,
 		 const char *driver_detail),
 
-	TP_ARGS(err_type, mc_index, msg, label, branch, channel, dimm, csrow,
-		cschannel, detail, driver_detail),
+	TP_ARGS(err_type, mc_index, msg, label, location,
+		detail, driver_detail),
 
 	TP_STRUCT__entry(
 		__field(	unsigned int,	err_type		)
 		__field(	unsigned int,	mc_index		)
-		__field(	int,		branch			)
-		__field(	int,		channel			)
-		__field(	int,		dimm			)
-		__field(	int,		csrow			)
-		__field(	int,		cschannel		)
 		__string(	msg,		msg			)
 		__string(	label,		label			)
 		__string(	detail,		detail			)
+		__string(	location,	location		)
 		__string(	driver_detail,	driver_detail		)
 	),
 
 	TP_fast_assign(
 		__entry->err_type		= err_type;
 		__entry->mc_index		= mc_index;
-		__entry->branch			= branch;
-		__entry->channel		= channel;
-		__entry->dimm			= dimm;
-		__entry->csrow			= csrow;
-		__entry->cschannel		= cschannel;
 		__assign_str(msg, msg);
 		__assign_str(label, label);
+		__assign_str(location, location);
 		__assign_str(detail, detail);
 		__assign_str(driver_detail, driver_detail);
 	),
 
-	TP_printk(HW_ERR "mce#%d: %s error %s on label \"%s\" (location %d.%d.%d.%d.%d %s %s)\n",
+	TP_printk(HW_ERR "mce#%d: %s error %s on label \"%s\" (%s %s %s)\n",
 		  __entry->mc_index,
 		  (__entry->err_type == HW_EVENT_ERR_CORRECTED) ? "Corrected" :
 			((__entry->err_type == HW_EVENT_ERR_FATAL) ?
 			"Fatal" : "Uncorrected"),
 		  __get_str(msg),
 		  __get_str(label),
-		  __entry->branch, __entry->channel, __entry->dimm,
-		  __entry->csrow, __entry->cschannel,
+		  __get_str(location),
 		  __get_str(detail),
 		  __get_str(driver_detail))
 );
-- 
1.7.8

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ