LinuxPPC-Dev Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] [PowerPC] MPC8272ADS: fix device tree for 8 MB flash, size
From: Scott Wood @ 2009-05-14 21:48 UTC (permalink / raw)
  To: Heiko Schocher; +Cc: linuxppc-dev, Wolfgang Denk, linux-kernel
In-Reply-To: <4A0A683B.5010209@denx.de>

On Wed, May 13, 2009 at 08:27:07AM +0200, Heiko Schocher wrote:
> Hello Wolfgang,
> 
> > The current device tree for the MPC8272ADS assumes a mapping of 32 MB
> > of NOR flash at 0xFE00.0000, while there are actually only 8 MB on
> > the boards, mapped at 0xFF80.0000. When booting an uImage with such a
> > device tree, the kernel crashes because 0xFE00.0000 is not mapped.
> 
> Wouldn;t it be better, if u-boot fixes the device tree entries?

We should proabbly leave out the ranges altogether, and have u-boot
populate it from the mappings it establishes.

> I think, u-boot should know, where the flash begins and ends, and
> because this is maybe a dynamic variable for this board, it should
> be better, if u-boot fixes this, so no need for adding a device tree
> for every board variant.

Flash is on a SIMM on this board, and the board manual says it's
expandable to 32 MiB.  However, I suspect that the current DTS was just
an error as I based it on a board that had not had its flash SIMM
modified.  That specific flash SIMM is no longer working (or perhaps just
got its contents corrupted -- one of these days I may hook up a BDI and
try to reflash), so I can't go back and check.

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,
but I don't see any setting of BR0 besides the preliminary value at
0xff800000).

-Scott

^ permalink raw reply

* [PATCH V2 1/3] powerpc: Use sg->dma_length in sg_dma_len() macro on 32-bit
From: Becky Bruce @ 2009-05-14 22:42 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: fujita.tomonori

Currently, the 32-bit code uses sg->length instead of sg->dma_lentgh
to report sg_dma_len.  However, since the default dma code for 32-bit
(the dma_direct case) sets dma_length and length to the same thing,
we should be able to use dma_length there as well.  This gets rid of
some 32-vs-64-bit ifdefs, and is needed by the swiotlb code which
actually distinguishes between dma_length and length.

Signed-off-by: Becky Bruce <beckyb@kernel.crashing.org>
---
 arch/powerpc/include/asm/scatterlist.h |    6 +-----
 1 files changed, 1 insertions(+), 5 deletions(-)

diff --git a/arch/powerpc/include/asm/scatterlist.h b/arch/powerpc/include/asm/scatterlist.h
index fcf7d55..912bf59 100644
--- a/arch/powerpc/include/asm/scatterlist.h
+++ b/arch/powerpc/include/asm/scatterlist.h
@@ -21,7 +21,7 @@ struct scatterlist {
 	unsigned int offset;
 	unsigned int length;
 
-	/* For TCE support */
+	/* For TCE or SWIOTLB support */
 	dma_addr_t dma_address;
 	u32 dma_length;
 };
@@ -34,11 +34,7 @@ struct scatterlist {
  * is 0.
  */
 #define sg_dma_address(sg)	((sg)->dma_address)
-#ifdef __powerpc64__
 #define sg_dma_len(sg)		((sg)->dma_length)
-#else
-#define sg_dma_len(sg)		((sg)->length)
-#endif
 
 #ifdef __powerpc64__
 #define ISA_DMA_THRESHOLD	(~0UL)
-- 
1.6.0.6

^ permalink raw reply related

* [PATCH V2 3/3] powerpc: Add 86xx support for SWIOTLB
From: Becky Bruce @ 2009-05-14 22:42 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: fujita.tomonori
In-Reply-To: <1242340949-16369-2-git-send-email-beckyb@kernel.crashing.org>

This is the final bit of code to allow enabling swiotlb on
mpc86xx.  The platform-specific code is very small and consists
of enabling SWIOTLB in the config file, registering the
swiotlb_setup_bus_notifier initcall, and setting pci_dma_ops
to point to swiotlb_pci_dma_ops if we have more memory than
can be mapped by the inbound PCI windows.

Signed-off-by: Becky Bruce <beckyb@kernel.crashing.org>
---
 arch/powerpc/platforms/86xx/Kconfig        |    1 +
 arch/powerpc/platforms/86xx/mpc86xx_hpcn.c |   15 +++++++++++++++
 2 files changed, 16 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/platforms/86xx/Kconfig b/arch/powerpc/platforms/86xx/Kconfig
index fdaf4dd..9c7b64a 100644
--- a/arch/powerpc/platforms/86xx/Kconfig
+++ b/arch/powerpc/platforms/86xx/Kconfig
@@ -15,6 +15,7 @@ config MPC8641_HPCN
 	select DEFAULT_UIMAGE
 	select FSL_ULI1575
 	select HAS_RAPIDIO
+	select SWIOTLB
 	help
 	  This option enables support for the MPC8641 HPCN board.
 
diff --git a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
index 7e9e83c..6632702 100644
--- a/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
+++ b/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
@@ -19,6 +19,7 @@
 #include <linux/delay.h>
 #include <linux/seq_file.h>
 #include <linux/of_platform.h>
+#include <linux/lmb.h>
 
 #include <asm/system.h>
 #include <asm/time.h>
@@ -27,6 +28,7 @@
 #include <asm/prom.h>
 #include <mm/mmu_decl.h>
 #include <asm/udbg.h>
+#include <asm/swiotlb.h>
 
 #include <asm/mpic.h>
 
@@ -70,7 +72,9 @@ mpc86xx_hpcn_setup_arch(void)
 {
 #ifdef CONFIG_PCI
 	struct device_node *np;
+	struct pci_controller *hose;
 #endif
+	dma_addr_t max = 0xffffffff;
 
 	if (ppc_md.progress)
 		ppc_md.progress("mpc86xx_hpcn_setup_arch()", 0);
@@ -83,6 +87,9 @@ mpc86xx_hpcn_setup_arch(void)
 			fsl_add_bridge(np, 1);
 		else
 			fsl_add_bridge(np, 0);
+		hose = pci_find_hose_for_OF_device(np);
+		max = min(max, hose->dma_window_base_cur +
+			  hose->dma_window_size);
 	}
 
 	ppc_md.pci_exclude_device = mpc86xx_exclude_device;
@@ -94,6 +101,13 @@ mpc86xx_hpcn_setup_arch(void)
 #ifdef CONFIG_SMP
 	mpc86xx_smp_init();
 #endif
+
+#ifdef CONFIG_SWIOTLB
+	if (lmb_end_of_DRAM() > max) {
+		ppc_swiotlb_enable = 1;
+		set_pci_dma_ops(&swiotlb_pci_dma_ops);
+	}
+#endif
 }
 
 
@@ -158,6 +172,7 @@ static int __init declare_of_platform_devices(void)
 	return 0;
 }
 machine_device_initcall(mpc86xx_hpcn, declare_of_platform_devices);
