PPC_G_DBELL_MC = 4,     /* guest mcheck doorbell */
 };
 
-extern void doorbell_message_pass(int cpu, int msg);
+extern void doorbell_cause_ipi(int cpu, unsigned long data);
 extern void doorbell_exception(struct pt_regs *regs);
-extern void doorbell_check_self(void);
 extern void doorbell_setup_this_cpu(void);
 
 static inline void ppc_msgsnd(enum ppc_dbell type, u32 flags, u32 tag)
 
 #include <linux/threads.h>
 #include <linux/cpumask.h>
 #include <linux/kernel.h>
+#include <linux/irqreturn.h>
 
 #ifndef __ASSEMBLY__
 
 
 struct smp_ops_t {
        void  (*message_pass)(int cpu, int msg);
+       void  (*cause_ipi)(int cpu, unsigned long data);
        int   (*probe)(void);
        int   (*kick_cpu)(int nr);
        void  (*setup_cpu)(int nr);
 };
 
 extern void smp_send_debugger_break(void);
-extern void smp_message_recv(int);
 extern void start_secondary_resume(void);
 extern void __devinit smp_generic_give_timebase(void);
 extern void __devinit smp_generic_take_timebase(void);
 #define PPC_MSG_CALL_FUNC_SINGLE       2
 #define PPC_MSG_DEBUGGER_BREAK  3
 
-/*
- * irq controllers that have dedicated ipis per message and don't
- * need additional code in the action handler may use this
- */
+/* for irq controllers that have dedicated ipis per message (4) */
 extern int smp_request_message_ipi(int virq, int message);
 extern const char *smp_ipi_name[];
 
+/* for irq controllers with only a single ipi */
+extern void smp_muxed_ipi_set_data(int cpu, unsigned long data);
+extern void smp_muxed_ipi_message_pass(int cpu, int msg);
+extern void smp_muxed_ipi_resend(void);
+extern irqreturn_t smp_ipi_demux(void);
+
 void smp_init_iSeries(void);
 void smp_init_pSeries(void);
 void smp_init_cell(void);
 extern unsigned long __secondary_hold_acknowledge;
 extern char __secondary_hold;
 
+extern irqreturn_t debug_ipi_action(int irq, void *data);
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
 
        void (*teardown_cpu)(void);
        void (*flush_ipi)(void);
 #ifdef CONFIG_SMP
-       void (*message_pass)(int cpu, int msg);
+       void (*cause_ipi)(int cpu, unsigned long data);
        irq_handler_t ipi_action;
 #endif
 };
 
 #include <linux/kernel.h>
 #include <linux/smp.h>
 #include <linux/threads.h>
-#include <linux/percpu.h>
+#include <linux/hardirq.h>
 
 #include <asm/dbell.h>
 #include <asm/irq_regs.h>
 
 #ifdef CONFIG_SMP
-struct doorbell_cpu_info {
-       unsigned long   messages;       /* current messages bits */
-       unsigned int    tag;            /* tag value */
-};
-
-static DEFINE_PER_CPU(struct doorbell_cpu_info, doorbell_cpu_info);
-
 void doorbell_setup_this_cpu(void)
 {
-       struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info);
+       unsigned long tag = mfspr(SPRN_PIR) & 0x3fff;
 
-       info->messages = 0;
-       info->tag = mfspr(SPRN_PIR) & 0x3fff;
+       smp_muxed_ipi_set_data(smp_processor_id(), tag);
 }
 
-void doorbell_message_pass(int cpu, int msg)
+void doorbell_cause_ipi(int cpu, unsigned long data)
 {
-       struct doorbell_cpu_info *info;
-
-       info = &per_cpu(doorbell_cpu_info, cpu);
-       set_bit(msg, &info->messages);
-       ppc_msgsnd(PPC_DBELL, 0, info->tag);
+       ppc_msgsnd(PPC_DBELL, 0, data);
 }
 
 void doorbell_exception(struct pt_regs *regs)
 {
        struct pt_regs *old_regs = set_irq_regs(regs);
-       struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info);
-       int msg;
 
-       /* Warning: regs can be NULL when called from irq enable */
+       irq_enter();
 
-       if (!info->messages || (num_online_cpus() < 2))
-               goto out;
+       smp_ipi_demux();
 
-       for (msg = 0; msg < 4; msg++)
-               if (test_and_clear_bit(msg, &info->messages))
-                       smp_message_recv(msg);
-
-out:
+       irq_exit();
        set_irq_regs(old_regs);
 }
