LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] fbdev: Add PLB support and cleanup DCR in xilinxfb driver.
From: Grant Likely @ 2009-05-15 18:19 UTC (permalink / raw)
  To: linuxppc-dev, linux-fbdev-devel, Antonino Daplas; +Cc: Suneel, John Linn

From: John Linn <john.linn@xilinx.com>

Added support for the new xps tft controller. The new core
has PLB interface support in addition to existing DCR interface.

Removed platform device support as both MicroBlaze and PowerPC
use device tree.

Previously, the dcr interface was assumed to be used in mmio mode,
and the register space of the dcr interface was precomputed and stuffed
into the device tree. This driver now makes use of the new dcr
infrastructure to represent the dcr interface. This enables the dcr
interface to be connected directly to a native dcr interface in a clean
way.

Added compatibility for ml507 dvi core.

Signed-off-by: Suneel <suneelg@xilinx.com>
Signed-off-by: Stephen Neuendorffer <stephen.neuendorffer@xilinx.com>
Signed-off-by: John Linn <john.linn@xilinx.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
---

Antonino,

This patch has gone through a couple of cycles of review on the linuxppc
mailing list (the linux-fbdev mailing list wasn't cc'd unfortunately,
hence I'm reposting it).  I think it's ready to be merged.  Can you please
comment and/or pick it up?

If you prefer, I'm willing to merge it via my powerpc tree.

Thanks,
g.

 drivers/video/xilinxfb.c |  290 ++++++++++++++++++++++++----------------------
 1 files changed, 151 insertions(+), 139 deletions(-)


diff --git a/drivers/video/xilinxfb.c b/drivers/video/xilinxfb.c
index 40a3a2a..7a868bd 100644
--- a/drivers/video/xilinxfb.c
+++ b/drivers/video/xilinxfb.c
@@ -1,13 +1,12 @@
 /*
- * xilinxfb.c
- *
- * Xilinx TFT LCD frame buffer driver
+ * Xilinx TFT frame buffer driver
  *
  * Author: MontaVista Software, Inc.
  *         source@mvista.com
  *
  * 2002-2007 (c) MontaVista Software, Inc.
  * 2007 (c) Secret Lab Technologies, Ltd.
+ * 2009 (c) Xilinx Inc.
  *
  * This file is licensed under the terms of the GNU General Public License
  * version 2.  This program is licensed "as is" without any warranty of any
@@ -24,33 +23,38 @@
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/version.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-#if defined(CONFIG_OF)
 #include <linux/of_device.h>
 #include <linux/of_platform.h>
-#endif
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/xilinxfb.h>
+#include <asm/dcr.h>
 
 #define DRIVER_NAME		"xilinxfb"
-#define DRIVER_DESCRIPTION	"Xilinx TFT LCD frame buffer driver"
+
 
 /*
  * Xilinx calls it "PLB TFT LCD Controller" though it can also be used for
- * the VGA port on the Xilinx ML40x board. This is a hardware display controller
- * for a 640x480 resolution TFT or VGA screen.
+ * the VGA port on the Xilinx ML40x board. This is a hardware display
+ * controller for a 640x480 resolution TFT or VGA screen.
  *
  * The interface to the framebuffer is nice and simple.  There are two
  * control registers.  The first tells the LCD interface where in memory
  * the frame buffer is (only the 11 most significant bits are used, so
  * don't start thinking about scrolling).  The second allows the LCD to
  * be turned on or off as well as rotated 180 degrees.
+ *
+ * In case of direct PLB access the second control register will be at
+ * an offset of 4 as compared to the DCR access where the offset is 1
+ * i.e. REG_CTRL. So this is taken care in the function
+ * xilinx_fb_out_be32 where it left shifts the offset 2 times in case of
+ * direct PLB access.
  */
 #define NUM_REGS	2
 #define REG_FB_ADDR	0
@@ -107,17 +111,28 @@ static struct fb_var_screeninfo xilinx_fb_var = {
 	.activate =	FB_ACTIVATE_NOW
 };
 
+
+#define PLB_ACCESS_FLAG	0x1		/* 1 = PLB, 0 = DCR */
+
 struct xilinxfb_drvdata {
 
 	struct fb_info	info;		/* FB driver info record */
 
-	u32		regs_phys;	/* phys. address of the control registers */
-	u32 __iomem	*regs;		/* virt. address of the control registers */
+	phys_addr_t	regs_phys;	/* phys. address of the control
+						registers */
+	void __iomem	*regs;		/* virt. address of the control
+						registers */
+
+	dcr_host_t      dcr_host;
+	unsigned int    dcr_start;
+	unsigned int    dcr_len;
 
 	void		*fb_virt;	/* virt. address of the frame buffer */
 	dma_addr_t	fb_phys;	/* phys. address of the frame buffer */
 	int		fb_alloced;	/* Flag, was the fb memory alloced? */
 
+	u8 		flags;		/* features of the driver */
+
 	u32		reg_ctrl_default;
 
 	u32		pseudo_palette[PALETTE_ENTRIES_NO];
@@ -128,14 +143,19 @@ struct xilinxfb_drvdata {
 	container_of(_info, struct xilinxfb_drvdata, info)
 
 /*
- * The LCD controller has DCR interface to its registers, but all
- * the boards and configurations the driver has been tested with
- * use opb2dcr bridge. So the registers are seen as memory mapped.
- * This macro is to make it simple to add the direct DCR access
- * when it's needed.
+ * The XPS TFT Controller can be accessed through PLB or DCR interface.
+ * To perform the read/write on the registers we need to check on
+ * which bus its connected and call the appropriate write API.
  */
-#define xilinx_fb_out_be32(driverdata, offset, val) \
-	out_be32(driverdata->regs + offset, val)
+static void xilinx_fb_out_be32(struct xilinxfb_drvdata *drvdata, u32 offset,
+				u32 val)
+{
+	if (drvdata->flags & PLB_ACCESS_FLAG)
+		out_be32(drvdata->regs + (offset << 2), val);
+	else
+		dcr_write(drvdata->dcr_host, offset, val);
+
+}
 
 static int
 xilinx_fb_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue,
@@ -203,35 +223,34 @@ static struct fb_ops xilinxfb_ops =
  * Bus independent setup/teardown
  */
 
-static int xilinxfb_assign(struct device *dev, unsigned long physaddr,
+static int xilinxfb_assign(struct device *dev,
+			   struct xilinxfb_drvdata *drvdata,
+			   unsigned long physaddr,
 			   struct xilinxfb_platform_data *pdata)
 {
-	struct xilinxfb_drvdata *drvdata;
 	int rc;
 	int fbsize = pdata->xvirt * pdata->yvirt * BYTES_PER_PIXEL;
 
-	/* Allocate the driver data region */
-	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
-	if (!drvdata) {
-		dev_err(dev, "Couldn't allocate device private record\n");
-		return -ENOMEM;
-	}
-	dev_set_drvdata(dev, drvdata);
-
-	/* Map the control registers in */
-	if (!request_mem_region(physaddr, 8, DRIVER_NAME)) {
-		dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
-			physaddr);
-		rc = -ENODEV;
-		goto err_region;
-	}
-	drvdata->regs_phys = physaddr;
-	drvdata->regs = ioremap(physaddr, 8);
-	if (!drvdata->regs) {
-		dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
-			physaddr);
-		rc = -ENODEV;
-		goto err_map;
+	if (drvdata->flags & PLB_ACCESS_FLAG) {
+		/*
+		 * Map the control registers in if the controller
+		 * is on direct PLB interface.
+		 */
+		if (!request_mem_region(physaddr, 8, DRIVER_NAME)) {
+			dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
+				physaddr);
+			rc = -ENODEV;
+			goto err_region;
+		}
+
+		drvdata->regs_phys = physaddr;
+		drvdata->regs = ioremap(physaddr, 8);
+		if (!drvdata->regs) {
+			dev_err(dev, "Couldn't lock memory region at 0x%08lX\n",
+				physaddr);
+			rc = -ENODEV;
+			goto err_map;
+		}
 	}
 
 	/* Allocate the framebuffer memory */
@@ -247,7 +266,10 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr,
 	if (!drvdata->fb_virt) {
 		dev_err(dev, "Could not allocate frame buffer memory\n");
 		rc = -ENOMEM;
-		goto err_fbmem;
+		if (drvdata->flags & PLB_ACCESS_FLAG)
+			goto err_fbmem;
+		else
+			goto err_region;
 	}
 
 	/* Clear (turn to black) the framebuffer */
@@ -260,7 +282,8 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr,
 	drvdata->reg_ctrl_default = REG_CTRL_ENABLE;
 	if (pdata->rotate_screen)
 		drvdata->reg_ctrl_default |= REG_CTRL_ROTATE;
-	xilinx_fb_out_be32(drvdata, REG_CTRL, drvdata->reg_ctrl_default);
+	xilinx_fb_out_be32(drvdata, REG_CTRL,
+					drvdata->reg_ctrl_default);
 
 	/* Fill struct fb_info */
 	drvdata->info.device = dev;
@@ -296,11 +319,14 @@ static int xilinxfb_assign(struct device *dev, unsigned long physaddr,
 		goto err_regfb;
 	}
 
+	if (drvdata->flags & PLB_ACCESS_FLAG) {
+		/* Put a banner in the log (for DEBUG) */
+		dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr,
+					drvdata->regs);
+	}
 	/* Put a banner in the log (for DEBUG) */
-	dev_dbg(dev, "regs: phys=%lx, virt=%p\n", physaddr, drvdata->regs);
-	dev_dbg(dev, "fb: phys=%llx, virt=%p, size=%x\n",
-		(unsigned long long) drvdata->fb_phys, drvdata->fb_virt,
-		fbsize);
+	dev_dbg(dev, "fb: phys=%p, virt=%p, size=%x\n",
+		(void *)drvdata->fb_phys, drvdata->fb_virt, fbsize);
 
 	return 0;	/* success */
 
@@ -311,14 +337,19 @@ err_cmap:
 	if (drvdata->fb_alloced)
 		dma_free_coherent(dev, PAGE_ALIGN(fbsize), drvdata->fb_virt,
 			drvdata->fb_phys);
+	else
+		iounmap(drvdata->fb_virt);
+
 	/* Turn off the display */
 	xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
 
 err_fbmem:
-	iounmap(drvdata->regs);
+	if (drvdata->flags & PLB_ACCESS_FLAG)
+		iounmap(drvdata->regs);
 
 err_map:
-	release_mem_region(physaddr, 8);
+	if (drvdata->flags & PLB_ACCESS_FLAG)
+		release_mem_region(physaddr, 8);
 
 err_region:
 	kfree(drvdata);
@@ -342,12 +373,18 @@ static int xilinxfb_release(struct device *dev)
 	if (drvdata->fb_alloced)
 		dma_free_coherent(dev, PAGE_ALIGN(drvdata->info.fix.smem_len),
 				  drvdata->fb_virt, drvdata->fb_phys);
+	else
+		iounmap(drvdata->fb_virt);
 
 	/* Turn off the display */
 	xilinx_fb_out_be32(drvdata, REG_CTRL, 0);
-	iounmap(drvdata->regs);
 
-	release_mem_region(drvdata->regs_phys, 8);
+	/* Release the resources, as allocated based on interface */
+	if (drvdata->flags & PLB_ACCESS_FLAG) {
+		iounmap(drvdata->regs);
+		release_mem_region(drvdata->regs_phys, 8);
+	} else
+		dcr_unmap(drvdata->dcr_host, drvdata->dcr_len);
 
 	kfree(drvdata);
 	dev_set_drvdata(dev, NULL);
@@ -356,77 +393,57 @@ static int xilinxfb_release(struct device *dev)
 }
 
 /* ---------------------------------------------------------------------
- * Platform bus binding
- */
-
-static int
-xilinxfb_platform_probe(struct platform_device *pdev)
-{
-	struct xilinxfb_platform_data *pdata;
-	struct resource *res;
-
-	/* Find the registers address */
-	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-	if (!res) {
-		dev_err(&pdev->dev, "Couldn't get registers resource\n");
-		return -ENODEV;
-	}
-
-	/* If a pdata structure is provided, then extract the parameters */
-	pdata = &xilinx_fb_default_pdata;
-	if (pdev->dev.platform_data) {
-		pdata = pdev->dev.platform_data;
-		if (!pdata->xres)
-			pdata->xres = xilinx_fb_default_pdata.xres;
-		if (!pdata->yres)
-			pdata->yres = xilinx_fb_default_pdata.yres;
-		if (!pdata->xvirt)
-			pdata->xvirt = xilinx_fb_default_pdata.xvirt;
-		if (!pdata->yvirt)
-			pdata->yvirt = xilinx_fb_default_pdata.yvirt;
-	}
-
-	return xilinxfb_assign(&pdev->dev, res->start, pdata);
-}
-
-static int
-xilinxfb_platform_remove(struct platform_device *pdev)
-{
-	return xilinxfb_release(&pdev->dev);
-}
-
-
-static struct platform_driver xilinxfb_platform_driver = {
-	.probe		= xilinxfb_platform_probe,
-	.remove		= xilinxfb_platform_remove,
-	.driver = {
-		.owner = THIS_MODULE,
-		.name = DRIVER_NAME,
-	},
-};
-
-/* ---------------------------------------------------------------------
  * OF bus binding
  */
 
-#if defined(CONFIG_OF)
 static int __devinit
 xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match)
 {
-	struct resource res;
 	const u32 *prop;
+	u32 *p;
+	u32 tft_access;
 	struct xilinxfb_platform_data pdata;
+	struct resource res;
 	int size, rc;
+	int start = 0, len = 0;
+	dcr_host_t dcr_host;
+	struct xilinxfb_drvdata *drvdata;
 
 	/* Copy with the default pdata (not a ptr reference!) */
 	pdata = xilinx_fb_default_pdata;
 
 	dev_dbg(&op->dev, "xilinxfb_of_probe(%p, %p)\n", op, match);
 
-	rc = of_address_to_resource(op->node, 0, &res);
-	if (rc) {
-		dev_err(&op->dev, "invalid address\n");
-		return rc;
+	/*
+	 * To check whether the core is connected directly to DCR or PLB
+	 * interface and initialize the tft_access accordingly.
+	 */
+	p = (u32 *)of_get_property(op->node, "xlnx,dcr-splb-slave-if", NULL);
+
+	if (p)
+		tft_access = *p;
+	else
+		tft_access = 0;		/* For backward compatibility */
+
+	/*
+	 * Fill the resource structure if its direct PLB interface
+	 * otherwise fill the dcr_host structure.
+	 */
+	if (tft_access) {
+		rc = of_address_to_resource(op->node, 0, &res);
+		if (rc) {
+			dev_err(&op->dev, "invalid address\n");
+			return -ENODEV;
+		}
+
+	} else {
+		start = dcr_resource_start(op->node, 0);
+		len = dcr_resource_len(op->node, 0);
+		dcr_host = dcr_map(op->node, start, len);
+		if (!DCR_MAP_OK(dcr_host)) {
+			dev_err(&op->dev, "invalid address\n");
+			return -ENODEV;
+		}
 	}
 
 	prop = of_get_property(op->node, "phys-size", &size);
@@ -450,7 +467,26 @@ xilinxfb_of_probe(struct of_device *op, const struct of_device_id *match)
 	if (of_find_property(op->node, "rotate-display", NULL))
 		pdata.rotate_screen = 1;
 
-	return xilinxfb_assign(&op->dev, res.start, &pdata);
+	/* Allocate the driver data region */
+	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
+	if (!drvdata) {
+		dev_err(&op->dev, "Couldn't allocate device private record\n");
+		return -ENOMEM;
+	}
+	dev_set_drvdata(&op->dev, drvdata);
+
+	if (tft_access)
+		drvdata->flags |= PLB_ACCESS_FLAG;
+
+	/* Arguments are passed based on the interface */
+	if (drvdata->flags & PLB_ACCESS_FLAG) {
+		return xilinxfb_assign(&op->dev, drvdata, res.start, &pdata);
+	} else {
+		drvdata->dcr_start = start;
+		drvdata->dcr_len = len;
+		drvdata->dcr_host = dcr_host;
+		return xilinxfb_assign(&op->dev, drvdata, 0, &pdata);
+	}
 }
 
 static int __devexit xilinxfb_of_remove(struct of_device *op)
@@ -460,7 +496,9 @@ static int __devexit xilinxfb_of_remove(struct of_device *op)
 
 /* Match table for of_platform binding */
 static struct of_device_id xilinxfb_of_match[] __devinitdata = {
+	{ .compatible = "xlnx,xps-tft-1.00.a", },
 	{ .compatible = "xlnx,plb-tft-cntlr-ref-1.00.a", },
+	{ .compatible = "xlnx,plb-dvi-cntlr-ref-1.00.c", },
 	{},
 };
 MODULE_DEVICE_TABLE(of, xilinxfb_of_match);
@@ -476,22 +514,6 @@ static struct of_platform_driver xilinxfb_of_driver = {
 	},
 };
 
