Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 455cc256 authored by Atsushi Nemoto's avatar Atsushi Nemoto Committed by Ralf Baechle
Browse files

[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: default avatarAtsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent 07517529
Loading
Loading
Loading
Loading
+34 −0
Original line number Diff line number Diff line
@@ -37,8 +37,11 @@
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/interrupt.h>

#include <asm/addrspace.h>
#include <asm/txx9irq.h>
#include <asm/txx9/pci.h>
#include <asm/txx9/tx3927.h>

static int mkaddr(struct pci_bus *bus, unsigned char devfn, unsigned char where)
@@ -194,3 +197,34 @@ void __init tx3927_pcic_setup(struct pci_controller *channel,
		PCI_COMMAND_PARITY | PCI_COMMAND_SERR;
	local_irq_restore(flags);
}

static irqreturn_t tx3927_pcierr_interrupt(int irq, void *dev_id)
{
	struct pt_regs *regs = get_irq_regs();

	if (txx9_pci_err_action != TXX9_PCI_ERR_IGNORE) {
		printk(KERN_WARNING "PCI error interrupt at 0x%08lx.\n",
		       regs->cp0_epc);
		printk(KERN_WARNING "pcistat:%02x, lbstat:%04lx\n",
		       tx3927_pcicptr->pcistat, tx3927_pcicptr->lbstat);
	}
	if (txx9_pci_err_action != TXX9_PCI_ERR_PANIC) {
		/* clear all pci errors */
		tx3927_pcicptr->pcistat |= TX3927_PCIC_PCISTATIM_ALL;
		tx3927_pcicptr->istat = TX3927_PCIC_IIM_ALL;
		tx3927_pcicptr->tstat = TX3927_PCIC_TIM_ALL;
		tx3927_pcicptr->lbstat = TX3927_PCIC_LBIM_ALL;
		return IRQ_HANDLED;
	}
	console_verbose();
	panic("PCI error.");
}

void __init tx3927_setup_pcierr_irq(void)
{
	if (request_irq(TXX9_IRQ_BASE + TX3927_IR_PCI,
			tx3927_pcierr_interrupt,
			IRQF_DISABLED, "PCI error",
			(void *)TX3927_PCIC_REG))
		printk(KERN_WARNING "Failed to request irq for PCIERR\n");
}
+62 −0
Original line number Diff line number Diff line
@@ -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 @@ void tx4927_report_pcic_status(void)
	}
}

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)
{
+10 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <asm/txx9/generic.h>
#include <asm/txx9/tx4927.h>

@@ -81,3 +82,12 @@ int __init tx4927_pciclk66_setup(void)
		pciclk = -1;
	return pciclk;
}

void __init tx4927_setup_pcierr_irq(void)
{
	if (request_irq(TXX9_IRQ_BASE + TX4927_IR_PCIERR,
			tx4927_pcierr_interrupt,
			IRQF_DISABLED, "PCI error",
			(void *)TX4927_PCIC_REG))
		printk(KERN_WARNING "Failed to request irq for PCIERR\n");
}
+10 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <asm/txx9/generic.h>
#include <asm/txx9/tx4938.h>

@@ -132,3 +133,12 @@ int tx4938_pcic1_map_irq(const struct pci_dev *dev, u8 slot)
	}
	return -1;
}

void __init tx4938_setup_pcierr_irq(void)
{
	if (request_irq(TXX9_IRQ_BASE + TX4938_IR_PCIERR,
			tx4927_pcierr_interrupt,
			IRQF_DISABLED, "PCI error",
			(void *)TX4927_PCIC_REG))
		printk(KERN_WARNING "Failed to request irq for PCIERR\n");
}
+0 −20
Original line number Diff line number Diff line
@@ -103,22 +103,6 @@ static int jmr3927_irq_dispatch(int pending)
	return irq;
}

#ifdef CONFIG_PCI
static irqreturn_t jmr3927_pcierr_interrupt(int irq, void *dev_id)
{
	printk(KERN_WARNING "PCI error interrupt (irq 0x%x).\n", irq);
	printk(KERN_WARNING "pcistat:%02x, lbstat:%04lx\n",
	       tx3927_pcicptr->pcistat, tx3927_pcicptr->lbstat);

	return IRQ_HANDLED;
}
static struct irqaction pcierr_action = {
	.handler = jmr3927_pcierr_interrupt,
	.mask = CPU_MASK_NONE,
	.name = "PCI error",
};
#endif

static void __init jmr3927_irq_init(void);

void __init jmr3927_irq_setup(void)
@@ -143,10 +127,6 @@ void __init jmr3927_irq_setup(void)
	/* setup IOC interrupt 1 (PCI, MODEM) */
	set_irq_chained_handler(JMR3927_IRQ_IOCINT, handle_simple_irq);

#ifdef CONFIG_PCI
	setup_irq(JMR3927_IRQ_IRC_PCI, &pcierr_action);
#endif

	/* enable all CPU interrupt bits. */
	set_c0_status(ST0_IM);	/* IE bit is still 0. */
}
Loading