source: trunk/packages/xen-3.1/xen-3.1/xen/arch/x86/hvm/vpt.c @ 34

Last change on this file since 34 was 34, checked in by hartmans, 18 years ago

Add xen and xen-common

File size: 6.0 KB
Line 
1/*
2 * vpt.c: Virtual Platform Timer
3 *
4 * Copyright (c) 2006, Xiaowei Yang, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place - Suite 330, Boston, MA 02111-1307 USA.
18 *
19 */
20#include <xen/time.h>
21#include <asm/hvm/support.h>
22#include <asm/hvm/vpt.h>
23#include <asm/event.h>
24
25static __inline__ void missed_ticks(struct periodic_time *pt)
26{
27    s_time_t missed_ticks;
28
29    missed_ticks = NOW() - pt->scheduled;
30    if ( missed_ticks > 0 ) 
31    {
32        missed_ticks = missed_ticks / (s_time_t) pt->period + 1;
33        if ( missed_ticks > 1000 )
34        {
35            /* TODO: Adjust guest time together */
36            pt->pending_intr_nr++;
37        }
38        else
39        {
40            pt->pending_intr_nr += missed_ticks;
41        }
42        pt->scheduled += missed_ticks * pt->period;
43    }
44}
45
46void pt_freeze_time(struct vcpu *v)
47{
48    struct list_head *head = &v->arch.hvm_vcpu.tm_list;
49    struct list_head *list;
50    struct periodic_time *pt;
51
52    if ( test_bit(_VPF_blocked, &v->pause_flags) )
53        return;
54
55    v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v);
56
57    list_for_each( list, head )
58    {
59        pt = list_entry(list, struct periodic_time, list);
60        stop_timer(&pt->timer);
61    }
62}
63
64void pt_thaw_time(struct vcpu *v)
65{
66    struct list_head *head = &v->arch.hvm_vcpu.tm_list;
67    struct list_head *list;
68    struct periodic_time *pt;
69
70    if ( v->arch.hvm_vcpu.guest_time )
71    {
72        hvm_set_guest_time(v, v->arch.hvm_vcpu.guest_time);
73        v->arch.hvm_vcpu.guest_time = 0;
74
75        list_for_each( list, head )
76        {
77            pt = list_entry(list, struct periodic_time, list);
78            missed_ticks(pt);
79            set_timer(&pt->timer, pt->scheduled);
80        }
81    }
82}
83
84/* Hook function for the platform periodic time */
85void pt_timer_fn(void *data)
86{
87    struct periodic_time *pt = data;
88
89    pt->pending_intr_nr++;
90    pt->scheduled += pt->period;
91
92    missed_ticks(pt);
93
94    if ( !pt->one_shot )
95        set_timer(&pt->timer, pt->scheduled);
96
97    vcpu_kick(pt->vcpu);
98}
99
100void pt_update_irq(struct vcpu *v)
101{
102    struct list_head *head = &v->arch.hvm_vcpu.tm_list;
103    struct list_head *list;
104    struct periodic_time *pt;
105    uint64_t max_lag = -1ULL;
106    int irq = -1;
107
108    list_for_each( list, head )
109    {
110        pt = list_entry(list, struct periodic_time, list);
111        if ( !is_isa_irq_masked(v, pt->irq) && pt->pending_intr_nr &&
112             ((pt->last_plt_gtime + pt->period_cycles) < max_lag) )
113        {
114            max_lag = pt->last_plt_gtime + pt->period_cycles;
115            irq = pt->irq;
116        }
117    }
118
119    if ( is_lvtt(v, irq) )
120    {
121        vlapic_set_irq(vcpu_vlapic(v), irq, 0);
122    }
123    else if ( irq >= 0 )
124    {
125        hvm_isa_irq_deassert(v->domain, irq);
126        hvm_isa_irq_assert(v->domain, irq);
127    }
128}
129
130struct periodic_time *is_pt_irq(struct vcpu *v, int vector, int type)
131{
132    struct list_head *head = &v->arch.hvm_vcpu.tm_list;
133    struct list_head *list;
134    struct periodic_time *pt;
135    struct RTCState *rtc = &v->domain->arch.hvm_domain.pl_time.vrtc;
136    int vec;
137
138    list_for_each( list, head )
139    {
140        pt = list_entry(list, struct periodic_time, list);
141        if ( !pt->pending_intr_nr )
142            continue;
143
144        if ( is_lvtt(v, pt->irq) )
145        {
146            if ( pt->irq != vector )
147                continue;
148            return pt;
149        }
150
151        vec = get_isa_irq_vector(v, pt->irq, type);
152
153        /* RTC irq need special care */
154        if ( (vector != vec) || (pt->irq == 8 && !is_rtc_periodic_irq(rtc)) )
155            continue;
156
157        return pt;
158    }
159
160    return NULL;
161}
162
163void pt_intr_post(struct vcpu *v, int vector, int type)
164{
165    struct periodic_time *pt = is_pt_irq(v, vector, type);
166
167    if ( pt == NULL )
168        return;
169
170    pt->pending_intr_nr--;
171    pt->last_plt_gtime += pt->period_cycles;
172
173    if ( hvm_get_guest_time(pt->vcpu) < pt->last_plt_gtime )
174        hvm_set_guest_time(pt->vcpu, pt->last_plt_gtime);
175
176    if ( pt->cb != NULL )
177        pt->cb(pt->vcpu, pt->priv);
178}
179
180/* If pt is enabled, discard pending intr */
181void pt_reset(struct vcpu *v)
182{
183    struct list_head *head = &v->arch.hvm_vcpu.tm_list;
184    struct list_head *list;
185    struct periodic_time *pt;
186
187    list_for_each( list, head )
188    {
189        pt = list_entry(list, struct periodic_time, list);
190        if ( pt->enabled )
191        {
192            pt->pending_intr_nr = 0;
193            pt->last_plt_gtime = hvm_get_guest_time(pt->vcpu);
194            pt->scheduled = NOW() + pt->period;
195            set_timer(&pt->timer, pt->scheduled);
196        }
197    }
198}
199
200void create_periodic_time(struct vcpu *v, struct periodic_time *pt, uint64_t period,
201                          uint8_t irq, char one_shot, time_cb *cb, void *data)
202{
203    destroy_periodic_time(pt);
204
205    pt->enabled = 1;
206    if ( period < 900000 ) /* < 0.9 ms */
207    {
208        gdprintk(XENLOG_WARNING,
209                 "HVM_PlatformTime: program too small period %"PRIu64"\n",
210                 period);
211        period = 900000; /* force to 0.9ms */
212    }
213    pt->period = period;
214    pt->vcpu = v;
215    pt->last_plt_gtime = hvm_get_guest_time(pt->vcpu);
216    pt->irq = irq;
217    pt->period_cycles = (u64)period * cpu_khz / 1000000L;
218    pt->one_shot = one_shot;
219    pt->scheduled = NOW() + period;
220    pt->cb = cb;
221    pt->priv = data;
222
223    list_add(&pt->list, &v->arch.hvm_vcpu.tm_list);
224    set_timer(&pt->timer, pt->scheduled);
225}
226
227void destroy_periodic_time(struct periodic_time *pt)
228{
229    if ( pt->enabled )
230    {
231        pt->enabled = 0;
232        pt->pending_intr_nr = 0;
233        list_del(&pt->list);
234        stop_timer(&pt->timer);
235    }
236}
Note: See TracBrowser for help on using the repository browser.