+machine_arch_initcall(mpc86xx_hpcn, swiotlb_setup_bus_notifier);
 
 define_machine(mpc86xx_hpcn) {
 	.name			= "MPC86xx HPCN",
-- 
1.6.0.6

^ permalink raw reply related

* [PATCH V2 2/3] powerpc: Add support for swiotlb on 32-bit
From: Becky Bruce @ 2009-05-14 22:42 UTC (permalink / raw)
  To: linuxppc-dev; +Cc: fujita.tomonori
In-Reply-To: <1242340949-16369-1-git-send-email-beckyb@kernel.crashing.org>

This patch includes the basic infrastructure to use swiotlb
bounce buffering on 32-bit powerpc.  It is not yet enabled on
any platforms.  Probably the most interesting bit is the
addition of addr_needs_map to dma_ops - we need this as
a dma_op because the decision of whether or not an addr
can be mapped by a device is device-specific.

Signed-off-by: Becky Bruce <beckyb@kernel.crashing.org>
---
 arch/powerpc/Kconfig                   |   12 ++-
 arch/powerpc/include/asm/dma-mapping.h |   11 ++
 arch/powerpc/include/asm/swiotlb.h     |   27 +++++
 arch/powerpc/kernel/Makefile           |    1 +
 arch/powerpc/kernel/dma-swiotlb.c      |  163 ++++++++++++++++++++++++++++++++
 arch/powerpc/kernel/dma.c              |    2 +-
 arch/powerpc/kernel/setup_32.c         |    6 +
 arch/powerpc/kernel/setup_64.c         |    6 +
 8 files changed, 226 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/include/asm/swiotlb.h
 create mode 100644 arch/powerpc/kernel/dma-swiotlb.c

diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index a0d1146..54e519a 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -296,9 +296,19 @@ config IOMMU_VMERGE
 config IOMMU_HELPER
 	def_bool PPC64
 
+config SWIOTLB
+	bool "SWIOTLB support"
+	default n
+	select IOMMU_HELPER
+	---help---
+	  Support for IO bounce buffering for systems without an IOMMU.
+	  This allows us to DMA to the full physical address space on
+	  platforms where the size of a physical address is larger
+	  than the bus address.  Not all platforms support this.
+
 config PPC_NEED_DMA_SYNC_OPS
 	def_bool y
-	depends on NOT_COHERENT_CACHE
+	depends on (NOT_COHERENT_CACHE || SWIOTLB)
 
 config HOTPLUG_CPU
 	bool "Support for enabling/disabling CPUs"
diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h
index c69f2b5..71bbc17 100644
--- a/arch/powerpc/include/asm/dma-mapping.h
+++ b/arch/powerpc/include/asm/dma-mapping.h
@@ -15,9 +15,18 @@
 #include <linux/scatterlist.h>
 #include <linux/dma-attrs.h>
 #include <asm/io.h>
+#include <asm/swiotlb.h>
 
 #define DMA_ERROR_CODE		(~(dma_addr_t)0x0)
 
+/* Some dma direct funcs must be visible for use in other dma_ops */
+extern void *dma_direct_alloc_coherent(struct device *dev, size_t size,
+				       dma_addr_t *dma_handle, gfp_t flag);
+extern void dma_direct_free_coherent(struct device *dev, size_t size,
+				     void *vaddr, dma_addr_t dma_handle);
+
+extern unsigned long get_dma_direct_offset(struct device *dev);
+
 #ifdef CONFIG_NOT_COHERENT_CACHE
 /*
  * DMA-consistent mapping functions for PowerPCs that don't support
@@ -76,6 +85,8 @@ struct dma_mapping_ops {
 				dma_addr_t dma_address, size_t size,
 				enum dma_data_direction direction,
 				struct dma_attrs *attrs);
+	int		(*addr_needs_map)(struct device *dev, dma_addr_t addr,
+				size_t size);
 #ifdef CONFIG_PPC_NEED_DMA_SYNC_OPS
 	void            (*sync_single_range_for_cpu)(struct device *hwdev,
 				dma_addr_t dma_handle, unsigned long offset,
diff --git a/arch/powerpc/include/asm/swiotlb.h b/arch/powerpc/include/asm/swiotlb.h
new file mode 100644
index 0000000..30891d6
--- /dev/null
+++ b/arch/powerpc/include/asm/swiotlb.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2009 Becky Bruce, Freescale Semiconductor
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#ifndef __ASM_SWIOTLB_H
+#define __ASM_SWIOTLB_H
+
+#include <linux/swiotlb.h>
+
+extern struct dma_mapping_ops swiotlb_dma_ops;
+extern struct dma_mapping_ops swiotlb_pci_dma_ops;
+
+int swiotlb_arch_address_needs_mapping(struct device *, dma_addr_t,
+				       size_t size);
+
+static inline void dma_mark_clean(void *addr, size_t size) {}
+
+extern unsigned int ppc_swiotlb_enable;
+int __init swiotlb_setup_bus_notifier(void);
+
+#endif /* __ASM_SWIOTLB_H */
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index 71901fb..34c0a95 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_KPROBES)		+= kprobes.o
 obj-$(CONFIG_PPC_UDBG_16550)	+= legacy_serial.o udbg_16550.o
 obj-$(CONFIG_STACKTRACE)	+= stacktrace.o
+obj-$(CONFIG_SWIOTLB)		+= dma-swiotlb.o
 
 pci64-$(CONFIG_PPC64)		+= pci_dn.o isa-bridge.o
 obj-$(CONFIG_PCI)		+= pci_$(CONFIG_WORD_SIZE).o $(pci64-y) \