-/* Registration helpers to keep the number of #ifdefs to a minimum */
-static inline int __init xilinxfb_of_register(void)
-{
-	pr_debug("xilinxfb: calling of_register_platform_driver()\n");
-	return of_register_platform_driver(&xilinxfb_of_driver);
-}
-
-static inline void __exit xilinxfb_of_unregister(void)
-{
-	of_unregister_platform_driver(&xilinxfb_of_driver);
-}
-#else /* CONFIG_OF */
-/* CONFIG_OF not enabled; do nothing helpers */
-static inline int __init xilinxfb_of_register(void) { return 0; }
-static inline void __exit xilinxfb_of_unregister(void) { }
-#endif /* CONFIG_OF */
 
 /* ---------------------------------------------------------------------
  * Module setup and teardown
@@ -500,28 +522,18 @@ static inline void __exit xilinxfb_of_unregister(void) { }
 static int __init
 xilinxfb_init(void)
 {
-	int rc;
-	rc = xilinxfb_of_register();
-	if (rc)
-		return rc;
-
-	rc = platform_driver_register(&xilinxfb_platform_driver);
-	if (rc)
-		xilinxfb_of_unregister();
-
-	return rc;
+	return of_register_platform_driver(&xilinxfb_of_driver);
 }
 
 static void __exit
 xilinxfb_cleanup(void)
 {
-	platform_driver_unregister(&xilinxfb_platform_driver);
-	xilinxfb_of_unregister();
+	of_unregister_platform_driver(&xilinxfb_of_driver);
 }
 
 module_init(xilinxfb_init);
 module_exit(xilinxfb_cleanup);
 
 MODULE_AUTHOR("MontaVista Software, Inc. <source@mvista.com>");
-MODULE_DESCRIPTION(DRIVER_DESCRIPTION);
+MODULE_DESCRIPTION("Xilinx TFT frame buffer driver");
 MODULE_LICENSE("GPL");

^ permalink raw reply related

* [PATCH] Allow selecting mv643xx_eth on Pegasos again
From: Gabriel Paubert @ 2009-05-15 18:18 UTC (permalink / raw)
  To: Matt Sealey; +Cc: LinuxPPC

Since PPC_MUTIPLATFORM was removed, it was impossible to select the
driver for mv643xx_eth on the Pegasos. Fix by allowing to select
the driver on CHRP platforms; Pegasos is a CHRP platform and the driver
will not work wihtout arch/powerpc/platforms/chrp/pegasos_eth.

The patch also removes all references to MV64360 config option which 
no more exists.

Signed-off-by: Gabriel Paubert <paubert@iram.es> 

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index a0d1146..1dfeb62 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -360,7 +360,7 @@ config PPCBUG_NVRAM
 
 config IRQ_ALL_CPUS
 	bool "Distribute interrupts on all CPUs by default"
-	depends on SMP && !MV64360
+	depends on SMP 
 	help
 	  This option gives the kernel permission to distribute IRQs across
 	  multiple CPUs.  Saying N here will route all IRQs to the first
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index 214a92d..6fc0ff4 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -2351,7 +2351,7 @@ config UGETH_TX_ON_DEMAND
 
 config MV643XX_ETH
 	tristate "Marvell Discovery (643XX) and Orion ethernet support"
-	depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || PLAT_ORION
+	depends on MV64X60 || PPC_CHRP || PLAT_ORION
 	select INET_LRO
 	select PHYLIB
 	help

^ permalink raw reply related

* [patch] powerpc/ps3: Update ps3_defconfig
From: Geoff Levand @ 2009-05-15 18:01 UTC (permalink / raw)
  To: Benjamin Herrenschmidt; +Cc: linuxppc-dev

Refresh and set these options:

 CONFIG_SYSFS_DEPRECATED_V2: y -> n
 CONFIG_INPUT_JOYSTICK:      y -> n
 CONFIG_HID_SONY:            n -> m
 CONFIG_RTC_DRV_PS3:         - -> m

Signed-off-by: Geoff Levand <geoffrey.levand@am.sony.com>
---
Ben,

Please apply for 2.6.30.

-Geoff

 arch/powerpc/configs/ps3_defconfig |  105 +++++++++++++++++++++----------------
 1 file changed, 62 insertions(+), 43 deletions(-)

--- a/arch/powerpc/configs/ps3_defconfig
+++ b/arch/powerpc/configs/ps3_defconfig
@@ -1,13 +1,14 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.29-rc8
-# Fri Mar 13 09:28:45 2009
+# Linux kernel version: 2.6.30-rc5
+# Fri May 15 10:37:00 2009
 #
 CONFIG_PPC64=y
 
 #
 # Processor support
 #
+CONFIG_PPC_BOOK3S=y
 # CONFIG_POWER4_ONLY is not set
 CONFIG_POWER3=y
 CONFIG_POWER4=y
@@ -55,9 +56,11 @@ CONFIG_OF=y
 # CONFIG_GENERIC_TBSYNC is not set
 CONFIG_AUDIT_ARCH=y
 CONFIG_GENERIC_BUG=y
+CONFIG_DTC=y
 # CONFIG_DEFAULT_UIMAGE is not set
 # CONFIG_PPC_DCR_NATIVE is not set
 # CONFIG_PPC_DCR_MMIO is not set
+CONFIG_ARCH_SUPPORTS_DEBUG_PAGEALLOC=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
@@ -72,6 +75,7 @@ CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
+CONFIG_POSIX_MQUEUE_SYSCTL=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
@@ -88,8 +92,7 @@ CONFIG_CLASSIC_RCU=y
 CONFIG_LOG_BUF_SHIFT=17
 # CONFIG_GROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
 CONFIG_NAMESPACES=y
 # CONFIG_UTS_NS is not set
@@ -99,6 +102,9 @@ CONFIG_NAMESPACES=y
 # CONFIG_NET_NS is not set
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_INITRAMFS_SOURCE=""
+CONFIG_RD_GZIP=y
+# CONFIG_RD_BZIP2 is not set
+# CONFIG_RD_LZMA is not set
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_ANON_INODES=y
@@ -107,6 +113,7 @@ CONFIG_SYSCTL_SYSCALL=y
 CONFIG_KALLSYMS=y
 CONFIG_KALLSYMS_ALL=y
 CONFIG_KALLSYMS_EXTRA_PASS=y
+# CONFIG_STRIP_ASM_SYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -138,6 +145,7 @@ CONFIG_HAVE_KRETPROBES=y
 CONFIG_HAVE_ARCH_TRACEHOOK=y
 CONFIG_HAVE_DMA_ATTRS=y
 CONFIG_USE_GENERIC_SMP_HELPERS=y
+# CONFIG_SLOW_WORK is not set
 # CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
@@ -150,7 +158,6 @@ CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_STOP_MACHINE=y
 CONFIG_BLOCK=y
-# CONFIG_BLK_DEV_IO_TRACE is not set
 CONFIG_BLK_DEV_BSG=y
 # CONFIG_BLK_DEV_INTEGRITY is not set
 CONFIG_BLOCK_COMPAT=y
@@ -172,7 +179,6 @@ CONFIG_DEFAULT_IOSCHED="anticipatory"
 #
 # Platform support
 #
-CONFIG_PPC_MULTIPLATFORM=y
 # CONFIG_PPC_PSERIES is not set
 # CONFIG_PPC_ISERIES is not set
 # CONFIG_PPC_PMAC is not set
@@ -209,6 +215,7 @@ CONFIG_SPU_FS_64K_LS=y
 # CONFIG_SPU_TRACE is not set
 CONFIG_SPU_BASE=y
 # CONFIG_PQ2ADS is not set
+# CONFIG_PPC_OF_BOOT_TRAMPOLINE is not set
 # CONFIG_IPIC is not set
 # CONFIG_MPIC is not set
 # CONFIG_MPIC_WEIRD is not set
@@ -279,11 +286,14 @@ CONFIG_PHYS_ADDR_T_64BIT=y
 CONFIG_ZONE_DMA_FLAG=1
 CONFIG_BOUNCE=y
 CONFIG_UNEVICTABLE_LRU=y
+CONFIG_HAVE_MLOCK=y
+CONFIG_HAVE_MLOCKED_PAGE_BIT=y
 CONFIG_ARCH_MEMORY_PROBE=y
 CONFIG_PPC_HAS_HASH_64K=y
 CONFIG_PPC_4K_PAGES=y
 # CONFIG_PPC_16K_PAGES is not set
 # CONFIG_PPC_64K_PAGES is not set
+# CONFIG_PPC_256K_PAGES is not set
 CONFIG_FORCE_MAX_ZONEORDER=13
 CONFIG_SCHED_SMT=y
 CONFIG_PROC_DEVICETREE=y
@@ -316,7 +326,6 @@ CONFIG_NET=y
 #
 # Networking options
 #
-CONFIG_COMPAT_NET_DEV_OPS=y
 CONFIG_PACKET=y
 CONFIG_PACKET_MMAP=y
 CONFIG_UNIX=y
@@ -389,6 +398,7 @@ CONFIG_IPV6_NDISC_NODETYPE=y
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+# CONFIG_PHONET is not set
 # CONFIG_NET_SCHED is not set
 # CONFIG_DCB is not set
 
@@ -396,6 +406,7 @@ CONFIG_IPV6_NDISC_NODETYPE=y
 # Network testing
 #
 # CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_DROP_MONITOR is not set
 # CONFIG_HAMRADIO is not set
 # CONFIG_CAN is not set
 # CONFIG_IRDA is not set
@@ -419,11 +430,9 @@ CONFIG_BT_HCIBTUSB=m
 # CONFIG_BT_HCIBFUSB is not set
 # CONFIG_BT_HCIVHCI is not set
 # CONFIG_AF_RXRPC is not set
-# CONFIG_PHONET is not set
 CONFIG_WIRELESS=y
 CONFIG_CFG80211=m
 # CONFIG_CFG80211_REG_DEBUG is not set
-CONFIG_NL80211=y
 # CONFIG_WIRELESS_OLD_REGULATORY is not set
 CONFIG_WIRELESS_EXT=y
 # CONFIG_WIRELESS_EXT_SYSFS is not set
@@ -602,6 +611,7 @@ CONFIG_SCSI_WAIT_SCAN=m
 # CONFIG_SCSI_SRP_ATTRS is not set
 # CONFIG_SCSI_LOWLEVEL is not set
 # CONFIG_SCSI_DH is not set
+# CONFIG_SCSI_OSD_INITIATOR is not set
 # CONFIG_ATA is not set
 CONFIG_MD=y
 # CONFIG_BLK_DEV_MD is not set
@@ -616,6 +626,7 @@ CONFIG_BLK_DEV_DM=m
 # CONFIG_DM_UEVENT is not set
 # CONFIG_MACINTOSH_DRIVERS is not set
 CONFIG_NETDEVICES=y
+CONFIG_COMPAT_NET_DEV_OPS=y
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
@@ -625,6 +636,8 @@ CONFIG_NETDEVICES=y
 # CONFIG_PHYLIB is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=m
+# CONFIG_ETHOC is not set
+# CONFIG_DNET is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
@@ -646,12 +659,13 @@ CONFIG_GELIC_WIRELESS_OLD_PSK_INTERFACE=
 CONFIG_WLAN_80211=y
 # CONFIG_LIBERTAS is not set
 # CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_AT76C50X_USB is not set
 # CONFIG_USB_ZD1201 is not set
 # CONFIG_USB_NET_RNDIS_WLAN is not set
 # CONFIG_RTL8187 is not set
 # CONFIG_MAC80211_HWSIM is not set
 # CONFIG_P54_COMMON is not set
-# CONFIG_IWLWIFI_LEDS is not set
+# CONFIG_AR9170_USB is not set
 # CONFIG_HOSTAP is not set
 # CONFIG_B43 is not set
 # CONFIG_B43LEGACY is not set
@@ -673,6 +687,7 @@ CONFIG_USB_PEGASUS=m
 CONFIG_USB_USBNET=m
 CONFIG_USB_NET_AX8817X=m
 # CONFIG_USB_NET_CDCETHER is not set
+# CONFIG_USB_NET_CDC_EEM is not set
 # CONFIG_USB_NET_DM9601 is not set
 # CONFIG_USB_NET_SMSC95XX is not set
 # CONFIG_USB_NET_GL620A is not set
@@ -724,28 +739,7 @@ CONFIG_INPUT_EVDEV=m
 #
 # CONFIG_INPUT_KEYBOARD is not set
 # CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_JOYSTICK=y
-# CONFIG_JOYSTICK_ANALOG is not set
-# CONFIG_JOYSTICK_A3D is not set
-# CONFIG_JOYSTICK_ADI is not set
-# CONFIG_JOYSTICK_COBRA is not set
-# CONFIG_JOYSTICK_GF2K is not set
-# CONFIG_JOYSTICK_GRIP is not set
-# CONFIG_JOYSTICK_GRIP_MP is not set
-# CONFIG_JOYSTICK_GUILLEMOT is not set
-# CONFIG_JOYSTICK_INTERACT is not set
-# CONFIG_JOYSTICK_SIDEWINDER is not set
-# CONFIG_JOYSTICK_TMDC is not set
-# CONFIG_JOYSTICK_IFORCE is not set
-# CONFIG_JOYSTICK_WARRIOR is not set
-# CONFIG_JOYSTICK_MAGELLAN is not set
-# CONFIG_JOYSTICK_SPACEORB is not set
-# CONFIG_JOYSTICK_SPACEBALL is not set
-# CONFIG_JOYSTICK_STINGER is not set
-# CONFIG_JOYSTICK_TWIDJOY is not set
-# CONFIG_JOYSTICK_ZHENHUA is not set
-# CONFIG_JOYSTICK_JOYDUMP is not set
-# CONFIG_JOYSTICK_XPAD is not set
+# CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
@@ -864,6 +858,7 @@ CONFIG_FB_PS3_DEFAULT_SIZE_M=9
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FB_METRONOME is not set
 # CONFIG_FB_MB862XX is not set
+# CONFIG_FB_BROADSHEET is not set
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
@@ -934,15 +929,17 @@ CONFIG_USB_HIDDEV=y
 #
 # Special HID drivers
 #
-# CONFIG_HID_COMPAT is not set
 # CONFIG_HID_A4TECH is not set
 # CONFIG_HID_APPLE is not set
 # CONFIG_HID_BELKIN is not set
 # CONFIG_HID_CHERRY is not set
 # CONFIG_HID_CHICONY is not set
 # CONFIG_HID_CYPRESS is not set
+# CONFIG_DRAGONRISE_FF is not set
 # CONFIG_HID_EZKEY is not set
+# CONFIG_HID_KYE is not set
 # CONFIG_HID_GYRATION is not set
+# CONFIG_HID_KENSINGTON is not set
 # CONFIG_HID_LOGITECH is not set
 # CONFIG_HID_MICROSOFT is not set
 # CONFIG_HID_MONTEREY is not set
@@ -950,7 +947,7 @@ CONFIG_USB_HIDDEV=y
 # CONFIG_HID_PANTHERLORD is not set
 # CONFIG_HID_PETALYNX is not set
 # CONFIG_HID_SAMSUNG is not set
-# CONFIG_HID_SONY is not set
+CONFIG_HID_SONY=m
 # CONFIG_HID_SUNPLUS is not set
 # CONFIG_GREENASIA_FF is not set
 # CONFIG_HID_TOPSEED is not set
@@ -1012,11 +1009,11 @@ CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_TMC is not set
 
 #
-# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may
 #
 
 #
-# see USB_STORAGE Help for more information
+# also be needed; see USB_STORAGE Help for more info
 #
 CONFIG_USB_STORAGE=m
 # CONFIG_USB_STORAGE_DEBUG is not set
@@ -1058,7 +1055,6 @@ CONFIG_USB_STORAGE=m
 # CONFIG_USB_LED is not set
 # CONFIG_USB_CYPRESS_CY7C63 is not set
 # CONFIG_USB_CYTHERM is not set
-# CONFIG_USB_PHIDGET is not set
 # CONFIG_USB_IDMOUSE is not set
 # CONFIG_USB_FTDI_ELAN is not set
 # CONFIG_USB_APPLEDISPLAY is not set
@@ -1074,6 +1070,7 @@ CONFIG_USB_STORAGE=m
 #
 # OTG and related infrastructure
 #
+# CONFIG_NOP_USB_XCEIV is not set
 # CONFIG_MMC is not set
 # CONFIG_MEMSTICK is not set
 # CONFIG_NEW_LEDS is not set
@@ -1113,8 +1110,10 @@ CONFIG_RTC_INTF_DEV=y
 #
 # on-CPU RTC drivers
 #
-CONFIG_RTC_DRV_PPC=m
+# CONFIG_RTC_DRV_GENERIC is not set
+CONFIG_RTC_DRV_PS3=m
 # CONFIG_DMADEVICES is not set
+# CONFIG_AUXDISPLAY is not set
 # CONFIG_UIO is not set
 # CONFIG_STAGING is not set
 
@@ -1125,6 +1124,7 @@ CONFIG_EXT2_FS=m
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=m
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
 CONFIG_EXT3_FS_XATTR=y
 # CONFIG_EXT3_FS_POSIX_ACL is not set
 # CONFIG_EXT3_FS_SECURITY is not set
@@ -1161,6 +1161,11 @@ CONFIG_AUTOFS4_FS=m
 # CONFIG_FUSE_FS is not set
 
 #
+# Caches
+#
+# CONFIG_FSCACHE is not set
+
+#
 # CD-ROM/DVD Filesystems
 #
 CONFIG_ISO9660_FS=m
@@ -1211,6 +1216,7 @@ CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ROMFS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
+# CONFIG_NILFS2_FS is not set
 CONFIG_NETWORK_FILESYSTEMS=y
 CONFIG_NFS_FS=y
 CONFIG_NFS_V3=y
@@ -1223,7 +1229,6 @@ CONFIG_LOCKD_V4=y
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 CONFIG_SUNRPC_GSS=y
-# CONFIG_SUNRPC_REGISTER_V4 is not set
 CONFIG_RPCSEC_GSS_KRB5=y
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
@@ -1283,6 +1288,7 @@ CONFIG_NLS_ISO8859_1=y
 # CONFIG_NLS_KOI8_U is not set
 # CONFIG_NLS_UTF8 is not set
 # CONFIG_DLM is not set
+CONFIG_BINARY_PRINTF=y
 
 #
 # Library routines
@@ -1296,15 +1302,16 @@ CONFIG_CRC_ITU_T=m
 CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
 # CONFIG_LIBCRC32C is not set
-CONFIG_ZLIB_INFLATE=m
+CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=m
 CONFIG_LZO_COMPRESS=m
 CONFIG_LZO_DECOMPRESS=m
-CONFIG_PLIST=y
+CONFIG_DECOMPRESS_GZIP=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
 CONFIG_HAS_DMA=y
 CONFIG_HAVE_LMB=y
+CONFIG_NLATTR=y
 
 #
 # Kernel hacking
@@ -1322,6 +1329,9 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_SOFTLOCKUP=y
 # CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
 CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_DETECT_HUNG_TASK=y
+# CONFIG_BOOTPARAM_HUNG_TASK_PANIC is not set
+CONFIG_BOOTPARAM_HUNG_TASK_PANIC_VALUE=0
 CONFIG_SCHED_DEBUG=y
 # CONFIG_SCHEDSTATS is not set
 # CONFIG_TIMER_STATS is not set
@@ -1357,12 +1367,15 @@ CONFIG_DEBUG_LIST=y
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_LATENCYTOP is not set
 CONFIG_SYSCTL_SYSCALL_CHECK=y
+# CONFIG_DEBUG_PAGEALLOC is not set
 CONFIG_NOP_TRACER=y
 CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_FUNCTION_GRAPH_TRACER=y
 CONFIG_HAVE_DYNAMIC_FTRACE=y
 CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
 CONFIG_RING_BUFFER=y
 CONFIG_TRACING=y
+CONFIG_TRACING_SUPPORT=y
 
 #
 # Tracers
@@ -1371,18 +1384,21 @@ CONFIG_TRACING=y
 # CONFIG_IRQSOFF_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_EVENT_TRACER is not set
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_KMEMTRACE is not set
+# CONFIG_WORKQUEUE_TRACER is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
 # CONFIG_FTRACE_STARTUP_TEST is not set
-# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_DYNAMIC_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
 CONFIG_PRINT_STACK_DEPTH=64
 CONFIG_DEBUG_STACKOVERFLOW=y
 # CONFIG_DEBUG_STACK_USAGE is not set
-# CONFIG_DEBUG_PAGEALLOC is not set
 # CONFIG_CODE_PATCHING_SELFTEST is not set
 # CONFIG_FTR_FIXUP_SELFTEST is not set
 # CONFIG_MSI_BITMAP_SELFTEST is not set
@@ -1415,10 +1431,12 @@ CONFIG_CRYPTO_HASH=y
 CONFIG_CRYPTO_HASH2=y
 CONFIG_CRYPTO_RNG=m
 CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_PCOMP=y
 CONFIG_CRYPTO_MANAGER=y
 CONFIG_CRYPTO_MANAGER2=y
 CONFIG_CRYPTO_GF128MUL=m
 # CONFIG_CRYPTO_NULL is not set
+CONFIG_CRYPTO_WORKQUEUE=y
 # CONFIG_CRYPTO_CRYPTD is not set
 # CONFIG_CRYPTO_AUTHENC is not set
 # CONFIG_CRYPTO_TEST is not set
@@ -1487,6 +1505,7 @@ CONFIG_CRYPTO_SALSA20=m
 # Compression
 #
 # CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_ZLIB is not set
 CONFIG_CRYPTO_LZO=m
 
 #

^ permalink raw reply

* Re: [PATCH] sata_fsl: Fix the command description of FSL SATA controller
From: Jeff Garzik @ 2009-05-15 18:16 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linux-ide, linux-kernel, linuxppc-dev
In-Reply-To: <Pine.LNX.4.64.0905140945540.8378@localhost.localdomain>

Kumar Gala wrote:
> From: Dave Liu <daveliu@freescale.com>
> 
> The bit 11 of command description is reserved bit in Freescale
> SATA controller and needs to be set to '1'.  This is needed to
> make sure the last write from the controller to the buffer
> descriptor is seen before an interrupt is raised.
> 
> Signed-off-by: Dave Liu <daveliu@freescale.com>
> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
> ---
> 
> Jeff, please pick this up as a bug fix for 2.6.30
> 
>  drivers/ata/sata_fsl.c |    8 +++++---
>  1 files changed, 5 insertions(+), 3 deletions(-)

applied

^ permalink raw reply

* Re: [PATCH v3] sata_fsl: Fix compile warnings
From: Jeff Garzik @ 2009-05-15 18:16 UTC (permalink / raw)
  To: Kumar Gala; +Cc: linux-ide, linux-kernel, linuxppc-dev
In-Reply-To: <1242270650-27945-1-git-send-email-galak@kernel.crashing.org>

Kumar Gala wrote:
> We we build with dma_addr_t as a 64-bit quantity we get:
> 
> drivers/ata/sata_fsl.c: In function 'sata_fsl_fill_sg':
> drivers/ata/sata_fsl.c:340: warning: format '%x' expects type 'unsigned int', but argument 4 has type 'dma_addr_t'
> 
> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
> ---
> * v2: fixed extra 'x'
> * v3: fixed whitespace issue
> 
>  drivers/ata/sata_fsl.c |    7 ++++---
>  1 files changed, 4 insertions(+), 3 deletions(-)

applied

^ permalink raw reply

* [PATCH] fsldma: fix memory leak on error path in fsl_dma_prep_memcpy()
From: Ira Snyder @ 2009-05-15 16:59 UTC (permalink / raw)
  To: Dan Williams, Li Yang, linuxppc-dev

When preparing a memcpy operation, if the kernel fails to allocate memory
for a link descriptor after the first link descriptor has already been
allocated, then some memory will never be released. Fix the problem by
walking the list of allocated descriptors backwards, and freeing the
allocated descriptors back into the DMA pool.

Signed-off-by: Ira W. Snyder <iws@ovro.caltech.edu>
---
 drivers/dma/fsldma.c |   18 +++++++++++++++---
 1 files changed, 15 insertions(+), 3 deletions(-)

diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index da8a8ed..4264c98 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -454,8 +454,8 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
 {
 	struct fsl_dma_chan *fsl_chan;
 	struct fsl_desc_sw *first = NULL, *prev = NULL, *new;
+	struct list_head *list;
 	size_t copy;
-	LIST_HEAD(link_chain);
 
 	if (!chan)
 		return NULL;
@@ -472,7 +472,7 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
 		if (!new) {
 			dev_err(fsl_chan->dev,
 					"No free memory for link descriptor\n");
-			return NULL;
+			goto fail;
 		}
 #ifdef FSL_DMA_LD_DEBUG
 		dev_dbg(fsl_chan->dev, "new link desc alloc %p\n", new);
@@ -507,7 +507,19 @@ static struct dma_async_tx_descriptor *fsl_dma_prep_memcpy(
 	/* Set End-of-link to the last link descriptor of new list*/
 	set_ld_eol(fsl_chan, new);
 
