aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/time.c')
-rw-r--r--arch/powerpc/kernel/time.c65
1 files changed, 41 insertions, 24 deletions
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c
index 2c8564d54e4d..e5df167f7824 100644
--- a/arch/powerpc/kernel/time.c
+++ b/arch/powerpc/kernel/time.c
@@ -77,9 +77,8 @@
77/* keep track of when we need to update the rtc */ 77/* keep track of when we need to update the rtc */
78time_t last_rtc_update; 78time_t last_rtc_update;
79#ifdef CONFIG_PPC_ISERIES 79#ifdef CONFIG_PPC_ISERIES
80unsigned long iSeries_recal_titan = 0; 80static unsigned long __initdata iSeries_recal_titan;
81unsigned long iSeries_recal_tb = 0; 81static signed long __initdata iSeries_recal_tb;
82static unsigned long first_settimeofday = 1;
83#endif 82#endif
84 83
85/* The decrementer counts down by 128 every 128ns on a 601. */ 84/* The decrementer counts down by 128 every 128ns on a 601. */
@@ -113,8 +112,9 @@ u64 ticklen_to_xs; /* 0.64 fraction */
113DEFINE_SPINLOCK(rtc_lock); 112DEFINE_SPINLOCK(rtc_lock);
114EXPORT_SYMBOL_GPL(rtc_lock); 113EXPORT_SYMBOL_GPL(rtc_lock);
115 114
116u64 tb_to_ns_scale; 115static u64 tb_to_ns_scale __read_mostly;
117unsigned tb_to_ns_shift; 116static unsigned tb_to_ns_shift __read_mostly;
117static unsigned long boot_tb __read_mostly;
118 118
119struct gettimeofday_struct do_gtod; 119struct gettimeofday_struct do_gtod;
120 120
@@ -214,7 +214,6 @@ static void account_process_time(struct pt_regs *regs)
214 run_posix_cpu_timers(current); 214 run_posix_cpu_timers(current);
215} 215}
216 216
217#ifdef CONFIG_PPC_SPLPAR
218/* 217/*
219 * Stuff for accounting stolen time. 218 * Stuff for accounting stolen time.
220 */ 219 */
@@ -222,19 +221,28 @@ struct cpu_purr_data {
222 int initialized; /* thread is running */ 221 int initialized; /* thread is running */
223 u64 tb; /* last TB value read */ 222 u64 tb; /* last TB value read */
224 u64 purr; /* last PURR value read */ 223 u64 purr; /* last PURR value read */
225 spinlock_t lock;
226}; 224};
227 225
226/*
227 * Each entry in the cpu_purr_data array is manipulated only by its
228 * "owner" cpu -- usually in the timer interrupt but also occasionally
229 * in process context for cpu online. As long as cpus do not touch
230 * each others' cpu_purr_data, disabling local interrupts is
231 * sufficient to serialize accesses.
232 */
228static DEFINE_PER_CPU(struct cpu_purr_data, cpu_purr_data); 233static DEFINE_PER_CPU(struct cpu_purr_data, cpu_purr_data);
229 234
230static void snapshot_tb_and_purr(void *data) 235static void snapshot_tb_and_purr(void *data)
231{ 236{
237 unsigned long flags;
232 struct cpu_purr_data *p = &__get_cpu_var(cpu_purr_data); 238 struct cpu_purr_data *p = &__get_cpu_var(cpu_purr_data);
233 239
240 local_irq_save(flags);
234 p->tb = mftb(); 241 p->tb = mftb();
235 p->purr = mfspr(SPRN_PURR); 242 p->purr = mfspr(SPRN_PURR);
236 wmb(); 243 wmb();
237 p->initialized = 1; 244 p->initialized = 1;
245 local_irq_restore(flags);
238} 246}
239 247
240/* 248/*
@@ -242,15 +250,14 @@ static void snapshot_tb_and_purr(void *data)
242 */ 250 */
243void snapshot_timebases(void) 251void snapshot_timebases(void)
244{ 252{
245 int cpu;
246
247 if (!cpu_has_feature(CPU_FTR_PURR)) 253 if (!cpu_has_feature(CPU_FTR_PURR))
248 return; 254 return;
249 for_each_possible_cpu(cpu)
250 spin_lock_init(&per_cpu(cpu_purr_data, cpu).lock);
251 on_each_cpu(snapshot_tb_and_purr, NULL, 0, 1); 255 on_each_cpu(snapshot_tb_and_purr, NULL, 0, 1);
252} 256}
253 257
258/*
259 * Must be called with interrupts disabled.
260 */
254void calculate_steal_time(void) 261void calculate_steal_time(void)
255{ 262{
256 u64 tb, purr; 263 u64 tb, purr;
@@ -262,7 +269,6 @@ void calculate_steal_time(void)
262 pme = &per_cpu(cpu_purr_data, smp_processor_id()); 269 pme = &per_cpu(cpu_purr_data, smp_processor_id());
263 if (!pme->initialized) 270 if (!pme->initialized)
264 return; /* this can happen in early boot */ 271 return; /* this can happen in early boot */
265 spin_lock(&pme->lock);
266 tb = mftb(); 272 tb = mftb();
267 purr = mfspr(SPRN_PURR); 273 purr = mfspr(SPRN_PURR);
268 stolen = (tb - pme->tb) - (purr - pme->purr); 274 stolen = (tb - pme->tb) - (purr - pme->purr);
@@ -270,9 +276,9 @@ void calculate_steal_time(void)
270 account_steal_time(current, stolen); 276 account_steal_time(current, stolen);
271 pme->tb = tb; 277 pme->tb = tb;
272 pme->purr = purr; 278 pme->purr = purr;
273 spin_unlock(&pme->lock);
274} 279}
275 280
281#ifdef CONFIG_PPC_SPLPAR
276/* 282/*
277 * Must be called before the cpu is added to the online map when 283 * Must be called before the cpu is added to the online map when
278 * a cpu is being brought up at runtime. 284 * a cpu is being brought up at runtime.
@@ -284,12 +290,12 @@ static void snapshot_purr(void)
284 290
285 if (!cpu_has_feature(CPU_FTR_PURR)) 291 if (!cpu_has_feature(CPU_FTR_PURR))
286 return; 292 return;
293 local_irq_save(flags);
287 pme = &per_cpu(cpu_purr_data, smp_processor_id()); 294 pme = &per_cpu(cpu_purr_data, smp_processor_id());
288 spin_lock_irqsave(&pme->lock, flags);
289 pme->tb = mftb(); 295 pme->tb = mftb();
290 pme->purr = mfspr(SPRN_PURR); 296 pme->purr = mfspr(SPRN_PURR);
291 pme->initialized = 1; 297 pme->initialized = 1;
292 spin_unlock_irqrestore(&pme->lock, flags); 298 local_irq_restore(flags);
293} 299}
294 300
295#endif /* CONFIG_PPC_SPLPAR */ 301#endif /* CONFIG_PPC_SPLPAR */
@@ -550,10 +556,15 @@ EXPORT_SYMBOL(profile_pc);
550 * returned by the service processor for the timebase frequency. 556 * returned by the service processor for the timebase frequency.
551 */ 557 */
552 558
553static void iSeries_tb_recal(void) 559static int __init iSeries_tb_recal(void)
554{ 560{
555 struct div_result divres; 561 struct div_result divres;
556 unsigned long titan, tb; 562 unsigned long titan, tb;
563
564 /* Make sure we only run on iSeries */
565 if (!firmware_has_feature(FW_FEATURE_ISERIES))
566 return -ENODEV;
567
557 tb = get_tb(); 568 tb = get_tb();
558 titan = HvCallXm_loadTod(); 569 titan = HvCallXm_loadTod();
559 if ( iSeries_recal_titan ) { 570 if ( iSeries_recal_titan ) {
@@ -594,8 +605,18 @@ static void iSeries_tb_recal(void)
594 } 605 }
595 iSeries_recal_titan = titan; 606 iSeries_recal_titan = titan;
596 iSeries_recal_tb = tb; 607 iSeries_recal_tb = tb;
608
609 return 0;
597} 610}
598#endif 611late_initcall(iSeries_tb_recal);
612
613/* Called from platform early init */
614void __init iSeries_time_init_early(void)
615{
616 iSeries_recal_tb = get_tb();
617 iSeries_recal_titan = HvCallXm_loadTod();
618}
619#endif /* CONFIG_PPC_ISERIES */
599 620
600/* 621/*
601 * For iSeries shared processors, we have to let the hypervisor 622 * For iSeries shared processors, we have to let the hypervisor
@@ -735,7 +756,7 @@ unsigned long long sched_clock(void)
735{ 756{
736 if (__USE_RTC()) 757 if (__USE_RTC())
737 return get_rtc(); 758 return get_rtc();
738 return mulhdu(get_tb(), tb_to_ns_scale) << tb_to_ns_shift; 759 return mulhdu(get_tb() - boot_tb, tb_to_ns_scale) << tb_to_ns_shift;
739} 760}
740 761
741int do_settimeofday(struct timespec *tv) 762int do_settimeofday(struct timespec *tv)
@@ -759,12 +780,6 @@ int do_settimeofday(struct timespec *tv)
759 * to the RTC again, or write to the RTC but then they don't call 780 * to the RTC again, or write to the RTC but then they don't call
760 * settimeofday to perform this operation. 781 * settimeofday to perform this operation.
761 */ 782 */
762#ifdef CONFIG_PPC_ISERIES
763 if (firmware_has_feature(FW_FEATURE_ISERIES) && first_settimeofday) {
764 iSeries_tb_recal();
765 first_settimeofday = 0;
766 }
767#endif
768 783
769 /* Make userspace gettimeofday spin until we're done. */ 784 /* Make userspace gettimeofday spin until we're done. */
770 ++vdso_data->tb_update_count; 785 ++vdso_data->tb_update_count;
@@ -960,6 +975,8 @@ void __init time_init(void)
960 } 975 }
961 tb_to_ns_scale = scale; 976 tb_to_ns_scale = scale;
962 tb_to_ns_shift = shift; 977 tb_to_ns_shift = shift;
978 /* Save the current timebase to pretty up CONFIG_PRINTK_TIME */
979 boot_tb = get_tb();
963 980
964 tm = get_boot_time(); 981 tm = get_boot_time();
965 982