Browse Source

[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>
tags/v1.20.1
Michael Brown 7 years ago
parent
commit
302f1eeb80

+ 0
- 12
src/arch/arm/include/bits/timer.h View File

@@ -1,12 +0,0 @@
1
-#ifndef _BITS_TIMER_H
2
-#define _BITS_TIMER_H
3
-
4
-/** @file
5
- *
6
- * ARM-specific timer API implementations
7
- *
8
- */
9
-
10
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
-
12
-#endif /* _BITS_TIMER_H */

+ 120
- 37
src/arch/x86/core/rdtsc_timer.c View File

@@ -29,16 +29,70 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
29 29
  *
30 30
  */
31 31
 
32
-#include <assert.h>
32
+#include <string.h>
33
+#include <errno.h>
33 34
 #include <ipxe/timer.h>
35
+#include <ipxe/cpuid.h>
34 36
 #include <ipxe/pit8254.h>
35 37
 
38
+/** Number of microseconds to use for TSC calibration */
39
+#define TSC_CALIBRATE_US 1024
40
+
41
+/** TSC increment per microsecond */
42
+static unsigned long tsc_per_us;
43
+
44
+/** Minimum resolution for scaled TSC timer */
45
+#define TSC_SCALED_HZ 32
46
+
47
+/** TSC scale (expressed as a bit shift)
48
+ *
49
+ * We use this to avoid the need for 64-bit divsion on 32-bit systems.
50
+ */
51
+static unsigned int tsc_scale;
52
+
53
+/** Number of timer ticks per scaled TSC increment */
54
+static unsigned long ticks_per_scaled_tsc;
55
+
56
+/** Colour for debug messages */
57
+#define colour &tsc_per_us
58
+
59
+/**
60
+ * Get raw TSC value
61
+ *
62
+ * @ret tsc		Raw TSC value
63
+ */
64
+static inline __always_inline unsigned long rdtsc_raw ( void ) {
65
+	unsigned long raw;
66
+
67
+	__asm__ __volatile__ ( "rdtsc\n\t" : "=a" ( raw ) : : "edx" );
68
+	return raw;
69
+}
70
+
71
+/**
72
+ * Get TSC value, shifted to avoid rollover within a realistic timescale
73
+ *
74
+ * @ret tsc		Scaled TSC value
75
+ */
76
+static inline __always_inline unsigned long rdtsc_scaled ( void ) {
77
+	unsigned long scaled;
78
+
79
+	__asm__ __volatile__ ( "rdtsc\n\t"
80
+			       "shrdl %b1, %%edx, %%eax\n\t"
81
+			       : "=a" ( scaled ) : "c" ( tsc_scale ) : "edx" );
82
+	return scaled;
83
+}
84
+
36 85
 /**
37
- * Number of TSC ticks per microsecond
86
+ * Get current system time in ticks
38 87
  *
39
- * This is calibrated on the first use of the timer.
88
+ * @ret ticks		Current time, in ticks
40 89
  */
41
-static unsigned long rdtsc_ticks_per_usec;
90
+static unsigned long rdtsc_currticks ( void ) {
91
+	unsigned long scaled;
92
+
93
+	scaled = rdtsc_scaled();
94
+	return ( scaled * ticks_per_scaled_tsc );
95
+}
42 96
 
43 97
 /**
44 98
  * Delay for a fixed number of microseconds
@@ -48,47 +102,76 @@ static unsigned long rdtsc_ticks_per_usec;
48 102
 static void rdtsc_udelay ( unsigned long usecs ) {
49 103
 	unsigned long start;
50 104
 	unsigned long elapsed;
105
+	unsigned long threshold;
51 106
 
52
-	/* Sanity guard, since we may divide by this */
53
-	if ( ! usecs )
54
-		usecs = 1;
55
-
56
-	start = currticks();
57
-	if ( rdtsc_ticks_per_usec ) {
58
-		/* Already calibrated; busy-wait until done */
59
-		do {
60
-			elapsed = ( currticks() - start );
61
-		} while ( elapsed < ( usecs * rdtsc_ticks_per_usec ) );
62
-	} else {
63
-		/* Not yet calibrated; use 8254 PIT and calibrate
64
-		 * based on result.
65
-		 */
66
-		pit8254_udelay ( usecs );
67
-		elapsed = ( currticks() - start );
68
-		rdtsc_ticks_per_usec = ( elapsed / usecs );
69
-		DBG ( "RDTSC timer calibrated: %ld ticks in %ld usecs "
70
-		      "(%ld MHz)\n", elapsed, usecs,
71
-		      ( rdtsc_ticks_per_usec << TSC_SHIFT ) );
72
-	}
107
+	start = rdtsc_raw();
108
+	threshold = ( usecs * tsc_per_us );
109
+	do {
110
+		elapsed = ( rdtsc_raw() - start );
111
+	} while ( elapsed < threshold );
73 112
 }
74 113
 