-	return first ? &first->async_tx : NULL;
+	return &first->async_tx;
+
+fail:
+	if (!first)
+		return NULL;
+
+	list = &first->async_tx.tx_list;
+	list_for_each_entry_safe_reverse(new, prev, list, node) {
+		list_del(&new->node);
+		dma_pool_free(fsl_chan->desc_pool, new, new->async_tx.phys);
+	}
+
+	return NULL;
 }
 
 /**
-- 
1.5.4.3

^ permalink raw reply related

* Re: [PATCH] [PowerPC] MPC8272ADS: fix device tree for 8 MB flash, size
From: Scott Wood @ 2009-05-15 15:36 UTC (permalink / raw)
  To: Heiko Schocher; +Cc: linuxppc-dev, Wolfgang Denk, linux-kernel
In-Reply-To: <4A0D03AB.2040602@denx.de>

On Fri, May 15, 2009 at 07:54:51AM +0200, Heiko Schocher wrote:
> Scott Wood wrote:
> > We should proabbly leave out the ranges altogether, and have u-boot
> > populate it from the mappings it establishes.
> 
> No, I vote for manipulating just the entries, which u-boot dynamically
> detect, and let the other entries untouched. It is possible that
> there is a device which u-boot didn;t use/know, and there is in the DTS
> an ranges entry for it (Maybe not on the MPC8727ADS, but we should
> define a rule, how a bootloader has to manipulate entries). So if
> u-boot build the complete ranges entry, it maybe miss something.

If u-boot doesn't know about it, then it didn't create the mapping, and
thus it's not accessible (if something later on creates a mapping, it can
update ranges itself).  The devices themselves would still be described,
just not the non-existent mapping.

The benefit is that you would have just one place that reads out the
localbus config into the device tree, with no error-prone duplication of
data, or separate hacks for each board that has something that is
variable.

We could leave ranges in the dts for cuImage, and have u-boot just
overwrite the entire thing rather than patch up individual entries.

> > I don't see how current u-boot would accomodate more than 8MiB flash on
> > this board (there's some detection in board/freescale/mpc8260ads/flash.c,
> 
> Didn;t this board uses the CFI driver? :-(

Not yet, unfortunately.  This is pretty old code.

-Scott

^ permalink raw reply

* Re: FEC & SDMA (bestcomm) interaction on the 5200
From: Grant Likely @ 2009-05-15 14:52 UTC (permalink / raw)
  To: Dimiter Popoff; +Cc: linuxppc-dev
In-Reply-To: <4A0D1FF1-302-2D5C780A@nukeman.tgi-sci.com>

On Fri, May 15, 2009 at 2:36 AM, Dimiter Popoff <dp@tgi-sci.com> wrote:
> Hi people,
>
> I am porting my (not linux) OS to the 5200. I went all the
> way understanding how the SDMA works and programming what
> I needed for it so things are now pretty stable in terms
> of disk I/O and system memory -> PCI (offscreen window
> buffers -> PCI display framebuffer).
>
> =A0And I wanted to make use of the Ethernet ("FEC", as they have
> it), hoping it would take me a few days (not my first one).
>
> =A0I am out of luck - it is practically undocumented. There is some
> talk of receive buffers which the FEC should see empty etc.,
> how on earth is that supposed to happen when it has no bus
> master capability at all? It relies on the SDMA for its bus
> activity - but in what format does it expect to get these
> buffer related data?
> =A0Or (more likely, at least hopefully so) this talk in the
> MPC5200BUM (and MPC5200UM, for that) is just nonsense and
> the FEC simply puts in the FIFO incoming packets, writing as
> a last .l the receive frame status word? If so, I could
> easily handle that with the SDMA.
> =A0Same question about transmitting. I can only hope/assume
> that the FEC will just send what it is handed through the
> FIFO by the SDMA, the very first .l being the frame control
> word, and ending when the TFD from the data drd1a or whatever
> makes it through?

It's been a long time since I've been in the bowels of the FEC driver,
but I believe you are correct.

g.

--=20
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.

^ permalink raw reply

* [PATCH V2] mpc5121/clocks: make debug output more readable
From: Wolfram Sang @ 2009-05-15 14:40 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev
In-Reply-To: <fa686aa40905080840x308c1addld75b1ec5df386c13@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1308 bytes --]


- refactor printk with pr_info/pr_cont
- use '=' in output to connect key/value pairs

Signed-off-by: Wolfram Sang <w.sang@pengutronix.de>
Cc: John Rigby <jcrigby@gmail.com>
Cc: Grant Likely <grant.likely@secretlab.ca>

---
 arch/powerpc/platforms/512x/clock.c |    8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

Index: arch/powerpc/platforms/512x/clock.c
===================================================================
--- arch/powerpc/platforms/512x/clock.c.orig
+++ arch/powerpc/platforms/512x/clock.c
@@ -83,13 +83,13 @@ static void dump_clocks(void)
 	mutex_lock(&clocks_mutex);
 	printk(KERN_INFO "CLOCKS:\n");
 	list_for_each_entry(p, &clocks, node) {
-		printk(KERN_INFO "  %s %ld", p->name, p->rate);
+		pr_info("  %s=%ld", p->name, p->rate);
 		if (p->parent)
-			printk(KERN_INFO " %s %ld", p->parent->name,
+			pr_cont(" %s=%ld", p->parent->name,
 			       p->parent->rate);
 		if (p->flags & CLK_HAS_CTRL)
-			printk(KERN_INFO " reg/bit %d/%d", p->reg, p->bit);
-		printk("\n");
+			pr_cont(" reg/bit=%d/%d", p->reg, p->bit);
+		pr_cont("\n");
 	}
 	mutex_unlock(&clocks_mutex);
 }

-- 
Pengutronix e.K.                           | Wolfram Sang                |
Industrial Linux Solutions                 | http://www.pengutronix.de/  |

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply

* [PATCH] powerpc/ftrace: fix constraint to be early clobber
From: Steven Rostedt @ 2009-05-15 14:33 UTC (permalink / raw)
  To: LKML, linuxppc-dev; +Cc: Ingo Molnar, Andrew Morton, Frederic Weisbecker


After upgrading my distcc boxes from gcc 4.2.2 to 4.4.0, the function 
graph tracer broke. This was discovered on my x86 boxes.

The issue is that gcc used the same register for an output as it did for 
an input in an asm statement. I first thought this was a bug in gcc and 
reported it. I was notified that gcc was correct and that the output had 
to be flagged as an "early clobber".

I noticed that powerpc had the same issue and this patch fixes it.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c
index 70e2a73..68fd74e 100644
--- a/arch/powerpc/kernel/ftrace.c
+++ b/arch/powerpc/kernel/ftrace.c
@@ -594,7 +594,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
 			PPC_LONG "2b,4b\n"
 		".previous"
 
-		: [old] "=r" (old), [faulted] "=r" (faulted)
+		: [old] "=&r" (old), [faulted] "=r" (faulted)
 		: [parent] "r" (parent), [return_hooker] "r" (return_hooker)
 		: "memory"
 	);

^ permalink raw reply related

* Re: [PATCH] i2c-mpc: generate START condition after STOP caused by read i2c_msg
From: Joakim Tjernlund @ 2009-05-15 14:16 UTC (permalink / raw)
  To: Esben Haabendal; +Cc: linuxppc-dev, linux-i2c
In-Reply-To: <d2b9ea600905150552u6951a92es5dd119dcc37e641d@mail.gmail.com>

Esben Haabendal <esbenhaabendal@gmail.com> wrote on 15/05/2009 14:52:28:
>
> Your new patch also does not work.
>
> Have you tested it?

sure, works fine. I haven't stressed it too much though.

>
> I already tried something very much what you sent here, I believe the
> only difference was that I named the "last" variable "stop". I also
> tried several other aproaches, and none of them worked.  I would
> appreciate not to have to test all of them seperately again through
> this mailing list ;-)

:), point taken.

>
> Anyway, your patch also is in conflict with the MPC8360ERM. The spec
> specifies that a repeated start must follow an ACK, and not a "NO
> ACK".

Ouch, will have to check too, but later.

>
> When doing a repeated start after a NO ACK, the slave does not ACK the
> address (I get an RXAK).  When doing as specified, ACK'ing the last
> byte read and then doing a repeated START, i2c_wait() fails due to
> CSR_MCF bit missing.  I thought it would be possible to find somewhere
> to do a dummy read to get around this, but failed to do so without
> breaking something else.
>
> Could we go forward with my initial patch, and then continue the work
> on this repeated START approach for future releases?

Yes, go ahead.

 Jocke

^ permalink raw reply

* Re: [PATCH] i2c-mpc: generate START condition after STOP caused by read i2c_msg
From: Esben Haabendal @ 2009-05-15 12:52 UTC (permalink / raw)
  To: Joakim Tjernlund; +Cc: linuxppc-dev, linux-i2c
In-Reply-To: <OFCADC684E.A2599121-ONC12575B7.003B8AB5-C12575B7.003CF795@transmode.se>

Your new patch also does not work.

Have you tested it?

I already tried something very much what you sent here, I believe the
only difference was that I named the "last" variable "stop". I also
tried several other aproaches, and none of them worked.  I would
appreciate not to have to test all of them seperately again through
this mailing list ;-)

Anyway, your patch also is in conflict with the MPC8360ERM. The spec
specifies that a repeated start must follow an ACK, and not a "NO
ACK".

When doing a repeated start after a NO ACK, the slave does not ACK the
address (I get an RXAK).  When doing as specified, ACK'ing the last
byte read and then doing a repeated START, i2c_wait() fails due to
CSR_MCF bit missing.  I thought it would be possible to find somewhere
to do a dummy read to get around this, but failed to do so without
breaking something else.

Could we go forward with my initial patch, and then continue the work
on this repeated START approach for future releases?

/Esben

^ permalink raw reply

* Re: [PATCH v2] powerpc/pci: clean up direct access to sysdata by iseries platform
From: Kumar Gala @ 2009-05-15 12:50 UTC (permalink / raw)
  To: Stephen Rothwell; +Cc: Linuxppc-dev Development
In-Reply-To: <1242391640-18826-1-git-send-email-galak@kernel.crashing.org>


On May 15, 2009, at 7:47 AM, Kumar Gala wrote:

> We shouldn't directly access sysdata to get the device node.  We  
> should
> be calling pci_device_to_OF_node().
>
> Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
> ---
> * Updated based on sfr's iseries pci fix patch
>
> arch/powerpc/platforms/iseries/iommu.c |    2 +-
> arch/powerpc/platforms/iseries/pci.c   |    8 ++++----
> 2 files changed, 5 insertions(+), 5 deletions(-)

Stephen if you can test this version that would be great.

thanks

- k

^ permalink raw reply

* git tree w/swiotlb/36-bit physical support for MPC8641/MPC85xx
From: Kumar Gala @ 2009-05-15 12:48 UTC (permalink / raw)
  To: Linuxppc-dev Development

For those that care and have an interest I've posted a 'swiotlb'  
branch that includes all the patches needed for running with large  
amounts of memory on MPC8641 or MPC85xx based systems.  This branch is  
based on v2.6.30-rc5 + next branch + core swiotlb patches

	git://git.kernel.org/pub/scm/linux/kernel/git/galak/powerpc.git swiotlb

The expectation is all this code will be in 2.6.31.

If you have any issues please let me know.

- k

^ permalink raw reply

* [PATCH v2] powerpc/pci: clean up direct access to sysdata by iseries platform
From: Kumar Gala @ 2009-05-15 12:47 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Stephen Rothwell

We shouldn't directly access sysdata to get the device node.  We should
be calling pci_device_to_OF_node().

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
* Updated based on sfr's iseries pci fix patch

 arch/powerpc/platforms/iseries/iommu.c |    2 +-
 arch/powerpc/platforms/iseries/pci.c   |    8 ++++----
 2 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/platforms/iseries/iommu.c b/arch/powerpc/platforms/iseries/iommu.c
index 4021982..224913a 100644
--- a/arch/powerpc/platforms/iseries/iommu.c
+++ b/arch/powerpc/platforms/iseries/iommu.c
@@ -177,7 +177,7 @@ static struct iommu_table *iommu_table_find(struct iommu_table * tbl)
 static void pci_dma_dev_setup_iseries(struct pci_dev *pdev)
 {
 	struct iommu_table *tbl;
-	struct device_node *dn = pdev->sysdata;
+	struct device_node *dn = pci_device_to_OF_node(dev);
 	struct pci_dn *pdn = PCI_DN(dn);
 	const u32 *lsn = of_get_property(dn, "linux,logical-slot-number", NULL);
 
diff --git a/arch/powerpc/platforms/iseries/pci.c b/arch/powerpc/platforms/iseries/pci.c
index 21cddc3..175aac8 100644
--- a/arch/powerpc/platforms/iseries/pci.c
+++ b/arch/powerpc/platforms/iseries/pci.c
@@ -318,6 +318,7 @@ static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)
 {
 	struct resource *bar_res = &dev->resource[bar_num];
 	long bar_size = pci_resource_len(dev, bar_num);
+	struct device_node *dn = pci_device_to_OF_node(dev);
 
 	/*
 	 * No space to allocate, quick exit, skip Allocation.
@@ -335,9 +336,9 @@ static void __init iomm_table_allocate_entry(struct pci_dev *dev, int bar_num)
 	 * Allocate the number of table entries needed for BAR.
 	 */
 	while (bar_size > 0 ) {
-		iomm_table[current_iomm_table_entry] = dev->sysdata;
+		iomm_table[current_iomm_table_entry] = dn;
 		ds_addr_table[current_iomm_table_entry] =
-			iseries_ds_addr(dev->sysdata) | (bar_num << 24);
+			iseries_ds_addr(dn) | (bar_num << 24);
 		bar_size -= IOMM_TABLE_ENTRY_SIZE;
 		++current_iomm_table_entry;
 	}
@@ -410,7 +411,7 @@ void __init iSeries_pcibios_fixup_resources(struct pci_dev *pdev)
 	struct device_node *node;
 	int i;
 
-	node = find_device_node(bus, pdev->devfn);
+	node = pci_device_to_OF_node(pdev);
 	pr_debug("PCI: iSeries %s, pdev %p, node %p\n",
 		 pci_name(pdev), pdev, node);
 	if (!node) {
@@ -441,7 +442,6 @@ void __init iSeries_pcibios_fixup_resources(struct pci_dev *pdev)
 		}
 	}
 
-	pdev->sysdata = node;
 	allocate_device_bars(pdev);
 	iseries_device_information(pdev, bus, *sub_bus);
 }
-- 
1.6.0.6

^ permalink raw reply related

* kernel module compilation error
From: Vijay Nikam @ 2009-05-15 11:51 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: Scott Wood, Ron Madrid

Hello All,

I upgraded the Linux kernel version from 2.6.20 to 2.6.23 on eval
board mpc8313erdb. Then I wrote a simple hello_world kernel module for
testing but when I do make it gives following compilation error.
Whereas I did not had this problem with kernel 2.6.20 !!!

It says; 'include/asm/current.h:35: error: invalid register name for =91cur=
rent=92'

Following is complete error log

################################
make -C /usr/local/mpc8313/linux-2.6.23 M=3D/opt/test/module/hello_world mo=
dules
make[1]: Entering directory `/usr/local/mpc8313/linux-2.6.23'
CC [M] /opt/test/module/hello_world/hello.o
In file included from include/linux/capability.h:48,
from include/linux/sched.h:50,
from include/asm/elf.h:6,
from include/linux/elf.h:8,
from include/linux/module.h:15,
from /opt/test/module/hello_world/hello.c:5:
include/asm/current.h:35: error: invalid register name for =91current=92
make[2]: *** [/opt/test/module/hello_world/hello.o] Error 1
make[1]: *** [_module_/opt/test/module/hello_world] Error 2
make[1]: Leaving directory `/usr/local/mpc8313/linux-2.6.23'
make: *** [all] Error 2
############################################

Could anyone please let me know the way to proceed or a way to think
to resolve this issue ? ? ?

Kindly please acknowledge ... thank you.

Kind Regards,
Vijay Nikam

^ permalink raw reply

* Re: [PATCH] powerpc/ftrace: Use pr_devel() in ftrace.c
From: Michael Ellerman @ 2009-05-15 11:30 UTC (permalink / raw)
  To: Steven Rostedt; +Cc: linuxppc-dev
In-Reply-To: <alpine.DEB.2.00.0905141149130.30591@gandalf.stny.rr.com>

[-- Attachment #1: Type: text/plain, Size: 295 bytes --]

On Thu, 2009-05-14 at 11:49 -0400, Steven Rostedt wrote:
> I'm fine with this patch, but it should go via the PPC tree.

Yep, it went To linux-ppc, CC you - so that's the plan, I'll nag Ben to
pick it up.

> Acked-by: Steven Rostedt <rostedt@goodmis.org>

Thanks for the ack.

cheers

[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply

* Re: [PATCH] i2c-mpc: generate START condition after STOP caused by read i2c_msg
From: Joakim Tjernlund @ 2009-05-15 11:05 UTC (permalink / raw)
  To: Esben Haabendal; +Cc: linuxppc-dev, linux-i2c
In-Reply-To: <d2b9ea600905150318s69b86b5ct3816b274bf343a79@mail.gmail.com>

Esben Haabendal <esbenhaabendal@gmail.com> wrote on 15/05/2009 12:18:39:

>
> I have now spent a few hours trying a lot of different paths to fix
> this approach, but I simply cannot find a way to get i2c read to work
> without a trailing STOP condition with this controller.

I found a bug which lets me remove the "fix" and seems related to your
problem. Updated patch last in mail

>
> Is there a problem in applying my patch, as it should be "clean"
> improvement over the current implementation, which uses STOP
> condition, but does not work.
>
> Until Isomeone finds a way to get it to work without STOP, we will
> have a working driver, which I assume is what we want.

Your patch appears OK too. I just wanted to see if a better fix was
possible. Your patch is less risky and it is the safe bet so soon before
release.

 Jocke

diff --git a/drivers/i2c/busses/i2c-mpc.c b/drivers/i2c/busses/i2c-mpc.c
index 6c1cddd..04eff40 100644
--- a/drivers/i2c/busses/i2c-mpc.c
+++ b/drivers/i2c/busses/i2c-mpc.c
@@ -189,9 +189,6 @@ static int mpc_write(struct mpc_i2c *i2c, int target,
 	unsigned timeout = i2c->adap.timeout;
 	u32 flags = restart ? CCR_RSTA : 0;

-	/* Start with MEN */
-	if (!restart)
-		writeccr(i2c, CCR_MEN);
 	/* Start as master */
 	writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
 	/* Write target byte */
@@ -214,15 +211,12 @@ static int mpc_write(struct mpc_i2c *i2c, int target,
 }

 static int mpc_read(struct mpc_i2c *i2c, int target,
-		    u8 * data, int length, int restart)
+		    u8 * data, int length, int restart, int last)
 {
 	unsigned timeout = i2c->adap.timeout;
 	int i, result;
 	u32 flags = restart ? CCR_RSTA : 0;

-	/* Start with MEN */
-	if (!restart)
-		writeccr(i2c, CCR_MEN);
 	/* Switch to read - restart */
 	writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
 	/* Write target address byte - this time with the read flag set */
@@ -241,18 +235,18 @@ static int mpc_read(struct mpc_i2c *i2c, int target,
 		readb(i2c->base + MPC_I2C_DR);
 	}

-	for (i = 0; i < length; i++) {
+	for (i = length; i ; --i) {
 		result = i2c_wait(i2c, timeout, 0);
 		if (result < 0)
 			return result;

 		/* Generate txack on next to last byte */
-		if (i == length - 2)
+		if (i == 2)
 			writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
-		/* Generate stop on last byte */
-		if (i == length - 1)
-			writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK);
-		data[i] = readb(i2c->base + MPC_I2C_DR);
+		/* Generate stop on last byte, iff last transaction */
+		if (i == 1 && last)
+			writeccr(i2c, CCR_MIEN | CCR_MEN);
+		data[length-i] = readb(i2c->base + MPC_I2C_DR);
 	}

 	return length;
@@ -294,7 +288,7 @@ static int mpc_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
 		tm_i2c_select_mux(pmsg->addr);
 		if (pmsg->flags & I2C_M_RD)
 			ret =
-			    mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
+			    mpc_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i, i == num-1);
 		else
 			ret =
 			    mpc_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);

^ permalink raw reply related

* Re: [PATCH] i2c-mpc: generate START condition after STOP caused by read i2c_msg
From: Esben Haabendal @ 2009-05-15 10:18 UTC (permalink / raw)
  To: Joakim Tjernlund; +Cc: linuxppc-dev, linux-i2c
In-Reply-To: <OF3CD158BA.04CCFBB5-ONC12575B6.005911D5-C12575B6.005CAFC2@transmode.se>

Hi

Your patch (and the small addition to mpc_i2c_start) does not work for me.

[   35.765803] mpc_xfer()
[   35.785480] writeccr 0
[   35.785505] writeccr 80
[   35.785523] mpc_xfer: 1 bytes to 2c:W - 1 of 2 messages
[   35.798817] mpc_write addr=3D2c len=3D1 restart=3D0
[   35.815327] writeccr f0
[   35.815503] I2C: SR=3Da2
[   35.818675] I2C: SR=3Da6
[   35.821450] mpc_xfer: 1 bytes to 2c:R - 2 of 2 messages
[   35.827119] mpc_read addr=3D2c len=3D1 restart=3D1
[   35.837463] writeccr f4
[   35.837641] I2C: SR=3Da6
[   35.840011] writeccr e8
[   35.840133] I2C: SR=3Da3
[   35.843596] writeccr 80
[   35.843632] mpc_xfer()
[   35.855068] writeccr 0
[   35.855093] writeccr 80
[   35.855111] mpc_xfer: 1 bytes to 2c:W - 1 of 2 messages
[   35.865346] mpc_write addr=3D2c len=3D1 restart=3D0
[   35.870109] writeccr f0
[   35.870272] I2C: SR=3Da2
[   35.873372] I2C: SR=3Da6
[   35.875757] mpc_xfer: 1 bytes to 2c:R - 2 of 2 messages
[   35.881606] mpc_read addr=3D2c len=3D1 restart=3D1
[   35.886290] writeccr f4
[   35.886463] I2C: SR=3Da6
[   35.889425] writeccr e8
[   35.889575] I2C: SR=3Da7
[   35.891944] writeccr 80
[   35.961177] mpc_xfer()
[   35.972517] writeccr 0
[   35.972541] writeccr 80
[   35.972559] mpc_xfer: 1 bytes to 4e:W - 1 of 20 messages
[   35.982628] mpc_write addr=3D4e len=3D1 restart=3D0
[   35.987389] writeccr f0
[   35.987424] I2C: SR=3Db3
[   35.990386] I2C: MAL
[   35.992971] i2c_wait(address) error: -5
[   35.997215] writeccr 80
[   35.997241] Error: i2c_transfer failed: -5

I have now spent a few hours trying a lot of different paths to fix
this approach, but I simply cannot find a way to get i2c read to work
without a trailing STOP condition with this controller.

Is there a problem in applying my patch, as it should be "clean"
improvement over the current implementation, which uses STOP
condition, but does not work.

Until Isomeone finds a way to get it to work without STOP, we will
have a working driver, which I assume is what we want.

Best regards,
Esben Haabendal

--=20
Esben Haabendal, Senior Software Consultant
Dor=E9Development ApS, Ved Stranden 1, 9560 Hadsund, DK-Denmark
Phone: +45 51 92 53 93, E-mail: eha@doredevelopment.dk
WWW: http://www.doredevelopment.dk

^ permalink raw reply

* [PATCH] ppc64: xmon: Add dl command to dump contents of __log_buf
From: Vinay Sridhar @ 2009-05-15  9:13 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: ellerman, vinay

Hello All,

Quite a while back Michael Ellerman had posted a patch to add support to xmon to print the contents of the console log pointed to by __log_buf.
Here's the link to that patch - http://ozlabs.org/pipermail/linuxppc64-dev/2005-March/003657.html
I've ported the patch in the above link to 2.6.30-rc5 and have tested it. 

Thanks & regards,
Vinay

Signed-off-by: Michael Ellerman <michael at ellerman.id.au>

diff -Nuarp linux-2.6.30-rc5_orig//arch/powerpc/xmon/xmon.c linux-2.6.30-rc5/arch/powerpc/xmon/xmon.c
--- linux-2.6.30-rc5_orig//arch/powerpc/xmon/xmon.c	2009-05-15 03:06:24.000000000 -0500
+++ linux-2.6.30-rc5/arch/powerpc/xmon/xmon.c	2009-05-15 03:26:26.000000000 -0500
@@ -110,6 +110,7 @@ static int bsesc(void);
 static void dump(void);
 static void prdump(unsigned long, long);
 static int ppc_inst_dump(unsigned long, long, int);
+static void dump_log_buf(void);
 static void backtrace(struct pt_regs *);
 static void excprint(struct pt_regs *);
 static void prregs(struct pt_regs *);
@@ -197,6 +198,7 @@ Commands:\n\
   di	dump instructions\n\
   df	dump float values\n\
   dd	dump double values\n\
+  dl    dump the kernel log buffer\n\
   dr	dump stream of raw bytes\n\
   e	print exception information\n\
   f	flush cache\n\
@@ -2009,6 +2011,8 @@ dump(void)
 			nidump = MAX_DUMP;
 		adrs += ppc_inst_dump(adrs, nidump, 1);
 		last_cmd = "di\n";
+	} else if (c == 'l') {
+		dump_log_buf();
 	} else if (c == 'r') {
 		scanhex(&ndump);
 		if (ndump == 0)
@@ -2122,6 +2126,49 @@ print_address(unsigned long addr)
 	xmon_print_symbol(addr, "\t# ", "");
 }
 
