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
-#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
  *
29
  *
30
  */
30
  */
31
 
31
 
32
-#include <assert.h>
32
+#include <string.h>
33
+#include <errno.h>
33
 #include <ipxe/timer.h>
34
 #include <ipxe/timer.h>
35
+#include <ipxe/cpuid.h>
34
 #include <ipxe/pit8254.h>
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
  * Delay for a fixed number of microseconds
98
  * Delay for a fixed number of microseconds
48
 static void rdtsc_udelay ( unsigned long usecs ) {
102
 static void rdtsc_udelay ( unsigned long usecs ) {
49
 	unsigned long start;
103
 	unsigned long start;
50
 	unsigned long elapsed;
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
 #define BDA_EBDA 0x000e
7
 #define BDA_EBDA 0x000e
8
 #define BDA_EQUIPMENT_WORD 0x0010
8
 #define BDA_EQUIPMENT_WORD 0x0010
9
 #define BDA_FBMS 0x0013
9
 #define BDA_FBMS 0x0013
10
+#define BDA_TICKS 0x006c
11
+#define BDA_MIDNIGHT 0x0070
10
 #define BDA_REBOOT 0x0072
12
 #define BDA_REBOOT 0x0072
11
 #define BDA_REBOOT_WARM 0x1234
13
 #define BDA_REBOOT_WARM 0x1234
12
 #define BDA_NUM_DRIVES 0x0075
14
 #define BDA_NUM_DRIVES 0x0075

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

26
 #define ERRFILE_rtc_entropy	( ERRFILE_ARCH | ERRFILE_CORE | 0x000f0000 )
26
 #define ERRFILE_rtc_entropy	( ERRFILE_ARCH | ERRFILE_CORE | 0x000f0000 )
27
 #define ERRFILE_acpipwr		( ERRFILE_ARCH | ERRFILE_CORE | 0x00100000 )
27
 #define ERRFILE_acpipwr		( ERRFILE_ARCH | ERRFILE_CORE | 0x00100000 )
28
 #define ERRFILE_cpuid		( ERRFILE_ARCH | ERRFILE_CORE | 0x00110000 )
28
 #define ERRFILE_cpuid		( ERRFILE_ARCH | ERRFILE_CORE | 0x00110000 )
29
+#define ERRFILE_rdtsc_timer	( ERRFILE_ARCH | ERRFILE_CORE | 0x00120000 )
29
 
30
 
30
 #define ERRFILE_bootsector     ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
31
 #define ERRFILE_bootsector     ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00000000 )
31
 #define ERRFILE_bzimage	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )
32
 #define ERRFILE_bzimage	       ( ERRFILE_ARCH | ERRFILE_IMAGE | 0x00010000 )

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

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
-#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
 /** Get CPU model */
57
 /** Get CPU model */
58
 #define CPUID_MODEL 0x80000002UL
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
  * Issue CPUID instruction
67
  * Issue CPUID instruction
62
  *
68
  *

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

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
 #include <ipxe/timer.h>
32
 #include <ipxe/timer.h>
33
 #include <realmode.h>
33
 #include <realmode.h>
34
 #include <bios.h>
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
  * Get current system time in ticks
49
  * Get current system time in ticks
43
  * of calling timeofday BIOS interrupt.
55
  * of calling timeofday BIOS interrupt.
44
  */
56
  */
45
 static unsigned long bios_currticks ( void ) {
57
 static unsigned long bios_currticks ( void ) {
46
-	static int days = 0;
58
+	static uint32_t offset;
47
 	uint32_t ticks;
59
 	uint32_t ticks;
48
 	uint8_t midnight;
60
 	uint8_t midnight;
49
 
61
 
53
 			       "nop\n\t"
65
 			       "nop\n\t"
54
 			       "cli\n\t" );
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
 	if ( midnight ) {
73
 	if ( midnight ) {
60
 		midnight = 0;
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

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
 		return rc;
117
 		return rc;
118
 
118
 
119
 	/* Convert to a number of timer ticks */
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
 	return 0;
122
 	return 0;
123
 }
123
 }

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

23
 
23
 
24
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
24
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
 
25
 
26
-#include <unistd.h>
26
+#include <string.h>
27
+#include <assert.h>
27
 #include <ipxe/process.h>
28
 #include <ipxe/process.h>
28
 #include <ipxe/console.h>
29
 #include <ipxe/console.h>
29
 #include <ipxe/keys.h>
30
 #include <ipxe/keys.h>
30
 #include <ipxe/nap.h>
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
  * Delay for a fixed number of milliseconds
61
  * Delay for a fixed number of milliseconds
61
 
89
 
62
 	return 0;
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
 	unsigned int counter = 1000;
1381
 	unsigned int counter = 1000;
1382
 
1382
 
1383
 	if (currticks() - sc->last_calib_ticks >
1383
 	if (currticks() - sc->last_calib_ticks >
1384
-	    ATH5K_CALIB_INTERVAL * ticks_per_sec()) {
1384
+	    ATH5K_CALIB_INTERVAL * TICKS_PER_SEC) {
1385
 		ath5k_calibrate(sc);
1385
 		ath5k_calibrate(sc);
1386
 		sc->last_calib_ticks = currticks();
1386
 		sc->last_calib_ticks = currticks();
1387
 	}
1387
 	}

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

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

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

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

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

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
-#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
 
3
 
4
 /** @file
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
 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
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
 #endif /* _IPXE_TIMER_H */
79
 #endif /* _IPXE_TIMER_H */

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

23
 		rc;							\
23
 		rc;							\
24
 	} )
24
 	} )