75 114
 /**
76
- * Get number of ticks per second
115
+ * Probe RDTSC timer
77 116
  *
78
- * @ret ticks_per_sec	Number of ticks per second
117
+ * @ret rc		Return status code
79 118
  */
80
-static unsigned long rdtsc_ticks_per_sec ( void ) {
119
+static int rdtsc_probe ( void ) {
120
+	unsigned long before;
121
+	unsigned long after;
122
+	unsigned long elapsed;
123
+	uint32_t apm;
124
+	uint32_t discard_a;
125
+	uint32_t discard_b;
126
+	uint32_t discard_c;
127
+	int rc;
81 128
 
82
-	/* Calibrate timer, if not already done */
83
-	if ( ! rdtsc_ticks_per_usec )
84
-		udelay ( 1 );
129
+	/* Check that TSC is invariant */
130
+	if ( ( rc = cpuid_supported ( CPUID_APM ) ) != 0 ) {
131
+		DBGC ( colour, "RDTSC cannot determine APM features: %s\n",
132
+		       strerror ( rc ) );
133
+		return rc;
134
+	}
135
+	cpuid ( CPUID_APM, &discard_a, &discard_b, &discard_c, &apm );
136
+	if ( ! ( apm & CPUID_APM_EDX_TSC_INVARIANT ) ) {
137
+		DBGC ( colour, "RDTSC has non-invariant TSC (%#08x)\n",
138
+		       apm );
139
+		return -ENOTTY;
140
+	}
85 141
 
86
-	/* Sanity check */
87
-	assert ( rdtsc_ticks_per_usec != 0 );
142
+	/* Calibrate udelay() timer via 8254 PIT */
143
+	before = rdtsc_raw();
144
+	pit8254_udelay ( TSC_CALIBRATE_US );
145
+	after = rdtsc_raw();
146
+	elapsed = ( after - before );
147
+	tsc_per_us = ( elapsed / TSC_CALIBRATE_US );
148
+	if ( ! tsc_per_us ) {
149
+		DBGC ( colour, "RDTSC has zero TSC per microsecond\n" );
150
+		return -EIO;
151
+	}
152
+
153
+	/* Calibrate currticks() scaling factor */
154
+	tsc_scale = 31;
155
+	ticks_per_scaled_tsc = ( ( 1UL << tsc_scale ) /
156
+				 ( tsc_per_us * ( 1000000 / TICKS_PER_SEC ) ) );
157
+	while ( ticks_per_scaled_tsc > ( TICKS_PER_SEC / TSC_SCALED_HZ ) ) {
158
+		tsc_scale--;
159
+		ticks_per_scaled_tsc >>= 1;
160
+	}
161
+	DBGC ( colour, "RDTSC has %ld tsc per us, %ld ticks per 2^%d tsc\n",
162
+	       tsc_per_us, ticks_per_scaled_tsc, tsc_scale );
163
+	if ( ! ticks_per_scaled_tsc ) {
164
+		DBGC ( colour, "RDTSC has zero ticks per TSC\n" );
165
+		return -EIO;
166
+	}
88 167
 
89
-	return ( rdtsc_ticks_per_usec * 1000 * 1000 );
168
+	return 0;
90 169
 }
91 170
 
92
-PROVIDE_TIMER ( rdtsc, udelay, rdtsc_udelay );
93
-PROVIDE_TIMER_INLINE ( rdtsc, currticks );
94
-PROVIDE_TIMER ( rdtsc, ticks_per_sec, rdtsc_ticks_per_sec );
171
+/** RDTSC timer */
172
+struct timer rdtsc_timer __timer ( TIMER_PREFERRED ) = {
173
+	.name = "rdtsc",
174
+	.probe = rdtsc_probe,
175
+	.currticks = rdtsc_currticks,
176
+	.udelay = rdtsc_udelay,
177
+};

+ 2
- 0
src/arch/x86/include/bios.h View File

@@ -7,6 +7,8 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
7 7
 #define BDA_EBDA 0x000e
8 8
 #define BDA_EQUIPMENT_WORD 0x0010
9 9
 #define BDA_FBMS 0x0013
10
+#define BDA_TICKS 0x006c
11
+#define BDA_MIDNIGHT 0x0070
10 12
 #define BDA_REBOOT 0x0072
11 13
 #define BDA_REBOOT_WARM 0x1234
12 14
 #define BDA_NUM_DRIVES 0x0075

+ 1
- 0
src/arch/x86/include/bits/errfile.h View File

@@ -26,6 +26,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
26 26
 #define ERRFILE_rtc_entropy	( ERRFILE_ARCH | ERRFILE_CORE | 0x000f0000 )
27 27
 #define ERRFILE_acpipwr		( ERRFILE_ARCH | ERRFILE_CORE | 0x00100000 )
28 28
 #define ERRFILE_cpuid		( ERRFILE_ARCH | ERRFILE_CORE | 0x00110000 )
29
+#define ERRFILE_rdtsc_timer	( ERRFILE_ARCH | ERRFILE_CORE | 0x00120000 )
29 30
 
30 31
 #define ERRFILE_bootsector     ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
31 32
 #define ERRFILE_bzimage	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )

+ 0
- 15
src/arch/x86/include/bits/timer.h View File

@@ -1,15 +0,0 @@
1
-#ifndef _BITS_TIMER_H
2
-#define _BITS_TIMER_H
3
-
4
-/** @file
5
- *
6
- * x86-specific timer API implementations
7
- *
8
- */
9
-
10
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
-
12
-#include <ipxe/bios_timer.h>
13
-#include <ipxe/rdtsc_timer.h>
14
-
15
-#endif /* _BITS_TIMER_H */

+ 0
- 44
src/arch/x86/include/ipxe/bios_timer.h View File

@@ -1,44 +0,0 @@
1
-#ifndef _IPXE_BIOS_TIMER_H
2
-#define _IPXE_BIOS_TIMER_H
3
-
4
-/** @file
5
- *
6
- * BIOS timer
7
- *
8
- */
9
-
10
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
-
12
-#ifdef TIMER_PCBIOS
13
-#define TIMER_PREFIX_pcbios
14
-#else
15
-#define TIMER_PREFIX_pcbios __pcbios_
16
-#endif
17
-
18
-#include <ipxe/pit8254.h>
19
-
20
-/**
21
- * Delay for a fixed number of microseconds
22
- *
23
- * @v usecs		Number of microseconds for which to delay
24
- */
25
-static inline __always_inline void
26
-TIMER_INLINE ( pcbios, udelay ) ( unsigned long usecs ) {
27
-	/* BIOS timer is not high-resolution enough for udelay(), so
28
-	 * we use the 8254 Programmable Interval Timer.
29
-	 */
30
-	pit8254_udelay ( usecs );
31
-}
32
-
33
-/**
34
- * Get number of ticks per second
35
- *
36
- * @ret ticks_per_sec	Number of ticks per second
37
- */
38
-static inline __always_inline unsigned long
39
-TIMER_INLINE ( pcbios, ticks_per_sec ) ( void ) {
40
-	/* BIOS timer ticks over at 18.2 ticks per second */
41
-	return 18;
42
-}
43
-
44
-#endif /* _IPXE_BIOS_TIMER_H */

+ 6
- 0
src/arch/x86/include/ipxe/cpuid.h View File

@@ -57,6 +57,12 @@ struct x86_features {
57 57
 /** Get CPU model */
58 58
 #define CPUID_MODEL 0x80000002UL
59 59
 
60
+/** Get APM information */
61
+#define CPUID_APM 0x80000007UL
62
+
63
+/** Invariant TSC */
64
+#define CPUID_APM_EDX_TSC_INVARIANT 0x00000100UL
65
+
60 66
 /**
61 67
  * Issue CPUID instruction
62 68
  *

+ 0
- 39
src/arch/x86/include/ipxe/rdtsc_timer.h View File

@@ -1,39 +0,0 @@
1
-#ifndef _IPXE_RDTSC_TIMER_H
2
-#define _IPXE_RDTSC_TIMER_H
3
-
4
-/** @file
5
- *
6
- * RDTSC timer
7
- *
8
- */
9
-
10
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
-
12
-#ifdef TIMER_RDTSC
13
-#define TIMER_PREFIX_rdtsc
14
-#else
15
-#define TIMER_PREFIX_rdtsc __rdtsc_
16
-#endif
17
-
18
-/**
19
- * RDTSC values can easily overflow an unsigned long.  We discard the
20
- * low-order bits in order to obtain sensibly-scaled values.
21
- */
22
-#define TSC_SHIFT 8
23
-
24
-/**
25
- * Get current system time in ticks
26
- *
27
- * @ret ticks		Current time, in ticks
28
- */
29
-static inline __always_inline unsigned long
30
-TIMER_INLINE ( rdtsc, currticks ) ( void ) {
31
-	unsigned long ticks;
32
-
33
-	__asm__ __volatile__ ( "rdtsc\n\t"
34
-			       "shrdl %1, %%edx, %%eax\n\t"
35
-			       : "=a" ( ticks ) : "i" ( TSC_SHIFT ) : "edx" );
36
-	return ticks;
37
-}
38
-
39
-#endif /* _IPXE_RDTSC_TIMER_H */

+ 28
- 9
src/arch/x86/interface/pcbios/bios_timer.c View File

@@ -32,6 +32,18 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
32 32
 #include <ipxe/timer.h>
33 33
 #include <realmode.h>
34 34
 #include <bios.h>
35
+#include <ipxe/pit8254.h>
36
+
37
+/** Number of ticks per day
38
+ *
39
+ * This seems to be the normative value, as used by e.g. SeaBIOS to
40
+ * decide when to set the midnight rollover flag.
41
+ */
42
+#define BIOS_TICKS_PER_DAY 0x1800b0
43
+
44
+/** Number of ticks per BIOS tick */
45
+#define TICKS_PER_BIOS_TICK \
46
+	( ( TICKS_PER_SEC * 60 * 60 * 24 ) / BIOS_TICKS_PER_DAY )
35 47
 
36 48
 /**
37 49
  * Get current system time in ticks
@@ -43,7 +55,7 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
43 55
  * of calling timeofday BIOS interrupt.
44 56
  */
45 57
 static unsigned long bios_currticks ( void ) {
46
-	static int days = 0;
58
+	static uint32_t offset;
47 59
 	uint32_t ticks;
48 60
 	uint8_t midnight;
49 61
 
@@ -53,18 +65,25 @@ static unsigned long bios_currticks ( void ) {
53 65
 			       "nop\n\t"
54 66
 			       "cli\n\t" );
55 67
 
56
-	get_real ( ticks, BDA_SEG, 0x006c );
57
-	get_real ( midnight, BDA_SEG, 0x0070 );
68
+	/* Read current BIOS time of day */
69
+	get_real ( ticks, BDA_SEG, BDA_TICKS );
70
+	get_real ( midnight, BDA_SEG, BDA_MIDNIGHT );
58 71
 
72
+	/* Handle midnight rollover */
59 73
 	if ( midnight ) {
60 74
 		midnight = 0;
61
-		put_real ( midnight, BDA_SEG, 0x0070 );
62
-		days += 0x1800b0;
75
+		put_real ( midnight, BDA_SEG, BDA_MIDNIGHT );
76
+		offset += BIOS_TICKS_PER_DAY;
63 77
 	}
78
+	ticks += offset;
64 79
 
65
-	return ( days + ticks );
80
+	/* Convert to timer ticks */
81
+	return ( ticks * TICKS_PER_BIOS_TICK );
66 82
 }
67 83
 
68
-PROVIDE_TIMER_INLINE ( pcbios, udelay );
69
-PROVIDE_TIMER ( pcbios, currticks, bios_currticks );
70
-PROVIDE_TIMER_INLINE ( pcbios, ticks_per_sec );
84
+/** BIOS timer */
85
+struct timer bios_timer __timer ( TIMER_NORMAL ) = {
86
+	.name = "bios",
87
+	.currticks = bios_currticks,
88
+	.udelay = pit8254_udelay,
89
+};

+ 48
- 0
src/config/config_timer.c View File

@@ -0,0 +1,48 @@
1
+/*
2
+ * This program is free software; you can redistribute it and/or
3
+ * modify it under the terms of the GNU General Public License as
4
+ * published by the Free Software Foundation; either version 2 of the
5
+ * License, or (at your option) any later version.
6
+ *
7
+ * This program is distributed in the hope that it will be useful, but
8
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
10
+ * General Public License for more details.
11
+ *
12
+ * You should have received a copy of the GNU General Public License
13
+ * along with this program; if not, write to the Free Software
14
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15
+ * 02110-1301, USA.
16
+ *
17
+ * You can also choose to distribute this program under the terms of
18
+ * the Unmodified Binary Distribution Licence (as given in the file
19
+ * COPYING.UBDL), provided that you have satisfied its requirements.
20
+ */
21
+
22
+FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
23
+
24
+#include <config/timer.h>
25
+
26
+/** @file
27
+ *
28
+ * Timer configuration options
29
+ *
30
+ */
31
+
32
+PROVIDE_REQUIRING_SYMBOL();
33
+
34
+/*
35
+ * Drag in timers
36
+ */
37
+#ifdef TIMER_PCBIOS
38
+REQUIRE_OBJECT ( bios_timer );
39
+#endif
40
+#ifdef TIMER_RDTSC
41
+REQUIRE_OBJECT ( rdtsc_timer );
42
+#endif
43
+#ifdef TIMER_EFI
44
+REQUIRE_OBJECT ( efi_timer );
45
+#endif
46
+#ifdef TIMER_LINUX
47
+REQUIRE_OBJECT ( linux_timer );
48
+#endif

+ 1
- 1
src/core/parseopt.c View File

@@ -117,7 +117,7 @@ int parse_timeout ( char *text, unsigned long *value ) {
117 117
 		return rc;
118 118
 
119 119
 	/* Convert to a number of timer ticks */
120
-	*value = ( ( value_ms * TICKS_PER_SEC ) / 1000 );
120
+	*value = ( value_ms * TICKS_PER_MS );
121 121
 
122 122
 	return 0;
123 123
 }

+ 61
- 1
src/core/timer.c View File

@@ -23,11 +23,39 @@
23 23
 
24 24
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 25
 
26
-#include <unistd.h>
26
+#include <string.h>
27
+#include <assert.h>
27 28
 #include <ipxe/process.h>
28 29
 #include <ipxe/console.h>
29 30
 #include <ipxe/keys.h>
30 31
 #include <ipxe/nap.h>
32
+#include <ipxe/init.h>
33
+#include <ipxe/timer.h>
34
+
35
+/** Current timer */
36
+static struct timer *timer;
37
+
38
+/**
39
+ * Get current system time in ticks
40
+ *
41
+ * @ret ticks		Current time, in ticks
42
+ */
43
+unsigned long currticks ( void ) {
44
+
45
+	assert ( timer != NULL );
46
+	return timer->currticks();
47
+}
48
+
49
+/**
50
+ * Delay for a fixed number of microseconds
51
+ *
52
+ * @v usecs		Number of microseconds for which to delay
53
+ */
54
+void udelay ( unsigned long usecs ) {
55
+
56
+	assert ( timer != NULL );
57
+	timer->udelay ( usecs );
58
+}
31 59
 
32 60
 /**
33 61
  * Delay for a fixed number of milliseconds
@@ -61,3 +89,35 @@ unsigned int sleep ( unsigned int secs ) {
61 89
 
62 90
 	return 0;
63 91
 }
92
+
93
+/**
94
+ * Find a working timer
95
+ *
96
+ */
97
+static void timer_probe ( void ) {
98
+	int rc;
99
+
100
+	/* Use first working timer */
101
+	for_each_table_entry ( timer, TIMERS ) {
102
+		if ( ( timer->probe == NULL ) ||
103
+		     ( ( rc = timer->probe() ) == 0 ) ) {
104
+			DBGC ( &timer, "TIMER using %s\n", timer->name );
105
+			return;
106
+		}
107
+		DBGC ( &timer, "TIMER could not initialise %s: %s\n",
108
+		       timer->name, strerror ( rc ) );
109
+	}
110
+
111
+	/* This is a fatal error */
112
+	DBGC ( &timer, "TIMER found no working timers!\n" );
113
+	while ( 1 ) {}
114
+}
115
+
116
+/** Timer initialisation function */
117
+struct init_fn timer_init_fn __init_fn ( INIT_EARLY ) = {
118
+	.initialise = timer_probe,
119
+};
120
+
121
+/* Drag in timer configuration */
122
+REQUIRING_SYMBOL ( timer_init_fn );
123
+REQUIRE_OBJECT ( config_timer );

+ 1
- 1
src/drivers/net/ath/ath5k/ath5k.c View File

@@ -1381,7 +1381,7 @@ ath5k_poll(struct net80211_device *dev)
1381 1381
 	unsigned int counter = 1000;
1382 1382
 
1383 1383
 	if (currticks() - sc->last_calib_ticks >
1384
-	    ATH5K_CALIB_INTERVAL * ticks_per_sec()) {
1384
+	    ATH5K_CALIB_INTERVAL * TICKS_PER_SEC) {
1385 1385
 		ath5k_calibrate(sc);
1386 1386
 		sc->last_calib_ticks = currticks();
1387 1387
 	}

+ 1
- 1
src/drivers/net/forcedeth.c View File

@@ -1176,7 +1176,7 @@ nv_mgmt_get_version ( struct forcedeth_private *priv )
1176 1176
 		ioaddr + NvRegTransmitterControl );
1177 1177
 	start = currticks();
1178 1178
 
1179
-	while ( currticks() > start + 5 * ticks_per_sec() ) {
1179
+	while ( currticks() > start + 5 * TICKS_PER_SEC ) {
1180 1180
 		data_ready2 = readl ( ioaddr + NvRegTransmitterControl );
1181 1181
 		if ( ( data_ready & NVREG_XMITCTL_DATA_READY ) !=
1182 1182
 		     ( data_ready2 & NVREG_XMITCTL_DATA_READY ) ) {

+ 1
- 1
src/hci/commands/time_cmd.c View File

@@ -68,7 +68,7 @@ static int time_exec ( int argc, char **argv ) {
68 68
 	start = currticks();
69 69
 	rc = execv ( argv[1], argv + 1 );
70 70
 	elapsed = ( currticks() - start );
71
-	decisecs = ( 10 * elapsed / ticks_per_sec() );
71
+	decisecs = ( 10 * elapsed / TICKS_PER_SEC );
72 72
 
73 73
 	printf ( "%s: %d.%ds\n", argv[0],
74 74
 		 ( decisecs / 10 ), ( decisecs % 10 ) );

+ 0
- 36
src/include/ipxe/efi/efi_timer.h View File

@@ -1,36 +0,0 @@
1
-#ifndef _IPXE_EFI_TIMER_H
2
-#define _IPXE_EFI_TIMER_H
3
-
4
-/** @file
5
- *
6
- * iPXE timer API for EFI
7
- *
8
- */
9
-
10
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
-
12
-#ifdef TIMER_EFI
13
-#define TIMER_PREFIX_efi
14
-#else
15
-#define TIMER_PREFIX_efi __efi_
16
-#endif
17
-
18
-/**
19
- * Number of ticks per second
20
- *
21
- * This is a policy decision.
22
- */
23
-#define EFI_TICKS_PER_SEC 20
24
-
25
-/**
26
- * Get number of ticks per second
27
- *
28
- * @ret ticks_per_sec	Number of ticks per second
29
- */
30
-static inline __attribute__ (( always_inline )) unsigned long
31
-TIMER_INLINE ( efi, ticks_per_sec ) ( void ) {
32
-
33
-	return EFI_TICKS_PER_SEC;
34
-}
35
-
36
-#endif /* _IPXE_EFI_TIMER_H */

+ 0
- 18
src/include/ipxe/linux/linux_timer.h View File

@@ -1,18 +0,0 @@
1
-#ifndef _IPXE_LINUX_TIMER_H
2
-#define _IPXE_LINUX_TIMER_H
3
-
4
-/** @file
5
- *
6
- * iPXE timer API for Linux
7
- *
8
- */
9
-
10
-FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
11
-
12
-#ifdef TIMER_LINUX
13
-#define TIMER_PREFIX_linux
14
-#else
15
-#define TIMER_PREFIX_linux __linux_
16
-#endif
17
-
18
-#endif /* _IPXE_LINUX_TIMER_H */

+ 52
- 50
src/include/ipxe/timer.h View File

@@ -3,75 +3,77 @@
3 3
 
4 4
 /** @file
5 5
  *
6
- * iPXE timer API
6
+ * iPXE timers
7 7
  *
8
- * The timer API provides udelay() for fixed delays, and currticks()
9
- * for a monotonically increasing tick counter.
10 8
  */
11 9
 
12 10
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
13 11
 
14
-#include <ipxe/api.h>
15
-#include <config/timer.h>
12
+#include <ipxe/tables.h>
16 13
 
17
-/**
18
- * Calculate static inline timer API function name
19
- *
20
- * @v _prefix		Subsystem prefix
21
- * @v _api_func		API function
22
- * @ret _subsys_func	Subsystem API function
23
- */
24
-#define TIMER_INLINE( _subsys, _api_func ) \
25
-	SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func )
14
+/** Number of ticks per second */
15
+#define TICKS_PER_SEC 1024
26 16
 
27
-/**
28
- * Provide a timer API implementation
17
+/** Number of ticks per millisecond
29 18
  *
30
- * @v _prefix		Subsystem prefix
31
- * @v _api_func		API function
32
- * @v _func		Implementing function
19
+ * This is (obviously) not 100% consistent with the definition of
20
+ * TICKS_PER_SEC, but it allows for multiplications and divisions to
21
+ * be elided.  In any case, timer ticks are not expected to be a
22
+ * precision timing source; for example, the standard BIOS timer is
23
+ * based on an 18.2Hz clock.
33 24
  */
34
-#define PROVIDE_TIMER( _subsys, _api_func, _func ) \
35
-	PROVIDE_SINGLE_API ( TIMER_PREFIX_ ## _subsys, _api_func, _func )
25
+#define TICKS_PER_MS 1
36 26
 
37
-/**
38
- * Provide a static inline timer API implementation
39
- *
40
- * @v _prefix		Subsystem prefix
41
- * @v _api_func		API function
42
- */
43
-#define PROVIDE_TIMER_INLINE( _subsys, _api_func ) \
44
-	PROVIDE_SINGLE_API_INLINE ( TIMER_PREFIX_ ## _subsys, _api_func )
27
+/** A timer */
28
+struct timer {
29
+	/** Name */
30
+	const char *name;
31
+	/**
32
+	 * Probe timer
33
+	 *
34
+	 * @ret rc		Return status code
35
+	 */
36
+	int ( * probe ) ( void );
37
+	/**
38
+	 * Get current system time in ticks
39
+	 *
40
+	 * @ret ticks		Current time, in ticks
41
+	 */
42
+	unsigned long ( * currticks ) ( void );
43
+	/**
44
+	 * Delay for a fixed number of microseconds
45
+	 *
46
+	 * @v usecs		Number of microseconds for which to delay
47
+	 */
48
+	void ( * udelay ) ( unsigned long usecs );
49
+};
45 50
 
46
-/* Include all architecture-independent I/O API headers */
47
-#include <ipxe/efi/efi_timer.h>
48
-#include <ipxe/linux/linux_timer.h>
51
+/** Timer table */
52
+#define TIMERS __table ( struct timer, "timers" )
49 53
 
50
-/* Include all architecture-dependent I/O API headers */
51
-#include <bits/timer.h>
54
+/** Declare a timer */
55
+#define __timer( order ) __table_entry ( TIMERS, order )
52 56
 
53
-/**
54
- * Delay for a fixed number of microseconds
57
+/** @defgroup timer_order Timer detection order
55 58
  *
56
- * @v usecs		Number of microseconds for which to delay
59
+ * @{
57 60
  */
58
-void udelay ( unsigned long usecs );
59 61
 
60
-/**
61
- * Get current system time in ticks
62
- *
63
- * @ret ticks		Current time, in ticks
64
- */
65
-unsigned long currticks ( void );
62
+#define TIMER_PREFERRED	01	/**< Preferred timer */
63
+#define TIMER_NORMAL	02	/**< Normal timer */
66 64
 
67
-/**
68
- * Get number of ticks per second
65
+/** @} */
66
+
67
+/*
68
+ * sleep() prototype is defined by POSIX.1.  usleep() prototype is
69
+ * defined by 4.3BSD.  udelay() and mdelay() prototypes are chosen to
70
+ * be reasonably sensible.
69 71
  *
70
- * @ret ticks_per_sec	Number of ticks per second
71 72
  */
72
-unsigned long ticks_per_sec ( void );
73 73
 
74
-/** Number of ticks per second */
75
-#define TICKS_PER_SEC ( ticks_per_sec() )
74
+extern void udelay ( unsigned long usecs );
75
+extern void mdelay ( unsigned long msecs );
76
+extern unsigned long currticks ( void );
77
+extern unsigned int sleep ( unsigned int seconds );
76 78
 
77 79
 #endif /* _IPXE_TIMER_H */

+ 1
- 11
src/include/unistd.h View File

@@ -23,19 +23,9 @@ extern int execv ( const char *command, char * const argv[] );
23 23
 		rc;							\
24 24
 	} )
25 25
 
26
-/* Pick up udelay() */
26
+/* Pick up udelay() and sleep() */
27 27
 #include <ipxe/timer.h>
28 28
 
29
-/*
30
- * sleep() prototype is defined by POSIX.1.  usleep() prototype is
31
- * defined by 4.3BSD.  udelay() and mdelay() prototypes are chosen to
32
- * be reasonably sensible.
33
- *
34
- */
35
-
36
-extern unsigned int sleep ( unsigned int seconds );
37
-extern void mdelay ( unsigned long msecs );
38
-
39 29
 static inline __always_inline void usleep ( unsigned long usecs ) {
40 30
 	udelay ( usecs );
41 31
 }

+ 16
- 6
src/interface/efi/efi_timer.c View File

@@ -36,6 +36,13 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
36 36
  *
37 37
  */
38 38
 
39
+/**
40
+ * Number of jiffies per second
41
+ *
42
+ * This is a policy decision.
43
+ */
44
+#define EFI_JIFFIES_PER_SEC 32
45
+
39 46
 /** Current tick count */
40 47
 static unsigned long efi_jiffies;
41 48
 
@@ -95,7 +102,7 @@ static unsigned long efi_currticks ( void ) {
95 102
 	if ( efi_shutdown_in_progress )
96 103
 		efi_jiffies++;
97 104
 
98
-	return efi_jiffies;
105
+	return ( efi_jiffies * ( TICKS_PER_SEC / EFI_JIFFIES_PER_SEC ) );
99 106
 }
100 107
 
101 108
 /**
@@ -133,7 +140,7 @@ static void efi_tick_startup ( void ) {
133 140
 
134 141
 	/* Start timer tick */
135 142
 	if ( ( efirc = bs->SetTimer ( efi_tick_event, TimerPeriodic,
136
-				      ( 10000000 / EFI_TICKS_PER_SEC ) ) ) !=0){
143
+				      ( 10000000 / EFI_JIFFIES_PER_SEC ) ))!=0){
137 144
 		rc = -EEFI ( efirc );
138 145
 		DBGC ( colour, "EFI could not start timer tick: %s\n",
139 146
 		       strerror ( rc ) );
@@ -141,7 +148,7 @@ static void efi_tick_startup ( void ) {
141 148
 		return;
142 149
 	}
143 150
 	DBGC ( colour, "EFI timer started at %d ticks per second\n",
144
-	       EFI_TICKS_PER_SEC );
151
+	       EFI_JIFFIES_PER_SEC );
145 152
 }
146 153
 
147 154
 /**
@@ -180,6 +187,9 @@ struct startup_fn efi_tick_startup_fn __startup_fn ( STARTUP_EARLY ) = {
180 187
 	.shutdown = efi_tick_shutdown,
181 188
 };
182 189
 
183
-PROVIDE_TIMER ( efi, udelay, efi_udelay );
184
-PROVIDE_TIMER ( efi, currticks, efi_currticks );
185
-PROVIDE_TIMER_INLINE ( efi, ticks_per_sec );
190
+/** EFI timer */
191
+struct timer efi_timer __timer ( TIMER_NORMAL ) = {
192
+	.name = "efi",
193
+	.currticks = efi_currticks,
194
+	.udelay = efi_udelay,
195
+};

+ 10
- 16
src/interface/linux/linux_timer.c View File

@@ -39,16 +39,6 @@ static void linux_udelay(unsigned long usecs)
39 39
 	linux_usleep(usecs);
40 40
 }
