From 9e5e66d15e2a7280fdba2ecbd9f583c8485e21bf Mon Sep 17 00:00:00 2001 From: Vladimir 'phcoder' Serbinenko Date: Sat, 9 Jun 2012 10:52:39 +0200 Subject: [PATCH] Use ITC on IA64 rather than broken routine based on daytime. * grub-core/kern/efi/efi.c (grub_rtc_get_time_ms) [__ia64__]: Remove on ia64. (grub_get_rtc) [__ia64__]: Likewise. * grub-core/kern/ia64/efi/init.c (divisor): New variable. (get_itc): New function. (grub_rtc_get_time_ms): Likewise. (grub_machine_init): Calibrate ITC. * include/grub/efi/time.h (grub_get_rtc), (GRUB_TICKS_PER_SECOND): Keep only on non-ia64. Don't export since it's broken and used only if TSC is unavailable. --- ChangeLog | 15 +++++++++++++++ grub-core/kern/efi/efi.c | 2 ++ grub-core/kern/ia64/efi/init.c | 33 +++++++++++++++++++++++++++++++++ include/grub/efi/time.h | 4 +++- 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 8fd093457..4c4d5336c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +2012-06-09 Vladimir Serbinenko + + Use ITC on IA64 rather than broken routine based on daytime. + + * grub-core/kern/efi/efi.c (grub_rtc_get_time_ms) [__ia64__]: Remove on + ia64. + (grub_get_rtc) [__ia64__]: Likewise. + * grub-core/kern/ia64/efi/init.c (divisor): New variable. + (get_itc): New function. + (grub_rtc_get_time_ms): Likewise. + (grub_machine_init): Calibrate ITC. + * include/grub/efi/time.h (grub_get_rtc), (GRUB_TICKS_PER_SECOND): + Keep only on non-ia64. Don't export since it's broken and used only + if TSC is unavailable. + 2012-06-09 Vladimir Serbinenko * grub-core/disk/efi/efidisk.c (find_parent_device): Return the parent diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c index 6f12c7618..a59a6edbc 100644 --- a/grub-core/kern/efi/efi.c +++ b/grub-core/kern/efi/efi.c @@ -230,6 +230,7 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, return NULL; } +#ifndef __ia64__ grub_uint64_t grub_rtc_get_time_ms (void) { @@ -250,6 +251,7 @@ grub_get_rtc (void) { return grub_rtc_get_time_ms (); } +#endif #pragma GCC diagnostic ignored "-Wcast-align" diff --git a/grub-core/kern/ia64/efi/init.c b/grub-core/kern/ia64/efi/init.c index e2fa58090..7fa6fbf71 100644 --- a/grub-core/kern/ia64/efi/init.c +++ b/grub-core/kern/ia64/efi/init.c @@ -27,10 +27,43 @@ #include #include +static grub_uint64_t divisor = 1; + +static grub_uint64_t +get_itc (void) +{ + grub_uint64_t ret; + asm volatile ("mov %0=ar.itc" : "=r" (ret)); + return ret; +} + +grub_uint64_t +grub_rtc_get_time_ms (void) +{ + return get_itc () / divisor; +} + void grub_machine_init (void) { + grub_efi_event_t event; + grub_uint64_t before, after; + grub_efi_uintn_t idx; grub_efi_init (); + + efi_call_5 (grub_efi_system_table->boot_services->create_event, + GRUB_EFI_EVT_TIMER, GRUB_EFI_TPL_CALLBACK, 0, 0, &event); + + before = get_itc (); + efi_call_3 (grub_efi_system_table->boot_services->set_timer, event, + GRUB_EFI_TIMER_RELATIVE, 200000); + efi_call_3 (grub_efi_system_table->boot_services->wait_for_event, 1, + &event, &idx); + after = get_itc (); + efi_call_1 (grub_efi_system_table->boot_services->close_event, event); + divisor = (after - before + 5) / 20; + if (divisor == 0) + divisor = 800000; grub_install_get_time_ms (grub_rtc_get_time_ms); } diff --git a/include/grub/efi/time.h b/include/grub/efi/time.h index 51b337309..1c38ac0e7 100644 --- a/include/grub/efi/time.h +++ b/include/grub/efi/time.h @@ -21,9 +21,11 @@ #include +#ifndef __ia64__ #define GRUB_TICKS_PER_SECOND 1000 /* Return the real time in ticks. */ -grub_uint32_t EXPORT_FUNC (grub_get_rtc) (void); +grub_uint32_t grub_get_rtc (void); +#endif #endif /* ! GRUB_EFI_TIME_HEADER */