aboutsummaryrefslogtreecommitdiffstats
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
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>
-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
-rw-r--r--include/asm-powerpc/mpic.h17
4 files changed, 66 insertions, 10 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 */
diff --git a/include/asm-powerpc/mpic.h b/include/asm-powerpc/mpic.h
index ae84dde3bc7f..e7ac8109b6e7 100644
--- a/include/asm-powerpc/mpic.h
+++ b/include/asm-powerpc/mpic.h
@@ -23,6 +23,7 @@
23#define MPIC_GREG_GCONF_RESET 0x80000000 23#define MPIC_GREG_GCONF_RESET 0x80000000
24#define MPIC_GREG_GCONF_8259_PTHROU_DIS 0x20000000 24#define MPIC_GREG_GCONF_8259_PTHROU_DIS 0x20000000
25#define MPIC_GREG_GCONF_BASE_MASK 0x000fffff 25#define MPIC_GREG_GCONF_BASE_MASK 0x000fffff
26#define MPIC_GREG_GCONF_MCK 0x08000000
26#define MPIC_GREG_GLOBAL_CONF_1 0x00030 27#define MPIC_GREG_GLOBAL_CONF_1 0x00030
27#define MPIC_GREG_GLOBAL_CONF_1_SIE 0x08000000 28#define MPIC_GREG_GLOBAL_CONF_1_SIE 0x08000000
28#define MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK 0x70000000 29#define MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK 0x70000000
@@ -78,6 +79,7 @@
78#define MPIC_CPU_WHOAMI_MASK 0x0000001f 79#define MPIC_CPU_WHOAMI_MASK 0x0000001f
79#define MPIC_CPU_INTACK 0x000a0 80#define MPIC_CPU_INTACK 0x000a0
80#define MPIC_CPU_EOI 0x000b0 81#define MPIC_CPU_EOI 0x000b0
82#define MPIC_CPU_MCACK 0x000c0
81 83
82/* 84/*
83 * Per-source registers 85 * Per-source registers
@@ -141,6 +143,7 @@
141#define TSI108_CPU_WHOAMI 0xffffffff 143#define TSI108_CPU_WHOAMI 0xffffffff
142#define TSI108_CPU_INTACK 0x00004 144#define TSI108_CPU_INTACK 0x00004
143#define TSI108_CPU_EOI 0x00008 145#define TSI108_CPU_EOI 0x00008
146#define TSI108_CPU_MCACK 0x00004 /* Doesn't really exist here */
144 147
145/* 148/*
146 * Per-source registers 149 * Per-source registers
@@ -183,6 +186,7 @@ enum {
183 MPIC_IDX_CPU_WHOAMI, 186 MPIC_IDX_CPU_WHOAMI,
184 MPIC_IDX_CPU_INTACK, 187 MPIC_IDX_CPU_INTACK,
185 MPIC_IDX_CPU_EOI, 188 MPIC_IDX_CPU_EOI,
189 MPIC_IDX_CPU_MCACK,
186 190
187 MPIC_IDX_IRQ_BASE, 191 MPIC_IDX_IRQ_BASE,
188 MPIC_IDX_IRQ_STRIDE, 192 MPIC_IDX_IRQ_STRIDE,
@@ -344,6 +348,8 @@ struct mpic
344#define MPIC_USES_DCR 0x00000080 348#define MPIC_USES_DCR 0x00000080
345/* MPIC has 11-bit vector fields (or larger) */ 349/* MPIC has 11-bit vector fields (or larger) */
346#define MPIC_LARGE_VECTORS 0x00000100 350#define MPIC_LARGE_VECTORS 0x00000100
351/* Enable delivery of prio 15 interrupts as MCK instead of EE */
352#define MPIC_ENABLE_MCK 0x00000200
347 353
348/* MPIC HW modification ID */ 354/* MPIC HW modification ID */
349#define MPIC_REGSET_MASK 0xf0000000 355#define MPIC_REGSET_MASK 0xf0000000
@@ -447,10 +453,19 @@ extern void mpic_send_ipi(unsigned int ipi_no, unsigned int cpu_mask);
447/* Send a message (IPI) to a given target (cpu number or MSG_*) */ 453/* Send a message (IPI) to a given target (cpu number or MSG_*) */
448void smp_mpic_message_pass(int target, int msg); 454void smp_mpic_message_pass(int target, int msg);
449 455
456/* Unmask a specific virq */
457extern void mpic_unmask_irq(unsigned int irq);
458/* Mask a specific virq */
459extern void mpic_mask_irq(unsigned int irq);
460/* EOI a specific virq */
461extern void mpic_end_irq(unsigned int irq);
462
450/* Fetch interrupt from a given mpic */ 463/* Fetch interrupt from a given mpic */
451extern unsigned int mpic_get_one_irq(struct mpic *mpic); 464extern unsigned int mpic_get_one_irq(struct mpic *mpic);
452/* This one gets to the primary mpic */ 465/* This one gets from the primary mpic */
453extern unsigned int mpic_get_irq(void); 466extern unsigned int mpic_get_irq(void);
467/* Fetch Machine Check interrupt from primary mpic */
468extern unsigned int mpic_get_mcirq(void);
454 469
455/* Set the EPIC clock ratio */ 470/* Set the EPIC clock ratio */
456void mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio); 471void mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio);