summaryrefslogtreecommitdiffstats
path: root/src/arch/i386/drivers
diff options
context:
space:
mode:
authorAlexey Zaytsev2007-12-01 05:07:01 +0100
committerAlexey Zaytsev2008-03-02 01:15:07 +0100
commit4006d229e50204c93c1aa04c58385ce2e66d597e (patch)
tree1c07ed3523e40304e0c4b81aaa33c6316d1bd11a /src/arch/i386/drivers
parent[DHCP] Fix RFC4390 client identifier constructions. (diff)
downloadipxe-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.c57
-rw-r--r--src/arch/i386/drivers/timer_rtdsc.c90
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,
+};
+