mirror of
https://github.com/ipxe/ipxe
synced 2025-12-19 11:00:27 +03:00
[time] Allow timer to be selected at runtime
Allow the active timer (providing udelay() and currticks()) to be selected at runtime based on probing during the INIT_EARLY stage of initialisation. TICKS_PER_SEC is now a fixed compile-time constant for all builds, and is independent of the underlying clock tick rate. We choose the value 1024 to allow multiplications and divisions on seconds to be converted to bit shifts. TICKS_PER_MS is defined as 1, allowing multiplications and divisions on milliseconds to be omitted entirely. The 2% inaccuracy in this definition is negligible when using the standard BIOS timer (running at around 18.2Hz). TIMER_RDTSC now checks for a constant TSC before claiming to be a usable timer. (This timer can be tested in KVM via the command-line option "-cpu host,+invtsc".) Signed-off-by: Michael Brown <mcb30@ipxe.org>
This commit is contained in:
@@ -1,36 +0,0 @@
|
||||
#ifndef _IPXE_EFI_TIMER_H
|
||||
#define _IPXE_EFI_TIMER_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* iPXE timer API for EFI
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#ifdef TIMER_EFI
|
||||
#define TIMER_PREFIX_efi
|
||||
#else
|
||||
#define TIMER_PREFIX_efi __efi_
|
||||
#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 */
|
||||
@@ -1,18 +0,0 @@
|
||||
#ifndef _IPXE_LINUX_TIMER_H
|
||||
#define _IPXE_LINUX_TIMER_H
|
||||
|
||||
/** @file
|
||||
*
|
||||
* iPXE timer API for Linux
|
||||
*
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#ifdef TIMER_LINUX
|
||||
#define TIMER_PREFIX_linux
|
||||
#else
|
||||
#define TIMER_PREFIX_linux __linux_
|
||||
#endif
|
||||
|
||||
#endif /* _IPXE_LINUX_TIMER_H */
|
||||
@@ -3,75 +3,77 @@
|
||||
|
||||
/** @file
|
||||
*
|
||||
* iPXE timer API
|
||||
* iPXE timers
|
||||
*
|
||||
* The timer API provides udelay() for fixed delays, and currticks()
|
||||
* for a monotonically increasing tick counter.
|
||||
*/
|
||||
|
||||
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
|
||||
|
||||
#include <ipxe/api.h>
|
||||
#include <config/timer.h>
|
||||
|
||||
/**
|
||||
* Calculate static inline timer API function name
|
||||
*
|
||||
* @v _prefix Subsystem prefix
|
||||
* @v _api_func API function
|
||||
* @ret _subsys_func Subsystem API function
|
||||
*/
|
||||
#define TIMER_INLINE( _subsys, _api_func ) \
|
||||
SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func )
|
||||
|
||||
/**
|
||||
* Provide a timer API implementation
|
||||
*
|
||||
* @v _prefix Subsystem prefix
|
||||
* @v _api_func API function
|
||||
* @v _func Implementing function
|
||||
*/
|
||||
#define PROVIDE_TIMER( _subsys, _api_func, _func ) \
|
||||
PROVIDE_SINGLE_API ( TIMER_PREFIX_ ## _subsys, _api_func, _func )
|
||||
|
||||
/**
|
||||
* Provide a static inline timer API implementation
|
||||
*
|
||||
* @v _prefix Subsystem prefix
|
||||
* @v _api_func API function
|
||||
*/
|
||||
#define PROVIDE_TIMER_INLINE( _subsys, _api_func ) \
|
||||
PROVIDE_SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func )
|
||||
|
||||
/* Include all architecture-independent I/O API headers */
|
||||
#include <ipxe/efi/efi_timer.h>
|
||||
#include <ipxe/linux/linux_timer.h>
|
||||
|
||||
/* Include all architecture-dependent I/O API headers */
|
||||
#include <bits/timer.h>
|
||||
|
||||
/**
|
||||
* Delay for a fixed number of microseconds
|
||||
*
|
||||
* @v usecs Number of microseconds for which to delay
|
||||
*/
|
||||
void udelay ( unsigned long usecs );
|
||||
|
||||
/**
|
||||
* Get current system time in ticks
|
||||
*
|
||||
* @ret ticks Current time, in ticks
|
||||
*/
|
||||
unsigned long currticks ( void );
|
||||
|
||||
/**
|
||||
* Get number of ticks per second
|
||||
*
|
||||
* @ret ticks_per_sec Number of ticks per second
|
||||
*/
|
||||
unsigned long ticks_per_sec ( void );
|
||||
#include <ipxe/tables.h>
|
||||
|
||||
/** Number of ticks per second */
|
||||
#define TICKS_PER_SEC ( ticks_per_sec() )
|
||||
#define TICKS_PER_SEC 1024
|
||||
|
||||
/** Number of ticks per millisecond
|
||||
*
|
||||
* This is (obviously) not 100% consistent with the definition of
|
||||
* TICKS_PER_SEC, but it allows for multiplications and divisions to
|
||||
* be elided. In any case, timer ticks are not expected to be a
|
||||
* precision timing source; for example, the standard BIOS timer is
|
||||
* based on an 18.2Hz clock.
|
||||
*/
|
||||
#define TICKS_PER_MS 1
|
||||
|
||||
/** A timer */
|
||||
struct timer {
|
||||
/** Name */
|
||||
const char *name;
|
||||
/**
|
||||
* Probe timer
|
||||
*
|
||||
* @ret rc Return status code
|
||||
*/
|
||||
int ( * probe ) ( void );
|
||||
/**
|
||||
* Get current system time in ticks
|
||||
*
|
||||
* @ret ticks Current time, in ticks
|
||||
*/
|
||||
unsigned long ( * currticks ) ( void );
|
||||
/**
|
||||
* Delay for a fixed number of microseconds
|
||||
*
|
||||
* @v usecs Number of microseconds for which to delay
|
||||
*/
|
||||
void ( * udelay ) ( unsigned long usecs );
|
||||
};
|
||||
|
||||
/** Timer table */
|
||||
#define TIMERS __table ( struct timer, "timers" )
|
||||
|
||||
/** Declare a timer */
|
||||
#define __timer( order ) __table_entry ( TIMERS, order )
|
||||
|
||||
/** @defgroup timer_order Timer detection order
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
|
||||
#define TIMER_PREFERRED 01 /**< Preferred timer */
|
||||
#define TIMER_NORMAL 02 /**< Normal timer */
|
||||
|
||||
/** @} */
|
||||
|
||||
/*
|
||||
* sleep() prototype is defined by POSIX.1. usleep() prototype is
|
||||
* defined by 4.3BSD. udelay() and mdelay() prototypes are chosen to
|
||||
* be reasonably sensible.
|
||||
*
|
||||
*/
|
||||
|
||||
extern void udelay ( unsigned long usecs );
|
||||
extern void mdelay ( unsigned long msecs );
|
||||
extern unsigned long currticks ( void );
|
||||
extern unsigned int sleep ( unsigned int seconds );
|
||||
|
||||
#endif /* _IPXE_TIMER_H */
|
||||
|
||||
@@ -23,19 +23,9 @@ extern int execv ( const char *command, char * const argv[] );
|
||||
rc; \
|
||||
} )
|
||||
|
||||
/* Pick up udelay() */
|
||||
/* Pick up udelay() and sleep() */
|
||||
#include <ipxe/timer.h>
|
||||
|
||||
/*
|
||||
* sleep() prototype is defined by POSIX.1. usleep() prototype is
|
||||
* defined by 4.3BSD. udelay() and mdelay() prototypes are chosen to
|
||||
* be reasonably sensible.
|
||||
*
|
||||
*/
|
||||
|
||||
extern unsigned int sleep ( unsigned int seconds );
|
||||
extern void mdelay ( unsigned long msecs );
|
||||
|
||||
static inline __always_inline void usleep ( unsigned long usecs ) {
|
||||
udelay ( usecs );
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user