41 41
 
42
-/**
43
- * Get number of ticks per second
44
- *
45
- * @ret ticks_per_sec	Number of ticks per second
46
- */
47
-static unsigned long linux_ticks_per_sec(void)
48
-{
49
-	return 1000;
50
-}
51
-
52 42
 /**
53 43
  * Get current system time in ticks
54 44
  *
@@ -67,21 +57,25 @@ static unsigned long linux_currticks(void)
67 57
 {
68 58
 	static struct timeval start;
69 59
 	static int initialized = 0;
60
+	struct timeval now;
61
+	unsigned long ticks;
70 62
 
71 63
 	if (! initialized) {
72 64
 		linux_gettimeofday(&start, NULL);
73 65
 		initialized = 1;
74 66
 	}
75 67
 
76
-	struct timeval now;
77 68
 	linux_gettimeofday(&now, NULL);
78 69
 
79
-	unsigned long ticks = (now.tv_sec - start.tv_sec) * linux_ticks_per_sec();
80
-	ticks += now.tv_usec / (long)(1000000 / linux_ticks_per_sec());
70
+	ticks = ( ( now.tv_sec - start.tv_sec ) * TICKS_PER_SEC );
71
+	ticks += ( now.tv_usec / ( 1000000 / TICKS_PER_SEC ) );
81 72
 
82 73
 	return ticks;
83 74
 }
84 75
 
85
-PROVIDE_TIMER(linux, udelay, linux_udelay);
86
-PROVIDE_TIMER(linux, currticks, linux_currticks);
87
-PROVIDE_TIMER(linux, ticks_per_sec, linux_ticks_per_sec);
76
+/** Linux timer */
77
+struct timer linux_timer __timer ( TIMER_NORMAL ) = {
78
+	.name = "linux",
79
+	.currticks = linux_currticks,
80
+	.udelay = linux_udelay,
81
+};