-
-void doorbell_check_self(void)
-{
-       struct doorbell_cpu_info *info = &__get_cpu_var(doorbell_cpu_info);
-
-       if (!info->messages)
-               return;
-
-       ppc_msgsnd(PPC_DBELL, 0, info->tag);
-}
-
 #else /* CONFIG_SMP */
 void doorbell_exception(struct pt_regs *regs)
 {
 
 #include <asm/ptrace.h>
 #include <asm/machdep.h>
 #include <asm/udbg.h>
-#include <asm/dbell.h>
 #include <asm/smp.h>
 
 #ifdef CONFIG_PPC64
 
 #if defined(CONFIG_BOOKE) && defined(CONFIG_SMP)
        /* Check for pending doorbell interrupts and resend to ourself */
-       doorbell_check_self();
+       if (cpu_has_feature(CPU_FTR_DBELL))
+               smp_muxed_ipi_resend();
 #endif
 
        /*
 
 }
 #endif
 
-void smp_message_recv(int msg)
-{
-       switch(msg) {
-       case PPC_MSG_CALL_FUNCTION:
-               generic_smp_call_function_interrupt();
-               break;
-       case PPC_MSG_RESCHEDULE:
-               /* we notice need_resched on exit */
-               break;
-       case PPC_MSG_CALL_FUNC_SINGLE:
-               generic_smp_call_function_single_interrupt();
-               break;
-       case PPC_MSG_DEBUGGER_BREAK:
-               if (crash_ipi_function_ptr) {
-                       crash_ipi_function_ptr(get_irq_regs());
-                       break;
-               }
-#ifdef CONFIG_DEBUGGER
-               debugger_ipi(get_irq_regs());
-               break;
-#endif /* CONFIG_DEBUGGER */
-               /* FALLTHROUGH */
-       default:
-               printk("SMP %d: smp_message_recv(): unknown msg %d\n",
-                      smp_processor_id(), msg);
-               break;
-       }
-}
-
 static irqreturn_t call_function_action(int irq, void *data)
 {
        generic_smp_call_function_interrupt();
        return IRQ_HANDLED;
 }
 
-static irqreturn_t debug_ipi_action(int irq, void *data)
+irqreturn_t debug_ipi_action(int irq, void *data)
 {
-       smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
+       if (crash_ipi_function_ptr) {
+               crash_ipi_function_ptr(get_irq_regs());
+               return IRQ_HANDLED;
+       }
+
+#ifdef CONFIG_DEBUGGER
+       debugger_ipi(get_irq_regs());
+#endif /* CONFIG_DEBUGGER */
+
        return IRQ_HANDLED;
 }
 
        return err;
 }
 
+struct cpu_messages {
+       unsigned long messages;         /* current messages bits */
+       unsigned long data;             /* data for cause ipi */
+};
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct cpu_messages, ipi_message);
+
+void smp_muxed_ipi_set_data(int cpu, unsigned long data)
+{
+       struct cpu_messages *info = &per_cpu(ipi_message, cpu);
+
+       info->data = data;
+}
+
+void smp_muxed_ipi_message_pass(int cpu, int msg)
+{
+       struct cpu_messages *info = &per_cpu(ipi_message, cpu);
+       unsigned long *tgt = &info->messages;
+
+       set_bit(msg, tgt);
+       mb();
+       smp_ops->cause_ipi(cpu, info->data);
+}
+
+void smp_muxed_ipi_resend(void)
+{
+       struct cpu_messages *info = &__get_cpu_var(ipi_message);
+       unsigned long *tgt = &info->messages;
+
+       if (*tgt)
+               smp_ops->cause_ipi(smp_processor_id(), info->data);
+}
+
+irqreturn_t smp_ipi_demux(void)
+{
+       struct cpu_messages *info = &__get_cpu_var(ipi_message);
+       unsigned long *tgt = &info->messages;
+
+       mb();   /* order any irq clear */
+       while (*tgt) {
+               if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt))
+                       generic_smp_call_function_interrupt();
+               if (test_and_clear_bit(PPC_MSG_RESCHEDULE, tgt))
+                       reschedule_action(0, NULL); /* upcoming sched hook */
+               if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, tgt))
+                       generic_smp_call_function_single_interrupt();
+#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
+               if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, tgt))
+                       debug_ipi_action(0, NULL);
+#endif
+       }
+       return IRQ_HANDLED;
+}
+
 void smp_send_reschedule(int cpu)
 {
        if (likely(smp_ops))
 
                smp_85xx_ops.message_pass = smp_mpic_message_pass;
        }
 
-       if (cpu_has_feature(CPU_FTR_DBELL))
-               smp_85xx_ops.message_pass = doorbell_message_pass;
+       if (cpu_has_feature(CPU_FTR_DBELL)) {
+               smp_85xx_ops.message_pass = smp_muxed_ipi_message_pass;
+               smp_85xx_ops.cause_ipi = doorbell_cause_ipi;
+       }
 
        BUG_ON(!smp_85xx_ops.message_pass);
 
 
 {
        int ipi = (int)(long)dev_id;
 
-       smp_message_recv(ipi);
-
+       switch(ipi) {
+       case PPC_MSG_CALL_FUNCTION:
+               generic_smp_call_function_interrupt();
+               break;
+       case PPC_MSG_RESCHEDULE:
+               /* Upcoming sched hook */
+               break;
+       case PPC_MSG_CALL_FUNC_SINGLE:
+               generic_smp_call_function_single_interrupt();
+               break;
+       case PPC_MSG_DEBUGGER_BREAK:
+               debug_ipi_action(0, NULL);
+               break;
+       }
        return IRQ_HANDLED;
 }
 static void iic_request_ipi(int ipi, const char *name)
 
 #include "irq.h"
 #include "pci.h"
 #include "call_pci.h"
-#include "smp.h"
 
 #ifdef CONFIG_PCI
 
 #ifdef CONFIG_SMP
        if (get_lppaca()->int_dword.fields.ipi_cnt) {
                get_lppaca()->int_dword.fields.ipi_cnt = 0;
-               iSeries_smp_message_recv();
+               smp_ipi_demux();
        }
 #endif /* CONFIG_SMP */
        if (hvlpevent_is_pending())
 
 #include <asm/cputable.h>
 #include <asm/system.h>
 
-#include "smp.h"
-
-static unsigned long iSeries_smp_message[NR_CPUS];
-
-void iSeries_smp_message_recv(void)
-{
-       int cpu = smp_processor_id();
-       int msg;
-
-       if (num_online_cpus() < 2)
-               return;
-
-       for (msg = 0; msg < 4; msg++)
-               if (test_and_clear_bit(msg, &iSeries_smp_message[cpu]))
-                       smp_message_recv(msg);
-}
-
-static void smp_iSeries_message_pass(int cpu, int msg)
+static void smp_iSeries_cause_ipi(int cpu, unsigned long data)
 {
-       set_bit(msg, &iSeries_smp_message[cpu]);
        HvCall_sendIPI(&(paca[cpu]));
 }
 
 }
 
 static struct smp_ops_t iSeries_smp_ops = {
-       .message_pass = smp_iSeries_message_pass,
+       .message_pass = smp_muxed_ipi_message_pass,
+       .cause_ipi    = smp_iSeries_cause_ipi,
        .probe        = smp_iSeries_probe,
        .kick_cpu     = smp_iSeries_kick_cpu,
        .setup_cpu    = smp_iSeries_setup_cpu,
 
+++ /dev/null
-#ifndef _PLATFORMS_ISERIES_SMP_H
-#define _PLATFORMS_ISERIES_SMP_H
-
-extern void iSeries_smp_message_recv(void);
-
-#endif /* _PLATFORMS_ISERIES_SMP_H */
 
 /*
  * On powersurge (old SMP powermac architecture) we don't have
  * separate IPIs for separate messages like openpic does.  Instead
- * we have a bitmap for each processor, where a 1 bit means that
- * the corresponding message is pending for that processor.
- * Ideally each cpu's entry would be in a different cache line.
+ * use the generic demux helpers
  *  -- paulus.
  */
-static unsigned long psurge_smp_message[NR_CPUS];
-
 void psurge_smp_message_recv(void)
 {
-       int cpu = smp_processor_id();
-       int msg;
-
-       /* clear interrupt */
-       psurge_clr_ipi(cpu);
-
-       if (num_online_cpus() < 2)
-               return;
-
-       /* make sure there is a message there */
-       for (msg = 0; msg < 4; msg++)
-               if (test_and_clear_bit(msg, &psurge_smp_message[cpu]))
-                       smp_message_recv(msg);
+       psurge_clr_ipi(smp_processor_id());
+       smp_ipi_demux();
 }
 
 irqreturn_t psurge_primary_intr(int irq, void *d)
        return IRQ_HANDLED;
 }
 
