|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2008 Michael Brown <[email protected]>. ! 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., 675 Mass Ave, Cambridge, MA 02139, USA. ! 17: */ ! 18: ! 19: FILE_LICENCE ( GPL2_OR_LATER ); ! 20: ! 21: #include <limits.h> ! 22: #include <assert.h> ! 23: #include <unistd.h> ! 24: #include <ipxe/timer.h> ! 25: #include <ipxe/efi/efi.h> ! 26: #include <ipxe/efi/Protocol/Cpu.h> ! 27: ! 28: /** @file ! 29: * ! 30: * iPXE timer API for EFI ! 31: * ! 32: */ ! 33: ! 34: /** Scale factor to apply to CPU timer 0 ! 35: * ! 36: * The timer is scaled down in order to ensure that reasonable values ! 37: * for "number of ticks" don't exceed the size of an unsigned long. ! 38: */ ! 39: #define EFI_TIMER0_SHIFT 12 ! 40: ! 41: /** Calibration time */ ! 42: #define EFI_CALIBRATE_DELAY_MS 1 ! 43: ! 44: /** CPU protocol */ ! 45: static EFI_CPU_ARCH_PROTOCOL *cpu_arch; ! 46: EFI_REQUIRE_PROTOCOL ( EFI_CPU_ARCH_PROTOCOL, &cpu_arch ); ! 47: ! 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: ! 57: if ( ( efirc = bs->Stall ( usecs ) ) != 0 ) { ! 58: DBG ( "EFI could not delay for %ldus: %s\n", ! 59: usecs, efi_strerror ( efirc ) ); ! 60: /* Probably screwed */ ! 61: } ! 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: ! 73: /* Read CPU timer 0 (TSC) */ ! 74: if ( ( efirc = cpu_arch->GetTimerValue ( cpu_arch, 0, &time, ! 75: NULL ) ) != 0 ) { ! 76: DBG ( "EFI could not read CPU timer: %s\n", ! 77: efi_strerror ( efirc ) ); ! 78: /* Probably screwed */ ! 79: return -1UL; ! 80: } ! 81: ! 82: return ( time >> EFI_TIMER0_SHIFT ); ! 83: } ! 84: ! 85: /** ! 86: * Get number of ticks per second ! 87: * ! 88: * @ret ticks_per_sec Number of ticks per second ! 89: */ ! 90: static unsigned long efi_ticks_per_sec ( void ) { ! 91: static unsigned long ticks_per_sec = 0; ! 92: ! 93: /* Calibrate timer, if necessary. EFI does nominally provide ! 94: * the timer speed via the (optional) TimerPeriod parameter to ! 95: * the GetTimerValue() call, but it gets the speed slightly ! 96: * wrong. By up to three orders of magnitude. Not helpful. ! 97: */ ! 98: if ( ! ticks_per_sec ) { ! 99: unsigned long start; ! 100: unsigned long elapsed; ! 101: ! 102: DBG ( "Calibrating EFI timer with a %d ms delay\n", ! 103: EFI_CALIBRATE_DELAY_MS ); ! 104: start = currticks(); ! 105: mdelay ( EFI_CALIBRATE_DELAY_MS ); ! 106: elapsed = ( currticks() - start ); ! 107: ticks_per_sec = ( elapsed * ( 1000 / EFI_CALIBRATE_DELAY_MS )); ! 108: DBG ( "EFI CPU timer calibrated at %ld ticks in %d ms (%ld " ! 109: "ticks/sec)\n", elapsed, EFI_CALIBRATE_DELAY_MS, ! 110: ticks_per_sec ); ! 111: } ! 112: ! 113: return ticks_per_sec; ! 114: } ! 115: ! 116: PROVIDE_TIMER ( efi, udelay, efi_udelay ); ! 117: PROVIDE_TIMER ( efi, currticks, efi_currticks ); ! 118: PROVIDE_TIMER ( efi, ticks_per_sec, efi_ticks_per_sec );
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.