25
 
25
 
26
-/* Pick up udelay() */
26
+/* Pick up udelay() and sleep() */
27
 #include <ipxe/timer.h>
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
 static inline __always_inline void usleep ( unsigned long usecs ) {
29
 static inline __always_inline void usleep ( unsigned long usecs ) {
40
 	udelay ( usecs );
30
 	udelay ( usecs );
41
 }
31
 }

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

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
 /** Current tick count */
46
 /** Current tick count */
40
 static unsigned long efi_jiffies;
47
 static unsigned long efi_jiffies;
41
 
48
 
95
 	if ( efi_shutdown_in_progress )
102
 	if ( efi_shutdown_in_progress )
96
 		efi_jiffies++;
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
 
140
 
134
 	/* Start timer tick */
141
 	/* Start timer tick */
135
 	if ( ( efirc = bs->SetTimer ( efi_tick_event, TimerPeriodic,
142
 	if ( ( efirc = bs->SetTimer ( efi_tick_event, TimerPeriodic,
136
-				      ( 10000000 / EFI_TICKS_PER_SEC ) ) ) !=0){
143
+				      ( 10000000 / EFI_JIFFIES_PER_SEC ) ))!=0){
137
 		rc = -EEFI ( efirc );
144
 		rc = -EEFI ( efirc );
138
 		DBGC ( colour, "EFI could not start timer tick: %s\n",
145
 		DBGC ( colour, "EFI could not start timer tick: %s\n",
139
 		       strerror ( rc ) );
146
 		       strerror ( rc ) );
141
 		return;
148
 		return;
142
 	}
149
 	}
143
 	DBGC ( colour, "EFI timer started at %d ticks per second\n",
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
 	.shutdown = efi_tick_shutdown,
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
 	linux_usleep(usecs);
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
  * Get current system time in ticks
43
  * Get current system time in ticks
54
  *
44
  *
67
 {
57
 {
68
 	static struct timeval start;
58
 	static struct timeval start;
69
 	static int initialized = 0;
59
 	static int initialized = 0;
60
+	struct timeval now;
61
+	unsigned long ticks;
70
 
62
 
71
 	if (! initialized) {
63
 	if (! initialized) {
72
 		linux_gettimeofday(&start, NULL);
64
 		linux_gettimeofday(&start, NULL);
73
 		initialized = 1;
65
 		initialized = 1;
74
 	}
66
 	}
75
 
67
 
76
-	struct timeval now;
77
 	linux_gettimeofday(&now, NULL);
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
 	return ticks;
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
 	ctx->ticks_start = currticks();
1321
 	ctx->ticks_start = currticks();
1322
 	ctx->ticks_beacon = 0;
1322
 	ctx->ticks_beacon = 0;
1323
 	ctx->ticks_channel = currticks();
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
 	 * Channels on 2.4GHz overlap, and the most commonly used
1327
 	 * Channels on 2.4GHz overlap, and the most commonly used
1363
 int net80211_probe_step ( struct net80211_probe_ctx *ctx )
1363
 int net80211_probe_step ( struct net80211_probe_ctx *ctx )
1364
 {
1364
 {
1365
 	struct net80211_device *dev = ctx->dev;
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
 	u32 now = currticks();
1368
 	u32 now = currticks();
1369
 	struct io_buffer *iob;
1369
 	struct io_buffer *iob;
1370
 	int signal;
1370
 	int signal;
2606
 		/* start a frag cache entry */
2606
 		/* start a frag cache entry */
2607
 		int i, newest = -1;
2607
 		int i, newest = -1;
2608
 		u32 curr_ticks = currticks(), newest_ticks = 0;
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
 		for ( i = 0; i < NET80211_NR_CONCURRENT_FRAGS; i++ ) {
2611
 		for ( i = 0; i < NET80211_NR_CONCURRENT_FRAGS; i++ ) {
2612
 			if ( dev->frags[i].in_use == 0 )
2612
 			if ( dev->frags[i].in_use == 0 )

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

1094
 
1094
 
1095
 		/* Send keepalive */
1095
 		/* Send keepalive */
1096
 		start_timer_fixed ( &fcoe->timer,
1096
 		start_timer_fixed ( &fcoe->timer,
1097
-			      ( ( fcoe->keepalive * TICKS_PER_SEC ) / 1000 ) );
1097
+				    ( fcoe->keepalive * TICKS_PER_MS ) );
1098
 		fcoe_fip_tx_keepalive ( fcoe );
1098
 		fcoe_fip_tx_keepalive ( fcoe );
1099
 
1099
 
1100
 		/* Abandon FCF if we have not seen its advertisements */
1100
 		/* Abandon FCF if we have not seen its advertisements */

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

110
 		       "forwarding\n",
110
 		       "forwarding\n",
111
 		       netdev->name, eth_ntoa ( stp->sender.mac ),
111
 		       netdev->name, eth_ntoa ( stp->sender.mac ),
112
 		       ntohs ( stp->port ), stp->flags );
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
 		netdev_link_block ( netdev, ( hello * 2 ) );
114
 		netdev_link_block ( netdev, ( hello * 2 ) );
115
 		rc = -ENETUNREACH;
115
 		rc = -ENETUNREACH;
116
 		goto done;
116
 		goto done;

Loading…
Cancel
Save