powerpc: generic clockevents broadcast receiver call tick_receive_broadcast
authorNicholas Piggin <npiggin@gmail.com>
Fri, 4 May 2018 17:19:31 +0000 (03:19 +1000)
committerMichael Ellerman <mpe@ellerman.id.au>
Sun, 3 Jun 2018 10:40:27 +0000 (20:40 +1000)
The broadcast tick recipient can call tick_receive_broadcast rather
than re-running the full timer interrupt.

It does not have to check for the next event time, because the sender
already determined the timer has expired. It does not have to test
irq_work_pending, because that's a direct decrementer interrupt and
does not go through the clock events subsystem. And it does not have
to read PURR because that was removed with the previous patch.

This results in no code size change, but both the decrementer and
broadcast path lengths are reduced.

Cc: Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com>
Cc: Preeti U Murthy <preeti@linux.vnet.ibm.com>
Signed-off-by: Nicholas Piggin <npiggin@gmail.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
arch/powerpc/include/asm/hw_irq.h
arch/powerpc/include/asm/time.h
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/time.c

index 3be8766427efe5fae790837b6c286c025b93880e..9aec7237f8c24e4189d6e566b4a60e9728971d0d 100644 (file)
@@ -55,6 +55,7 @@ extern void replay_system_reset(void);
 extern void __replay_interrupt(unsigned int vector);
 
 extern void timer_interrupt(struct pt_regs *);
+extern void timer_broadcast_interrupt(void);
 extern void performance_monitor_exception(struct pt_regs *regs);
 extern void WatchdogException(struct pt_regs *regs);
 extern void unknown_exception(struct pt_regs *regs);
index c965c79765c4e32f07188edc44fe09662c2ebeb3..69b89f941252637ea457cb2f9ffdfc8c26e0cdc8 100644 (file)
@@ -28,7 +28,6 @@ extern struct clock_event_device decrementer_clockevent;
 
 struct rtc_time;
 extern void to_tm(int tim, struct rtc_time * tm);
-extern void tick_broadcast_ipi_handler(void);
 
 extern void generic_calibrate_decr(void);
 extern void hdec_interrupt(struct pt_regs *regs);
index c96f8fbc19423ab39956dde4b519ccb25ac798c0..f66eec89c14cb4e83dd339c305812e7f9c7e93ec 100644 (file)
@@ -158,7 +158,7 @@ static irqreturn_t reschedule_action(int irq, void *data)
 
 static irqreturn_t tick_broadcast_ipi_action(int irq, void *data)
 {
-       tick_broadcast_ipi_handler();
+       timer_broadcast_interrupt();
        return IRQ_HANDLED;
 }
 
@@ -279,7 +279,7 @@ irqreturn_t smp_ipi_demux_relaxed(void)
                if (all & IPI_MESSAGE(PPC_MSG_RESCHEDULE))
                        scheduler_ipi();
                if (all & IPI_MESSAGE(PPC_MSG_TICK_BROADCAST))
-                       tick_broadcast_ipi_handler();
+                       timer_broadcast_interrupt();
 #ifdef CONFIG_NMI_IPI
                if (all & IPI_MESSAGE(PPC_MSG_NMI_IPI))
                        nmi_ipi_action(0, NULL);
index 1fe6a24357e7d0030491382db337332b2e134b7e..ad876906f847ba47fdb877f37e7fe8a4fb155a8e 100644 (file)
@@ -567,47 +567,16 @@ void arch_irq_work_raise(void)
 
 #endif /* CONFIG_IRQ_WORK */
 
-static void __timer_interrupt(void)
-{
-       struct pt_regs *regs = get_irq_regs();
-       u64 *next_tb = this_cpu_ptr(&decrementers_next_tb);
-       struct clock_event_device *evt = this_cpu_ptr(&decrementers);
-       u64 now;
-
-       trace_timer_interrupt_entry(regs);
-
-       if (test_irq_work_pending()) {
-               clear_irq_work_pending();
-               irq_work_run();
-       }
-
-       now = get_tb_or_rtc();
-       if (now >= *next_tb) {
-               *next_tb = ~(u64)0;
-               if (evt->event_handler)
-                       evt->event_handler(evt);
-               __this_cpu_inc(irq_stat.timer_irqs_event);
-       } else {
-               now = *next_tb - now;
-               if (now <= decrementer_max)
-                       set_dec(now);
-               /* We may have raced with new irq work */
-               if (test_irq_work_pending())
-                       set_dec(1);
-               __this_cpu_inc(irq_stat.timer_irqs_others);
-       }
-
-       trace_timer_interrupt_exit(regs);
-}
-
 /*
  * timer_interrupt - gets called when the decrementer overflows,
  * with interrupts disabled.
  */
-void timer_interrupt(struct pt_regs * regs)
+void timer_interrupt(struct pt_regs *regs)
 {
-       struct pt_regs *old_regs;
+       struct clock_event_device *evt = this_cpu_ptr(&decrementers);
        u64 *next_tb = this_cpu_ptr(&decrementers_next_tb);
+       struct pt_regs *old_regs;
+       u64 now;
 
        /* Ensure a positive value is written to the decrementer, or else
         * some CPUs will continue to take decrementer exceptions.
@@ -638,13 +607,47 @@ void timer_interrupt(struct pt_regs * regs)
 
        old_regs = set_irq_regs(regs);
        irq_enter();
+       trace_timer_interrupt_entry(regs);
+
+       if (test_irq_work_pending()) {
+               clear_irq_work_pending();
+               irq_work_run();
+       }
+
+       now = get_tb_or_rtc();
+       if (now >= *next_tb) {
+               *next_tb = ~(u64)0;
+               if (evt->event_handler)
+                       evt->event_handler(evt);
+               __this_cpu_inc(irq_stat.timer_irqs_event);
+       } else {
+               now = *next_tb - now;
+               if (now <= decrementer_max)
+                       set_dec(now);
+               /* We may have raced with new irq work */
+               if (test_irq_work_pending())
+                       set_dec(1);
+               __this_cpu_inc(irq_stat.timer_irqs_others);
+       }
 
-       __timer_interrupt();
+       trace_timer_interrupt_exit(regs);
        irq_exit();
        set_irq_regs(old_regs);
 }
 EXPORT_SYMBOL(timer_interrupt);
 
+void timer_broadcast_interrupt(void)
+{
+       u64 *next_tb = this_cpu_ptr(&decrementers_next_tb);
+       struct pt_regs *regs = get_irq_regs();
+
+       trace_timer_interrupt_entry(regs);
+       *next_tb = ~(u64)0;
+       tick_receive_broadcast();
+       __this_cpu_inc(irq_stat.timer_irqs_event);
+       trace_timer_interrupt_exit(regs);
+}
+
 /*
  * Hypervisor decrementer interrupts shouldn't occur but are sometimes
  * left pending on exit from a KVM guest.  We don't need to do anything
@@ -992,15 +995,6 @@ static int decrementer_shutdown(struct clock_event_device *dev)
        return 0;
 }
 
-/* Interrupt handler for the timer broadcast IPI */
-void tick_broadcast_ipi_handler(void)
-{
-       u64 *next_tb = this_cpu_ptr(&decrementers_next_tb);
-
-       *next_tb = get_tb_or_rtc();
-       __timer_interrupt();
-}
-
 static void register_decrementer_clockevent(int cpu)
 {
        struct clock_event_device *dec = &per_cpu(decrementers, cpu);