-static void smp_psurge_message_pass(int cpu, int msg)
+static void smp_psurge_cause_ipi(int cpu, unsigned long data)
 {
-       set_bit(msg, &psurge_smp_message[cpu]);
        psurge_set_ipi(cpu);
 }
 
 
 /* PowerSurge-style Macs */
 struct smp_ops_t psurge_smp_ops = {
-       .message_pass   = smp_psurge_message_pass,
+       .message_pass   = smp_muxed_ipi_message_pass,
+       .cause_ipi      = smp_psurge_cause_ipi,
        .probe          = smp_psurge_probe,
        .kick_cpu       = smp_psurge_kick_cpu,
        .setup_cpu      = smp_psurge_setup_cpu,
 
 };
 
 static struct smp_ops_t pSeries_xics_smp_ops = {
-       .message_pass   = NULL, /* Filled at runtime by xics_smp_probe() */
+       .message_pass   = smp_muxed_ipi_message_pass,
+       .cause_ipi      = NULL, /* Filled at runtime by xics_smp_probe() */
        .probe          = xics_smp_probe,
        .kick_cpu       = smp_pSeries_kick_cpu,
        .setup_cpu      = smp_xics_setup_cpu,
 
 }
 
 static struct smp_ops_t a2_smp_ops = {
-       .message_pass   = doorbell_message_pass,
+       .message_pass   = smp_muxed_ipi_message_pass,
+       .cause_ipi      = doorbell_cause_ipi,
        .probe          = smp_a2_probe,
        .kick_cpu       = smp_a2_kick_cpu,
        .setup_cpu      = smp_a2_setup_cpu,
 
 
 #ifdef CONFIG_SMP
 
-static void icp_hv_message_pass(int cpu, int msg)
+static void icp_hv_cause_ipi(int cpu, unsigned long data)
 {
-       unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
-
-       set_bit(msg, tgt);
-       mb();
        icp_hv_set_qirr(cpu, IPI_PRIORITY);
 }
 
 
        icp_hv_set_qirr(cpu, 0xff);
 
-       return xics_ipi_dispatch(cpu);
+       return smp_ipi_demux();
 }
 
 #endif /* CONFIG_SMP */
        .flush_ipi      = icp_hv_flush_ipi,
 #ifdef CONFIG_SMP
        .ipi_action     = icp_hv_ipi_action,
-       .message_pass   = icp_hv_message_pass,
+       .cause_ipi      = icp_hv_cause_ipi,
 #endif
 };
 
 
 
 #ifdef CONFIG_SMP
 
-static void icp_native_message_pass(int cpu, int msg)
+static void icp_native_cause_ipi(int cpu, unsigned long data)
 {
-       unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
-
-       set_bit(msg, tgt);
-       mb();
        icp_native_set_qirr(cpu, IPI_PRIORITY);
 }
 
 
        icp_native_set_qirr(cpu, 0xff);
 
-       return xics_ipi_dispatch(cpu);
+       return smp_ipi_demux();
 }
 
 #endif /* CONFIG_SMP */
        .flush_ipi      = icp_native_flush_ipi,
 #ifdef CONFIG_SMP
        .ipi_action     = icp_native_ipi_action,
-       .message_pass   = icp_native_message_pass,
+       .cause_ipi      = icp_native_cause_ipi,
 #endif
 };
 
 
 
 #ifdef CONFIG_SMP
 
-DEFINE_PER_CPU_SHARED_ALIGNED(unsigned long, xics_ipi_message);
-
-irqreturn_t xics_ipi_dispatch(int cpu)
-{
-       unsigned long *tgt = &per_cpu(xics_ipi_message, cpu);
-
-       mb();   /* order mmio clearing qirr */
-       while (*tgt) {
-               if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, tgt)) {
-                       smp_message_recv(PPC_MSG_CALL_FUNCTION);
-               }
-               if (test_and_clear_bit(PPC_MSG_RESCHEDULE, tgt)) {
-                       smp_message_recv(PPC_MSG_RESCHEDULE);
-               }
-               if (test_and_clear_bit(PPC_MSG_CALL_FUNC_SINGLE, tgt)) {
-                       smp_message_recv(PPC_MSG_CALL_FUNC_SINGLE);
-               }
-#if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
-               if (test_and_clear_bit(PPC_MSG_DEBUGGER_BREAK, tgt)) {
-                       smp_message_recv(PPC_MSG_DEBUGGER_BREAK);
-               }
-#endif
-       }
-       return IRQ_HANDLED;
-}
-
 static void xics_request_ipi(void)
 {
        unsigned int ipi;
 
 int __init xics_smp_probe(void)
 {
-       /* Setup message_pass callback  based on which ICP is used */
-       smp_ops->message_pass = icp_ops->message_pass;
+       /* Setup cause_ipi callback  based on which ICP is used */
+       smp_ops->cause_ipi = icp_ops->cause_ipi;
 
        /* Register all the IPIs */
        xics_request_ipi();