]> asedeno.scripts.mit.edu Git - linux.git/blobdiff - arch/powerpc/sysdev/xics/icp-opal.c
Merge branches 'pm-core', 'pm-qos', 'pm-domains' and 'pm-opp'
[linux.git] / arch / powerpc / sysdev / xics / icp-opal.c
index 60c57657c772fef576e5c4703dfb2a17203978a7..f9670eabfcfa70ca338aa0c5f2e10217803c7162 100644 (file)
@@ -120,18 +120,49 @@ static void icp_opal_cause_ipi(int cpu, unsigned long data)
 {
        int hw_cpu = get_hard_smp_processor_id(cpu);
 
+       kvmppc_set_host_ipi(cpu, 1);
        opal_int_set_mfrr(hw_cpu, IPI_PRIORITY);
 }
 
 static irqreturn_t icp_opal_ipi_action(int irq, void *dev_id)
 {
-       int hw_cpu = hard_smp_processor_id();
+       int cpu = smp_processor_id();
 
-       opal_int_set_mfrr(hw_cpu, 0xff);
+       kvmppc_set_host_ipi(cpu, 0);
+       opal_int_set_mfrr(get_hard_smp_processor_id(cpu), 0xff);
 
        return smp_ipi_demux();
 }
 
+/*
+ * Called when an interrupt is received on an off-line CPU to
+ * clear the interrupt, so that the CPU can go back to nap mode.
+ */
+void icp_opal_flush_interrupt(void)
+{
+       unsigned int xirr;
+       unsigned int vec;
+
+       do {
+               xirr = icp_opal_get_xirr();
+               vec = xirr & 0x00ffffff;
+               if (vec == XICS_IRQ_SPURIOUS)
+                       break;
+               if (vec == XICS_IPI) {
+                       /* Clear pending IPI */
+                       int cpu = smp_processor_id();
+                       kvmppc_set_host_ipi(cpu, 0);
+                       opal_int_set_mfrr(get_hard_smp_processor_id(cpu), 0xff);
+               } else {
+                       pr_err("XICS: hw interrupt 0x%x to offline cpu, "
+                              "disabling\n", vec);
+                       xics_mask_unknown_vec(vec);
+               }
+
+               /* EOI the interrupt */
+       } while (opal_int_eoi(xirr) > 0);
+}
+
 #endif /* CONFIG_SMP */
 
 static const struct icp_ops icp_opal_ops = {