summaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2007-12-20 13:11:18 -0600
committerOlof Johansson <olof@lixom.net>2007-12-28 09:22:24 -0600
commitf365355e65ee619e3b7baeca69b46fd2c4a5ec68 (patch)
tree24133f987dc9ffe8f3a9b02355193e3d5113f8f2 /arch/powerpc/platforms
parentc2a7dcad9f0d92d7a96e735abb8bec7b9c621536 (diff)
[POWERPC] pasemi: Implement NMI support
Some PWRficient-based boards have a NMI button that's wired up to a GPIO as interrupt source. By configuring the openpic accordingly, these get delivered as a machine check with high priority, instead of as an external interrupt. The device tree contains a property "nmi-source" in the openpic node for these systems, and it's the (hwirq) source for the input. Also, for these interrupts, the IACK is read from another register than the regular (MCACK instead), but they are EOI'd as usual. So implement said function for the mpic driver. Finally, move a couple of external function defines to include/ instead of local under sysdev. Being able to mask/unmask and eoi directly saves us from setting up a dummy irq handler that will never be called. Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'arch/powerpc/platforms')
-rw-r--r--arch/powerpc/platforms/pasemi/setup.c30
1 files changed, 27 insertions, 3 deletions
diff --git a/arch/powerpc/platforms/pasemi/setup.c b/arch/powerpc/platforms/pasemi/setup.c
index b5dfd4252110..eb271fded876 100644
--- a/arch/powerpc/platforms/pasemi/setup.c
+++ b/arch/powerpc/platforms/pasemi/setup.c
@@ -61,6 +61,7 @@ struct mce_regs {
static struct mce_regs mce_regs[MAX_MCE_REGS];
static int num_mce_regs;
+static int nmi_virq = NO_IRQ;
static void pas_restart(char *cmd)
@@ -189,6 +190,8 @@ static __init void pas_init_IRQ(void)
unsigned long openpic_addr;
const unsigned int *opprop;
int naddr, opplen;
+ int mpic_flags;
+ const unsigned int *nmiprop;
struct mpic *mpic;
mpic_node = NULL;
@@ -221,13 +224,26 @@ static __init void pas_init_IRQ(void)
openpic_addr = of_read_number(opprop, naddr);
printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr);
+ mpic_flags = MPIC_PRIMARY | MPIC_LARGE_VECTORS;
+
+ nmiprop = of_get_property(mpic_node, "nmi-source", NULL);
+ if (nmiprop)
+ mpic_flags |= MPIC_ENABLE_MCK;
+
mpic = mpic_alloc(mpic_node, openpic_addr,
- MPIC_PRIMARY|MPIC_LARGE_VECTORS,
- 0, 0, "PASEMI-OPIC");
+ mpic_flags, 0, 0, "PASEMI-OPIC");
BUG_ON(!mpic);
mpic_assign_isu(mpic, 0, openpic_addr + 0x10000);
mpic_init(mpic);
+ /* The NMI/MCK source needs to be prio 15 */
+ if (nmiprop) {
+ nmi_virq = irq_create_mapping(NULL, *nmiprop);
+ mpic_irq_set_priority(nmi_virq, 15);
+ set_irq_type(nmi_virq, IRQ_TYPE_EDGE_RISING);
+ mpic_unmask_irq(nmi_virq);
+ }
+
of_node_put(mpic_node);
of_node_put(root);
}
@@ -247,6 +263,14 @@ static int pas_machine_check_handler(struct pt_regs *regs)
srr0 = regs->nip;
srr1 = regs->msr;
+
+ if (mpic_get_mcirq() == nmi_virq) {
+ printk(KERN_ERR "NMI delivered\n");
+ debugger(regs);
+ mpic_end_irq(nmi_virq);
+ goto out;
+ }
+
dsisr = mfspr(SPRN_DSISR);
printk(KERN_ERR "Machine Check on CPU %d\n", cpu);
printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1);
@@ -310,7 +334,7 @@ static int pas_machine_check_handler(struct pt_regs *regs)
}
}
-
+out:
/* SRR1[62] is from MSR[62] if recoverable, so pass that back */
return !!(srr1 & 0x2);
}