You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

efi_timer.c 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /*
  2. * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. *
  19. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. #include <string.h>
  25. #include <errno.h>
  26. #include <limits.h>
  27. #include <assert.h>
  28. #include <unistd.h>
  29. #include <ipxe/timer.h>
  30. #include <ipxe/efi/efi.h>
  31. #include <ipxe/efi/Protocol/Cpu.h>
  32. /** @file
  33. *
  34. * iPXE timer API for EFI
  35. *
  36. */
  37. /** Scale factor to apply to CPU timer 0
  38. *
  39. * The timer is scaled down in order to ensure that reasonable values
  40. * for "number of ticks" don't exceed the size of an unsigned long.
  41. */
  42. #define EFI_TIMER0_SHIFT 12
  43. /** Calibration time */
  44. #define EFI_CALIBRATE_DELAY_MS 1
  45. /** CPU protocol */
  46. static EFI_CPU_ARCH_PROTOCOL *cpu_arch;
  47. EFI_REQUIRE_PROTOCOL ( EFI_CPU_ARCH_PROTOCOL, &cpu_arch );
  48. /**
  49. * Delay for a fixed number of microseconds
  50. *
  51. * @v usecs Number of microseconds for which to delay
  52. */
  53. static void efi_udelay ( unsigned long usecs ) {
  54. EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
  55. EFI_STATUS efirc;
  56. int rc;
  57. if ( ( efirc = bs->Stall ( usecs ) ) != 0 ) {
  58. rc = -EEFI ( efirc );
  59. DBG ( "EFI could not delay for %ldus: %s\n",
  60. usecs, strerror ( rc ) );
  61. /* Probably screwed */
  62. }
  63. }
  64. /**
  65. * Get current system time in ticks
  66. *
  67. * @ret ticks Current time, in ticks
  68. */
  69. static unsigned long efi_currticks ( void ) {
  70. UINT64 time;
  71. EFI_STATUS efirc;
  72. int rc;
  73. /* Read CPU timer 0 (TSC) */
  74. if ( ( efirc = cpu_arch->GetTimerValue ( cpu_arch, 0, &time,
  75. NULL ) ) != 0 ) {
  76. rc = -EEFI ( efirc );
  77. DBG ( "EFI could not read CPU timer: %s\n", strerror ( rc ) );
  78. /* Probably screwed */
  79. return -1UL;
  80. }
  81. return ( time >> EFI_TIMER0_SHIFT );
  82. }
  83. /**
  84. * Get number of ticks per second
  85. *
  86. * @ret ticks_per_sec Number of ticks per second
  87. */
  88. static unsigned long efi_ticks_per_sec ( void ) {
  89. static unsigned long ticks_per_sec = 0;
  90. /* Calibrate timer, if necessary. EFI does nominally provide
  91. * the timer speed via the (optional) TimerPeriod parameter to
  92. * the GetTimerValue() call, but it gets the speed slightly
  93. * wrong. By up to three orders of magnitude. Not helpful.
  94. */
  95. if ( ! ticks_per_sec ) {
  96. unsigned long start;
  97. unsigned long elapsed;
  98. DBG ( "Calibrating EFI timer with a %d ms delay\n",
  99. EFI_CALIBRATE_DELAY_MS );
  100. start = currticks();
  101. mdelay ( EFI_CALIBRATE_DELAY_MS );
  102. elapsed = ( currticks() - start );
  103. ticks_per_sec = ( elapsed * ( 1000 / EFI_CALIBRATE_DELAY_MS ));
  104. DBG ( "EFI CPU timer calibrated at %ld ticks in %d ms (%ld "
  105. "ticks/sec)\n", elapsed, EFI_CALIBRATE_DELAY_MS,
  106. ticks_per_sec );
  107. }
  108. return ticks_per_sec;
  109. }
  110. PROVIDE_TIMER ( efi, udelay, efi_udelay );
  111. PROVIDE_TIMER ( efi, currticks, efi_currticks );
  112. PROVIDE_TIMER ( efi, ticks_per_sec, efi_ticks_per_sec );