<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:syn="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/">
  <channel rdf:about="http://blog.gmane.org/gmane.linux.ports.ppc64.devel">
    <title>gmane.linux.ports.ppc64.devel</title>
    <link>http://blog.gmane.org/gmane.linux.ports.ppc64.devel</link>
    <description/>
    <syn:updatePeriod>hourly</syn:updatePeriod>
    <syn:updateFrequency>1</syn:updateFrequency>
    <syn:updateBase>1901-01-01T00:00+00:00</syn:updateBase>
    <items>
      <rdf:Seq>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82226"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82225"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82221"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82220"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82212"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82211"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82210"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82209"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82208"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82203"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82202"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82200"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82199"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82188"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82173"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82165"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82164"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82159"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82151"/>
        <rdf:li rdf:resource="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82150"/>
      </rdf:Seq>
    </items>
    <image rdf:resource="http://gmane.org/img/gmane-25t.png"/>
    <textinput rdf:resource=""/>
  </channel>
  <image rdf:about="http://gmane.org/img/gmane-25t.png">
    <title>Gmane</title>
    <url>http://gmane.org/img/gmane-25t.png</url>
    <link>http://gmane.org</link>
  </image>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82226">
    <title>pread() and pwrite() system calls</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82226</link>
    <description>&lt;pre&gt;We have a system with linux 2.6.32 and the somewhat archaic
uClibc 0.9.27 (but I'm not sure the current version is
any better, and I think there are binary compatibility
if we update).

I've just discovered that pread() is 'implemented'
by using 3 lseek() system calls and read().
(the same is true for the 64bit versions).

I thought that pread() was supposed to be atomic
(so usable concurrently by multiple threads) which
means that this implementation is completely broken.

I've not looked to see what glibc does.

I can see that part of the problem is the alignment
of the 64bit value on the argument list of syscall()
(when the register save area is cast to a sycall
argument structure).
But it also looks as though the uClibc syscall()
stub can only pass 5 arguments in registers, and
pread() (with an aligned 64bit offset) requires 6.

The ucLibc source seems to be predicated by __NR_pread,
but if that were defined it would try to call
__syscall_pread() and I can't find that anywhere.

A special pread/pwrite asm stub that just copies
r7 to r0 could be used.

Would it be enough to do:
syscall_pread_pwrite:
mov 0,7
sc
blr
and handle the -ve -&amp;gt; errno in C?

I've seen other parts of linux pass structures to
avoid issues with excessive number of arguments.
Unlike things like NetBSD amd64 which will read
additional args off the user stack (and has per-system
call stubs in libc so doesn't lose one argument).
(I rearranged the NetBSD amd64 kernel trap frame
layout so all the args ended up adjacent...)

David
&lt;/pre&gt;</description>
    <dc:creator>David Laight</dc:creator>
    <dc:date>2012-05-25T13:29:06</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82225">
    <title>Re: module loading issue/flaw in busy memory situation?</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82225</link>
    <description>&lt;pre&gt;Hi,

The basic question is, has the GPR r11 a dedicated function (to point to the previous stack frame)
or is it still a volatile GPR, according to EABI definition ?
In the case of a dedicated function was assigned, the trampoline code generation in

     arch/powerpc/kernel/module_32.c

must be corrected. I'd suggest to use r12 instead of r11, in this case.

Best Regards
Steffen
&lt;/pre&gt;</description>
    <dc:creator>Steffen Rumler</dc:creator>
    <dc:date>2012-05-25T07:56:07</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82221">
    <title>Re: Oops with Radeon/Uninorth on Maple</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82221</link>
    <description>&lt;pre&gt;
Machine Check probably means that there's a HW configuration issue,
possibly something missing in the initialization of the AGP hardware to
make it actually work.

Cheers,
Ben.

&lt;/pre&gt;</description>
    <dc:creator>Benjamin Herrenschmidt</dc:creator>
    <dc:date>2012-05-25T00:59:55</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82220">
    <title>module loading issue/flaw in busy memory situation?</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82220</link>
    <description>&lt;pre&gt;Hi,

let's assume a module gets loaded into an already busy system, and the ".init.text" section with the __init function gets loaded into one memory region, and the normal ".text" section gets loaded into a totally different memory region.
Now assume that both regions are &amp;gt;32MB apart in addressing, so that a call from the __init .init.text function to any function in .text requires a trampoline as set up by the do_plt_call() function in arch/kernel/module*.c
So far so good for user code.

Now assume that the __init function is not trivial and will require register save/restore functions in prologue/epilogue with such calls generated by gcc, e.g., the __init function calls _rest32gpr_28_x() in the epilogue. This restore functions however is in the .text section due to the static link of the normal libs.

Now we have the __init function calling the trampoline, which is destroying r11. The trampoline is then jumping to the register restore function which relies on r11 still being intact, which it now isn't anymore.
Net result is a crash because the trampoline ABI conflicts with the register restore ABI and you get a case of garbage in leading to garbage out.

This situation has apparently occurred based on the debug results I have here.

In the general case of module development it seems unpredictable if gcc will actually call a register restore function from the __init function, or if the sections get loaded to require a trampoline, so for any non-trivial function in non-trivial memory setups, a crash would have to be expected, depending on the time of day and moon phase when the module gets loaded.

Is this a fundamental flaw in the interaction of the module section use specification and the module load mechanism with the ABI definition?

Or am I missing some incorrect setup or requirement for __init functions that I should deal with?

Thanks,

Heinz
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev&amp;lt; at &amp;gt;lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev&lt;/pre&gt;</description>
    <dc:creator>Wrobel Heinz-R39252</dc:creator>
    <dc:date>2012-05-24T20:05:19</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82212">
    <title>[PATCH 2/2] powerpc/85xx: Add P1024rdb board support</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82212</link>
    <description>&lt;pre&gt;From: Tang Yuantian &amp;lt;Yuantian.Tang&amp;lt; at &amp;gt;freescale.com&amp;gt;

The p1024rdb has the similar feature as the p1020rdb. Therefore, p1024rdb use
the same platform file as the p1/p2 rdb board.
Overview of P2020RDB platform
- DDR3 1G
- NOR flash 16M
- 3 Ethernet interfaces
- NAND Flash 32M
- SPI EEPROM 16M
- SD/MMC
- 2 USB ports
- 4 TDM ports

Signed-off-by: Jin Qing &amp;lt;b24347&amp;lt; at &amp;gt;freescale.com&amp;gt;
Signed-off-by: Li Yang &amp;lt;leoli&amp;lt; at &amp;gt;freescale.com&amp;gt;
Signed-off-by: Tang Yuantian &amp;lt;Yuantian.Tang&amp;lt; at &amp;gt;freescale.com&amp;gt;
---
 arch/powerpc/platforms/85xx/mpc85xx_rdb.c |   22 ++++++++++++++++++++++
 1 files changed, 22 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
index 313fce4..1910fdc 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_rdb.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -169,6 +169,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; machine_device_initcall(p1020_rdb_pc, mpc85xx_common_publish_devices);
 machine_device_initcall(p1020_utm_pc, mpc85xx_common_publish_devices);
 machine_device_initcall(p1021_rdb_pc, mpc85xx_common_publish_devices);
 machine_device_initcall(p1025_rdb, mpc85xx_common_publish_devices);
+machine_device_initcall(p1024_rdb, mpc85xx_common_publish_devices);
 
 /*
  * Called very early, device-tree isn't unflattened
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -237,6 +238,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int __init p1020_utm_pc_probe(void)
 return of_flat_dt_is_compatible(root, "fsl,P1020UTM-PC");
 }
 
+static int __init p1024_rdb_probe(void)
+{
+unsigned long root = of_get_flat_dt_root();
+
+return of_flat_dt_is_compatible(root, "fsl,P1024RDB");
+}
+
 define_machine(p2020_rdb) {
 .name= "P2020 RDB",
 .probe= p2020_rdb_probe,
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -348,3 +356,17 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; define_machine(p1020_rdb_pc) {
 .calibrate_decr= generic_calibrate_decr,
 .progress= udbg_progress,
 };
+
+define_machine(p1024_rdb) {
+.name= "P1024 RDB",
+.probe= p1024_rdb_probe,
+.setup_arch= mpc85xx_rdb_setup_arch,
+.init_IRQ= mpc85xx_rdb_pic_init,
+#ifdef CONFIG_PCI
+.pcibios_fixup_bus= fsl_pcibios_fixup_bus,
+#endif
+.get_irq= mpic_get_irq,
+.restart= fsl_rstcr_restart,
+.calibrate_decr= generic_calibrate_decr,
+.progress= udbg_progress,
+};
&lt;/pre&gt;</description>
    <dc:creator>b29983&lt; at &gt;freescale.com</dc:creator>
    <dc:date>2012-05-24T09:08:28</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82211">
    <title>[PATCH 1/2] powerpc/85xx: Add P1024rdb dts support</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82211</link>
    <description>&lt;pre&gt;From: Tang Yuantian &amp;lt;Yuantian.Tang&amp;lt; at &amp;gt;freescale.com&amp;gt;

Signed-off-by: Jin Qing &amp;lt;b24347&amp;lt; at &amp;gt;freescale.com&amp;gt;
Signed-off-by: Li Yang &amp;lt;leoli&amp;lt; at &amp;gt;freescale.com&amp;gt;
Signed-off-by: Tang Yuantian &amp;lt;Yuantian.Tang&amp;lt; at &amp;gt;freescale.com&amp;gt;
---
 arch/powerpc/boot/dts/p1024rdb.dtsi    |  228 ++++++++++++++++++++++++++++++++
 arch/powerpc/boot/dts/p1024rdb_32b.dts |   87 ++++++++++++
 arch/powerpc/boot/dts/p1024rdb_36b.dts |   87 ++++++++++++
 3 files changed, 402 insertions(+), 0 deletions(-)
 create mode 100644 arch/powerpc/boot/dts/p1024rdb.dtsi
 create mode 100644 arch/powerpc/boot/dts/p1024rdb_32b.dts
 create mode 100644 arch/powerpc/boot/dts/p1024rdb_36b.dts

diff --git a/arch/powerpc/boot/dts/p1024rdb.dtsi b/arch/powerpc/boot/dts/p1024rdb.dtsi
new file mode 100644
index 0000000..b05dcb4
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1024rdb.dtsi
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,228 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+/*
+ * P1024 RDB Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+&amp;amp;lbc {
+nor&amp;lt; at &amp;gt;0,0 {
+#address-cells = &amp;lt;1&amp;gt;;
+#size-cells = &amp;lt;1&amp;gt;;
+compatible = "cfi-flash";
+reg = &amp;lt;0x0 0x0 0x1000000&amp;gt;;
+bank-width = &amp;lt;2&amp;gt;;
+device-width = &amp;lt;1&amp;gt;;
+
+partition&amp;lt; at &amp;gt;0 {
+/* This location must not be altered  */
+/* 256KB for Vitesse 7385 Switch firmware */
+reg = &amp;lt;0x0 0x00040000&amp;gt;;
+label = "NOR Vitesse-7385 Firmware";
+read-only;
+};
+
+partition&amp;lt; at &amp;gt;40000 {
+/* 256KB for DTB Image */
+reg = &amp;lt;0x00040000 0x00040000&amp;gt;;
+label = "NOR DTB Image";
+};
+
+partition&amp;lt; at &amp;gt;80000 {
+/* 3.5 MB for Linux Kernel Image */
+reg = &amp;lt;0x00080000 0x00380000&amp;gt;;
+label = "NOR Linux Kernel Image";
+};
+
+partition&amp;lt; at &amp;gt;400000 {
+/* 11MB for JFFS2 based Root file System */
+reg = &amp;lt;0x00400000 0x00b00000&amp;gt;;
+label = "NOR JFFS2 Root File System";
+};
+
+partition&amp;lt; at &amp;gt;f00000 {
+/* This location must not be altered  */
+/* 512KB for u-boot Bootloader Image */
+/* 512KB for u-boot Environment Variables */
+reg = &amp;lt;0x00f00000 0x00100000&amp;gt;;
+label = "NOR U-Boot Image";
+read-only;
+};
+};
+
+nand&amp;lt; at &amp;gt;1,0 {
+#address-cells = &amp;lt;1&amp;gt;;
+#size-cells = &amp;lt;1&amp;gt;;
+compatible = "fsl,p1020-fcm-nand",
+ "fsl,elbc-fcm-nand";
+reg = &amp;lt;0x1 0x0 0x40000&amp;gt;;
+
+partition&amp;lt; at &amp;gt;0 {
+/* This location must not be altered  */
+/* 1MB for u-boot Bootloader Image */
+reg = &amp;lt;0x0 0x00100000&amp;gt;;
+label = "NAND U-Boot Image";
+read-only;
+};
+
+partition&amp;lt; at &amp;gt;100000 {
+/* 1MB for DTB Image */
+reg = &amp;lt;0x00100000 0x00100000&amp;gt;;
+label = "NAND DTB Image";
+};
+
+partition&amp;lt; at &amp;gt;200000 {
+/* 4MB for Linux Kernel Image */
+reg = &amp;lt;0x00200000 0x00400000&amp;gt;;
+label = "NAND Linux Kernel Image";
+};
+
+partition&amp;lt; at &amp;gt;600000 {
+/* 4MB for Compressed Root file System Image */
+reg = &amp;lt;0x00600000 0x00400000&amp;gt;;
+label = "NAND Compressed RFS Image";
+};
+
+partition&amp;lt; at &amp;gt;a00000 {
+/* 15MB for JFFS2 based Root file System */
+reg = &amp;lt;0x00a00000 0x00f00000&amp;gt;;
+label = "NAND JFFS2 Root File System";
+};
+
+partition&amp;lt; at &amp;gt;1900000 {
+/* 7MB for User Writable Area */
+reg = &amp;lt;0x01900000 0x00700000&amp;gt;;
+label = "NAND Writable User area";
+};
+};
+};
+
+&amp;amp;soc {
+spi&amp;lt; at &amp;gt;7000 {
+flash&amp;lt; at &amp;gt;0 {
+#address-cells = &amp;lt;1&amp;gt;;
+#size-cells = &amp;lt;1&amp;gt;;
+compatible = "spansion,m25p80";
+reg = &amp;lt;0&amp;gt;;
+spi-max-frequency = &amp;lt;40000000&amp;gt;;
+
+partition&amp;lt; at &amp;gt;0 {
+/* 512KB for u-boot Bootloader Image */
+reg = &amp;lt;0x0 0x00080000&amp;gt;;
+label = "SPI U-Boot Image";
+read-only;
+};
+
+partition&amp;lt; at &amp;gt;80000 {
+/* 512KB for DTB Image */
+reg = &amp;lt;0x00080000 0x00080000&amp;gt;;
+label = "SPI DTB Image";
+};
+
+partition&amp;lt; at &amp;gt;100000 {
+/* 4MB for Linux Kernel Image */
+reg = &amp;lt;0x00100000 0x00400000&amp;gt;;
+label = "SPI Linux Kernel Image";
+};
+
+partition&amp;lt; at &amp;gt;500000 {
+/* 4MB for Compressed RFS Image */
+reg = &amp;lt;0x00500000 0x00400000&amp;gt;;
+label = "SPI Compressed RFS Image";
+};
+
+partition&amp;lt; at &amp;gt;900000 {
+/* 7MB for JFFS2 based RFS */
+reg = &amp;lt;0x00900000 0x00700000&amp;gt;;
+label = "SPI JFFS2 RFS";
+};
+};
+};
+
+i2c&amp;lt; at &amp;gt;3000 {
+rtc&amp;lt; at &amp;gt;68 {
+compatible = "dallas,ds1339";
+reg = &amp;lt;0x68&amp;gt;;
+};
+};
+
+usb&amp;lt; at &amp;gt;22000 {
+phy_type = "ulpi";
+};
+
+usb&amp;lt; at &amp;gt;23000 {
+status = "disabled";
+};
+
+mdio&amp;lt; at &amp;gt;24000 {
+phy0: ethernet-phy&amp;lt; at &amp;gt;0 {
+interrupts = &amp;lt;3 1 0 0&amp;gt;;
+reg = &amp;lt;0x0&amp;gt;;
+};
+phy1: ethernet-phy&amp;lt; at &amp;gt;1 {
+interrupts = &amp;lt;2 1 0 0&amp;gt;;
+reg = &amp;lt;0x1&amp;gt;;
+};
+phy2: ethernet-phy&amp;lt; at &amp;gt;2 {
+interrupts = &amp;lt;1 1 0 0&amp;gt;;
+reg = &amp;lt;0x2&amp;gt;;
+};
+};
+
+mdio&amp;lt; at &amp;gt;25000 {
+tbi0: tbi-phy&amp;lt; at &amp;gt;11 {
+reg = &amp;lt;0x11&amp;gt;;
+device_type = "tbi-phy";
+};
+};
+
+mdio&amp;lt; at &amp;gt;26000 {
+tbi1: tbi-phy&amp;lt; at &amp;gt;11 {
+reg = &amp;lt;0x11&amp;gt;;
+device_type = "tbi-phy";
+};
+};
+
+ethernet&amp;lt; at &amp;gt;b0000 {
+phy-handle = &amp;lt;&amp;amp;phy2&amp;gt;;
+phy-connection-type = "rgmii-id";
+};
+
+ethernet&amp;lt; at &amp;gt;b1000 {
+phy-handle = &amp;lt;&amp;amp;phy0&amp;gt;;
+tbi-handle = &amp;lt;&amp;amp;tbi0&amp;gt;;
+phy-connection-type = "sgmii";
+};
+
+ethernet&amp;lt; at &amp;gt;b2000 {
+phy-handle = &amp;lt;&amp;amp;phy1&amp;gt;;
+phy-connection-type = "rgmii-id";
+};
+};
diff --git a/arch/powerpc/boot/dts/p1024rdb_32b.dts b/arch/powerpc/boot/dts/p1024rdb_32b.dts
new file mode 100644
index 0000000..90e803e
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1024rdb_32b.dts
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,87 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+/*
+ * P1024 RDB 32Bit Physical Address Map Device Tree Source
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p1020si-pre.dtsi"
+/ {
+model = "fsl,P1024RDB";
+compatible = "fsl,P1024RDB";
+
+memory {
+device_type = "memory";
+};
+
+lbc: localbus&amp;lt; at &amp;gt;ffe05000 {
+reg = &amp;lt;0x0 0xffe05000 0 0x1000&amp;gt;;
+ranges = &amp;lt;0x0 0x0 0x0 0xef000000 0x01000000
+  0x1 0x0 0x0 0xff800000 0x00040000&amp;gt;;
+};
+
+soc: soc&amp;lt; at &amp;gt;ffe00000 {
+ranges = &amp;lt;0x0 0x0 0xffe00000 0x100000&amp;gt;;
+};
+
+pci0: pcie&amp;lt; at &amp;gt;ffe09000 {
+reg = &amp;lt;0x0 0xffe09000 0 0x1000&amp;gt;;
+ranges = &amp;lt;0x2000000 0x0 0xe0000000 0x0 0xa0000000 0x0 0x20000000
+  0x1000000 0x0 0x00000000 0x0 0xffc10000 0x0 0x10000&amp;gt;;
+pcie&amp;lt; at &amp;gt;0 {
+ranges = &amp;lt;0x2000000 0x0 0xe0000000
+  0x2000000 0x0 0xe0000000
+  0x0 0x20000000
+
+  0x1000000 0x0 0x0
+  0x1000000 0x0 0x0
+  0x0 0x100000&amp;gt;;
+};
+};
+
+pci1: pcie&amp;lt; at &amp;gt;ffe0a000 {
+reg = &amp;lt;0x0 0xffe0a000 0 0x1000&amp;gt;;
+ranges = &amp;lt;0x2000000 0x0 0xe0000000 0x0 0x80000000 0x0 0x20000000
+  0x1000000 0x0 0x00000000 0x0 0xffc00000 0x0 0x10000&amp;gt;;
+pcie&amp;lt; at &amp;gt;0 {
+reg = &amp;lt;0x0 0x0 0x0 0x0 0x0&amp;gt;;
+ranges = &amp;lt;0x2000000 0x0 0xe0000000
+  0x2000000 0x0 0xe0000000
+  0x0 0x20000000
+
+  0x1000000 0x0 0x0
+  0x1000000 0x0 0x0
+  0x0 0x100000&amp;gt;;
+};
+};
+};
+
+/include/ "p1024rdb.dtsi"
+/include/ "fsl/p1020si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1024rdb_36b.dts b/arch/powerpc/boot/dts/p1024rdb_36b.dts
new file mode 100644
index 0000000..3656825
--- /dev/null
+++ b/arch/powerpc/boot/dts/p1024rdb_36b.dts
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,87 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+/*
+ * P1024 RDB 36Bit Physical Address Map Device Tree Source
+ *
+ * Copyright 2012 Freescale Semiconductor Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in the
+ *       documentation and/or other materials provided with the distribution.
+ *     * Neither the name of Freescale Semiconductor nor the
+ *       names of its contributors may be used to endorse or promote products
+ *       derived from this software without specific prior written permission.
+ *
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/include/ "fsl/p1020si-pre.dtsi"
+/ {
+model = "fsl,P1024RDB";
+compatible = "fsl,P1024RDB";
+
+memory {
+device_type = "memory";
+};
+
+lbc: localbus&amp;lt; at &amp;gt;fffe05000 {
+reg = &amp;lt;0xf 0xffe05000 0 0x1000&amp;gt;;
+ranges = &amp;lt;0x0 0x0 0xf 0xef000000 0x01000000
+  0x1 0x0 0xf 0xff800000 0x00040000&amp;gt;;
+};
+
+soc: soc&amp;lt; at &amp;gt;fffe00000 {
+ranges = &amp;lt;0x0 0xf 0xffe00000 0x100000&amp;gt;;
+};
+
+pci0: pcie&amp;lt; at &amp;gt;fffe09000 {
+reg = &amp;lt;0xf 0xffe09000 0 0x1000&amp;gt;;
+ranges = &amp;lt;0x2000000 0x0 0xe0000000 0xc 0x20000000 0x0 0x20000000
+  0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000&amp;gt;;
+pcie&amp;lt; at &amp;gt;0 {
+ranges = &amp;lt;0x2000000 0x0 0xe0000000
+  0x2000000 0x0 0xe0000000
+  0x0 0x20000000
+
+  0x1000000 0x0 0x0
+  0x1000000 0x0 0x0
+  0x0 0x100000&amp;gt;;
+};
+};
+
+pci1: pcie&amp;lt; at &amp;gt;fffe0a000 {
+reg = &amp;lt;0xf 0xffe0a000 0 0x1000&amp;gt;;
+ranges = &amp;lt;0x2000000 0x0 0xe0000000 0xc 0x00000000 0x0 0x20000000
+  0x1000000 0x0 0x00000000 0xf 0xffc00000 0x0 0x10000&amp;gt;;
+pcie&amp;lt; at &amp;gt;0 {
+reg = &amp;lt;0x0 0x0 0x0 0x0 0x0&amp;gt;;
+ranges = &amp;lt;0x2000000 0x0 0xe0000000
+  0x2000000 0x0 0xe0000000
+  0x0 0x20000000
+
+  0x1000000 0x0 0x0
+  0x1000000 0x0 0x0
+  0x0 0x100000&amp;gt;;
+};
+};
+};
+
+/include/ "p1024rdb.dtsi"
+/include/ "fsl/p1020si-post.dtsi"
&lt;/pre&gt;</description>
    <dc:creator>b29983&lt; at &gt;freescale.com</dc:creator>
    <dc:date>2012-05-24T09:08:27</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82210">
    <title>Oops with Radeon/Uninorth on Maple</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82210</link>
    <description>&lt;pre&gt;Hello, colleagues,

I'm trying to enable an AGP slot (again) on my Maple board (dual 
PPC970FX board, with CPC925 (U3H) north bridge).

  For now I'm stuck with a problem: I use radeon card, drm-radeon driver 
with KMS.

If I force drm-radeon to think about a card as about PCI card (by 
commenting corresponding lines in drm_radeon_kms.c), everything works, I 
get framebuffer, working X11, etc. If I enable agpgart-uninorth driver
and RADEON_IS_AGP flag in drm driver, I get an Oops early during the 
bootstrap. Relevant part of the log (I can send full dmesg of normal 
bootstrap or this oops on request, if that would help).

[    2.820647] Linux agpgart interface v0.103
[    2.824909] agpgart-uninorth 0000:f0:0b.0: Apple U3H chipset
[    2.830668] agpgart-uninorth 0000:f0:0b.0: Found device u3, rev 35
[    2.843611] agpgart-uninorth 0000:f0:0b.0: configuring for size idx: 64
[    2.850638] agpgart-uninorth 0000:f0:0b.0: AGP aperture is 256M &amp;lt; at &amp;gt; 0x0
[    2.857646] [drm] Initialized drm 1.1.0 20060810
[    2.862567] [drm] radeon defaulting to kernel modesetting.
[    2.868091] [drm] radeon kernel modesetting enabled.
[    2.873222] radeon 0000:f0:10.0: enabling device (0000 -&amp;gt; 0003)
[    2.880311] radeon 0000:f0:10.0: enabling bus mastering
[    2.885591] [drm] initializing kernel modesetting (RV350 
0x1002:0x4152 0x18BC:0x0416).
[    2.893629] [drm] register mmio base: 0xD0020000
[    2.898260] [drm] register mmio size: 65536
[    2.947112] [drm] GPU not posted. posting now...
[    3.051033] agpgart-uninorth 0000:f0:0b.0: putting AGP V3 device into 
8x mode
[    3.058197] radeon 0000:f0:10.0: putting AGP V3 device into 8x mode
[    3.064666] radeon 0000:f0:10.0: GTT: 256M 0x00000000 - 0x0FFFFFFF
[    3.070864] [drm] Generation 2 PCI interface, using max accessible memory
[    3.077672] radeon 0000:f0:10.0: VRAM: 128M 0x00000000C0000000 - 
0x00000000C7FFFFFF (128M used)
[    3.086487] [drm] Supports vblank timestamp caching Rev 1 (10.10.2010).
[    3.093126] [drm] Driver supports precise vblank timestamp query.
[    3.099291] [drm] radeon: irq initialized.
[    3.103404] [drm] Detected VRAM RAM=128M, BAR=128M
[    3.108214] [drm] RAM width 128bits DDR
[    3.112263] [TTM] Zone  kernel: Available graphics memory: 496682 kiB
[    3.118732] [TTM] Initializing pool allocator
[    3.123346] [drm] radeon: 128M of VRAM memory ready
[    3.128256] [drm] radeon: 256M of GTT memory ready.
[    3.133295] [drm] radeon: ib pool ready.
[    3.137708] [drm] radeon: 1 quad pipes, 1 Z pipes initialized.
[    3.144018] radeon 0000:f0:10.0: WB disabled
[    3.148326] [drm] fence driver on ring 0 use gpu addr 0x00000000 and 
cpu addr 0xd000000000066000
[    3.157474] [drm] Loading R300 Microcode
[    3.162480] [drm] radeon: ring at 0x0000000000001000
[    3.167569] [drm] ring test succeeded in 0 usecs
cpu 0x0: Vector: 200 (Machine Check) at [c000000000d63aa0]
     pc: c0000000000cc07c: .trace_hardirqs_on_caller+0x6c/0x190
     lr: c0000000000152f4: .cpu_idle+0x1a4/0x220
     sp: c000000000d63d20
    msr: 9000000000009032
   current = 0xc000000000c4db30
   paca    = 0xc00000000ffff000   softe: 0        irq_happened: 0x01
     pid   = 0, comm = swapper/0
enter ? for help
[c000000000d63db0] c0000000000152f4 .cpu_idle+0x1a4/0x220
[c000000000d63e50] c000000000008fb8 .rest_init+0xe8/0x110
[c000000000d63ee0] c000000000ba2998 .start_kernel+0x3e4/0x408
[c000000000d63f90] c000000000007558 .start_here_common+0x20/0x48
0:mon&amp;gt; x
[  843.783295] Oops: Machine check, sig: 7 [#1]
[  843.787589] SMP NR_CPUS=4 Maple
[  843.790768] Modules linked in:
[  843.793855] NIP: c0000000000cc07c LR: c0000000000152f4 CTR: 
c000000000023eac
[  843.800920] REGS: c000000000d63aa0 TRAP: 0200   Not tainted  (3.4.0+)
[  843.807376] MSR: 9000000000009032 &amp;lt;SF,HV,EE,ME,IR,DR,RI&amp;gt;  CR: 
24222222  XER: 00000006
[  843.815412] SOFTE: 0
[  843.817607] TASK = c000000000c4db30[0] 'swapper/0' THREAD: 
c000000000d60000 CPU: 0
[  843.825035] GPR00: 0000000000000000 c000000000d63d20 c000000000d63280 
c0000000000152f4
[  843.833169] GPR04: 0000000000000000 c000000000099d10 0000000000000001 
0000000000000002
[  843.841302] GPR08: 0100000000000000 c000000000e828e8 0140000000000000 
0000000000000000
[  843.849436] GPR12: 0000000044222282 c00000000ffff000 0000000000000000 
0000000000000000
[  843.857570] GPR16: 0000000000ff8750 0000000000cdc890 00000000010001e0 
0000000000000000
[  843.865702] GPR20: 0000000000000000 0000000000000000 000000001dcd6500 
0000000000000000
[  843.873835] GPR24: 0000000000000000 0000000000ec7b00 9000000000009032 
c000000000d7b178
[  843.881979] GPR28: c000000000d7b278 0000000000000008 c000000000c970f8 
c0000000000152f4
[  843.890314] NIP [c0000000000cc07c] .trace_hardirqs_on_caller+0x6c/0x190
[  843.896942] LR [c0000000000152f4] .cpu_idle+0x1a4/0x220
[  843.902181] Call Trace:
[  843.904640] [c000000000d63d20] [c000000000d63db0] 
init_thread_union+0x3db0/0x4000 (unreliable)
[  843.913317] [c000000000d63db0] [c0000000000152f4] .cpu_idle+0x1a4/0x220
[  843.919964] [c000000000d63e50] [c000000000008fb8] .rest_init+0xe8/0x110
[  843.926615] [c000000000d63ee0] [c000000000ba2998] 
.start_kernel+0x3e4/0x408
[  843.933611] [c000000000d63f90] [c000000000007558] 
.start_here_common+0x20/0x48
[  843.940866] Instruction dump:
[  843.943868] 40de00a4 e92d01c8 800908e8 2f800000 40de0094 e93e8098 
80090000 2f800000
[  843.951829] 409e0030 880d01f2 2fa00000 40de00b0 &amp;lt;e93e84e8&amp;gt; 88090000 
2f800000 40de00c8


Looking for any suggestions on this.

&lt;/pre&gt;</description>
    <dc:creator>Dmitry Eremin-Solenikov</dc:creator>
    <dc:date>2012-05-24T06:18:55</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82209">
    <title>[PATCH] [ppc] Do not reserve cpu spin-table for crash kernel</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82209</link>
    <description>&lt;pre&gt;As of now, the kexec reserves the spin-table for all the CPUs
on an SMP machine. The spin-table is pointed to by the 
cpu-release-addr property in the device-tree. Reserving the
spin-table in the crash kernel will cause a BUG(), if the table
lies outside the memory reserved for the crashkernel.

Disable reserving the spin-table regions and use maxcpus=1 to 
use only the crashing CPU to boot the crash kernel.

Signed-off-by: Suzuki K. Poulose &amp;lt;suzuki&amp;lt; at &amp;gt;in.ibm.com&amp;gt;
---

 kexec/arch/ppc/crashdump-powerpc.c |   19 +++++++++++++------
 kexec/arch/ppc/fixup_dtb.c         |    4 ++++
 2 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/kexec/arch/ppc/crashdump-powerpc.c b/kexec/arch/ppc/crashdump-powerpc.c
index 1bef69b..4c8c75d 100644
--- a/kexec/arch/ppc/crashdump-powerpc.c
+++ b/kexec/arch/ppc/crashdump-powerpc.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -262,10 +262,19 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void ulltoa(unsigned long long i, char *str)
 }
 }
 
+/* Append str to cmdline */
+static void add_cmdline(char *cmdline, char *str)
+{
+int cmdlen = strlen(cmdline) + strlen(str);
+if (cmdlen &amp;gt; (COMMAND_LINE_SIZE - 1))
+die("Command line overflow\n");
+strcat(cmdline, str);
+}
+
 static int add_cmdline_param(char *cmdline, unsigned long long addr,
 char *cmdstr, char *byte)
 {
-int cmdlen, len, align = 1024;
+int align = 1024;
 char str[COMMAND_LINE_SIZE], *ptr;
 
 /* Passing in =xxxK / =xxxM format. Saves space required in cmdline.*/
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -284,11 +293,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int add_cmdline_param(char *cmdline, unsigned long long addr,
 ptr += strlen(str);
 ulltoa(addr, ptr);
 strcat(str, byte);
-len = strlen(str);
-cmdlen = strlen(cmdline) + len;
-if (cmdlen &amp;gt; (COMMAND_LINE_SIZE - 1))
-die("Command line overflow\n");
-strcat(cmdline, str);
+
+add_cmdline(cmdline, str);
 
 dbgprintf("Command line after adding elfcorehdr: %s\n", cmdline);
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -365,6 +371,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; int load_crashdump_segments(struct kexec_info *info, char *mod_cmdline,
  */
 add_cmdline_param(mod_cmdline, elfcorehdr, " elfcorehdr=", "K");
 add_cmdline_param(mod_cmdline, saved_max_mem, " savemaxmem=", "M");
+add_cmdline(mod_cmdline, " maxcpus=1");
 return 0;
 }
 
diff --git a/kexec/arch/ppc/fixup_dtb.c b/kexec/arch/ppc/fixup_dtb.c
index e9890a4..f832026 100644
--- a/kexec/arch/ppc/fixup_dtb.c
+++ b/kexec/arch/ppc/fixup_dtb.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -172,6 +172,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void fixup_reserve_regions(struct kexec_info *info, char *blob_buf)
 }
 }
 
