[v0 PATCH 1/4] EDAC: MPIC Hypertransport IRQ support

Harry Ciao qingtao.cao at windriver.com
Fri May 15 18:43:51 EST 2009


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 at 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 at 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



More information about the Linuxppc-dev mailing list