forked from mirrors/linux
		
	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:8fd63a9epowerpc: Rework VDSO gettimeofday to prevent time going backwardsc1aa687dpowerpc: Clean up obsolete code relating to decrementer and timebase John Stultz identified them and provided the conflict resolution. Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
		
						commit
						47916be4e2
					
				
					 11 changed files with 80 additions and 363 deletions
				
			
		|  | @ -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 @@ | ||||||
| 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) | ||||||
| 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 { | ||||||
| 	__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 { | ||||||
| 	__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) | ||||||
| 	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)); | ||||||
|  |  | ||||||
|  | @ -288,8 +288,6 @@ void __init smp_prepare_cpus(unsigned int max_cpus) | ||||||
| 			max_cpus = NR_CPUS; | 			max_cpus = NR_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) | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
| 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); | ||||||
| 
 | 
 | ||||||
| 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) | ||||||
| 				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) | ||||||
| 	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) | ||||||
| 	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) | ||||||
| } | } | ||||||
| #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, | ||||||
| 			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, | ||||||
| 	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, | ||||||
| 	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) | ||||||
| /* 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) | ||||||
| 		       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) | ||||||
| 	/* 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) | ||||||
| 	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 @@ | ||||||
| /* 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) | ||||||
| 	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) | ||||||
| 	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) | ||||||
| 	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) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* | /* | ||||||
|  * 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: | ||||||
| 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) | ||||||
| 	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) | ||||||
|   .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) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* | /* | ||||||
|  * 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) | ||||||
| 	/* 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) | ||||||
| 	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) | ||||||
| 
 | 
 | ||||||
| 	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) | ||||||
| 	/* 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) | ||||||
| 	/* 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); | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Thomas Gleixner
						Thomas Gleixner