diff --git a/arch/powerpc/kernel/dma-swiotlb.c b/arch/powerpc/kernel/dma-swiotlb.c
new file mode 100644
index 0000000..68ccf11
--- /dev/null
+++ b/arch/powerpc/kernel/dma-swiotlb.c
@@ -0,0 +1,163 @@
+/*
+ * Contains routines needed to support swiotlb for ppc.
+ *
+ * Copyright (C) 2009 Becky Bruce, Freescale Semiconductor
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/pfn.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pci.h>
+
+#include <asm/machdep.h>
+#include <asm/swiotlb.h>
+#include <asm/dma.h>
+#include <asm/abs_addr.h>
+
+int swiotlb __read_mostly;
+unsigned int ppc_swiotlb_enable;
+
+void *swiotlb_bus_to_virt(struct device *hwdev, dma_addr_t addr)
+{
+	unsigned long pfn = PFN_DOWN(swiotlb_bus_to_phys(hwdev, addr));
+	void *pageaddr = page_address(pfn_to_page(pfn));
+
+	if (pageaddr != NULL)
+		return pageaddr + (addr % PAGE_SIZE);
+	return NULL;
+}
+
+dma_addr_t swiotlb_phys_to_bus(struct device *hwdev, phys_addr_t paddr)
+{
+	return paddr + get_dma_direct_offset(hwdev);
+}
+
+phys_addr_t swiotlb_bus_to_phys(struct device *hwdev, dma_addr_t baddr)
+
+{
+	return baddr - get_dma_direct_offset(hwdev);
+}
+
+/*
+ * Determine if an address needs bounce buffering via swiotlb.
+ * Going forward I expect the swiotlb code to generalize on using
+ * a dma_ops->addr_needs_map, and this function will move from here to the
+ * generic swiotlb code.
+ */
+int
+swiotlb_arch_address_needs_mapping(struct device *hwdev, dma_addr_t addr,
+				   size_t size)
+{
+	struct dma_mapping_ops *dma_ops = get_dma_ops(hwdev);
+
+	BUG_ON(!dma_ops);
+	return dma_ops->addr_needs_map(hwdev, addr, size);
+}
+
+/*
+ * Determine if an address is reachable by a pci device, or if we must bounce.
+ */
+static int
+swiotlb_pci_addr_needs_map(struct device *hwdev, dma_addr_t addr, size_t size)
+{
+	u64 mask = dma_get_mask(hwdev);
+	dma_addr_t max;
+	struct pci_controller *hose;
+	struct pci_dev *pdev = to_pci_dev(hwdev);
+
+	hose = pci_bus_to_host(pdev->bus);
+	max = hose->dma_window_base_cur + hose->dma_window_size;
+
+	/* check that we're within mapped pci window space */
+	if ((addr + size > max) | (addr < hose->dma_window_base_cur))
+		return 1;
+
+	return !is_buffer_dma_capable(mask, addr, size);
+}
+
+static int
+swiotlb_addr_needs_map(struct device *hwdev, dma_addr_t addr, size_t size)
+{
+	return !is_buffer_dma_capable(dma_get_mask(hwdev), addr, size);
+}
+
+
+/*
+ * At the moment, all platforms that use this code only require
+ * swiotlb to be used if we're operating on HIGHMEM.  Since
+ * we don't ever call anything other than map_sg, unmap_sg,
+ * map_page, and unmap_page on highmem, use normal dma_ops
+ * for everything else.
+ */
+struct dma_mapping_ops swiotlb_dma_ops = {
+	.alloc_coherent = dma_direct_alloc_coherent,
+	.free_coherent = dma_direct_free_coherent,
+	.map_sg = swiotlb_map_sg_attrs,
+	.unmap_sg = swiotlb_unmap_sg_attrs,
+	.dma_supported = swiotlb_dma_supported,
+	.map_page = swiotlb_map_page,
+	.unmap_page = swiotlb_unmap_page,
+	.addr_needs_map = swiotlb_addr_needs_map,
+	.sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
+	.sync_single_range_for_device = swiotlb_sync_single_range_for_device,
+	.sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
+	.sync_sg_for_device = swiotlb_sync_sg_for_device
+};
+
+struct dma_mapping_ops swiotlb_pci_dma_ops = {
+	.alloc_coherent = dma_direct_alloc_coherent,
+	.free_coherent = dma_direct_free_coherent,
+	.map_sg = swiotlb_map_sg_attrs,
+	.unmap_sg = swiotlb_unmap_sg_attrs,
+	.dma_supported = swiotlb_dma_supported,
+	.map_page = swiotlb_map_page,
+	.unmap_page = swiotlb_unmap_page,
+	.addr_needs_map = swiotlb_pci_addr_needs_map,
+	.sync_single_range_for_cpu = swiotlb_sync_single_range_for_cpu,
+	.sync_single_range_for_device = swiotlb_sync_single_range_for_device,
+	.sync_sg_for_cpu = swiotlb_sync_sg_for_cpu,
+	.sync_sg_for_device = swiotlb_sync_sg_for_device
+};
+
+static int ppc_swiotlb_bus_notify(struct notifier_block *nb,
+				  unsigned long action, void *data)
+{
+	struct device *dev = data;
+
+	/* We are only intereted in device addition */
+	if (action != BUS_NOTIFY_ADD_DEVICE)
+		return 0;
+
+	/* May need to bounce if the device can't address all of DRAM */
+	if (dma_get_mask(dev) < lmb_end_of_DRAM())
+		set_dma_ops(dev, &swiotlb_dma_ops);
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block ppc_swiotlb_plat_bus_notifier = {
+	.notifier_call = ppc_swiotlb_bus_notify,
+	.priority = 0,
+};
+
+static struct notifier_block ppc_swiotlb_of_bus_notifier = {
+	.notifier_call = ppc_swiotlb_bus_notify,
+	.priority = 0,
+};
+
+int __init swiotlb_setup_bus_notifier(void)
+{
+	bus_register_notifier(&platform_bus_type,
+			      &ppc_swiotlb_plat_bus_notifier);
+	bus_register_notifier(&of_platform_bus_type,
+			      &ppc_swiotlb_of_bus_notifier);
+
+	return 0;
+}
diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c
index 53c7788..62d80c4 100644
--- a/arch/powerpc/kernel/dma.c
+++ b/arch/powerpc/kernel/dma.c
@@ -19,7 +19,7 @@
  * default the offset is PCI_DRAM_OFFSET.
  */
 
-static unsigned long get_dma_direct_offset(struct device *dev)
+unsigned long get_dma_direct_offset(struct device *dev)
 {
 	if (dev)
 		return (unsigned long)dev->archdata.dma_data;
diff --git a/arch/powerpc/kernel/setup_32.c b/arch/powerpc/kernel/setup_32.c
index 9e1ca74..1d15424 100644
--- a/arch/powerpc/kernel/setup_32.c
+++ b/arch/powerpc/kernel/setup_32.c
@@ -39,6 +39,7 @@
 #include <asm/serial.h>
 #include <asm/udbg.h>
 #include <asm/mmu_context.h>
+#include <asm/swiotlb.h>
 
 #include "setup.h"
 
@@ -332,6 +333,11 @@ void __init setup_arch(char **cmdline_p)
 		ppc_md.setup_arch();
 	if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
 
+#ifdef CONFIG_SWIOTLB
+	if (ppc_swiotlb_enable)
+		swiotlb_init();
+#endif
+
 	paging_init();
 
 	/* Initialize the MMU context management stuff */
diff --git a/arch/powerpc/kernel/setup_64.c b/arch/powerpc/kernel/setup_64.c
index c410c60..fbcca72 100644
--- a/arch/powerpc/kernel/setup_64.c
+++ b/arch/powerpc/kernel/setup_64.c
@@ -61,6 +61,7 @@
 #include <asm/xmon.h>
 #include <asm/udbg.h>
 #include <asm/kexec.h>
+#include <asm/swiotlb.h>
 
 #include "setup.h"
 
@@ -524,6 +525,11 @@ void __init setup_arch(char **cmdline_p)
 	if (ppc_md.setup_arch)
 		ppc_md.setup_arch();
 
+#ifdef CONFIG_SWIOTLB
+	if (ppc_swiotlb_enable)
+		swiotlb_init();
+#endif
+
 	paging_init();
 	ppc64_boot_msg(0x15, "Setup Done");
 }
-- 
1.6.0.6

^ permalink raw reply related

* RE: Does U-BOOT (MPC8560) support Micron MT18VDD12872DG
From: Liu Dave-R63238 @ 2009-05-15  0:27 UTC (permalink / raw)
  To: Deepak Gaur, linuxppc-dev, u-boot
In-Reply-To: <20090514070132.M24973@cdotd.ernet.in>

> I have a custom board similar to MPC8560ADS board with 1GB=20
> DDR SDRAM. The DDR SDRAM Make
> is MT18VDDF12872DG-335D3. In U-BOOT (2009.01) config file I=20
> have enabled CONFIG_SPD_EEPROM
> so U-boot configures MPC8560ADS DDR controller with the=20
> values read from SPD_EEPROM (i2c
> address 0x51)=20
>=20
> After card reset U-BOOT runs from BOOT Flash and debug prints=20
> start coming on SCC1 port
> But after configuring the MPC8560 DDR controller the U-BOOT=20
> HANGS when it tries to run
> from RAM locations after relocation from BOOT Flash.=20
>=20
> Somewhere I read that it is due to failure of Burst Mode=20
> access of RAM. But DDR SDRAM=20
> inherently work in Burst Mode only. Moreover U-BBOT =20
> initialized the DDR SDRAM Mode
> config register using SPD EEPROM values . The value indicate=20
> that SDRAM is in Burst Mode
>=20
> MPC8560 CPU Version is 2.0.2
>=20
> Please help in understanding the issue here
>=20
> The U-BOOT Details are
> --------------------------------------------------------------
> ---------------------------
> U-Boot 2009.01 (Apr 27 2009 - 14:17:09)
>=20
>=20
> CPU:   8560, Version: 2.0, (0x80700020)
> Core:  E500, Version: 2.0, (0x80200020)
> Clock Configuration:
>        CPU:660  MHz, CCB:264  MHz,
>        DDR:132  MHz (264 MT/s data rate), LBC:66   MHz
> CPM:   264 MHz
> L1:    D-cache 32 kB enabled
>        I-cache 32 kB enabled
> Board: ADS
>     PCI1: 32 bit, 33 MHz (compiled)
> I2C:   ready
> DRAM:  Initializing
> SDRAM SPD EEPROM
> starting at step 1 (STEP_GET_SPD)
>=20
>  MEM TYPE 0x7DDR: DDR I rank density =3D 0x20000000
> mclk_ps =3D 7580
> i=3D0, x =3D 0, lowest_tCKmin_found =3D 0
> i=3D1, x =3D 7500, lowest_tCKmin_found =3D 0
> i=3D2, x =3D 6000, lowest_tCKmin_found =3D 7500
> i=3D3, x =3D 5000, lowest_tCKmin_found =3D 7500
> lowest_tCKmin_CL =3D 2
> Computing lowest common DIMM parameters for memctl=3D0
> using mclk_ps =3D 7580
> checking common caslat =3D 3
> CL =3D 3 ok on DIMM 0 at tCK=3D7580 ps with its tCKmin_X_ps of 6000
> checking common caslat =3D 2
> CL =3D 2 ok on DIMM 0 at tCK=3D7580 ps with its=20
> tCKmin_X_minus_1_ps of 7500
> lowest common SPD-defined CAS latency =3D 2
> highest common dereated CAS latency =3D 2
> all DIMMs ECC capable
> Reloading memory controller configuration options for memctl=3D0
> mclk_ps =3D 7580 ps
> FSL Memory ctrl cg register computation
> FSLDDR: cs[0]_bnds =3D 0x0000001f
> FSLDDR: cs[0]_config =3D 0x80010103
> FSLDDR: cs[0]_config_2 =3D 0x00000000
> FSLDDR: cs[1]_bnds =3D 0x0020003f
> FSLDDR: cs[1]_config =3D 0x80010103
> FSLDDR: cs[1]_config_2 =3D 0x00000000
> FSLDDR: timing_cfg_3 =3D 0x00000000
> FSLDDR: timing_cfg_1 =3D 0x36332422
> FSLDDR: timing_cfg_2 =3D 0x00006482
> FSLDDR: ddr_sdram_cfg =3D 0xe2000000
> FSLDDR: ddr_sdram_cfg_2 =3D 0x20401000
> FSLDDR: ddr_sdram_mode =3D 0x00000022
> FSLDDR: ddr_sdram_mode_2 =3D 0x00000000
> FSLDDR: ddr_sdram_interval =3D 0x04060100
> FSLDDR: timing_cfg_4 =3D 0x00000000
> FSLDDR: timing_cfg_5 =3D 0x00000000
>=20
> ...
> ...
> Some stack location related prints=20
> ...
> <hangs> here   <---- checked with emulator its somewhere in=20
> RAM but no prints coming

Have a try change clk_adjust, cpo_override, write_data_delay
in the board/freescale/mpc8560ads/ddr.c for your DIMMs.

Thanks, Dave

^ permalink raw reply

* The question about the u-boot on intel ixp460?
From: guojin02 @ 2009-05-15  1:43 UTC (permalink / raw)
  To: linuxppc-embedded; +Cc: linuxppc-dev, wd, linux-kernel

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

Hi, friends,

I move the u-boot patched from http://www.evidence.eu.com/content/view/104/169/   to my IXP460 board. There are some difference between ixdp465 board and my ixp460 board.  The cpu part number is different, my ixp460 board have 128MB ddr memory(MT46V32M16-6T ), and 16MB flash (JS28F128J3D75), but the ixdp465 have 64MB ddr (MT46V16M16-6T) and 32MB flash(RC28F256J3C125). I am sure that the UART selected by me is right. I did not change any code from evidence, I used the arm-linux-tools-20061213, the build is success. then I used the BintoS19 convert u-boot.bin to S19 style, write to the flash by OCDemon flash memory programmer.  but my ixp460 board had no any response from serial interface, my ixp460 board can work normally with REDBOOT, so the hardware have no problem. Could you tell me why? Thanks.


2009-05-15 



    郭  劲
13810607876
010-62771694

[-- Attachment #2: Type: text/html, Size: 2024 bytes --]

^ permalink raw reply

* [PATCH] powerpc/pseries: Really fix the oprofile CPU type on pseries
From: Benjamin Herrenschmidt @ 2009-05-15  4:34 UTC (permalink / raw)
  To: linuxppc-dev

My previous pach for fixing the oprofile CPU type got somewhat mismerged
(by my fault) when it collided with another related patch. This should
finally (fingers crossed) fix the whole thing.

We make sure we keep the -old- oprofile type and CPU type whenever
one of them was specified in the first pass through the function.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

More eyes welcome to check I finally got that right.

 arch/powerpc/kernel/cputable.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

--- linux-work.orig/arch/powerpc/kernel/cputable.c	2009-05-15 14:24:53.000000000 +1000
+++ linux-work/arch/powerpc/kernel/cputable.c	2009-05-15 14:27:04.000000000 +1000
@@ -1836,7 +1836,7 @@ static void __init setup_cpu_spec(unsign
 		 * and, in that case, keep the current value for
 		 * oprofile_cpu_type.
 		 */
-		if (old.oprofile_cpu_type == NULL) {
+		if (old.oprofile_cpu_type != NULL) {
 			t->oprofile_cpu_type = old.oprofile_cpu_type;
 			t->oprofile_type = old.oprofile_type;
 		}

^ permalink raw reply

* Re: Please pull from 'merge' branch for 2.6.30
From: Benjamin Herrenschmidt @ 2009-05-15  4:20 UTC (permalink / raw)
  To: Grant Likely; +Cc: linuxppc-dev
In-Reply-To: <fa686aa40905140941y742320eep5070ec9c579e9b6@mail.gmail.com>

On Thu, 2009-05-14 at 10:41 -0600, Grant Likely wrote:
> Hi Ben,
> 
> Here are some more commits which got missed in the last merge cycle.
> I've based this on top of Kumar's pull request from yesterday to
> minimize merge commits.
> 
> Note: This pull request replaces my previous pull request.  I rebased
> the series since some of the commits in my previous request have
> already been merged.  If you've already pulled my last request then
> you don't need to pull this one.

What branch ? I don't see them in either your merge or next branch...

Cheers,
Ben.

> Cheers,
> g.
> 
> The following changes since commit 2e15eedffaae555085071c68cb94b9eeed2245be:
>   Kumar Gala (1):
>         powerpc/8xx: Update defconfigs
> 
> are available in the git repository at:
> 
>   git://git.secretlab.ca/git/linux-2.6 merge
> 
> Grant Likely (2):
>       powerpc/boot: add simpleImage.* to clean-files list
>       powerpc/virtex: Add uImage to the default images list
> 
> John Linn (1):
>       powerpc/virtex: Fix duplicate level irq events.
> 
>  arch/powerpc/boot/Makefile         |    2 +-
>  arch/powerpc/platforms/40x/Kconfig |    1 +
>  arch/powerpc/platforms/44x/Kconfig |    1 +
>  arch/powerpc/sysdev/xilinx_intc.c  |  117 ++++++++++++++++++++++++++++++++---
>  4 files changed, 110 insertions(+), 11 deletions(-)
> 
> 
> On Wed, May 13, 2009 at 4:31 PM, Kumar Gala <galak@kernel.crashing.org> wrote:
> > Just added defconfig updates for the normal FSL set of HW.
> >
> > - k
> >
> > Please pull from 'merge' branch of
> >
> >        master.kernel.org:/pub/scm/linux/kernel/git/galak/powerpc.git merge
> >
> > to receive the following updates:
> >
> >  arch/powerpc/configs/83xx/asp8347_defconfig       |  104 ++++-
> >  arch/powerpc/configs/83xx/mpc8313_rdb_defconfig   |  114 ++++--
> >  arch/powerpc/configs/83xx/mpc8315_rdb_defconfig   |  114 ++++--
> >  arch/powerpc/configs/83xx/mpc832x_mds_defconfig   |  107 ++++--
> >  arch/powerpc/configs/83xx/mpc832x_rdb_defconfig   |  113 ++++--
> >  arch/powerpc/configs/83xx/mpc834x_itx_defconfig   |  108 ++++--
> >  arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig |  108 ++++--
> >  arch/powerpc/configs/83xx/mpc834x_mds_defconfig   |  103 ++++-
> >  arch/powerpc/configs/83xx/mpc836x_mds_defconfig   |  108 ++++--
> >  arch/powerpc/configs/83xx/mpc836x_rdk_defconfig   |   96 ++++-
> >  arch/powerpc/configs/83xx/mpc837x_mds_defconfig   |  104 ++++-
> >  arch/powerpc/configs/83xx/mpc837x_rdb_defconfig   |  111 ++++--
> >  arch/powerpc/configs/83xx/sbc834x_defconfig       |   96 ++++-
> >  arch/powerpc/configs/85xx/ksi8560_defconfig       |   86 +++-
> >  arch/powerpc/configs/85xx/mpc8540_ads_defconfig   |   82 +++-
> >  arch/powerpc/configs/85xx/mpc8560_ads_defconfig   |   89 +++--
> >  arch/powerpc/configs/85xx/mpc85xx_cds_defconfig   |   88 +++--
> >  arch/powerpc/configs/85xx/sbc8548_defconfig       |   84 +++-
> >  arch/powerpc/configs/85xx/sbc8560_defconfig       |   83 +++-
> >  arch/powerpc/configs/85xx/socrates_defconfig      |  385 ++++++++++++++++------
> >  arch/powerpc/configs/85xx/stx_gp3_defconfig       |  105 ++++--
> >  arch/powerpc/configs/85xx/tqm8540_defconfig       |  100 ++++-
> >  arch/powerpc/configs/85xx/tqm8541_defconfig       |  101 ++++-
> >  arch/powerpc/configs/85xx/tqm8548_defconfig       |   64 ++-
> >  arch/powerpc/configs/85xx/tqm8555_defconfig       |  101 ++++-
> >  arch/powerpc/configs/85xx/tqm8560_defconfig       |  101 ++++-
> >  arch/powerpc/configs/86xx/gef_ppc9a_defconfig     |   92 ++++-
> >  arch/powerpc/configs/86xx/gef_sbc310_defconfig    |   92 ++++-
> >  arch/powerpc/configs/86xx/gef_sbc610_defconfig    |  122 +++++-
> >  arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig  |  100 ++++-
> >  arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig  |  211 ++++--------
> >  arch/powerpc/configs/86xx/sbc8641d_defconfig      |  114 ++++--
> >  arch/powerpc/configs/adder875_defconfig           |   65 ++-
> >  arch/powerpc/configs/c2k_defconfig                |  128 +++++--
> >  arch/powerpc/configs/ep8248e_defconfig            |   74 +++-
> >  arch/powerpc/configs/ep88xc_defconfig             |   63 ++-
> >  arch/powerpc/configs/linkstation_defconfig        |   96 ++++-
> >  arch/powerpc/configs/mgcoge_defconfig             |   74 +++-
> >  arch/powerpc/configs/mgsuvd_defconfig             |   72 +++-
> >  arch/powerpc/configs/mpc7448_hpc2_defconfig       |   91 +++--
> >  arch/powerpc/configs/mpc8272_ads_defconfig        |   77 +++-
> >  arch/powerpc/configs/mpc83xx_defconfig            |  115 ++++--
> >  arch/powerpc/configs/mpc866_ads_defconfig         |   77 +++-
> >  arch/powerpc/configs/mpc86xx_defconfig            |  211 ++++--------
> >  arch/powerpc/configs/mpc885_ads_defconfig         |   63 ++-
> >  arch/powerpc/configs/pq2fads_defconfig            |   90 +++--
> >  arch/powerpc/configs/prpmc2800_defconfig          |  120 +++++-
> >  arch/powerpc/configs/storcenter_defconfig         |   71 ++--
> >  arch/powerpc/sysdev/fsl_soc.c                     |   46 --
> >  49 files changed, 3630 insertions(+), 1489 deletions(-)
> >
> > Anton Vorontsov (1):
> >      powerpc/fsl_soc: Remove mpc83xx_wdt_init, again
> >
> > Kumar Gala (5):
> >      powerpc/83xx: Update defconfigs
> >      powerpc/85xx: Update defconfigs
> >      powerpc/86xx: Update defconfigs
> >      powerpc/embedded6xx: Update defconfigs
> >      powerpc/8xx: Update defconfigs
> >
> > _______________________________________________
> > Linuxppc-dev mailing list
> > Linuxppc-dev@ozlabs.org
> > https://ozlabs.org/mailman/listinfo/linuxppc-dev
> >
> 
> 
> 

^ permalink raw reply

* Re: [PATCH V2 2/3] powerpc: Add support for swiotlb on 32-bit
From: Kumar Gala @ 2009-05-15  4:49 UTC (permalink / raw)
  To: Becky Bruce; +Cc: fujita.tomonori, linuxppc-dev
In-Reply-To: <1242340949-16369-2-git-send-email-beckyb@kernel.crashing.org>


On May 14, 2009, at 5:42 PM, Becky Bruce wrote:

> This patch includes the basic infrastructure to use swiotlb
> bounce buffering on 32-bit powerpc.  It is not yet enabled on
> any platforms.  Probably the most interesting bit is the
> addition of addr_needs_map to dma_ops - we need this as
> a dma_op because the decision of whether or not an addr
> can be mapped by a device is device-specific.
>
> Signed-off-by: Becky Bruce <beckyb@kernel.crashing.org>
> ---
> arch/powerpc/Kconfig                   |   12 ++-
> arch/powerpc/include/asm/dma-mapping.h |   11 ++
> arch/powerpc/include/asm/swiotlb.h     |   27 +++++
> arch/powerpc/kernel/Makefile           |    1 +
> arch/powerpc/kernel/dma-swiotlb.c      |  163 +++++++++++++++++++++++ 
> +++++++++
> arch/powerpc/kernel/dma.c              |    2 +-
> arch/powerpc/kernel/setup_32.c         |    6 +
> arch/powerpc/kernel/setup_64.c         |    6 +
> 8 files changed, 226 insertions(+), 2 deletions(-)
> create mode 100644 arch/powerpc/include/asm/swiotlb.h
> create mode 100644 arch/powerpc/kernel/dma-swiotlb.c

Acked-by: Kumar Gala <galak@kernel.crashing.org>

- k

^ permalink raw reply

* [PATCH] powerpc/85xx: Add SWIOTLB support to FSL boards
From: Kumar Gala @ 2009-05-15  5:45 UTC (permalink / raw)
  To: linuxppc-dev

Add the platform-specific code for enabling SWIOTLB if needed on P2020DS,
MPC85xx DS, and MPC85xx MDS boards as they are capable of having >4G of
memory.

We determine if we need to enable swiotlb based on how much memory is in
the board and if it exceeds 4G or what we can map via PCI inbound
windows.

Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
---
 arch/powerpc/platforms/85xx/Kconfig       |    3 +++
 arch/powerpc/platforms/85xx/mpc8536_ds.c  |   17 +++++++++++++++++
 arch/powerpc/platforms/85xx/mpc85xx_ds.c  |   19 +++++++++++++++++++
 arch/powerpc/platforms/85xx/mpc85xx_mds.c |   20 ++++++++++++++++++++
 4 files changed, 59 insertions(+), 0 deletions(-)

diff --git a/arch/powerpc/platforms/85xx/Kconfig b/arch/powerpc/platforms/85xx/Kconfig
index 43d385c..0ee5b12 100644
--- a/arch/powerpc/platforms/85xx/Kconfig
+++ b/arch/powerpc/platforms/85xx/Kconfig
@@ -35,12 +35,14 @@ config MPC85xx_MDS
 	select DEFAULT_UIMAGE
 	select PHYLIB
 	select HAS_RAPIDIO
+	select SWIOTLB
 	help
 	  This option enables support for the MPC85xx MDS board
 
 config MPC8536_DS
 	bool "Freescale MPC8536 DS"
 	select DEFAULT_UIMAGE
+	select SWIOTLB
 	help
 	  This option enables support for the MPC8536 DS board
 
@@ -49,6 +51,7 @@ config MPC85xx_DS
 	select PPC_I8259
 	select DEFAULT_UIMAGE
 	select FSL_ULI1575
+	select SWIOTLB
 	help
 	  This option enables support for the MPC85xx DS (MPC8544 DS) board
 
diff --git a/arch/powerpc/platforms/85xx/mpc8536_ds.c b/arch/powerpc/platforms/85xx/mpc8536_ds.c
index 63efca2..055ff41 100644
--- a/arch/powerpc/platforms/85xx/mpc8536_ds.c
+++ b/arch/powerpc/platforms/85xx/mpc8536_ds.c
@@ -17,6 +17,7 @@
 #include <linux/seq_file.h>
 #include <linux/interrupt.h>
 #include <linux/of_platform.h>
+#include <linux/lmb.h>
 
 #include <asm/system.h>
 #include <asm/time.h>
@@ -26,6 +27,7 @@
 #include <asm/prom.h>
 #include <asm/udbg.h>
 #include <asm/mpic.h>
+#include <asm/swiotlb.h>
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
@@ -65,7 +67,9 @@ static void __init mpc8536_ds_setup_arch(void)
 {
 #ifdef CONFIG_PCI
 	struct device_node *np;
+	struct pci_controller *hose;
 #endif
+	dma_addr_t max = 0xffffffff;
 
 	if (ppc_md.progress)
 		ppc_md.progress("mpc8536_ds_setup_arch()", 0);
@@ -80,11 +84,22 @@ static void __init mpc8536_ds_setup_arch(void)
 				fsl_add_bridge(np, 1);
 			else
 				fsl_add_bridge(np, 0);
+
+			hose = pci_find_hose_for_OF_device(np);
+			max = min(max, hose->dma_window_base_cur +
+					hose->dma_window_size);
 		}
 	}
 
 #endif
 
+#ifdef CONFIG_SWIOTLB
+	if (lmb_end_of_DRAM() > max) {
+		ppc_swiotlb_enable = 1;
+		set_pci_dma_ops(&swiotlb_pci_dma_ops);
+	}
+#endif
+
 	printk("MPC8536 DS board from Freescale Semiconductor\n");
 }
 
@@ -102,6 +117,8 @@ static int __init mpc8536_ds_publish_devices(void)
 }
 machine_device_initcall(mpc8536_ds, mpc8536_ds_publish_devices);
 
+machine_arch_initcall(mpc8536_ds, swiotlb_setup_bus_notifier);
+
 /*
  * Called very early, device-tree isn't unflattened
  */
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_ds.c b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
index 53d5851..849c0ac 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_ds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_ds.c
@@ -20,6 +20,7 @@
 #include <linux/seq_file.h>
 #include <linux/interrupt.h>
 #include <linux/of_platform.h>
+#include <linux/lmb.h>
 
 #include <asm/system.h>
 #include <asm/time.h>
@@ -30,6 +31,7 @@
 #include <asm/udbg.h>
 #include <asm/mpic.h>
 #include <asm/i8259.h>
+#include <asm/swiotlb.h>
 
 #include <sysdev/fsl_soc.h>
 #include <sysdev/fsl_pci.h>
@@ -155,7 +157,9 @@ static void __init mpc85xx_ds_setup_arch(void)
 {
 #ifdef CONFIG_PCI
 	struct device_node *np;
+	struct pci_controller *hose;
 #endif
+	dma_addr_t max = 0xffffffff;
 
 	if (ppc_md.progress)
 		ppc_md.progress("mpc85xx_ds_setup_arch()", 0);
@@ -171,6 +175,10 @@ static void __init mpc85xx_ds_setup_arch(void)
 				fsl_add_bridge(np, 1);
 			else
 				fsl_add_bridge(np, 0);
+
+			hose = pci_find_hose_for_OF_device(np);
+			max = min(max, hose->dma_window_base_cur +
+					hose->dma_window_size);
 		}
 	}
 
@@ -181,6 +189,13 @@ static void __init mpc85xx_ds_setup_arch(void)
 	mpc85xx_smp_init();
 #endif
 
+#ifdef CONFIG_SWIOTLB
+	if (lmb_end_of_DRAM() > max) {
+		ppc_swiotlb_enable = 1;
+		set_pci_dma_ops(&swiotlb_pci_dma_ops);
+	}
+#endif
+
 	printk("MPC85xx DS board from Freescale Semiconductor\n");
 }
 
@@ -217,6 +232,10 @@ machine_device_initcall(mpc8544_ds, mpc85xxds_publish_devices);
 machine_device_initcall(mpc8572_ds, mpc85xxds_publish_devices);
 machine_device_initcall(p2020_ds, mpc85xxds_publish_devices);
 
+machine_arch_initcall(mpc8544_ds, swiotlb_setup_bus_notifier);
+machine_arch_initcall(mpc8572_ds, swiotlb_setup_bus_notifier);
+machine_arch_initcall(p2020_ds, swiotlb_setup_bus_notifier);
+
 /*
  * Called very early, device-tree isn't unflattened
  */
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index b2c0a43..77f90b3 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -33,6 +33,7 @@
 #include <linux/of_platform.h>
 #include <linux/of_device.h>
 #include <linux/phy.h>
