Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

+66 -10
+27 -3
arch/powerpc/platforms/pasemi/setup.c
··· 61 61 62 62 static struct mce_regs mce_regs[MAX_MCE_REGS]; 63 63 static int num_mce_regs; 64 + static int nmi_virq = NO_IRQ; 64 65 65 66 66 67 static void pas_restart(char *cmd) ··· 190 189 unsigned long openpic_addr; 191 190 const unsigned int *opprop; 192 191 int naddr, opplen; 192 + int mpic_flags; 193 + const unsigned int *nmiprop; 193 194 struct mpic *mpic; 194 195 195 196 mpic_node = NULL; ··· 224 221 openpic_addr = of_read_number(opprop, naddr); 225 222 printk(KERN_DEBUG "OpenPIC addr: %lx\n", openpic_addr); 226 223 224 + mpic_flags = MPIC_PRIMARY | MPIC_LARGE_VECTORS; 225 + 226 + nmiprop = of_get_property(mpic_node, "nmi-source", NULL); 227 + if (nmiprop) 228 + mpic_flags |= MPIC_ENABLE_MCK; 229 + 227 230 mpic = mpic_alloc(mpic_node, openpic_addr, 228 - MPIC_PRIMARY|MPIC_LARGE_VECTORS, 229 - 0, 0, "PASEMI-OPIC"); 231 + mpic_flags, 0, 0, "PASEMI-OPIC"); 230 232 BUG_ON(!mpic); 231 233 232 234 mpic_assign_isu(mpic, 0, openpic_addr + 0x10000); 233 235 mpic_init(mpic); 236 + /* The NMI/MCK source needs to be prio 15 */ 237 + if (nmiprop) { 238 + nmi_virq = irq_create_mapping(NULL, *nmiprop); 239 + mpic_irq_set_priority(nmi_virq, 15); 240 + set_irq_type(nmi_virq, IRQ_TYPE_EDGE_RISING); 241 + mpic_unmask_irq(nmi_virq); 242 + } 243 + 234 244 of_node_put(mpic_node); 235 245 of_node_put(root); 236 246 } ··· 263 247 264 248 srr0 = regs->nip; 265 249 srr1 = regs->msr; 250 + 251 + if (mpic_get_mcirq() == nmi_virq) { 252 + printk(KERN_ERR "NMI delivered\n"); 253 + debugger(regs); 254 + mpic_end_irq(nmi_virq); 255 + goto out; 256 + } 257 + 266 258 dsisr = mfspr(SPRN_DSISR); 267 259 printk(KERN_ERR "Machine Check on CPU %d\n", cpu); 268 260 printk(KERN_ERR "SRR0 0x%016lx SRR1 0x%016lx\n", srr0, srr1); ··· 334 310 } 335 311 } 336 312 337 - 313 + out: 338 314 /* SRR1[62] is from MSR[62] if recoverable, so pass that back */ 339 315 return !!(srr1 & 0x2); 340 316 }
+23 -3
arch/powerpc/sysdev/mpic.c
··· 83 83 MPIC_CPU_WHOAMI, 84 84 MPIC_CPU_INTACK, 85 85 MPIC_CPU_EOI, 86 + MPIC_CPU_MCACK, 86 87 87 88 MPIC_IRQ_BASE, 88 89 MPIC_IRQ_STRIDE, ··· 122 121 TSI108_CPU_WHOAMI, 123 122 TSI108_CPU_INTACK, 124 123 TSI108_CPU_EOI, 124 + TSI108_CPU_MCACK, 125 125 126 126 TSI108_IRQ_BASE, 127 127 TSI108_IRQ_STRIDE, ··· 1128 1126 mb(); 1129 1127 } 1130 1128 1129 + if (flags & MPIC_ENABLE_MCK) 1130 + mpic_write(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0), 1131 + mpic_read(mpic->gregs, MPIC_INFO(GREG_GLOBAL_CONF_0)) 1132 + | MPIC_GREG_GCONF_MCK); 1133 + 1131 1134 /* Read feature register, calculate num CPUs and, for non-ISU 1132 1135 * MPICs, num sources as well. On ISU MPICs, sources are counted 1133 1136 * as ISUs are added ··· 1445 1438 mpic_physmask(cpu_mask & cpus_addr(cpu_online_map)[0])); 1446 1439 } 1447 1440 1448 - unsigned int mpic_get_one_irq(struct mpic *mpic) 1441 + static unsigned int _mpic_get_one_irq(struct mpic *mpic, int reg) 1449 1442 { 1450 1443 u32 src; 1451 1444 1452 - src = mpic_cpu_read(MPIC_INFO(CPU_INTACK)) & MPIC_INFO(VECPRI_VECTOR_MASK); 1445 + src = mpic_cpu_read(reg) & MPIC_INFO(VECPRI_VECTOR_MASK); 1453 1446 #ifdef DEBUG_LOW 1454 - DBG("%s: get_one_irq(): %d\n", mpic->name, src); 1447 + DBG("%s: get_one_irq(reg 0x%x): %d\n", mpic->name, reg, src); 1455 1448 #endif 1456 1449 if (unlikely(src == mpic->spurious_vec)) { 1457 1450 if (mpic->flags & MPIC_SPV_EOI) ··· 1469 1462 return irq_linear_revmap(mpic->irqhost, src); 1470 1463 } 1471 1464 1465 + unsigned int mpic_get_one_irq(struct mpic *mpic) 1466 + { 1467 + return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_INTACK)); 1468 + } 1469 + 1472 1470 unsigned int mpic_get_irq(void) 1473 1471 { 1474 1472 struct mpic *mpic = mpic_primary; ··· 1483 1471 return mpic_get_one_irq(mpic); 1484 1472 } 1485 1473 1474 + unsigned int mpic_get_mcirq(void) 1475 + { 1476 + struct mpic *mpic = mpic_primary; 1477 + 1478 + BUG_ON(mpic == NULL); 1479 + 1480 + return _mpic_get_one_irq(mpic, MPIC_INFO(CPU_MCACK)); 1481 + } 1486 1482 1487 1483 #ifdef CONFIG_SMP 1488 1484 void mpic_request_ipis(void)
-3
arch/powerpc/sysdev/mpic.h
··· 38 38 39 39 extern int mpic_set_irq_type(unsigned int virq, unsigned int flow_type); 40 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 41 extern void mpic_set_affinity(unsigned int irq, cpumask_t cpumask); 45 42 46 43 #endif /* _POWERPC_SYSDEV_MPIC_H */
+16 -1
include/asm-powerpc/mpic.h
··· 23 23 #define MPIC_GREG_GCONF_RESET 0x80000000 24 24 #define MPIC_GREG_GCONF_8259_PTHROU_DIS 0x20000000 25 25 #define MPIC_GREG_GCONF_BASE_MASK 0x000fffff 26 + #define MPIC_GREG_GCONF_MCK 0x08000000 26 27 #define MPIC_GREG_GLOBAL_CONF_1 0x00030 27 28 #define MPIC_GREG_GLOBAL_CONF_1_SIE 0x08000000 28 29 #define MPIC_GREG_GLOBAL_CONF_1_CLK_RATIO_MASK 0x70000000 ··· 79 78 #define MPIC_CPU_WHOAMI_MASK 0x0000001f 80 79 #define MPIC_CPU_INTACK 0x000a0 81 80 #define MPIC_CPU_EOI 0x000b0 81 + #define MPIC_CPU_MCACK 0x000c0 82 82 83 83 /* 84 84 * Per-source registers ··· 143 141 #define TSI108_CPU_WHOAMI 0xffffffff 144 142 #define TSI108_CPU_INTACK 0x00004 145 143 #define TSI108_CPU_EOI 0x00008 144 + #define TSI108_CPU_MCACK 0x00004 /* Doesn't really exist here */ 146 145 147 146 /* 148 147 * Per-source registers ··· 186 183 MPIC_IDX_CPU_WHOAMI, 187 184 MPIC_IDX_CPU_INTACK, 188 185 MPIC_IDX_CPU_EOI, 186 + MPIC_IDX_CPU_MCACK, 189 187 190 188 MPIC_IDX_IRQ_BASE, 191 189 MPIC_IDX_IRQ_STRIDE, ··· 348 344 #define MPIC_USES_DCR 0x00000080 349 345 /* MPIC has 11-bit vector fields (or larger) */ 350 346 #define MPIC_LARGE_VECTORS 0x00000100 347 + /* Enable delivery of prio 15 interrupts as MCK instead of EE */ 348 + #define MPIC_ENABLE_MCK 0x00000200 351 349 352 350 /* MPIC HW modification ID */ 353 351 #define MPIC_REGSET_MASK 0xf0000000 ··· 453 447 /* Send a message (IPI) to a given target (cpu number or MSG_*) */ 454 448 void smp_mpic_message_pass(int target, int msg); 455 449 450 + /* Unmask a specific virq */ 451 + extern void mpic_unmask_irq(unsigned int irq); 452 + /* Mask a specific virq */ 453 + extern void mpic_mask_irq(unsigned int irq); 454 + /* EOI a specific virq */ 455 + extern void mpic_end_irq(unsigned int irq); 456 + 456 457 /* Fetch interrupt from a given mpic */ 457 458 extern unsigned int mpic_get_one_irq(struct mpic *mpic); 458 - /* This one gets to the primary mpic */ 459 + /* This one gets from the primary mpic */ 459 460 extern unsigned int mpic_get_irq(void); 461 + /* Fetch Machine Check interrupt from primary mpic */ 462 + extern unsigned int mpic_get_mcirq(void); 460 463 461 464 /* Set the EPIC clock ratio */ 462 465 void mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio);