[MIPS] TXx9: PCI error handling

From: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Date: Thu, 24 Jul 2008 00:25:16 +0900
Subject: [PATCH] txx9: PCI error handling

Add more control and detailed report on PCI error interrupt.

Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
diff --git a/arch/mips/pci/ops-tx4927.c b/arch/mips/pci/ops-tx4927.c
index 038e311..5989e74 100644
--- a/arch/mips/pci/ops-tx4927.c
+++ b/arch/mips/pci/ops-tx4927.c
@@ -16,6 +16,8 @@
  * option) any later version.
  */
 #include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <asm/txx9/pci.h>
 #include <asm/txx9/tx4927pcic.h>
 
 static struct {
@@ -431,6 +433,66 @@
 	}
 }
 
+static void tx4927_dump_pcic_settings1(struct tx4927_pcic_reg __iomem *pcicptr)
+{
+	int i;
+	__u32 __iomem *preg = (__u32 __iomem *)pcicptr;
+
+	printk(KERN_INFO "tx4927 pcic (0x%p) settings:", pcicptr);
+	for (i = 0; i < sizeof(struct tx4927_pcic_reg); i += 4, preg++) {
+		if (i % 32 == 0) {
+			printk(KERN_CONT "\n");
+			printk(KERN_INFO "%04x:", i);
+		}
+		/* skip registers with side-effects */
+		if (i == offsetof(struct tx4927_pcic_reg, g2pintack)
+		    || i == offsetof(struct tx4927_pcic_reg, g2pspc)
+		    || i == offsetof(struct tx4927_pcic_reg, g2pcfgadrs)
+		    || i == offsetof(struct tx4927_pcic_reg, g2pcfgdata)) {
+			printk(KERN_CONT " XXXXXXXX");
+			continue;
+		}
+		printk(KERN_CONT " %08x", __raw_readl(preg));
+	}
+	printk(KERN_CONT "\n");
+}
+
+void tx4927_dump_pcic_settings(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(pcicptrs); i++) {
+		if (pcicptrs[i].pcicptr)
+			tx4927_dump_pcic_settings1(pcicptrs[i].pcicptr);
+	}
+}
+
+irqreturn_t tx4927_pcierr_interrupt(int irq, void *dev_id)
+{
+	struct pt_regs *regs = get_irq_regs();
+	struct tx4927_pcic_reg __iomem *pcicptr =
+		(struct tx4927_pcic_reg __iomem *)(unsigned long)dev_id;
+
+	if (txx9_pci_err_action != TXX9_PCI_ERR_IGNORE) {
+		printk(KERN_WARNING "PCIERR interrupt at 0x%0*lx\n",
+		       (int)(2 * sizeof(unsigned long)), regs->cp0_epc);
+		tx4927_report_pcic_status1(pcicptr);
+	}
+	if (txx9_pci_err_action != TXX9_PCI_ERR_PANIC) {
+		/* clear all pci errors */
+		__raw_writel((__raw_readl(&pcicptr->pcistatus) & 0x0000ffff)
+			     | (TX4927_PCIC_PCISTATUS_ALL << 16),
+			     &pcicptr->pcistatus);
+		__raw_writel(TX4927_PCIC_G2PSTATUS_ALL, &pcicptr->g2pstatus);
+		__raw_writel(TX4927_PCIC_PBASTATUS_ALL, &pcicptr->pbastatus);
+		__raw_writel(TX4927_PCIC_PCICSTATUS_ALL, &pcicptr->pcicstatus);
+		return IRQ_HANDLED;
+	}
+	console_verbose();
+	tx4927_dump_pcic_settings1(pcicptr);
+	panic("PCI error.");
+}
+
 #ifdef CONFIG_TOSHIBA_FPCIB0
 static void __init tx4927_quirk_slc90e66_bridge(struct pci_dev *dev)
 {