diff options
Diffstat (limited to 'arch/powerpc/kernel/time.c')
-rw-r--r-- | arch/powerpc/kernel/time.c | 116 |
1 files changed, 8 insertions, 108 deletions
diff --git a/arch/powerpc/kernel/time.c b/arch/powerpc/kernel/time.c index 567dd7c3ac2a..2c42cd72d0f5 100644 --- a/arch/powerpc/kernel/time.c +++ b/arch/powerpc/kernel/time.c | |||
@@ -17,8 +17,7 @@ | |||
17 | * | 17 | * |
18 | * TODO (not necessarily in this file): | 18 | * TODO (not necessarily in this file): |
19 | * - improve precision and reproducibility of timebase frequency | 19 | * - improve precision and reproducibility of timebase frequency |
20 | * measurement at boot time. (for iSeries, we calibrate the timebase | 20 | * measurement at boot time. |
21 | * against the Titan chip's clock.) | ||
22 | * - for astronomical applications: add a new function to get | 21 | * - for astronomical applications: add a new function to get |
23 | * non ambiguous timestamps even around leap seconds. This needs | 22 | * non ambiguous timestamps even around leap seconds. This needs |
24 | * a new timestamp format and a good name. | 23 | * a new timestamp format and a good name. |
@@ -70,10 +69,6 @@ | |||
70 | #include <asm/vdso_datapage.h> | 69 | #include <asm/vdso_datapage.h> |
71 | #include <asm/firmware.h> | 70 | #include <asm/firmware.h> |
72 | #include <asm/cputime.h> | 71 | #include <asm/cputime.h> |
73 | #ifdef CONFIG_PPC_ISERIES | ||
74 | #include <asm/iseries/it_lp_queue.h> | ||
75 | #include <asm/iseries/hv_call_xm.h> | ||
76 | #endif | ||
77 | 72 | ||
78 | /* powerpc clocksource/clockevent code */ | 73 | /* powerpc clocksource/clockevent code */ |
79 | 74 | ||
@@ -117,14 +112,6 @@ static struct clock_event_device decrementer_clockevent = { | |||
117 | DEFINE_PER_CPU(u64, decrementers_next_tb); | 112 | DEFINE_PER_CPU(u64, decrementers_next_tb); |
118 | static DEFINE_PER_CPU(struct clock_event_device, decrementers); | 113 | static DEFINE_PER_CPU(struct clock_event_device, decrementers); |
119 | 114 | ||
120 | #ifdef CONFIG_PPC_ISERIES | ||
121 | static unsigned long __initdata iSeries_recal_titan; | ||
122 | static signed long __initdata iSeries_recal_tb; | ||
123 | |||
124 | /* Forward declaration is only needed for iSereis compiles */ | ||
125 | static void __init clocksource_init(void); | ||
126 | #endif | ||
127 | |||
128 | #define XSEC_PER_SEC (1024*1024) | 115 | #define XSEC_PER_SEC (1024*1024) |
129 | 116 | ||
130 | #ifdef CONFIG_PPC64 | 117 | #ifdef CONFIG_PPC64 |
@@ -259,7 +246,6 @@ void accumulate_stolen_time(void) | |||
259 | u64 sst, ust; | 246 | u64 sst, ust; |
260 | 247 | ||
261 | u8 save_soft_enabled = local_paca->soft_enabled; | 248 | u8 save_soft_enabled = local_paca->soft_enabled; |
262 | u8 save_hard_enabled = local_paca->hard_enabled; | ||
263 | 249 | ||
264 | /* We are called early in the exception entry, before | 250 | /* We are called early in the exception entry, before |
265 | * soft/hard_enabled are sync'ed to the expected state | 251 | * soft/hard_enabled are sync'ed to the expected state |
@@ -268,7 +254,6 @@ void accumulate_stolen_time(void) | |||
268 | * complain | 254 | * complain |
269 | */ | 255 | */ |
270 | local_paca->soft_enabled = 0; | 256 | local_paca->soft_enabled = 0; |
271 | local_paca->hard_enabled = 0; | ||
272 | 257 | ||
273 | sst = scan_dispatch_log(local_paca->starttime_user); | 258 | sst = scan_dispatch_log(local_paca->starttime_user); |
274 | ust = scan_dispatch_log(local_paca->starttime); | 259 | ust = scan_dispatch_log(local_paca->starttime); |
@@ -277,7 +262,6 @@ void accumulate_stolen_time(void) | |||
277 | local_paca->stolen_time += ust + sst; | 262 | local_paca->stolen_time += ust + sst; |
278 | 263 | ||
279 | local_paca->soft_enabled = save_soft_enabled; | 264 | local_paca->soft_enabled = save_soft_enabled; |
280 | local_paca->hard_enabled = save_hard_enabled; | ||
281 | } | 265 | } |
282 | 266 | ||
283 | static inline u64 calculate_stolen_time(u64 stop_tb) | 267 | static inline u64 calculate_stolen_time(u64 stop_tb) |
@@ -426,74 +410,6 @@ unsigned long profile_pc(struct pt_regs *regs) | |||
426 | EXPORT_SYMBOL(profile_pc); | 410 | EXPORT_SYMBOL(profile_pc); |
427 | #endif | 411 | #endif |
428 | 412 | ||
429 | #ifdef CONFIG_PPC_ISERIES | ||
430 | |||
431 | /* | ||
432 | * This function recalibrates the timebase based on the 49-bit time-of-day | ||
433 | * value in the Titan chip. The Titan is much more accurate than the value | ||
434 | * returned by the service processor for the timebase frequency. | ||
435 | */ | ||
436 | |||
437 | static int __init iSeries_tb_recal(void) | ||
438 | { | ||
439 | unsigned long titan, tb; | ||
440 | |||
441 | /* Make sure we only run on iSeries */ | ||
442 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | ||
443 | return -ENODEV; | ||
444 | |||
445 | tb = get_tb(); | ||
446 | titan = HvCallXm_loadTod(); | ||
447 | if ( iSeries_recal_titan ) { | ||
448 | unsigned long tb_ticks = tb - iSeries_recal_tb; | ||
449 | unsigned long titan_usec = (titan - iSeries_recal_titan) >> 12; | ||
450 | unsigned long new_tb_ticks_per_sec = (tb_ticks * USEC_PER_SEC)/titan_usec; | ||
451 | unsigned long new_tb_ticks_per_jiffy = | ||
452 | DIV_ROUND_CLOSEST(new_tb_ticks_per_sec, HZ); | ||
453 | long tick_diff = new_tb_ticks_per_jiffy - tb_ticks_per_jiffy; | ||
454 | char sign = '+'; | ||
455 | /* make sure tb_ticks_per_sec and tb_ticks_per_jiffy are consistent */ | ||
456 | new_tb_ticks_per_sec = new_tb_ticks_per_jiffy * HZ; | ||
457 | |||
458 | if ( tick_diff < 0 ) { | ||
459 | tick_diff = -tick_diff; | ||
460 | sign = '-'; | ||
461 | } | ||
462 | if ( tick_diff ) { | ||
463 | if ( tick_diff < tb_ticks_per_jiffy/25 ) { | ||
464 | printk( "Titan recalibrate: new tb_ticks_per_jiffy = %lu (%c%ld)\n", | ||
465 | new_tb_ticks_per_jiffy, sign, tick_diff ); | ||
466 | tb_ticks_per_jiffy = new_tb_ticks_per_jiffy; | ||
467 | tb_ticks_per_sec = new_tb_ticks_per_sec; | ||
468 | calc_cputime_factors(); | ||
469 | vdso_data->tb_ticks_per_sec = tb_ticks_per_sec; | ||
470 | setup_cputime_one_jiffy(); | ||
471 | } | ||
472 | else { | ||
473 | printk( "Titan recalibrate: FAILED (difference > 4 percent)\n" | ||
474 | " new tb_ticks_per_jiffy = %lu\n" | ||
475 | " old tb_ticks_per_jiffy = %lu\n", | ||
476 | new_tb_ticks_per_jiffy, tb_ticks_per_jiffy ); | ||
477 | } | ||
478 | } | ||
479 | } | ||
480 | iSeries_recal_titan = titan; | ||
481 | iSeries_recal_tb = tb; | ||
482 | |||
483 | /* Called here as now we know accurate values for the timebase */ | ||
484 | clocksource_init(); | ||
485 | return 0; | ||
486 | } | ||
487 | late_initcall(iSeries_tb_recal); | ||
488 | |||
489 | /* Called from platform early init */ | ||
490 | void __init iSeries_time_init_early(void) | ||
491 | { | ||
492 | iSeries_recal_tb = get_tb(); | ||
493 | iSeries_recal_titan = HvCallXm_loadTod(); | ||
494 | } | ||
495 | #endif /* CONFIG_PPC_ISERIES */ | ||
496 | |||
497 | #ifdef CONFIG_IRQ_WORK | 413 | #ifdef CONFIG_IRQ_WORK |
498 | 414 | ||
499 | /* | 415 | /* |
@@ -550,16 +466,6 @@ void arch_irq_work_raise(void) | |||
550 | #endif /* CONFIG_IRQ_WORK */ | 466 | #endif /* CONFIG_IRQ_WORK */ |
551 | 467 | ||
552 | /* | 468 | /* |
553 | * For iSeries shared processors, we have to let the hypervisor | ||
554 | * set the hardware decrementer. We set a virtual decrementer | ||
555 | * in the lppaca and call the hypervisor if the virtual | ||
556 | * decrementer is less than the current value in the hardware | ||
557 | * decrementer. (almost always the new decrementer value will | ||
558 | * be greater than the current hardware decementer so the hypervisor | ||
559 | * call will not be needed) | ||
560 | */ | ||
561 | |||
562 | /* | ||
563 | * timer_interrupt - gets called when the decrementer overflows, | 469 | * timer_interrupt - gets called when the decrementer overflows, |
564 | * with interrupts disabled. | 470 | * with interrupts disabled. |
565 | */ | 471 | */ |
@@ -580,6 +486,11 @@ void timer_interrupt(struct pt_regs * regs) | |||
580 | if (!cpu_online(smp_processor_id())) | 486 | if (!cpu_online(smp_processor_id())) |
581 | return; | 487 | return; |
582 | 488 | ||
489 | /* Conditionally hard-enable interrupts now that the DEC has been | ||
490 | * bumped to its maximum value | ||
491 | */ | ||
492 | may_hard_irq_enable(); | ||
493 | |||
583 | trace_timer_interrupt_entry(regs); | 494 | trace_timer_interrupt_entry(regs); |
584 | 495 | ||
585 | __get_cpu_var(irq_stat).timer_irqs++; | 496 | __get_cpu_var(irq_stat).timer_irqs++; |
@@ -597,20 +508,10 @@ void timer_interrupt(struct pt_regs * regs) | |||
597 | irq_work_run(); | 508 | irq_work_run(); |
598 | } | 509 | } |
599 | 510 | ||
600 | #ifdef CONFIG_PPC_ISERIES | ||
601 | if (firmware_has_feature(FW_FEATURE_ISERIES)) | ||
602 | get_lppaca()->int_dword.fields.decr_int = 0; | ||
603 | #endif | ||
604 | |||
605 | *next_tb = ~(u64)0; | 511 | *next_tb = ~(u64)0; |
606 | if (evt->event_handler) | 512 | if (evt->event_handler) |
607 | evt->event_handler(evt); | 513 | evt->event_handler(evt); |
608 | 514 | ||
609 | #ifdef CONFIG_PPC_ISERIES | ||
610 | if (firmware_has_feature(FW_FEATURE_ISERIES) && hvlpevent_is_pending()) | ||
611 | process_hvlpevents(); | ||
612 | #endif | ||
613 | |||
614 | #ifdef CONFIG_PPC64 | 515 | #ifdef CONFIG_PPC64 |
615 | /* collect purr register values often, for accurate calculations */ | 516 | /* collect purr register values often, for accurate calculations */ |
616 | if (firmware_has_feature(FW_FEATURE_SPLPAR)) { | 517 | if (firmware_has_feature(FW_FEATURE_SPLPAR)) { |
@@ -982,9 +883,8 @@ void __init time_init(void) | |||
982 | */ | 883 | */ |
983 | start_cpu_decrementer(); | 884 | start_cpu_decrementer(); |
984 | 885 | ||
985 | /* Register the clocksource, if we're not running on iSeries */ | 886 | /* Register the clocksource */ |
986 | if (!firmware_has_feature(FW_FEATURE_ISERIES)) | 887 | clocksource_init(); |
987 | clocksource_init(); | ||
988 | 888 | ||
989 | init_decrementer_clockevent(); | 889 | init_decrementer_clockevent(); |
990 | } | 890 | } |