+#include <linux/lmb.h>
 
 #include <asm/system.h>
 #include <asm/atomic.h>
@@ -49,6 +50,7 @@
 #include <asm/qe.h>
 #include <asm/qe_ic.h>
 #include <asm/mpic.h>
+#include <asm/swiotlb.h>
 
 #undef DEBUG
 #ifdef DEBUG
@@ -155,6 +157,10 @@ static void __init mpc85xx_mds_setup_arch(void)
 {
 	struct device_node *np;
 	static u8 __iomem *bcsr_regs = NULL;
+#ifdef CONFIG_PCI
+	struct pci_controller *hose;
+#endif
+	dma_addr_t max = 0xffffffff;
 
 	if (ppc_md.progress)
 		ppc_md.progress("mpc85xx_mds_setup_arch()", 0);
@@ -179,6 +185,10 @@ static void __init mpc85xx_mds_setup_arch(void)
 				fsl_add_bridge(np, 1);
 			else
 				fsl_add_bridge(np, 0);
+
+			hose = pci_find_hose_for_OF_device(np);
+			max = min(max, hose->dma_window_base_cur +
+					hose->dma_window_size);
 		}
 	}
 #endif
@@ -227,6 +237,13 @@ static void __init mpc85xx_mds_setup_arch(void)
 		iounmap(bcsr_regs);
 	}
 #endif	/* CONFIG_QUICC_ENGINE */