+ 4
- 4
src/net/80211/net80211.c View File

@@ -1321,7 +1321,7 @@ struct net80211_probe_ctx * net80211_probe_start ( struct net80211_device *dev,
1321 1321
 	ctx->ticks_start = currticks();
1322 1322
 	ctx->ticks_beacon = 0;
1323 1323
 	ctx->ticks_channel = currticks();
1324
-	ctx->hop_time = ticks_per_sec() / ( active ? 2 : 6 );
1324
+	ctx->hop_time = TICKS_PER_SEC / ( active ? 2 : 6 );
1325 1325
 
1326 1326
 	/*
1327 1327
 	 * Channels on 2.4GHz overlap, and the most commonly used
@@ -1363,8 +1363,8 @@ struct net80211_probe_ctx * net80211_probe_start ( struct net80211_device *dev,
1363 1363
 int net80211_probe_step ( struct net80211_probe_ctx *ctx )
1364 1364
 {
1365 1365
 	struct net80211_device *dev = ctx->dev;
1366
-	u32 start_timeout = NET80211_PROBE_TIMEOUT * ticks_per_sec();
1367
-	u32 gather_timeout = ticks_per_sec();
1366
+	u32 start_timeout = NET80211_PROBE_TIMEOUT * TICKS_PER_SEC;
1367
+	u32 gather_timeout = TICKS_PER_SEC;
1368 1368
 	u32 now = currticks();
1369 1369
 	struct io_buffer *iob;
1370 1370
 	int signal;
@@ -2606,7 +2606,7 @@ static void net80211_rx_frag ( struct net80211_device *dev,
2606 2606
 		/* start a frag cache entry */
2607 2607
 		int i, newest = -1;
2608 2608
 		u32 curr_ticks = currticks(), newest_ticks = 0;
2609
-		u32 timeout = ticks_per_sec() * NET80211_FRAG_TIMEOUT;
2609
+		u32 timeout = TICKS_PER_SEC * NET80211_FRAG_TIMEOUT;
2610 2610
 
2611 2611
 		for ( i = 0; i < NET80211_NR_CONCURRENT_FRAGS; i++ ) {
2612 2612
 			if ( dev->frags[i].in_use == 0 )

+ 1
- 1
src/net/fcoe.c View File

@@ -1094,7 +1094,7 @@ static void fcoe_expired ( struct retry_timer *timer, int over __unused ) {
1094 1094
 
1095 1095
 		/* Send keepalive */
1096 1096
 		start_timer_fixed ( &fcoe->timer,
1097
-			      ( ( fcoe->keepalive * TICKS_PER_SEC ) / 1000 ) );
1097
+				    ( fcoe->keepalive * TICKS_PER_MS ) );
1098 1098
 		fcoe_fip_tx_keepalive ( fcoe );
1099 1099
 
1100 1100
 		/* Abandon FCF if we have not seen its advertisements */

+ 1
- 1
src/net/stp.c View File

@@ -110,7 +110,7 @@ static int stp_rx ( struct io_buffer *iobuf, struct net_device *netdev,
110 110
 		       "forwarding\n",
111 111
 		       netdev->name, eth_ntoa ( stp->sender.mac ),
112 112
 		       ntohs ( stp->port ), stp->flags );
113
-		hello = ( ( ntohs ( stp->hello ) * TICKS_PER_SEC ) / 256 );
113
+		hello = ( ntohs ( stp->hello ) * ( TICKS_PER_SEC / 256 ) );
114 114
 		netdev_link_block ( netdev, ( hello * 2 ) );
115 115
 		rc = -ENETUNREACH;
116 116
 		goto done;

Loading…
Cancel
Save