+#if 0
+/* XXX: Do not reserve spin-table for CPUs. */
+
 /* Add reserve regions for cpu-release-addr */
 nodeoffset = fdt_node_offset_by_prop_value(blob_buf, -1, "device_type", "cpu", 4);
 while (nodeoffset != -FDT_ERR_NOTFOUND) {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -201,6 +204,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void fixup_reserve_regions(struct kexec_info *info, char *blob_buf)
 nodeoffset = fdt_node_offset_by_prop_value(blob_buf, nodeoffset,
 "device_type", "cpu", 4);
 }
+#endif
 
 out:
 print_fdt_reserve_regions(blob_buf);
&lt;/pre&gt;</description>
    <dc:creator>Suzuki K. Poulose</dc:creator>
    <dc:date>2012-05-24T06:09:45</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82208">
    <title>[PATCH v3 2/2] microblaze/PCI: move DMA &amp; IRQ init to device_add() notification path</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82208</link>
    <description>&lt;pre&gt;From: Hiroo Matsumoto &amp;lt;matsumoto.hiroo&amp;lt; at &amp;gt;jp.fujitsu.com&amp;gt;

Microblaze initialized DMA and IRQ information in the pci_scan_child_bus()
-&amp;gt; pcibios_fixup_bus() path.  Some hotplug drivers use that path, but
others don't, e.g., pciehp, so sometimes hot-added devices are only
partly initialized.

This patch moves that initialization from pcibios_fixup_bus() to a new
pci_bus_notify() called in the pci_bus_add_device() -&amp;gt; device_add() path.
That means the initialization happens the same way for all PCI devices,
whether they are present at boot or hot-added later.

[bhelgaas: changelog, notifier name, inline registration]
Signed-off-by: Hiroo MATSUMOTO &amp;lt;matsumoto.hiroo&amp;lt; at &amp;gt;jp.fujitsu.com&amp;gt;
Signed-off-by: Bjorn Helgaas &amp;lt;bhelgaas&amp;lt; at &amp;gt;google.com&amp;gt;
---
 arch/microblaze/include/asm/pci.h |    1 -
 arch/microblaze/pci/pci-common.c  |   62 ++++++++++++++++++++-----------------
 2 files changed, 34 insertions(+), 29 deletions(-)

diff --git a/arch/microblaze/include/asm/pci.h b/arch/microblaze/include/asm/pci.h
index a0da88b..2aa97fd 100644
--- a/arch/microblaze/include/asm/pci.h
+++ b/arch/microblaze/include/asm/pci.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -141,7 +141,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; extern void pci_resource_to_user(const struct pci_dev *dev, int bar,
  const struct resource *rsrc,
  resource_size_t *start, resource_size_t *end);
 
-extern void pcibios_setup_bus_devices(struct pci_bus *bus);
 extern void pcibios_setup_bus_self(struct pci_bus *bus);
 
 /* This part of code was originally in xilinx-pci.h */
diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
index 9b32483..6487ed0 100644
--- a/arch/microblaze/pci/pci-common.c
+++ b/arch/microblaze/pci/pci-common.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -983,31 +983,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void __devinit pcibios_setup_bus_self(struct pci_bus *bus)
 pcibios_fixup_bridge(bus);
 }
 
-void __devinit pcibios_setup_bus_devices(struct pci_bus *bus)
-{
-struct pci_dev *dev;
-
-pr_debug("PCI: Fixup bus devices %d (%s)\n",
- bus-&amp;gt;number, bus-&amp;gt;self ? pci_name(bus-&amp;gt;self) : "PHB");
-
-list_for_each_entry(dev, &amp;amp;bus-&amp;gt;devices, bus_list) {
-/* Setup OF node pointer in archdata */
-dev-&amp;gt;dev.of_node = pci_device_to_OF_node(dev);
-
-/* Fixup NUMA node as it may not be setup yet by the generic
- * code and is needed by the DMA init
- */
-set_dev_node(&amp;amp;dev-&amp;gt;dev, pcibus_to_node(dev-&amp;gt;bus));
-
-/* Hook up default DMA ops */
-set_dma_ops(&amp;amp;dev-&amp;gt;dev, pci_dma_ops);
-dev-&amp;gt;dev.archdata.dma_data = (void *)PCI_DRAM_OFFSET;
-
-/* Read default IRQs and fixup if necessary */
-pci_read_irq_line(dev);
-}
-}
-
 void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 {
 /* When called from the generic PCI probe, read PCI&amp;lt;-&amp;gt;PCI bridge
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1019,9 +994,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void __devinit pcibios_fixup_bus(struct pci_bus *bus)
 
 /* Now fixup the bus bus */
 pcibios_setup_bus_self(bus);
-
-/* Now fixup devices on that bus */
-pcibios_setup_bus_devices(bus);
 }
 EXPORT_SYMBOL(pcibios_fixup_bus);
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1512,6 +1484,38 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void __devinit pcibios_scan_phb(struct pci_controller *hose)
 hose-&amp;gt;last_busno = bus-&amp;gt;busn_res.end;
 }
 
