iPXE
Defines | Functions | Variables
rdtsc_timer.c File Reference

RDTSC timer. More...

#include <string.h>
#include <errno.h>
#include <ipxe/timer.h>
#include <ipxe/cpuid.h>
#include <ipxe/pit8254.h>

Go to the source code of this file.

Defines

#define TSC_CALIBRATE_US   1024
 Number of microseconds to use for TSC calibration.
#define TSC_SCALED_HZ   32
 Minimum resolution for scaled TSC timer.
#define colour   &tsc_per_us
 Colour for debug messages.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
static __always_inline
unsigned long 
rdtsc_raw (void)
 Get raw TSC value.
static __always_inline
unsigned long 
rdtsc_scaled (void)
 Get TSC value, shifted to avoid rollover within a realistic timescale.
static unsigned long rdtsc_currticks (void)
 Get current system time in ticks.
static void rdtsc_udelay (unsigned long usecs)
 Delay for a fixed number of microseconds.
static int rdtsc_probe (void)
 Probe RDTSC timer.
struct timer rdtsc_timer __timer (TIMER_PREFERRED)
 RDTSC timer.

Variables

static unsigned long tsc_per_us
 TSC increment per microsecond.
static unsigned int tsc_scale
 TSC scale (expressed as a bit shift)
static unsigned long ticks_per_scaled_tsc
 Number of timer ticks per scaled TSC increment.

Detailed Description

RDTSC timer.

Definition in file rdtsc_timer.c.


Define Documentation

#define TSC_CALIBRATE_US   1024

Number of microseconds to use for TSC calibration.

Definition at line 39 of file rdtsc_timer.c.

Referenced by rdtsc_probe().

#define TSC_SCALED_HZ   32

Minimum resolution for scaled TSC timer.

Definition at line 45 of file rdtsc_timer.c.

Referenced by rdtsc_probe().

#define colour   &tsc_per_us

Colour for debug messages.

Definition at line 57 of file rdtsc_timer.c.

Referenced by rdtsc_probe().


Function Documentation

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )
static __always_inline unsigned long rdtsc_raw ( void  ) [inline, static]

Get raw TSC value.

Return values:
tscRaw TSC value

Definition at line 64 of file rdtsc_timer.c.

References __asm__(), and raw.

Referenced by rdtsc_probe(), and rdtsc_udelay().

                                                               {
        unsigned long raw;

        __asm__ __volatile__ ( "rdtsc\n\t" : "=a" ( raw ) : : "edx" );
        return raw;
}
static __always_inline unsigned long rdtsc_scaled ( void  ) [inline, static]

Get TSC value, shifted to avoid rollover within a realistic timescale.

Return values:
tscScaled TSC value

Definition at line 76 of file rdtsc_timer.c.

References __asm__(), and tsc_scale.

Referenced by rdtsc_currticks().

                                                                  {
        unsigned long scaled;

        __asm__ __volatile__ ( "rdtsc\n\t"
                               "shrdl %b1, %%edx, %%eax\n\t"
                               : "=a" ( scaled ) : "c" ( tsc_scale ) : "edx" );
        return scaled;
}
static unsigned long rdtsc_currticks ( void  ) [static]

Get current system time in ticks.

Return values:
ticksCurrent time, in ticks

Definition at line 90 of file rdtsc_timer.c.

References rdtsc_scaled(), and ticks_per_scaled_tsc.

                                              {
        unsigned long scaled;

        scaled = rdtsc_scaled();
        return ( scaled * ticks_per_scaled_tsc );
}
static void rdtsc_udelay ( unsigned long  usecs) [static]

Delay for a fixed number of microseconds.

Parameters:
usecsNumber of microseconds for which to delay

Definition at line 102 of file rdtsc_timer.c.