+void
+dump_log_buf(void)
+{
+        const unsigned long size = 128;
+        unsigned long i, end, addr;
+        unsigned char buf[size + 1];
+
+        addr = 0;
+        buf[size] = '\0';
+
+        if (setjmp(bus_error_jmp) != 0) {
+                printf("Unable to lookup symbol __log_buf!\n");
+                return;
+        }
+
+        catch_memory_errors = 1;
+        sync();
+        addr = kallsyms_lookup_name("__log_buf");
+
+        if (! addr)
+                printf("Symbol __log_buf not found!\n");
+        else {
+                end = addr + (1 << CONFIG_LOG_BUF_SHIFT);
+                while (addr < end) {
+                        if (! mread(addr, buf, size)) {
+                                printf("Can't read memory at address 0x%lx\n", addr);
+                                break;
+                        }
+      
+                        printf("%s", buf);
+       
+                        if (strlen(buf) < size)
+                                break;
+
+                        addr += size;
+                }
+        }
+
+        sync();
+        /* wait a little while to see if we get a machine check */
+        __delay(200);
+        catch_memory_errors = 0;
+}
 
 /*
  * Memory operations - move, set, print differences

^ permalink raw reply

* [v0 PATCH 4/4] EDAC: INT mode support for AMD8131 driver
From: Harry Ciao @ 2009-05-15  8:43 UTC (permalink / raw)
  To: bluesmoke-devel; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <1242377034-7378-4-git-send-email-qingtao.cao@windriver.com>

Support EDAC INT mode for AMD8131 EDAC driver, which may post upstream
NMI interrupt request messages that will latch MPIC INT0 pin.

Following aspects for this patch have been tested:
1, module initialization and deletion for NMI mode;
2, creation and deletion for the mapping between hwirq==0 to a virq;

Note, due to the difficulty and complexity to generate a real hardware
EDAC Errors, below aspects have not been tested yet:
1, code that controls the generation of the NMI Request Message;
2, the mapping from the NMI Request Messages to MPIC INT0 pin;
3, if EDAC isr methods could handle errors correctly.

Signed-off-by: Harry Ciao <qingtao.cao@windriver.com>
diff --git a/drivers/edac/amd8131_edac.c b/drivers/edac/amd8131_edac.c
index b432d60..913be34 100644
--- a/drivers/edac/amd8131_edac.c
+++ b/drivers/edac/amd8131_edac.c
@@ -28,6 +28,7 @@
 #include <linux/bitops.h>
 #include <linux/edac.h>
 #include <linux/pci_ids.h>
+#include <linux/interrupt.h>
 
 #include "edac_core.h"
 #include "edac_module.h"
@@ -36,6 +37,11 @@
 #define AMD8131_EDAC_REVISION	" Ver: 1.0.0 " __DATE__
 #define AMD8131_EDAC_MOD_STR	"amd8131_edac"
 
+static int amd8131_op_state = EDAC_OPSTATE_POLL;
+module_param(amd8131_op_state, int, 0444);
+MODULE_PARM_DESC(amd8131_op_state, "EDAC Error Reporting state: 0=Poll, 1=NMI");
+static int amd8131_nmi_irq;
+
 /* Wrapper functions for accessing PCI configuration space */
 static void edac_pci_read_dword(struct pci_dev *dev, int reg, u32 *val32)
 {
@@ -139,6 +145,17 @@ static void amd8131_pcix_init(struct amd8131_dev_info *dev_info)
 	edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
 	val32 |= LNK_CTRL_CRCFEN;
 	edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
+
+	/* enable HT NMI messages generation on errors */
+	if (amd8131_op_state == EDAC_OPSTATE_NMI) {
+		edac_pci_read_dword(dev, REG_MISC_I, &val32);
+		val32 &= ~MISC_I_NIOAMODE;
+		edac_pci_write_dword(dev, REG_MISC_I, val32);
+
+		edac_pci_read_dword(dev, REG_MISC_II, &val32);
+		val32 |= MISC_II_NMIEN;
+		edac_pci_write_dword(dev, REG_MISC_II, val32);
+	}
 }
 
 static void amd8131_pcix_exit(struct amd8131_dev_info *dev_info)
@@ -165,6 +182,17 @@ static void amd8131_pcix_exit(struct amd8131_dev_info *dev_info)
 	edac_pci_read_dword(dev, REG_LNK_CTRL_B, &val32);
 	val32 &= ~LNK_CTRL_CRCFEN;
 	edac_pci_write_dword(dev, REG_LNK_CTRL_B, val32);
+
+	/* Disable HT NMI messages on errors*/
+	if (amd8131_op_state == EDAC_OPSTATE_NMI) {
+		edac_pci_read_dword(dev, REG_MISC_II, &val32);
+		val32 &= ~MISC_II_NMIEN;
+		edac_pci_write_dword(dev, REG_MISC_II, val32);
+
+		edac_pci_read_dword(dev, REG_MISC_I, &val32);
+		val32 |= MISC_I_NIOAMODE;
+		edac_pci_write_dword(dev, REG_MISC_I, val32);
+	}
 }
 
 static void amd8131_pcix_check(struct edac_pci_ctl_info *edac_dev)
@@ -233,12 +261,33 @@ static void amd8131_pcix_check(struct edac_pci_ctl_info *edac_dev)
 	}
 }
 
+static irqreturn_t amd8131_pcix_isr(int irq, void *dev_id)
+{
+	struct edac_pci_ctl_info *edac_pci = dev_id;
+	struct amd8131_dev_info *dev_info = edac_pci->pvt_info;
+	struct pci_dev *dev = dev_info->dev;
+	u32 val32;
+
+	/*
+	 * Only a handful of errors in PCI-X Bridge Memory Base-Limit
+	 * Register could trigger NMI interrupt request message.
+	 */
+	edac_pci_read_dword(dev, REG_MEM_LIM, &val32);
+	if (!(val32 & MEM_LIMIT_NMI_MASK))
+		return IRQ_NONE;
+
+	amd8131_pcix_check(edac_pci);
+
+	return IRQ_HANDLED;
+}
+
 static struct amd8131_info amd8131_chipset = {
 	.err_dev = PCI_DEVICE_ID_AMD_8131_APIC,
 	.devices = amd8131_devices,
 	.init = amd8131_pcix_init,
 	.exit = amd8131_pcix_exit,
 	.check = amd8131_pcix_check,
+	.isr = amd8131_pcix_isr,
 };
 
 /*
@@ -249,6 +298,7 @@ static struct amd8131_info amd8131_chipset = {
 static int amd8131_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
 	struct amd8131_dev_info *dev_info;
+	int ret = -ENODEV;
 
 	for (dev_info = amd8131_chipset.devices; dev_info->inst != NO_BRIDGE;
 		dev_info++)
@@ -256,7 +306,7 @@ static int amd8131_probe(struct pci_dev *dev, const struct pci_device_id *id)
 			break;
 
 	if (dev_info->inst == NO_BRIDGE) /* should never happen */
-		return -ENODEV;
+		goto out;
 
 	/*
 	 * We can't call pci_get_device() as we are used to do because
@@ -265,12 +315,11 @@ static int amd8131_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	dev_info->dev = pci_dev_get(dev);
 
 	if (pci_enable_device(dev_info->dev)) {
-		pci_dev_put(dev_info->dev);
 		printk(KERN_ERR "failed to enable:"
 			"vendor %x, device %x, devfn %x, name %s\n",
 			PCI_VENDOR_ID_AMD, amd8131_chipset.err_dev,
 			dev_info->devfn, dev_info->ctl_name);
-		return -ENODEV;
+		goto err1;
 	}
 
 	/*
@@ -280,8 +329,10 @@ static int amd8131_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	 */
 	dev_info->edac_idx = edac_pci_alloc_index();
 	dev_info->edac_dev = edac_pci_alloc_ctl_info(0, dev_info->ctl_name);
-	if (!dev_info->edac_dev)
-		return -ENOMEM;
+	if (!dev_info->edac_dev) {
+		ret = -ENOMEM;
+		goto err1;
+	}
 
 	dev_info->edac_dev->pvt_info = dev_info;
 	dev_info->edac_dev->dev = &dev_info->dev->dev;
@@ -289,7 +340,7 @@ static int amd8131_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	dev_info->edac_dev->ctl_name = dev_info->ctl_name;
 	dev_info->edac_dev->dev_name = dev_name(&dev_info->dev->dev);
 
-	if (edac_op_state == EDAC_OPSTATE_POLL)
+	if (amd8131_op_state == EDAC_OPSTATE_POLL)
 		dev_info->edac_dev->edac_check = amd8131_chipset.check;
 
 	if (amd8131_chipset.init)
@@ -298,8 +349,8 @@ static int amd8131_probe(struct pci_dev *dev, const struct pci_device_id *id)
 	if (edac_pci_add_device(dev_info->edac_dev, dev_info->edac_idx) > 0) {
 		printk(KERN_ERR "failed edac_pci_add_device() for %s\n",
 			dev_info->ctl_name);
-		edac_pci_free_ctl_info(dev_info->edac_dev);
-		return -ENODEV;
+		ret = -ENOMEM;
+		goto err2;
 	}
 
 	printk(KERN_INFO "added one device on AMD8131 "
@@ -307,7 +358,18 @@ static int amd8131_probe(struct pci_dev *dev, const struct pci_device_id *id)
 		PCI_VENDOR_ID_AMD, amd8131_chipset.err_dev,
 		dev_info->devfn, dev_info->ctl_name);
 
-	return 0;
+	ret = 0;
+	goto out;
+
+err2:
+	if (amd8131_chipset.exit)
+		amd8131_chipset.exit(dev_info);
+
+	edac_pci_free_ctl_info(dev_info->edac_dev);
+err1:
+	pci_dev_put(dev_info->dev);
+out:
+	return ret;
 }
 
 static void amd8131_remove(struct pci_dev *dev)
@@ -322,14 +384,14 @@ static void amd8131_remove(struct pci_dev *dev)
 	if (dev_info->inst == NO_BRIDGE) /* should never happen */
 		return;
 
+	if (amd8131_chipset.exit)
+		amd8131_chipset.exit(dev_info);
+
 	if (dev_info->edac_dev) {
 		edac_pci_del_device(dev_info->edac_dev->dev);
 		edac_pci_free_ctl_info(dev_info->edac_dev);
 	}
 
-	if (amd8131_chipset.exit)
-		amd8131_chipset.exit(dev_info);
-
 	pci_dev_put(dev_info->dev);
 }
 
@@ -342,9 +404,7 @@ static const struct pci_device_id amd8131_edac_pci_tbl[] = {
 	.class_mask = 0,
 	.driver_data = 0,
 	},
-	{
-	0,
-	}			/* table is NULL-terminated */
+	{0}	/* table is NULL-terminated */
 };
 MODULE_DEVICE_TABLE(pci, amd8131_edac_pci_tbl);
 
@@ -355,20 +415,97 @@ static struct pci_driver amd8131_edac_driver = {
 	.id_table = amd8131_edac_pci_tbl,
 };
 
+/*
+ * AMD8131 NMI handler - check PCI-X Bridges to claim any
+ * possible NMI instance.
+ * Southbridge NMI Request messages posted through Hypertransport
+ * Channel will be transferred to a MPIC interrupt instance.
+ *
+ * NOTE: According to AMD8131 data sheet 4.5.7 section,
+ * only a partial of error detections could generate NMI
+ * Upstream Hypertransport Interrupt request messages, so
+ * use NMI mode at sacrifice that not all error detections
+ * could be made use of.
+ */
+static irqreturn_t amd8131_nmi_handler(int irq, void *dev_id)
+{
+	struct amd8131_info *info = dev_id;
+	struct amd8131_dev_info *dev_info;
+	irqreturn_t ret = IRQ_NONE;
+
+	if (!info->isr)
+		return IRQ_NONE;
+
+	for (dev_info = info->devices; dev_info->inst != NO_BRIDGE; dev_info++)
+		ret |= info->isr(irq, dev_info->edac_dev);
+
+	return ret;
+}
+
+static void __init amd8131_nmi_handler_setup(void)
+{
+	int ret;
+
+	if (amd8131_op_state != EDAC_OPSTATE_NMI)
+		return;
+
+	amd8131_nmi_irq = NO_IRQ;
+
+#ifdef CONFIG_MPIC
+	amd8131_nmi_irq = edac_get_mpic_irq(MPIC_HWIRQ_HT_NMI);
+#endif
+
+	if (amd8131_nmi_irq == NO_IRQ) {
+		printk(KERN_ERR "%s: failed to get virq "
+			"for AMD8131 NMI requests\n", __func__);
+		return;
+	}
+
+	ret = request_irq(amd8131_nmi_irq, amd8131_nmi_handler,
+			  IRQF_SHARED, "[EDAC] AMD8131", &amd8131_chipset);
+	if (ret < 0) {
+		printk(KERN_INFO "%s: failed to request irq %d for "
+			"AMD8131 NMI requests\n", __func__, amd8131_nmi_irq);
+		return;
+	}
+
+	debugf0("%s: Successfully requested irq %d for AMD8131 NMI requests\n",
+		 __func__, amd8131_nmi_irq);
+}
+
+static void __exit amd8131_nmi_handler_exit(void)
+{
+	if (amd8131_op_state != EDAC_OPSTATE_NMI)
+		return;
+
+	if (amd8131_nmi_irq != NO_IRQ) {
+		free_irq(amd8131_nmi_irq, &amd8131_chipset);
+#ifdef CONGIF_MPIC
+		edac_put_mpic_irq(MPIC_HWIRQ_HT_NMI);
+#endif
+	}
+}
+
 static int __init amd8131_edac_init(void)
 {
+	int ret;
+
 	printk(KERN_INFO "AMD8131 EDAC driver " AMD8131_EDAC_REVISION "\n");
 	printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n");
 
-	/* Only POLL mode supported so far */
-	edac_op_state = EDAC_OPSTATE_POLL;
+	ret = pci_register_driver(&amd8131_edac_driver);
 
-	return pci_register_driver(&amd8131_edac_driver);
+	if (ret == 0)
+		amd8131_nmi_handler_setup();
+
+	return ret;
 }
 
 static void __exit amd8131_edac_exit(void)
 {
 	pci_unregister_driver(&amd8131_edac_driver);
+
+	amd8131_nmi_handler_exit();
 }
 
 module_init(amd8131_edac_init);