+
+#ifdef CONFIG_SWIOTLB
+	if (lmb_end_of_DRAM() > max) {
+		ppc_swiotlb_enable = 1;
+		set_pci_dma_ops(&swiotlb_pci_dma_ops);
+	}
+#endif
 }
 
 
@@ -281,6 +298,9 @@ static int __init mpc85xx_publish_devices(void)
 machine_device_initcall(mpc8568_mds, mpc85xx_publish_devices);
 machine_device_initcall(mpc8569_mds, mpc85xx_publish_devices);
 
+machine_arch_initcall(mpc8568_mds, swiotlb_setup_bus_notifier);
+machine_arch_initcall(mpc8569_mds, swiotlb_setup_bus_notifier);
+
 static void __init mpc85xx_mds_pic_init(void)
 {
 	struct mpic *mpic;
-- 
1.6.0.6

^ permalink raw reply related

* Re: [PATCH] [PowerPC] MPC8272ADS: fix device tree for 8 MB flash, size
From: Heiko Schocher @ 2009-05-15  5:54 UTC (permalink / raw)
  To: Scott Wood; +Cc: linuxppc-dev, Wolfgang Denk, linux-kernel
In-Reply-To: <20090514214819.GA15549@b07421-ec1.am.freescale.net>

Hello Scott,

Scott Wood wrote:
> On Wed, May 13, 2009 at 08:27:07AM +0200, Heiko Schocher wrote:
>> Hello Wolfgang,
>>
>>> The current device tree for the MPC8272ADS assumes a mapping of 32 MB
>>> of NOR flash at 0xFE00.0000, while there are actually only 8 MB on
>>> the boards, mapped at 0xFF80.0000. When booting an uImage with such a
>>> device tree, the kernel crashes because 0xFE00.0000 is not mapped.
>> Wouldn;t it be better, if u-boot fixes the device tree entries?
> 
> 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.

>> I think, u-boot should know, where the flash begins and ends, and
>> because this is maybe a dynamic variable for this board, it should
>> be better, if u-boot fixes this, so no need for adding a device tree
>> for every board variant.
> 
> Flash is on a SIMM on this board, and the board manual says it's
> expandable to 32 MiB.  However, I suspect that the current DTS was just
> an error as I based it on a board that had not had its flash SIMM
> modified.  That specific flash SIMM is no longer working (or perhaps just
> got its contents corrupted -- one of these days I may hook up a BDI and
> try to reflash), so I can't go back and check.
> 
> 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? :-(

> but I don't see any setting of BR0 besides the preliminary value at
> 0xff800000).

OK, then the patch from Wolfgang should be sufficient.

bye
Heiko
-- 
DENX Software Engineering GmbH,     MD: Wolfgang Denk & Detlev Zundel
HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany

^ permalink raw reply

* [PATCH] powerpc: Fix PCI ROM access
From: Benjamin Herrenschmidt @ 2009-05-15  6:16 UTC (permalink / raw)
  To: linuxppc-dev

A couple of issues crept in since about 2.6.27 related to accessing PCI
device ROMs on various powerpc machines.

First, historically, we don't allocate the ROM resource in the resource
tree. I'm not entirely certain of why, I susepct they often contained
garbage on x86 but it's hard to tell. This causes the current generic
code to always call pci_assign_resource() when trying to access the said
ROM from sysfs, which will try to re-assign some new address regardless
of what the ROM BAR was already set to at boot time. This can be a
problem on hypervisor platforms like pSeries where we aren't supposed
to move PCI devices around (and in fact probably can't).

Second, our code that generates the PCI tree from the OF device-tree
(instead of doing config space probing) which we mostly use on pseries
at the moment, didn't set the (new) flag IORESOURCE_SIZEALIGN on any
resource. That means that any attempt at re-assigning such a resource
with pci_assign_resource() would fail due to resource_alignment()
returning 0.

This fixes this by doing these two things:

 - The code that calculates resource flags based on the OF device-node
is improved to set IORESOURCE_SIZEALIGN on any valid BAR, and while at
it also set IORESOURCE_READONLY for ROMs since we were lacking that too

 - We now allocate ROM resources as part of the resource tree. However
to limit the chances of nasty conflicts due to busted firmwares, we
only do it on the second pass of our two-passes allocation scheme,
so that all valid and enabled BARs get precedence.

This brings pSeries back the ability to access PCI ROMs via sysfs (and
thus initialize various video cards from X etc...).

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

 arch/powerpc/kernel/pci-common.c |   21 ++++++++++++++-------
 arch/powerpc/kernel/pci_64.c     |   15 ++++++++++++---
 2 files changed, 26 insertions(+), 10 deletions(-)

--- linux-work.orig/arch/powerpc/kernel/pci_64.c	2009-05-15 15:47:21.000000000 +1000
+++ linux-work/arch/powerpc/kernel/pci_64.c	2009-05-15 16:00:35.000000000 +1000
@@ -64,7 +64,7 @@ static u32 get_int_prop(struct device_no
 	return def;
 }
 
-static unsigned int pci_parse_of_flags(u32 addr0)
+static unsigned int pci_parse_of_flags(u32 addr0, int bridge)
 {
 	unsigned int flags = 0;
 
@@ -75,8 +75,17 @@ static unsigned int pci_parse_of_flags(u
 		if (addr0 & 0x40000000)
 			flags |= IORESOURCE_PREFETCH
 				 | PCI_BASE_ADDRESS_MEM_PREFETCH;
+		/* Note: We don't know whether the ROM has been left enabled
+		 * by the firmware or not. We mark it as disabled (ie, we do
+		 * not set the IORESOURCE_ROM_ENABLE flag) for now rather than
+		 * do a config space read, it will be force-enabled if needed
+		 */
+		if (!bridge && (addr0 & 0xff) == 0x30)
+			flags |= IORESOURCE_READONLY;
 	} else if (addr0 & 0x01000000)
 		flags = IORESOURCE_IO | PCI_BASE_ADDRESS_SPACE_IO;
+	if (flags)
+		flags |= IORESOURCE_SIZEALIGN;
 	return flags;
 }
 
@@ -95,7 +104,7 @@ static void pci_parse_of_addrs(struct de
 		return;
 	pr_debug("    parse addresses (%d bytes) @ %p\n", proplen, addrs);
 	for (; proplen >= 20; proplen -= 20, addrs += 5) {
-		flags = pci_parse_of_flags(addrs[0]);
+		flags = pci_parse_of_flags(addrs[0], 0);
 		if (!flags)
 			continue;
 		base = of_read_number(&addrs[1], 2);
@@ -293,7 +302,7 @@ void __devinit of_scan_pci_bridge(struct
 	}
 	i = 1;
 	for (; len >= 32; len -= 32, ranges += 8) {
-		flags = pci_parse_of_flags(ranges[0]);
+		flags = pci_parse_of_flags(ranges[0], 1);
 		size = of_read_number(&ranges[6], 2);
 		if (flags == 0 || size == 0)
 			continue;
Index: linux-work/arch/powerpc/kernel/pci-common.c
===================================================================
--- linux-work.orig/arch/powerpc/kernel/pci-common.c	2009-05-15 15:51:43.000000000 +1000
+++ linux-work/arch/powerpc/kernel/pci-common.c	2009-05-15 16:00:28.000000000 +1000
@@ -1366,12 +1366,17 @@ static void __init pcibios_allocate_reso
 
 	for_each_pci_dev(dev) {
 		pci_read_config_word(dev, PCI_COMMAND, &command);
-		for (idx = 0; idx < 6; idx++) {
+		for (idx = 0; idx <= PCI_ROM_RESOURCE; idx++) {
 			r = &dev->resource[idx];
 			if (r->parent)		/* Already allocated */
 				continue;
 			if (!r->flags || (r->flags & IORESOURCE_UNSET))
 				continue;	/* Not assigned at all */
+			/* We only allocate ROMs on pass 1 just in case they
+			 * have been screwed up by firmware
+			 */
+			if (idx == PCI_ROM_RESOURCE )
+				disabled = 1;
 			if (r->flags & IORESOURCE_IO)
 				disabled = !(command & PCI_COMMAND_IO);
 			else
@@ -1382,17 +1387,19 @@ static void __init pcibios_allocate_reso
 		if (pass)
 			continue;
 		r = &dev->resource[PCI_ROM_RESOURCE];
-		if (r->flags & IORESOURCE_ROM_ENABLE) {
+		if (r->flags) {
 			/* Turn the ROM off, leave the resource region,
 			 * but keep it unregistered.
 			 */
 			u32 reg;
-			pr_debug("PCI: Switching off ROM of %s\n",
-				 pci_name(dev));
-			r->flags &= ~IORESOURCE_ROM_ENABLE;
 			pci_read_config_dword(dev, dev->rom_base_reg, &reg);
-			pci_write_config_dword(dev, dev->rom_base_reg,
-					       reg & ~PCI_ROM_ADDRESS_ENABLE);
+			if (reg & PCI_ROM_ADDRESS_ENABLE) {
+				pr_debug("PCI: Switching off ROM of %s\n",
+					 pci_name(dev));
+				r->flags &= ~IORESOURCE_ROM_ENABLE;
+				pci_write_config_dword(dev, dev->rom_base_reg,
+						       reg & ~PCI_ROM_ADDRESS_ENABLE);
+			}
 		}
 	}
 }

^ permalink raw reply

* Re: [Linux-fbdev-devel] [PATCH] offb: use framebuffer_alloc() to allocate fb_info struct
From: Benjamin Herrenschmidt @ 2009-05-15  6:28 UTC (permalink / raw)
  To: Krzysztof Helt
  Cc: linuxppc-dev, Andrew Morton, Linux-fbdev-devel,
	Geert Uytterhoeven
In-Reply-To: <20090504190724.c2dfb53c.krzysztof.h1@poczta.fm>

On Mon, 2009-05-04 at 19:07 +0200, Krzysztof Helt wrote:
> From: Krzysztof Helt <krzysztof.h1@wp.pl>
> 
> Use the framebuffer_alloc() function to allocate the fb_info
> structure so the structure is correctly initialized after allocation.
> 
> Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>

Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
---

> ---
> 
> diff -urp linux-orig/drivers/video/offb.c linux-2.6.30/drivers/video/offb.c
> --- linux-orig/drivers/video/offb.c	2008-08-09 05:09:05.000000000 +0200
> +++ linux-2.6.30/drivers/video/offb.c	2009-05-04 00:14:28.000000000 +0200
> @@ -378,7 +378,6 @@ static void __init offb_init_fb(const ch
>  	struct fb_fix_screeninfo *fix;
>  	struct fb_var_screeninfo *var;
>  	struct fb_info *info;
> -	int size;
>  
>  	if (!request_mem_region(res_start, res_size, "offb"))
>  		return;
> @@ -393,15 +392,12 @@ static void __init offb_init_fb(const ch
>  		return;
>  	}
>  
> -	size = sizeof(struct fb_info) + sizeof(u32) * 16;
> -
> -	info = kmalloc(size, GFP_ATOMIC);
> +	info = framebuffer_alloc(sizeof(u32) * 16, NULL);
>  	
>  	if (info == 0) {
>  		release_mem_region(res_start, res_size);
>  		return;
>  	}
> -	memset(info, 0, size);
>  
>  	fix = &info->fix;
>  	var = &info->var;
> 
> ----------------------------------------------------------------------
> Wygraj 3000 zl, wycieczke lub lot balonem!
> Sprawdz >> http://link.interia.pl/f2154
> 
> 
> ------------------------------------------------------------------------------
> Register Now & Save for Velocity, the Web Performance & Operations 
> Conference from O'Reilly Media. Velocity features a full day of 
> expert-led, hands-on workshops and two days of sessions from industry 
> leaders in dedicated Performance & Operations tracks. Use code vel09scf 
> and Save an extra 15% before 5/3. http://p.sf.net/sfu/velocityconf
> _______________________________________________
> Linux-fbdev-devel mailing list
> Linux-fbdev-devel@lists.sourceforge.net
> https://lists.sourceforge.net/lists/listinfo/linux-fbdev-devel

^ permalink raw reply

* Re: RapidIO - general questions
From: Jan Neskudla @ 2009-05-15  7:33 UTC (permalink / raw)
  To: ext Li Yang; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <2a27d3730905130357re0adf41l19f5603a70dac57b@mail.gmail.com>

On Wed, 2009-05-13 at 18:57 +0800, ext Li Yang wrote:
> cc'ed LKML
> 
> On Tue, May 12, 2009 at 5:17 PM, Jan Neskudla <jan.neskudla.ext@nsn.com> wrote:
> > Hallo
> >
> > we'd likes to use a RapidIO as a general communication bus on our new
> > product, and so I have some questions about general design of Linux RIO
> > subsystem. I did not find any better mailing list for RapidIO
> > discussion.
> >
> > [1] - we'd like to implement following features
> >    * Hot-plug (hot-insert/hot-remove) of devices
> >    * Error handling (port-write packets - configuration, handling of
> > them)
> >    * Static ID configuration based on port numbers
> >    * Aux driver - basic driver, for sending messages over different
> > mboxes, handling ranges of doorbells
> >
> >    Is it here anyone who is working on any improvement, or anyone who
> > knows the development plans for RapidIO subsystem?
> >
> 
> AFAIK, there is no one currently working on these features for Linux.
> It will be good if you can add these useful features.
Yes it looks like that, currently we are analyzing current rapidIO
system, and how we can add these features. 

> 
> > [2] - I have a following problem with a current implementation of
> > loading drivers. The driver probe-function call is based on comparison
> > of VendorID (VID) and DeviceID (DID) only. Thus if I have 3 devices with
> > same DID and VID connected to the same network (bus), the driver is
> > loaded 3times, instead only once for the actual device Master port.
> 
> This should be the correct way as you actually have 3 instances of the device.
> 
> >
> > Rionet driver solved this by enabling to call initialization function
> > just once, and it expect that this is the Master port.
> 
> Rionet is kind of special.  It's not working like a simple device
> driver, but more like a customized protocol stack to support multiple
> ethernet over rio links.
> 
> >
> > Is it this correct behavior  ? It looks to me that RapidIO is handled
> > like a local bus (like PCI)
> 
> This is correct behavior.  All of them are using Linux device/driver
> infrastructure, but rionet is a special device.

But I do not have a 3 devices on one silicon. I am talking about 3
devices (3 x EP8548 boards + IDT switch) connected over rapidIO through
the switch. And in this case I'd like to have only one driver siting on
the top of Linux RapidIO subsystem. I don't see the advantage of loading
a driver locally for remote device. Am I missing something  ?

And one more think, I am getting so much Bus errors OOPSes. Whenever
there is a problem with a comunication over Rio I get such a kernel OPS.
I had to add some delays into some function to be able to finish the
enum+discovery process. Did you have some experience with some bigger
rio network running under linux ? 


                Jan 

^ permalink raw reply

* [git pull] Please pull powerpc.git merge branch
From: Benjamin Herrenschmidt @ 2009-05-15  8:01 UTC (permalink / raw)
  To: Linus Torvalds; +Cc: linuxppc-dev list, Andrew Morton, Linux Kernel list

Hi Linus !

Here are some updates for .30. A bit more than I would have hoped at
this stage in the game, but I've been MIA for a while, first on vacation
and then carried off to a customer issue, and so a lot of this have
actually been around for some time. There are bug fixes and defconfig
updates exclusively (though not all are regressions).

The tree is based on an older -rc3 checkout but it seems to merge fine
with your latest so I didn't feel the need to stick a merge commit
myself in there.

Cheers,
Ben.

The following changes since commit 45d447406a19cbfd42720f066f156f4eb9d68801:
  Linus Torvalds (1):
        Merge git://git.kernel.org/.../czankel/xtensa-2.6

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc.git merge

Anton Vorontsov (1):
      powerpc/fsl_soc: Remove mpc83xx_wdt_init, again

Becky Bruce (1):
      powerpc: Allow mem=x cmdline to work with 4G+

Benjamin Herrenschmidt (2):
      powerpc/pseries: Really fix the oprofile CPU type on pseries
      powerpc: Fix PCI ROM access

Benjamin Krill (1):
      serial/nwpserial: Fix wrong register read address and add interrupt acknowledge.

Gerhard Stenzel (1):
      powerpc/cell: Make ptcal more reliable

Grant Likely (2):
      powerpc/boot: add simpleImage.* to clean-files list
      powerpc/virtex: Add uImage to the default images list

John Linn (1):
      powerpc/virtex: Fix duplicate level irq events.

Kumar Gala (6):
      powerpc/83xx: Update defconfigs
      powerpc/85xx: Update defconfigs
      powerpc/86xx: Update defconfigs
      powerpc/embedded6xx: Update defconfigs
      powerpc/8xx: Update defconfigs
      powerpc/mpic: Fix incorrect allocation of interrupt rev-map

Maynard Johnson (1):
      powerpc: Fix oprofile sampling of marked events on POWER7

Stephen Rothwell  x (1):
      powerpc/iseries: Fix pci breakage due to bad dma_data initialization

Timur Tabi (1):
      powerpc: Fix mktree build error on Mac OS X host

 arch/powerpc/boot/Makefile                        |    2 +-
 arch/powerpc/boot/mktree.c                        |   10 +-
 arch/powerpc/configs/83xx/asp8347_defconfig       |  104 ++++--
 arch/powerpc/configs/83xx/mpc8313_rdb_defconfig   |  114 +++++--
 arch/powerpc/configs/83xx/mpc8315_rdb_defconfig   |  114 +++++--
 arch/powerpc/configs/83xx/mpc832x_mds_defconfig   |  107 +++++--
 arch/powerpc/configs/83xx/mpc832x_rdb_defconfig   |  113 +++++--
 arch/powerpc/configs/83xx/mpc834x_itx_defconfig   |  108 +++++--
 arch/powerpc/configs/83xx/mpc834x_itxgp_defconfig |  108 +++++--
 arch/powerpc/configs/83xx/mpc834x_mds_defconfig   |  103 ++++--
 arch/powerpc/configs/83xx/mpc836x_mds_defconfig   |  108 +++++--
 arch/powerpc/configs/83xx/mpc836x_rdk_defconfig   |   96 ++++--
 arch/powerpc/configs/83xx/mpc837x_mds_defconfig   |  104 +++++--
 arch/powerpc/configs/83xx/mpc837x_rdb_defconfig   |  111 +++++--
 arch/powerpc/configs/83xx/sbc834x_defconfig       |   96 ++++--
 arch/powerpc/configs/85xx/ksi8560_defconfig       |   86 ++++--
 arch/powerpc/configs/85xx/mpc8540_ads_defconfig   |   82 ++++--
 arch/powerpc/configs/85xx/mpc8560_ads_defconfig   |   89 ++++--
 arch/powerpc/configs/85xx/mpc85xx_cds_defconfig   |   88 ++++--
 arch/powerpc/configs/85xx/sbc8548_defconfig       |   84 ++++-
 arch/powerpc/configs/85xx/sbc8560_defconfig       |   83 ++++--
 arch/powerpc/configs/85xx/socrates_defconfig      |  385 ++++++++++++++++-----
 arch/powerpc/configs/85xx/stx_gp3_defconfig       |  105 +++++--
 arch/powerpc/configs/85xx/tqm8540_defconfig       |  100 ++++--
 arch/powerpc/configs/85xx/tqm8541_defconfig       |  101 ++++--
 arch/powerpc/configs/85xx/tqm8548_defconfig       |   64 +++-
 arch/powerpc/configs/85xx/tqm8555_defconfig       |  101 ++++--
 arch/powerpc/configs/85xx/tqm8560_defconfig       |  101 ++++--
 arch/powerpc/configs/86xx/gef_ppc9a_defconfig     |   92 ++++--
 arch/powerpc/configs/86xx/gef_sbc310_defconfig    |   92 ++++--
 arch/powerpc/configs/86xx/gef_sbc610_defconfig    |  122 +++++--
 arch/powerpc/configs/86xx/mpc8610_hpcd_defconfig  |  100 ++++--
 arch/powerpc/configs/86xx/mpc8641_hpcn_defconfig  |  211 +++++-------
 arch/powerpc/configs/86xx/sbc8641d_defconfig      |  114 +++++--
 arch/powerpc/configs/adder875_defconfig           |   65 +++-
 arch/powerpc/configs/c2k_defconfig                |  128 +++++--
 arch/powerpc/configs/ep8248e_defconfig            |   74 +++--
 arch/powerpc/configs/ep88xc_defconfig             |   63 +++-
 arch/powerpc/configs/linkstation_defconfig        |   96 ++++--
 arch/powerpc/configs/mgcoge_defconfig             |   74 +++-
 arch/powerpc/configs/mgsuvd_defconfig             |   72 +++-
 arch/powerpc/configs/mpc7448_hpc2_defconfig       |   91 ++++--
 arch/powerpc/configs/mpc8272_ads_defconfig        |   77 +++--
 arch/powerpc/configs/mpc83xx_defconfig            |  115 +++++--
 arch/powerpc/configs/mpc866_ads_defconfig         |   77 +++--
 arch/powerpc/configs/mpc86xx_defconfig            |  211 +++++-------
 arch/powerpc/configs/mpc885_ads_defconfig         |   63 +++-
 arch/powerpc/configs/pq2fads_defconfig            |   90 ++++--
 arch/powerpc/configs/prpmc2800_defconfig          |  120 +++++--
 arch/powerpc/configs/storcenter_defconfig         |   71 +++-
 arch/powerpc/include/asm/iseries/iommu.h          |    4 -
 arch/powerpc/include/asm/system.h                 |    2 +-
 arch/powerpc/kernel/cputable.c                    |    2 +-
 arch/powerpc/kernel/machine_kexec.c               |    4 +-
 arch/powerpc/kernel/pci-common.c                  |   21 +-
 arch/powerpc/kernel/pci_64.c                      |   15 +-
 arch/powerpc/kernel/prom.c                        |    8 +-
 arch/powerpc/mm/mem.c                             |    2 +-
 arch/powerpc/oprofile/op_model_power4.c           |    9 +-
 arch/powerpc/platforms/40x/Kconfig                |    1 +
 arch/powerpc/platforms/44x/Kconfig                |    1 +
 arch/powerpc/platforms/cell/ras.c                 |   17 +-
 arch/powerpc/platforms/iseries/iommu.c            |    6 +-
 arch/powerpc/platforms/iseries/pci.c              |    1 -
 arch/powerpc/sysdev/fsl_soc.c                     |   46 ---
 arch/powerpc/sysdev/mpic.c                        |   16 +-
 arch/powerpc/sysdev/xilinx_intc.c                 |  117 ++++++-
 drivers/serial/nwpserial.c                        |    4 +-
 68 files changed, 3819 insertions(+), 1542 deletions(-)

^ permalink raw reply

* FEC & SDMA (bestcomm) interaction on the 5200
From: Dimiter Popoff @ 2009-05-15  8:36 UTC (permalink / raw)
  To: linuxppc-dev

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).

 And 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).

 I 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?
 Or (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.
 Same 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?

 If the above assumptions are correct, I could manage it
in a reasonably short time. 
 I know this is an "untypicall" question, but people who
have wrestled the FEC & SDMA may have enough observations
to confirm or reject my assumptions and perhaps provide
some more insight.

Thanks for any input,

Dimiter

------------------------------------------------------
Dimiter Popoff               Transgalactic Instruments

http://www.tgi-sci.com
------------------------------------------------------
http://www.flickr.com/photos/didi_tgi/sets/72157600228621276/

^ permalink raw reply

* Re: RapidIO - general questions
From: Li Yang @ 2009-05-15  7:56 UTC (permalink / raw)
  To: Jan Neskudla; +Cc: linuxppc-dev, linux-kernel
In-Reply-To: <1242372791.26759.34.camel@demuxf9c>

On Fri, May 15, 2009 at 3:33 PM, Jan Neskudla <jan.neskudla.ext@nsn.com> wr=
ote:
> On Wed, 2009-05-13 at 18:57 +0800, ext Li Yang wrote:
>> cc'ed LKML
>>
>> On Tue, May 12, 2009 at 5:17 PM, Jan Neskudla <jan.neskudla.ext@nsn.com>=
 wrote:
>> > Hallo
>> >
>> > we'd likes to use a RapidIO as a general communication bus on our new
>> > product, and so I have some questions about general design of Linux RI=
O
>> > subsystem. I did not find any better mailing list for RapidIO
>> > discussion.
>> >
>> > [1] - we'd like to implement following features
>> > =C2=A0 =C2=A0* Hot-plug (hot-insert/hot-remove) of devices
>> > =C2=A0 =C2=A0* Error handling (port-write packets - configuration, han=
dling of
>> > them)
>> > =C2=A0 =C2=A0* Static ID configuration based on port numbers
>> > =C2=A0 =C2=A0* Aux driver - basic driver, for sending messages over di=
fferent
>> > mboxes, handling ranges of doorbells
>> >
>> > =C2=A0 =C2=A0Is it here anyone who is working on any improvement, or a=
nyone who
>> > knows the development plans for RapidIO subsystem?
>> >
>>
>> AFAIK, there is no one currently working on these features for Linux.
>> It will be good if you can add these useful features.
> Yes it looks like that, currently we are analyzing current rapidIO
> system, and how we can add these features.
>
>>
>> > [2] - I have a following problem with a current implementation of
>> > loading drivers. The driver probe-function call is based on comparison
>> > of VendorID (VID) and DeviceID (DID) only. Thus if I have 3 devices wi=
th
>> > same DID and VID connected to the same network (bus), the driver is
>> > loaded 3times, instead only once for the actual device Master port.
>>
>> This should be the correct way as you actually have 3 instances of the d=
evice.
>>
>> >
>> > Rionet driver solved this by enabling to call initialization function
>> > just once, and it expect that this is the Master port.
>>
>> Rionet is kind of special. =C2=A0It's not working like a simple device
>> driver, but more like a customized protocol stack to support multiple
>> ethernet over rio links.
>>
>> >
>> > Is it this correct behavior =C2=A0? It looks to me that RapidIO is han=
dled
>> > like a local bus (like PCI)
>>
>> This is correct behavior. =C2=A0All of them are using Linux device/drive=
r
>> infrastructure, but rionet is a special device.
>
> But I do not have a 3 devices on one silicon. I am talking about 3
> devices (3 x EP8548 boards + IDT switch) connected over rapidIO through
> the switch. And in this case I'd like to have only one driver siting on
> the top of Linux RapidIO subsystem. I don't see the advantage of loading

You are having one driver, but it probes 3 times for each device using
the driver.

> a driver locally for remote device. Am I missing something =C2=A0?

If you want to interact with the remote device, you need the driver to
do the work locally.

>
> And one more think, I am getting so much Bus errors OOPSes. Whenever
> there is a problem with a comunication over Rio I get such a kernel OPS.
> I had to add some delays into some function to be able to finish the
> enum+discovery process. Did you have some experience with some bigger
> rio network running under linux ?

It looks like an known issue for switched rio network, but I don't
have the correct equipment to reproduce the problem here.  Could you
do some basic debugging and share your findings?  Thanks.

- Leo

^ permalink raw reply

* [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

* [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 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 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 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

* [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

* 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

* 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


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