Ignore:
Timestamp:
Jul 3, 2017, 11:21:16 AM (7 years ago)
Author:
max@…
Message:

Calibrate the LAPIC timer with the PIT, with one interrupt per
second for now (will be revisited).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/hal/x86_64/core/hal_apic.c

    r89 r117  
    5454/* -------------------------------------------------------------------------- */
    5555
     56uint64_t pit_ticks_base __in_kdata = 0;
     57
     58#define PIT_FREQUENCY   1193182
     59#define HZ              100 /* 1/HZ = 10ms */
     60
     61#define PIT_TIMER0      0x40
     62
     63#define PIT_CMD         0x43
     64#       define CMD_BINARY       0x00 /* Use Binary counter values */
     65#       define CMD_BCD          0x01 /* Use Binary Coded Decimal counter values */
     66#       define CMD_MODE0        0x00 /* Interrupt on Terminal Count */
     67#       define CMD_MODE1        0x02 /* Hardware Retriggerable One-Shot */
     68#       define CMD_MODE2        0x04 /* Rate Generator */
     69#       define CMD_MODE3        0x06 /* Square Wave */
     70#       define CMD_MODE4        0x08 /* Software Trigerred Strobe */
     71#       define CMD_MODE5        0x0a /* Hardware Trigerred Strobe */
     72#       define CMD_LATCH        0x00 /* latch counter for reading */
     73#       define CMD_LSB          0x10 /* LSB, 8 bits */
     74#       define CMD_MSB          0x20 /* MSB, 8 bits */
     75#       define CMD_16BIT        0x30 /* LSB and MSB, 16 bits */
     76#       define CMD_COUNTER0     0x00
     77#       define CMD_COUNTER1     0x40
     78#       define CMD_COUNTER2     0x80
     79#       define CMD_READBACK     0xc0
     80
     81void hal_pit_init()
     82{
     83        /* Initialize PIT clock 0 to the maximum counter value, 65535. */
     84        out8(PIT_CMD, CMD_COUNTER0|CMD_MODE2|CMD_16BIT);
     85        out8(PIT_TIMER0, 0xFF);
     86        out8(PIT_TIMER0, 0xFF);
     87}
     88
     89uint64_t
     90hal_pit_timer_read()
     91{
     92        static uint16_t last;
     93
     94        uint8_t lo, hi;
     95        uint16_t ctr;
     96        uint64_t ticks;
     97
     98        /* Read the current timer counter. */
     99        out8(PIT_CMD, CMD_COUNTER0|CMD_LATCH);
     100        lo = in8(PIT_TIMER0);
     101        hi = in8(PIT_TIMER0);
     102        ctr = (hi << 8) | lo;
     103
     104        /* If the counter has wrapped, assume we're into the next tick. */
     105        if (ctr > last)
     106                pit_ticks_base += 0xFFFF;
     107        last = ctr;
     108
     109        ticks = pit_ticks_base + (0xFFFF - ctr);
     110
     111        return ticks;
     112}
     113
     114/* -------------------------------------------------------------------------- */
     115
    56116paddr_t ioapic_pa __in_kdata = 0;
    57117vaddr_t ioapic_va __in_kdata = 0;
     
    132192{
    133193        return hal_lapic_read(LAPIC_ID) >> LAPIC_ID_SHIFT;
     194}
     195
     196/*
     197 * Use the PIT, which has a standard clock frequency, to determine the CPU's
     198 * exact bus frequency.
     199 */
     200static void hal_lapic_calibrate()
     201{
     202        uint64_t pittick, lapictick0, lapictick1;
     203        uint32_t lapicticks, lapicstart;
     204
     205        /* Initialize the LAPIC timer to the maximum value */
     206        hal_lapic_write(LAPIC_ICR_TIMER, 0xFFFFFFFF);
     207
     208        pittick = hal_pit_timer_read() + 1;
     209        while (hal_pit_timer_read() < pittick) {
     210                /* Wait until start of a PIT tick */
     211        }
     212
     213        /* Read base count from LAPIC */
     214        lapictick0 = hal_lapic_read(LAPIC_CCR_TIMER);
     215
     216        while (hal_pit_timer_read() < pittick + (PIT_FREQUENCY + HZ/2) / HZ) {
     217                /* Wait 1/HZ sec = 10ms */
     218        }
     219
     220        /* Read final count from LAPIC */
     221        lapictick1 = hal_lapic_read(LAPIC_CCR_TIMER);
     222
     223        /* Total number of LAPIC ticks per 1/HZ tick */
     224        lapicticks = (lapictick1 - lapictick0);
     225
     226        /* Finally, calibrate the timer, an interrupt each 1s. */
     227        lapicstart = - (lapicticks * 100);
     228        hal_lapic_write(LAPIC_ICR_TIMER, lapicstart);
    134229}
    135230
     
    171266        hal_lapic_write(LAPIC_LVT_TMR, LAPIC_TMR_TM|LAPIC_TMR_M);
    172267        hal_lapic_write(LAPIC_DCR_TIMER, LAPIC_DCRT_DIV1);
    173         hal_lapic_write(LAPIC_ICR_TIMER, 1000000000); // XXX calibrate
     268        hal_lapic_calibrate();
    174269        hal_lapic_write(LAPIC_LVT_TMR, LAPIC_TMR_TM|LAPIC_TIMER_VECTOR);
    175270}
Note: See TracChangeset for help on using the changeset viewer.