diff --git a/drivers/edac/amd8131_edac.h b/drivers/edac/amd8131_edac.h
index 60e0d1c..7e86cbf 100644
--- a/drivers/edac/amd8131_edac.h
+++ b/drivers/edac/amd8131_edac.h
@@ -61,7 +61,8 @@ enum mem_limit_bits {
 	MEM_LIMIT_STA	= BIT(27),
 	MEM_LIMIT_MDPE	= BIT(24),
 	MEM_LIMIT_MASK	= MEM_LIMIT_DPE|MEM_LIMIT_RSE|MEM_LIMIT_RMA|
-				MEM_LIMIT_RTA|MEM_LIMIT_STA|MEM_LIMIT_MDPE
+				MEM_LIMIT_RTA|MEM_LIMIT_STA|MEM_LIMIT_MDPE,
+	MEM_LIMIT_NMI_MASK = MEM_LIMIT_DPE | MEM_LIMIT_RSE
 };
 
 /************************************************************
@@ -80,6 +81,22 @@ enum lnk_ctrl_bits {
 	LNK_CTRL_CRCFEN		= BIT(1)
 };
 
+/************************************************************
+ *	PCI-X Miscellaneous Register, Dev[B,A]:0x40
+ ************************************************************/
+#define REG_MISC_I	0x40
+enum misc_i_bits {
+	MISC_I_NIOAMODE	= BIT(0),
+};
+
+/************************************************************
+ *	PCI-X Miscellaneous II Register, Dev[B,A]:0x44
+ ************************************************************/
+#define REG_MISC_II	0x44
+enum misc_ii_bits {
+	MISC_II_NMIEN	= BIT(0),
+};
+
 enum pcix_bridge_inst {
 	NORTH_A = 0,
 	NORTH_B = 1,
@@ -113,6 +130,7 @@ struct amd8131_info {
 	void (*init)(struct amd8131_dev_info *dev_info);
 	void (*exit)(struct amd8131_dev_info *dev_info);
 	void (*check)(struct edac_pci_ctl_info *edac_dev);
+	irqreturn_t (*isr)(int irq, void *dev_id);
 };
 
 #endif /* _AMD8131_EDAC_H_ */

^ permalink raw reply related

* [v0 PATCH 1/4] EDAC: MPIC Hypertransport IRQ support
From: Harry Ciao @ 2009-05-15  8:43 UTC (permalink / raw)
  To: bluesmoke-devel; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <1242377034-7378-1-git-send-email-qingtao.cao@windriver.com>

Support EDAC INT mode for Hypertransport devices, where southbridge
NMI Request messages posted through Hypertransport Channel will
be transferred to a MPIC interrupt instance that latches MPIC INT0
pin. Also, Hypertransport Hostbridge controller may latch MPIC INT2
pin for Hypertransport Link Errors.

Since multiple Hypertransport southbridges such as AMD8131 & AMD8111
could post NMI request messages, EDAC core should be responsible
for maintaining the mapping from hwirq == 0 to a virq.

The edac_mpic_irq.c is inert for EDAC drivers where related hardware
is not connecting to MPIC, so it should be controlled by CONFIG_MPIC.

Signed-off-by: Harry Ciao <qingtao.cao@windriver.com>
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 07a31cf..62778ee 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -17,6 +17,10 @@ ifdef CONFIG_PCI
 edac_core-objs	+= edac_pci.o edac_pci_sysfs.o
 endif
 
+ifdef CONFIG_MPIC
+edac_core-objs += edac_mpic_irq.o
+endif
+
 obj-$(CONFIG_EDAC_AMD76X)		+= amd76x_edac.o
 obj-$(CONFIG_EDAC_CPC925)		+= cpc925_edac.o
 obj-$(CONFIG_EDAC_I5000)		+= i5000_edac.o
diff --git a/drivers/edac/edac_mpic_irq.c b/drivers/edac/edac_mpic_irq.c
new file mode 100644
index 0000000..26b43c0
--- /dev/null
+++ b/drivers/edac/edac_mpic_irq.c
@@ -0,0 +1,145 @@
+/*
+ * edac_mpic_irq.c -
+ * 	For all EDAC Hypertransport southbridge devices(such as AMD8111
+ * 	or AMD8131) that could post upstream NMI Request Messages, this
+ * 	driver is used to manage the mapping from the hardware IRQ that
+ * 	carried in the NMI Request Message to its related virtual IRQ.
+ *
+ * 	The EDAC driver for a specific Hypertransport southbridge device
+ * 	must implement its mach-specific method for edac_mach_get_irq().
+ *
+ * Copyright (c) 2009 Wind River Systems, Inc.
+ *
+ * Authors:	Cao Qingtao <qingtao.cao@windriver.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/edac.h>
+
+struct irqmap {
+	int virq;
+	int count;
+};
+
+static struct irqmap hwirq2virqs[MPIC_HWIRQS] = {
+	[MPIC_HWIRQ_HT_NMI] = {
+		.virq = NO_IRQ,
+		.count = 0,
+	},
+	[MPIC_HWIRQ_INTERNAL_ERROR] = {
+		.virq = NO_IRQ,
+		.count = 0,
+	},
+};
+
+#ifdef CONFIG_PPC_MAPLE
+static int edac_maple_get_irq(int hwirq)
+{
+	struct device_node *np, *mpic_node = NULL;
+	int irq = NO_IRQ;
+
+	/*
+	 * Locate MPIC in the device-tree. Note that there is a bug
+	 * in Maple device-tree where the type of the controller is
+	 * open-pic and not interrupt-controller
+	 */
+	for_each_node_by_type(np, "interrupt-controller") {
+		if (of_device_is_compatible(np, "open-pic")) {
+			mpic_node = np;
+			break;
+		}
+	}
+
+	if (mpic_node == NULL) {
+		for_each_node_by_type(np, "open-pic") {
+			mpic_node = np;
+			break;
+		}
+	}
+
+	if (mpic_node) {
+		irq = irq_create_of_mapping(mpic_node, &hwirq, 1);
+		of_node_put(mpic_node);
+	} else
+		printk(KERN_ERR "Failed to locate the MPIC DTB node\n");
+
+	return irq;
+}
+#endif
+
+/*
+ * NOTE:
+ * The EDAC driver should implement and register its machine-specific
+ * method to get a virtual IRQ here.
+ */
+static int edac_mach_get_irq(int hwirq)
+{
+	int virq = NO_IRQ;
+
+#ifdef CONFIG_PPC_MAPLE
+	virq = edac_maple_get_irq(hwirq);
+#endif
+
+	return virq;
+}
+
+int edac_get_mpic_irq(int hwirq)
+{
+	struct irqmap *irq;
+
+	if ((hwirq != MPIC_HWIRQ_HT_NMI) &&
+	    (hwirq != MPIC_HWIRQ_INTERNAL_ERROR))
+		return NO_IRQ;
+
+	irq = &hwirq2virqs[hwirq];
+
+	if (irq->virq == NO_IRQ) {
+		if (irq->count == 0) {
+			irq->virq = edac_mach_get_irq(hwirq);
+			if (irq->virq != NO_IRQ)
+				irq->count++;
+			else
+				irq->count = -1; /* error */
+		}
+	} else
+		irq->count++;
+
+	return irq->virq;
+}
+EXPORT_SYMBOL_GPL(edac_get_mpic_irq);
+
+void edac_put_mpic_irq(int hwirq)
+{
+	struct irqmap *irq;
+
+	if ((hwirq != MPIC_HWIRQ_HT_NMI) &&
+	    (hwirq != MPIC_HWIRQ_INTERNAL_ERROR))
+		return;
+
+	irq = &hwirq2virqs[hwirq];
+
+	if (irq->count <= 0)
+		return;
+
+	if (--irq->count == 0) {
+		irq_dispose_mapping(irq->virq);
+		irq->virq = NO_IRQ;
+	}
+}
+EXPORT_SYMBOL_GPL(edac_put_mpic_irq);
diff --git a/include/linux/edac.h b/include/linux/edac.h
index 7cf92e8..804dbb6 100644
--- a/include/linux/edac.h
+++ b/include/linux/edac.h
@@ -38,4 +38,27 @@ static inline void opstate_init(void)
 	return;
 }
 
+#ifdef CONFIG_MPIC
+enum {
+	/*
+	 * Vector carried in southbridge NMI Request Messages
+	 * posted through Hypertransport Channel
+	 */
+	MPIC_HWIRQ_HT_NMI = 0,
+
+	/*
+	 * Vector for MPIC Internal Error
+	 */
+	MPIC_HWIRQ_INTERNAL_ERROR = 2,
+
+	MPIC_HWIRQS,	/* must be the very last */
+};
+
+/* Create a hwirq2virq mapping for the specified hwirq */
+extern int edac_get_mpic_irq(int hwirq);
+
+/* Dispose the hwirq2virq mapping for the specified hwirq */
+extern void edac_put_mpic_irq(int hwirq);
+#endif
+
 #endif

^ permalink raw reply related

* [v0 PATCH 3/4] EDAC: INT mode support for AMD8111 driver
From: Harry Ciao @ 2009-05-15  8:43 UTC (permalink / raw)
  To: bluesmoke-devel; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <1242377034-7378-3-git-send-email-qingtao.cao@windriver.com>

Support EDAC INT mode for AMD8111 EDAC driver, which may post upstream
NMI interrupt request messages that will latch MPIC INT0 pin.

Following aspects for this patch have been tested:
1, module initialization and deletion for NMI mode;
2, creation and deletion for the mapping between hwirq==0 to a virq;

Note, due to the difficulty and complexity to generate a real hardware
EDAC Errors, below aspects have not been tested yet:
1, code that controls the generation of the NMI Request Message;
2, the mapping from the NMI Request Messages to MPIC INT0 pin;
3, if EDAC isr methods could handle errors correctly.

Signed-off-by: Harry Ciao <qingtao.cao@windriver.com>
diff --git a/drivers/edac/amd8111_edac.c b/drivers/edac/amd8111_edac.c
index 35b78d0..022a5bc 100644
--- a/drivers/edac/amd8111_edac.c
+++ b/drivers/edac/amd8111_edac.c
@@ -38,6 +38,11 @@
 
 #define PCI_DEVICE_ID_AMD_8111_PCI	0x7460
 
+static int amd8111_op_state = EDAC_OPSTATE_POLL;
+module_param(amd8111_op_state, int, 0444);
+MODULE_PARM_DESC(amd8111_op_state, "EDAC Error Reporting state: 0=Poll, 1=NMI");
+static int amd8111_nmi_irq;
+
 enum amd8111_edac_devs {
 	LPC_BRIDGE = 0,
 };
@@ -89,10 +94,9 @@ static void edac_pci_write_byte(struct pci_dev *dev, int reg, u8 val8)
 			" PCI Access Write Error at 0x%x\n", reg);
 }
 
+/* device specific methods for AMD8111 PCI Bridge device */
 /*
- * device-specific methods for amd8111 PCI Bridge Controller
- *
- * Error Reporting and Handling for amd8111 chipset could be found
+ * Error Reporting and Handling for AMD8111 chipset could be found
  * in its datasheet 3.1.2 section, P37
  */
 static void amd8111_pci_bridge_init(struct amd8111_pci_info *pci_info)
@@ -125,7 +129,7 @@ static void amd8111_pci_bridge_init(struct amd8111_pci_info *pci_info)
 		edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
 
 	/* Last enable error detections */
-	if (edac_op_state == EDAC_OPSTATE_POLL) {
+	if (amd8111_op_state == EDAC_OPSTATE_POLL) {
 		/* Enable System Error reporting in global status register */
 		edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
 		val32 |= PCI_STSCMD_SERREN;
@@ -140,6 +144,11 @@ static void amd8111_pci_bridge_init(struct amd8111_pci_info *pci_info)
 		edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
 		val32 |= PCI_INTBRG_CTRL_POLL_MASK;
 		edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
+	} else if (amd8111_op_state == EDAC_OPSTATE_NMI) {
+		/* Enable Parity Error detection on secondary PCI bus */
+		edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
+		val32 |= PCI_INTBRG_CTRL_PEREN;
+		edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
 	}
 }
 
@@ -148,7 +157,7 @@ static void amd8111_pci_bridge_exit(struct amd8111_pci_info *pci_info)
 	u32 val32;
 	struct pci_dev *dev = pci_info->dev;
 
-	if (edac_op_state == EDAC_OPSTATE_POLL) {
+	if (amd8111_op_state == EDAC_OPSTATE_POLL) {
 		/* Disable System Error reporting */
 		edac_pci_read_dword(dev, REG_PCI_STSCMD, &val32);
 		val32 &= ~PCI_STSCMD_SERREN;
@@ -163,6 +172,11 @@ static void amd8111_pci_bridge_exit(struct amd8111_pci_info *pci_info)
 		edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
 		val32 &= ~PCI_INTBRG_CTRL_POLL_MASK;
 		edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
+	} else if (amd8111_op_state == EDAC_OPSTATE_NMI) {
+		/* Disable Parity Error detection on secondary PCI bus */
+		edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &val32);
+		val32 &= ~PCI_INTBRG_CTRL_PEREN;
+		edac_pci_write_dword(dev, REG_PCI_INTBRG_CTRL, val32);
 	}
 }
 
@@ -238,11 +252,136 @@ static void amd8111_pci_bridge_check(struct edac_pci_ctl_info *edac_dev)
 	}
 }
 
+static irqreturn_t amd8111_pci_bridge_isr(int irq, void *dev_id)
+{
+	struct edac_pci_ctl_info *edac_dev = dev_id;
+	struct amd8111_pci_info *pci_info = edac_dev->pvt_info;
+	struct pci_dev *dev = pci_info->dev;
+	u32 stscmd, htlink, intbrg, memlim;
+
+	edac_pci_read_dword(dev, REG_PCI_STSCMD, &stscmd);
+	edac_pci_read_dword(dev, REG_HT_LINK, &htlink);
+	edac_pci_read_dword(dev, REG_PCI_INTBRG_CTRL, &intbrg);
+	edac_pci_read_dword(dev, REG_MEM_LIM, &memlim);
+
+	if (!((stscmd & PCI_STSCMD_NMI_MASK) ||
+	      (htlink & HT_LINK_CRCERR) ||
+	      (intbrg & PCI_INTBRG_CTRL_DTSTAT) ||
+	      (memlim & MEM_LIMIT_CLEAR_MASK)))
+		return IRQ_NONE;
+
+	amd8111_pci_bridge_check(edac_dev);
+
+	return IRQ_HANDLED;
+}
+
+/* device specific methods for AMD8111 LPC Bridge device */
+/*
+ * According to AMD8111 datasheet 3.4.2.4 section, NMI is controlled
+ * by following equation:
+ * NMI = ~PORT70[NMIDIS] &
+ * 	(PM48[NMI_NOW] | ~PM48[NMI2SMI_EN] &
+ *	 (PORT61[SERR] & ~PORT61[CLRSERR]
+ *	 | PORT61[IOCHK] & ~PORT61[CLRIOCHK]
+ *	 | DevB:0x40[NMIONERR] & [status bits described in section 3.1.2]
+ *	 | DevA:0x1C[MDPE] & DevA:0x3C[PEREN]));
+ *
+ * PORT70[NMIDIS] and PM48[NMI2SMI_EN] will be turned off here
+ * if necessary, the rest of device-specific NMI control bits
+ * will be set separately.
+ */
+static int amd8111_NMI_global_enable(struct pci_dev *lpc_dev)
+{
+	struct pci_dev *dev = lpc_dev;
+	u8 val8;
+	u16 val16;
+	u32 val32, mapbase;
+	void __iomem *mmio_vbase;
+
+	/*
+	 * Global NMI disablement status could be read from
+	 * DevB:0x41[NMIDIS], clear PORT70[NMIDIS] only when
+	 * DevB:0x41[NMIDIS] is set.
+	 */
+	edac_pci_read_byte(dev, REG_IO_CTRL_2, &val8);
+	if (val8 & IO_CTRL_2_NMIDIS) {
+		val8 = __do_inb(REG_RTC);
+		val8 &= ~RTC_NMIDIS;
+		__do_outb(val8, REG_RTC);
+	}
+
+	/*
+	 * The start address of the 256-byte relocatable System Management
+	 * I/O register block is specified by DevB:3x58[PMBASE], and
+	 * accessing this MMIO region is controlled by DevB:3x41[PMIOEN].
+	 */
+	dev = pci_get_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS,
+			     NULL);
+	if (!dev) {
+		printk(KERN_ERR "%s: AMD8111 NMI control device not found: "
+			"vendor %x, device %x\n", __func__,
+			PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS);
+		return -ENODEV;
+	}
+
+	if (pci_enable_device(dev)) {
+		pci_dev_put(dev);
+		printk(KERN_ERR "%s: failed to enable: "
+			"vendor %x, device %x\n", __func__,
+			PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8111_SMBUS);
+		return -ENODEV;
+	}
+
+	edac_pci_read_byte(dev, REG_GEN_CONFIG_2, &val8);
+	if (!(val8 & GEN_CONFIG_2_PMIOEN)) {
+		val8 |= GEN_CONFIG_2_PMIOEN;
+		edac_pci_write_byte(dev, REG_GEN_CONFIG_2, val8);
+	}
+
+	/*
+	 * get the physical address of the relocatable 256-byte
+	 * System Management I/O register block.
+	 */
+	edac_pci_read_dword(dev, REG_SYSMAN_IO_SPACE, &val32);
+	mapbase = val32 & SYSMAN_IO_SPACE_PMBASE_MASK;
+	mapbase += dev->bus->resource[0]->start;
+
+	if (!request_mem_region(mapbase, AMD8111_SYSMAN_IO_SIZE,
+				"amd8111_PMxx")) {
+		pci_dev_put(dev);
+		printk(KERN_ERR "%s: failed to request region\n", __func__);
+		return -EBUSY;
+	}
+
+	mmio_vbase = ioremap(mapbase, AMD8111_SYSMAN_IO_SIZE);
+	if (!mmio_vbase) {
+		printk(KERN_ERR "%s: failed to ioremap region: "
+			"address 0x%x, len 0x%x\n", __func__,
+			mapbase, AMD8111_SYSMAN_IO_SIZE);
+		pci_dev_put(dev);
+		return -ENOMEM;
+	}
+
+	/* clear PM48[NMI2SMI_EN] if necessary */
+	val16 = in_le16(mmio_vbase + IO_TCO_CTRL_1);
+	if (val16 & IO_TCO_CTRL_1_NMI2SMI_EN) {
+		val16 &= ~IO_TCO_CTRL_1_NMI2SMI_EN;
+		out_le16(mmio_vbase + IO_TCO_CTRL_1, val16);
+		printk(KERN_INFO "%s: PM48[NMI2SMI_EN] is cleared\n", __func__);
+	}
+
+	iounmap(mmio_vbase);
+	release_mem_region(mapbase, AMD8111_SYSMAN_IO_SIZE);
+
+	pci_dev_put(dev);
+
+	return 0;
+}
+
 static struct resource *legacy_io_res;
 static int at_compat_reg_broken;
 #define LEGACY_NR_PORTS	1
 
-/* device-specific methods for amd8111 LPC Bridge device */
 static void amd8111_lpc_bridge_init(struct amd8111_dev_info *dev_info)
 {
 	u8 val8;
@@ -278,10 +417,29 @@ static void amd8111_lpc_bridge_init(struct amd8111_dev_info *dev_info)
 	edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8);
 	if (val8 & IO_CTRL_1_CLEAR_MASK)
 		edac_pci_write_byte(dev, REG_IO_CTRL_1, val8);
+
+	if (amd8111_op_state == EDAC_OPSTATE_NMI) {
+		/* Enable NMI generation on errors */
+		edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8);
+		val8 |= IO_CTRL_1_NMIONERR;
+		edac_pci_write_byte(dev, REG_IO_CTRL_1, val8);
+
+		amd8111_NMI_global_enable(dev);
+	}
 }
 
 static void amd8111_lpc_bridge_exit(struct amd8111_dev_info *dev_info)
 {
+	u8 val8;
+	struct pci_dev *dev = dev_info->dev;
+
+	if (amd8111_op_state == EDAC_OPSTATE_NMI) {
+		/* Disable NMI generation on errors */
+		edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8);
+		val8 &= ~IO_CTRL_1_NMIONERR;
+		edac_pci_write_byte(dev, REG_IO_CTRL_1, val8);
+	}
+
 	if (legacy_io_res)
 		release_region(REG_AT_COMPAT, LEGACY_NR_PORTS);
 }
@@ -322,6 +480,22 @@ static void amd8111_lpc_bridge_check(struct edac_device_ctl_info *edac_dev)
 	}
 }
 
+static irqreturn_t amd8111_lpc_bridge_isr(int irq, void *dev_id)
+{
+	struct edac_device_ctl_info *edac_dev = dev_id;
+	struct amd8111_dev_info *dev_info = edac_dev->pvt_info;
+	struct pci_dev *dev = dev_info->dev;
+	u8 val8;
+
+	edac_pci_read_byte(dev, REG_IO_CTRL_1, &val8);
+	if (!(val8 & IO_CTRL_1_CLEAR_MASK))
+		return IRQ_NONE;
+
+	amd8111_lpc_bridge_check(edac_dev);
+
+	return IRQ_HANDLED;
+}
+
 /* General devices represented by edac_device_ctl_info */
 static struct amd8111_dev_info amd8111_devices[] = {
 	[LPC_BRIDGE] = {
@@ -330,6 +504,7 @@ static struct amd8111_dev_info amd8111_devices[] = {
 		.init = amd8111_lpc_bridge_init,
 		.exit = amd8111_lpc_bridge_exit,
 		.check = amd8111_lpc_bridge_check,
+		.isr = amd8111_lpc_bridge_isr,
 	},
 	{0},
 };
@@ -342,6 +517,7 @@ static struct amd8111_pci_info amd8111_pcis[] = {
 		.init = amd8111_pci_bridge_init,
 		.exit = amd8111_pci_bridge_exit,
 		.check = amd8111_pci_bridge_check,
+		.isr = amd8111_pci_bridge_isr,
 	},
 	{0},
 };
@@ -350,25 +526,24 @@ static int amd8111_dev_probe(struct pci_dev *dev,
 				const struct pci_device_id *id)
 {
 	struct amd8111_dev_info *dev_info = &amd8111_devices[id->driver_data];
+	int ret = -ENODEV;
 
 	dev_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,
 					dev_info->err_dev, NULL);
