powerpc/time: Optimise decrementer_check_overflow

decrementer_check_overflow is called from arch_local_irq_restore so
we want to make it as light weight as possible. As such, turn
decrementer_check_overflow into an inline function.

To avoid a circular mess of includes, separate out the two components
of struct decrementer_clock and keep the struct clock_event_device
part local to time.c.

The fast path improves from:

arch_local_irq_restore
     0:       mflr    r0
     4:       std     r0,16(r1)
     8:       stdu    r1,-112(r1)
     c:       stb     r3,578(r13)
    10:       cmpdi   cr7,r3,0
    14:       beq-    cr7,24 <.arch_local_irq_restore+0x24>
...
    24:       addi    r1,r1,112
    28:       ld      r0,16(r1)
    2c:       mtlr    r0
    30:       blr

to:

arch_local_irq_restore
    0:       std     r30,-16(r1)
    4:       ld      r30,0(r2)
    8:       stb     r3,578(r13)
    c:       cmpdi   cr7,r3,0
   10:       beq-    cr7,6c <.arch_local_irq_restore+0x6c>
...
   6c:       ld      r30,-16(r1)
   70:       blr

Unfortunately we still setup a local TOC (due to -mminimal-toc). Yet
another sign we should be moving to -mcmodel=medium.

Signed-off-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
This commit is contained in:
Anton Blanchard 2011-11-23 20:07:22 +00:00 committed by Benjamin Herrenschmidt
parent 621692cb7e
commit 7df1027542
3 changed files with 17 additions and 21 deletions

View File

@ -219,7 +219,7 @@ DECLARE_PER_CPU(struct cpu_usage, cpu_usage_array);
extern void secondary_cpu_time_init(void); extern void secondary_cpu_time_init(void);
extern void iSeries_time_init_early(void); extern void iSeries_time_init_early(void);
extern void decrementer_check_overflow(void); DECLARE_PER_CPU(u64, decrementers_next_tb);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* __POWERPC_TIME_H */ #endif /* __POWERPC_TIME_H */

View File

@ -115,6 +115,15 @@ static inline notrace void set_soft_enabled(unsigned long enable)
: : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled))); : : "r" (enable), "i" (offsetof(struct paca_struct, soft_enabled)));
} }
static inline notrace void decrementer_check_overflow(void)
{
u64 now = get_tb_or_rtc();
u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
if (now >= *next_tb)
set_dec(1);
}
notrace void arch_local_irq_restore(unsigned long en) notrace void arch_local_irq_restore(unsigned long en)
{ {
/* /*

View File

@ -114,12 +114,8 @@ static struct clock_event_device decrementer_clockevent = {
.features = CLOCK_EVT_FEAT_ONESHOT, .features = CLOCK_EVT_FEAT_ONESHOT,
}; };
struct decrementer_clock { DEFINE_PER_CPU(u64, decrementers_next_tb);
struct clock_event_device event; static DEFINE_PER_CPU(struct clock_event_device, decrementers);
u64 next_tb;
};
static DEFINE_PER_CPU(struct decrementer_clock, decrementers);
#ifdef CONFIG_PPC_ISERIES #ifdef CONFIG_PPC_ISERIES
static unsigned long __initdata iSeries_recal_titan; static unsigned long __initdata iSeries_recal_titan;
@ -570,8 +566,8 @@ void arch_irq_work_raise(void)
void timer_interrupt(struct pt_regs * regs) void timer_interrupt(struct pt_regs * regs)
{ {
struct pt_regs *old_regs; struct pt_regs *old_regs;
struct decrementer_clock *decrementer = &__get_cpu_var(decrementers); u64 *next_tb = &__get_cpu_var(decrementers_next_tb);
struct clock_event_device *evt = &decrementer->event; struct clock_event_device *evt = &__get_cpu_var(decrementers);
/* Ensure a positive value is written to the decrementer, or else /* Ensure a positive value is written to the decrementer, or else
* some CPUs will continue to take decrementer exceptions. * some CPUs will continue to take decrementer exceptions.
@ -606,7 +602,7 @@ void timer_interrupt(struct pt_regs * regs)
get_lppaca()->int_dword.fields.decr_int = 0; get_lppaca()->int_dword.fields.decr_int = 0;
#endif #endif
decrementer->next_tb = ~(u64)0; *next_tb = ~(u64)0;
if (evt->event_handler) if (evt->event_handler)
evt->event_handler(evt); evt->event_handler(evt);
@ -872,19 +868,10 @@ static void __init clocksource_init(void)
clock->name, clock->mult, clock->shift); clock->name, clock->mult, clock->shift);
} }
void decrementer_check_overflow(void)
{
u64 now = get_tb_or_rtc();
struct decrementer_clock *decrementer = &__get_cpu_var(decrementers);
if (now >= decrementer->next_tb)
set_dec(1);
}
static int decrementer_set_next_event(unsigned long evt, static int decrementer_set_next_event(unsigned long evt,
struct clock_event_device *dev) struct clock_event_device *dev)
{ {
__get_cpu_var(decrementers).next_tb = get_tb_or_rtc() + evt; __get_cpu_var(decrementers_next_tb) = get_tb_or_rtc() + evt;
set_dec(evt); set_dec(evt);
return 0; return 0;
} }
@ -898,7 +885,7 @@ static void decrementer_set_mode(enum clock_event_mode mode,
static void register_decrementer_clockevent(int cpu) static void register_decrementer_clockevent(int cpu)
{ {
struct clock_event_device *dec = &per_cpu(decrementers, cpu).event; struct clock_event_device *dec = &per_cpu(decrementers, cpu);
*dec = decrementer_clockevent; *dec = decrementer_clockevent;
dec->cpumask = cpumask_of(cpu); dec->cpumask = cpumask_of(cpu);