2
* Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
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.
24
FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
29
#include <ipxe/timer.h>
30
#include <ipxe/init.h>
31
#include <ipxe/efi/efi.h>
35
* iPXE timer API for EFI
39
/** Current tick count */
40
static unsigned long efi_jiffies;
42
/** Timer tick event */
43
static EFI_EVENT efi_tick_event;
45
/** Colour for debug messages */
46
#define colour &efi_jiffies
49
* Delay for a fixed number of microseconds
51
* @v usecs Number of microseconds for which to delay
53
static void efi_udelay ( unsigned long usecs ) {
54
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
58
if ( ( efirc = bs->Stall ( usecs ) ) != 0 ) {
60
DBGC ( colour, "EFI could not delay for %ldus: %s\n",
61
usecs, strerror ( rc ) );
62
/* Probably screwed */
67
* Get current system time in ticks
69
* @ret ticks Current time, in ticks
71
static unsigned long efi_currticks ( void ) {
79
* @v event Timer tick event
80
* @v context Event context
82
static EFIAPI void efi_tick ( EFI_EVENT event __unused,
83
void *context __unused ) {
85
/* Increment tick count */
93
static void efi_tick_startup ( void ) {
94
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
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 ) {
102
rc = -EEFI ( efirc );
103
DBGC ( colour, "EFI could not create timer tick: %s\n",
105
/* Nothing we can do about it */
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",
115
/* Nothing we can do about it */
118
DBGC ( colour, "EFI timer started at %d ticks per second\n",
125
* @v booting System is shutting down in order to boot
127
static void efi_tick_shutdown ( int booting __unused ) {
128
EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
132
/* Stop timer tick */
133
if ( ( efirc = bs->SetTimer ( efi_tick_event, TimerCancel, 0 ) ) != 0 ){
134
rc = -EEFI ( efirc );
135
DBGC ( colour, "EFI could not stop timer tick: %s\n",
137
/* Self-destruct initiated */
140
DBGC ( colour, "EFI timer stopped\n" );
142
/* Destroy timer tick event */
143
if ( ( efirc = bs->CloseEvent ( efi_tick_event ) ) != 0 ) {
144
rc = -EEFI ( efirc );
145
DBGC ( colour, "EFI could not destroy timer tick: %s\n",
147
/* Probably non-fatal */
152
/** Timer tick startup function */
153
struct startup_fn efi_tick_startup_fn __startup_fn ( STARTUP_EARLY ) = {
154
.startup = efi_tick_startup,
155
.shutdown = efi_tick_shutdown,
158
PROVIDE_TIMER ( efi, udelay, efi_udelay );
159
PROVIDE_TIMER ( efi, currticks, efi_currticks );
160
PROVIDE_TIMER_INLINE ( efi, ticks_per_sec );