-
 	if (!dev_info->dev) {
 		printk(KERN_ERR "EDAC device not found:"
 			"vendor %x, device %x, name %s\n",
 			PCI_VENDOR_ID_AMD, dev_info->err_dev,
 			dev_info->ctl_name);
-		return -ENODEV;
+		goto out;
 	}
 
 	if (pci_enable_device(dev_info->dev)) {
-		pci_dev_put(dev_info->dev);
 		printk(KERN_ERR "failed to enable:"
 			"vendor %x, device %x, name %s\n",
 			PCI_VENDOR_ID_AMD, dev_info->err_dev,
 			dev_info->ctl_name);
-		return -ENODEV;
+		goto err1;
 	}
 
 	/*
@@ -381,8 +556,10 @@ static int amd8111_dev_probe(struct pci_dev *dev,
 		edac_device_alloc_ctl_info(0, dev_info->ctl_name, 1,
 					   NULL, 0, 0,
 					   NULL, 0, dev_info->edac_idx);
-	if (!dev_info->edac_dev)
-		return -ENOMEM;
+	if (!dev_info->edac_dev) {
+		ret = -ENOMEM;
+		goto err1;
+	}
 
 	dev_info->edac_dev->pvt_info = dev_info;
 	dev_info->edac_dev->dev = &dev_info->dev->dev;
@@ -390,7 +567,7 @@ static int amd8111_dev_probe(struct pci_dev *dev,
 	dev_info->edac_dev->ctl_name = dev_info->ctl_name;
 	dev_info->edac_dev->dev_name = dev_name(&dev_info->dev->dev);
 
-	if (edac_op_state == EDAC_OPSTATE_POLL)
+	if (amd8111_op_state == EDAC_OPSTATE_POLL)
 		dev_info->edac_dev->edac_check = dev_info->check;
 
 	if (dev_info->init)
@@ -399,16 +576,27 @@ static int amd8111_dev_probe(struct pci_dev *dev,
 	if (edac_device_add_device(dev_info->edac_dev) > 0) {
 		printk(KERN_ERR "failed to add edac_dev for %s\n",
 			dev_info->ctl_name);
-		edac_device_free_ctl_info(dev_info->edac_dev);
-		return -ENODEV;
+		ret = -ENOMEM;
+		goto err2;
 	}
 
-	printk(KERN_INFO "added one edac_dev on AMD8111 "
+	printk(KERN_INFO "added one device on AMD8111 "
 		"vendor %x, device %x, name %s\n",
 		PCI_VENDOR_ID_AMD, dev_info->err_dev,
 		dev_info->ctl_name);
 
-	return 0;
+	ret = 0;
+	goto out;
+
+err2:
+	if (dev_info->exit)
+		dev_info->exit(dev_info);
+
+	edac_device_free_ctl_info(dev_info->edac_dev);
+err1:
+	pci_dev_put(dev_info->dev);
+out:
+	return ret;
 }
 
 static void amd8111_dev_remove(struct pci_dev *dev)
@@ -422,14 +610,14 @@ static void amd8111_dev_remove(struct pci_dev *dev)
 	if (!dev_info->err_dev)	/* should never happen */
 		return;
 
+	if (dev_info->exit)
+		dev_info->exit(dev_info);
+
 	if (dev_info->edac_dev) {
 		edac_device_del_device(dev_info->edac_dev->dev);
 		edac_device_free_ctl_info(dev_info->edac_dev);
 	}
 
-	if (dev_info->exit)
-		dev_info->exit(dev_info);
-
 	pci_dev_put(dev_info->dev);
 }
 
@@ -437,25 +625,24 @@ static int amd8111_pci_probe(struct pci_dev *dev,
 				const struct pci_device_id *id)
 {
 	struct amd8111_pci_info *pci_info = &amd8111_pcis[id->driver_data];
+	int ret = -ENODEV;
 
 	pci_info->dev = pci_get_device(PCI_VENDOR_ID_AMD,
 					pci_info->err_dev, NULL);
-
 	if (!pci_info->dev) {
 		printk(KERN_ERR "EDAC device not found:"
 			"vendor %x, device %x, name %s\n",
 			PCI_VENDOR_ID_AMD, pci_info->err_dev,
 			pci_info->ctl_name);
-		return -ENODEV;
+		goto out;
 	}
 
 	if (pci_enable_device(pci_info->dev)) {
-		pci_dev_put(pci_info->dev);
 		printk(KERN_ERR "failed to enable:"
 			"vendor %x, device %x, name %s\n",
 			PCI_VENDOR_ID_AMD, pci_info->err_dev,
 			pci_info->ctl_name);
-		return -ENODEV;
+		goto err1;
 	}
 
 	/*
@@ -465,8 +652,10 @@ static int amd8111_pci_probe(struct pci_dev *dev,
 	*/
 	pci_info->edac_idx = edac_pci_alloc_index();
 	pci_info->edac_dev = edac_pci_alloc_ctl_info(0, pci_info->ctl_name);
-	if (!pci_info->edac_dev)
-		return -ENOMEM;
+	if (!pci_info->edac_dev) {
+		ret = -ENOMEM;
+		goto err1;
+	}
 
 	pci_info->edac_dev->pvt_info = pci_info;
 	pci_info->edac_dev->dev = &pci_info->dev->dev;
@@ -474,7 +663,7 @@ static int amd8111_pci_probe(struct pci_dev *dev,
 	pci_info->edac_dev->ctl_name = pci_info->ctl_name;
 	pci_info->edac_dev->dev_name = dev_name(&pci_info->dev->dev);
 
-	if (edac_op_state == EDAC_OPSTATE_POLL)
+	if (amd8111_op_state == EDAC_OPSTATE_POLL)
 		pci_info->edac_dev->edac_check = pci_info->check;
 
 	if (pci_info->init)
@@ -483,16 +672,27 @@ static int amd8111_pci_probe(struct pci_dev *dev,
 	if (edac_pci_add_device(pci_info->edac_dev, pci_info->edac_idx) > 0) {
 		printk(KERN_ERR "failed to add edac_pci for %s\n",
 			pci_info->ctl_name);
-		edac_pci_free_ctl_info(pci_info->edac_dev);
-		return -ENODEV;
+		ret = -ENOMEM;
+		goto err2;
 	}
 
-	printk(KERN_INFO "added one edac_pci on AMD8111 "
+	printk(KERN_INFO "added one device on AMD8111 "
 		"vendor %x, device %x, name %s\n",
 		PCI_VENDOR_ID_AMD, pci_info->err_dev,
 		pci_info->ctl_name);
 
-	return 0;
+	ret = 0;
+	goto out;
+
+err2:
+	if (pci_info->exit)
+		pci_info->exit(pci_info);
+
+	edac_pci_free_ctl_info(pci_info->edac_dev);
+err1:
+	pci_dev_put(pci_info->dev);
+out:
+	return ret;
 }
 
 static void amd8111_pci_remove(struct pci_dev *dev)
@@ -506,14 +706,14 @@ static void amd8111_pci_remove(struct pci_dev *dev)
 	if (!pci_info->err_dev)	/* should never happen */
 		return;
 
+	if (pci_info->exit)
+		pci_info->exit(pci_info);
+
 	if (pci_info->edac_dev) {
 		edac_pci_del_device(pci_info->edac_dev->dev);
 		edac_pci_free_ctl_info(pci_info->edac_dev);
 	}
 
-	if (pci_info->exit)
-		pci_info->exit(pci_info);
-
 	pci_dev_put(pci_info->dev);
 }
 
@@ -527,9 +727,7 @@ static const struct pci_device_id amd8111_edac_dev_tbl[] = {
 	.class_mask = 0,
 	.driver_data = LPC_BRIDGE,
 	},
-	{
-	0,
-	}			/* table is NULL-terminated */
+	{0}	/* table is NULL-terminated */
 };
 MODULE_DEVICE_TABLE(pci, amd8111_edac_dev_tbl);
 
@@ -550,9 +748,7 @@ static const struct pci_device_id amd8111_edac_pci_tbl[] = {
 	.class_mask = 0,
 	.driver_data = PCI_BRIDGE,
 	},
-	{
-	0,
-	}			/* table is NULL-terminated */
+	{0}	/* table is NULL-terminated */
 };
 MODULE_DEVICE_TABLE(pci, amd8111_edac_pci_tbl);
 
@@ -563,6 +759,73 @@ static struct pci_driver amd8111_edac_pci_driver = {
 	.id_table = amd8111_edac_pci_tbl,
 };
 
+/*
+ * AMD8111 NMI handler - check Legacy ISA Bridge and PCI Bridge
+ * to claim any possible NMI instance.
+ * Southbridge NMI Request messages posted through Hypertransport
+ * Channel will be transferred to a MPIC interrupt instance.
+ */
+static irqreturn_t amd8111_nmi_handler(int irq, void *dev_id)
+{
+	struct amd8111_dev_info *dev_info;
+	struct amd8111_pci_info *pci_info;
+	irqreturn_t ret = IRQ_NONE;
+
+	for (dev_info = amd8111_devices; dev_info->err_dev; dev_info++)
+		if (dev_info->isr)
+			ret |= dev_info->isr(irq, dev_info->edac_dev);
+
+	for (pci_info = amd8111_pcis; pci_info->err_dev; pci_info++)
+		if (pci_info->isr)
+			ret |= pci_info->isr(irq, pci_info->edac_dev);
+
+	return ret;
+}
+
+static void __init amd8111_nmi_handler_setup(void)
+{
+	int ret;
+
+	if (amd8111_op_state != EDAC_OPSTATE_NMI)
+		return;
+
+	amd8111_nmi_irq = NO_IRQ;
+
+#ifdef CONFIG_MPIC
+	amd8111_nmi_irq = edac_get_mpic_irq(MPIC_HWIRQ_HT_NMI);
+#endif
+
+	if (amd8111_nmi_irq == NO_IRQ) {
+		printk(KERN_ERR "%s: failed to get virq "
+			"for AMD8111 NMI requests\n", __func__);
+		return;
+	}
+
+	ret = request_irq(amd8111_nmi_irq, amd8111_nmi_handler,
+			  IRQF_SHARED, "[EDAC] AMD8111", amd8111_devices);
+	if (ret < 0) {
+		printk(KERN_INFO "%s: failed to request irq %d for "
+			"AMD8111 NMI requests\n", __func__, amd8111_nmi_irq);
+		return;
+	}
+
+	debugf0("%s: Successfully requested irq %d for AMD8111 NMI requests\n",
+		__func__, amd8131_nmi_irq);
+}
+
+static void __exit amd8111_nmi_handler_exit(void)
+{
+	if (amd8111_op_state != EDAC_OPSTATE_NMI)
+		return;
+
+	if (amd8111_nmi_irq != NO_IRQ) {
+		free_irq(amd8111_nmi_irq, amd8111_devices);
+#ifdef CONFIG_MPIC
+		edac_put_mpic_irq(MPIC_HWIRQ_HT_NMI);
+#endif
+	}
+}
+
 static int __init amd8111_edac_init(void)
 {
 	int val;
@@ -570,12 +833,12 @@ static int __init amd8111_edac_init(void)
 	printk(KERN_INFO "AMD8111 EDAC driver "	AMD8111_EDAC_REVISION "\n");
 	printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc.\n");
 
-	/* Only POLL mode supported so far */
-	edac_op_state = EDAC_OPSTATE_POLL;
-
 	val = pci_register_driver(&amd8111_edac_dev_driver);
 	val |= pci_register_driver(&amd8111_edac_pci_driver);
 
+	if (val == 0)
+		amd8111_nmi_handler_setup();
+
 	return val;
 }
 
@@ -583,8 +846,9 @@ static void __exit amd8111_edac_exit(void)
 {
 	pci_unregister_driver(&amd8111_edac_pci_driver);
 	pci_unregister_driver(&amd8111_edac_dev_driver);
-}
 
+	amd8111_nmi_handler_exit();
+}
 
 module_init(amd8111_edac_init);
 module_exit(amd8111_edac_exit);
diff --git a/drivers/edac/amd8111_edac.h b/drivers/edac/amd8111_edac.h
index 3579433..51776b1 100644
--- a/drivers/edac/amd8111_edac.h
+++ b/drivers/edac/amd8111_edac.h
@@ -33,9 +33,8 @@ enum pci_stscmd_bits {
 	PCI_STSCMD_RMA		= BIT(29),
 	PCI_STSCMD_RTA		= BIT(28),
 	PCI_STSCMD_SERREN	= BIT(8),
-	PCI_STSCMD_CLEAR_MASK	= (PCI_STSCMD_SSE |
-				   PCI_STSCMD_RMA |
-				   PCI_STSCMD_RTA)
+	PCI_STSCMD_NMI_MASK	= (PCI_STSCMD_RMA | PCI_STSCMD_RTA),
+	PCI_STSCMD_CLEAR_MASK	= (PCI_STSCMD_SSE | PCI_STSCMD_NMI_MASK),
 };
 
 /************************************************************
@@ -62,9 +61,10 @@ enum mem_limit_bits {
  ************************************************************/
 #define REG_HT_LINK	0xc4
 enum ht_link_bits {
+	HT_LINK_CRCERR	= BIT(8),
 	HT_LINK_LKFAIL	= BIT(4),
 	HT_LINK_CRCFEN	= BIT(1),
-	HT_LINK_CLEAR_MASK = (HT_LINK_LKFAIL)
+	HT_LINK_CLEAR_MASK = (HT_LINK_LKFAIL | HT_LINK_CRCERR)
 };
 
 /************************************************************
@@ -105,6 +105,39 @@ enum at_compat_bits {
 	AT_COMPAT_CLRSERR	= BIT(2),
 };
 
+#define REG_IO_CTRL_2 0x41
+enum io_ctrl_2_bits {
+	IO_CTRL_2_NMIDIS	= BIT(1),
+};
+
+/************************************************************
+ *	System Management Configuration Registers, DevB:3xXX
+ ************************************************************/
+#define REG_GEN_CONFIG_2 0x41
+enum gen_config_2_bits {
+	GEN_CONFIG_2_PMIOEN	= BIT(7),
+};
+
+#define REG_SYSMAN_IO_SPACE 0x58
+#define SYSMAN_IO_SPACE_PMBASE_MASK 0xff00
+
+/************************************************************
+ *	System Management I/O Space, PMxx
+ ************************************************************/
+#define AMD8111_SYSMAN_IO_SIZE 256
+#define IO_TCO_CTRL_1 0x48
+enum io_tco_ctrl_1_bits {
+	IO_TCO_CTRL_1_NMI2SMI_EN = BIT(9),
+};
+
+/************************************************************
+ *	Real-Time Clock Port I/O
+ ************************************************************/
+#define REG_RTC	0x70
+enum rtc_bits {
+	RTC_NMIDIS = BIT(7),
+};
+
 struct amd8111_dev_info {
 	u16 err_dev;	/* PCI Device ID */
 	struct pci_dev *dev;
@@ -114,6 +147,7 @@ struct amd8111_dev_info {
 	void (*init)(struct amd8111_dev_info *dev_info);
 	void (*exit)(struct amd8111_dev_info *dev_info);
 	void (*check)(struct edac_device_ctl_info *edac_dev);
+	irqreturn_t (*isr)(int irq, void *dev_id);
 };
 
 struct amd8111_pci_info {
@@ -125,6 +159,7 @@ struct amd8111_pci_info {
 	void (*init)(struct amd8111_pci_info *dev_info);
 	void (*exit)(struct amd8111_pci_info *dev_info);
 	void (*check)(struct edac_pci_ctl_info *edac_dev);
+	irqreturn_t (*isr)(int irq, void *dev_id);
 };
 
 #endif /* _AMD8111_EDAC_H_ */

^ permalink raw reply related

* [v0 PATCH 2/4] EDAC: MCE & INT mode support for CPC925 driver
From: Harry Ciao @ 2009-05-15  8:43 UTC (permalink / raw)
  To: bluesmoke-devel; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <1242377034-7378-2-git-send-email-qingtao.cao@windriver.com>

Support EDAC INT mode and add a new EDAC MCE mode for CPC925 EDAC driver.
CPC925 Hypertransport hostbridge controller may trigger interrupt that
latches MPIC INT2 pin on Hypertransport Link Errors, and generate MCE on
memory ECC Errors and Processor Interface Errors.

The global variable "edac_op_state" defined by EDAC core will be
obsolete, not only different EDAC modules on the same machine may
operate in different EDAC modes, but further this could be the
case for different EDAC devices of the same EDAC module, for example,
each CPC925 EDAC device could work in the mode specified by their own
"op_state" member in their private structure.

A spinlock will be used to protect the EDAC MCE handler from being
silently unregistered, however, it also implies a constraint that
when EDAC MCE handler is called on one CPU, it will be bypassed by 
another MCE event on other CPUs.

Following aspects for this patch have been tested:
1, module initialization and deletion;
2, creation and deletion for the mapping between hwirq==2 to a virq
   for the Hypertransport Link Errors;
3, registration and unregistration for the EDAC MCE handler from the
   generic MCE handler on PPC;

Note, due to the difficulty and complexity to generate a real hardware
ECC/HT Link/CPU Errors, below aspects have not been tested yet:
1, if ECC or CPU Errors would generate MCE event;
2, if HT Link Error will indeed latch MPIC INT2 pin;
3, if EDAC isr/mce methods could handle errors correctly.

Signed-off-by: Harry Ciao <qingtao.cao@windriver.com>
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index 678fbff..1ae3465 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -57,6 +57,10 @@
 #include <asm/dbell.h>
 #endif
 
+#ifdef CONFIG_EDAC
+#include <linux/edac.h>
+#endif
+
 #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
 int (*__debugger)(struct pt_regs *regs);
 int (*__debugger_ipi)(struct pt_regs *regs);
@@ -481,6 +485,18 @@ int machine_check_generic(struct pt_regs *regs)
 	default:
 		printk("Unknown values in msr\n");
 	}
+
+#ifdef CONFIG_EDAC
+	if (spin_trylock(&edac_mce_lock)) {
+		if (edac_mce_handler) {
+			int ret = edac_mce_handler();
+			spin_unlock(&edac_mce_lock);
+			return ret;
+		}
+		spin_unlock(&edac_mce_lock);
+	}
+#endif
+
 	return 0;
 }
 #endif /* everything else */
diff --git a/drivers/edac/cpc925_edac.c b/drivers/edac/cpc925_edac.c
index 8c54196..13ff428 100644
--- a/drivers/edac/cpc925_edac.c
+++ b/drivers/edac/cpc925_edac.c
@@ -25,6 +25,8 @@
 #include <linux/edac.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <asm/reg.h>
 
 #include "edac_core.h"
 #include "edac_module.h"
@@ -273,22 +275,29 @@ enum brgctrl_bits {
 
 /* Private structure for edac memory controller */
 struct cpc925_mc_pdata {
+	int op_state;
 	void __iomem *vbase;
 	unsigned long total_mem;
 	const char *name;
 	int edac_idx;
+	struct mem_ctl_info *mci;
+	int (*mce)(struct mem_ctl_info *mci);
 };
 
 /* Private structure for common edac device */
 struct cpc925_dev_info {
+	int op_state;
 	void __iomem *vbase;
 	struct platform_device *pdev;
 	char *ctl_name;
 	int edac_idx;
 	struct edac_device_ctl_info *edac_dev;
+	int irq;
 	void (*init)(struct cpc925_dev_info *dev_info);
 	void (*exit)(struct cpc925_dev_info *dev_info);
 	void (*check)(struct edac_device_ctl_info *edac_dev);
+	int (*mce)(struct edac_device_ctl_info *edac_dev);
+	irqreturn_t (*isr)(int irq, void *dev_id);
 };
 
 /* Get total memory size from Open Firmware DTB */
@@ -382,6 +391,18 @@ static void cpc925_init_csrows(struct mem_ctl_info *mci)
 	}
 }
 
+/* Set up HID0_EMCP bit if necessary, MSR[ME] has been set up */
+static void cpc925_mce_enable(void)
+{
+	unsigned long hid0 = mfspr(SPRN_HID0);
+
+	if ((hid0 & HID0_EMCP) == 0)
+		mtspr(SPRN_HID0, hid0 | HID0_EMCP);
+
+	debugf0("%s: MSR[ME] = %d, HID0[EMCP] = %d\n", __func__,
+		mfmsr() & MSR_ME, mfspr(SPRN_HID0));
+}
+
 /* Enable memory controller ECC detection */
 static void cpc925_mc_init(struct mem_ctl_info *mci)
 {
@@ -402,6 +423,9 @@ static void cpc925_mc_init(struct mem_ctl_info *mci)
 		mccr |= MCCR_ECC_EN;
 		__raw_writel(mccr, pdata->vbase + REG_MCCR_OFFSET);
 	}
+
+	if (pdata->op_state == EDAC_OPSTATE_MCE)
+		cpc925_mce_enable();
 }
 
 /* Disable memory controller ECC detection */
@@ -520,7 +544,10 @@ static int cpc925_mc_find_channel(struct mem_ctl_info *mci, u16 syndrome)
 	return 1;
 }
 
-/* Check memory controller registers for ECC errors */
+/*
+ * Check memory controller registers for ECC errors,
+ * called when EDAC MC works in POLL mode.
+ */
 static void cpc925_mc_check(struct mem_ctl_info *mci)
 {
 	struct cpc925_mc_pdata *pdata = mci->pvt_info;
@@ -579,6 +606,70 @@ static void cpc925_mc_check(struct mem_ctl_info *mci)
 		syndrome);
 }
 
