mirror of
https://github.com/ipxe/ipxe
synced 2025-12-22 13:00:39 +03:00
[efi] Use a timer event to generate the currticks() timer
We currently use the EFI_CPU_ARCH_PROTOCOL's GetTimerValue() method to generate the currticks() timer, calibrated against a 1ms delay from the boot services Stall() method. This does not work on ARM platforms, where GetTimerValue() is an empty stub which just returns EFI_UNSUPPORTED. Fix by instead creating a periodic timer event, and using this event to increment a current tick counter. Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -1,302 +0,0 @@
|
|||||||
/** @file
|
|
||||||
CPU Architectural Protocol as defined in PI spec Volume 2 DXE
|
|
||||||
|
|
||||||
This code abstracts the DXE core from processor implementation details.
|
|
||||||
|
|
||||||
Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
|
|
||||||
This program and the accompanying materials
|
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
|
||||||
which accompanies this distribution. The full text of the license may be found at
|
|
||||||
http://opensource.org/licenses/bsd-license.php
|
|
||||||
|
|
||||||
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
||||||
|
|
||||||
**/
|
|
||||||
|
|
||||||
#ifndef __ARCH_PROTOCOL_CPU_H__
|
|
||||||
#define __ARCH_PROTOCOL_CPU_H__
|
|
||||||
|
|
||||||
FILE_LICENCE ( BSD3 );
|
|
||||||
|
|
||||||
#include <ipxe/efi/Protocol/DebugSupport.h>
|
|
||||||
|
|
||||||
#define EFI_CPU_ARCH_PROTOCOL_GUID \
|
|
||||||
{ 0x26baccb1, 0x6f42, 0x11d4, {0xbc, 0xe7, 0x0, 0x80, 0xc7, 0x3c, 0x88, 0x81 } }
|
|
||||||
|
|
||||||
typedef struct _EFI_CPU_ARCH_PROTOCOL EFI_CPU_ARCH_PROTOCOL;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// The type of flush operation
|
|
||||||
///
|
|
||||||
typedef enum {
|
|
||||||
EfiCpuFlushTypeWriteBackInvalidate,
|
|
||||||
EfiCpuFlushTypeWriteBack,
|
|
||||||
EfiCpuFlushTypeInvalidate,
|
|
||||||
EfiCpuMaxFlushType
|
|
||||||
} EFI_CPU_FLUSH_TYPE;
|
|
||||||
|
|
||||||
///
|
|
||||||
/// The type of processor INIT.
|
|
||||||
///
|
|
||||||
typedef enum {
|
|
||||||
EfiCpuInit,
|
|
||||||
EfiCpuMaxInitType
|
|
||||||
} EFI_CPU_INIT_TYPE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
EFI_CPU_INTERRUPT_HANDLER that is called when a processor interrupt occurs.
|
|
||||||
|
|
||||||
@param InterruptType Defines the type of interrupt or exception that
|
|
||||||
occurred on the processor.This parameter is processor architecture specific.
|
|
||||||
@param SystemContext A pointer to the processor context when
|
|
||||||
the interrupt occurred on the processor.
|
|
||||||
|
|
||||||
@return None
|
|
||||||
|
|
||||||
**/
|
|
||||||
typedef
|
|
||||||
VOID
|
|
||||||
(EFIAPI *EFI_CPU_INTERRUPT_HANDLER)(
|
|
||||||
IN CONST EFI_EXCEPTION_TYPE InterruptType,
|
|
||||||
IN CONST EFI_SYSTEM_CONTEXT SystemContext
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function flushes the range of addresses from Start to Start+Length
|
|
||||||
from the processor's data cache. If Start is not aligned to a cache line
|
|
||||||
boundary, then the bytes before Start to the preceding cache line boundary
|
|
||||||
are also flushed. If Start+Length is not aligned to a cache line boundary,
|
|
||||||
then the bytes past Start+Length to the end of the next cache line boundary
|
|
||||||
are also flushed. The FlushType of EfiCpuFlushTypeWriteBackInvalidate must be
|
|
||||||
supported. If the data cache is fully coherent with all DMA operations, then
|
|
||||||
this function can just return EFI_SUCCESS. If the processor does not support
|
|
||||||
flushing a range of the data cache, then the entire data cache can be flushed.
|
|
||||||
|
|
||||||
@param This The EFI_CPU_ARCH_PROTOCOL instance.
|
|
||||||
@param Start The beginning physical address to flush from the processor's data
|
|
||||||
cache.
|
|
||||||
@param Length The number of bytes to flush from the processor's data cache. This
|
|
||||||
function may flush more bytes than Length specifies depending upon
|
|
||||||
the granularity of the flush operation that the processor supports.
|
|
||||||
@param FlushType Specifies the type of flush operation to perform.
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS The address range from Start to Start+Length was flushed from
|
|
||||||
the processor's data cache.
|
|
||||||
@retval EFI_UNSUPPORTEDT The processor does not support the cache flush type specified
|
|
||||||
by FlushType.
|
|
||||||
@retval EFI_DEVICE_ERROR The address range from Start to Start+Length could not be flushed
|
|
||||||
from the processor's data cache.
|
|
||||||
|
|
||||||
**/
|
|
||||||
typedef
|
|
||||||
EFI_STATUS
|
|
||||||
(EFIAPI *EFI_CPU_FLUSH_DATA_CACHE)(
|
|
||||||
IN EFI_CPU_ARCH_PROTOCOL *This,
|
|
||||||
IN EFI_PHYSICAL_ADDRESS Start,
|
|
||||||
IN UINT64 Length,
|
|
||||||
IN EFI_CPU_FLUSH_TYPE FlushType
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function enables interrupt processing by the processor.
|
|
||||||
|
|
||||||
@param This The EFI_CPU_ARCH_PROTOCOL instance.
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS Interrupts are enabled on the processor.
|
|
||||||
@retval EFI_DEVICE_ERROR Interrupts could not be enabled on the processor.
|
|
||||||
|
|
||||||
**/
|
|
||||||
typedef
|
|
||||||
EFI_STATUS
|
|
||||||
(EFIAPI *EFI_CPU_ENABLE_INTERRUPT)(
|
|
||||||
IN EFI_CPU_ARCH_PROTOCOL *This
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function disables interrupt processing by the processor.
|
|
||||||
|
|
||||||
@param This The EFI_CPU_ARCH_PROTOCOL instance.
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS Interrupts are disabled on the processor.
|
|
||||||
@retval EFI_DEVICE_ERROR Interrupts could not be disabled on the processor.
|
|
||||||
|
|
||||||
**/
|
|
||||||
typedef
|
|
||||||
EFI_STATUS
|
|
||||||
(EFIAPI *EFI_CPU_DISABLE_INTERRUPT)(
|
|
||||||
IN EFI_CPU_ARCH_PROTOCOL *This
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function retrieves the processor's current interrupt state a returns it in
|
|
||||||
State. If interrupts are currently enabled, then TRUE is returned. If interrupts
|
|
||||||
are currently disabled, then FALSE is returned.
|
|
||||||
|
|
||||||
@param This The EFI_CPU_ARCH_PROTOCOL instance.
|
|
||||||
@param State A pointer to the processor's current interrupt state. Set to TRUE if
|
|
||||||
interrupts are enabled and FALSE if interrupts are disabled.
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS The processor's current interrupt state was returned in State.
|
|
||||||
@retval EFI_INVALID_PARAMETER State is NULL.
|
|
||||||
|
|
||||||
**/
|
|
||||||
typedef
|
|
||||||
EFI_STATUS
|
|
||||||
(EFIAPI *EFI_CPU_GET_INTERRUPT_STATE)(
|
|
||||||
IN EFI_CPU_ARCH_PROTOCOL *This,
|
|
||||||
OUT BOOLEAN *State
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function generates an INIT on the processor. If this function succeeds, then the
|
|
||||||
processor will be reset, and control will not be returned to the caller. If InitType is
|
|
||||||
not supported by this processor, or the processor cannot programmatically generate an
|
|
||||||
INIT without help from external hardware, then EFI_UNSUPPORTED is returned. If an error
|
|
||||||
occurs attempting to generate an INIT, then EFI_DEVICE_ERROR is returned.
|
|
||||||
|
|
||||||
@param This The EFI_CPU_ARCH_PROTOCOL instance.
|
|
||||||
@param InitType The type of processor INIT to perform.
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS The processor INIT was performed. This return code should never be seen.
|
|
||||||
@retval EFI_UNSUPPORTED The processor INIT operation specified by InitType is not supported
|
|
||||||
by this processor.
|
|
||||||
@retval EFI_DEVICE_ERROR The processor INIT failed.
|
|
||||||
|
|
||||||
**/
|
|
||||||
typedef
|
|
||||||
EFI_STATUS
|
|
||||||
(EFIAPI *EFI_CPU_INIT)(
|
|
||||||
IN EFI_CPU_ARCH_PROTOCOL *This,
|
|
||||||
IN EFI_CPU_INIT_TYPE InitType
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function registers and enables the handler specified by InterruptHandler for a processor
|
|
||||||
interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
|
|
||||||
handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
|
|
||||||
The installed handler is called once for each processor interrupt or exception.
|
|
||||||
|
|
||||||
@param This The EFI_CPU_ARCH_PROTOCOL instance.
|
|
||||||
@param InterruptType A pointer to the processor's current interrupt state. Set to TRUE if interrupts
|
|
||||||
are enabled and FALSE if interrupts are disabled.
|
|
||||||
@param InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
|
|
||||||
when a processor interrupt occurs. If this parameter is NULL, then the handler
|
|
||||||
will be uninstalled.
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
|
|
||||||
@retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
|
|
||||||
previously installed.
|
|
||||||
@retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
|
|
||||||
previously installed.
|
|
||||||
@retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported.
|
|
||||||
|
|
||||||
**/
|
|
||||||
typedef
|
|
||||||
EFI_STATUS
|
|
||||||
(EFIAPI *EFI_CPU_REGISTER_INTERRUPT_HANDLER)(
|
|
||||||
IN EFI_CPU_ARCH_PROTOCOL *This,
|
|
||||||
IN EFI_EXCEPTION_TYPE InterruptType,
|
|
||||||
IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function reads the processor timer specified by TimerIndex and returns it in TimerValue.
|
|
||||||
|
|
||||||
@param This The EFI_CPU_ARCH_PROTOCOL instance.
|
|
||||||
@param TimerIndex Specifies which processor timer is to be returned in TimerValue. This parameter
|
|
||||||
must be between 0 and NumberOfTimers-1.
|
|
||||||
@param TimerValue Pointer to the returned timer value.
|
|
||||||
@param TimerPeriod A pointer to the amount of time that passes in femtoseconds for each increment
|
|
||||||
of TimerValue. If TimerValue does not increment at a predictable rate, then 0 is
|
|
||||||
returned. This parameter is optional and may be NULL.
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS The processor timer value specified by TimerIndex was returned in TimerValue.
|
|
||||||
@retval EFI_DEVICE_ERROR An error occurred attempting to read one of the processor's timers.
|
|
||||||
@retval EFI_INVALID_PARAMETER TimerValue is NULL or TimerIndex is not valid.
|
|
||||||
@retval EFI_UNSUPPORTED The processor does not have any readable timers.
|
|
||||||
|
|
||||||
**/
|
|
||||||
typedef
|
|
||||||
EFI_STATUS
|
|
||||||
(EFIAPI *EFI_CPU_GET_TIMER_VALUE)(
|
|
||||||
IN EFI_CPU_ARCH_PROTOCOL *This,
|
|
||||||
IN UINT32 TimerIndex,
|
|
||||||
OUT UINT64 *TimerValue,
|
|
||||||
OUT UINT64 *TimerPeriod OPTIONAL
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
This function modifies the attributes for the memory region specified by BaseAddress and
|
|
||||||
Length from their current attributes to the attributes specified by Attributes.
|
|
||||||
|
|
||||||
@param This The EFI_CPU_ARCH_PROTOCOL instance.
|
|
||||||
@param BaseAddress The physical address that is the start address of a memory region.
|
|
||||||
@param Length The size in bytes of the memory region.
|
|
||||||
@param Attributes The bit mask of attributes to set for the memory region.
|
|
||||||
|
|
||||||
@retval EFI_SUCCESS The attributes were set for the memory region.
|
|
||||||
@retval EFI_ACCESS_DENIED The attributes for the memory resource range specified by
|
|
||||||
BaseAddress and Length cannot be modified.
|
|
||||||
@retval EFI_INVALID_PARAMETER Length is zero.
|
|
||||||
Attributes specified an illegal combination of attributes that
|
|
||||||
cannot be set together.
|
|
||||||
@retval EFI_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
|
|
||||||
the memory resource range.
|
|
||||||
@retval EFI_UNSUPPORTED The processor does not support one or more bytes of the memory
|
|
||||||
resource range specified by BaseAddress and Length.
|
|
||||||
The bit mask of attributes is not support for the memory resource
|
|
||||||
range specified by BaseAddress and Length.
|
|
||||||
|
|
||||||
**/
|
|
||||||
typedef
|
|
||||||
EFI_STATUS
|
|
||||||
(EFIAPI *EFI_CPU_SET_MEMORY_ATTRIBUTES)(
|
|
||||||
IN EFI_CPU_ARCH_PROTOCOL *This,
|
|
||||||
IN EFI_PHYSICAL_ADDRESS BaseAddress,
|
|
||||||
IN UINT64 Length,
|
|
||||||
IN UINT64 Attributes
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
///
|
|
||||||
/// The EFI_CPU_ARCH_PROTOCOL is used to abstract processor-specific functions from the DXE
|
|
||||||
/// Foundation. This includes flushing caches, enabling and disabling interrupts, hooking interrupt
|
|
||||||
/// vectors and exception vectors, reading internal processor timers, resetting the processor, and
|
|
||||||
/// determining the processor frequency.
|
|
||||||
///
|
|
||||||
struct _EFI_CPU_ARCH_PROTOCOL {
|
|
||||||
EFI_CPU_FLUSH_DATA_CACHE FlushDataCache;
|
|
||||||
EFI_CPU_ENABLE_INTERRUPT EnableInterrupt;
|
|
||||||
EFI_CPU_DISABLE_INTERRUPT DisableInterrupt;
|
|
||||||
EFI_CPU_GET_INTERRUPT_STATE GetInterruptState;
|
|
||||||
EFI_CPU_INIT Init;
|
|
||||||
EFI_CPU_REGISTER_INTERRUPT_HANDLER RegisterInterruptHandler;
|
|
||||||
EFI_CPU_GET_TIMER_VALUE GetTimerValue;
|
|
||||||
EFI_CPU_SET_MEMORY_ATTRIBUTES SetMemoryAttributes;
|
|
||||||
///
|
|
||||||
/// The number of timers that are available in a processor. The value in this
|
|
||||||
/// field is a constant that must not be modified after the CPU Architectural
|
|
||||||
/// Protocol is installed. All consumers must treat this as a read-only field.
|
|
||||||
///
|
|
||||||
UINT32 NumberOfTimers;
|
|
||||||
///
|
|
||||||
/// The size, in bytes, of the alignment required for DMA buffer allocations.
|
|
||||||
/// This is typically the size of the largest data cache line in the platform.
|
|
||||||
/// The value in this field is a constant that must not be modified after the
|
|
||||||
/// CPU Architectural Protocol is installed. All consumers must treat this as
|
|
||||||
/// a read-only field.
|
|
||||||
///
|
|
||||||
UINT32 DmaBufferAlignment;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern EFI_GUID gEfiCpuArchProtocolGuid;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -15,4 +15,22 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||||||
#define TIMER_PREFIX_efi __efi_
|
#define TIMER_PREFIX_efi __efi_
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of ticks per second
|
||||||
|
*
|
||||||
|
* This is a policy decision.
|
||||||
|
*/
|
||||||
|
#define EFI_TICKS_PER_SEC 20
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get number of ticks per second
|
||||||
|
*
|
||||||
|
* @ret ticks_per_sec Number of ticks per second
|
||||||
|
*/
|
||||||
|
static inline __attribute__ (( always_inline )) unsigned long
|
||||||
|
TIMER_INLINE ( efi, ticks_per_sec ) ( void ) {
|
||||||
|
|
||||||
|
return EFI_TICKS_PER_SEC;
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* _IPXE_EFI_TIMER_H */
|
#endif /* _IPXE_EFI_TIMER_H */
|
||||||
|
|||||||
@@ -25,12 +25,10 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <ipxe/timer.h>
|
#include <ipxe/timer.h>
|
||||||
|
#include <ipxe/init.h>
|
||||||
#include <ipxe/efi/efi.h>
|
#include <ipxe/efi/efi.h>
|
||||||
#include <ipxe/efi/Protocol/Cpu.h>
|
|
||||||
|
|
||||||
/** @file
|
/** @file
|
||||||
*
|
*
|
||||||
@@ -38,19 +36,14 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Scale factor to apply to CPU timer 0
|
/** Current tick count */
|
||||||
*
|
static unsigned long efi_jiffies;
|
||||||
* The timer is scaled down in order to ensure that reasonable values
|
|
||||||
* for "number of ticks" don't exceed the size of an unsigned long.
|
|
||||||
*/
|
|
||||||
#define EFI_TIMER0_SHIFT 12
|
|
||||||
|
|
||||||
/** Calibration time */
|
/** Timer tick event */
|
||||||
#define EFI_CALIBRATE_DELAY_MS 1
|
static EFI_EVENT efi_tick_event;
|
||||||
|
|
||||||
/** CPU protocol */
|
/** Colour for debug messages */
|
||||||
static EFI_CPU_ARCH_PROTOCOL *cpu_arch;
|
#define colour &efi_jiffies
|
||||||
EFI_REQUIRE_PROTOCOL ( EFI_CPU_ARCH_PROTOCOL, &cpu_arch );
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delay for a fixed number of microseconds
|
* Delay for a fixed number of microseconds
|
||||||
@@ -64,8 +57,8 @@ static void efi_udelay ( unsigned long usecs ) {
|
|||||||
|
|
||||||
if ( ( efirc = bs->Stall ( usecs ) ) != 0 ) {
|
if ( ( efirc = bs->Stall ( usecs ) ) != 0 ) {
|
||||||
rc = -EEFI ( efirc );
|
rc = -EEFI ( efirc );
|
||||||
DBG ( "EFI could not delay for %ldus: %s\n",
|
DBGC ( colour, "EFI could not delay for %ldus: %s\n",
|
||||||
usecs, strerror ( rc ) );
|
usecs, strerror ( rc ) );
|
||||||
/* Probably screwed */
|
/* Probably screwed */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -76,53 +69,78 @@ static void efi_udelay ( unsigned long usecs ) {
|
|||||||
* @ret ticks Current time, in ticks
|
* @ret ticks Current time, in ticks
|
||||||
*/
|
*/
|
||||||
static unsigned long efi_currticks ( void ) {
|
static unsigned long efi_currticks ( void ) {
|
||||||
UINT64 time;
|
|
||||||
EFI_STATUS efirc;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
/* Read CPU timer 0 (TSC) */
|
return efi_jiffies;
|
||||||
if ( ( efirc = cpu_arch->GetTimerValue ( cpu_arch, 0, &time,
|
|
||||||
NULL ) ) != 0 ) {
|
|
||||||
rc = -EEFI ( efirc );
|
|
||||||
DBG ( "EFI could not read CPU timer: %s\n", strerror ( rc ) );
|
|
||||||
/* Probably screwed */
|
|
||||||
return -1UL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ( time >> EFI_TIMER0_SHIFT );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get number of ticks per second
|
* Timer tick
|
||||||
*
|
*
|
||||||
* @ret ticks_per_sec Number of ticks per second
|
* @v event Timer tick event
|
||||||
|
* @v context Event context
|
||||||
*/
|
*/
|
||||||
static unsigned long efi_ticks_per_sec ( void ) {
|
static EFIAPI void efi_tick ( EFI_EVENT event __unused,
|
||||||
static unsigned long ticks_per_sec = 0;
|
void *context __unused ) {
|
||||||
|
|
||||||
/* Calibrate timer, if necessary. EFI does nominally provide
|
/* Increment tick count */
|
||||||
* the timer speed via the (optional) TimerPeriod parameter to
|
efi_jiffies++;
|
||||||
* the GetTimerValue() call, but it gets the speed slightly
|
}
|
||||||
* wrong. By up to three orders of magnitude. Not helpful.
|
|
||||||
*/
|
|
||||||
if ( ! ticks_per_sec ) {
|
|
||||||
unsigned long start;
|
|
||||||
unsigned long elapsed;
|
|
||||||
|
|
||||||
DBG ( "Calibrating EFI timer with a %d ms delay\n",
|
/**
|
||||||
EFI_CALIBRATE_DELAY_MS );
|
* Start timer tick
|
||||||
start = currticks();
|
*
|
||||||
mdelay ( EFI_CALIBRATE_DELAY_MS );
|
*/
|
||||||
elapsed = ( currticks() - start );
|
static void efi_tick_startup ( void ) {
|
||||||
ticks_per_sec = ( elapsed * ( 1000 / EFI_CALIBRATE_DELAY_MS ));
|
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||||
DBG ( "EFI CPU timer calibrated at %ld ticks in %d ms (%ld "
|
EFI_STATUS efirc;
|
||||||
"ticks/sec)\n", elapsed, EFI_CALIBRATE_DELAY_MS,
|
int rc;
|
||||||
ticks_per_sec );
|
|
||||||
|
/* Create timer tick event */
|
||||||
|
if ( ( efirc = bs->CreateEvent ( ( EVT_TIMER | EVT_NOTIFY_SIGNAL ),
|
||||||
|
TPL_CALLBACK, efi_tick, NULL,
|
||||||
|
&efi_tick_event ) ) != 0 ) {
|
||||||
|
rc = -EEFI ( efirc );
|
||||||
|
DBGC ( colour, "EFI could not create timer tick: %s\n",
|
||||||
|
strerror ( rc ) );
|
||||||
|
/* Nothing we can do about it */
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ticks_per_sec;
|
/* Start timer tick */
|
||||||
|
if ( ( efirc = bs->SetTimer ( efi_tick_event, TimerPeriodic,
|
||||||
|
( 10000000 / EFI_TICKS_PER_SEC ) ) ) !=0){
|
||||||
|
rc = -EEFI ( efirc );
|
||||||
|
DBGC ( colour, "EFI could not start timer tick: %s\n",
|
||||||
|
strerror ( rc ) );
|
||||||
|
/* Nothing we can do about it */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DBGC ( colour, "EFI timer started at %d ticks per second\n",
|
||||||
|
EFI_TICKS_PER_SEC );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stop timer tick
|
||||||
|
*
|
||||||
|
* @v booting System is shutting down in order to boot
|
||||||
|
*/
|
||||||
|
static void efi_tick_shutdown ( int booting __unused ) {
|
||||||
|
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
|
||||||
|
|
||||||
|
/* Stop timer tick */
|
||||||
|
bs->SetTimer ( efi_tick_event, TimerCancel, 0 );
|
||||||
|
DBGC ( colour, "EFI timer stopped\n" );
|
||||||
|
|
||||||
|
/* Destroy timer tick event */
|
||||||
|
bs->CloseEvent ( efi_tick_event );
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Timer tick startup function */
|
||||||
|
struct startup_fn efi_tick_startup_fn __startup_fn ( STARTUP_EARLY ) = {
|
||||||
|
.startup = efi_tick_startup,
|
||||||
|
.shutdown = efi_tick_shutdown,
|
||||||
|
};
|
||||||
|
|
||||||
PROVIDE_TIMER ( efi, udelay, efi_udelay );
|
PROVIDE_TIMER ( efi, udelay, efi_udelay );
|
||||||
PROVIDE_TIMER ( efi, currticks, efi_currticks );
|
PROVIDE_TIMER ( efi, currticks, efi_currticks );
|
||||||
PROVIDE_TIMER ( efi, ticks_per_sec, efi_ticks_per_sec );
|
PROVIDE_TIMER_INLINE ( efi, ticks_per_sec );
|
||||||
|
|||||||
Reference in New Issue
Block a user