aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2007-12-20 14:11:18 -0500
committerOlof Johansson <olof@lixom.net>2007-12-28 10:22:24 -0500
commitf365355e65ee619e3b7baeca69b46fd2c4a5ec68 (patch)
tree24133f987dc9ffe8f3a9b02355193e3d5113f8f2 /arch
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')
-rw-r--r--arch/powerpc/platforms/pasemi/setup.c30
-rw-r--r--arch/powerpc/sysdev/mpic.c26
-rw-r--r--arch/powerpc/sysdev/mpic.h3
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
62static struct mce_regs mce_regs[MAX_MCE_REGS]; 62static struct mce_regs mce_regs[MAX_MCE_REGS];
63static int num_mce_regs; 63static int num_mce_regs;
64static int nmi_virq = NO_IRQ;
64 65
65 66
66static void pas_restart(char *cmd) 67static 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 337out:
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
1441unsigned int mpic_get_one_irq(struct mpic *mpic) 1448static 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
1472unsigned int mpic_get_one_irq(struct mpic *mpic)
1473{
1474 return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_INTACK));
1475}
1476
1465unsigned int mpic_get_irq(void) 1477unsigned 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
1486unsigned 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
1476void mpic_request_ipis(void) 1496void 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
39extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type); 39extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type);
40extern void mpic_set_vector(unsigned int virq, unsigned int vector); 40extern void mpic_set_vector(unsigned int virq, unsigned int vector);
41extern void mpic_end_irq(unsigned int irq);
42extern void mpic_mask_irq(unsigned int irq);
43extern void mpic_unmask_irq(unsigned int irq);
44extern void mpic_set_affinity(unsigned int irq, cpumask_t cpumask); 41extern void mpic_set_affinity(unsigned int irq, cpumask_t cpumask);
45 42
46#endif /* _POWERPC_SYSDEV_MPIC_H */ 43#endif /* _POWERPC_SYSDEV_MPIC_H */