+static int pci_bus_notify(struct notifier_block *nb, unsigned long action,
+  void *data)
+{
+struct pci_dev *dev = to_pci_dev(data);
+
+switch (action) {
+case BUS_NOTIFY_ADD_DEVICE:
+/* Setup OF node pointer in archdata */
+dev-&amp;gt;dev.of_node = pci_device_to_OF_node(dev);
+
+/* Fixup NUMA node as it may not be setup yet by the generic
+ * code and is needed by the DMA init
+ */
+set_dev_node(&amp;amp;dev-&amp;gt;dev, pcibus_to_node(dev-&amp;gt;bus));
+
+/* Hook up default DMA ops */
+set_dma_ops(&amp;amp;dev-&amp;gt;dev, pci_dma_ops);
+dev-&amp;gt;dev.archdata.dma_data = (void *)PCI_DRAM_OFFSET;
+
+/* Read default IRQs and fixup if necessary */
+pci_read_irq_line(dev);
+
+break;
+}
+
+return 0;
+}
+
+static struct notifier_block device_nb = {
+.notifier_call = pci_bus_notify,
+};
+
 static int __init pcibios_init(void)
 {
 struct pci_controller *hose, *tmp;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1519,6 +1523,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int __init pcibios_init(void)
 
 printk(KERN_INFO "PCI: Probing PCI hardware\n");
 
+bus_register_notifier(&amp;amp;pci_bus_type, &amp;amp;device_nb);
+
 /* Scan all of the recorded PCI controllers.  */
 list_for_each_entry_safe(hose, tmp, &amp;amp;hose_list, list_node) {
 hose-&amp;gt;last_busno = 0xff;
&lt;/pre&gt;</description>
    <dc:creator>Bjorn Helgaas</dc:creator>
    <dc:date>2012-05-23T22:37:05</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82203">
    <title>[PATCH] powerpc/p1010rdb: add EEPROMs to device tree</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82203</link>
    <description>&lt;pre&gt;Add EEPROM to the P1010RDB device tree.
The 24c01 acts as a memory SPD so it shouldn't be overwritten without
care.
The 24c256 is a general purpose memory.

Signed-off-by: Gustavo Zacarias &amp;lt;gustavo&amp;lt; at &amp;gt;zacarias.com.ar&amp;gt;
---
 arch/powerpc/boot/dts/p1010rdb.dtsi |   12 ++++++++++++
 1 files changed, 12 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/boot/dts/p1010rdb.dtsi b/arch/powerpc/boot/dts/p1010rdb.dtsi
index 4977614..ec7c27a 100644
--- a/arch/powerpc/boot/dts/p1010rdb.dtsi
+++ b/arch/powerpc/boot/dts/p1010rdb.dtsi
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -126,12 +126,24 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 &amp;amp;board_soc {
 i2c&amp;lt; at &amp;gt;3000 {
+eeprom&amp;lt; at &amp;gt;50 {
+compatible = "st,24c256";
+reg = &amp;lt;0x50&amp;gt;;
+};
+
 rtc&amp;lt; at &amp;gt;68 {
 compatible = "pericom,pt7c4338";
 reg = &amp;lt;0x68&amp;gt;;
 };
 };
 
+i2c&amp;lt; at &amp;gt;3100 {
+eeprom&amp;lt; at &amp;gt;52 {
+compatible = "atmel,24c01";
+reg = &amp;lt;0x52&amp;gt;;
+};
+};
+
 spi&amp;lt; at &amp;gt;7000 {
 flash&amp;lt; at &amp;gt;0 {
 #address-cells = &amp;lt;1&amp;gt;;
&lt;/pre&gt;</description>
    <dc:creator>Gustavo Zacarias</dc:creator>
    <dc:date>2012-05-23T14:35:18</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82202">
    <title>[PATCH] powerpc: tracing: Avoid tracepoint duplication with DECLARE_EVENT_CLASS</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82202</link>
    <description>&lt;pre&gt;
irq_entry, irq_exit, timer_interrupt_entry and timer_interrupt_exit
all do the same thing so use DECLARE_EVENT_CLASS to avoid duplicating
everything 4 times.

This saves quite a lot of space in both instruction text and data:

   text    data     bss     dec     hex filename
   9265   19622      16   28903    70e7 arch/powerpc/kernel/irq.o
   6817   19019      16   25852    64fc arch/powerpc/kernel/irq.o

Signed-off-by: Anton Blanchard &amp;lt;anton&amp;lt; at &amp;gt;samba.org&amp;gt;
---

Index: linux-build/arch/powerpc/include/asm/trace.h
===================================================================
--- linux-build.orig/arch/powerpc/include/asm/trace.h2012-05-23 13:30:51.235534219 +1000
+++ linux-build/arch/powerpc/include/asm/trace.h2012-05-23 14:10:44.406639628 +1000
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -8,7 +8,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 struct pt_regs;
 
-TRACE_EVENT(irq_entry,
+DECLARE_EVENT_CLASS(ppc64_interrupt_class,
 
 TP_PROTO(struct pt_regs *regs),
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -25,55 +25,32 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; TRACE_EVENT(irq_entry,
 TP_printk("pt_regs=%p", __entry-&amp;gt;regs)
 );
 
-TRACE_EVENT(irq_exit,
+DEFINE_EVENT(ppc64_interrupt_class, irq_entry,
 
 TP_PROTO(struct pt_regs *regs),
 
-TP_ARGS(regs),
-
-TP_STRUCT__entry(
-__field(struct pt_regs *, regs)
-),
-
-TP_fast_assign(
-__entry-&amp;gt;regs = regs;
-),
-
-TP_printk("pt_regs=%p", __entry-&amp;gt;regs)
+TP_ARGS(regs)
 );
 
-TRACE_EVENT(timer_interrupt_entry,
+DEFINE_EVENT(ppc64_interrupt_class, irq_exit,
 
 TP_PROTO(struct pt_regs *regs),
 
-TP_ARGS(regs),
-
-TP_STRUCT__entry(
-__field(struct pt_regs *, regs)
-),
-
-TP_fast_assign(
-__entry-&amp;gt;regs = regs;
-),
-
-TP_printk("pt_regs=%p", __entry-&amp;gt;regs)
+TP_ARGS(regs)
 );
 
-TRACE_EVENT(timer_interrupt_exit,
+DEFINE_EVENT(ppc64_interrupt_class, timer_interrupt_entry,
 
 TP_PROTO(struct pt_regs *regs),
 
-TP_ARGS(regs),
+TP_ARGS(regs)
+);
 
-TP_STRUCT__entry(
-__field(struct pt_regs *, regs)
-),
+DEFINE_EVENT(ppc64_interrupt_class, timer_interrupt_exit,
 
-TP_fast_assign(
-__entry-&amp;gt;regs = regs;
-),
+TP_PROTO(struct pt_regs *regs),
 
-TP_printk("pt_regs=%p", __entry-&amp;gt;regs)
+TP_ARGS(regs)
 );
 
 #ifdef CONFIG_PPC_PSERIES
&lt;/pre&gt;</description>
    <dc:creator>Anton Blanchard</dc:creator>
    <dc:date>2012-05-23T04:47:48</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82200">
    <title>[PATCH] powerpc: Enable jump label support</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82200</link>
    <description>&lt;pre&gt;
When looking through some instruction traces I noticed our tracepoint
checks were inline. It turns out we don't have CONFIG_JUMP_LABEL
enabled.

By enabling CONFIG_JUMP_LABEL we replace a load/compare/branch with
a nop at every tracepoint call. For example in do_IRQ:

CONFIG_JUMP_LABEL disabled:
        stdx 3,11,9
        lwz 0,8(29)
        cmpwi 7,0,0
        bne- 7,.L124
        bl .irq_enter

CONFIG_JUMP_LABEL enabled:
        stdx 3,11,9     
        nop
        bl .irq_enter  

Signed-off-by: Anton Blanchard &amp;lt;anton&amp;lt; at &amp;gt;samba.org&amp;gt;
---

Index: linux-build/arch/powerpc/configs/ppc64_defconfig
===================================================================
--- linux-build.orig/arch/powerpc/configs/ppc64_defconfig2012-04-05 13:47:45.691857096 +1000
+++ linux-build/arch/powerpc/configs/ppc64_defconfig2012-05-23 13:14:04.254270594 +1000
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -16,6 +16,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; CONFIG_BLK_DEV_INITRD=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=y
 CONFIG_KPROBES=y
+CONFIG_JUMP_LABEL=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
Index: linux-build/arch/powerpc/configs/pseries_defconfig
===================================================================
--- linux-build.orig/arch/powerpc/configs/pseries_defconfig2012-04-05 13:47:45.691857096 +1000
+++ linux-build/arch/powerpc/configs/pseries_defconfig2012-05-23 13:14:59.783222304 +1000
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -24,6 +24,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; CONFIG_BLK_DEV_INITRD=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=y
 CONFIG_KPROBES=y
+CONFIG_JUMP_LABEL=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 CONFIG_MODVERSIONS=y
&lt;/pre&gt;</description>
    <dc:creator>Anton Blanchard</dc:creator>
    <dc:date>2012-05-23T03:58:41</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82199">
    <title>powerc tree maintainership status</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82199</link>
    <description>&lt;pre&gt;Hi Folks !

I'm going to be getting some surgery next week. In the good case, I
should be officially back to work 2 weeks later, but I might end
up being unavailable for longer.

So while I'm away, Michael Ellerman and Paul Mackerras are going to take
care of the powerpc tree. I'll make sure Paul and I sign Michael's PGP
key before I leave.

Cheers,
Ben.
&lt;/pre&gt;</description>
    <dc:creator>Benjamin Herrenschmidt</dc:creator>
    <dc:date>2012-05-23T03:43:27</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82188">
    <title>Handling spin table in kdump</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82188</link>
    <description>&lt;pre&gt;Hi

I came across the following issue while testing Kdump on an SMP 
board(Currituck) running a non-SMP kernel. Even though the kernel is UP,
the device-tree has the nodes for second CPU and the related details.


The kexec tool adds the spin table area as a reserved section in the 
device tree for the dump capture kernel. This value is read from the 
'cpu-release-addr'.

But now, if the spin table is not located within the 'Reserved region' 
for the crash kernel, the dump capture kernel would fail to boot, 
hitting a BUG in mm/bootmem.c as in [1].

This is because we try to reserve a region which is not available to the 
kernel.

So I am wondering how is this handled really on an SMP board (Fsl_bookE).

There are two possible solutions :
1) Do not reserve the regions for the spin-table, as we will use
only the crashing CPU in the second kernel(maxcpus=1).


2) Add the spin-table region to the available memory regions passed
to the kernel by kexec-tools.

I have tested (1) and it works fine for me. Yet to test (2).


Thoughts ?


Thanks
Suzuki



[1] Kernel Bug
----------------


Linux version 3.3.0-rc5 (root&amp;lt; at &amp;gt;suzukikp.in.ibm.com) (gcc version 4.3.4 
[gcc-4_3-branch revision 152973] (GCC) ) #12 Tue May 22 18:03:01 IST2
Found legacy serial port 0 for /plb/opb/serial&amp;lt; at &amp;gt;10000000
   mem=20010000000, taddr=20010000000, irq=0, clk=1851851, speed=115200
------------[ cut here ]------------
kernel BUG at mm/bootmem.c:351!
Vector: 700 (Program Check) at [c8a61e90]
     pc: c847f91c: mark_bootmem+0xa0/0x14c
     lr: c8472670: do_init_bootmem+0x1ac/0x218
     sp: c8a61f40
    msr: 21000
   current = 0xc8a4a500
     pid   = 0, comm = swapper
kernel BUG at mm/bootmem.c:351!
enter ? for help
[c8a61f70] c8472670 do_init_bootmem+0x1ac/0x218
[c8a61f90] c847025c setup_arch+0x1bc/0x234
[c8a61fb0] c846b62c start_kernel+0x98/0x358
[c8a61ff0] c80000b4 _start+0xb4/0xf8
&lt;/pre&gt;</description>
    <dc:creator>Suzuki K. Poulose</dc:creator>
    <dc:date>2012-05-22T12:42:10</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82173">
    <title>powerpc -next rebase WARNING</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82173</link>
    <description>&lt;pre&gt;Folks, bad news ... my fault.

I accidentally forgot a --signoff on a git am command last week, meaning
that a pair of patches are in -next and not signed off by me.

For various (legal) reasons that cannot go into Linus tree as-is, so I
have to rebase the tree to fix it.

Sorry about that ...

Cheers,
Ben.
&lt;/pre&gt;</description>
    <dc:creator>Benjamin Herrenschmidt</dc:creator>
    <dc:date>2012-05-22T01:51:13</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82165">
    <title>RE: ppc/sata-fsl: orphan config value: CONFIG_MPC8315_DS</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82165</link>
    <description>&lt;pre&gt;


Thanks for bringing it up again.  Looks like we do have a problem here.

Btw, did it help with your problem by enabling it?

Leo
&lt;/pre&gt;</description>
    <dc:creator>Li Yang-R58472</dc:creator>
    <dc:date>2012-05-21T06:31:48</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82164">
    <title>Re: [PATCH] cpuidle: (POWER) Replace pseries_notify_cpuidle_add call with a elegant notifier to fix lockdep problem in start_secondary</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82164</link>
    <description>&lt;pre&gt;Hi Ben,

On 05/21/2012 06:17 AM, Benjamin Herrenschmidt wrote:


  In the current design disable and enable device are called
  when the cpu comes online. This is to make sure that we clean up and
  re-register again. All the counters are reset.

  Not calling cpu disable when cpu goes offline currently, would only
  retain the counters right now.

  But I could add a offline check and disable the device there, if that
  results in cleaner design.  I will test and send across the patch with
  couple more pseries-idle fixes soon.

  Thanks for your review comments !

&lt;/pre&gt;</description>
    <dc:creator>Deepthi Dharwar</dc:creator>
    <dc:date>2012-05-21T04:55:07</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82159">
    <title>Re: [PATCH] cpuidle: (POWER) Replace pseries_notify_cpuidle_add call with a elegant notifier to fix lockdep problem in start_secondary</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82159</link>
    <description>&lt;pre&gt;
Any reason why you don't do cpuidle_disable_device() when the
CPU is going offline and cpuidle_enable_device() when it's coming
back ?

I'm applying the patch for now since it fixes a real problem but
if the above makes sense, please send a followup fix.

Cheers,
Ben.

&lt;/pre&gt;</description>
    <dc:creator>Benjamin Herrenschmidt</dc:creator>
    <dc:date>2012-05-21T00:47:01</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82151">
    <title>[PATCH EDAC v26 02/66] edac: move dimm properties to struct dimm_info</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82151</link>
    <description>&lt;pre&gt;On systems based on chip select rows, all channels need to use memories
with the same properties, otherwise the memories on channels A and B
won't be recognized.

However, such assumption is not true for all types of memory
controllers.

Controllers for FB-DIMM's don't have such requirements.

Also, modern Intel controllers seem to be capable of handling such
differences.

So, we need to get rid of storing the DIMM information into a per-csrow
data, storing it, instead at the right place.

The first step is to move grain, mtype, dtype and edac_mode to the
per-dimm struct.

Reviewed-by: Aristeu Rozanski &amp;lt;arozansk&amp;lt; at &amp;gt;redhat.com&amp;gt;
Reviewed-by: Borislav Petkov &amp;lt;borislav.petkov&amp;lt; at &amp;gt;amd.com&amp;gt;
Acked-by: Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
Cc: Doug Thompson &amp;lt;norsk5&amp;lt; at &amp;gt;yahoo.com&amp;gt;
Cc: Borislav Petkov &amp;lt;borislav.petkov&amp;lt; at &amp;gt;amd.com&amp;gt;
Cc: Mark Gross &amp;lt;mark.gross&amp;lt; at &amp;gt;intel.com&amp;gt;
Cc: Jason Uhlenkott &amp;lt;juhlenko&amp;lt; at &amp;gt;akamai.com&amp;gt;
Cc: Tim Small &amp;lt;tim&amp;lt; at &amp;gt;buttersideup.com&amp;gt;
Cc: Ranganathan Desikan &amp;lt;ravi&amp;lt; at &amp;gt;jetztechnologies.com&amp;gt;
Cc: "Arvind R." &amp;lt;arvino55&amp;lt; at &amp;gt;gmail.com&amp;gt;
Cc: Olof Johansson &amp;lt;olof&amp;lt; at &amp;gt;lixom.net&amp;gt;
Cc: Egor Martovetsky &amp;lt;egor&amp;lt; at &amp;gt;pasemi.com&amp;gt;
Cc: Michal Marek &amp;lt;mmarek&amp;lt; at &amp;gt;suse.cz&amp;gt;
Cc: Jiri Kosina &amp;lt;jkosina&amp;lt; at &amp;gt;suse.cz&amp;gt;
Cc: Joe Perches &amp;lt;joe&amp;lt; at &amp;gt;perches.com&amp;gt;
Cc: Dmitry Eremin-Solenikov &amp;lt;dbaryshkov&amp;lt; at &amp;gt;gmail.com&amp;gt;
Cc: Benjamin Herrenschmidt &amp;lt;benh&amp;lt; at &amp;gt;kernel.crashing.org&amp;gt;
Cc: Hitoshi Mitake &amp;lt;h.mitake&amp;lt; at &amp;gt;gmail.com&amp;gt;
Cc: Andrew Morton &amp;lt;akpm&amp;lt; at &amp;gt;linux-foundation.org&amp;gt;
Cc: James Bottomley &amp;lt;James.Bottomley&amp;lt; at &amp;gt;parallels.com&amp;gt;
Cc: "Niklas Söderlund" &amp;lt;niklas.soderlund&amp;lt; at &amp;gt;ericsson.com&amp;gt;
Cc: Shaohui Xie &amp;lt;Shaohui.Xie&amp;lt; at &amp;gt;freescale.com&amp;gt;
Cc: Josh Boyer &amp;lt;jwboyer&amp;lt; at &amp;gt;gmail.com&amp;gt;
Cc: Mike Williams &amp;lt;mike&amp;lt; at &amp;gt;mikebwilliams.com&amp;gt;
Cc: linuxppc-dev&amp;lt; at &amp;gt;lists.ozlabs.org
Signed-off-by: Mauro Carvalho Chehab &amp;lt;mchehab&amp;lt; at &amp;gt;redhat.com&amp;gt;
---
 drivers/edac/amd64_edac.c      |   18 ++++++++----
 drivers/edac/amd76x_edac.c     |   10 ++++--
 drivers/edac/cell_edac.c       |   10 +++++-
 drivers/edac/cpc925_edac.c     |   62 +++++++++++++++++++++------------------
 drivers/edac/e752x_edac.c      |   44 +++++++++++++++-------------
 drivers/edac/e7xxx_edac.c      |   44 ++++++++++++++++------------
 drivers/edac/edac_mc.c         |   19 ++++++++----
 drivers/edac/edac_mc_sysfs.c   |    6 ++--
 drivers/edac/i3000_edac.c      |   18 ++++++-----
 drivers/edac/i3200_edac.c      |   18 ++++++-----
 drivers/edac/i5000_edac.c      |   24 +++++++--------
 drivers/edac/i5100_edac.c      |   38 +++++++++++++-----------
 drivers/edac/i5400_edac.c      |   24 ++++++---------
 drivers/edac/i7300_edac.c      |   25 +++++++++------
 drivers/edac/i7core_edac.c     |   27 ++++++++---------
 drivers/edac/i82443bxgx_edac.c |   13 +++++---
 drivers/edac/i82860_edac.c     |   11 ++++--
 drivers/edac/i82875p_edac.c    |   17 ++++++++---
 drivers/edac/i82975x_edac.c    |   17 +++++++----
 drivers/edac/mpc85xx_edac.c    |   13 +++++---
 drivers/edac/mv64x60_edac.c    |   18 ++++++-----
 drivers/edac/pasemi_edac.c     |   10 ++++--
 drivers/edac/ppc4xx_edac.c     |   13 +++++---
 drivers/edac/r82600_edac.c     |   10 ++++--
 drivers/edac/sb_edac.c         |   31 +++++++++++---------
 drivers/edac/tile_edac.c       |   13 ++++----
 drivers/edac/x38_edac.c        |   17 ++++++-----
 include/linux/edac.h           |   21 ++++++++-----
 28 files changed, 334 insertions(+), 257 deletions(-)

diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 7ef73c9..8126db0 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2187,7 +2187,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int init_csrows(struct mem_ctl_info *mci)
 struct amd64_pvt *pvt = mci-&amp;gt;pvt_info;
 u64 input_addr_min, input_addr_max, sys_addr, base, mask;
 u32 val;
-int i, empty = 1;
+int i, j, empty = 1;
+enum mem_type mtype;
+enum edac_type edac_mode;
 
 amd64_read_pci_cfg(pvt-&amp;gt;F3, NBCFG, &amp;amp;val);
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2224,7 +2226,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int init_csrows(struct mem_ctl_info *mci)
 csrow-&amp;gt;page_mask = ~mask;
 /* 8 bytes of resolution */
 
-csrow-&amp;gt;mtype = amd64_determine_memory_type(pvt, i);
+mtype = amd64_determine_memory_type(pvt, i);
 
 debugf1("  for MC node %d csrow %d:\n", pvt-&amp;gt;mc_node_id, i);
 debugf1("    input_addr_min: 0x%lx input_addr_max: 0x%lx\n",
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2241,11 +2243,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int init_csrows(struct mem_ctl_info *mci)
  * determine whether CHIPKILL or JUST ECC or NO ECC is operating
  */
 if (pvt-&amp;gt;nbcfg &amp;amp; NBCFG_ECC_ENABLE)
-csrow-&amp;gt;edac_mode =
-    (pvt-&amp;gt;nbcfg &amp;amp; NBCFG_CHIPKILL) ?
-    EDAC_S4ECD4ED : EDAC_SECDED;
+edac_mode = (pvt-&amp;gt;nbcfg &amp;amp; NBCFG_CHIPKILL) ?
+    EDAC_S4ECD4ED : EDAC_SECDED;
 else
-csrow-&amp;gt;edac_mode = EDAC_NONE;
+edac_mode = EDAC_NONE;
+
+for (j = 0; j &amp;lt; pvt-&amp;gt;channel_count; j++) {
+csrow-&amp;gt;channels[j].dimm-&amp;gt;mtype = mtype;
+csrow-&amp;gt;channels[j].dimm-&amp;gt;edac_mode = edac_mode;
+}
 }
 
 return empty;
diff --git a/drivers/edac/amd76x_edac.c b/drivers/edac/amd76x_edac.c
index f8fd3c8..fcfe359 100644
--- a/drivers/edac/amd76x_edac.c
+++ b/drivers/edac/amd76x_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -186,11 +186,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 enum edac_type edac_mode)
 {
 struct csrow_info *csrow;
+struct dimm_info *dimm;
 u32 mba, mba_base, mba_mask, dms;
 int index;
 
 for (index = 0; index &amp;lt; mci-&amp;gt;nr_csrows; index++) {
 csrow = &amp;amp;mci-&amp;gt;csrows[index];
+dimm = csrow-&amp;gt;channels[0].dimm;
 
 /* find the DRAM Chip Select Base address and mask */
 pci_read_config_dword(pdev,
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -206,10 +208,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void amd76x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 csrow-&amp;gt;nr_pages = (mba_mask + 1) &amp;gt;&amp;gt; PAGE_SHIFT;
 csrow-&amp;gt;last_page = csrow-&amp;gt;first_page + csrow-&amp;gt;nr_pages - 1;
 csrow-&amp;gt;page_mask = mba_mask &amp;gt;&amp;gt; PAGE_SHIFT;
-csrow-&amp;gt;grain = csrow-&amp;gt;nr_pages &amp;lt;&amp;lt; PAGE_SHIFT;
-csrow-&amp;gt;mtype = MEM_RDDR;
-csrow-&amp;gt;dtype = ((dms &amp;gt;&amp;gt; index) &amp;amp; 0x1) ? DEV_X4 : DEV_UNKNOWN;
-csrow-&amp;gt;edac_mode = edac_mode;
+dimm-&amp;gt;grain = csrow-&amp;gt;nr_pages &amp;lt;&amp;lt; PAGE_SHIFT;
+dimm-&amp;gt;mtype = MEM_RDDR;
+dimm-&amp;gt;dtype = ((dms &amp;gt;&amp;gt; index) &amp;amp; 0x1) ? DEV_X4 : DEV_UNKNOWN;
+dimm-&amp;gt;edac_mode = edac_mode;
 }
 }
 
diff --git a/drivers/edac/cell_edac.c b/drivers/edac/cell_edac.c
index 9a6a274..94fbb12 100644
--- a/drivers/edac/cell_edac.c
+++ b/drivers/edac/cell_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -124,8 +124,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void cell_edac_check(struct mem_ctl_info *mci)
 static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
 {
 struct csrow_info*csrow = &amp;amp;mci-&amp;gt;csrows[0];
+struct dimm_info*dimm;
 struct cell_edac_priv*priv = mci-&amp;gt;pvt_info;
 struct device_node*np;
+intj;
 
 for (np = NULL;
      (np = of_find_node_by_name(np, "memory")) != NULL;) {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -142,8 +144,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void __devinit cell_edac_init_csrows(struct mem_ctl_info *mci)
 csrow-&amp;gt;first_page = r.start &amp;gt;&amp;gt; PAGE_SHIFT;
 csrow-&amp;gt;nr_pages = resource_size(&amp;amp;r) &amp;gt;&amp;gt; PAGE_SHIFT;
 csrow-&amp;gt;last_page = csrow-&amp;gt;first_page + csrow-&amp;gt;nr_pages - 1;
-csrow-&amp;gt;mtype = MEM_XDR;
-csrow-&amp;gt;edac_mode = EDAC_SECDED;
+
+for (j = 0; j &amp;lt; csrow-&amp;gt;nr_channels; j++) {
+dimm = csrow-&amp;gt;channels[j].dimm;
+dimm-&amp;gt;mtype = MEM_XDR;
+dimm-&amp;gt;edac_mode = EDAC_SECDED;
+}
 dev_dbg(mci-&amp;gt;dev,
 "Initialized on node %d, chanmask=0x%x,"
 " first_page=0x%lx, nr_pages=0x%x\n",
diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c
index a774c0d..ee90f3d 100644
--- a/drivers/edac/cpc925_edac.c
+++ b/drivers/edac/cpc925_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -329,7 +329,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void cpc925_init_csrows(struct mem_ctl_info *mci)
 {
 struct cpc925_mc_pdata *pdata = mci-&amp;gt;pvt_info;
 struct csrow_info *csrow;
-int index;
+struct dimm_info *dimm;
+int index, j;
 u32 mbmr, mbbar, bba;
 unsigned long row_size, last_nr_pages = 0;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -354,32 +355,35 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void cpc925_init_csrows(struct mem_ctl_info *mci)
 csrow-&amp;gt;last_page = csrow-&amp;gt;first_page + csrow-&amp;gt;nr_pages - 1;
 last_nr_pages = csrow-&amp;gt;last_page + 1;
 
-csrow-&amp;gt;mtype = MEM_RDDR;
-csrow-&amp;gt;edac_mode = EDAC_SECDED;
-
-switch (csrow-&amp;gt;nr_channels) {
-case 1: /* Single channel */
-csrow-&amp;gt;grain = 32; /* four-beat burst of 32 bytes */
-break;
-case 2: /* Dual channel */
-default:
-csrow-&amp;gt;grain = 64; /* four-beat burst of 64 bytes */
-break;
-}
-
-switch ((mbmr &amp;amp; MBMR_MODE_MASK) &amp;gt;&amp;gt; MBMR_MODE_SHIFT) {
-case 6: /* 0110, no way to differentiate X8 VS X16 */
-case 5:/* 0101 */
-case 8: /* 1000 */
-csrow-&amp;gt;dtype = DEV_X16;
-break;
-case 7: /* 0111 */
-case 9: /* 1001 */
-csrow-&amp;gt;dtype = DEV_X8;
-break;
-default:
-csrow-&amp;gt;dtype = DEV_UNKNOWN;
-break;
+for (j = 0; j &amp;lt; csrow-&amp;gt;nr_channels; j++) {
+dimm = csrow-&amp;gt;channels[j].dimm;
+dimm-&amp;gt;mtype = MEM_RDDR;
+dimm-&amp;gt;edac_mode = EDAC_SECDED;
+
+switch (csrow-&amp;gt;nr_channels) {
+case 1: /* Single channel */
+dimm-&amp;gt;grain = 32; /* four-beat burst of 32 bytes */
+break;
+case 2: /* Dual channel */
+default:
+dimm-&amp;gt;grain = 64; /* four-beat burst of 64 bytes */
+break;
+}
+
+switch ((mbmr &amp;amp; MBMR_MODE_MASK) &amp;gt;&amp;gt; MBMR_MODE_SHIFT) {
+case 6: /* 0110, no way to differentiate X8 VS X16 */
+case 5:/* 0101 */
+case 8: /* 1000 */
+dimm-&amp;gt;dtype = DEV_X16;
+break;
+case 7: /* 0111 */
+case 9: /* 1001 */
+dimm-&amp;gt;dtype = DEV_X8;
+break;
+default:
+dimm-&amp;gt;dtype = DEV_UNKNOWN;
+break;
+}
 }
 }
 }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -962,9 +966,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int __devinit cpc925_probe(struct platform_device *pdev)
 goto err2;
 }
 
-nr_channels = cpc925_mc_get_channels(vbase);
+nr_channels = cpc925_mc_get_channels(vbase) + 1;
 mci = edac_mc_alloc(sizeof(struct cpc925_mc_pdata),
-CPC925_NR_CSROWS, nr_channels + 1, edac_mc_idx);
+CPC925_NR_CSROWS, nr_channels, edac_mc_idx);
 if (!mci) {
 cpc925_printk(KERN_ERR, "No memory for mem_ctl_info\n");
 res = -ENOMEM;
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c
index 4122326..6cf6ec6 100644
--- a/drivers/edac/e752x_edac.c
+++ b/drivers/edac/e752x_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1044,7 +1044,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 int drc_drbg;/* DRB granularity 0=64mb, 1=128mb */
 int drc_ddim;/* DRAM Data Integrity Mode 0=none, 2=edac */
 u8 value;
-u32 dra, drc, cumul_size;
+u32 dra, drc, cumul_size, i;
 
 dra = 0;
 for (index = 0; index &amp;lt; 4; index++) {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1053,7 +1053,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 dra |= dra_reg &amp;lt;&amp;lt; (index * 8);
 }
 pci_read_config_dword(pdev, E752X_DRC, &amp;amp;drc);
-drc_chan = dual_channel_active(ddrcsr);
+drc_chan = dual_channel_active(ddrcsr) ? 1 : 0;
 drc_drbg = drc_chan + 1;/* 128 in dual mode, 64 in single */
 drc_ddim = (drc &amp;gt;&amp;gt; 20) &amp;amp; 0x3;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1080,24 +1080,28 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void e752x_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 csrow-&amp;gt;last_page = cumul_size - 1;
 csrow-&amp;gt;nr_pages = cumul_size - last_cumul_size;
 last_cumul_size = cumul_size;
-csrow-&amp;gt;grain = 1 &amp;lt;&amp;lt; 12;/* 4KiB - resolution of CELOG */
-csrow-&amp;gt;mtype = MEM_RDDR;/* only one type supported */
-csrow-&amp;gt;dtype = mem_dev ? DEV_X4 : DEV_X8;
-
-/*
- * if single channel or x8 devices then SECDED
- * if dual channel and x4 then S4ECD4ED
- */
-if (drc_ddim) {
-if (drc_chan &amp;amp;&amp;amp; mem_dev) {
-csrow-&amp;gt;edac_mode = EDAC_S4ECD4ED;
-mci-&amp;gt;edac_cap |= EDAC_FLAG_S4ECD4ED;
-} else {
-csrow-&amp;gt;edac_mode = EDAC_SECDED;
-mci-&amp;gt;edac_cap |= EDAC_FLAG_SECDED;
-}
-} else
-csrow-&amp;gt;edac_mode = EDAC_NONE;
+
+for (i = 0; i &amp;lt; drc_chan + 1; i++) {
+struct dimm_info *dimm = csrow-&amp;gt;channels[i].dimm;
+dimm-&amp;gt;grain = 1 &amp;lt;&amp;lt; 12;/* 4KiB - resolution of CELOG */
+dimm-&amp;gt;mtype = MEM_RDDR;/* only one type supported */
+dimm-&amp;gt;dtype = mem_dev ? DEV_X4 : DEV_X8;
+
+/*
+* if single channel or x8 devices then SECDED
+* if dual channel and x4 then S4ECD4ED
+*/
+if (drc_ddim) {
+if (drc_chan &amp;amp;&amp;amp; mem_dev) {
+dimm-&amp;gt;edac_mode = EDAC_S4ECD4ED;
+mci-&amp;gt;edac_cap |= EDAC_FLAG_S4ECD4ED;
+} else {
+dimm-&amp;gt;edac_mode = EDAC_SECDED;
+mci-&amp;gt;edac_cap |= EDAC_FLAG_SECDED;
+}
+} else
+dimm-&amp;gt;edac_mode = EDAC_NONE;
+}
 }
 }
 
diff --git a/drivers/edac/e7xxx_edac.c b/drivers/edac/e7xxx_edac.c
index 68dea87..5ed97f6 100644
--- a/drivers/edac/e7xxx_edac.c
+++ b/drivers/edac/e7xxx_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -347,11 +347,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 int dev_idx, u32 drc)
 {
 unsigned long last_cumul_size;
-int index;
+int index, j;
 u8 value;
 u32 dra, cumul_size;
 int drc_chan, drc_drbg, drc_ddim, mem_dev;
 struct csrow_info *csrow;
+struct dimm_info *dimm;
 
 pci_read_config_dword(pdev, E7XXX_DRA, &amp;amp;dra);
 drc_chan = dual_channel_active(drc, dev_idx);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -381,24 +382,29 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void e7xxx_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 csrow-&amp;gt;last_page = cumul_size - 1;
 csrow-&amp;gt;nr_pages = cumul_size - last_cumul_size;
 last_cumul_size = cumul_size;
-csrow-&amp;gt;grain = 1 &amp;lt;&amp;lt; 12;/* 4KiB - resolution of CELOG */
-csrow-&amp;gt;mtype = MEM_RDDR;/* only one type supported */
-csrow-&amp;gt;dtype = mem_dev ? DEV_X4 : DEV_X8;
-
-/*
- * if single channel or x8 devices then SECDED
- * if dual channel and x4 then S4ECD4ED
- */
-if (drc_ddim) {
-if (drc_chan &amp;amp;&amp;amp; mem_dev) {
-csrow-&amp;gt;edac_mode = EDAC_S4ECD4ED;
-mci-&amp;gt;edac_cap |= EDAC_FLAG_S4ECD4ED;
-} else {
-csrow-&amp;gt;edac_mode = EDAC_SECDED;
-mci-&amp;gt;edac_cap |= EDAC_FLAG_SECDED;
-}
-} else
-csrow-&amp;gt;edac_mode = EDAC_NONE;
+
+for (j = 0; j &amp;lt; drc_chan + 1; j++) {
+dimm = csrow-&amp;gt;channels[j].dimm;
+
+dimm-&amp;gt;grain = 1 &amp;lt;&amp;lt; 12;/* 4KiB - resolution of CELOG */
+dimm-&amp;gt;mtype = MEM_RDDR;/* only one type supported */
+dimm-&amp;gt;dtype = mem_dev ? DEV_X4 : DEV_X8;
+
+/*
+* if single channel or x8 devices then SECDED
+* if dual channel and x4 then S4ECD4ED
+*/
+if (drc_ddim) {
+if (drc_chan &amp;amp;&amp;amp; mem_dev) {
+dimm-&amp;gt;edac_mode = EDAC_S4ECD4ED;
+mci-&amp;gt;edac_cap |= EDAC_FLAG_S4ECD4ED;
+} else {
+dimm-&amp;gt;edac_mode = EDAC_SECDED;
+mci-&amp;gt;edac_cap |= EDAC_FLAG_SECDED;
+}
+} else
+dimm-&amp;gt;edac_mode = EDAC_NONE;
+}
 }
 }
 
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index c1aae72..0942efa 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -43,7 +43,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void edac_mc_dump_channel(struct rank_info *chan)
 {
 debugf4("\tchannel = %p\n", chan);
 debugf4("\tchannel-&amp;gt;chan_idx = %d\n", chan-&amp;gt;chan_idx);
-debugf4("\tchannel-&amp;gt;ce_count = %d\n", chan-&amp;gt;ce_count);
+debugf4("\tchannel-&amp;gt;ce_count = %d\n", chan-&amp;gt;dimm-&amp;gt;ce_count);
 debugf4("\tchannel-&amp;gt;label = '%s'\n", chan-&amp;gt;dimm-&amp;gt;label);
 debugf4("\tchannel-&amp;gt;csrow = %p\n\n", chan-&amp;gt;csrow);
 }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -695,6 +695,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void edac_mc_handle_ce(struct mem_ctl_info *mci,
 {
 unsigned long remapped_page;
 char *label = NULL;
+u32 grain;
 
 debugf3("MC%d: %s()\n", mci-&amp;gt;mc_idx, __func__);
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -719,6 +720,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void edac_mc_handle_ce(struct mem_ctl_info *mci,
 }
 
 label = mci-&amp;gt;csrows[row].channels[channel].dimm-&amp;gt;label;
+grain = mci-&amp;gt;csrows[row].channels[channel].dimm-&amp;gt;grain;
 
 if (edac_mc_get_log_ce())
 /* FIXME - put in DIMM location */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -726,11 +728,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void edac_mc_handle_ce(struct mem_ctl_info *mci,
 "CE page 0x%lx, offset 0x%lx, grain %d, syndrome "
 "0x%lx, row %d, channel %d, label \"%s\": %s\n",
 page_frame_number, offset_in_page,
-mci-&amp;gt;csrows[row].grain, syndrome, row, channel,
+grain, syndrome, row, channel,
 label, msg);
 
 mci-&amp;gt;ce_count++;
 mci-&amp;gt;csrows[row].ce_count++;
+mci-&amp;gt;csrows[row].channels[channel].dimm-&amp;gt;ce_count++;
 mci-&amp;gt;csrows[row].channels[channel].ce_count++;
 
 if (mci-&amp;gt;scrub_mode &amp;amp; SCRUB_SW_SRC) {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -747,8 +750,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void edac_mc_handle_ce(struct mem_ctl_info *mci,
 mci-&amp;gt;ctl_page_to_phys(mci, page_frame_number) :
 page_frame_number;
 
-edac_mc_scrub_block(remapped_page, offset_in_page,
-mci-&amp;gt;csrows[row].grain);
+edac_mc_scrub_block(remapped_page, offset_in_page, grain);
 }
 }
 EXPORT_SYMBOL_GPL(edac_mc_handle_ce);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -774,6 +776,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void edac_mc_handle_ue(struct mem_ctl_info *mci,
 int chan;
 int chars;
 char *label = NULL;
+u32 grain;
 
 debugf3("MC%d: %s()\n", mci-&amp;gt;mc_idx, __func__);
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -787,6 +790,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void edac_mc_handle_ue(struct mem_ctl_info *mci,
 return;
 }
 
+grain = mci-&amp;gt;csrows[row].channels[0].dimm-&amp;gt;grain;
 label = mci-&amp;gt;csrows[row].channels[0].dimm-&amp;gt;label;
 chars = snprintf(pos, len + 1, "%s", label);
 len -= chars;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -804,14 +808,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void edac_mc_handle_ue(struct mem_ctl_info *mci,
 edac_mc_printk(mci, KERN_EMERG,
 "UE page 0x%lx, offset 0x%lx, grain %d, row %d, "
 "labels \"%s\": %s\n", page_frame_number,
-offset_in_page, mci-&amp;gt;csrows[row].grain, row,
-labels, msg);
+offset_in_page, grain, row, labels, msg);
 
 if (edac_mc_get_panic_on_ue())
 panic("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, "
 "row %d, labels \"%s\": %s\n", mci-&amp;gt;mc_idx,
 page_frame_number, offset_in_page,
-mci-&amp;gt;csrows[row].grain, row, labels, msg);
+grain, row, labels, msg);
 
 mci-&amp;gt;ue_count++;
 mci-&amp;gt;csrows[row].ue_count++;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -883,6 +886,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
 chars = snprintf(pos, len + 1, "%s", label);
 len -= chars;
 pos += chars;
+
 chars = snprintf(pos, len + 1, "-%s",
 mci-&amp;gt;csrows[csrow].channels[channelb].dimm-&amp;gt;label);
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -936,6 +940,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
 
 mci-&amp;gt;ce_count++;
 mci-&amp;gt;csrows[csrow].ce_count++;
+mci-&amp;gt;csrows[csrow].channels[channel].dimm-&amp;gt;ce_count++;
 mci-&amp;gt;csrows[csrow].channels[channel].ce_count++;
 }
 EXPORT_SYMBOL(edac_mc_handle_fbd_ce);
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index af66b22..487e03e 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -150,19 +150,19 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static ssize_t csrow_size_show(struct csrow_info *csrow, char *data,
 static ssize_t csrow_mem_type_show(struct csrow_info *csrow, char *data,
 int private)
 {
-return sprintf(data, "%s\n", mem_types[csrow-&amp;gt;mtype]);
+return sprintf(data, "%s\n", mem_types[csrow-&amp;gt;channels[0].dimm-&amp;gt;mtype]);
 }
 
 static ssize_t csrow_dev_type_show(struct csrow_info *csrow, char *data,
 int private)
 {
-return sprintf(data, "%s\n", dev_types[csrow-&amp;gt;dtype]);
+return sprintf(data, "%s\n", dev_types[csrow-&amp;gt;channels[0].dimm-&amp;gt;dtype]);
 }
 
 static ssize_t csrow_edac_mode_show(struct csrow_info *csrow, char *data,
 int private)
 {
-return sprintf(data, "%s\n", edac_caps[csrow-&amp;gt;edac_mode]);
+return sprintf(data, "%s\n", edac_caps[csrow-&amp;gt;channels[0].dimm-&amp;gt;edac_mode]);
 }
 
 /* show/store functions for DIMM Label attributes */
diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c
index 277689a..8fe60ee 100644
--- a/drivers/edac/i3000_edac.c
+++ b/drivers/edac/i3000_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -304,7 +304,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int i3000_is_interleaved(const unsigned char *c0dra,
 static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
 {
 int rc;
-int i;
+int i, j;
 struct mem_ctl_info *mci = NULL;
 unsigned long last_cumul_size;
 int interleaved, nr_channels;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -386,19 +386,21 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int i3000_probe1(struct pci_dev *pdev, int dev_idx)
 cumul_size &amp;lt;&amp;lt;= 1;
 debugf3("MC: %s(): (%d) cumul_size 0x%x\n",
 __func__, i, cumul_size);
-if (cumul_size == last_cumul_size) {
-csrow-&amp;gt;mtype = MEM_EMPTY;
+if (cumul_size == last_cumul_size)
 continue;
-}
 
 csrow-&amp;gt;first_page = last_cumul_size;
 csrow-&amp;gt;last_page = cumul_size - 1;
 csrow-&amp;gt;nr_pages = cumul_size - last_cumul_size;
 last_cumul_size = cumul_size;
-csrow-&amp;gt;grain = I3000_DEAP_GRAIN;
-csrow-&amp;gt;mtype = MEM_DDR2;
-csrow-&amp;gt;dtype = DEV_UNKNOWN;
-csrow-&amp;gt;edac_mode = EDAC_UNKNOWN;
+
+for (j = 0; j &amp;lt; nr_channels; j++) {
+struct dimm_info *dimm = csrow-&amp;gt;channels[j].dimm;
+dimm-&amp;gt;grain = I3000_DEAP_GRAIN;
+dimm-&amp;gt;mtype = MEM_DDR2;
+dimm-&amp;gt;dtype = DEV_UNKNOWN;
+dimm-&amp;gt;edac_mode = EDAC_UNKNOWN;
+}
 }
 
 /*
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c
index 046808c..6ae3017 100644
--- a/drivers/edac/i3200_edac.c
+++ b/drivers/edac/i3200_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -319,7 +319,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static unsigned long drb_to_nr_pages(
 static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
 {
 int rc;
-int i;
+int i, j;
 struct mem_ctl_info *mci = NULL;
 unsigned long last_page;
 u16 drbs[I3200_CHANNELS][I3200_RANKS_PER_CHANNEL];
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -375,20 +375,22 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int i3200_probe1(struct pci_dev *pdev, int dev_idx)
 i / I3200_RANKS_PER_CHANNEL,
 i % I3200_RANKS_PER_CHANNEL);
 
-if (nr_pages == 0) {
-csrow-&amp;gt;mtype = MEM_EMPTY;
+if (nr_pages == 0)
 continue;
-}
 
 csrow-&amp;gt;first_page = last_page + 1;
 last_page += nr_pages;
 csrow-&amp;gt;last_page = last_page;
 csrow-&amp;gt;nr_pages = nr_pages;
 
-csrow-&amp;gt;grain = nr_pages &amp;lt;&amp;lt; PAGE_SHIFT;
-csrow-&amp;gt;mtype = MEM_DDR2;
-csrow-&amp;gt;dtype = DEV_UNKNOWN;
-csrow-&amp;gt;edac_mode = EDAC_UNKNOWN;
+for (j = 0; j &amp;lt; nr_channels; j++) {
+struct dimm_info *dimm = csrow-&amp;gt;channels[j].dimm;
+
+dimm-&amp;gt;grain = nr_pages &amp;lt;&amp;lt; PAGE_SHIFT;
+dimm-&amp;gt;mtype = MEM_DDR2;
+dimm-&amp;gt;dtype = DEV_UNKNOWN;
+dimm-&amp;gt;edac_mode = EDAC_UNKNOWN;
+}
 }
 
 i3200_clear_error_info(mci);
diff --git a/drivers/edac/i5000_edac.c b/drivers/edac/i5000_edac.c
index a2680d8..95966ba 100644
--- a/drivers/edac/i5000_edac.c
+++ b/drivers/edac/i5000_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1268,25 +1268,23 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int i5000_init_csrows(struct mem_ctl_info *mci)
 p_csrow-&amp;gt;last_page = 9 + csrow * 20;
 p_csrow-&amp;gt;page_mask = 0xFFF;
 
-p_csrow-&amp;gt;grain = 8;
-
 csrow_megs = 0;
 for (channel = 0; channel &amp;lt; pvt-&amp;gt;maxch; channel++) {
 csrow_megs += pvt-&amp;gt;dimm_info[csrow][channel].megabytes;
-}
+p_csrow-&amp;gt;channels[channel].dimm-&amp;gt;grain = 8;
 
-p_csrow-&amp;gt;nr_pages = csrow_megs &amp;lt;&amp;lt; 8;
+/* Assume DDR2 for now */
+p_csrow-&amp;gt;channels[channel].dimm-&amp;gt;mtype = MEM_FB_DDR2;
 
-/* Assume DDR2 for now */
-p_csrow-&amp;gt;mtype = MEM_FB_DDR2;
+/* ask what device type on this row */
+if (MTR_DRAM_WIDTH(mtr))
+p_csrow-&amp;gt;channels[channel].dimm-&amp;gt;dtype = DEV_X8;
+else
+p_csrow-&amp;gt;channels[channel].dimm-&amp;gt;dtype = DEV_X4;
 
-/* ask what device type on this row */
-if (MTR_DRAM_WIDTH(mtr))
-p_csrow-&amp;gt;dtype = DEV_X8;
-else
-p_csrow-&amp;gt;dtype = DEV_X4;
-
-p_csrow-&amp;gt;edac_mode = EDAC_S8ECD8ED;
+p_csrow-&amp;gt;channels[channel].dimm-&amp;gt;edac_mode = EDAC_S8ECD8ED;
+}
+p_csrow-&amp;gt;nr_pages = csrow_megs &amp;lt;&amp;lt; 8;
 
 empty = 0;
 }
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c
index d55e552..6c0dafa 100644
--- a/drivers/edac/i5100_edac.c
+++ b/drivers/edac/i5100_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -428,12 +428,16 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void i5100_handle_ce(struct mem_ctl_info *mci,
     const char *msg)
 {
 const int csrow = i5100_rank_to_csrow(mci, chan, rank);
+char *label = NULL;
+
+if (mci-&amp;gt;csrows[csrow].channels[0].dimm)
+label = mci-&amp;gt;csrows[csrow].channels[0].dimm-&amp;gt;label;
 
 printk(KERN_ERR
 "CE chan %d, bank %u, rank %u, syndrome 0x%lx, "
 "cas %u, ras %u, csrow %u, label \"%s\": %s\n",
 chan, bank, rank, syndrome, cas, ras,
-csrow, mci-&amp;gt;csrows[csrow].channels[0].dimm-&amp;gt;label, msg);
+csrow, label, msg);
 
 mci-&amp;gt;ce_count++;
 mci-&amp;gt;csrows[csrow].ce_count++;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -450,12 +454,16 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void i5100_handle_ue(struct mem_ctl_info *mci,
     const char *msg)
 {
 const int csrow = i5100_rank_to_csrow(mci, chan, rank);
+char *label = NULL;
+
+if (mci-&amp;gt;csrows[csrow].channels[0].dimm)
+label = mci-&amp;gt;csrows[csrow].channels[0].dimm-&amp;gt;label;
 
 printk(KERN_ERR
 "UE chan %d, bank %u, rank %u, syndrome 0x%lx, "
 "cas %u, ras %u, csrow %u, label \"%s\": %s\n",
 chan, bank, rank, syndrome, cas, ras,
-csrow, mci-&amp;gt;csrows[csrow].channels[0].dimm-&amp;gt;label, msg);
+csrow, label, msg);
 
 mci-&amp;gt;ue_count++;
 mci-&amp;gt;csrows[csrow].ue_count++;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -837,6 +845,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void __devinit i5100_init_csrows(struct mem_ctl_info *mci)
 int i;
 unsigned long total_pages = 0UL;
 struct i5100_priv *priv = mci-&amp;gt;pvt_info;
+struct dimm_info *dimm;
 
 for (i = 0; i &amp;lt; mci-&amp;gt;nr_csrows; i++) {
 const unsigned long npages = i5100_npages(mci, i);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -852,27 +861,22 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void __devinit i5100_init_csrows(struct mem_ctl_info *mci)
  */
 mci-&amp;gt;csrows[i].first_page = total_pages;
 mci-&amp;gt;csrows[i].last_page = total_pages + npages - 1;
-mci-&amp;gt;csrows[i].page_mask = 0UL;
-
 mci-&amp;gt;csrows[i].nr_pages = npages;
-mci-&amp;gt;csrows[i].grain = 32;
 mci-&amp;gt;csrows[i].csrow_idx = i;
-mci-&amp;gt;csrows[i].dtype =
-(priv-&amp;gt;mtr[chan][rank].width == 4) ? DEV_X4 : DEV_X8;
-mci-&amp;gt;csrows[i].ue_count = 0;
-mci-&amp;gt;csrows[i].ce_count = 0;
-mci-&amp;gt;csrows[i].mtype = MEM_RDDR2;
-mci-&amp;gt;csrows[i].edac_mode = EDAC_SECDED;
 mci-&amp;gt;csrows[i].mci = mci;
 mci-&amp;gt;csrows[i].nr_channels = 1;
-mci-&amp;gt;csrows[i].channels[0].chan_idx = 0;
-mci-&amp;gt;csrows[i].channels[0].ce_count = 0;
 mci-&amp;gt;csrows[i].channels[0].csrow = mci-&amp;gt;csrows + i;
-snprintf(mci-&amp;gt;csrows[i].channels[0].dimm-&amp;gt;label,
- sizeof(mci-&amp;gt;csrows[i].channels[0].dimm-&amp;gt;label),
- "DIMM%u", i5100_rank_to_slot(mci, chan, rank));
-
 total_pages += npages;
+
+dimm = mci-&amp;gt;csrows[i].channels[0].dimm;
+dimm-&amp;gt;grain = 32;
+dimm-&amp;gt;dtype = (priv-&amp;gt;mtr[chan][rank].width == 4) ?
+      DEV_X4 : DEV_X8;
+dimm-&amp;gt;mtype = MEM_RDDR2;
+dimm-&amp;gt;edac_mode = EDAC_SECDED;
+snprintf(dimm-&amp;gt;label, sizeof(dimm-&amp;gt;label),
+ "DIMM%u",
+ i5100_rank_to_slot(mci, chan, rank));
 }
 }
 
diff --git a/drivers/edac/i5400_edac.c b/drivers/edac/i5400_edac.c
index 1869a10..c2379ba 100644
--- a/drivers/edac/i5400_edac.c
+++ b/drivers/edac/i5400_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1159,6 +1159,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int i5400_init_csrows(struct mem_ctl_info *mci)
 int csrow_megs;
 int channel;
 int csrow;
+struct dimm_info *dimm;
 
 pvt = mci-&amp;gt;pvt_info;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1184,24 +1185,17 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int i5400_init_csrows(struct mem_ctl_info *mci)
 p_csrow-&amp;gt;last_page = 9 + csrow * 20;
 p_csrow-&amp;gt;page_mask = 0xFFF;
 
-p_csrow-&amp;gt;grain = 8;
-
 csrow_megs = 0;
-for (channel = 0; channel &amp;lt; pvt-&amp;gt;maxch; channel++)
+for (channel = 0; channel &amp;lt; pvt-&amp;gt;maxch; channel++) {
 csrow_megs += pvt-&amp;gt;dimm_info[csrow][channel].megabytes;
 
-p_csrow-&amp;gt;nr_pages = csrow_megs &amp;lt;&amp;lt; 8;
-
-/* Assume DDR2 for now */
-p_csrow-&amp;gt;mtype = MEM_FB_DDR2;
-
-/* ask what device type on this row */
-if (MTR_DRAM_WIDTH(mtr))
-p_csrow-&amp;gt;dtype = DEV_X8;
-else
-p_csrow-&amp;gt;dtype = DEV_X4;
-
-p_csrow-&amp;gt;edac_mode = EDAC_S8ECD8ED;
+p_csrow-&amp;gt;nr_pages = csrow_megs &amp;lt;&amp;lt; 8;
+dimm = p_csrow-&amp;gt;channels[channel].dimm;
+dimm-&amp;gt;grain = 8;
+dimm-&amp;gt;dtype = MTR_DRAM_WIDTH(mtr) ? DEV_X8 : DEV_X4;
+dimm-&amp;gt;mtype = MEM_RDDR2;
+dimm-&amp;gt;edac_mode = EDAC_SECDED;
+}
 
 empty = 0;
 }
diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c
index 3bafa3b..4bfcb3d 100644
--- a/drivers/edac/i7300_edac.c
+++ b/drivers/edac/i7300_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -618,6 +618,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int decode_mtr(struct i7300_pvt *pvt,
       int slot, int ch, int branch,
       struct i7300_dimm_info *dinfo,
       struct csrow_info *p_csrow,
+      struct dimm_info *dimm,
       u32 *nr_pages)
 {
 int mtr, ans, addrBits, channel;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -663,10 +664,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int decode_mtr(struct i7300_pvt *pvt,
 debugf2("\t\tNUMCOL: %s\n", numcol_toString[MTR_DIMM_COLS(mtr)]);
 debugf2("\t\tSIZE: %d MB\n", dinfo-&amp;gt;megabytes);
 
-p_csrow-&amp;gt;grain = 8;
-p_csrow-&amp;gt;mtype = MEM_FB_DDR2;
 p_csrow-&amp;gt;csrow_idx = slot;
-p_csrow-&amp;gt;page_mask = 0;
 
 /*
  * The type of error detection actually depends of the
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -677,15 +675,17 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int decode_mtr(struct i7300_pvt *pvt,
  * See datasheet Sections 7.3.6 to 7.3.8
  */
 
+dimm-&amp;gt;grain = 8;
+dimm-&amp;gt;mtype = MEM_FB_DDR2;
 if (IS_SINGLE_MODE(pvt-&amp;gt;mc_settings_a)) {
-p_csrow-&amp;gt;edac_mode = EDAC_SECDED;
+dimm-&amp;gt;edac_mode = EDAC_SECDED;
 debugf2("\t\tECC code is 8-byte-over-32-byte SECDED+ code\n");
 } else {
 debugf2("\t\tECC code is on Lockstep mode\n");
 if (MTR_DRAM_WIDTH(mtr) == 8)
-p_csrow-&amp;gt;edac_mode = EDAC_S8ECD8ED;
+dimm-&amp;gt;edac_mode = EDAC_S8ECD8ED;
 else
-p_csrow-&amp;gt;edac_mode = EDAC_S4ECD4ED;
+dimm-&amp;gt;edac_mode = EDAC_S4ECD4ED;
 }
 
 /* ask what device type on this row */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -694,9 +694,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int decode_mtr(struct i7300_pvt *pvt,
 IS_SCRBALGO_ENHANCED(pvt-&amp;gt;mc_settings) ?
     "enhanced" : "normal");
 
-p_csrow-&amp;gt;dtype = DEV_X8;
+dimm-&amp;gt;dtype = DEV_X8;
 } else
-p_csrow-&amp;gt;dtype = DEV_X4;
+dimm-&amp;gt;dtype = DEV_X4;
 
 return mtr;
 }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -779,6 +779,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int i7300_init_csrows(struct mem_ctl_info *mci)
 int mtr;
 int ch, branch, slot, channel;
 u32 last_page = 0, nr_pages;
+struct dimm_info *dimm;
 
 pvt = mci-&amp;gt;pvt_info;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -803,20 +804,24 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int i7300_init_csrows(struct mem_ctl_info *mci)
 }
 
 /* Get the set of MTR[0-7] regs by each branch */
+nr_pages = 0;
 for (slot = 0; slot &amp;lt; MAX_SLOTS; slot++) {
 int where = mtr_regs[slot];
 for (branch = 0; branch &amp;lt; MAX_BRANCHES; branch++) {
 pci_read_config_word(pvt-&amp;gt;pci_dev_2x_0_fbd_branch[branch],
 where,
 &amp;amp;pvt-&amp;gt;mtr[slot][branch]);
-for (ch = 0; ch &amp;lt; MAX_BRANCHES; ch++) {
+for (ch = 0; ch &amp;lt; MAX_CH_PER_BRANCH; ch++) {
 int channel = to_channel(ch, branch);
 
 dinfo = &amp;amp;pvt-&amp;gt;dimm_info[slot][channel];
 p_csrow = &amp;amp;mci-&amp;gt;csrows[slot];
 
+dimm = p_csrow-&amp;gt;channels[branch * MAX_CH_PER_BRANCH + ch].dimm;
+
 mtr = decode_mtr(pvt, slot, ch, branch,
- dinfo, p_csrow, &amp;amp;nr_pages);
+ dinfo, p_csrow, dimm,
+ &amp;amp;nr_pages);
 /* if no DIMMS on this row, continue */
 if (!MTR_DIMMS_PRESENT(mtr))
 continue;
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c
index df0acf0..5449bd4 100644
--- a/drivers/edac/i7core_edac.c
+++ b/drivers/edac/i7core_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -592,7 +592,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int i7core_get_active_channels(const u8 socket, unsigned *channels,
 return 0;
 }
 
-static int get_dimm_config(const struct mem_ctl_info *mci)
+static int get_dimm_config(struct mem_ctl_info *mci)
 {
 struct i7core_pvt *pvt = mci-&amp;gt;pvt_info;
 struct csrow_info *csr;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -602,6 +602,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int get_dimm_config(const struct mem_ctl_info *mci)
 unsigned long last_page = 0;
 enum edac_type mode;
 enum mem_type mtype;
+struct dimm_info *dimm;
 
 /* Get data from the MC register, function 0 */
 pdev = pvt-&amp;gt;pci_mcr[0];
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -721,7 +722,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int get_dimm_config(const struct mem_ctl_info *mci)
 csr-&amp;gt;nr_pages = npages;
 
 csr-&amp;gt;page_mask = 0;
-csr-&amp;gt;grain = 8;
 csr-&amp;gt;csrow_idx = csrow;
 csr-&amp;gt;nr_channels = 1;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -730,28 +730,27 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int get_dimm_config(const struct mem_ctl_info *mci)
 
 pvt-&amp;gt;csrow_map[i][j] = csrow;
 
+dimm = csr-&amp;gt;channels[0].dimm;
 switch (banks) {
 case 4:
-csr-&amp;gt;dtype = DEV_X4;
+dimm-&amp;gt;dtype = DEV_X4;
 break;
 case 8:
-csr-&amp;gt;dtype = DEV_X8;
+dimm-&amp;gt;dtype = DEV_X8;
 break;
 case 16:
-csr-&amp;gt;dtype = DEV_X16;
+dimm-&amp;gt;dtype = DEV_X16;
 break;
 default:
-csr-&amp;gt;dtype = DEV_UNKNOWN;
+dimm-&amp;gt;dtype = DEV_UNKNOWN;
 }
 
-csr-&amp;gt;edac_mode = mode;
-csr-&amp;gt;mtype = mtype;
-snprintf(csr-&amp;gt;channels[0].dimm-&amp;gt;label,
-sizeof(csr-&amp;gt;channels[0].dimm-&amp;gt;label),
-"CPU#%uChannel#%u_DIMM#%u",
-pvt-&amp;gt;i7core_dev-&amp;gt;socket, i, j);
-
-csrow++;
+snprintf(dimm-&amp;gt;label, sizeof(dimm-&amp;gt;label),
+ "CPU#%uChannel#%u_DIMM#%u",
+ pvt-&amp;gt;i7core_dev-&amp;gt;socket, i, j);
+dimm-&amp;gt;grain = 8;
+dimm-&amp;gt;edac_mode = mode;
+dimm-&amp;gt;mtype = mtype;
 }
 
 pci_read_config_dword(pdev, MC_SAG_CH_0, &amp;amp;value[0]);
diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c
index 3bf2b2f..0b98dd3 100644
--- a/drivers/edac/i82443bxgx_edac.c
+++ b/drivers/edac/i82443bxgx_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -12,7 +12,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * 440GX fix by Jason Uhlenkott &amp;lt;juhlenko&amp;lt; at &amp;gt;akamai.com&amp;gt;.
  *
  * Written with reference to 82443BX Host Bridge Datasheet:
- * http://download.intel.com/design/chipsets/datashts/29063301.pdf 
+ * http://download.intel.com/design/chipsets/datashts/29063301.pdf
  * references to this document given in [].
  *
  * This module doesn't support the 440LX, but it may be possible to
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -189,6 +189,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
 enum mem_type mtype)
 {
 struct csrow_info *csrow;
+struct dimm_info *dimm;
 int index;
 u8 drbar, dramc;
 u32 row_base, row_high_limit, row_high_limit_last;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -197,6 +198,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
 row_high_limit_last = 0;
 for (index = 0; index &amp;lt; mci-&amp;gt;nr_csrows; index++) {
 csrow = &amp;amp;mci-&amp;gt;csrows[index];
+dimm = csrow-&amp;gt;channels[0].dimm;
+
 pci_read_config_byte(pdev, I82443BXGX_DRB + index, &amp;amp;drbar);
 debugf1("MC%d: %s: %s() Row=%d DRB = %#0x\n",
 mci-&amp;gt;mc_idx, __FILE__, __func__, index, drbar);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -219,12 +222,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
 csrow-&amp;gt;last_page = (row_high_limit &amp;gt;&amp;gt; PAGE_SHIFT) - 1;
 csrow-&amp;gt;nr_pages = csrow-&amp;gt;last_page - csrow-&amp;gt;first_page + 1;
 /* EAP reports in 4kilobyte granularity [61] */
-csrow-&amp;gt;grain = 1 &amp;lt;&amp;lt; 12;
-csrow-&amp;gt;mtype = mtype;
+dimm-&amp;gt;grain = 1 &amp;lt;&amp;lt; 12;
+dimm-&amp;gt;mtype = mtype;
 /* I don't think 440BX can tell you device type? FIXME? */
-csrow-&amp;gt;dtype = DEV_UNKNOWN;
+dimm-&amp;gt;dtype = DEV_UNKNOWN;
 /* Mode is global to all rows on 440BX */
-csrow-&amp;gt;edac_mode = edac_mode;
+dimm-&amp;gt;edac_mode = edac_mode;
 row_high_limit_last = row_high_limit;
 }
 }
diff --git a/drivers/edac/i82860_edac.c b/drivers/edac/i82860_edac.c
index c779092..3eb7784 100644
--- a/drivers/edac/i82860_edac.c
+++ b/drivers/edac/i82860_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -140,6 +140,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
 u16 value;
 u32 cumul_size;
 struct csrow_info *csrow;
+struct dimm_info *dimm;
 int index;
 
 pci_read_config_word(pdev, I82860_MCHCFG, &amp;amp;mchcfg_ddim);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -153,6 +154,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
  */
 for (index = 0; index &amp;lt; mci-&amp;gt;nr_csrows; index++) {
 csrow = &amp;amp;mci-&amp;gt;csrows[index];
+dimm = csrow-&amp;gt;channels[0].dimm;
+
 pci_read_config_word(pdev, I82860_GBA + index * 2, &amp;amp;value);
 cumul_size = (value &amp;amp; I82860_GBA_MASK) &amp;lt;&amp;lt;
 (I82860_GBA_SHIFT - PAGE_SHIFT);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -166,10 +169,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void i82860_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev)
 csrow-&amp;gt;last_page = cumul_size - 1;
 csrow-&amp;gt;nr_pages = cumul_size - last_cumul_size;
 last_cumul_size = cumul_size;
-csrow-&amp;gt;grain = 1 &amp;lt;&amp;lt; 12;/* I82860_EAP has 4KiB reolution */
-csrow-&amp;gt;mtype = MEM_RMBS;
-csrow-&amp;gt;dtype = DEV_UNKNOWN;
-csrow-&amp;gt;edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE;
+dimm-&amp;gt;grain = 1 &amp;lt;&amp;lt; 12;/* I82860_EAP has 4KiB reolution */
+dimm-&amp;gt;mtype = MEM_RMBS;
+dimm-&amp;gt;dtype = DEV_UNKNOWN;
+dimm-&amp;gt;edac_mode = mchcfg_ddim ? EDAC_SECDED : EDAC_NONE;
 }
 }
 
diff --git a/drivers/edac/i82875p_edac.c b/drivers/edac/i82875p_edac.c
index 10f15d8..eac5742 100644
--- a/drivers/edac/i82875p_edac.c
+++ b/drivers/edac/i82875p_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -342,11 +342,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void i82875p_init_csrows(struct mem_ctl_info *mci,
 void __iomem * ovrfl_window, u32 drc)
 {
 struct csrow_info *csrow;
+struct dimm_info *dimm;
+unsigned nr_chans = dual_channel_active(drc) + 1;
 unsigned long last_cumul_size;
 u8 value;
 u32 drc_ddim;/* DRAM Data Integrity Mode 0=none,2=edac */
 u32 cumul_size;
-int index;
+int index, j;
 
 drc_ddim = (drc &amp;gt;&amp;gt; 18) &amp;amp; 0x1;
 last_cumul_size = 0;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -371,10 +373,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void i82875p_init_csrows(struct mem_ctl_info *mci,
 csrow-&amp;gt;last_page = cumul_size - 1;
 csrow-&amp;gt;nr_pages = cumul_size - last_cumul_size;
 last_cumul_size = cumul_size;
-csrow-&amp;gt;grain = 1 &amp;lt;&amp;lt; 12;/* I82875P_EAP has 4KiB reolution */
-csrow-&amp;gt;mtype = MEM_DDR;
-csrow-&amp;gt;dtype = DEV_UNKNOWN;
-csrow-&amp;gt;edac_mode = drc_ddim ? EDAC_SECDED : EDAC_NONE;
+
+for (j = 0; j &amp;lt; nr_chans; j++) {
+dimm = csrow-&amp;gt;channels[j].dimm;
+
+dimm-&amp;gt;grain = 1 &amp;lt;&amp;lt; 12;/* I82875P_EAP has 4KiB reolution */
+dimm-&amp;gt;mtype = MEM_DDR;
+dimm-&amp;gt;dtype = DEV_UNKNOWN;
+dimm-&amp;gt;edac_mode = drc_ddim ? EDAC_SECDED : EDAC_NONE;
+}
 }
 }
 
diff --git a/drivers/edac/i82975x_edac.c b/drivers/edac/i82975x_edac.c
index b7aca58..b8ec871 100644
--- a/drivers/edac/i82975x_edac.c
+++ b/drivers/edac/i82975x_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -309,7 +309,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int i82975x_process_error_info(struct mem_ctl_info *mci,
 chan = (mci-&amp;gt;csrows[row].nr_channels == 1) ? 0 : info-&amp;gt;eap &amp;amp; 1;
 offst = info-&amp;gt;eap
 &amp;amp; ((1 &amp;lt;&amp;lt; PAGE_SHIFT) -
-(1 &amp;lt;&amp;lt; mci-&amp;gt;csrows[row].grain));
+   (1 &amp;lt;&amp;lt; mci-&amp;gt;csrows[row].channels[chan].dimm-&amp;gt;grain));
 
 if (info-&amp;gt;errsts &amp;amp; 0x0002)
 edac_mc_handle_ue(mci, page, offst , row, "i82975x UE");
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -372,6 +372,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void i82975x_init_csrows(struct mem_ctl_info *mci,
 u8 value;
 u32 cumul_size;
 int index, chan;
+struct dimm_info *dimm;
+enum dev_type dtype;
 
 last_cumul_size = 0;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -406,10 +408,17 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void i82975x_init_csrows(struct mem_ctl_info *mci,
  *   [0-7] for single-channel; i.e. csrow-&amp;gt;nr_channels = 1
  *   [0-3] for dual-channel; i.e. csrow-&amp;gt;nr_channels = 2
  */
-for (chan = 0; chan &amp;lt; csrow-&amp;gt;nr_channels; chan++)
+dtype = i82975x_dram_type(mch_window, index);
+for (chan = 0; chan &amp;lt; csrow-&amp;gt;nr_channels; chan++) {
+dimm = mci-&amp;gt;csrows[index].channels[chan].dimm;
 strncpy(csrow-&amp;gt;channels[chan].dimm-&amp;gt;label,
 labels[(index &amp;gt;&amp;gt; 1) + (chan * 2)],
 EDAC_MC_LABEL_LEN);
+dimm-&amp;gt;grain = 1 &amp;lt;&amp;lt; 7;/* 128Byte cache-line resolution */
+dimm-&amp;gt;dtype = i82975x_dram_type(mch_window, index);
+dimm-&amp;gt;mtype = MEM_DDR2; /* I82975x supports only DDR2 */
+dimm-&amp;gt;edac_mode = EDAC_SECDED; /* only supported */
+}
 
 if (cumul_size == last_cumul_size)
 continue;/* not populated */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -418,10 +427,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void i82975x_init_csrows(struct mem_ctl_info *mci,
 csrow-&amp;gt;last_page = cumul_size - 1;
 csrow-&amp;gt;nr_pages = cumul_size - last_cumul_size;
 last_cumul_size = cumul_size;
-csrow-&amp;gt;grain = 1 &amp;lt;&amp;lt; 7;/* 128Byte cache-line resolution */
-csrow-&amp;gt;mtype = MEM_DDR2; /* I82975x supports only DDR2 */
-csrow-&amp;gt;dtype = i82975x_dram_type(mch_window, index);
-csrow-&amp;gt;edac_mode = EDAC_SECDED; /* only supported */
 }
 }
 
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index 73464a6..fb92916 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -883,6 +883,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
 {
 struct mpc85xx_mc_pdata *pdata = mci-&amp;gt;pvt_info;
 struct csrow_info *csrow;
+struct dimm_info *dimm;
 u32 sdram_ctl;
 u32 sdtype;
 enum mem_type mtype;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -929,6 +930,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
 u32 end;
 
 csrow = &amp;amp;mci-&amp;gt;csrows[index];
+dimm = csrow-&amp;gt;channels[0].dimm;
+
 cs_bnds = in_be32(pdata-&amp;gt;mc_vbase + MPC85XX_MC_CS_BNDS_0 +
   (index * MPC85XX_MC_CS_BNDS_OFS));
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -945,12 +948,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void __devinit mpc85xx_init_csrows(struct mem_ctl_info *mci)
 csrow-&amp;gt;first_page = start;
 csrow-&amp;gt;last_page = end;
 csrow-&amp;gt;nr_pages = end + 1 - start;
-csrow-&amp;gt;grain = 8;
-csrow-&amp;gt;mtype = mtype;
-csrow-&amp;gt;dtype = DEV_UNKNOWN;
+dimm-&amp;gt;grain = 8;
+dimm-&amp;gt;mtype = mtype;
+dimm-&amp;gt;dtype = DEV_UNKNOWN;
 if (sdram_ctl &amp;amp; DSC_X32_EN)
-csrow-&amp;gt;dtype = DEV_X32;
-csrow-&amp;gt;edac_mode = EDAC_SECDED;
+dimm-&amp;gt;dtype = DEV_X32;
+dimm-&amp;gt;edac_mode = EDAC_SECDED;
 }
 }
 
diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c
index 7e5ff36..12d7fe0 100644
--- a/drivers/edac/mv64x60_edac.c
+++ b/drivers/edac/mv64x60_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -656,6 +656,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void mv64x60_init_csrows(struct mem_ctl_info *mci,
 struct mv64x60_mc_pdata *pdata)
 {
 struct csrow_info *csrow;
+struct dimm_info *dimm;
+
 u32 devtype;
 u32 ctl;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -664,30 +666,30 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void mv64x60_init_csrows(struct mem_ctl_info *mci,
 ctl = in_le32(pdata-&amp;gt;mc_vbase + MV64X60_SDRAM_CONFIG);
 
 csrow = &amp;amp;mci-&amp;gt;csrows[0];
-csrow-&amp;gt;first_page = 0;
+dimm = csrow-&amp;gt;channels[0].dimm;
 csrow-&amp;gt;nr_pages = pdata-&amp;gt;total_mem &amp;gt;&amp;gt; PAGE_SHIFT;
 csrow-&amp;gt;last_page = csrow-&amp;gt;first_page + csrow-&amp;gt;nr_pages - 1;
-csrow-&amp;gt;grain = 8;
+dimm-&amp;gt;grain = 8;
 
-csrow-&amp;gt;mtype = (ctl &amp;amp; MV64X60_SDRAM_REGISTERED) ? MEM_RDDR : MEM_DDR;
+dimm-&amp;gt;mtype = (ctl &amp;amp; MV64X60_SDRAM_REGISTERED) ? MEM_RDDR : MEM_DDR;
 
 devtype = (ctl &amp;gt;&amp;gt; 20) &amp;amp; 0x3;
 switch (devtype) {
 case 0x0:
-csrow-&amp;gt;dtype = DEV_X32;
+dimm-&amp;gt;dtype = DEV_X32;
 break;
 case 0x2:/* could be X8 too, but no way to tell */
-csrow-&amp;gt;dtype = DEV_X16;
+dimm-&amp;gt;dtype = DEV_X16;
 break;
 case 0x3:
-csrow-&amp;gt;dtype = DEV_X4;
+dimm-&amp;gt;dtype = DEV_X4;
 break;
 default:
-csrow-&amp;gt;dtype = DEV_UNKNOWN;
+dimm-&amp;gt;dtype = DEV_UNKNOWN;
 break;
 }
 
-csrow-&amp;gt;edac_mode = EDAC_SECDED;
+dimm-&amp;gt;edac_mode = EDAC_SECDED;
 }
 
 static int __devinit mv64x60_mc_err_probe(struct platform_device *pdev)
diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c
index 7f71ee4..4e53270 100644
--- a/drivers/edac/pasemi_edac.c
+++ b/drivers/edac/pasemi_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -135,11 +135,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int pasemi_edac_init_csrows(struct mem_ctl_info *mci,
    enum edac_type edac_mode)
 {
 struct csrow_info *csrow;
+struct dimm_info *dimm;
 u32 rankcfg;
 int index;
 
 for (index = 0; index &amp;lt; mci-&amp;gt;nr_csrows; index++) {
 csrow = &amp;amp;mci-&amp;gt;csrows[index];
+dimm = csrow-&amp;gt;channels[0].dimm;
 
 pci_read_config_dword(pdev,
       MCDRAM_RANKCFG + (index * 12),
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -177,10 +179,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int pasemi_edac_init_csrows(struct mem_ctl_info *mci,
 csrow-&amp;gt;last_page = csrow-&amp;gt;first_page + csrow-&amp;gt;nr_pages - 1;
 last_page_in_mmc += csrow-&amp;gt;nr_pages;
 csrow-&amp;gt;page_mask = 0;
-csrow-&amp;gt;grain = PASEMI_EDAC_ERROR_GRAIN;
-csrow-&amp;gt;mtype = MEM_DDR;
-csrow-&amp;gt;dtype = DEV_UNKNOWN;
-csrow-&amp;gt;edac_mode = edac_mode;
+dimm-&amp;gt;grain = PASEMI_EDAC_ERROR_GRAIN;
+dimm-&amp;gt;mtype = MEM_DDR;
+dimm-&amp;gt;dtype = DEV_UNKNOWN;
+dimm-&amp;gt;edac_mode = edac_mode;
 }
 return 0;
 }
diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c
index d427c69..a75e567 100644
--- a/drivers/edac/ppc4xx_edac.c
+++ b/drivers/edac/ppc4xx_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -895,7 +895,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1)
 enum mem_type mtype;
 enum dev_type dtype;
 enum edac_type edac_mode;
-int row;
+int row, j;
 u32 mbxcf, size;
 static u32 ppc4xx_last_page;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -975,15 +975,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; ppc4xx_edac_init_csrows(struct mem_ctl_info *mci, u32 mcopt1)
  * possible values would be the PLB width (16), the
  * page size (PAGE_SIZE) or the memory width (2 or 4).
  */
+for (j = 0; j &amp;lt; csi-&amp;gt;nr_channels; j++) {
+struct dimm_info *dimm = csi-&amp;gt;channels[j].dimm;
 
-csi-&amp;gt;grain= 1;
+dimm-&amp;gt;grain= 1;
 
-csi-&amp;gt;mtype= mtype;
-csi-&amp;gt;dtype= dtype;
+dimm-&amp;gt;mtype= mtype;
+dimm-&amp;gt;dtype= dtype;
 
-csi-&amp;gt;edac_mode= edac_mode;
+dimm-&amp;gt;edac_mode= edac_mode;
 
 ppc4xx_last_page += csi-&amp;gt;nr_pages;
+}
 }
 
  done:
diff --git a/drivers/edac/r82600_edac.c b/drivers/edac/r82600_edac.c
index 6d908ad..70b0dfa 100644
--- a/drivers/edac/r82600_edac.c
+++ b/drivers/edac/r82600_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -216,6 +216,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 u8 dramcr)
 {
 struct csrow_info *csrow;
+struct dimm_info *dimm;
 int index;
 u8 drbar;/* SDRAM Row Boundary Address Register */
 u32 row_high_limit, row_high_limit_last;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -227,6 +228,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 
 for (index = 0; index &amp;lt; mci-&amp;gt;nr_csrows; index++) {
 csrow = &amp;amp;mci-&amp;gt;csrows[index];
+dimm = csrow-&amp;gt;channels[0].dimm;
 
 /* find the DRAM Chip Select Base address and mask */
 pci_read_config_byte(pdev, R82600_DRBA + index, &amp;amp;drbar);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -250,13 +252,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void r82600_init_csrows(struct mem_ctl_info *mci, struct pci_dev *pdev,
 csrow-&amp;gt;nr_pages = csrow-&amp;gt;last_page - csrow-&amp;gt;first_page + 1;
 /* Error address is top 19 bits - so granularity is      *
  * 14 bits                                               */
-csrow-&amp;gt;grain = 1 &amp;lt;&amp;lt; 14;
-csrow-&amp;gt;mtype = reg_sdram ? MEM_RDDR : MEM_DDR;
+dimm-&amp;gt;grain = 1 &amp;lt;&amp;lt; 14;
+dimm-&amp;gt;mtype = reg_sdram ? MEM_RDDR : MEM_DDR;
 /* FIXME - check that this is unknowable with this chipset */
-csrow-&amp;gt;dtype = DEV_UNKNOWN;
+dimm-&amp;gt;dtype = DEV_UNKNOWN;
 
 /* Mode is global on 82600 */
-csrow-&amp;gt;edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE;
+dimm-&amp;gt;edac_mode = ecc_on ? EDAC_SECDED : EDAC_NONE;
 row_high_limit_last = row_high_limit;
 }
 }
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 95901c2..21147ac 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -551,7 +551,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int sbridge_get_active_channels(const u8 bus, unsigned *channels,
 return 0;
 }
 
-static int get_dimm_config(const struct mem_ctl_info *mci)
+static int get_dimm_config(struct mem_ctl_info *mci)
 {
 struct sbridge_pvt *pvt = mci-&amp;gt;pvt_info;
 struct csrow_info *csr;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -561,6 +561,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int get_dimm_config(const struct mem_ctl_info *mci)
 u32 reg;
 enum edac_type mode;
 enum mem_type mtype;
+struct dimm_info *dimm;
 
 pci_read_config_dword(pvt-&amp;gt;pci_br, SAD_TARGET, &amp;amp;reg);
 pvt-&amp;gt;sbridge_dev-&amp;gt;source_id = SOURCE_ID(reg);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -612,6 +613,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int get_dimm_config(const struct mem_ctl_info *mci)
 /* On all supported DDR3 DIMM types, there are 8 banks available */
 banks = 8;
 
+dimm = mci-&amp;gt;dimms;
 for (i = 0; i &amp;lt; NUM_CHANNELS; i++) {
 u32 mtr;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -634,29 +636,30 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int get_dimm_config(const struct mem_ctl_info *mci)
 pvt-&amp;gt;sbridge_dev-&amp;gt;mc, i, j,
 size, npages,
 banks, ranks, rows, cols);
-csr = &amp;amp;mci-&amp;gt;csrows[csrow];
 
+/*
+ * Fake stuff. This controller doesn't see
+ * csrows.
+ */
+csr = &amp;amp;mci-&amp;gt;csrows[csrow];
 csr-&amp;gt;first_page = last_page;
 csr-&amp;gt;last_page = last_page + npages - 1;
-csr-&amp;gt;page_mask = 0UL;/* Unused */
 csr-&amp;gt;nr_pages = npages;
-csr-&amp;gt;grain = 32;
 csr-&amp;gt;csrow_idx = csrow;
-csr-&amp;gt;dtype = (banks == 8) ? DEV_X8 : DEV_X4;
-csr-&amp;gt;ce_count = 0;
-csr-&amp;gt;ue_count = 0;
-csr-&amp;gt;mtype = mtype;
-csr-&amp;gt;edac_mode = mode;
 csr-&amp;gt;nr_channels = 1;
 csr-&amp;gt;channels[0].chan_idx = i;
-csr-&amp;gt;channels[0].ce_count = 0;
 pvt-&amp;gt;csrow_map[i][j] = csrow;
-snprintf(csr-&amp;gt;channels[0].dimm-&amp;gt;label,
- sizeof(csr-&amp;gt;channels[0].dimm-&amp;gt;label),
- "CPU_SrcID#%u_Channel#%u_DIMM#%u",
- pvt-&amp;gt;sbridge_dev-&amp;gt;source_id, i, j);
 last_page += npages;
 csrow++;
+
+csr-&amp;gt;channels[0].dimm = dimm;
+dimm-&amp;gt;grain = 32;
+dimm-&amp;gt;dtype = (banks == 8) ? DEV_X8 : DEV_X4;
+dimm-&amp;gt;mtype = mtype;
+dimm-&amp;gt;edac_mode = mode;
+snprintf(dimm-&amp;gt;label, sizeof(dimm-&amp;gt;label),
+ "CPU_SrcID#%u_Channel#%u_DIMM#%u",
+ pvt-&amp;gt;sbridge_dev-&amp;gt;source_id, i, j);
 }
 }
 }
diff --git a/drivers/edac/tile_edac.c b/drivers/edac/tile_edac.c
index e99d009..c870f68 100644
--- a/drivers/edac/tile_edac.c
+++ b/drivers/edac/tile_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -84,6 +84,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int __devinit tile_edac_init_csrows(struct mem_ctl_info *mci)
 struct csrow_info*csrow = &amp;amp;mci-&amp;gt;csrows[0];
 struct tile_edac_priv*priv = mci-&amp;gt;pvt_info;
 struct mshim_mem_infomem_info;
+struct dimm_info *dimm = csrow-&amp;gt;channels[0].dimm;
 
 if (hv_dev_pread(priv-&amp;gt;hv_devhdl, 0, (HV_VirtAddr)&amp;amp;mem_info,
 sizeof(struct mshim_mem_info), MSHIM_MEM_INFO_OFF) !=
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -93,16 +94,16 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int __devinit tile_edac_init_csrows(struct mem_ctl_info *mci)
 }
 
 if (mem_info.mem_ecc)
-csrow-&amp;gt;edac_mode = EDAC_SECDED;
+dimm-&amp;gt;edac_mode = EDAC_SECDED;
 else
-csrow-&amp;gt;edac_mode = EDAC_NONE;
+dimm-&amp;gt;edac_mode = EDAC_NONE;
 switch (mem_info.mem_type) {
 case DDR2:
-csrow-&amp;gt;mtype = MEM_DDR2;
+dimm-&amp;gt;mtype = MEM_DDR2;
 break;
 
 case DDR3:
-csrow-&amp;gt;mtype = MEM_DDR3;
+dimm-&amp;gt;mtype = MEM_DDR3;
 break;
 
 default:
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -112,8 +113,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int __devinit tile_edac_init_csrows(struct mem_ctl_info *mci)
 csrow-&amp;gt;first_page = 0;
 csrow-&amp;gt;nr_pages = mem_info.mem_size &amp;gt;&amp;gt; PAGE_SHIFT;
 csrow-&amp;gt;last_page = csrow-&amp;gt;first_page + csrow-&amp;gt;nr_pages - 1;
-csrow-&amp;gt;grain = TILE_EDAC_ERROR_GRAIN;
-csrow-&amp;gt;dtype = DEV_UNKNOWN;
+dimm-&amp;gt;grain = TILE_EDAC_ERROR_GRAIN;
+dimm-&amp;gt;dtype = DEV_UNKNOWN;
 
 return 0;
 }
diff --git a/drivers/edac/x38_edac.c b/drivers/edac/x38_edac.c
index a438297..f7cc4d2 100644
--- a/drivers/edac/x38_edac.c
+++ b/drivers/edac/x38_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -317,7 +317,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static unsigned long drb_to_nr_pages(
 static int x38_probe1(struct pci_dev *pdev, int dev_idx)
 {
 int rc;
-int i;
+int i, j;
 struct mem_ctl_info *mci = NULL;
 unsigned long last_page;
 u16 drbs[X38_CHANNELS][X38_RANKS_PER_CHANNEL];
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -372,20 +372,21 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int x38_probe1(struct pci_dev *pdev, int dev_idx)
 i / X38_RANKS_PER_CHANNEL,
 i % X38_RANKS_PER_CHANNEL);
 
-if (nr_pages == 0) {
-csrow-&amp;gt;mtype = MEM_EMPTY;
+if (nr_pages == 0)
 continue;
-}
 
 csrow-&amp;gt;first_page = last_page + 1;
 last_page += nr_pages;
 csrow-&amp;gt;last_page = last_page;
 csrow-&amp;gt;nr_pages = nr_pages;
 
-csrow-&amp;gt;grain = nr_pages &amp;lt;&amp;lt; PAGE_SHIFT;
-csrow-&amp;gt;mtype = MEM_DDR2;
-csrow-&amp;gt;dtype = DEV_UNKNOWN;
-csrow-&amp;gt;edac_mode = EDAC_UNKNOWN;
+for (j = 0; j &amp;lt; x38_channel_num; j++) {
+struct dimm_info *dimm = csrow-&amp;gt;channels[j].dimm;
+dimm-&amp;gt;grain = nr_pages &amp;lt;&amp;lt; PAGE_SHIFT;
+dimm-&amp;gt;mtype = MEM_DDR2;
+dimm-&amp;gt;dtype = DEV_UNKNOWN;
+dimm-&amp;gt;edac_mode = EDAC_UNKNOWN;
+}
 }
 
 x38_clear_error_info(mci);
diff --git a/include/linux/edac.h b/include/linux/edac.h
index 52bceca..87aa07d 100644
--- a/include/linux/edac.h
+++ b/include/linux/edac.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -318,6 +318,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct dimm_info {
 unsigned memory_controller;
 unsigned csrow;
 unsigned csrow_channel;
+
+u32 grain;/* granularity of reported error in bytes */
+enum dev_type dtype;/* memory device type */
+enum mem_type mtype;/* memory dimm type */
+enum edac_type edac_mode;/* EDAC mode for this dimm */
+
+u32 ce_count;/* Correctable Errors for this dimm */
 };
 
 /**
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -343,19 +350,17 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct rank_info {
 };
 
 struct csrow_info {
-unsigned long first_page;/* first page number in dimm */
-unsigned long last_page;/* last page number in dimm */
+unsigned long first_page;/* first page number in csrow */
+unsigned long last_page;/* last page number in csrow */
+u32 nr_pages;/* number of pages in csrow */
 unsigned long page_mask;/* used for interleaving -
  * 0UL for non intlv
  */
-u32 nr_pages;/* number of pages in csrow */
-u32 grain;/* granularity of reported error in bytes */
-int csrow_idx;/* the chip-select row */
-enum dev_type dtype;/* memory device type */
+int csrow_idx;/* the chip-select row */
+
 u32 ue_count;/* Uncorrectable Errors for this csrow */
 u32 ce_count;/* Correctable Errors for this csrow */
-enum mem_type mtype;/* memory csrow type */
-enum edac_type edac_mode;/* EDAC mode for this csrow */
+
 struct mem_ctl_info *mci;/* the parent */
 
 struct kobject kobj;/* sysfs kobject for this csrow */
&lt;/pre&gt;</description>
    <dc:creator>Mauro Carvalho Chehab</dc:creator>
    <dc:date>2012-05-18T16:31:49</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82150">
    <title>[PATCH EDAC v26 07/66] edac: Change internal representation to work with layers</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82150</link>
    <description>&lt;pre&gt;Change the EDAC internal representation to work with non-csrow
based memory controllers.

There are lots of those memory controllers nowadays, and more
are coming. So, the EDAC internal representation needs to be
changed, in order to work with those memory controllers, while
preserving backward compatibility with the old ones.

The edac core was written with the idea that memory controllers
are able to directly access csrows.

This is not true for FB-DIMM and RAMBUS memory controllers.

Also, some recent advanced memory controllers don't present a per-csrows
view. Instead, they view memories as DIMMs, instead of ranks.

So, change the allocation and error report routines to allow
them to work with all types of architectures.

This will allow the removal of several hacks with FB-DIMM and RAMBUS
memory controllers.

Also, several tests were done on different platforms using different
x86 drivers.

TODO: a multi-rank DIMMs are currently represented by multiple DIMM
entries in struct dimm_info. That means that changing a label for one
rank won't change the same label for the other ranks at the same DIMM.
This bug is present since the beginning of the EDAC, so it is not a big
deal. However, on several drivers, it is possible to fix this issue, but
it should be a per-driver fix, as the csrow =&amp;gt; DIMM arrangement may not
be equal for all. So, don't try to fix it here yet.

I tried to make this patch as short as possible, preceding it with
several other patches that simplified the logic here. Yet, as the
internal API changes, all drivers need changes. The changes are
generally bigger in the drivers for FB-DIMMs.

Cc: Aristeu Rozanski &amp;lt;arozansk&amp;lt; at &amp;gt;redhat.com&amp;gt;
Cc: Doug Thompson &amp;lt;norsk5&amp;lt; at &amp;gt;yahoo.com&amp;gt;
Cc: Borislav Petkov &amp;lt;borislav.petkov&amp;lt; at &amp;gt;amd.com&amp;gt;
Cc: Mark Gross &amp;lt;mark.gross&amp;lt; at &amp;gt;intel.com&amp;gt;
Cc: Jason Uhlenkott &amp;lt;juhlenko&amp;lt; at &amp;gt;akamai.com&amp;gt;
Cc: Tim Small &amp;lt;tim&amp;lt; at &amp;gt;buttersideup.com&amp;gt;
Cc: Ranganathan Desikan &amp;lt;ravi&amp;lt; at &amp;gt;jetztechnologies.com&amp;gt;
Cc: "Arvind R." &amp;lt;arvino55&amp;lt; at &amp;gt;gmail.com&amp;gt;
Cc: Olof Johansson &amp;lt;olof&amp;lt; at &amp;gt;lixom.net&amp;gt;
Cc: Egor Martovetsky &amp;lt;egor&amp;lt; at &amp;gt;pasemi.com&amp;gt;
Cc: Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
Cc: Michal Marek &amp;lt;mmarek&amp;lt; at &amp;gt;suse.cz&amp;gt;
Cc: Jiri Kosina &amp;lt;jkosina&amp;lt; at &amp;gt;suse.cz&amp;gt;
Cc: Joe Perches &amp;lt;joe&amp;lt; at &amp;gt;perches.com&amp;gt;
Cc: Dmitry Eremin-Solenikov &amp;lt;dbaryshkov&amp;lt; at &amp;gt;gmail.com&amp;gt;
Cc: Benjamin Herrenschmidt &amp;lt;benh&amp;lt; at &amp;gt;kernel.crashing.org&amp;gt;
Cc: Hitoshi Mitake &amp;lt;h.mitake&amp;lt; at &amp;gt;gmail.com&amp;gt;
Cc: Andrew Morton &amp;lt;akpm&amp;lt; at &amp;gt;linux-foundation.org&amp;gt;
Cc: "Niklas Söderlund" &amp;lt;niklas.soderlund&amp;lt; at &amp;gt;ericsson.com&amp;gt;
Cc: Shaohui Xie &amp;lt;Shaohui.Xie&amp;lt; at &amp;gt;freescale.com&amp;gt;
Cc: Josh Boyer &amp;lt;jwboyer&amp;lt; at &amp;gt;gmail.com&amp;gt;
Cc: linuxppc-dev&amp;lt; at &amp;gt;lists.ozlabs.org
Signed-off-by: Mauro Carvalho Chehab &amp;lt;mchehab&amp;lt; at &amp;gt;redhat.com&amp;gt;
---
 drivers/edac/edac_core.h |   99 ++++++--
 drivers/edac/edac_mc.c   |  702 +++++++++++++++++++++++++++++-----------------
 include/linux/edac.h     |   38 ++-
 3 files changed, 552 insertions(+), 287 deletions(-)

diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h
index e48ab31..1286c5e 100644
--- a/drivers/edac/edac_core.h
+++ b/drivers/edac/edac_core.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -447,8 +447,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline void pci_write_bits32(struct pci_dev *pdev, int offset,
 
 #endif/* CONFIG_PCI */
 
-extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
-  unsigned nr_chans, int edac_index);
+struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
+   unsigned nr_chans, int edac_index);
+struct mem_ctl_info *new_edac_mc_alloc(unsigned edac_index,
+   unsigned n_layers,
+   struct edac_mc_layer *layers,
+   unsigned sz_pvt);
 extern int edac_mc_add_mc(struct mem_ctl_info *mci);
 extern void edac_mc_free(struct mem_ctl_info *mci);
 extern struct mem_ctl_info *edac_mc_find(int idx);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -467,24 +471,78 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci,
  * reporting logic and function interface - reduces conditional
  * statement clutter and extra function arguments.
  */
-extern void edac_mc_handle_ce(struct mem_ctl_info *mci,
-      unsigned long page_frame_number,
-      unsigned long offset_in_page,
-      unsigned long syndrome, int row, int channel,
-      const char *msg);
-extern void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci,
-      const char *msg);
-extern void edac_mc_handle_ue(struct mem_ctl_info *mci,
-      unsigned long page_frame_number,
-      unsigned long offset_in_page, int row,
-      const char *msg);
-extern void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci,
-      const char *msg);
-extern void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci, unsigned int csrow,
-  unsigned int channel0, unsigned int channel1,
-  char *msg);
-extern void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci, unsigned int csrow,
-  unsigned int channel, char *msg);
+
+void edac_mc_handle_error(const enum hw_event_mc_err_type type,
+  struct mem_ctl_info *mci,
+  const unsigned long page_frame_number,
+  const unsigned long offset_in_page,
+  const unsigned long syndrome,
+  const int layer0,
+  const int layer1,
+  const int layer2,
+  const char *msg,
+  const char *other_detail,
+  const void *mcelog);
+
+static inline void edac_mc_handle_ce(struct mem_ctl_info *mci,
+     unsigned long page_frame_number,
+     unsigned long offset_in_page,
+     unsigned long syndrome, int row, int channel,
+     const char *msg)
+{
+ edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+      page_frame_number, offset_in_page, syndrome,
+      row, channel, -1, msg, NULL, NULL);
+}
+
+static inline void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci,
+     const char *msg)
+{
+ edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+      0, 0, 0, -1, -1, -1, msg, NULL, NULL);
+}
+
+static inline void edac_mc_handle_ue(struct mem_ctl_info *mci,
+     unsigned long page_frame_number,
+     unsigned long offset_in_page, int row,
+     const char *msg)
+{
+ edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+      page_frame_number, offset_in_page, 0,
+      row, -1, -1, msg, NULL, NULL);
+}
+
+static inline void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci,
+     const char *msg)
+{
+ edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+      0, 0, 0, -1, -1, -1, msg, NULL, NULL);
+}
+
+static inline void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
+ unsigned int csrow,
+ unsigned int channel0,
+ unsigned int channel1,
+ char *msg)
+{
+/*
+ *FIXME: The error can also be at channel1 (e. g. at the second
+ *  channel of the same branch). The fix is to push
+ *  edac_mc_handle_error() call into each driver
+ */
+ edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+      0, 0, 0,
+      csrow, channel0, -1, msg, NULL, NULL);
+}
+
+static inline void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
+ unsigned int csrow,
+ unsigned int channel, char *msg)
+{
+ edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+      0, 0, 0,
+      csrow, channel, -1, msg, NULL, NULL);
+}
 
 /*
  * edac_device APIs
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -496,6 +554,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; 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 ff8c002..1bd237e 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -44,9 +44,25 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void edac_mc_dump_channel(struct rank_info *chan)
 debugf4("\tchannel = %p\n", chan);
 debugf4("\tchannel-&amp;gt;chan_idx = %d\n", chan-&amp;gt;chan_idx);
 debugf4("\tchannel-&amp;gt;csrow = %p\n\n", chan-&amp;gt;csrow);
-debugf4("\tdimm-&amp;gt;ce_count = %d\n", chan-&amp;gt;dimm-&amp;gt;ce_count);
-debugf4("\tdimm-&amp;gt;label = '%s'\n", chan-&amp;gt;dimm-&amp;gt;label);
-debugf4("\tdimm-&amp;gt;nr_pages = 0x%x\n", chan-&amp;gt;dimm-&amp;gt;nr_pages);
+debugf4("\tchannel-&amp;gt;dimm = %p\n", chan-&amp;gt;dimm);
+}
+
+static void edac_mc_dump_dimm(struct dimm_info *dimm)
+{
+int i;
+
+debugf4("\tdimm = %p\n", dimm);
+debugf4("\tdimm-&amp;gt;label = '%s'\n", dimm-&amp;gt;label);
+debugf4("\tdimm-&amp;gt;nr_pages = 0x%x\n", dimm-&amp;gt;nr_pages);
+debugf4("\tdimm location ");
+for (i = 0; i &amp;lt; dimm-&amp;gt;mci-&amp;gt;n_layers; i++) {
+printk(KERN_CONT "%d", dimm-&amp;gt;location[i]);
+if (i &amp;lt; dimm-&amp;gt;mci-&amp;gt;n_layers - 1)
+printk(KERN_CONT ".");
+}
+printk(KERN_CONT "\n");
+debugf4("\tdimm-&amp;gt;grain = %d\n", dimm-&amp;gt;grain);
+debugf4("\tdimm-&amp;gt;nr_pages = 0x%x\n", dimm-&amp;gt;nr_pages);
 }
 
 static void edac_mc_dump_csrow(struct csrow_info *csrow)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -70,6 +86,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void edac_mc_dump_mci(struct mem_ctl_info *mci)
 debugf4("\tmci-&amp;gt;edac_check = %p\n", mci-&amp;gt;edac_check);
 debugf3("\tmci-&amp;gt;nr_csrows = %d, csrows = %p\n",
 mci-&amp;gt;nr_csrows, mci-&amp;gt;csrows);
+debugf3("\tmci-&amp;gt;nr_dimms = %d, dimms = %p\n",
+mci-&amp;gt;tot_dimms, mci-&amp;gt;dimms);
 debugf3("\tdev = %p\n", mci-&amp;gt;dev);
 debugf3("\tmod_name:ctl_name = %s:%s\n", mci-&amp;gt;mod_name, mci-&amp;gt;ctl_name);
 debugf3("\tpvt_info = %p\n\n", mci-&amp;gt;pvt_info);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -157,10 +175,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void *edac_align_ptr(void **p, unsigned size, int n_elems)
 }
 
 /**
- * edac_mc_alloc: Allocate a struct mem_ctl_info structure
- * &amp;lt; at &amp;gt;size_pvt:size of private storage needed
- * &amp;lt; at &amp;gt;nr_csrows:Number of CWROWS needed for this MC
- * &amp;lt; at &amp;gt;nr_chans:Number of channels for the MC
+ * edac_mc_alloc: Allocate and partially fill a struct mem_ctl_info structure
+ * &amp;lt; at &amp;gt;mc_num:Memory controller number
+ * &amp;lt; at &amp;gt;n_layers:Number of MC hierarchy layers
+ * layers:Describes each layer as seen by the Memory Controller
+ * &amp;lt; at &amp;gt;size_pvt:size of private storage needed
+ *
  *
  * Everything is kmalloc'ed as one big chunk - more efficient.
  * Only can be used if all structures have the same lifetime - otherwise
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -168,22 +188,49 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void *edac_align_ptr(void **p, unsigned size, int n_elems)
  *
  * Use edac_mc_free() to free mc structures allocated by this function.
  *
+ * NOTE: drivers handle multi-rank memories in different ways: in some
+ * drivers, one multi-rank memory stick is mapped as one entry, while, in
+ * others, a single multi-rank memory stick would be mapped into several
+ * entries. Currently, this function will allocate multiple struct dimm_info
+ * on such scenarios, as grouping the multiple ranks require drivers change.
+ *
  * Returns:
  *NULL allocation failed
  *struct mem_ctl_info pointer
  */
-struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
-unsigned nr_chans, int edac_index)
+struct mem_ctl_info *new_edac_mc_alloc(unsigned mc_num,
+       unsigned n_layers,
+       struct edac_mc_layer *layers,
+       unsigned sz_pvt)
 {
-void *ptr = NULL;
 struct mem_ctl_info *mci;
-struct csrow_info *csi, *csrow;
+struct edac_mc_layer *layer;
+struct csrow_info *csi, *csr;
 struct rank_info *chi, *chp, *chan;
 struct dimm_info *dimm;
-void *pvt;
-unsigned size;
-int row, chn;
-int err;
+u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
+unsigned pos[EDAC_MAX_LAYERS];
+void *pvt, *ptr = NULL;
+unsigned size, tot_dimms = 1, count = 1;
+unsigned tot_csrows = 1, tot_channels = 1, tot_errcount = 0;
+int i, j, err, row, chn;
+bool per_rank = false;
+
+BUG_ON(n_layers &amp;gt; EDAC_MAX_LAYERS || n_layers == 0);
+/*
+ * Calculate the total amount of dimms and csrows/cschannels while
+ * in the old API emulation mode
+ */
+for (i = 0; i &amp;lt; n_layers; i++) {
+tot_dimms *= layers[i].size;
+if (layers[i].is_virt_csrow)
+tot_csrows *= layers[i].size;
+else
+tot_channels *= layers[i].size;
+
+if (layers[i].type == EDAC_MC_LAYER_CHIP_SELECT)
+per_rank = true;
+}
 
 /* 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
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -191,12 +238,27 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
  * hardcode everything into a single struct.
  */
 mci = edac_align_ptr(&amp;amp;ptr, sizeof(*mci), 1);
-csi = edac_align_ptr(&amp;amp;ptr, sizeof(*csi), nr_csrows);
-chi = edac_align_ptr(&amp;amp;ptr, sizeof(*chi), nr_csrows * nr_chans);
-dimm = edac_align_ptr(&amp;amp;ptr, sizeof(*dimm), nr_csrows * nr_chans);
+layer = edac_align_ptr(&amp;amp;ptr, sizeof(*layer), n_layers);
+csi = edac_align_ptr(&amp;amp;ptr, sizeof(*csi), tot_csrows);
+chi = edac_align_ptr(&amp;amp;ptr, sizeof(*chi), tot_csrows * tot_channels);
+dimm = edac_align_ptr(&amp;amp;ptr, sizeof(*dimm), tot_dimms);
+for (i = 0; i &amp;lt; n_layers; i++) {
+count *= layers[i].size;
+debugf4("%s: errcount layer %d size %d\n", __func__, i, count);
+ce_per_layer[i] = edac_align_ptr(&amp;amp;ptr, sizeof(u32), count);
+ue_per_layer[i] = edac_align_ptr(&amp;amp;ptr, sizeof(u32), count);
+tot_errcount += 2 * count;
+}
+
+debugf4("%s: allocating %d error counters\n", __func__, tot_errcount);
 pvt = edac_align_ptr(&amp;amp;ptr, sz_pvt, 1);
 size = ((unsigned long)pvt) + sz_pvt;
 
+debugf1("%s(): allocating %u bytes for mci data (%d %s, %d csrows/channels)\n",
+__func__, size,
+tot_dimms,
+per_rank ? "ranks" : "dimms",
+tot_csrows * tot_channels);
 mci = kzalloc(size, GFP_KERNEL);
 if (mci == NULL)
 return NULL;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -204,42 +266,87 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
 /* Adjust pointers so they point within the memory we just allocated
  * rather than an imaginary chunk of memory located at address 0.
  */
+layer = (struct edac_mc_layer *)(((char *)mci) + ((unsigned long)layer));
 csi = (struct csrow_info *)(((char *)mci) + ((unsigned long)csi));
 chi = (struct rank_info *)(((char *)mci) + ((unsigned long)chi));
 dimm = (struct dimm_info *)(((char *)mci) + ((unsigned long)dimm));
+for (i = 0; i &amp;lt; n_layers; i++) {
+mci-&amp;gt;ce_per_layer[i] = (u32 *)((char *)mci + ((unsigned long)ce_per_layer[i]));
+mci-&amp;gt;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-&amp;gt;mc_idx = edac_index;
+mci-&amp;gt;mc_idx = mc_num;
 mci-&amp;gt;csrows = csi;
 mci-&amp;gt;dimms  = dimm;
+mci-&amp;gt;tot_dimms = tot_dimms;
 mci-&amp;gt;pvt_info = pvt;
-mci-&amp;gt;nr_csrows = nr_csrows;
+mci-&amp;gt;n_layers = n_layers;
+mci-&amp;gt;layers = layer;
+memcpy(mci-&amp;gt;layers, layers, sizeof(*layer) * n_layers);
+mci-&amp;gt;nr_csrows = tot_csrows;
+mci-&amp;gt;num_cschannel = tot_channels;
+mci-&amp;gt;mem_is_per_rank = per_rank;
 
 /*
- * For now, assumes that a per-csrow arrangement for dimms.
- * This will be latter changed.
+ * Fill the csrow struct
  */
-dimm = mci-&amp;gt;dimms;
-
-for (row = 0; row &amp;lt; nr_csrows; row++) {
-csrow = &amp;amp;csi[row];
-csrow-&amp;gt;csrow_idx = row;
-csrow-&amp;gt;mci = mci;
-csrow-&amp;gt;nr_channels = nr_chans;
-chp = &amp;amp;chi[row * nr_chans];
-csrow-&amp;gt;channels = chp;
-
-for (chn = 0; chn &amp;lt; nr_chans; chn++) {
+for (row = 0; row &amp;lt; tot_csrows; row++) {
+csr = &amp;amp;csi[row];
+csr-&amp;gt;csrow_idx = row;
+csr-&amp;gt;mci = mci;
+csr-&amp;gt;nr_channels = tot_channels;
+chp = &amp;amp;chi[row * tot_channels];
+csr-&amp;gt;channels = chp;
+
+for (chn = 0; chn &amp;lt; tot_channels; chn++) {
 chan = &amp;amp;chp[chn];
 chan-&amp;gt;chan_idx = chn;
-chan-&amp;gt;csrow = csrow;
+chan-&amp;gt;csrow = csr;
+}
+}
+
+/*
+ * Fill the dimm struct
+ */
+memset(&amp;amp;pos, 0, sizeof(pos));
+row = 0;
+chn = 0;
+debugf4("%s: initializing %d %s\n", __func__, tot_dimms,
+per_rank ? "ranks" : "dimms");
+for (i = 0; i &amp;lt; tot_dimms; i++) {
+chan = &amp;amp;csi[row].channels[chn];
+dimm = EDAC_DIMM_PTR(layer, mci-&amp;gt;dimms, n_layers,
+       pos[0], pos[1], pos[2]);
+dimm-&amp;gt;mci = mci;
+
+debugf2("%s: %d: %s%zd (%d:%d:%d): row %d, chan %d\n", __func__,
+i, per_rank ? "rank" : "dimm", (dimm - mci-&amp;gt;dimms),
+pos[0], pos[1], pos[2], row, chn);
+
+/* Copy DIMM location */
+for (j = 0; j &amp;lt; n_layers; j++)
+dimm-&amp;gt;location[j] = pos[j];
+
+/* Link it to the csrows old API data */
+chan-&amp;gt;dimm = dimm;
+dimm-&amp;gt;csrow = row;
+dimm-&amp;gt;cschannel = chn;
+
+/* Increment csrow location */
+row++;
+if (row == tot_csrows) {
+row = 0;
+chn++;
+}
 
-mci-&amp;gt;csrows[row].channels[chn].dimm = dimm;
-dimm-&amp;gt;csrow = row;
-dimm-&amp;gt;csrow_channel = chn;
-dimm++;
-mci-&amp;gt;nr_dimms++;
+/* Increment dimm location */
+for (j = n_layers - 1; j &amp;gt;= 0; j--) {
+pos[j]++;
+if (pos[j] &amp;lt; layers[j].size)
+break;
+pos[j] = 0;
 }
 }
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -263,6 +370,46 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
  */
 return mci;
 }
+EXPORT_SYMBOL_GPL(new_edac_mc_alloc);
+
+/**
+ * edac_mc_alloc: Allocate and partially fill a struct mem_ctl_info structure
+ * &amp;lt; at &amp;gt;mc_num:Memory controller number
+ * &amp;lt; at &amp;gt;n_layers:Number of layers at the MC hierarchy
+ * layers:Describes each layer as seen by the Memory Controller
+ * &amp;lt; at &amp;gt;size_pvt:Size of private storage needed
+ *
+ *
+ * FIXME: drivers handle multi-rank memories in different ways: some
+ * drivers map multi-ranked DIMMs as one DIMM while others
+ * as several DIMMs.
+ *
+ * Everything is kmalloc'ed as one big chunk - more efficient.
+ * It can only be used if all structures have the same lifetime - otherwise
+ * you have to allocate and initialize your own structures.
+ *
+ * Use edac_mc_free() to free mc structures allocated by this function.
+ *
+ * Returns:
+ *On failure: NULL
+ *On success: struct mem_ctl_info pointer
+ */
+
+struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows,
+   unsigned nr_chans, int mc_num)
+{
+unsigned n_layers = 2;
+struct edac_mc_layer layers[n_layers];
+
+layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+layers[0].size = nr_csrows;
+layers[0].is_virt_csrow = true;
+layers[1].type = EDAC_MC_LAYER_CHANNEL;
+layers[1].size = nr_chans;
+layers[1].is_virt_csrow = false;
+
+return new_edac_mc_alloc(mc_num, ARRAY_SIZE(layers), layers, sz_pvt);
+}
 EXPORT_SYMBOL_GPL(edac_mc_alloc);
 
 /**
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -528,7 +675,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; EXPORT_SYMBOL(edac_mc_find);
  * edac_mc_add_mc: Insert the 'mci' structure into the mci global list and
  *                 create sysfs entries associated with mci structure
  * &amp;lt; at &amp;gt;mci: pointer to the mci structure to be added to the list
- * &amp;lt; at &amp;gt;mc_idx: A unique numeric identifier to be assigned to the 'mci' structure.
  *
  * Return:
  *0Success
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -555,6 +701,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; int edac_mc_add_mc(struct mem_ctl_info *mci)
 edac_mc_dump_channel(&amp;amp;mci-&amp;gt;csrows[i].
 channels[j]);
 }
+for (i = 0; i &amp;lt; mci-&amp;gt;tot_dimms; i++)
+edac_mc_dump_dimm(&amp;amp;mci-&amp;gt;dimms[i]);
 }
 #endif
 mutex_lock(&amp;amp;mem_ctls_mutex);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -712,261 +860,307 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page)
 }
 EXPORT_SYMBOL_GPL(edac_mc_find_csrow_by_page);
 
-/* FIXME - setable log (warning/emerg) levels */
-/* FIXME - integrate with evlog: http://evlog.sourceforge.net/ */
-void edac_mc_handle_ce(struct mem_ctl_info *mci,
-unsigned long page_frame_number,
-unsigned long offset_in_page, unsigned long syndrome,
-int row, int channel, const char *msg)
+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);
+
+static void edac_inc_ce_error(struct mem_ctl_info *mci,
+    bool enable_per_layer_report,
+    const int pos[EDAC_MAX_LAYERS])
 {
-unsigned long remapped_page;
-char *label = NULL;
-u32 grain;
+int i, index = 0;
 
-debugf3("MC%d: %s()\n", mci-&amp;gt;mc_idx, __func__);
+mci-&amp;gt;ce_count++;
 
-/* FIXME - maybe make panic on INTERNAL ERROR an option */
-if (row &amp;gt;= mci-&amp;gt;nr_csrows || row &amp;lt; 0) {
-/* something is wrong */
-edac_mc_printk(mci, KERN_ERR,
-"INTERNAL ERROR: row out of range "
-"(%d &amp;gt;= %d)\n", row, mci-&amp;gt;nr_csrows);
-edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
+if (!enable_per_layer_report) {
+mci-&amp;gt;ce_noinfo_count++;
 return;
 }
 
-if (channel &amp;gt;= mci-&amp;gt;csrows[row].nr_channels || channel &amp;lt; 0) {
-/* something is wrong */
-edac_mc_printk(mci, KERN_ERR,
-"INTERNAL ERROR: channel out of range "
-"(%d &amp;gt;= %d)\n", channel,
-mci-&amp;gt;csrows[row].nr_channels);
-edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
+for (i = 0; i &amp;lt; mci-&amp;gt;n_layers; i++) {
+if (pos[i] &amp;lt; 0)
+break;
+index += pos[i];
+mci-&amp;gt;ce_per_layer[i][index]++;
+
+if (i &amp;lt; mci-&amp;gt;n_layers - 1)
+index *= mci-&amp;gt;layers[i + 1].size;
+}
+}
+
+static void edac_inc_ue_error(struct mem_ctl_info *mci,
+    bool enable_per_layer_report,
+    const int pos[EDAC_MAX_LAYERS])
+{
+int i, index = 0;
+
+mci-&amp;gt;ue_count++;
+
+if (!enable_per_layer_report) {
+mci-&amp;gt;ce_noinfo_count++;
 return;
 }
 
-label = mci-&amp;gt;csrows[row].channels[channel].dimm-&amp;gt;label;
-grain = mci-&amp;gt;csrows[row].channels[channel].dimm-&amp;gt;grain;
+for (i = 0; i &amp;lt; mci-&amp;gt;n_layers; i++) {
+if (pos[i] &amp;lt; 0)
+break;
+index += pos[i];
+mci-&amp;gt;ue_per_layer[i][index]++;
 
-if (edac_mc_get_log_ce())
-/* FIXME - put in DIMM location */
-edac_mc_printk(mci, KERN_WARNING,
-"CE page 0x%lx, offset 0x%lx, grain %d, syndrome "
-"0x%lx, row %d, channel %d, label \"%s\": %s\n",
-page_frame_number, offset_in_page,
-grain, syndrome, row, channel,
-label, msg);
+if (i &amp;lt; mci-&amp;gt;n_layers - 1)
+index *= mci-&amp;gt;layers[i + 1].size;
+}
+}
 
-mci-&amp;gt;ce_count++;
-mci-&amp;gt;csrows[row].ce_count++;
-mci-&amp;gt;csrows[row].channels[channel].dimm-&amp;gt;ce_count++;
-mci-&amp;gt;csrows[row].channels[channel].ce_count++;
+static void edac_ce_error(struct mem_ctl_info *mci,
+  const int pos[EDAC_MAX_LAYERS],
+  const char *msg,
+  const char *location,
+  const char *label,
+  const char *detail,
+  const char *other_detail,
+  const bool enable_per_layer_report,
+  const unsigned long page_frame_number,
+  const unsigned long offset_in_page,
+  u32 grain)
+{
+unsigned long remapped_page;
+
+if (edac_mc_get_log_ce()) {
+if (other_detail &amp;amp;&amp;amp; *other_detail)
+edac_mc_printk(mci, KERN_WARNING,
+       "CE %s on %s (%s%s - %s)\n",
+       msg, label, location,
+       detail, other_detail);
+else
+edac_mc_printk(mci, KERN_WARNING,
+       "CE %s on %s (%s%s)\n",
+       msg, label, location,
+       detail);
+}
+edac_inc_ce_error(mci, enable_per_layer_report, pos);
 
 if (mci-&amp;gt;scrub_mode &amp;amp; SCRUB_SW_SRC) {
 /*
- * Some MC's can remap memory so that it is still available
- * at a different address when PCI devices map into memory.
- * MC's that can't do this lose the memory where PCI devices
- * are mapped.  This mapping is MC dependent and so we call
- * back into the MC driver for it to map the MC page to
- * a physical (CPU) page which can then be mapped to a virtual
- * page - which can then be scrubbed.
- */
+* Some memory controllers (called MCs below) can remap
+* memory so that it is still available at a different
+* address when PCI devices map into memory.
+* MC's that can't do this, lose the memory where PCI
+* devices are mapped. This mapping is MC-dependent
+* and so we call back into the MC driver for it to
+* map the MC page to a physical (CPU) page which can
+* then be mapped to a virtual page - which can then
+* be scrubbed.
+*/
 remapped_page = mci-&amp;gt;ctl_page_to_phys ?
 mci-&amp;gt;ctl_page_to_phys(mci, page_frame_number) :
 page_frame_number;
 
-edac_mc_scrub_block(remapped_page, offset_in_page, grain);
+edac_mc_scrub_block(remapped_page,
+offset_in_page, grain);
 }
 }
-EXPORT_SYMBOL_GPL(edac_mc_handle_ce);
 
-void edac_mc_handle_ce_no_info(struct mem_ctl_info *mci, const char *msg)
+static void edac_ue_error(struct mem_ctl_info *mci,
+  const int pos[EDAC_MAX_LAYERS],
+  const char *msg,
+  const char *location,
+  const char *label,
+  const char *detail,
+  const char *other_detail,
+  const bool enable_per_layer_report)
 {
-if (edac_mc_get_log_ce())
-edac_mc_printk(mci, KERN_WARNING,
-"CE - no information available: %s\n", msg);
+if (edac_mc_get_log_ue()) {
+if (other_detail &amp;amp;&amp;amp; *other_detail)
+edac_mc_printk(mci, KERN_WARNING,
+       "UE %s on %s (%s%s - %s)\n",
+               msg, label, location, detail,
+       other_detail);
+else
+edac_mc_printk(mci, KERN_WARNING,
+       "UE %s on %s (%s%s)\n",
+               msg, label, location, detail);
+}
 
-mci-&amp;gt;ce_noinfo_count++;
-mci-&amp;gt;ce_count++;
+if (edac_mc_get_panic_on_ue()) {
+if (other_detail &amp;amp;&amp;amp; *other_detail)
+panic("UE %s on %s (%s%s - %s)\n",
+      msg, label, location, detail, other_detail);
+else
+panic("UE %s on %s (%s%s)\n",
+      msg, label, location, detail);
+}
+
+edac_inc_ue_error(mci, enable_per_layer_report, pos);
 }
-EXPORT_SYMBOL_GPL(edac_mc_handle_ce_no_info);
 
-void edac_mc_handle_ue(struct mem_ctl_info *mci,
-unsigned long page_frame_number,
-unsigned long offset_in_page, int row, const char *msg)
+#define OTHER_LABEL " or "
+void edac_mc_handle_error(const enum hw_event_mc_err_type type,
+  struct mem_ctl_info *mci,
+  const unsigned long page_frame_number,
+  const unsigned long offset_in_page,
+  const unsigned long syndrome,
+  const int layer0,
+  const int layer1,
+  const int layer2,
+  const char *msg,
+  const char *other_detail,
+  const void *mcelog)
 {
-int len = EDAC_MC_LABEL_LEN * 4;
-char labels[len + 1];
-char *pos = labels;
-int chan;
-int chars;
-char *label = NULL;
+/* FIXME: too much for stack: move it to some pre-alocated area */
+char detail[80], location[80];
+char label[(EDAC_MC_LABEL_LEN + 1 + sizeof(OTHER_LABEL)) * mci-&amp;gt;tot_dimms];
+char *p;
+int row = -1, chan = -1;
+int pos[EDAC_MAX_LAYERS] = { layer0, layer1, layer2 };
+int i;
 u32 grain;
+bool enable_per_layer_report = false;
 
 debugf3("MC%d: %s()\n", mci-&amp;gt;mc_idx, __func__);
 
-/* FIXME - maybe make panic on INTERNAL ERROR an option */
-if (row &amp;gt;= mci-&amp;gt;nr_csrows || row &amp;lt; 0) {
-/* something is wrong */
-edac_mc_printk(mci, KERN_ERR,
-"INTERNAL ERROR: row out of range "
-"(%d &amp;gt;= %d)\n", row, mci-&amp;gt;nr_csrows);
-edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
-return;
-}
-
-grain = mci-&amp;gt;csrows[row].channels[0].dimm-&amp;gt;grain;
-label = mci-&amp;gt;csrows[row].channels[0].dimm-&amp;gt;label;
-chars = snprintf(pos, len + 1, "%s", label);
-len -= chars;
-pos += chars;
-
-for (chan = 1; (chan &amp;lt; mci-&amp;gt;csrows[row].nr_channels) &amp;amp;&amp;amp; (len &amp;gt; 0);
-chan++) {
-label = mci-&amp;gt;csrows[row].channels[chan].dimm-&amp;gt;label;
-chars = snprintf(pos, len + 1, ":%s", label);
-len -= chars;
-pos += chars;
+/*
+ * Check if the event report is consistent and if the memory
+ * location is known. If it is known, enable_per_layer_report will be
+ * true, the DIMM(s) label info will be filled and the per-layer
+ * error counters will be incremented.
+ */
+for (i = 0; i &amp;lt; mci-&amp;gt;n_layers; i++) {
+if (pos[i] &amp;gt;= (int)mci-&amp;gt;layers[i].size) {
+if (type == HW_EVENT_ERR_CORRECTED)
+p = "CE";
+else
+p = "UE";
+
+edac_mc_printk(mci, KERN_ERR,
+       "INTERNAL ERROR: %s value is out of range (%d &amp;gt;= %d)\n",
+       edac_layer_name[mci-&amp;gt;layers[i].type],
+       pos[i], mci-&amp;gt;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] &amp;gt;= 0)
+enable_per_layer_report = true;
 }
 
-if (edac_mc_get_log_ue())
-edac_mc_printk(mci, KERN_EMERG,
-"UE page 0x%lx, offset 0x%lx, grain %d, row %d, "
-"labels \"%s\": %s\n", page_frame_number,
-offset_in_page, grain, row, labels, msg);
-
-if (edac_mc_get_panic_on_ue())
-panic("EDAC MC%d: UE page 0x%lx, offset 0x%lx, grain %d, "
-"row %d, labels \"%s\": %s\n", mci-&amp;gt;mc_idx,
-page_frame_number, offset_in_page,
-grain, row, labels, msg);
-
-mci-&amp;gt;ue_count++;
-mci-&amp;gt;csrows[row].ue_count++;
-}
-EXPORT_SYMBOL_GPL(edac_mc_handle_ue);
-
-void edac_mc_handle_ue_no_info(struct mem_ctl_info *mci, const char *msg)
-{
-if (edac_mc_get_panic_on_ue())
-panic("EDAC MC%d: Uncorrected Error", mci-&amp;gt;mc_idx);
+/*
+ * Get the dimm label/grain that applies to the match criteria.
+ * As the error algorithm may not be able to point to just one memory
+ * stick, the logic here will get all possible labels that could
+ * pottentially be affected by the error.
+ * On FB-DIMM memory controllers, for uncorrected errors, it is common
+ * to have only the MC channel and the MC dimm (also called "branch")
+ * but the channel is not known, as the memory is arranged in pairs,
+ * where each memory belongs to a separate channel within the same
+ * branch.
+ */
+grain = 0;
+p = label;
+*p = '\0';
+for (i = 0; i &amp;lt; mci-&amp;gt;tot_dimms; i++) {
+struct dimm_info *dimm = &amp;amp;mci-&amp;gt;dimms[i];
 
-if (edac_mc_get_log_ue())
-edac_mc_printk(mci, KERN_WARNING,
-"UE - no information available: %s\n", msg);
-mci-&amp;gt;ue_noinfo_count++;
-mci-&amp;gt;ue_count++;
-}
-EXPORT_SYMBOL_GPL(edac_mc_handle_ue_no_info);
+if (layer0 &amp;gt;= 0 &amp;amp;&amp;amp; layer0 != dimm-&amp;gt;location[0])
+continue;
+if (layer1 &amp;gt;= 0 &amp;amp;&amp;amp; layer1 != dimm-&amp;gt;location[1])
+continue;
+if (layer2 &amp;gt;= 0 &amp;amp;&amp;amp; layer2 != dimm-&amp;gt;location[2])
+continue;
 
-/*************************************************************
- * On Fully Buffered DIMM modules, this help function is
- * called to process UE events
- */
-void edac_mc_handle_fbd_ue(struct mem_ctl_info *mci,
-unsigned int csrow,
-unsigned int channela,
-unsigned int channelb, char *msg)
-{
-int len = EDAC_MC_LABEL_LEN * 4;
-char labels[len + 1];
-char *pos = labels;
-int chars;
-char *label;
-
-if (csrow &amp;gt;= mci-&amp;gt;nr_csrows) {
-/* something is wrong */
-edac_mc_printk(mci, KERN_ERR,
-"INTERNAL ERROR: row out of range (%d &amp;gt;= %d)\n",
-csrow, mci-&amp;gt;nr_csrows);
-edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
-return;
-}
+/* get the max grain, over the error match range */
+if (dimm-&amp;gt;grain &amp;gt; grain)
+grain = dimm-&amp;gt;grain;
 
-if (channela &amp;gt;= mci-&amp;gt;csrows[csrow].nr_channels) {
-/* something is wrong */
-edac_mc_printk(mci, KERN_ERR,
-"INTERNAL ERROR: channel-a out of range "
-"(%d &amp;gt;= %d)\n",
-channela, mci-&amp;gt;csrows[csrow].nr_channels);
-edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
-return;
+/*
+ * If the error is memory-controller wide, there's no need to
+ * seek for the affected DIMMs because the whole
+ * channel/memory controller/...  may be affected.
+ * Also, don't show errors for empty DIMM slots.
+ */
+if (enable_per_layer_report &amp;amp;&amp;amp; dimm-&amp;gt;nr_pages) {
+if (p != label) {
+strcpy(p, OTHER_LABEL);
+p += strlen(OTHER_LABEL);
+}
+strcpy(p, dimm-&amp;gt;label);
+p += strlen(p);
+*p = '\0';
+
+/*
+ * get csrow/channel of the DIMM, in order to allow
+ * incrementing the compat API counters
+ */
+debugf4("%s: %s csrows map: (%d,%d)\n",
+__func__,
+mci-&amp;gt;mem_is_per_rank ? "rank" : "dimm",
+dimm-&amp;gt;csrow, dimm-&amp;gt;cschannel);
+
+if (row == -1)
+row = dimm-&amp;gt;csrow;
+else if (row &amp;gt;= 0 &amp;amp;&amp;amp; row != dimm-&amp;gt;csrow)
+row = -2;
+
+if (chan == -1)
+chan = dimm-&amp;gt;cschannel;
+else if (chan &amp;gt;= 0 &amp;amp;&amp;amp; chan != dimm-&amp;gt;cschannel)
+chan = -2;
+}
 }
 
-if (channelb &amp;gt;= mci-&amp;gt;csrows[csrow].nr_channels) {
-/* something is wrong */
-edac_mc_printk(mci, KERN_ERR,
-"INTERNAL ERROR: channel-b out of range "
-"(%d &amp;gt;= %d)\n",
-channelb, mci-&amp;gt;csrows[csrow].nr_channels);
-edac_mc_handle_ue_no_info(mci, "INTERNAL ERROR");
-return;
+if (!enable_per_layer_report) {
+strcpy(label, "any memory");
+} else {
+debugf4("%s: csrow/channel to increment: (%d,%d)\n",
+__func__, row, chan);
+if (p == label)
+strcpy(label, "unknown memory");
+if (type == HW_EVENT_ERR_CORRECTED) {
+if (row &amp;gt;= 0) {
+mci-&amp;gt;csrows[row].ce_count++;
+if (chan &amp;gt;= 0)
+mci-&amp;gt;csrows[row].channels[chan].ce_count++;
+}
+} else
+if (row &amp;gt;= 0)
+mci-&amp;gt;csrows[row].ue_count++;
 }
 
-mci-&amp;gt;ue_count++;
-mci-&amp;gt;csrows[csrow].ue_count++;
-
-/* Generate the DIMM labels from the specified channels */
-label = mci-&amp;gt;csrows[csrow].channels[channela].dimm-&amp;gt;label;
-chars = snprintf(pos, len + 1, "%s", label);
-len -= chars;
-pos += chars;
-
-chars = snprintf(pos, len + 1, "-%s",
-mci-&amp;gt;csrows[csrow].channels[channelb].dimm-&amp;gt;label);
-
-if (edac_mc_get_log_ue())
-edac_mc_printk(mci, KERN_EMERG,
-"UE row %d, channel-a= %d channel-b= %d "
-"labels \"%s\": %s\n", csrow, channela, channelb,
-labels, msg);
-
-if (edac_mc_get_panic_on_ue())
-panic("UE row %d, channel-a= %d channel-b= %d "
-"labels \"%s\": %s\n", csrow, channela,
-channelb, labels, msg);
-}
-EXPORT_SYMBOL(edac_mc_handle_fbd_ue);
-
-/*************************************************************
- * On Fully Buffered DIMM modules, this help function is
- * called to process CE events
- */
-void edac_mc_handle_fbd_ce(struct mem_ctl_info *mci,
-unsigned int csrow, unsigned int channel, char *msg)
-{
-char *label = NULL;
+/* Fill the RAM location data */
+p = location;
+for (i = 0; i &amp;lt; mci-&amp;gt;n_layers; i++) {
+if (pos[i] &amp;lt; 0)
+continue;
 
-/* Ensure boundary values */
-if (csrow &amp;gt;= mci-&amp;gt;nr_csrows) {
-/* something is wrong */
-edac_mc_printk(mci, KERN_ERR,
-"INTERNAL ERROR: row out of range (%d &amp;gt;= %d)\n",
-csrow, mci-&amp;gt;nr_csrows);
-edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
-return;
+p += sprintf(p, "%s:%d ",
+     edac_layer_name[mci-&amp;gt;layers[i].type],
+     pos[i]);
 }
-if (channel &amp;gt;= mci-&amp;gt;csrows[csrow].nr_channels) {
-/* something is wrong */
-edac_mc_printk(mci, KERN_ERR,
-"INTERNAL ERROR: channel out of range (%d &amp;gt;= %d)\n",
-channel, mci-&amp;gt;csrows[csrow].nr_channels);
-edac_mc_handle_ce_no_info(mci, "INTERNAL ERROR");
-return;
-}
-
-label = mci-&amp;gt;csrows[csrow].channels[channel].dimm-&amp;gt;label;
 
-if (edac_mc_get_log_ce())
-/* FIXME - put in DIMM location */
-edac_mc_printk(mci, KERN_WARNING,
-"CE row %d, channel %d, label \"%s\": %s\n",
-csrow, channel, label, msg);
+/* Memory type dependent details about the error */
+if (type == HW_EVENT_ERR_CORRECTED) {
+snprintf(detail, sizeof(detail),
+"page:0x%lx offset:0x%lx grain:%d syndrome:0x%lx",
+page_frame_number, offset_in_page,
+grain, syndrome);
+edac_ce_error(mci, pos, msg, location, label, detail,
+      other_detail, enable_per_layer_report,
+      page_frame_number, offset_in_page, grain);
+} else {
+snprintf(detail, sizeof(detail),
+"page:0x%lx offset:0x%lx grain:%d",
+page_frame_number, offset_in_page, grain);
 
-mci-&amp;gt;ce_count++;
-mci-&amp;gt;csrows[csrow].ce_count++;
-mci-&amp;gt;csrows[csrow].channels[channel].dimm-&amp;gt;ce_count++;
-mci-&amp;gt;csrows[csrow].channels[channel].ce_count++;
+edac_ue_error(mci, pos, msg, location, label, detail,
+      other_detail, enable_per_layer_report);
+}
 }
-EXPORT_SYMBOL(edac_mc_handle_fbd_ce);
+EXPORT_SYMBOL_GPL(edac_mc_handle_error);
diff --git a/include/linux/edac.h b/include/linux/edac.h
index 9e628434e..d68b01c 100644
--- a/include/linux/edac.h
+++ b/include/linux/edac.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -416,18 +416,20 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct edac_mc_layer {
 /* FIXME: add the proper per-location error counts */
 struct dimm_info {
 char label[EDAC_MC_LABEL_LEN + 1];/* DIMM label on motherboard */
-unsigned memory_controller;
-unsigned csrow;
-unsigned csrow_channel;
+
+/* Memory location data */
+unsigned location[EDAC_MAX_LAYERS];
+
+struct mem_ctl_info *mci;/* the parent */
 
 u32 grain;/* granularity of reported error in bytes */
 enum dev_type dtype;/* memory device type */
 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 */
 
-u32 ce_count;/* Correctable Errors for this dimm */
+unsigned csrow, cschannel;/* Points to the old API data */
 };
 
 /**
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -447,9 +449,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct dimm_info {
  */
 struct rank_info {
 int chan_idx;
-u32 ce_count;
 struct csrow_info *csrow;
 struct dimm_info *dimm;
+
+u32 ce_count;/* Correctable Errors for this csrow */
 };
 
 struct csrow_info {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -545,13 +548,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct mem_ctl_info {
 unsigned long (*ctl_page_to_phys) (struct mem_ctl_info * mci,
    unsigned long page);
 int mc_idx;
-int nr_csrows;
 struct csrow_info *csrows;
+unsigned nr_csrows, num_cschannel;
+
+/* Memory Controller hierarchy */
+unsigned n_layers;
+struct edac_mc_layer *layers;
+bool mem_is_per_rank;
 
 /*
  * DIMM info. Will eventually remove the entire csrows_info some day
  */
-unsigned nr_dimms;
+unsigned tot_dimms;
 struct dimm_info *dimms;
 
 /*
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -566,12 +574,16 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct mem_ctl_info {
 const char *dev_name;
 char proc_name[MC_PROC_NAME_MAX_LEN + 1];
 void *pvt_info;
-u32 ue_noinfo_count;/* Uncorrectable Errors w/o info */
-u32 ce_noinfo_count;/* Correctable Errors w/o info */
-u32 ue_count;/* Total Uncorrectable Errors for this MC */
-u32 ce_count;/* Total Correctable Errors for this MC */
 unsigned long start_time;/* mci load start time (in jiffies) */
 
+/*
+ * drivers shouldn't access those fields directly, as the core
+ * already handles that.
+ */
+u32 ce_noinfo_count, ue_noinfo_count;
+u32 ue_count, ce_count;
+u32 *ce_per_layer[EDAC_MAX_LAYERS], *ue_per_layer[EDAC_MAX_LAYERS];
+
 struct completion complete;
 
 /* edac sysfs device control */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -584,7 +596,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct mem_ctl_info {
  * by the low level driver.
  *
  * Set by the low level driver to provide attributes at the
- * controller level, same level as 'ue_count' and 'ce_count' above.
+ * controller level.
  * An array of structures, NULL terminated
  *
  * If attributes are desired, then set to array of attributes
&lt;/pre&gt;</description>
    <dc:creator>Mauro Carvalho Chehab</dc:creator>
    <dc:date>2012-05-18T16:31:54</dc:date>
  </item>
  <item rdf:about="http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82146">
    <title>[PATCH EDAC v26 27/66] pasemi_edac: convert driver to use the new edac ABI</title>
    <link>http://permalink.gmane.org/gmane.linux.ports.ppc64.devel/82146</link>
    <description>&lt;pre&gt;The legacy edac ABI is going to be removed. Port the driver to use
and benefit from the new API functionality.

Cc: Olof Johansson &amp;lt;olof&amp;lt; at &amp;gt;lixom.net&amp;gt;
Cc: Egor Martovetsky &amp;lt;egor&amp;lt; at &amp;gt;pasemi.com&amp;gt;
Cc: linuxppc-dev&amp;lt; at &amp;gt;lists.ozlabs.org
Signed-off-by: Mauro Carvalho Chehab &amp;lt;mchehab&amp;lt; at &amp;gt;redhat.com&amp;gt;
---
 drivers/edac/pasemi_edac.c |   25 ++++++++++++++++---------
 1 files changed, 16 insertions(+), 9 deletions(-)

diff --git a/drivers/edac/pasemi_edac.c b/drivers/edac/pasemi_edac.c
index 3fcefda..46aed62 100644
--- a/drivers/edac/pasemi_edac.c
+++ b/drivers/edac/pasemi_edac.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -110,15 +110,16 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void pasemi_edac_process_error_info(struct mem_ctl_info *mci, u32 errsta)
 /* uncorrectable/multi-bit errors */
 if (errsta &amp;amp; (MCDEBUG_ERRSTA_MBE_STATUS |
       MCDEBUG_ERRSTA_RFL_STATUS)) {
-edac_mc_handle_ue(mci, mci-&amp;gt;csrows[cs].first_page, 0,
-  cs, mci-&amp;gt;ctl_name);
+edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+     mci-&amp;gt;csrows[cs].first_page, 0, 0,
+     cs, 0, -1, mci-&amp;gt;ctl_name, "", NULL);
 }
 
 /* correctable/single-bit errors */
-if (errsta &amp;amp; MCDEBUG_ERRSTA_SBE_STATUS) {
-edac_mc_handle_ce(mci, mci-&amp;gt;csrows[cs].first_page, 0,
-  0, cs, 0, mci-&amp;gt;ctl_name);
-}
+if (errsta &amp;amp; MCDEBUG_ERRSTA_SBE_STATUS)
+edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+     mci-&amp;gt;csrows[cs].first_page, 0, 0,
+     cs, 0, -1, mci-&amp;gt;ctl_name, "", NULL);
 }
 
 static void pasemi_edac_check(struct mem_ctl_info *mci)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -191,6 +192,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; 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, &amp;amp;mcen);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -207,9 +209,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int __devinit pasemi_edac_probe(struct pci_dev *pdev,
 MCDEBUG_ERRCTL1_RFL_LOG_EN;
 pci_write_config_dword(pdev, MCDEBUG_ERRCTL1, errctl1);
 
-mci = edac_mc_alloc(0, PASEMI_EDAC_NR_CSROWS, PASEMI_EDAC_NR_CHANS,
-system_mmc_id++);
-
+layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+layers[0].size = PASEMI_EDAC_NR_CSROWS;
+layers[0].is_virt_csrow = true;
+layers[1].type = EDAC_MC_LAYER_CHANNEL;
+layers[1].size = PASEMI_EDAC_NR_CHANS;
+layers[1].is_virt_csrow = false;
+mci = new_edac_mc_alloc(system_mmc_id++, ARRAY_SIZE(layers), layers,
+    0);
 if (mci == NULL)
 return -ENOMEM;
 
&lt;/pre&gt;</description>
    <dc:creator>Mauro Carvalho Chehab</dc:creator>
    <dc:date>2012-05-18T16:32:14</dc:date>
  </item>
  <textinput rdf:about="http://search.gmane.org/?group=$group=gmane.linux.ports.ppc64.devel">
    <title>Search Engine</title>
    <description>Search the mailing list at Gmane</description>
    <name>query</name>
    <link>http://search.gmane.org/?group=$group=gmane.linux.ports.ppc64.devel</link>
  </textinput>
</rdf:RDF>

