patch-2.2.3 linux/arch/i386/kernel/time.c
Next file: linux/arch/m68k/defconfig
Previous file: linux/arch/i386/kernel/bios32.c
Back to the patch index
Back to the overall index
- Lines: 195
- Date:
Mon Mar 8 11:38:51 1999
- Orig file:
v2.2.2/linux/arch/i386/kernel/time.c
- Orig date:
Wed Jan 20 23:14:04 1999
diff -u --recursive --new-file v2.2.2/linux/arch/i386/kernel/time.c linux/arch/i386/kernel/time.c
@@ -30,19 +30,6 @@
* serialize accesses to xtime/lost_ticks).
*/
-/* What about the "updated NTP code" stuff in 2.0 time.c? It's not in
- * 2.1, perhaps it should be ported, too.
- *
- * What about the BUGGY_NEPTUN_TIMER stuff in do_slow_gettimeoffset()?
- * Whatever it fixes, is it also fixed in the new code from the Jumbo
- * patch, so that that code can be used instead?
- *
- * The CPU Hz should probably be displayed in check_bugs() together
- * with the CPU vendor and type. Perhaps even only in MHz, though that
- * takes away some of the fun of the new code :)
- *
- * - Michael Krause */
-
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -556,70 +543,72 @@
* device.
*/
+#define CALIBRATE_LATCH (5 * LATCH)
+#define CALIBRATE_TIME (5 * 1000020/HZ)
+
__initfunc(static unsigned long calibrate_tsc(void))
{
- unsigned long retval;
+ /* Set the Gate high, disable speaker */
+ outb((inb(0x61) & ~0x02) | 0x01, 0x61);
- __asm__( /* set the Gate high, program CTC channel 2 for mode 0
- * (interrupt on terminal count mode), binary count,
- * load 5 * LATCH count, (LSB and MSB)
- * to begin countdown, read the TSC and busy wait.
- * BTW LATCH is calculated in timex.h from the HZ value
- */
+ /*
+ * Now let's take care of CTC channel 2
+ *
+ * Set the Gate high, program CTC channel 2 for mode 0,
+ * (interrupt on terminal count mode), binary count,
+ * load 5 * LATCH count, (LSB and MSB) to begin countdown.
+ */
+ outb(0xb0, 0x43); /* binary, mode 0, LSB/MSB, Ch 2 */
+ outb(CALIBRATE_LATCH & 0xff, 0x42); /* LSB of count */
+ outb(CALIBRATE_LATCH >> 8, 0x42); /* MSB of count */
- /* Set the Gate high, disable speaker */
- "inb $0x61, %%al\n\t" /* Read port */
- "andb $0xfd, %%al\n\t" /* Turn off speaker Data */
- "orb $0x01, %%al\n\t" /* Set Gate high */
- "outb %%al, $0x61\n\t" /* Write port */
-
- /* Now let's take care of CTC channel 2 */
- "movb $0xb0, %%al\n\t" /* binary, mode 0, LSB/MSB, ch 2*/
- "outb %%al, $0x43\n\t" /* Write to CTC command port */
- "movl %1, %%eax\n\t"
- "outb %%al, $0x42\n\t" /* LSB of count */
- "shrl $8, %%eax\n\t"
- "outb %%al, $0x42\n\t" /* MSB of count */
-
- /* Read the TSC; counting has just started */
- "rdtsc\n\t"
- /* Move the value for safe-keeping. */
- "movl %%eax, %%ebx\n\t"
- "movl %%edx, %%ecx\n\t"
-
- /* Busy wait. Only 50 ms wasted at boot time. */
- "0: inb $0x61, %%al\n\t" /* Read Speaker Output Port */
- "testb $0x20, %%al\n\t" /* Check CTC channel 2 output (bit 5) */
- "jz 0b\n\t"
-
- /* And read the TSC. 5 jiffies (50.00077ms) have elapsed. */
- "rdtsc\n\t"
-
- /* Great. So far so good. Store last TSC reading in
- * last_tsc_low (only 32 lsb bits needed) */
- "movl %%eax, last_tsc_low\n\t"
- /* And now calculate the difference between the readings. */
- "subl %%ebx, %%eax\n\t"
- "sbbl %%ecx, %%edx\n\t" /* 64-bit subtract */
- /* but probably edx = 0 at this point (see below). */
- /* Now we have 5 * (TSC counts per jiffy) in eax. We want
- * to calculate TSC->microsecond conversion factor. */
-
- /* Note that edx (high 32-bits of difference) will now be
- * zero iff CPU clock speed is less than 85 GHz. Moore's
- * law says that this is likely to be true for the next
- * 12 years or so. You will have to change this code to
- * do a real 64-by-64 divide before that time's up. */
- "movl %%eax, %%ecx\n\t"
- "xorl %%eax, %%eax\n\t"
- "movl %2, %%edx\n\t"
- "divl %%ecx\n\t" /* eax= 2^32 / (1 * TSC counts per microsecond) */
- /* Return eax for the use of fast_gettimeoffset */
- "movl %%eax, %0\n\t"
- : "=r" (retval)
- : "r" (5 * LATCH), "r" (5 * 1000020/HZ)
- : /* we clobber: */ "ax", "bx", "cx", "dx", "cc", "memory");
- return retval;
+ {
+ unsigned long startlow, starthigh;
+ unsigned long endlow, endhigh;
+ unsigned long count;
+
+ __asm__ __volatile__("rdtsc":"=a" (startlow),"=d" (starthigh));
+ count = 0;
+ do {
+ count++;
+ } while ((inb(0x61) & 0x20) == 0);
+ __asm__ __volatile__("rdtsc":"=a" (endlow),"=d" (endhigh));
+
+ last_tsc_low = endlow;
+
+ /* Error: ECTCNEVERSET */
+ if (count <= 1)
+ goto bad_ctc;
+
+ /* 64-bit subtract - gcc just messes up with long longs */
+ __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;
+
+ /* Error: ECPUTOOSLOW */
+ if (endlow <= CALIBRATE_TIME)
+ goto bad_ctc;
+
+ __asm__("divl %2"
+ :"=a" (endlow), "=d" (endhigh)
+ :"r" (endlow), "0" (0), "1" (CALIBRATE_TIME));
+
+ 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;
}
__initfunc(void time_init(void))
@@ -655,23 +644,26 @@
dodgy_tsc();
if (boot_cpu_data.x86_capability & X86_FEATURE_TSC) {
+ unsigned long tsc_quotient = calibrate_tsc();
+ if (tsc_quotient) {
+ fast_gettimeoffset_quotient = tsc_quotient;
+ use_tsc = 1;
#ifndef do_gettimeoffset
- do_gettimeoffset = do_fast_gettimeoffset;
+ do_gettimeoffset = do_fast_gettimeoffset;
#endif
- do_get_fast_time = do_gettimeofday;
- use_tsc = 1;
- fast_gettimeoffset_quotient = calibrate_tsc();
-
- /* report CPU clock rate in Hz.
- * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
- * clock/second. Our precision is about 100 ppm.
- */
- { unsigned long eax=0, edx=1000000;
- __asm__("divl %2"
- :"=a" (cpu_hz), "=d" (edx)
- :"r" (fast_gettimeoffset_quotient),
- "0" (eax), "1" (edx));
- printk("Detected %ld Hz processor.\n", cpu_hz);
+ do_get_fast_time = do_gettimeofday;
+
+ /* report CPU clock rate in Hz.
+ * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =
+ * clock/second. Our precision is about 100 ppm.
+ */
+ { unsigned long eax=0, edx=1000000;
+ __asm__("divl %2"
+ :"=a" (cpu_hz), "=d" (edx)
+ :"r" (tsc_quotient),
+ "0" (eax), "1" (edx));
+ printk("Detected %ld Hz processor.\n", cpu_hz);
+ }
}
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)