References rdtsc_raw(), start, and tsc_per_us.

                                                 {
        unsigned long start;
        unsigned long elapsed;
        unsigned long threshold;

        start = rdtsc_raw();
        threshold = ( usecs * tsc_per_us );
        do {
                elapsed = ( rdtsc_raw() - start );
        } while ( elapsed < threshold );
}
static int rdtsc_probe ( void  ) [static]

Probe RDTSC timer.

Return values:
rcReturn status code

Definition at line 119 of file rdtsc_timer.c.

References colour, CPUID_APM, CPUID_APM_EDX_TSC_INVARIANT, cpuid_supported(), DBGC, EIO, ENOTTY, rc, rdtsc_raw(), strerror(), ticks_per_scaled_tsc, TICKS_PER_SEC, TSC_CALIBRATE_US, tsc_per_us, tsc_scale, and TSC_SCALED_HZ.

                                {
        unsigned long before;
        unsigned long after;
        unsigned long elapsed;
        uint32_t apm;
        uint32_t discard_a;
        uint32_t discard_b;
        uint32_t discard_c;
        int rc;

        /* Check that TSC is invariant */
        if ( ( rc = cpuid_supported ( CPUID_APM ) ) != 0 ) {
                DBGC ( colour, "RDTSC cannot determine APM features: %s\n",
                       strerror ( rc ) );
                return rc;
        }
        cpuid ( CPUID_APM, 0, &discard_a, &discard_b, &discard_c, &apm );
        if ( ! ( apm & CPUID_APM_EDX_TSC_INVARIANT ) ) {
                DBGC ( colour, "RDTSC has non-invariant TSC (%#08x)\n",
                       apm );
                return -ENOTTY;
        }

        /* Calibrate udelay() timer via 8254 PIT */
        before = rdtsc_raw();
        pit8254_udelay ( TSC_CALIBRATE_US );
        after = rdtsc_raw();
        elapsed = ( after - before );
        tsc_per_us = ( elapsed / TSC_CALIBRATE_US );
        if ( ! tsc_per_us ) {
                DBGC ( colour, "RDTSC has zero TSC per microsecond\n" );
                return -EIO;
        }

        /* Calibrate currticks() scaling factor */
        tsc_scale = 31;
        ticks_per_scaled_tsc = ( ( 1UL << tsc_scale ) /
                                 ( tsc_per_us * ( 1000000 / TICKS_PER_SEC ) ) );
        while ( ticks_per_scaled_tsc > ( TICKS_PER_SEC / TSC_SCALED_HZ ) ) {
                tsc_scale--;
                ticks_per_scaled_tsc >>= 1;
        }
        DBGC ( colour, "RDTSC has %ld tsc per us, %ld ticks per 2^%d tsc\n",
               tsc_per_us, ticks_per_scaled_tsc, tsc_scale );
        if ( ! ticks_per_scaled_tsc ) {
                DBGC ( colour, "RDTSC has zero ticks per TSC\n" );
                return -EIO;
        }

        return 0;
}
struct timer acpi_timer __timer ( TIMER_PREFERRED  ) [read]
Initial value:
 {
        .name = "acpi",
        .probe = acpi_timer_probe,
        .currticks = acpi_currticks,
        .udelay = acpi_udelay,
}

RDTSC timer.

ACPI timer.


Variable Documentation

unsigned long tsc_per_us [static]

TSC increment per microsecond.

Definition at line 42 of file rdtsc_timer.c.

Referenced by rdtsc_probe(), and rdtsc_udelay().

unsigned int tsc_scale [static]

TSC scale (expressed as a bit shift)

We use this to avoid the need for 64-bit divsion on 32-bit systems.

Definition at line 51 of file rdtsc_timer.c.

Referenced by rdtsc_probe(), and rdtsc_scaled().

unsigned long ticks_per_scaled_tsc [static]

Number of timer ticks per scaled TSC increment.

Definition at line 54 of file rdtsc_timer.c.

Referenced by rdtsc_currticks(), and rdtsc_probe().