+/*
+ * Check memory controller registers for ECC errors,
+ * called when EDAC MC works in MCE mode.
+ */
+static int cpc925_mc_mce(struct mem_ctl_info *mci)
+{
+	struct cpc925_mc_pdata *pdata = mci->pvt_info;
+	u32 apiexcp;
+	u32 mear;
+	u32 mesr;
+	u16 syndrome;
+	unsigned long pfn = 0, offset = 0;
+	int csrow = 0, channel = 0;
+
+	/* APIEXCP is cleared when read */
+	apiexcp = __raw_readl(pdata->vbase + REG_APIEXCP_OFFSET);
+	if ((apiexcp & ECC_EXCP_DETECTED) == 0)
+		return 0;
+
+	mesr = __raw_readl(pdata->vbase + REG_MESR_OFFSET);
+	syndrome = mesr | (MESR_ECC_SYN_H_MASK | MESR_ECC_SYN_L_MASK);
+
+	mear = __raw_readl(pdata->vbase + REG_MEAR_OFFSET);
+
+	/* Revert column/row addresses into page frame number, etc */
+	cpc925_mc_get_pfn(mci, mear, &pfn, &offset, &csrow);
+
+	if (apiexcp & CECC_EXCP_DETECTED) {
+		cpc925_mc_printk(mci, KERN_EMERG, "DRAM CECC Fault\n");
+		channel = cpc925_mc_find_channel(mci, syndrome);
+		edac_mc_handle_ce(mci, pfn, offset, syndrome,
+				  csrow, channel, mci->ctl_name);
+	}
+
+	if (apiexcp & UECC_EXCP_DETECTED) {
+		cpc925_mc_printk(mci, KERN_EMERG, "DRAM UECC Fault\n");
+		edac_mc_handle_ue(mci, pfn, offset, csrow, mci->ctl_name);
+	}
+
+	cpc925_mc_printk(mci, KERN_EMERG, "Dump registers:\n");
+	cpc925_mc_printk(mci, KERN_EMERG, "APIMASK               0x%08x\n",
+		__raw_readl(pdata->vbase + REG_APIMASK_OFFSET));
+	cpc925_mc_printk(mci, KERN_EMERG, "APIEXCP               0x%08x\n",
+		apiexcp);
+	cpc925_mc_printk(mci, KERN_EMERG, "Mem Scrub Ctrl        0x%08x\n",
+		__raw_readl(pdata->vbase + REG_MSCR_OFFSET));
+	cpc925_mc_printk(mci, KERN_EMERG, "Mem Scrub Rge Start   0x%08x\n",
+		__raw_readl(pdata->vbase + REG_MSRSR_OFFSET));
+	cpc925_mc_printk(mci, KERN_EMERG, "Mem Scrub Rge End     0x%08x\n",
+		__raw_readl(pdata->vbase + REG_MSRER_OFFSET));
+	cpc925_mc_printk(mci, KERN_EMERG, "Mem Scrub Pattern     0x%08x\n",
+		__raw_readl(pdata->vbase + REG_MSPR_OFFSET));
+	cpc925_mc_printk(mci, KERN_EMERG, "Mem Chk Ctrl          0x%08x\n",
+		__raw_readl(pdata->vbase + REG_MCCR_OFFSET));
+	cpc925_mc_printk(mci, KERN_EMERG, "Mem Chk Rge End       0x%08x\n",
+		__raw_readl(pdata->vbase + REG_MCRER_OFFSET));
+	cpc925_mc_printk(mci, KERN_EMERG, "Mem Err Address       0x%08x\n",
+		mesr);
+	cpc925_mc_printk(mci, KERN_EMERG, "Mem Err Syndrome      0x%08x\n",
+		syndrome);
+
+	return 1;
+}
+
 /******************** CPU err device********************************/
 /* Enable CPU Errors detection */
 static void cpc925_cpu_init(struct cpc925_dev_info *dev_info)
@@ -609,7 +700,7 @@ static void cpc925_cpu_exit(struct cpc925_dev_info *dev_info)
 	return;
 }
 
-/* Check for CPU Errors */
+/* Check for CPU Errors, called in POLL mode */
 static void cpc925_cpu_check(struct edac_device_ctl_info *edac_dev)
 {
 	struct cpc925_dev_info *dev_info = edac_dev->pvt_info;
@@ -630,6 +721,28 @@ static void cpc925_cpu_check(struct edac_device_ctl_info *edac_dev)
 	edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
 }
 
+/* Check for CPU Errors, called in MCE mode */
+static int cpc925_cpu_mce(struct edac_device_ctl_info *edac_dev)
+{
+	struct cpc925_dev_info *dev_info = edac_dev->pvt_info;
+	u32 apiexcp;
+	u32 apimask;
+
+	/* APIEXCP is cleared when read */
+	apiexcp = __raw_readl(dev_info->vbase + REG_APIEXCP_OFFSET);
+	if ((apiexcp & CPU_EXCP_DETECTED) == 0)
+		return 0;
+
+	apimask = __raw_readl(dev_info->vbase + REG_APIMASK_OFFSET);
+	cpc925_printk(KERN_EMERG, "Processor Interface Fault\n"
+				  "Processor Interface register dump:\n");
+	cpc925_printk(KERN_EMERG, "APIMASK               0x%08x\n", apimask);
+	cpc925_printk(KERN_EMERG, "APIEXCP               0x%08x\n", apiexcp);
+
+	edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
+	return 1;
+}
+
 /******************** HT Link err device****************************/
 /* Enable HyperTransport Link Error detection */
 static void cpc925_htlink_init(struct cpc925_dev_info *dev_info)
@@ -704,23 +817,105 @@ static void cpc925_htlink_check(struct edac_device_ctl_info *edac_dev)
 	edac_device_handle_ce(edac_dev, 0, 0, edac_dev->ctl_name);
 }
 
+static irqreturn_t cpc925_htlink_isr(int irq, void *dev_id)
+{
+	struct edac_device_ctl_info *edac_dev = dev_id;
+	struct cpc925_dev_info *dev_info = edac_dev->pvt_info;
+	u32 brgctrl = __raw_readl(dev_info->vbase + REG_BRGCTRL_OFFSET);
+	u32 linkctrl = __raw_readl(dev_info->vbase + REG_LINKCTRL_OFFSET);
+	u32 errctrl = __raw_readl(dev_info->vbase + REG_ERRCTRL_OFFSET);
+	u32 linkerr = __raw_readl(dev_info->vbase + REG_LINKERR_OFFSET);
+
+	if (!((brgctrl & BRGCTRL_DETSERR) ||
+	      (linkctrl & HT_LINKCTRL_DETECTED) ||
+	      (errctrl & HT_ERRCTRL_DETECTED) ||
+	      (linkerr & HT_LINKERR_DETECTED)))
+		return IRQ_NONE;
+
+	cpc925_htlink_check(edac_dev);
+
+	return IRQ_HANDLED;
+}
+
+/* Private structure for EDAC Memory Controller */
+static struct cpc925_mc_pdata cpc925_mc_private = {
+	/* EDAC MC supports POLL and MCE mode */
+	.op_state = EDAC_OPSTATE_MCE,
+	.mce = cpc925_mc_mce,
+	.mci = NULL,
+};
+
+/*
+ * Private strucutures for common EDAC devices for CPU Error
+ * and Hypertransport Link Error
+ */
 static struct cpc925_dev_info cpc925_devs[] = {
 	{
+	/* CPU Error supports POLL and MCE mode */
+	.op_state = EDAC_OPSTATE_MCE,
 	.ctl_name = CPC925_CPU_ERR_DEV,
 	.init = cpc925_cpu_init,
 	.exit = cpc925_cpu_exit,
 	.check = cpc925_cpu_check,
+	.mce = cpc925_cpu_mce,
 	},
 	{
+	/* Hypertransport Link Error supports POLL and INT mode */
+	.op_state = EDAC_OPSTATE_INT,
 	.ctl_name = CPC925_HT_LINK_DEV,
 	.init = cpc925_htlink_init,
 	.exit = cpc925_htlink_exit,
 	.check = cpc925_htlink_check,
+	.irq = NO_IRQ,
+	.isr = cpc925_htlink_isr,
 	},
 	{0}, /* Terminated by NULL */
 };
 
 /*
+ * MCE handler for EDAC CPC925 driver, check memory controller and
+ * Hypertransport hostbridge to claim any possbile MCE instance.
+ */
+static int cpc925_mce_handler(void)
+{
+	struct cpc925_mc_pdata *pdata = &cpc925_mc_private;
+	struct cpc925_dev_info *dev_info;
+	int ret = 0;
+
+	if (pdata->op_state == EDAC_OPSTATE_MCE)
+		if (pdata->mce)
+			ret |= pdata->mce(pdata->mci);
+
+	for (dev_info = &cpc925_devs[0]; dev_info->init; dev_info++) {
+		if (dev_info->op_state == EDAC_OPSTATE_MCE)
+			if (dev_info->mce)
+				ret |= dev_info->mce(dev_info->edac_dev);
+	}
+
+	return ret;
+}
+
+/* Hook CPC925 MCE handler to PowerPC generic MCE handler */
+static void cpc925_mce_handler_setup(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&edac_mce_lock, flags);
+	edac_mce_handler = cpc925_mce_handler;
+	spin_unlock_irqrestore(&edac_mce_lock, flags);
+}
+
+static void cpc925_mce_handler_exit(void)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&edac_mce_lock, flags);
+	if (edac_mce_handler)
+		edac_mce_handler = NULL;
+	spin_unlock_irqrestore(&edac_mce_lock, flags);
+}
+
+/*
  * Add CPU Err detection and HyperTransport Link Err detection
  * as common "edac_device", they have no corresponding device
  * nodes in the Open Firmware DTB and we have to add platform
@@ -730,6 +925,7 @@ static struct cpc925_dev_info cpc925_devs[] = {
 static void cpc925_add_edac_devices(void __iomem *vbase)
 {
 	struct cpc925_dev_info *dev_info;
+	int ret = 0;
 
 	if (!vbase) {
 		cpc925_printk(KERN_ERR, "MMIO not established yet\n");
@@ -766,8 +962,36 @@ static void cpc925_add_edac_devices(void __iomem *vbase)
 		dev_info->edac_dev->mod_name = CPC925_EDAC_MOD_STR;
 		dev_info->edac_dev->dev_name = dev_name(&dev_info->pdev->dev);
 
-		if (edac_op_state == EDAC_OPSTATE_POLL)
+		if (dev_info->op_state == EDAC_OPSTATE_POLL)
 			dev_info->edac_dev->edac_check = dev_info->check;
+		else if (dev_info->irq == EDAC_OPSTATE_MCE) {
+			/*
+			 * do nothing, MCE handler has been registered
+			 * by memory controller.
+			 */
+		} else if (dev_info->op_state == EDAC_OPSTATE_INT) {
+			dev_info->irq =
+				edac_get_mpic_irq(MPIC_HWIRQ_INTERNAL_ERROR);
+			if (dev_info->irq == NO_IRQ) {
+				cpc925_printk(KERN_ERR,	"%s: failed to get "
+					"virq for %s\n", __func__,
+					dev_info->ctl_name);
+				goto err2;
+			}
+
+			ret = request_irq(dev_info->irq, dev_info->isr,
+					IRQF_SHARED, "[EDAC] CPC925 ",
+					dev_info->edac_dev);
+			if (ret < 0) {
+				cpc925_printk(KERN_INFO, "%s: failed to "
+					"request irq %d for %s\n", __func__,
+					dev_info->irq, dev_info->ctl_name);
+				goto err3;
+			}
+
+			debugf0("%s: Successfully requested irq %d for %s\n",
+				 __func__, dev_info->irq, dev_info->ctl_name);
+		}
 
 		if (dev_info->init)
 			dev_info->init(dev_info);
@@ -776,7 +1000,7 @@ static void cpc925_add_edac_devices(void __iomem *vbase)
 			cpc925_printk(KERN_ERR,
 				"Unable to add edac device for %s\n",
 				dev_info->ctl_name);
-			goto err2;
+			goto err4;
 		}
 
 		debugf0("%s: Successfully added edac device for %s\n",
@@ -784,9 +1008,16 @@ static void cpc925_add_edac_devices(void __iomem *vbase)
 
 		continue;
 
-err2:
+err4:
 		if (dev_info->exit)
 			dev_info->exit(dev_info);
+
+		if (dev_info->op_state == EDAC_OPSTATE_INT)
+			free_irq(dev_info->irq, dev_info->edac_dev);
+err3:
+		if (dev_info->op_state == EDAC_OPSTATE_INT)
+			edac_put_mpic_irq(MPIC_HWIRQ_INTERNAL_ERROR);
+err2:
 		edac_device_free_ctl_info(dev_info->edac_dev);
 err1:
 		platform_device_unregister(dev_info->pdev);
@@ -802,15 +1033,19 @@ static void cpc925_del_edac_devices(void)
 	struct cpc925_dev_info *dev_info;
 
 	for (dev_info = &cpc925_devs[0]; dev_info->init; dev_info++) {
+		if (dev_info->exit)
+			dev_info->exit(dev_info);
+
 		if (dev_info->edac_dev) {
+			if (dev_info->op_state == EDAC_OPSTATE_INT) {
+				free_irq(dev_info->irq, dev_info->edac_dev);
+				edac_put_mpic_irq(MPIC_HWIRQ_INTERNAL_ERROR);
+			}
 			edac_device_del_device(dev_info->edac_dev->dev);
 			edac_device_free_ctl_info(dev_info->edac_dev);
 			platform_device_unregister(dev_info->pdev);
 		}
 
-		if (dev_info->exit)
-			dev_info->exit(dev_info);
-
 		debugf0("%s: Successfully deleted edac device for %s\n",
 			__func__, dev_info->ctl_name);
 	}
@@ -900,18 +1135,18 @@ static int __devinit cpc925_probe(struct platform_device *pdev)
 	}
 
 	nr_channels = cpc925_mc_get_channels(vbase);
-	mci = edac_mc_alloc(sizeof(struct cpc925_mc_pdata),
-			CPC925_NR_CSROWS, nr_channels + 1, edac_mc_idx);
+	mci = edac_mc_alloc(0, CPC925_NR_CSROWS, nr_channels + 1, edac_mc_idx);
 	if (!mci) {
 		cpc925_printk(KERN_ERR, "No memory for mem_ctl_info\n");
 		res = -ENOMEM;
 		goto err2;
 	}
 
-	pdata = mci->pvt_info;
+	pdata = mci->pvt_info = &cpc925_mc_private;
 	pdata->vbase = vbase;
 	pdata->edac_idx = edac_mc_idx++;
 	pdata->name = pdev->name;
+	pdata->mci = mci;
 
 	mci->dev = &pdev->dev;
 	platform_set_drvdata(pdev, mci);
@@ -922,15 +1157,16 @@ static int __devinit cpc925_probe(struct platform_device *pdev)
 	mci->mod_name = CPC925_EDAC_MOD_STR;
 	mci->mod_ver = CPC925_EDAC_REVISION;
 	mci->ctl_name = pdev->name;
-
-	if (edac_op_state == EDAC_OPSTATE_POLL)
-		mci->edac_check = cpc925_mc_check;
-
 	mci->ctl_page_to_phys = NULL;
 	mci->scrub_mode = SCRUB_SW_SRC;
 	mci->set_sdram_scrub_rate = NULL;
 	mci->get_sdram_scrub_rate = cpc925_get_sdram_scrub_rate;
 
+	if (pdata->op_state == EDAC_OPSTATE_POLL)
+		mci->edac_check = cpc925_mc_check;
+	else if (pdata->op_state == EDAC_OPSTATE_MCE)
+		cpc925_mce_handler_setup();
+
 	cpc925_init_csrows(mci);
 
 	/* Setup memory controller registers */
@@ -951,6 +1187,10 @@ static int __devinit cpc925_probe(struct platform_device *pdev)
 
 err3:
 	cpc925_mc_exit(mci);
+
+	if (pdata->op_state == EDAC_OPSTATE_MCE)
+		cpc925_mce_handler_exit();
+
 	edac_mc_free(mci);
 err2:
 	devm_release_mem_region(&pdev->dev, r->start, r->end-r->start+1);
