iPXE
timer.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2008 Michael Brown <mbrown@fensystems.co.uk>.
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., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
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.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 #include <string.h>
27 #include <ipxe/process.h>
28 #include <ipxe/console.h>
29 #include <ipxe/keys.h>
30 #include <ipxe/nap.h>
31 #include <ipxe/init.h>
32 #include <ipxe/timer.h>
33 
34 /** Current timer */
35 static struct timer *timer;
36 
37 /**
38  * Get current system time in ticks
39  *
40  * @ret ticks Current time, in ticks
41  */
42 unsigned long currticks ( void ) {
43 
44  /* Guard against use during early initialisation */
45  if ( ! timer ) {
46  DBGC ( &timer, "TIMER currticks() called before initialisation "
47  "from %p\n", __builtin_return_address ( 0 ) );
48  return 0;
49  }
50 
51  /* Use selected timer */
52  return timer->currticks();
53 }
54 
55 /**
56  * Delay for a fixed number of microseconds
57  *
58  * @v usecs Number of microseconds for which to delay
59  */
60 void udelay ( unsigned long usecs ) {
61 
62  /* Guard against use during early initialisation */
63  if ( ! timer ) {
64  DBGC ( &timer, "TIMER udelay() called before initialisation "
65  "from %p\n", __builtin_return_address ( 0 ) );
66  return;
67  }
68 
69  /* Use selected timer */
70  timer->udelay ( usecs );
71 }
72 
73 /**
74  * Delay for a fixed number of milliseconds
75  *
76  * @v msecs Number of milliseconds for which to delay
77  */
78 void mdelay ( unsigned long msecs ) {
79 
80  /* Guard against use during early initialisation */
81  if ( ! timer ) {
82  DBGC ( &timer, "TIMER mdelay() called before initialisation "
83  "from %p\n", __builtin_return_address ( 0 ) );
84  return;
85  }
86 
87  /* Delay for specified number of milliseconds */
88  while ( msecs-- )
89  udelay ( 1000 );
90 }
91 
92 /**
93  * Sleep (possibly interruptibly) for a fixed number of seconds
94  *
95  * @v secs Number of seconds for which to delay
96  * @v interrupted Interrupt checking method, or NULL
97  * @ret secs Number of seconds remaining, if interrupted
98  */
99 static unsigned int sleep_interruptible ( unsigned int secs,
100  int ( * interrupted ) ( void ) ) {
101  unsigned long start = currticks();
102  unsigned long now;
103 
104  for ( ; secs ; secs-- ) {
105  while ( ( ( now = currticks() ) - start ) < TICKS_PER_SEC ) {
106  step();
107  if ( interrupted && interrupted() )
108  return secs;
109  cpu_nap();
110  }
111  start = now;
112  }
113 
114  return 0;
115 }
116 
117 /**
118  * Check if sleep has been interrupted by keypress
119  *
120  * @ret interrupted Sleep has been interrupted
121  */
122 static int keypress_interrupted ( void ) {
123 
124  return ( iskey() && ( getchar() == CTRL_C ) );
125 }
126 
127 /**
128  * Sleep (interruptibly) for a fixed number of seconds
129  *
130  * @v secs Number of seconds for which to delay
131  * @ret secs Number of seconds remaining, if interrupted
132  */
133 unsigned int sleep ( unsigned int secs ) {
134 
135  return sleep_interruptible ( secs, keypress_interrupted );
136 }
137 
138 /**
139  * Sleep (uninterruptibly) for a fixed number of seconds
140  *
141  * @v secs Number of seconds for which to delay
142  */
143 void sleep_fixed ( unsigned int secs ) {
144 
145  sleep_interruptible ( secs, NULL );
146 }
147 
148 /**
149  * Find a working timer
150  *
151  */
152 static void timer_probe ( void ) {
153  int rc;
154 
155  /* Use first working timer */
157  if ( ( timer->probe == NULL ) ||
158  ( ( rc = timer->probe() ) == 0 ) ) {
159  DBGC ( &timer, "TIMER using %s\n", timer->name );
160  return;
161  }
162  DBGC ( &timer, "TIMER could not initialise %s: %s\n",
163  timer->name, strerror ( rc ) );
164  }
165 
166  /* This is a fatal error */
167  DBGC ( &timer, "TIMER found no working timers!\n" );
168  while ( 1 ) {}
169 }
170 
171 /** Timer initialisation function */
172 struct init_fn timer_init_fn __init_fn ( INIT_EARLY ) = {
174 };
175 
176 /* Drag in timer configuration */
177 REQUIRING_SYMBOL ( timer_init_fn );
178 REQUIRE_OBJECT ( config_timer );
CPU sleeping.
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
#define TICKS_PER_SEC
Number of ticks per second.
Definition: timer.h:15
void(* initialise)(void)
Definition: init.h:15
struct init_fn timer_init_fn __init_fn(INIT_EARLY)
Timer initialisation function.
#define INIT_EARLY
Early initialisation.
Definition: init.h:28
#define DBGC(...)
Definition: compiler.h:505
iPXE timers
A timer.
Definition: timer.h:28
uint32_t start
Starting offset.
Definition: netvsc.h:12
An initialisation function.
Definition: init.h:14
void(* udelay)(unsigned long usecs)
Delay for a fixed number of microseconds.
Definition: timer.h:48
REQUIRE_OBJECT(config_timer)
void udelay(unsigned long usecs)
Delay for a fixed number of microseconds.
Definition: timer.c:60
REQUIRING_SYMBOL(timer_init_fn)
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
#define CTRL_C
Definition: keys.h:20
unsigned long(* currticks)(void)
Get current system time in ticks.
Definition: timer.h:42
User interaction.
int getchar(void)
Read a single character from any console.
Definition: console.c:85
char * strerror(int errno)
Retrieve string representation of error number.
Definition: strerror.c:78
#define for_each_table_entry(pointer, table)
Iterate through all entries within a linker table.
Definition: tables.h:385
Processes.
int(* probe)(void)
Probe timer.
Definition: timer.h:36
void mdelay(unsigned long msecs)
Delay for a fixed number of milliseconds.
Definition: timer.c:78
void cpu_nap(void)
Sleep with interrupts enabled until next CPU interrupt.
const char * name
Name.
Definition: timer.h:30
Key definitions.
static struct timer * timer
Current timer.
Definition: timer.c:35
void step(void)
Single-step a single process.
Definition: process.c:98
void sleep_fixed(unsigned int secs)
Sleep (uninterruptibly) for a fixed number of seconds.
Definition: timer.c:143
static int keypress_interrupted(void)
Check if sleep has been interrupted by keypress.
Definition: timer.c:122
#define TIMERS
Timer table.
Definition: timer.h:52
static void timer_probe(void)
Find a working timer.
Definition: timer.c:152
unsigned long currticks(void)
Get current system time in ticks.
Definition: timer.c:42
static unsigned int sleep_interruptible(unsigned int secs, int(*interrupted)(void))
Sleep (possibly interruptibly) for a fixed number of seconds.
Definition: timer.c:99
unsigned int sleep(unsigned int secs)
Sleep (interruptibly) for a fixed number of seconds.
Definition: timer.c:133
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
String functions.
int iskey(void)
Check for available input on any console.
Definition: console.c:130