diff options
| author | Alexey Zaytsev | 2007-12-01 05:07:01 +0100 |
|---|---|---|
| committer | Alexey Zaytsev | 2008-03-02 01:15:07 +0100 |
| commit | 4006d229e50204c93c1aa04c58385ce2e66d597e (patch) | |
| tree | 1c07ed3523e40304e0c4b81aaa33c6316d1bd11a /src/arch/i386/drivers | |
| parent | [DHCP] Fix RFC4390 client identifier constructions. (diff) | |
| download | ipxe-4006d229e50204c93c1aa04c58385ce2e66d597e.tar.gz ipxe-4006d229e50204c93c1aa04c58385ce2e66d597e.tar.xz ipxe-4006d229e50204c93c1aa04c58385ce2e66d597e.zip | |
Introduce the new timer subsystem.
Timer subsystem initialization code in core/timer.c
Split the BIOS and RTDSC timer drivers from i386_timer.c
Split arch/i386/firmware/pcbios/bios.c into the RTSDC
timer driver and arch/i386/core/nap.c
Split the headers properly:
include/unistd.h - delay functions to be used by the
gPXE core and drivers.
include/gpxe/timer.h - the fimer subsystem interface
to be used by the timer drivers
and currticks() to be used by
the code gPXE subsystems.
include/latch.h - removed
include/timer.h - scheduled for removal. Some driver
are using currticks, which is
only for core subsystems.
Signed-off-by: Alexey Zaytsev <alexey.zaytsev@gmail.com>
Diffstat (limited to 'src/arch/i386/drivers')
| -rw-r--r-- | src/arch/i386/drivers/timer_bios.c | 57 | ||||
| -rw-r--r-- | src/arch/i386/drivers/timer_rtdsc.c | 90 |
2 files changed, 147 insertions, 0 deletions
diff --git a/src/arch/i386/drivers/timer_bios.c b/src/arch/i386/drivers/timer_bios.c new file mode 100644 index 000000000..f9caf8d9a --- /dev/null +++ b/src/arch/i386/drivers/timer_bios.c @@ -0,0 +1,57 @@ +/* + * Etherboot routines for PCBIOS firmware. + * + * Body of routines taken from old pcbios.S + */ + +#include <gpxe/init.h> +#include <gpxe/timer.h> +#include <stdio.h> +#include <realmode.h> +#include <bios.h> +#include <bits/timer2.h> + +/* A bit faster actually, but we don't care. */ +#define TIMER2_TICKS_PER_SEC 18 + +/* + * Use direct memory access to BIOS variables, longword 0040:006C (ticks + * today) and byte 0040:0070 (midnight crossover flag) instead of calling + * timeofday BIOS interrupt. + */ + +static tick_t bios_currticks ( void ) { + static int days = 0; + uint32_t ticks; + uint8_t midnight; + + /* Re-enable interrupts so that the timer interrupt can occur */ + __asm__ __volatile__ ( REAL_CODE ( "sti\n\t" + "nop\n\t" + "nop\n\t" + "cli\n\t" ) : : ); + + get_real ( ticks, BDA_SEG, 0x006c ); + get_real ( midnight, BDA_SEG, 0x0070 ); + + if ( midnight ) { + midnight = 0; + put_real ( midnight, BDA_SEG, 0x0070 ); + days += 0x1800b0; + } + + return ( (days + ticks) * (USECS_IN_SEC / TIMER2_TICKS_PER_SEC) ); +} + +static int bios_ts_init(void) +{ + DBG("BIOS timer installed\n"); + return 0; +} + +struct timer bios_ts __timer ( 02 ) = { + .init = bios_ts_init, + .udelay = i386_timer2_udelay, + .currticks = bios_currticks, +}; + diff --git a/src/arch/i386/drivers/timer_rtdsc.c b/src/arch/i386/drivers/timer_rtdsc.c new file mode 100644 index 000000000..1cd2abead --- /dev/null +++ b/src/arch/i386/drivers/timer_rtdsc.c @@ -0,0 +1,90 @@ + +#include <gpxe/init.h> +#include <gpxe/timer.h> +#include <stdio.h> +#include <bits/cpu.h> +#include <bits/timer2.h> +#include <io.h> + + +#define rdtsc(low,high) \ + __asm__ __volatile__("rdtsc" : "=a" (low), "=d" (high)) + +#define rdtscll(val) \ + __asm__ __volatile__ ("rdtsc" : "=A" (val)) + +static unsigned long long calibrate_tsc(void) +{ + uint32_t startlow, starthigh; + uint32_t endlow, endhigh; + + rdtsc(startlow,starthigh); + i386_timer2_udelay(USECS_IN_MSEC/2); + rdtsc(endlow,endhigh); + + /* 64-bit subtract - gcc just messes up with long longs */ + /* XXX ORLY? Check it. */ + __asm__("subl %2,%0\n\t" + "sbbl %3,%1" + :"=a" (endlow), "=d" (endhigh) + :"g" (startlow), "g" (starthigh), + "0" (endlow), "1" (endhigh)); + + /* Error: ECPUTOOFAST */ + if (endhigh) + goto bad_ctc; + + endlow *= MSECS_IN_SEC*2; + return endlow; + + /* + * The CTC wasn't reliable: we got a hit on the very first read, + * or the CPU was so fast/slow that the quotient wouldn't fit in + * 32 bits.. + */ +bad_ctc: + return 0; +} +static uint32_t clocks_per_second = 0; + +static tick_t rtdsc_currticks(void) +{ + uint32_t clocks_high, clocks_low; + uint32_t currticks; + + /* Read the Time Stamp Counter */ + rdtsc(clocks_low, clocks_high); + + /* currticks = clocks / clocks_per_tick; */ + __asm__("divl %1" + :"=a" (currticks) + :"r" (clocks_per_second/USECS_IN_SEC), "0" (clocks_low), "d" (clocks_high)); + + return currticks; +} + +static int rtdsc_ts_init(void) +{ + + struct cpuinfo_x86 cpu_info; + + get_cpuinfo(&cpu_info); + if (cpu_info.features & X86_FEATURE_TSC) { + clocks_per_second = calibrate_tsc(); + if (clocks_per_second) { + DBG("RTDSC Ticksource installed. CPU running at %ld Mhz\n", + clocks_per_second/(1000*1000)); + return 0; + } + } + + printf("RTDSC timer not available on this machine.\n"); + return 1; +} + +struct timer rtdsc_ts __timer (01) = { + .init = rtdsc_ts_init, + .udelay = generic_currticks_udelay, + .currticks = rtdsc_currticks, +}; + |