@@ -963,14 +1203,19 @@ out:
 static int cpc925_remove(struct platform_device *pdev)
 {
 	struct mem_ctl_info *mci = platform_get_drvdata(pdev);
+	struct cpc925_mc_pdata *pdata = mci->pvt_info;
 
 	/*
 	 * Delete common edac devices before edac mc, because
 	 * the former share the MMIO of the latter.
 	 */
 	cpc925_del_edac_devices();
+
 	cpc925_mc_exit(mci);
 
+	if (pdata->op_state == EDAC_OPSTATE_MCE)
+		cpc925_mce_handler_exit();
+
 	edac_mc_del_mc(&pdev->dev);
 	edac_mc_free(mci);
 
@@ -981,7 +1226,7 @@ static struct platform_driver cpc925_edac_driver = {
 	.probe = cpc925_probe,
 	.remove = cpc925_remove,
 	.driver = {
-		   .name = "cpc925_edac",
+		.name = "cpc925_edac",
 	}
 };
 
@@ -992,9 +1237,6 @@ static int __init cpc925_edac_init(void)
 	printk(KERN_INFO "IBM CPC925 EDAC driver " CPC925_EDAC_REVISION "\n");
 	printk(KERN_INFO "\t(c) 2008 Wind River Systems, Inc\n");
 
-	/* Only support POLL mode so far */
-	edac_op_state = EDAC_OPSTATE_POLL;
-
 	ret = platform_driver_register(&cpc925_edac_driver);
 	if (ret) {
 		printk(KERN_WARNING "Failed to register %s\n",
diff --git a/drivers/edac/edac_stub.c b/drivers/edac/edac_stub.c
index 20b428a..d2814d0 100644
--- a/drivers/edac/edac_stub.c
+++ b/drivers/edac/edac_stub.c
@@ -44,3 +44,9 @@ void edac_atomic_assert_error(void)
 	edac_err_assert++;
 }
 EXPORT_SYMBOL_GPL(edac_atomic_assert_error);
+
+int (*edac_mce_handler)(void) = NULL;
+EXPORT_SYMBOL_GPL(edac_mce_handler);
+
+DEFINE_SPINLOCK(edac_mce_lock);
+EXPORT_SYMBOL_GPL(edac_mce_lock);
diff --git a/include/linux/edac.h b/include/linux/edac.h
index 804dbb6..c17fec5 100644
--- a/include/linux/edac.h
+++ b/include/linux/edac.h
@@ -12,12 +12,14 @@
 #ifndef _LINUX_EDAC_H_
 #define _LINUX_EDAC_H_
 
+#include <linux/spinlock.h>
 #include <asm/atomic.h>
 
 #define EDAC_OPSTATE_INVAL	-1
 #define EDAC_OPSTATE_POLL	0
 #define EDAC_OPSTATE_NMI	1
 #define EDAC_OPSTATE_INT	2
+#define EDAC_OPSTATE_MCE	3
 
 extern int edac_op_state;
 extern int edac_err_assert;
@@ -26,11 +28,15 @@ extern atomic_t edac_handlers;
 extern int edac_handler_set(void);
 extern void edac_atomic_assert_error(void);
 
+extern int (*edac_mce_handler)(void);
+extern spinlock_t edac_mce_lock;
+
 static inline void opstate_init(void)
 {
 	switch (edac_op_state) {
 	case EDAC_OPSTATE_POLL:
 	case EDAC_OPSTATE_NMI:
+	case EDAC_OPSTATE_MCE:
 		break;
 	default:
 		edac_op_state = EDAC_OPSTATE_POLL;

^ permalink raw reply related

* [v0 PATCH 0/4] Add INT mode support for EDAC drivers on Maple
From: Harry Ciao @ 2009-05-15  8:43 UTC (permalink / raw)
  To: bluesmoke-devel; +Cc: linuxppc-dev, linux-kernel


Comments:		
---------

What to be added
-----------------

1, Support EDAC INT mode on Maple platform, where CPC925 Hypertransport
hostbridge controller will latch MPIC INT0 pin on receiving upstream
NMI request messages with vector == 0 that posted from Hypertransport
southbridges such as AMD8131 & AMD8111 chips.

Since multiple southbridges could post NMI request messages, EDAC core
should be responsible for maintaining the mapping from hwirq == 0 to
the related virq, that's what edac_mpic_irq.c is for - on the very first
call to edac_get_mpic_irq() related mapping will be created, and the
same virq will be returned to caller on successive calls with its
reference count increased. On EDAC driver module removal the reference
count will be decreased by edac_put_mpic_irq() accordingly, and the 
mapping will be disposed if it reaches zero. 

edac_mpic_irq.c and its exported APIs will be controlled by CONFIG_MPIC
since it will be inert for EDAC drivers where related hardware doesn't
support MPIC.

Now AMD8111 & AMD8131 EDAC drivers could register their error handlers
to the virtual IRQ that maps to hardware IRQ == 0. If they ever adopted
on a new machine other than Maple or where MPIC is not supported, their
new EDAC driver should implement a machine-specific method to get a IRQ
from their NMI request messages.

2, Add a new EDAC MCE mode for CPC925 EDAC driver. CPC925 Hypertransport
hostbridge controller may generate MCE on memory ECC Errors and Processor
Interface Errors, their EDAC handlers could be hooked into the generic MCE
handler in MCE mode.


Known limitations
------------------
I once tried to trigger memory ECC errors by trying to mask two DIMM data
pins in the way described by the first test method on EDAC twiki page(
http://bluesmoke.sourceforge.net/testing.html), but only resulted in Maple's
FRU date being destroyed and only after reflashing FRU data could Maple
boot up normally when inserted back to chassis. Since Maple is locked in
the chassis the second approach of heat-lamp won't be applicable either.

As for the MCE/INT mode support for CPC925 EDAC driver, following aspects
have been tested:
1, module initialization and deletion in MCE/INT mode;
2, creation and deletion for the mapping between hwirq==2 to a virq
   for the Hypertransport Link Errors;
3, registration and unregistration for the EDAC MCE handler from the
   generic MCE handler on PPC;

Due to the difficulty and complexity to generate a real hardware
ECC/HT Link/CPU Errors, below aspects have not been tested yet:
1, if ECC or CPU Errors would generate MCE event;
2, if HT Link Error will indeed latch MPIC INT2 pin;
3, if EDAC isr/mce methods could handle errors correctly.

As for the INT mode support for AMD8111 & AMD87131 EDAC driver,
below aspects have not been tested yet:
1, code that controls the generation of the NMI Request Message;
2, the mapping from the NMI Request Messages to MPIC INT0 pin;
3, if EDAC isr methods could handle errors correctly.

I think I am at the point where I'd like to seek comments and ideas
from others about how to resolve above test issues, hope someone knows
a proper method or has an instrument to generate real hardware errors.

Any comments are welcomed!


Test steps:
-----------
CONFIG_EDAC=y
CONFIG_EDAC_MM_EDAC=m
CONFIG_EDAC_AMD8111=m
CONFIG_EDAC_AMD8131=m
CONFIG_EDAC_CPC925=m

insmod edac_core.ko
insmod cpc925_edac.ko
insmod amd8111_edac.ko amd8111_op_state=1
insmod amd8131_edac.ko amd8131_op_state=1
cat /proc/interrupts

cd /sys/devices/system/edac/
cat cpu/poll_msec
cat htlink/poll_msec
cat lpc/poll_msec

rmmod cpc925_edac
rmmod amd8111_edac
rmmod amd8131_edac

insmod amd8111_edac.ko amd8111_op_state=1
insmod amd8131_edac.ko amd8131_op_state=1
insmod cpc925_edac.ko
cat /proc/interrupts

rmmod cpc925_edac
rmmod amd8111_edac
rmmod amd8131_edac
cat /proc/interrupts

insmod amd8131_edac.ko
insmod amd8111_edac.ko
cat /proc/interrupts
cd /sys/devices/system/edac/
cat lpc/poll_msec

rmmod amd8111_edac
rmmod amd8131_edac
rmmod edac_core

Test results:
-------------

root@localhost:/root> cd /int
root@localhost:/int> dmesg -n 8
root@localhost:/int> lsmod
Module                  Size  Used by
root@localhost:/int> insmod edac_core.ko 
EDAC MC: Ver: 2.1.0 May 12 2009
insmod used greatest stack depth: 4880 bytes left
root@localhost:/int> insmod amd8111_edac.ko amd8111_op_state=1
AMD8111 EDAC driver  Ver: 1.0.0 May 12 2009
	(c) 2008 Wind River Systems, Inc.
amd8111_lpc_bridge_init: port 97 is buggy, not supported by hardware?
amd8111_NMI_global_enable: PM48[NMI2SMI_EN] is cleared
EDAC DEVICE0: Giving out device to module 'amd8111_edac' controller 'lpc': DEV '0000:00:06.0' (INTERRUPT)
added one device on AMD8111 vendor 1022, device 7468, name lpc
EDAC PCI0: Giving out device to module 'amd8111_edac' controller 'AMD8111_PCI_Controller': DEV '0000:00:05.0' (INTERRUPT)
added one device on AMD8111 vendor 1022, device 7460, name AMD8111_PCI_Controller
irq: irq 0 on host /hostbridge@0/interrupt-controller@f8040000 mapped to virtual irq 18
root@localhost:/int> cat /proc/interrupts 
           CPU0       CPU1       
 16:        120        300   MPIC      Edge      serial
 18:          0          0   MPIC      Edge      [EDAC] AMD8111
 22:       6020      23894   MPIC      Level     eth6
 25:          0          0   MPIC      Level     ohci_hcd:usb1, ohci_hcd:usb2
251:          0          0   MPIC      Edge      ipi call function
252:       2912       2595   MPIC      Edge      ipi reschedule
253:          0          0   MPIC      Edge      ipi call function single
254:          0          0   MPIC      Edge      ipi debugger
BAD:          0
root@localhost:/int> insmod amd8131_edac.ko amd8131_op_state=1
AMD8131 EDAC driver  Ver: 1.0.0 May 12 2009
	(c) 2008 Wind River Systems, Inc.
EDAC PCI1: Giving out device to module 'amd8131_edac' controller 'AMD8131_PCIX_NORTH_A': DEV '0000:00:01.0' (INTERRUPT)
added one device on AMD8131 vendor 1022, device 7451, devfn 8, name AMD8131_PCIX_NORTH_A
EDAC PCI2: Giving out device to module 'amd8131_edac' controller 'AMD8131_PCIX_NORTH_B': DEV '0000:00:02.0' (INTERRUPT)
added one device on AMD8131 vendor 1022, device 7451, devfn 10, name AMD8131_PCIX_NORTH_B
EDAC PCI3: Giving out device to module 'amd8131_edac' controller 'AMD8131_PCIX_SOUTH_A': DEV '0000:00:03.0' (INTERRUPT)
added one device on AMD8131 vendor 1022, device 7451, devfn 18, name AMD8131_PCIX_SOUTH_A
EDAC PCI4: Giving out device to module 'amd8131_edac' controller 'AMD8131_PCIX_SOUTH_B': DEV '0000:00:04.0' (INTERRUPT)
added one device on AMD8131 vendor 1022, device 7451, devfn 20, name AMD8131_PCIX_SOUTH_B
root@localhost:/int> cat /proc/interrupts 
           CPU0       CPU1       
 16:        141        420   MPIC      Edge      serial
 18:          0          0   MPIC      Edge      [EDAC] AMD8111, [EDAC] AMD8131
 22:       6031      23955   MPIC      Level     eth6
 25:          0          0   MPIC      Level     ohci_hcd:usb1, ohci_hcd:usb2
251:          0          0   MPIC      Edge      ipi call function
252:       2931       2608   MPIC      Edge      ipi reschedule
253:          0          0   MPIC      Edge      ipi call function single
254:          0          0   MPIC      Edge      ipi debugger
BAD:          0
root@localhost:/int> insmod cpc925_edac.ko 
IBM CPC925 EDAC driver  Ver: 1.0.0 May 12 2009
	(c) 2008 Wind River Systems, Inc
EDAC MC0: Giving out device to 'cpc925_edac' 'cpc925_edac': DEV cpc925_edac.0
EDAC DEVICE1: Giving out device to module 'cpc925_edac' controller 'cpu': DEV 'cpu.0' (INTERRUPT)
irq: irq 2 on host /hostbridge@0/interrupt-controller@f8040000 mapped to virtual irq 19
EDAC DEVICE2: Giving out device to module 'cpc925_edac' controller 'htlink': DEV 'htlink.0' (INTERRUPT)
root@localhost:/int> cat /proc/interrupts 
           CPU0       CPU1       
 16:        172        464   MPIC      Edge      serial
 18:          0          0   MPIC      Edge      [EDAC] AMD8111, [EDAC] AMD8131
 19:          0          0   MPIC      Edge      [EDAC] CPC925 
 22:       6186      24557   MPIC      Level     eth6
 25:          0          0   MPIC      Level     ohci_hcd:usb1, ohci_hcd:usb2
251:          0          0   MPIC      Edge      ipi call function
252:       2971       2632   MPIC      Edge      ipi reschedule
253:          0          0   MPIC      Edge      ipi call function single
254:          0          0   MPIC      Edge      ipi debugger
BAD:          0
root@localhost:/int> cd /sys/devices/system/edac/
root@localhost:/sys/devices/system/edac> ls -lt
total 0
drwxr-xr-x 3 root root 0 Jan  1 05:46 cpu
drwxr-xr-x 3 root root 0 Jan  1 05:46 htlink
drwxr-xr-x 3 root root 0 Jan  1 05:46 lpc
drwxr-xr-x 3 root root 0 Jan  1 05:46 mc
drwxr-xr-x 7 root root 0 Jan  1 05:46 pci
root@localhost:/sys/devices/system/edac> cat cpu/poll_msec 
0
root@localhost:/sys/devices/system/edac> cat htlink/poll_msec 
0
root@localhost:/sys/devices/system/edac> cat lpc/poll_msec 
0
root@localhost:/sys/devices/system/edac> ls -lt mc/mc0
total 0
-r--r--r-- 1 root root 4096 Jan  1 05:46 ce_count
-r--r--r-- 1 root root 4096 Jan  1 05:46 ce_noinfo_count
drwxr-xr-x 2 root root    0 Jan  1 05:46 csrow0
drwxr-xr-x 2 root root    0 Jan  1 05:46 csrow4
lrwxrwxrwx 1 root root    0 Jan  1 05:46 device -> ../../../../platform/cpc925_edac.0
-r--r--r-- 1 root root 4096 Jan  1 05:46 mc_name
--w------- 1 root root 4096 Jan  1 05:46 reset_counters
-rw-r--r-- 1 root root 4096 Jan  1 05:46 sdram_scrub_rate
-r--r--r-- 1 root root 4096 Jan  1 05:46 seconds_since_reset
-r--r--r-- 1 root root 4096 Jan  1 05:46 size_mb
-r--r--r-- 1 root root 4096 Jan  1 05:46 ue_count
-r--r--r-- 1 root root 4096 Jan  1 05:46 ue_noinfo_count
root@localhost:/sys/devices/system/edac> ls -lt pci   
total 0
-rw-r--r-- 1 root root 4096 Jan  1 05:46 check_pci_errors
-rw-r--r-- 1 root root 4096 Jan  1 05:46 edac_pci_log_npe
-rw-r--r-- 1 root root 4096 Jan  1 05:46 edac_pci_log_pe
-rw-r--r-- 1 root root 4096 Jan  1 05:46 edac_pci_panic_on_pe
drwxr-xr-x 2 root root    0 Jan  1 05:46 pci0
drwxr-xr-x 2 root root    0 Jan  1 05:46 pci1
drwxr-xr-x 2 root root    0 Jan  1 05:46 pci2
drwxr-xr-x 2 root root    0 Jan  1 05:46 pci3
drwxr-xr-x 2 root root    0 Jan  1 05:46 pci4
-r--r--r-- 1 root root 4096 Jan  1 05:46 pci_nonparity_count
-r--r--r-- 1 root root 4096 Jan  1 05:46 pci_parity_count
root@localhost:/sys/devices/system/edac> cd /int
root@localhost:/int> rmmod amd8111_edac.ko 
EDAC PCI: Removed device 0 for amd8111_edac AMD8111_PCI_Controller: DEV 0000:00:05.0
EDAC MC: Removed device 0 for amd8111_edac lpc: DEV 0000:00:06.0
root@localhost:/int> cat /proc/interrupts 
           CPU0       CPU1       
 16:        278        792   MPIC      Edge      serial
 18:          0          0   MPIC      Edge      [EDAC] AMD8131
 19:          0          0   MPIC      Edge      [EDAC] CPC925 
 22:       6484      25426   MPIC      Level     eth6
 25:          0          0   MPIC      Level     ohci_hcd:usb1, ohci_hcd:usb2
251:          0          0   MPIC      Edge      ipi call function
252:       3047       2707   MPIC      Edge      ipi reschedule
253:          0          0   MPIC      Edge      ipi call function single
254:          0          0   MPIC      Edge      ipi debugger
BAD:          0
root@localhost:/int> rmmod amd8131_edac.ko 
EDAC PCI: Removed device 4 for amd8131_edac AMD8131_PCIX_SOUTH_B: DEV 0000:00:04.0
EDAC PCI: Removed device 3 for amd8131_edac AMD8131_PCIX_SOUTH_A: DEV 0000:00:03.0
EDAC PCI: Removed device 2 for amd8131_edac AMD8131_PCIX_NORTH_B: DEV 0000:00:02.0
EDAC PCI: Removed device 1 for amd8131_edac AMD8131_PCIX_NORTH_A: DEV 0000:00:01.0
root@localhost:/int> rmmod cpc925_edac.ko 
EDAC MC: Removed device 1 for cpc925_edac cpu: DEV cpu.0
EDAC MC: Removed device 2 for cpc925_edac htlink: DEV htlink.0
EDAC MC: Removed device 0 for cpc925_edac cpc925_edac: DEV cpc925_edac.0
root@localhost:/int> cat /proc/interrupts 
           CPU0       CPU1       
 16:        305        890   MPIC      Edge      serial
 22:       6659      25995   MPIC      Level     eth6
 25:          0          0   MPIC      Level     ohci_hcd:usb1, ohci_hcd:usb2
251:          0          0   MPIC      Edge      ipi call function
252:       3107       2766   MPIC      Edge      ipi reschedule
253:          0          0   MPIC      Edge      ipi call function single
254:          0          0   MPIC      Edge      ipi debugger
BAD:          0
root@localhost:/int> ls -lt /sys/devices/system/edac/
total 0
drwxr-xr-x 2 root root 0 Jan  1 05:46 mc
root@localhost:/int> dmesg -n 4
root@localhost:/int> insmod cpc925_edac.ko 
root@localhost:/int> insmod amd8131_edac.ko amd8131_op_state=1
root@localhost:/int> insmod amd8111_edac.ko amd8111_op_state=1
root@localhost:/int> cat /proc/interrupts 
           CPU0       CPU1       
 16:        404       1163   MPIC      Edge      serial
 18:          0          0   MPIC      Edge      [EDAC] CPC925 
 19:          0          0   MPIC      Edge      [EDAC] AMD8131, [EDAC] AMD8111
 22:       6946      27069   MPIC      Level     eth6
 25:          0          0   MPIC      Level     ohci_hcd:usb1, ohci_hcd:usb2
251:          0          0   MPIC      Edge      ipi call function
252:       3244       2877   MPIC      Edge      ipi reschedule
253:          0          0   MPIC      Edge      ipi call function single
254:          0          0   MPIC      Edge      ipi debugger
BAD:          0
root@localhost:/int> rmmod amd8131_edac.ko 
root@localhost:/int> rmmod amd8111_edac.ko 
root@localhost:/int> rmmod cpc925_edac.ko 
root@localhost:/int> cat /proc/interrupts 
           CPU0       CPU1       
 16:        456       1268   MPIC      Edge      serial
 22:       7097      27525   MPIC      Level     eth6
 25:          0          0   MPIC      Level     ohci_hcd:usb1, ohci_hcd:usb2
251:          0          0   MPIC      Edge      ipi call function
252:       3318       2936   MPIC      Edge      ipi reschedule
253:          0          0   MPIC      Edge      ipi call function single
254:          0          0   MPIC      Edge      ipi debugger
BAD:          0
root@localhost:/int> dmesg -n 8
root@localhost:/int> insmod amd8131_edac.ko 
AMD8131 EDAC driver  Ver: 1.0.0 May 12 2009
	(c) 2008 Wind River Systems, Inc.
EDAC PCI10: Giving out device to module 'amd8131_edac' controller 'AMD8131_PCIX_NORTH_A': DEV '0000:00:01.0' (POLLED)
added one device on AMD8131 vendor 1022, device 7451, devfn 8, name AMD8131_PCIX_NORTH_A
EDAC PCI11: Giving out device to module 'amd8131_edac' controller 'AMD8131_PCIX_NORTH_B': DEV '0000:00:02.0' (POLLED)
added one device on AMD8131 vendor 1022, device 7451, devfn 10, name AMD8131_PCIX_NORTH_B
EDAC PCI12: Giving out device to module 'amd8131_edac' controller 'AMD8131_PCIX_SOUTH_A': DEV '0000:00:03.0' (POLLED)
added one device on AMD8131 vendor 1022, device 7451, devfn 18, name AMD8131_PCIX_SOUTH_A
EDAC PCI13: Giving out device to module 'amd8131_edac' controller 'AMD8131_PCIX_SOUTH_B': DEV '0000:00:04.0' (POLLED)
added one device on AMD8131 vendor 1022, device 7451, devfn 20, name AMD8131_PCIX_SOUTH_B
root@localhost:/int> insmod amd8111_edac.ko 
AMD8111 EDAC driver  Ver: 1.0.0 May 12 2009
	(c) 2008 Wind River Systems, Inc.
amd8111_lpc_bridge_init: port 97 is buggy, not supported by hardware?
EDAC DEVICE8: Giving out device to module 'amd8111_edac' controller 'lpc': DEV '0000:00:06.0' (POLLED)
added one device on AMD8111 vendor 1022, device 7468, name lpc
EDAC PCI14: Giving out device to module 'amd8111_edac' controller 'AMD8111_PCI_Controller': DEV '0000:00:05.0' (POLLED)
added one device on AMD8111 vendor 1022, device 7460, name AMD8111_PCI_Controller
root@localhost:/int> cat /proc/interrupts 
           CPU0       CPU1       
 16:        480       1393   MPIC      Edge      serial
 22:       7130      27610   MPIC      Level     eth6
 25:          0          0   MPIC      Level     ohci_hcd:usb1, ohci_hcd:usb2
251:          0          0   MPIC      Edge      ipi call function
252:       3346       2964   MPIC      Edge      ipi reschedule
253:          0          0   MPIC      Edge      ipi call function single
254:          0          0   MPIC      Edge      ipi debugger
BAD:          0
root@localhost:/int> cd /sys/devices/system/edac/
root@localhost:/sys/devices/system/edac> ls -lt
total 0
drwxr-xr-x 3 root root 0 Jan  1 05:48 lpc
drwxr-xr-x 7 root root 0 Jan  1 05:48 pci
drwxr-xr-x 2 root root 0 Jan  1 05:48 mc
root@localhost:/sys/devices/system/edac> cat lpc/poll_msec 
1000
root@localhost:/sys/devices/system/edac> ls -lt pci
total 0
-rw-r--r-- 1 root root 4096 Jan  1 05:48 check_pci_errors
-rw-r--r-- 1 root root 4096 Jan  1 05:48 edac_pci_log_npe
-rw-r--r-- 1 root root 4096 Jan  1 05:48 edac_pci_log_pe
-rw-r--r-- 1 root root 4096 Jan  1 05:48 edac_pci_panic_on_pe
drwxr-xr-x 2 root root    0 Jan  1 05:48 pci10
drwxr-xr-x 2 root root    0 Jan  1 05:48 pci11
drwxr-xr-x 2 root root    0 Jan  1 05:48 pci12
drwxr-xr-x 2 root root    0 Jan  1 05:48 pci13
drwxr-xr-x 2 root root    0 Jan  1 05:48 pci14
-r--r--r-- 1 root root 4096 Jan  1 05:48 pci_nonparity_count
-r--r--r-- 1 root root 4096 Jan  1 05:48 pci_parity_count
root@localhost:/sys/devices/system/edac> cd /int
root@localhost:/int> rmmod amd8111_edac.ko 
EDAC PCI: Removed device 14 for amd8111_edac AMD8111_PCI_Controller: DEV 0000:00:05.0
EDAC MC: Removed device 8 for amd8111_edac lpc: DEV 0000:00:06.0
root@localhost:/int> rmmod amd8131_edac.ko 
EDAC PCI: Removed device 13 for amd8131_edac AMD8131_PCIX_SOUTH_B: DEV 0000:00:04.0
EDAC PCI: Removed device 12 for amd8131_edac AMD8131_PCIX_SOUTH_A: DEV 0000:00:03.0
EDAC PCI: Removed device 11 for amd8131_edac AMD8131_PCIX_NORTH_B: DEV 0000:00:02.0
EDAC PCI: Removed device 10 for amd8131_edac AMD8131_PCIX_NORTH_A: DEV 0000:00:01.0
root@localhost:/int> rmmod edac_core.ko 
root@localhost:/int> lsmod
Module                  Size  Used by
root@localhost:/int> 


diffstat:
---------
0001-EDAC-MPIC-Hypertransport-IRQ-support.patch
 drivers/edac/Makefile        |    4 +
 drivers/edac/edac_mpic_irq.c |  145 +++++++++++++++++++++++++++++++++++++++++++
 include/linux/edac.h         |   23 ++++++
 3 files changed, 172 insertions(+)

0002-EDAC-MCE-INT-mode-support-for-CPC925-driver.patch
 arch/powerpc/kernel/traps.c |   16 ++
 drivers/edac/cpc925_edac.c  |  280 +++++++++++++++++++++++++++++++++++++++++---
 drivers/edac/edac_stub.c    |    6 
 include/linux/edac.h        |    6 
 4 files changed, 289 insertions(+), 19 deletions(-)

0003-EDAC-INT-mode-support-for-AMD8111-driver.patch
 amd8111_edac.c |  352 +++++++++++++++++++++++++++++++++++++++++++++++++--------
 amd8111_edac.h |   43 ++++++
 2 files changed, 347 insertions(+), 48 deletions(-)

0004-EDAC-INT-mode-support-for-AMD8131-driver.patch
 amd8131_edac.c |  173 +++++++++++++++++++++++++++++++++++++++++++++++++++------
 amd8131_edac.h |   20 ++++++
 2 files changed, 174 insertions(+), 19 deletions(-)

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox