Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1b783955 authored by Preeti U Murthy's avatar Preeti U Murthy Committed by Benjamin Herrenschmidt
Browse files

powerpc: Split timer_interrupt() into timer handling and interrupt handling routines



Split timer_interrupt(), which is the local timer interrupt handler on ppc
into routines called during regular interrupt handling and __timer_interrupt(),
which takes care of running local timers and collecting time related stats.

This will enable callers interested only in running expired local timers to
directly call into __timer_interupt(). One of the use cases of this is the
tick broadcast IPI handling in which the sleeping CPUs need to handle the local
timers that have expired.

Signed-off-by: default avatarPreeti U Murthy <preeti@linux.vnet.ibm.com>
Signed-off-by: default avatarBenjamin Herrenschmidt <benh@kernel.crashing.org>
parent 1b67bee1
Loading
Loading
Loading
Loading
+46 −35
Original line number Diff line number Diff line
@@ -478,6 +478,47 @@ void arch_irq_work_raise(void)

#endif /* CONFIG_IRQ_WORK */

void __timer_interrupt(void)
{
	struct pt_regs *regs = get_irq_regs();
	u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
	struct clock_event_device *evt = &__get_cpu_var(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);
		__get_cpu_var(irq_stat).timer_irqs_event++;
	} else {
		now = *next_tb - now;
		if (now <= DECREMENTER_MAX)
			set_dec((int)now);
		/* We may have raced with new irq work */
		if (test_irq_work_pending())
			set_dec(1);
		__get_cpu_var(irq_stat).timer_irqs_others++;
	}

#ifdef CONFIG_PPC64
	/* collect purr register values often, for accurate calculations */
	if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
		struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);
		cu->current_tb = mfspr(SPRN_PURR);
	}
#endif

	trace_timer_interrupt_exit(regs);
}

/*
 * timer_interrupt - gets called when the decrementer overflows,
 * with interrupts disabled.
@@ -486,8 +527,6 @@ void timer_interrupt(struct pt_regs * regs)
{
	struct pt_regs *old_regs;
	u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
	struct clock_event_device *evt = &__get_cpu_var(decrementers);
	u64 now;

	/* Ensure a positive value is written to the decrementer, or else
	 * some CPUs will continue to take decrementer exceptions.
@@ -519,39 +558,7 @@ 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);
		__get_cpu_var(irq_stat).timer_irqs_event++;
	} else {
		now = *next_tb - now;
		if (now <= DECREMENTER_MAX)
			set_dec((int)now);
		/* We may have raced with new irq work */
		if (test_irq_work_pending())
			set_dec(1);
		__get_cpu_var(irq_stat).timer_irqs_others++;
	}

#ifdef CONFIG_PPC64
	/* collect purr register values often, for accurate calculations */
	if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
		struct cpu_usage *cu = &__get_cpu_var(cpu_usage_array);
		cu->current_tb = mfspr(SPRN_PURR);
	}
#endif

	trace_timer_interrupt_exit(regs);

	__timer_interrupt();
	irq_exit();
	set_irq_regs(old_regs);
}
@@ -828,6 +835,10 @@ static void decrementer_set_mode(enum clock_event_mode mode,
/* Interrupt handler for the timer broadcast IPI */
void tick_broadcast_ipi_handler(void)
{
	u64 *next_tb = &__get_cpu_var(decrementers_next_tb);

	*next_tb = get_tb_or_rtc();
	__timer_interrupt();
}

static void register_decrementer_clockevent(int cpu)