diff options
author | Olof Johansson <olof@lixom.net> | 2007-12-20 14:11:18 -0500 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2007-12-28 10:22:24 -0500 |
commit | f365355e65ee619e3b7baeca69b46fd2c4a5ec68 (patch) | |
tree | 24133f987dc9ffe8f3a9b02355193e3d5113f8f2 /arch | |
parent | c2a7dcad9f0d92d7a96e735abb8bec7b9c621536 (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')
-rw-r--r-- | arch/powerpc/platforms/pasemi/setup.c | 30 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpic.c | 26 | ||||
-rw-r--r-- | arch/powerpc/sysdev/mpic.h | 3 |
3 files changed, 50 insertions, 9 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 { | |||
61 | 61 | ||
62 | static struct mce_regs mce_regs[MAX_MCE_REGS]; | 62 | static struct mce_regs mce_regs[MAX_MCE_REGS]; |
63 | static int num_mce_regs; | 63 | static int num_mce_regs; |
64 | static int nmi_virq = NO_IRQ; | ||
64 | 65 | ||
65 | 66 | ||
66 | static void pas_restart(char *cmd) | 67 | static void pas_restart(char *cmd) |
@@ -189,6 +190,8 @@ static __init void pas_init_IRQ(void) | |||
189 | unsigned long openpic_addr; | 190 | unsigned long openpic_addr; |
190 | const unsigned int *opprop; | 191 | const unsigned int *opprop; |
191 | int naddr, opplen; | 192 | int naddr, opplen; |
193 | int mpic_flags; | ||
194 | const unsigned int *nmiprop; | ||
192 | struct mpic *mpic; | 195 | struct mpic *mpic; |
193 | 196 | ||
194 | mpic_node = NULL; | 197 | mpic_node = NULL; |
@@ -221,13 +224,26 @@ static __init void pas_init_IRQ(void) | |||
221 | openpic_addr = of_read_number(opprop, naddr); | 224 | openpic_addr = of_read_number(opprop, naddr); |
222 | printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); | 225 | printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); |
223 | 226 | ||
227 | mpic_flags = MPIC_PRIMARY | MPIC_LARGE_VECTORS; | ||
228 | |||
229 | nmiprop = of_get_property(mpic_node, "nmi-source", NULL); | ||
230 | if (nmiprop) | ||
231 | mpic_flags |= MPIC_ENABLE_MCK; | ||
232 | |||
224 | mpic = mpic_alloc(mpic_node, openpic_addr, | 233 | mpic = mpic_alloc(mpic_node, openpic_addr, |
225 | MPIC_PRIMARY|MPIC_LARGE_VECTORS, | 234 | mpic_flags, 0, 0, "PASEMI-OPIC"); |
226 | 0, 0, "PASEMI-OPIC"); | ||
227 | BUG_ON(!mpic); | 235 | BUG_ON(!mpic); |
228 | 236 | ||
229 | mpic_assign_isu(mpic, 0, openpic_addr + 0x10000); | 237 | mpic_assign_isu(mpic, 0, openpic_addr + 0x10000); |
230 | mpic_init(mpic); | 238 | mpic_init(mpic); |
239 | /* The NMI/MCK source needs to be prio 15 */ | ||
240 | if (nmiprop) { | ||
241 | nmi_virq = irq_create_mapping(NULL, *nmiprop); | ||
242 | mpic_irq_set_priority(nmi_virq, 15); | ||
243 | set_irq_type(nmi_virq, IRQ_TYPE_EDGE_RISING); | ||
244 | mpic_unmask_irq(nmi_virq); | ||
245 | } | ||
246 | |||
231 | of_node_put(mpic_node); | 247 | of_node_put(mpic_node); |
232 | of_node_put(root); | 248 | of_node_put(root); |
233 | } | 249 | } |
@@ -247,6 +263,14 @@ static int pas_machine_check_handler(struct pt_regs *regs) | |||
247 | 263 | ||
248 | srr0 = regs->nip; | 264 | srr0 = regs->nip; |
249 | srr1 = regs->msr; | 265 | srr1 = regs->msr; |
266 | |||
267 | if (mpic_get_mcirq() == nmi_virq) { | ||
268 | printk(KERN_ERR "NMI delivered\n"); | ||
269 | debugger(regs); | ||
270 | mpic_end_irq(nmi_virq); | ||
271 | goto out; | ||
272 | } | ||
273 | |||
250 | dsisr = mfspr(SPRN_DSISR); | 274 | dsisr = mfspr(SPRN_DSISR); |
251 | printk(KERN_ERR "Machine Check on CPU %d\n", cpu); | 275 | printk(KERN_ERR "Machine Check on CPU %d\n", cpu); |
252 | printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1); | 276 | 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) | |||
310 | } | 334 | } |
311 | } | 335 | } |
312 | 336 | ||
313 | 337 | out: | |
314 | /* SRR1[62] is from MSR[62] if recoverable, so pass that back */ | 338 | /* SRR1[62] is from MSR[62] if recoverable, so pass that back */ |
315 | return !!(srr1 & 0x2); | 339 | return !!(srr1 & 0x2); |
316 | } | 340 | } |
diff --git a/arch/powerpc/sysdev/mpic.c b/arch/powerpc/sysdev/mpic.c index f74fe26b787e..5a9d8c141e60 100644 --- a/arch/powerpc/sysdev/mpic.c +++ b/arch/powerpc/sysdev/mpic.c | |||
@@ -83,6 +83,7 @@ static u32 mpic_infos[][MPIC_IDX_END] = { | |||
83 | MPIC_CPU_WHOAMI, | 83 | MPIC_CPU_WHOAMI, |
84 | MPIC_CPU_INTACK, | 84 | MPIC_CPU_INTACK, |
85 | MPIC_CPU_EOI, | 85 | MPIC_CPU_EOI, |
86 | MPIC_CPU_MCACK, | ||
86 | 87 | ||
87 | MPIC_IRQ_BASE, | 88 | MPIC_IRQ_BASE, |
88 | MPIC_IRQ_STRIDE, | 89 | MPIC_IRQ_STRIDE, |
@@ -121,6 +122,7 @@ static u32 mpic_infos[][MPIC_IDX_END] = { | |||
121 | TSI108_CPU_WHOAMI, | 122 | TSI108_CPU_WHOAMI, |
122 | TSI108_CPU_INTACK, | 123 | TSI108_CPU_INTACK, |
123 | TSI108_CPU_EOI, | 124 | TSI108_CPU_EOI, |
125 | TSI108_CPU_MCACK, | ||
124 | 126 | ||
125 | TSI108_IRQ_BASE, | 127 | TSI108_IRQ_BASE, |
126 | TSI108_IRQ_STRIDE, | 128 | TSI108_IRQ_STRIDE, |
@@ -1126,6 +1128,11 @@ struct mpic * __init mpic_alloc(struct device_node *node, | |||
1126 | mb(); | 1128 | mb(); |
1127 | } | 1129 | } |
1128 | 1130 | ||
1131 | if (flags & MPIC_ENABLE_MCK) | ||
1132 | mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), | ||
1133 | mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) | ||
1134 | | MPIC_GREG_GCONF_MCK); | ||
1135 | |||
1129 | /* Read feature register, calculate num CPUs and, for non-ISU | 1136 | /* Read feature register, calculate num CPUs and, for non-ISU |
1130 | * MPICs, num sources as well. On ISU MPICs, sources are counted | 1137 | * MPICs, num sources as well. On ISU MPICs, sources are counted |
1131 | * as ISUs are added | 1138 | * as ISUs are added |
@@ -1438,13 +1445,13 @@ void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask) | |||
1438 | mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); | 1445 | mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); |
1439 | } | 1446 | } |
1440 | 1447 | ||
1441 | unsigned int mpic_get_one_irq(struct mpic *mpic) | 1448 | static unsigned int _mpic_get_one_irq(struct mpic *mpic, int reg) |
1442 | { | 1449 | { |
1443 | u32 src; | 1450 | u32 src; |
1444 | 1451 | ||
1445 | src = mpic_cpu_read(MPIC_INFO(CPU_INTACK)) & MPIC_INFO(VECPRI_VECTOR_MASK); | 1452 | src = mpic_cpu_read(reg) & MPIC_INFO(VECPRI_VECTOR_MASK); |
1446 | #ifdef DEBUG_LOW | 1453 | #ifdef DEBUG_LOW |
1447 | DBG("%s: get_one_irq(): %d\n", mpic->name, src); | 1454 | DBG("%s: get_one_irq(reg 0x%x): %d\n", mpic->name, reg, src); |
1448 | #endif | 1455 | #endif |
1449 | if (unlikely(src == mpic->spurious_vec)) { | 1456 | if (unlikely(src == mpic->spurious_vec)) { |
1450 | if (mpic->flags & MPIC_SPV_EOI) | 1457 | if (mpic->flags & MPIC_SPV_EOI) |
@@ -1462,6 +1469,11 @@ unsigned int mpic_get_one_irq(struct mpic *mpic) | |||
1462 | return irq_linear_revmap(mpic->irqhost, src); | 1469 | return irq_linear_revmap(mpic->irqhost, src); |
1463 | } | 1470 | } |
1464 | 1471 | ||
1472 | unsigned int mpic_get_one_irq(struct mpic *mpic) | ||
1473 | { | ||
1474 | return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_INTACK)); | ||
1475 | } | ||
1476 | |||
1465 | unsigned int mpic_get_irq(void) | 1477 | unsigned int mpic_get_irq(void) |
1466 | { | 1478 | { |
1467 | struct mpic *mpic = mpic_primary; | 1479 | struct mpic *mpic = mpic_primary; |
@@ -1471,6 +1483,14 @@ unsigned int mpic_get_irq(void) | |||
1471 | return mpic_get_one_irq(mpic); | 1483 | return mpic_get_one_irq(mpic); |
1472 | } | 1484 | } |
1473 | 1485 | ||
1486 | unsigned int mpic_get_mcirq(void) | ||
1487 | { | ||
1488 | struct mpic *mpic = mpic_primary; | ||
1489 | |||
1490 | BUG_ON(mpic == NULL); | ||
1491 | |||
1492 | return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_MCACK)); | ||
1493 | } | ||
1474 | 1494 | ||
1475 | #ifdef CONFIG_SMP | 1495 | #ifdef CONFIG_SMP |
1476 | void mpic_request_ipis(void) | 1496 | void mpic_request_ipis(void) |
diff --git a/arch/powerpc/sysdev/mpic.h b/arch/powerpc/sysdev/mpic.h index 4783c6e9f30d..fbf8a266941c 100644 --- a/arch/powerpc/sysdev/mpic.h +++ b/arch/powerpc/sysdev/mpic.h | |||
@@ -38,9 +38,6 @@ static inline int mpic_pasemi_msi_init(struct mpic *mpic) | |||
38 | 38 | ||
39 | extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type); | 39 | extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type); |
40 | extern void mpic_set_vector(unsigned int virq, unsigned int vector); | 40 | extern void mpic_set_vector(unsigned int virq, unsigned int vector); |
41 | extern void mpic_end_irq(unsigned int irq); | ||
42 | extern void mpic_mask_irq(unsigned int irq); | ||
43 | extern void mpic_unmask_irq(unsigned int irq); | ||
44 | extern void mpic_set_affinity(unsigned int irq, cpumask_t cpumask); | 41 | extern void mpic_set_affinity(unsigned int irq, cpumask_t cpumask); |
45 | 42 | ||
46 | #endif /* _POWERPC_SYSDEV_MPIC_H */ | 43 | #endif /* _POWERPC_SYSDEV_MPIC_H */ |