aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/platforms/powernv/opal.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-05-10 02:59:18 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2013-05-10 02:59:18 -0400
commit73ed148aea9dc0508be7e30e7a447f55c1b2f378 (patch)
tree2571b5d1851a9f2bef62e92def3608f738748251 /arch/powerpc/platforms/powernv/opal.c
parent1de1455f33709a8afd8d41d26d09739a1148105b (diff)
powerpc/powernv: Improve kexec reliability
We add a machine_shutdown hook that frees the OPAL interrupts (so they get masked at the source and don't fire while kexec'ing) and which triggers an IODA reset on all the PCIe host bridges which will have the effect of blocking all DMAs and subsequent PCIs interrupts. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/platforms/powernv/opal.c')
-rw-r--r--arch/powerpc/platforms/powernv/opal.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 12d9846aa87e..27907cb18b8a 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -15,6 +15,7 @@
15#include <linux/of.h> 15#include <linux/of.h>
16#include <linux/of_platform.h> 16#include <linux/of_platform.h>
17#include <linux/interrupt.h> 17#include <linux/interrupt.h>
18#include <linux/slab.h>
18#include <asm/opal.h> 19#include <asm/opal.h>
19#include <asm/firmware.h> 20#include <asm/firmware.h>
20 21
@@ -28,6 +29,8 @@ struct opal {
28static struct device_node *opal_node; 29static struct device_node *opal_node;
29static DEFINE_SPINLOCK(opal_write_lock); 30static DEFINE_SPINLOCK(opal_write_lock);
30extern u64 opal_mc_secondary_handler[]; 31extern u64 opal_mc_secondary_handler[];
32static unsigned int *opal_irqs;
33static unsigned int opal_irq_count;
31 34
32int __init early_init_dt_scan_opal(unsigned long node, 35int __init early_init_dt_scan_opal(unsigned long node,
33 const char *uname, int depth, void *data) 36 const char *uname, int depth, void *data)
@@ -323,6 +326,8 @@ static int __init opal_init(void)
323 irqs = of_get_property(opal_node, "opal-interrupts", &irqlen); 326 irqs = of_get_property(opal_node, "opal-interrupts", &irqlen);
324 pr_debug("opal: Found %d interrupts reserved for OPAL\n", 327 pr_debug("opal: Found %d interrupts reserved for OPAL\n",
325 irqs ? (irqlen / 4) : 0); 328 irqs ? (irqlen / 4) : 0);
329 opal_irq_count = irqlen / 4;
330 opal_irqs = kzalloc(opal_irq_count * sizeof(unsigned int), GFP_KERNEL);
326 for (i = 0; irqs && i < (irqlen / 4); i++, irqs++) { 331 for (i = 0; irqs && i < (irqlen / 4); i++, irqs++) {
327 unsigned int hwirq = be32_to_cpup(irqs); 332 unsigned int hwirq = be32_to_cpup(irqs);
328 unsigned int irq = irq_create_mapping(NULL, hwirq); 333 unsigned int irq = irq_create_mapping(NULL, hwirq);
@@ -334,7 +339,19 @@ static int __init opal_init(void)
334 if (rc) 339 if (rc)
335 pr_warning("opal: Error %d requesting irq %d" 340 pr_warning("opal: Error %d requesting irq %d"
336 " (0x%x)\n", rc, irq, hwirq); 341 " (0x%x)\n", rc, irq, hwirq);
342 opal_irqs[i] = irq;
337 } 343 }
338 return 0; 344 return 0;
339} 345}
340subsys_initcall(opal_init); 346subsys_initcall(opal_init);
347
348void opal_shutdown(void)
349{
350 unsigned int i;
351
352 for (i = 0; i < opal_irq_count; i++) {
353 if (opal_irqs[i])
354 free_irq(opal_irqs[i], 0);
355 opal_irqs[i] = 0;
356 }
357}