Revision 0cdd3d14

b/hw/kvm/i8254.c
23 23
 * THE SOFTWARE.
24 24
 */
25 25
#include "qemu-timer.h"
26
#include "sysemu.h"
26 27
#include "hw/i8254.h"
27 28
#include "hw/i8254_internal.h"
28 29
#include "kvm.h"
29 30

  
30 31
#define KVM_PIT_REINJECT_BIT 0
31 32

  
33
#define CALIBRATION_ROUNDS   3
34

  
32 35
typedef struct KVMPITState {
33 36
    PITCommonState pit;
34 37
    LostTickPolicy lost_tick_policy;
38
    bool state_valid;
35 39
} KVMPITState;
36 40

  
37
static void kvm_pit_get(PITCommonState *s)
41
static int64_t abs64(int64_t v)
38 42
{
43
    return v < 0 ? -v : v;
44
}
45

  
46
static void kvm_pit_get(PITCommonState *pit)
47
{
48
    KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
39 49
    struct kvm_pit_state2 kpit;
40 50
    struct kvm_pit_channel_state *kchan;
41 51
    struct PITChannelState *sc;
52
    int64_t offset, clock_offset;
53
    struct timespec ts;
42 54
    int i, ret;
43 55

  
56
    if (s->state_valid) {
57
        return;
58
    }
59

  
60
    /*
61
     * Measure the delta between CLOCK_MONOTONIC, the base used for
62
     * kvm_pit_channel_state::count_load_time, and vm_clock. Take the
63
     * minimum of several samples to filter out scheduling noise.
64
     */
65
    clock_offset = INT64_MAX;
66
    for (i = 0; i < CALIBRATION_ROUNDS; i++) {
67
        offset = qemu_get_clock_ns(vm_clock);
68
        clock_gettime(CLOCK_MONOTONIC, &ts);
69
        offset -= ts.tv_nsec;
70
        offset -= (int64_t)ts.tv_sec * 1000000000;
71
        if (abs64(offset) < abs64(clock_offset)) {
72
            clock_offset = offset;
73
        }
74
    }
75

  
44 76
    if (kvm_has_pit_state2()) {
45 77
        ret = kvm_vm_ioctl(kvm_state, KVM_GET_PIT2, &kpit);
46 78
        if (ret < 0) {
47 79
            fprintf(stderr, "KVM_GET_PIT2 failed: %s\n", strerror(ret));
48 80
            abort();
49 81
        }
50
        s->channels[0].irq_disabled = kpit.flags & KVM_PIT_FLAGS_HPET_LEGACY;
82
        pit->channels[0].irq_disabled = kpit.flags & KVM_PIT_FLAGS_HPET_LEGACY;
51 83
    } else {
52 84
        /*
53 85
         * kvm_pit_state2 is superset of kvm_pit_state struct,
......
61 93
    }
62 94
    for (i = 0; i < 3; i++) {
63 95
        kchan = &kpit.channels[i];
64
        sc = &s->channels[i];
96
        sc = &pit->channels[i];
65 97
        sc->count = kchan->count;
66 98
        sc->latched_count = kchan->latched_count;
67 99
        sc->count_latched = kchan->count_latched;
......
74 106
        sc->mode = kchan->mode;
75 107
        sc->bcd = kchan->bcd;
76 108
        sc->gate = kchan->gate;
77
        sc->count_load_time = kchan->count_load_time;
109
        sc->count_load_time = kchan->count_load_time + clock_offset;
78 110
    }
79 111

  
80
    sc = &s->channels[0];
112
    sc = &pit->channels[0];
81 113
    sc->next_transition_time =
82 114
        pit_get_next_transition_time(sc, sc->count_load_time);
83 115
}
......
173 205
    kvm_pit_put(pit);
174 206
}
175 207

  
208
static void kvm_pit_vm_state_change(void *opaque, int running,
209
                                    RunState state)
210
{
211
    KVMPITState *s = opaque;
212

  
213
    if (running) {
214
        s->state_valid = false;
215
    } else {
216
        kvm_pit_get(&s->pit);
217
        s->state_valid = true;
218
    }
219
}
220

  
176 221
static int kvm_pit_initfn(PITCommonState *pit)
177 222
{
178 223
    KVMPITState *s = DO_UPCAST(KVMPITState, pit, pit);
......
215 260

  
216 261
    qdev_init_gpio_in(&pit->dev.qdev, kvm_pit_irq_control, 1);
217 262

  
263
    qemu_add_vm_change_state_handler(kvm_pit_vm_state_change, s);
264

  
218 265
    return 0;
219 266
}
220 267

  

Also available in: Unified diff