Commit 47916be4 authored by Thomas Gleixner's avatar Thomas Gleixner

Merge branch 'powerpc.cherry-picks' into timers/clocksource

Conflicts:
	arch/powerpc/kernel/time.c

Reason: The powerpc next tree contains two commits which conflict with
the timekeeping changes:

8fd63a9e powerpc: Rework VDSO gettimeofday to prevent time going backwards
c1aa687d powerpc: Clean up obsolete code relating to decrementer and timebase

John Stultz identified them and provided the conflict resolution.
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parents 852db46d d75d68cf
...@@ -366,8 +366,5 @@ static inline void log_error(char *buf, unsigned int err_type, int fatal) ...@@ -366,8 +366,5 @@ static inline void log_error(char *buf, unsigned int err_type, int fatal)
#define machine_late_initcall(mach,fn) __define_machine_initcall(mach,"7",fn,7) #define machine_late_initcall(mach,fn) __define_machine_initcall(mach,"7",fn,7)
#define machine_late_initcall_sync(mach,fn) __define_machine_initcall(mach,"7s",fn,7s) #define machine_late_initcall_sync(mach,fn) __define_machine_initcall(mach,"7s",fn,7s)
void generic_suspend_disable_irqs(void);
void generic_suspend_enable_irqs(void);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* _ASM_POWERPC_MACHDEP_H */ #endif /* _ASM_POWERPC_MACHDEP_H */
...@@ -28,16 +28,12 @@ ...@@ -28,16 +28,12 @@
extern unsigned long tb_ticks_per_jiffy; extern unsigned long tb_ticks_per_jiffy;
extern unsigned long tb_ticks_per_usec; extern unsigned long tb_ticks_per_usec;
extern unsigned long tb_ticks_per_sec; extern unsigned long tb_ticks_per_sec;
extern u64 tb_to_xs;
extern unsigned tb_to_us;
struct rtc_time; struct rtc_time;
extern void to_tm(int tim, struct rtc_time * tm); extern void to_tm(int tim, struct rtc_time * tm);
extern void GregorianDay(struct rtc_time *tm); extern void GregorianDay(struct rtc_time *tm);
extern time_t last_rtc_update;
extern void generic_calibrate_decr(void); extern void generic_calibrate_decr(void);
extern void wakeup_decrementer(void);
extern void snapshot_timebase(void); extern void snapshot_timebase(void);
extern void set_dec_cpu6(unsigned int val); extern void set_dec_cpu6(unsigned int val);
...@@ -204,9 +200,6 @@ static inline unsigned long tb_ticks_since(unsigned long tstamp) ...@@ -204,9 +200,6 @@ static inline unsigned long tb_ticks_since(unsigned long tstamp)
extern u64 mulhdu(u64, u64); extern u64 mulhdu(u64, u64);
#endif #endif
extern void smp_space_timers(unsigned int);
extern unsigned mulhwu_scale_factor(unsigned, unsigned);
extern void div128_by_32(u64 dividend_high, u64 dividend_low, extern void div128_by_32(u64 dividend_high, u64 dividend_low,
unsigned divisor, struct div_result *dr); unsigned divisor, struct div_result *dr);
......
...@@ -85,6 +85,7 @@ struct vdso_data { ...@@ -85,6 +85,7 @@ struct vdso_data {
__s32 wtom_clock_sec; /* Wall to monotonic clock */ __s32 wtom_clock_sec; /* Wall to monotonic clock */
__s32 wtom_clock_nsec; __s32 wtom_clock_nsec;
struct timespec stamp_xtime; /* xtime as at tb_orig_stamp */ struct timespec stamp_xtime; /* xtime as at tb_orig_stamp */
__u32 stamp_sec_fraction; /* fractional seconds of stamp_xtime */
__u32 syscall_map_64[SYSCALL_MAP_SIZE]; /* map of syscalls */ __u32 syscall_map_64[SYSCALL_MAP_SIZE]; /* map of syscalls */
__u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */ __u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */
}; };
...@@ -105,6 +106,7 @@ struct vdso_data { ...@@ -105,6 +106,7 @@ struct vdso_data {
__s32 wtom_clock_sec; /* Wall to monotonic clock */ __s32 wtom_clock_sec; /* Wall to monotonic clock */
__s32 wtom_clock_nsec; __s32 wtom_clock_nsec;
struct timespec stamp_xtime; /* xtime as at tb_orig_stamp */ struct timespec stamp_xtime; /* xtime as at tb_orig_stamp */
__u32 stamp_sec_fraction; /* fractional seconds of stamp_xtime */
__u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */ __u32 syscall_map_32[SYSCALL_MAP_SIZE]; /* map of syscalls */
__u32 dcache_block_size; /* L1 d-cache block size */ __u32 dcache_block_size; /* L1 d-cache block size */
__u32 icache_block_size; /* L1 i-cache block size */ __u32 icache_block_size; /* L1 i-cache block size */
......
...@@ -342,6 +342,7 @@ int main(void) ...@@ -342,6 +342,7 @@ int main(void)
DEFINE(WTOM_CLOCK_SEC, offsetof(struct vdso_data, wtom_clock_sec)); DEFINE(WTOM_CLOCK_SEC, offsetof(struct vdso_data, wtom_clock_sec));
DEFINE(WTOM_CLOCK_NSEC, offsetof(struct vdso_data, wtom_clock_nsec)); DEFINE(WTOM_CLOCK_NSEC, offsetof(struct vdso_data, wtom_clock_nsec));
DEFINE(STAMP_XTIME, offsetof(struct vdso_data, stamp_xtime)); DEFINE(STAMP_XTIME, offsetof(struct vdso_data, stamp_xtime));
DEFINE(STAMP_SEC_FRAC, offsetof(struct vdso_data, stamp_sec_fraction));
DEFINE(CFG_ICACHE_BLOCKSZ, offsetof(struct vdso_data, icache_block_size)); DEFINE(CFG_ICACHE_BLOCKSZ, offsetof(struct vdso_data, icache_block_size));
DEFINE(CFG_DCACHE_BLOCKSZ, offsetof(struct vdso_data, dcache_block_size)); DEFINE(CFG_DCACHE_BLOCKSZ, offsetof(struct vdso_data, dcache_block_size));
DEFINE(CFG_ICACHE_LOGBLOCKSZ, offsetof(struct vdso_data, icache_log_block_size)); DEFINE(CFG_ICACHE_LOGBLOCKSZ, offsetof(struct vdso_data, icache_log_block_size));
......
...@@ -289,8 +289,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) ...@@ -289,8 +289,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
else else
max_cpus = 1; max_cpus = 1;
smp_space_timers(max_cpus);
for_each_possible_cpu(cpu) for_each_possible_cpu(cpu)
if (cpu != boot_cpuid) if (cpu != boot_cpuid)
smp_create_idle(cpu); smp_create_idle(cpu);
......
...@@ -149,16 +149,6 @@ unsigned long tb_ticks_per_usec = 100; /* sane default */ ...@@ -149,16 +149,6 @@ unsigned long tb_ticks_per_usec = 100; /* sane default */
EXPORT_SYMBOL(tb_ticks_per_usec); EXPORT_SYMBOL(tb_ticks_per_usec);
unsigned long tb_ticks_per_sec; unsigned long tb_ticks_per_sec;
EXPORT_SYMBOL(tb_ticks_per_sec); /* for cputime_t conversions */ EXPORT_SYMBOL(tb_ticks_per_sec); /* for cputime_t conversions */
u64 tb_to_xs;
unsigned tb_to_us;
#define TICKLEN_SCALE NTP_SCALE_SHIFT
static u64 last_tick_len; /* units are ns / 2^TICKLEN_SCALE */
static u64 ticklen_to_xs; /* 0.64 fraction */
/* If last_tick_len corresponds to about 1/HZ seconds, then
last_tick_len << TICKLEN_SHIFT will be about 2^63. */
#define TICKLEN_SHIFT (63 - 30 - TICKLEN_SCALE + SHIFT_HZ)
DEFINE_SPINLOCK(rtc_lock); DEFINE_SPINLOCK(rtc_lock);
EXPORT_SYMBOL_GPL(rtc_lock); EXPORT_SYMBOL_GPL(rtc_lock);
...@@ -174,7 +164,6 @@ unsigned long ppc_proc_freq; ...@@ -174,7 +164,6 @@ unsigned long ppc_proc_freq;
EXPORT_SYMBOL(ppc_proc_freq); EXPORT_SYMBOL(ppc_proc_freq);
unsigned long ppc_tb_freq; unsigned long ppc_tb_freq;
static u64 tb_last_jiffy __cacheline_aligned_in_smp;
static DEFINE_PER_CPU(u64, last_jiffy); static DEFINE_PER_CPU(u64, last_jiffy);
#ifdef CONFIG_VIRT_CPU_ACCOUNTING #ifdef CONFIG_VIRT_CPU_ACCOUNTING
...@@ -446,7 +435,6 @@ EXPORT_SYMBOL(profile_pc); ...@@ -446,7 +435,6 @@ EXPORT_SYMBOL(profile_pc);
static int __init iSeries_tb_recal(void) static int __init iSeries_tb_recal(void)
{ {
struct div_result divres;
unsigned long titan, tb; unsigned long titan, tb;
/* Make sure we only run on iSeries */ /* Make sure we only run on iSeries */
...@@ -477,10 +465,7 @@ static int __init iSeries_tb_recal(void) ...@@ -477,10 +465,7 @@ static int __init iSeries_tb_recal(void)
tb_ticks_per_jiffy = new_tb_ticks_per_jiffy; tb_ticks_per_jiffy = new_tb_ticks_per_jiffy;
tb_ticks_per_sec = new_tb_ticks_per_sec; tb_ticks_per_sec = new_tb_ticks_per_sec;
calc_cputime_factors(); calc_cputime_factors();
div128_by_32( XSEC_PER_SEC, 0, tb_ticks_per_sec, &divres );
tb_to_xs = divres.result_low;
vdso_data->tb_ticks_per_sec = tb_ticks_per_sec; vdso_data->tb_ticks_per_sec = tb_ticks_per_sec;
vdso_data->tb_to_xs = tb_to_xs;
setup_cputime_one_jiffy(); setup_cputime_one_jiffy();
} }
else { else {
...@@ -643,27 +628,9 @@ void timer_interrupt(struct pt_regs * regs) ...@@ -643,27 +628,9 @@ void timer_interrupt(struct pt_regs * regs)
trace_timer_interrupt_exit(regs); trace_timer_interrupt_exit(regs);
} }
void wakeup_decrementer(void)
{
unsigned long ticks;
/*
* The timebase gets saved on sleep and restored on wakeup,
* so all we need to do is to reset the decrementer.
*/
ticks = tb_ticks_since(__get_cpu_var(last_jiffy));
if (ticks < tb_ticks_per_jiffy)
ticks = tb_ticks_per_jiffy - ticks;
else
ticks = 1;
set_dec(ticks);
}
#ifdef CONFIG_SUSPEND #ifdef CONFIG_SUSPEND
void generic_suspend_disable_irqs(void) static void generic_suspend_disable_irqs(void)
{ {
preempt_disable();
/* Disable the decrementer, so that it doesn't interfere /* Disable the decrementer, so that it doesn't interfere
* with suspending. * with suspending.
*/ */
...@@ -673,12 +640,9 @@ void generic_suspend_disable_irqs(void) ...@@ -673,12 +640,9 @@ void generic_suspend_disable_irqs(void)
set_dec(0x7fffffff); set_dec(0x7fffffff);
} }
void generic_suspend_enable_irqs(void) static void generic_suspend_enable_irqs(void)
{ {
wakeup_decrementer();
local_irq_enable(); local_irq_enable();
preempt_enable();
} }
/* Overrides the weak version in kernel/power/main.c */ /* Overrides the weak version in kernel/power/main.c */
...@@ -698,23 +662,6 @@ void arch_suspend_enable_irqs(void) ...@@ -698,23 +662,6 @@ void arch_suspend_enable_irqs(void)
} }
#endif #endif
#ifdef CONFIG_SMP
void __init smp_space_timers(unsigned int max_cpus)
{
int i;
u64 previous_tb = per_cpu(last_jiffy, boot_cpuid);
/* make sure tb > per_cpu(last_jiffy, cpu) for all cpus always */
previous_tb -= tb_ticks_per_jiffy;
for_each_possible_cpu(i) {
if (i == boot_cpuid)
continue;
per_cpu(last_jiffy, i) = previous_tb;
}
}
#endif
/* /*
* Scheduler clock - returns current time in nanosec units. * Scheduler clock - returns current time in nanosec units.
* *
...@@ -853,6 +800,7 @@ void update_vsyscall(struct timespec *wall_time, struct timespec *wtm, ...@@ -853,6 +800,7 @@ void update_vsyscall(struct timespec *wall_time, struct timespec *wtm,
struct clocksource *clock, u32 mult) struct clocksource *clock, u32 mult)
{ {
u64 new_tb_to_xs, new_stamp_xsec; u64 new_tb_to_xs, new_stamp_xsec;
u32 frac_sec;
if (clock != &clocksource_timebase) if (clock != &clocksource_timebase)
return; return;
...@@ -868,6 +816,10 @@ void update_vsyscall(struct timespec *wall_time, struct timespec *wtm, ...@@ -868,6 +816,10 @@ void update_vsyscall(struct timespec *wall_time, struct timespec *wtm,
do_div(new_stamp_xsec, 1000000000); do_div(new_stamp_xsec, 1000000000);
new_stamp_xsec += (u64) wall_time->tv_sec * XSEC_PER_SEC; new_stamp_xsec += (u64) wall_time->tv_sec * XSEC_PER_SEC;
BUG_ON(wall_time->tv_nsec >= NSEC_PER_SEC);
/* this is tv_nsec / 1e9 as a 0.32 fraction */
frac_sec = ((u64) wall_time->tv_nsec * 18446744073ULL) >> 32;
/* /*
* tb_update_count is used to allow the userspace gettimeofday code * tb_update_count is used to allow the userspace gettimeofday code
* to assure itself that it sees a consistent view of the tb_to_xs and * to assure itself that it sees a consistent view of the tb_to_xs and
...@@ -885,6 +837,7 @@ void update_vsyscall(struct timespec *wall_time, struct timespec *wtm, ...@@ -885,6 +837,7 @@ void update_vsyscall(struct timespec *wall_time, struct timespec *wtm,
vdso_data->wtom_clock_sec = wtm->tv_sec; vdso_data->wtom_clock_sec = wtm->tv_sec;
vdso_data->wtom_clock_nsec = wtm->tv_nsec; vdso_data->wtom_clock_nsec = wtm->tv_nsec;
vdso_data->stamp_xtime = *wall_time; vdso_data->stamp_xtime = *wall_time;
vdso_data->stamp_sec_fraction = frac_sec;
smp_wmb(); smp_wmb();
++(vdso_data->tb_update_count); ++(vdso_data->tb_update_count);
} }
...@@ -1002,15 +955,13 @@ void secondary_cpu_time_init(void) ...@@ -1002,15 +955,13 @@ void secondary_cpu_time_init(void)
/* This function is only called on the boot processor */ /* This function is only called on the boot processor */
void __init time_init(void) void __init time_init(void)
{ {
unsigned long flags;
struct div_result res; struct div_result res;
u64 scale, x; u64 scale;
unsigned shift; unsigned shift;
if (__USE_RTC()) { if (__USE_RTC()) {
/* 601 processor: dec counts down by 128 every 128ns */ /* 601 processor: dec counts down by 128 every 128ns */
ppc_tb_freq = 1000000000; ppc_tb_freq = 1000000000;
tb_last_jiffy = get_rtcl();
} else { } else {
/* Normal PowerPC with timebase register */ /* Normal PowerPC with timebase register */
ppc_md.calibrate_decr(); ppc_md.calibrate_decr();
...@@ -1018,49 +969,14 @@ void __init time_init(void) ...@@ -1018,49 +969,14 @@ void __init time_init(void)
ppc_tb_freq / 1000000, ppc_tb_freq % 1000000); ppc_tb_freq / 1000000, ppc_tb_freq % 1000000);
printk(KERN_DEBUG "time_init: processor frequency = %lu.%.6lu MHz\n", printk(KERN_DEBUG "time_init: processor frequency = %lu.%.6lu MHz\n",
ppc_proc_freq / 1000000, ppc_proc_freq % 1000000); ppc_proc_freq / 1000000, ppc_proc_freq % 1000000);
tb_last_jiffy = get_tb();
} }
tb_ticks_per_jiffy = ppc_tb_freq / HZ; tb_ticks_per_jiffy = ppc_tb_freq / HZ;
tb_ticks_per_sec = ppc_tb_freq; tb_ticks_per_sec = ppc_tb_freq;
tb_ticks_per_usec = ppc_tb_freq / 1000000; tb_ticks_per_usec = ppc_tb_freq / 1000000;
tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000);
calc_cputime_factors(); calc_cputime_factors();
setup_cputime_one_jiffy(); setup_cputime_one_jiffy();
/*
* Calculate the length of each tick in ns. It will not be
* exactly 1e9/HZ unless ppc_tb_freq is divisible by HZ.
* We compute 1e9 * tb_ticks_per_jiffy / ppc_tb_freq,
* rounded up.
*/
x = (u64) NSEC_PER_SEC * tb_ticks_per_jiffy + ppc_tb_freq - 1;
do_div(x, ppc_tb_freq);
tick_nsec = x;
last_tick_len = x << TICKLEN_SCALE;
/*
* Compute ticklen_to_xs, which is a factor which gets multiplied
* by (last_tick_len << TICKLEN_SHIFT) to get a tb_to_xs value.
* It is computed as:
* ticklen_to_xs = 2^N / (tb_ticks_per_jiffy * 1e9)
* where N = 64 + 20 - TICKLEN_SCALE - TICKLEN_SHIFT
* which turns out to be N = 51 - SHIFT_HZ.
* This gives the result as a 0.64 fixed-point fraction.
* That value is reduced by an offset amounting to 1 xsec per
* 2^31 timebase ticks to avoid problems with time going backwards
* by 1 xsec when we do timer_recalc_offset due to losing the
* fractional xsec. That offset is equal to ppc_tb_freq/2^51
* since there are 2^20 xsec in a second.
*/
div128_by_32((1ULL << 51) - ppc_tb_freq, 0,
tb_ticks_per_jiffy << SHIFT_HZ, &res);
div128_by_32(res.result_high, res.result_low, NSEC_PER_SEC, &res);
ticklen_to_xs = res.result_low;
/* Compute tb_to_xs from tick_nsec */
tb_to_xs = mulhdu(last_tick_len << TICKLEN_SHIFT, ticklen_to_xs);
/* /*
* Compute scale factor for sched_clock. * Compute scale factor for sched_clock.
* The calibrate_decr() function has set tb_ticks_per_sec, * The calibrate_decr() function has set tb_ticks_per_sec,
...@@ -1082,21 +998,14 @@ void __init time_init(void) ...@@ -1082,21 +998,14 @@ void __init time_init(void)
/* Save the current timebase to pretty up CONFIG_PRINTK_TIME */ /* Save the current timebase to pretty up CONFIG_PRINTK_TIME */
boot_tb = get_tb_or_rtc(); boot_tb = get_tb_or_rtc();
write_seqlock_irqsave(&xtime_lock, flags);
/* If platform provided a timezone (pmac), we correct the time */ /* If platform provided a timezone (pmac), we correct the time */
if (timezone_offset) { if (timezone_offset) {
sys_tz.tz_minuteswest = -timezone_offset / 60; sys_tz.tz_minuteswest = -timezone_offset / 60;
sys_tz.tz_dsttime = 0; sys_tz.tz_dsttime = 0;
} }
vdso_data->tb_orig_stamp = tb_last_jiffy;
vdso_data->tb_update_count = 0; vdso_data->tb_update_count = 0;
vdso_data->tb_ticks_per_sec = tb_ticks_per_sec; vdso_data->tb_ticks_per_sec = tb_ticks_per_sec;
vdso_data->stamp_xsec = (u64) get_seconds() * XSEC_PER_SEC;
vdso_data->tb_to_xs = tb_to_xs;
write_sequnlock_irqrestore(&xtime_lock, flags);
/* Start the decrementer on CPUs that have manual control /* Start the decrementer on CPUs that have manual control
* such as BookE * such as BookE
...@@ -1190,39 +1099,6 @@ void to_tm(int tim, struct rtc_time * tm) ...@@ -1190,39 +1099,6 @@ void to_tm(int tim, struct rtc_time * tm)
GregorianDay(tm); GregorianDay(tm);
} }
/* Auxiliary function to compute scaling factors */
/* Actually the choice of a timebase running at 1/4 the of the bus
* frequency giving resolution of a few tens of nanoseconds is quite nice.
* It makes this computation very precise (27-28 bits typically) which
* is optimistic considering the stability of most processor clock
* oscillators and the precision with which the timebase frequency
* is measured but does not harm.
*/
unsigned mulhwu_scale_factor(unsigned inscale, unsigned outscale)
{
unsigned mlt=0, tmp, err;
/* No concern for performance, it's done once: use a stupid
* but safe and compact method to find the multiplier.
*/
for (tmp = 1U<<31; tmp != 0; tmp >>= 1) {
if (mulhwu(inscale, mlt|tmp) < outscale)
mlt |= tmp;
}
/* We might still be off by 1 for the best approximation.
* A side effect of this is that if outscale is too large
* the returned value will be zero.
* Many corner cases have been checked and seem to work,
* some might have been forgotten in the test however.
*/
err = inscale * (mlt+1);
if (err <= inscale/2)
mlt++;
return mlt;
}
/* /*
* Divide a 128-bit dividend by a 32-bit divisor, leaving a 128 bit * Divide a 128-bit dividend by a 32-bit divisor, leaving a 128 bit
* result. * result.
......
...@@ -19,8 +19,10 @@ ...@@ -19,8 +19,10 @@
/* Offset for the low 32-bit part of a field of long type */ /* Offset for the low 32-bit part of a field of long type */
#ifdef CONFIG_PPC64 #ifdef CONFIG_PPC64
#define LOPART 4 #define LOPART 4
#define TSPEC_TV_SEC TSPC64_TV_SEC+LOPART
#else #else
#define LOPART 0 #define LOPART 0
#define TSPEC_TV_SEC TSPC32_TV_SEC
#endif #endif
.text .text
...@@ -41,23 +43,11 @@ V_FUNCTION_BEGIN(__kernel_gettimeofday) ...@@ -41,23 +43,11 @@ V_FUNCTION_BEGIN(__kernel_gettimeofday)
mr r9, r3 /* datapage ptr in r9 */ mr r9, r3 /* datapage ptr in r9 */
cmplwi r10,0 /* check if tv is NULL */ cmplwi r10,0 /* check if tv is NULL */
beq 3f beq 3f
bl __do_get_xsec@local /* get xsec from tb & kernel */ lis r7,1000000@ha /* load up USEC_PER_SEC */
bne- 2f /* out of line -> do syscall */ addi r7,r7,1000000@l /* so we get microseconds in r4 */
bl __do_get_tspec@local /* get sec/usec from tb & kernel */
/* seconds are xsec >> 20 */ stw r3,TVAL32_TV_SEC(r10)
rlwinm r5,r4,12,20,31 stw r4,TVAL32_TV_USEC(r10)
rlwimi r5,r3,12,0,19
stw r5,TVAL32_TV_SEC(r10)
/* get remaining xsec and convert to usec. we scale
* up remaining xsec by 12 bits and get the top 32 bits
* of the multiplication
*/
rlwinm r5,r4,12,0,19
lis r6,1000000@h
ori r6,r6,1000000@l
mulhwu r5,r5,r6
stw r5,TVAL32_TV_USEC(r10)
3: cmplwi r11,0 /* check if tz is NULL */ 3: cmplwi r11,0 /* check if tz is NULL */
beq 1f beq 1f
...@@ -70,14 +60,6 @@ V_FUNCTION_BEGIN(__kernel_gettimeofday) ...@@ -70,14 +60,6 @@ V_FUNCTION_BEGIN(__kernel_gettimeofday)
crclr cr0*4+so crclr cr0*4+so
li r3,0 li r3,0
blr blr
2:
mtlr r12
mr r3,r10
mr r4,r11
li r0,__NR_gettimeofday
sc
blr
.cfi_endproc .cfi_endproc
V_FUNCTION_END(__kernel_gettimeofday) V_FUNCTION_END(__kernel_gettimeofday)
...@@ -100,7 +82,8 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) ...@@ -100,7 +82,8 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
mr r11,r4 /* r11 saves tp */ mr r11,r4 /* r11 saves tp */
bl __get_datapage@local /* get data page */ bl __get_datapage@local /* get data page */
mr r9,r3 /* datapage ptr in r9 */ mr r9,r3 /* datapage ptr in r9 */
lis r7,NSEC_PER_SEC@h /* want nanoseconds */
ori r7,r7,NSEC_PER_SEC@l
50: bl __do_get_tspec@local /* get sec/nsec from tb & kernel */ 50: bl __do_get_tspec@local /* get sec/nsec from tb & kernel */
bne cr1,80f /* not monotonic -> all done */ bne cr1,80f /* not monotonic -> all done */
...@@ -198,83 +181,12 @@ V_FUNCTION_END(__kernel_clock_getres) ...@@ -198,83 +181,12 @@ V_FUNCTION_END(__kernel_clock_getres)
/* /*
* This is the core of gettimeofday() & friends, it returns the xsec * This is the core of clock_gettime() and gettimeofday(),
* value in r3 & r4 and expects the datapage ptr (non clobbered) * it returns the current time in r3 (seconds) and r4.
* in r9. clobbers r0,r4,r5,r6,r7,r8. * On entry, r7 gives the resolution of r4, either USEC_PER_SEC
* When returning, r8 contains the counter value that can be reused * or NSEC_PER_SEC, giving r4 in microseconds or nanoseconds.
* by the monotonic clock implementation
*/
__do_get_xsec:
.cfi_startproc
/* Check for update count & load values. We use the low
* order 32 bits of the update count
*/
1: lwz r8,(CFG_TB_UPDATE_COUNT+LOPART)(r9)
andi. r0,r8,1 /* pending update ? loop */
bne- 1b
xor r0,r8,r8 /* create dependency */
add r9,r9,r0
/* Load orig stamp (offset to TB) */
lwz r5,CFG_TB_ORIG_STAMP(r9)
lwz r6,(CFG_TB_ORIG_STAMP+4)(r9)
/* Get a stable TB value */
2: mftbu r3
mftbl r4
mftbu r0
cmpl cr0,r3,r0
bne- 2b
/* Substract tb orig stamp. If the high part is non-zero, we jump to
* the slow path which call the syscall.
* If it's ok, then we have our 32 bits tb_ticks value in r7
*/
subfc r7,r6,r4
subfe. r0,r5,r3
bne- 3f
/* Load scale factor & do multiplication */
lwz r5,CFG_TB_TO_XS(r9) /* load values */
lwz r6,(CFG_TB_TO_XS+4)(r9)
mulhwu r4,r7,r5
mulhwu r6,r7,r6
mullw r0,r7,r5
addc r6,r6,r0
/* At this point, we have the scaled xsec value in r4 + XER:CA
* we load & add the stamp since epoch
*/
lwz r5,CFG_STAMP_XSEC(r9)
lwz r6,(CFG_STAMP_XSEC+4)(r9)
adde r4,r4,r6
addze r3,r5
/* We now have our result in r3,r4. We create a fake dependency
* on that result and re-check the counter
*/
or r6,r4,r3
xor r0,r6,r6
add r9,r9,r0
lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9)
cmpl cr0,r8,r0 /* check if updated */
bne- 1b
/* Warning ! The caller expects CR:EQ to be set to indicate a
* successful calculation (so it won't fallback to the syscall
* method). We have overriden that CR bit in the counter check,
* but fortunately, the loop exit condition _is_ CR:EQ set, so
* we can exit safely here. If you change this code, be careful
* of that side effect.
*/
3: blr
.cfi_endproc
/*
* This is the core of clock_gettime(), it returns the current
* time in seconds and nanoseconds in r3 and r4.
* It expects the datapage ptr in r9 and doesn't clobber it. * It expects the datapage ptr in r9 and doesn't clobber it.
* It clobbers r0, r5, r6, r10 and returns NSEC_PER_SEC in r7. * It clobbers r0, r5 and r6.
* On return, r8 contains the counter value that can be reused. * On return, r8 contains the counter value that can be reused.
* This clobbers cr0 but not any other cr field. * This clobbers cr0 but not any other cr field.
*/ */
...@@ -297,70 +209,58 @@ __do_get_tspec: ...@@ -297,70 +209,58 @@ __do_get_tspec:
2: mftbu r3 2: mftbu r3
mftbl r4 mftbl r4
mftbu r0 mftbu r0
cmpl cr0,r3,r0 cmplw cr0,r3,r0
bne- 2b bne- 2b
/* Subtract tb orig stamp and shift left 12 bits. /* Subtract tb orig stamp and shift left 12 bits.
*/ */
subfc r7,r6,r4 subfc r4,r6,r4
subfe r0,r5,r3 subfe r0,r5,r3
slwi r0,r0,12 slwi r0,r0,12
rlwimi. r0,r7,12,20,31 rlwimi. r0,r4,12,20,31
slwi r7,r7,12 slwi r4,r4,12
/* Load scale factor & do multiplication */ /*
* Load scale factor & do multiplication.
* We only use the high 32 bits of the tb_to_xs value.
* Even with a 1GHz timebase clock, the high 32 bits of
* tb_to_xs will be at least 4 million, so the error from
* ignoring the low 32 bits will be no more than 0.25ppm.
* The error will just make the clock run very very slightly
* slow until the next time the kernel updates the VDSO data,
* at which point the clock will catch up to the kernel's value,
* so there is no long-term error accumulation.
*/
lwz r5,CFG_TB_TO_XS(r9) /* load values */ lwz r5,CFG_TB_TO_XS(r9) /* load values */
lwz r6,(CFG_TB_TO_XS+4)(r9) mulhwu r4,r4,r5
mulhwu r3,r7,r6
mullw r10,r7,r5
mulhwu r4,r7,r5
addc r10,r3,r10
li r3,0 li r3,0
beq+ 4f /* skip high part computation if 0 */ beq+ 4f /* skip high part computation if 0 */
mulhwu r3,r0,r5 mulhwu r3,r0,r5
mullw r7,r0,r5 mullw r5,r0,r5
mulhwu r5,r0,r6
mullw r6,r0,r6
adde r4,r4,r7
addze r3,r3
addc r4,r4,r5 addc r4,r4,r5
addze r3,r3 addze r3,r3
addc r10,r10,r6 4:
/* At this point, we have seconds since the xtime stamp
4: addze r4,r4 /* add in carry */ * as a 32.32 fixed-point number in r3 and r4.
lis r7,NSEC_PER_SEC@h * Load & add the xtime stamp.
ori r7,r7,NSEC_PER_SEC@l
mulhwu r4,r4,r7 /* convert to nanoseconds */
/* At this point, we have seconds & nanoseconds since the xtime
* stamp in r3+CA and r4. Load & add the xtime stamp.
*/ */
#ifdef CONFIG_PPC64 lwz r5,STAMP_XTIME+TSPEC_TV_SEC(r9)
lwz r5,STAMP_XTIME+TSPC64_TV_SEC+LOPART(r9) lwz r6,STAMP_SEC_FRAC(r9)
lwz r6,STAMP_XTIME+TSPC64_TV_NSEC+LOPART(r9) addc r4,r4,r6
#else
lwz r5,STAMP_XTIME+TSPC32_TV_SEC(r9)
lwz r6,STAMP_XTIME+TSPC32_TV_NSEC(r9)
#endif
add r4,r4,r6
adde r3,r3,r5 adde r3,r3,r5
/* We now have our result in r3,r4. We create a fake dependency /* We create a fake dependency on the result in r3/r4
* on that result and re-check the counter * and re-check the counter
*/ */
or r6,r4,r3 or r6,r4,r3
xor r0,r6,r6 xor r0,r6,r6
add r9,r9,r0 add r9,r9,r0
lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9) lwz r0,(CFG_TB_UPDATE_COUNT+LOPART)(r9)
cmpl cr0,r8,r0 /* check if updated */ cmplw cr0,r8,r0 /* check if updated */
bne- 1b bne- 1b
/* check for nanosecond overflow and adjust if necessary */ mulhwu r4,r4,r7 /* convert to micro or nanoseconds */
cmpw r4,r7
bltlr /* all done if no overflow */
subf r4,r7,r4 /* adjust if overflow */
addi r3,r3,1
blr blr
.cfi_endproc .cfi_endproc
...@@ -33,18 +33,11 @@ V_FUNCTION_BEGIN(__kernel_gettimeofday) ...@@ -33,18 +33,11 @@ V_FUNCTION_BEGIN(__kernel_gettimeofday)
bl V_LOCAL_FUNC(__get_datapage) /* get data page */ bl V_LOCAL_FUNC(__get_datapage) /* get data page */
cmpldi r11,0 /* check if tv is NULL */ cmpldi r11,0 /* check if tv is NULL */
beq 2f beq 2f
bl V_LOCAL_FUNC(__do_get_xsec) /* get xsec from tb & kernel */ lis r7,1000000@ha /* load up USEC_PER_SEC */
lis r7,15 /* r7 = 1000000 = USEC_PER_SEC */ addi r7,r7,1000000@l
ori r7,r7,16960 bl V_LOCAL_FUNC(__do_get_tspec) /* get sec/us from tb & kernel */
rldicl r5,r4,44,20 /* r5 = sec = xsec / XSEC_PER_SEC */ std r4,TVAL64_TV_SEC(r11) /* store sec in tv */
rldicr r6,r5,20,43 /* r6 = sec * XSEC_PER_SEC */ std r5,TVAL64_TV_USEC(r11) /* store usec in tv */
std r5,TVAL64_TV_SEC(r11) /* store sec in tv */
subf r0,r6,r4 /* r0 = xsec = (xsec - r6) */
mulld r0,r0,r7 /* usec = (xsec * USEC_PER_SEC) /
* XSEC_PER_SEC
*/
rldicl r0,r0,44,20
std r0,TVAL64_TV_USEC(r11) /* store usec in tv */
2: cmpldi r10,0 /* check if tz is NULL */ 2: cmpldi r10,0 /* check if tz is NULL */
beq 1f beq 1f
lwz r4,CFG_TZ_MINUTEWEST(r3)/* fill tz */ lwz r4,CFG_TZ_MINUTEWEST(r3)/* fill tz */
...@@ -77,6 +70,8 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime) ...@@ -77,6 +70,8 @@ V_FUNCTION_BEGIN(__kernel_clock_gettime)
.cfi_register lr,r12 .cfi_register lr,r12
mr r11,r4 /* r11 saves tp */ mr r11,r4 /* r11 saves tp */
bl V_LOCAL_FUNC(__get_datapage) /* get data page */ bl V_LOCAL_FUNC(__get_datapage) /* get data page */
lis r7,NSEC_PER_SEC@h /* want nanoseconds */
ori r7,r7,NSEC_PER_SEC@l
50: bl V_LOCAL_FUNC(__do_get_tspec) /* get time from tb & kernel */ 50: bl V_LOCAL_FUNC(__do_get_tspec) /* get time from tb & kernel */
bne cr1,80f /* if not monotonic, all done */ bne cr1,80f /* if not monotonic, all done */
...@@ -171,49 +166,12 @@ V_FUNCTION_END(__kernel_clock_getres) ...@@ -171,49 +166,12 @@ V_FUNCTION_END(__kernel_clock_getres)
/* /*
* This is the core of gettimeofday(), it returns the xsec * This is the core of clock_gettime() and gettimeofday(),
* value in r4 and expects the datapage ptr (non clobbered) * it returns the current time in r4 (seconds) and r5.
* in r3. clobbers r0,r4,r5,r6,r7,r8 * On entry, r7 gives the resolution of r5, either USEC_PER_SEC
* When returning, r8 contains the counter value that can be reused * or NSEC_PER_SEC, giving r5 in microseconds or nanoseconds.
*/
V_FUNCTION_BEGIN(__do_get_xsec)
.cfi_startproc
/* check for update count & load values */
1: ld r8,CFG_TB_UPDATE_COUNT(r3)
andi. r0,r8,1 /* pending update ? loop */
bne- 1b
xor r0,r8,r8 /* create dependency */
add r3,r3,r0
/* Get TB & offset it. We use the MFTB macro which will generate
* workaround code for Cell.
*/
MFTB(r7)
ld r9,CFG_TB_ORIG_STAMP(r3)
subf r7,r9,r7
/* Scale result */
ld r5,CFG_TB_TO_XS(r3)
mulhdu r7,r7,r5
/* Add stamp since epoch */
ld r6,CFG_STAMP_XSEC(r3)
add r4,r6,r7
xor r0,r4,r4
add r3,r3,r0
ld r0,CFG_TB_UPDATE_COUNT(r3)
cmpld cr0,r0,r8 /* check if updated */
bne- 1b
blr
.cfi_endproc
V_FUNCTION_END(__do_get_xsec)
/*
* This is the core of clock_gettime(), it returns the current
* time in seconds and nanoseconds in r4 and r5.
* It expects the datapage ptr in r3 and doesn't clobber it. * It expects the datapage ptr in r3 and doesn't clobber it.
* It clobbers r0 and r6 and returns NSEC_PER_SEC in r7. * It clobbers r0, r6 and r9.
* On return, r8 contains the counter value that can be reused. * On return, r8 contains the counter value that can be reused.
* This clobbers cr0 but not any other cr field. * This clobbers cr0 but not any other cr field.
*/ */
...@@ -229,18 +187,18 @@ V_FUNCTION_BEGIN(__do_get_tspec) ...@@ -229,18 +187,18 @@ V_FUNCTION_BEGIN(__do_get_tspec)
/* Get TB & offset it. We use the MFTB macro which will generate /* Get TB & offset it. We use the MFTB macro which will generate
* workaround code for Cell. * workaround code for Cell.
*/ */
MFTB(r7) MFTB(r6)
ld r9,CFG_TB_ORIG_STAMP(r3) ld r9,CFG_TB_ORIG_STAMP(r3)
subf r7,r9,r7 subf r6,r9,r6
/* Scale result */ /* Scale result */
ld r5,CFG_TB_TO_XS(r3) ld r5,CFG_TB_TO_XS(r3)
sldi r7,r7,12 /* compute time since stamp_xtime */ sldi r6,r6,12 /* compute time since stamp_xtime */
mulhdu r6,r7,r5 /* in units of 2^-32 seconds */ mulhdu r6,r6,r5 /* in units of 2^-32 seconds */
/* Add stamp since epoch */ /* Add stamp since epoch */
ld r4,STAMP_XTIME+TSPC64_TV_SEC(r3) ld r4,STAMP_XTIME+TSPC64_TV_SEC(r3)
ld r5,STAMP_XTIME+TSPC64_TV_NSEC(r3) lwz r5,STAMP_SEC_FRAC(r3)
or r0,r4,r5 or r0,r4,r5
or r0,r0,r6 or r0,r0,r6
xor r0,r0,r0 xor r0,r0,r0
...@@ -250,17 +208,11 @@ V_FUNCTION_BEGIN(__do_get_tspec) ...@@ -250,17 +208,11 @@ V_FUNCTION_BEGIN(__do_get_tspec)
bne- 1b /* reload if so */ bne- 1b /* reload if so */
/* convert to seconds & nanoseconds and add to stamp */ /* convert to seconds & nanoseconds and add to stamp */
lis r7,NSEC_PER_SEC@h add r6,r6,r5 /* add on fractional seconds of xtime */
ori r7,r7,NSEC_PER_SEC@l mulhwu r5,r6,r7 /* compute micro or nanoseconds and */
mulhwu r0,r6,r7 /* compute nanoseconds and */
srdi r6,r6,32 /* seconds since stamp_xtime */ srdi r6,r6,32 /* seconds since stamp_xtime */
clrldi r0,r0,32 clrldi r5,r5,32
add r5,r5,r0 /* add nanoseconds together */
cmpd r5,r7 /* overflow? */
add r4,r4,r6 add r4,r4,r6
bltlr /* all done if no overflow */
subf r5,r7,r5 /* if overflow, adjust */
addi r4,r4,1
blr blr
.cfi_endproc .cfi_endproc
V_FUNCTION_END(__do_get_tspec) V_FUNCTION_END(__do_get_tspec)
...@@ -216,9 +216,6 @@ static int lite5200_pm_enter(suspend_state_t state) ...@@ -216,9 +216,6 @@ static int lite5200_pm_enter(suspend_state_t state)
lite5200_restore_regs(); lite5200_restore_regs();
/* restart jiffies */
wakeup_decrementer();
iounmap(mbar); iounmap(mbar);
return 0; return 0;
} }
......
...@@ -171,9 +171,6 @@ int mpc52xx_pm_enter(suspend_state_t state) ...@@ -171,9 +171,6 @@ int mpc52xx_pm_enter(suspend_state_t state)
/* restore SRAM */ /* restore SRAM */
memcpy(sram, saved_sram, sram_size); memcpy(sram, saved_sram, sram_size);
/* restart jiffies */
wakeup_decrementer();
/* reenable interrupts in PIC */ /* reenable interrupts in PIC */
out_be32(&intr->main_mask, intr_main_mask); out_be32(&intr->main_mask, intr_main_mask);
......
...@@ -310,8 +310,12 @@ static int pmu_set_cpu_speed(int low_speed) ...@@ -310,8 +310,12 @@ static int pmu_set_cpu_speed(int low_speed)
/* Restore low level PMU operations */ /* Restore low level PMU operations */
pmu_unlock(); pmu_unlock();
/* Restore decrementer */ /*
wakeup_decrementer(); * Restore decrementer; we'll take a decrementer interrupt
* as soon as interrupts are re-enabled and the generic
* clockevents code will reprogram it with the right value.
*/
set_dec(1);
/* Restore interrupts */ /* Restore interrupts */
mpic_cpu_set_priority(pic_prio); mpic_cpu_set_priority(pic_prio);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment