powerpc: Implement tick broadcast IPI as a fixed IPI message
authorSrivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Wed, 26 Feb 2014 00:07:43 +0000 (05:37 +0530)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 5 Mar 2014 04:55:04 +0000 (15:55 +1100)
For scalability and performance reasons, we want the tick broadcast IPIs
to be handled as efficiently as possible. Fixed IPI messages
are one of the most efficient mechanisms available - they are faster than
the smp_call_function mechanism because the IPI handlers are fixed and hence
they don't involve costly operations such as adding IPI handlers to the target
CPU's function queue, acquiring locks for synchronization etc.

Luckily we have an unused IPI message slot, so use that to implement
tick broadcast IPIs efficiently.

Signed-off-by: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
[Functions renamed to tick_broadcast* and Changelog modified by
 Preeti U. Murthy<preeti@linux.vnet.ibm.com>]
Signed-off-by: Preeti U. Murthy <preeti@linux.vnet.ibm.com>
Acked-by: Geoff Levand <geoff@infradead.org> [For the PS3 part]
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/include/asm/smp.h
arch/powerpc/include/asm/time.h
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/time.c
arch/powerpc/platforms/cell/interrupt.c
arch/powerpc/platforms/ps3/smp.c

index 9f7356bf64828fcb468355be83ae5b9d0d1a4900..ff51046b6466993ead747864b115facbd08af6b4 100644 (file)
@@ -120,7 +120,7 @@ extern int cpu_to_core_id(int cpu);
  * in /proc/interrupts will be wrong!!! --Troy */
 #define PPC_MSG_CALL_FUNCTION   0
 #define PPC_MSG_RESCHEDULE      1
-#define PPC_MSG_UNUSED         2
+#define PPC_MSG_TICK_BROADCAST 2
 #define PPC_MSG_DEBUGGER_BREAK  3
 
 /* for irq controllers that have dedicated ipis per message (4) */
index c1f267694acbecd7f072245f57199faa0594e3c6..1d428e6007caa64de18efcd0f5c5291ad53b9f94 100644 (file)
@@ -28,6 +28,7 @@ extern struct clock_event_device decrementer_clockevent;
 struct rtc_time;
 extern void to_tm(int tim, struct rtc_time * tm);
 extern void GregorianDay(struct rtc_time *tm);
+extern void tick_broadcast_ipi_handler(void);
 
 extern void generic_calibrate_decr(void);
 
index ee7d76bfcb4c01c91eeecd91222fd9fe63c80bd8..e2a4232c5871a19056b0b5b666adb540a17b1403 100644 (file)
@@ -35,6 +35,7 @@
 #include <asm/ptrace.h>
 #include <linux/atomic.h>
 #include <asm/irq.h>
+#include <asm/hw_irq.h>
 #include <asm/page.h>
 #include <asm/pgtable.h>
 #include <asm/prom.h>
@@ -145,9 +146,9 @@ static irqreturn_t reschedule_action(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static irqreturn_t unused_action(int irq, void *data)
+static irqreturn_t tick_broadcast_ipi_action(int irq, void *data)
 {
-       /* This slot is unused and hence available for use, if needed */
+       tick_broadcast_ipi_handler();
        return IRQ_HANDLED;
 }
 
@@ -168,14 +169,14 @@ static irqreturn_t debug_ipi_action(int irq, void *data)
 static irq_handler_t smp_ipi_action[] = {
        [PPC_MSG_CALL_FUNCTION] =  call_function_action,
        [PPC_MSG_RESCHEDULE] = reschedule_action,
-       [PPC_MSG_UNUSED] = unused_action,
+       [PPC_MSG_TICK_BROADCAST] = tick_broadcast_ipi_action,
        [PPC_MSG_DEBUGGER_BREAK] = debug_ipi_action,
 };
 
 const char *smp_ipi_name[] = {
        [PPC_MSG_CALL_FUNCTION] =  "ipi call function",
        [PPC_MSG_RESCHEDULE] = "ipi reschedule",
-       [PPC_MSG_UNUSED] = "ipi unused",
+       [PPC_MSG_TICK_BROADCAST] = "ipi tick-broadcast",
        [PPC_MSG_DEBUGGER_BREAK] = "ipi debugger",
 };
 
@@ -251,6 +252,8 @@ irqreturn_t smp_ipi_demux(void)
                        generic_smp_call_function_interrupt();
                if (all & IPI_MESSAGE(PPC_MSG_RESCHEDULE))
                        scheduler_ipi();
+               if (all & IPI_MESSAGE(PPC_MSG_TICK_BROADCAST))
+                       tick_broadcast_ipi_handler();
                if (all & IPI_MESSAGE(PPC_MSG_DEBUGGER_BREAK))
                        debug_ipi_action(0, NULL);
        } while (info->messages);
@@ -289,6 +292,16 @@ void arch_send_call_function_ipi_mask(const struct cpumask *mask)
                do_message_pass(cpu, PPC_MSG_CALL_FUNCTION);
 }
 
+#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
+void tick_broadcast(const struct cpumask *mask)
+{
+       unsigned int cpu;
+
+       for_each_cpu(cpu, mask)
+               do_message_pass(cpu, PPC_MSG_TICK_BROADCAST);
+}
+#endif
+
 #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC)
 void smp_send_debugger_break(void)
 {
index b3dab20acf34abe126e244d34a7dee39021457de..3ff97dbb35be38b3e1ff9b2543f0a003a4e7f3b7 100644 (file)
@@ -825,6 +825,11 @@ static void decrementer_set_mode(enum clock_event_mode mode,
                decrementer_set_next_event(DECREMENTER_MAX, dev);
 }
 
+/* Interrupt handler for the timer broadcast IPI */
+void tick_broadcast_ipi_handler(void)
+{
+}
+
 static void register_decrementer_clockevent(int cpu)
 {
        struct clock_event_device *dec = &per_cpu(decrementers, cpu);
index adf372606a1cf66fb5e9cf5d10caab59345131b6..8a106b4172e0e740dd8cedd7f54b6dc61a5bc270 100644 (file)
@@ -215,7 +215,7 @@ void iic_request_IPIs(void)
 {
        iic_request_ipi(PPC_MSG_CALL_FUNCTION);
        iic_request_ipi(PPC_MSG_RESCHEDULE);
-       iic_request_ipi(PPC_MSG_UNUSED);
+       iic_request_ipi(PPC_MSG_TICK_BROADCAST);
        iic_request_ipi(PPC_MSG_DEBUGGER_BREAK);
 }
 
index 00d1a7c2a5a46c345610b51a2464ead641f6753e..b358bec6c8cb16837aa460bbd6c9908cf9abf093 100644 (file)
@@ -76,7 +76,7 @@ static int __init ps3_smp_probe(void)
 
                BUILD_BUG_ON(PPC_MSG_CALL_FUNCTION    != 0);
                BUILD_BUG_ON(PPC_MSG_RESCHEDULE       != 1);
-               BUILD_BUG_ON(PPC_MSG_UNUSED           != 2);
+               BUILD_BUG_ON(PPC_MSG_TICK_BROADCAST   != 2);
                BUILD_BUG_ON(PPC_MSG_DEBUGGER_BREAK   != 3);
 
                for (i = 0; i < MSG_COUNT; i++) {