@@ -25,32 +25,25 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
25
26
26
#include <string.h>
27
27
#include <errno.h>
28
- #include <limits.h>
29
- #include <assert.h>
30
28
#include <unistd.h>
31
29
#include <ipxe/timer.h>
30
+ #include <ipxe/init.h>
32
31
#include <ipxe/efi/efi.h>
33
- #include <ipxe/efi/Protocol/Cpu.h>
34
32
35
33
/** @file
36
34
*
37
35
* iPXE timer API for EFI
38
36
*
39
37
*/
40
38
41
- /** Scale factor to apply to CPU timer 0
42
- *
43
- * The timer is scaled down in order to ensure that reasonable values
44
- * for "number of ticks" don't exceed the size of an unsigned long.
45
- */
46
- #define EFI_TIMER0_SHIFT 12
39
+ /** Current tick count */
40
+ static unsigned long efi_jiffies ;
47
41
48
- /** Calibration time */
49
- #define EFI_CALIBRATE_DELAY_MS 1
42
+ /** Timer tick event */
43
+ static EFI_EVENT efi_tick_event ;
50
44
51
- /** CPU protocol */
52
- static EFI_CPU_ARCH_PROTOCOL * cpu_arch ;
53
- EFI_REQUIRE_PROTOCOL ( EFI_CPU_ARCH_PROTOCOL , & cpu_arch );
45
+ /** Colour for debug messages */
46
+ #define colour &efi_jiffies
54
47
55
48
/**
56
49
* Delay for a fixed number of microseconds
@@ -64,8 +57,8 @@ static void efi_udelay ( unsigned long usecs ) {
64
57
65
58
if ( ( efirc = bs -> Stall ( usecs ) ) != 0 ) {
66
59
rc = - EEFI ( efirc );
67
- DBG ( "EFI could not delay for %ldus: %s\n" ,
68
- usecs , strerror ( rc ) );
60
+ DBGC ( colour , "EFI could not delay for %ldus: %s\n" ,
61
+ usecs , strerror ( rc ) );
69
62
/* Probably screwed */
70
63
}
71
64
}
@@ -76,53 +69,78 @@ static void efi_udelay ( unsigned long usecs ) {
76
69
* @ret ticks Current time, in ticks
77
70
*/
78
71
static unsigned long efi_currticks ( void ) {
79
- UINT64 time ;
72
+
73
+ return efi_jiffies ;
74
+ }
75
+
76
+ /**
77
+ * Timer tick
78
+ *
79
+ * @v event Timer tick event
80
+ * @v context Event context
81
+ */
82
+ static EFIAPI void efi_tick ( EFI_EVENT event __unused ,
83
+ void * context __unused ) {
84
+
85
+ /* Increment tick count */
86
+ efi_jiffies ++ ;
87
+ }
88
+
89
+ /**
90
+ * Start timer tick
91
+ *
92
+ */
93
+ static void efi_tick_startup ( void ) {
94
+ EFI_BOOT_SERVICES * bs = efi_systab -> BootServices ;
80
95
EFI_STATUS efirc ;
81
96
int rc ;
82
97
83
- /* Read CPU timer 0 (TSC) */
84
- if ( ( efirc = cpu_arch -> GetTimerValue ( cpu_arch , 0 , & time ,
85
- NULL ) ) != 0 ) {
98
+ /* Create timer tick event */
99
+ if ( ( efirc = bs -> CreateEvent ( ( EVT_TIMER | EVT_NOTIFY_SIGNAL ),
100
+ TPL_CALLBACK , efi_tick , NULL ,
101
+ & efi_tick_event ) ) != 0 ) {
86
102
rc = - EEFI ( efirc );
87
- DBG ( "EFI could not read CPU timer: %s\n" , strerror ( rc ) );
88
- /* Probably screwed */
89
- return -1UL ;
103
+ DBGC ( colour , "EFI could not create timer tick: %s\n" ,
104
+ strerror ( rc ) );
105
+ /* Nothing we can do about it */
106
+ return ;
90
107
}
91
108
92
- return ( time >> EFI_TIMER0_SHIFT );
109
+ /* Start timer tick */
110
+ if ( ( efirc = bs -> SetTimer ( efi_tick_event , TimerPeriodic ,
111
+ ( 10000000 / EFI_TICKS_PER_SEC ) ) ) != 0 ){
112
+ rc = - EEFI ( efirc );
113
+ DBGC ( colour , "EFI could not start timer tick: %s\n" ,
114
+ strerror ( rc ) );
115
+ /* Nothing we can do about it */
116
+ return ;
117
+ }
118
+ DBGC ( colour , "EFI timer started at %d ticks per second\n" ,
119
+ EFI_TICKS_PER_SEC );
93
120
}
94
121
95
122
/**
96
- * Get number of ticks per second
123
+ * Stop timer tick
97
124
*
98
- * @ret ticks_per_sec Number of ticks per second
125
+ * @v booting System is shutting down in order to boot
99
126
*/
100
- static unsigned long efi_ticks_per_sec ( void ) {
101
- static unsigned long ticks_per_sec = 0 ;
102
-
103
- /* Calibrate timer, if necessary. EFI does nominally provide
104
- * the timer speed via the (optional) TimerPeriod parameter to
105
- * the GetTimerValue() call, but it gets the speed slightly
106
- * wrong. By up to three orders of magnitude. Not helpful.
107
- */
108
- if ( ! ticks_per_sec ) {
109
- unsigned long start ;
110
- unsigned long elapsed ;
111
-
112
- DBG ( "Calibrating EFI timer with a %d ms delay\n" ,
113
- EFI_CALIBRATE_DELAY_MS );
114
- start = currticks ();
115
- mdelay ( EFI_CALIBRATE_DELAY_MS );
116
- elapsed = ( currticks () - start );
117
- ticks_per_sec = ( elapsed * ( 1000 / EFI_CALIBRATE_DELAY_MS ));
118
- DBG ( "EFI CPU timer calibrated at %ld ticks in %d ms (%ld "
119
- "ticks/sec)\n" , elapsed , EFI_CALIBRATE_DELAY_MS ,
120
- ticks_per_sec );
121
- }
127
+ static void efi_tick_shutdown ( int booting __unused ) {
128
+ EFI_BOOT_SERVICES * bs = efi_systab -> BootServices ;
122
129
123
- return ticks_per_sec ;
130
+ /* Stop timer tick */
131
+ bs -> SetTimer ( efi_tick_event , TimerCancel , 0 );
132
+ DBGC ( colour , "EFI timer stopped\n" );
133
+
134
+ /* Destroy timer tick event */
135
+ bs -> CloseEvent ( efi_tick_event );
124
136
}
125
137
138
+ /** Timer tick startup function */
139
+ struct startup_fn efi_tick_startup_fn __startup_fn ( STARTUP_EARLY ) = {
140
+ .startup = efi_tick_startup ,
141
+ .shutdown = efi_tick_shutdown ,
142
+ };
143
+
126
144
PROVIDE_TIMER ( efi , udelay , efi_udelay );
127
145
PROVIDE_TIMER ( efi , currticks , efi_currticks );
128
- PROVIDE_TIMER ( efi , ticks_per_sec , efi_ticks_per_sec );
146
+ PROVIDE_TIMER_INLINE ( efi , ticks_per_sec );
0 commit comments