direct-io.hg

changeset 13097:516e4faac066

[HVM] Sync per vcpu LAPIC timer with its TSC:
- benefits LAPIC calibration
- makes scheduling policy based on LAPIC more precise
- makes LAPIC timer code becomes simpler and cleaner after using
periodic time layer

Signed-off-by: Xiaowei Yang <xiaowei.yang@intel.com>
author kfraser@localhost.localdomain
date Wed Dec 20 10:41:33 2006 +0000 (2006-12-20)
parents 2a1edeedf28d
children 3a28be71b667
files xen/arch/x86/hvm/hvm.c xen/arch/x86/hvm/io.c xen/arch/x86/hvm/irq.c xen/arch/x86/hvm/svm/intr.c xen/arch/x86/hvm/vlapic.c xen/arch/x86/hvm/vmx/intr.c xen/arch/x86/hvm/vpt.c xen/include/asm-x86/hvm/vlapic.h xen/include/asm-x86/hvm/vpt.h
line diff
     1.1 --- a/xen/arch/x86/hvm/hvm.c	Wed Dec 20 10:37:23 2006 +0000
     1.2 +++ b/xen/arch/x86/hvm/hvm.c	Wed Dec 20 10:41:33 2006 +0000
     1.3 @@ -87,7 +87,8 @@ void hvm_migrate_timers(struct vcpu *v)
     1.4      pit_migrate_timers(v);
     1.5      rtc_migrate_timers(v);
     1.6      pmtimer_migrate_timers(v);
     1.7 -    migrate_timer(&vcpu_vlapic(v)->vlapic_timer, v->processor);
     1.8 +    if ( vcpu_vlapic(v)->pt.enabled )
     1.9 +        migrate_timer(&vcpu_vlapic(v)->pt.timer, v->processor);
    1.10  }
    1.11  
    1.12  void hvm_do_resume(struct vcpu *v)
     2.1 --- a/xen/arch/x86/hvm/io.c	Wed Dec 20 10:37:23 2006 +0000
     2.2 +++ b/xen/arch/x86/hvm/io.c	Wed Dec 20 10:41:33 2006 +0000
     2.3 @@ -689,21 +689,6 @@ static void hvm_mmio_assist(struct cpu_u
     2.4      }
     2.5  }
     2.6  
     2.7 -void hvm_interrupt_post(struct vcpu *v, int vector, int type)
     2.8 -{
     2.9 -    pt_intr_post(v, vector, type);
    2.10 -    
    2.11 -    switch(type) {
    2.12 -    case APIC_DM_EXTINT:
    2.13 -        break;
    2.14 -            
    2.15 -    default:
    2.16 -        vlapic_post_injection(v, vector, type);
    2.17 -        break;
    2.18 -    }
    2.19 -}
    2.20 -
    2.21 -
    2.22  void hvm_io_assist(struct vcpu *v)
    2.23  {
    2.24      vcpu_iodata_t *vio;
     3.1 --- a/xen/arch/x86/hvm/irq.c	Wed Dec 20 10:37:23 2006 +0000
     3.2 +++ b/xen/arch/x86/hvm/irq.c	Wed Dec 20 10:41:33 2006 +0000
     3.3 @@ -229,10 +229,9 @@ void hvm_set_callback_gsi(struct domain 
     3.4  int cpu_has_pending_irq(struct vcpu *v)
     3.5  {
     3.6      struct hvm_domain *plat = &v->domain->arch.hvm_domain;
     3.7 -    int dummy;
     3.8  
     3.9      /* APIC */
    3.10 -    if ( cpu_get_apic_interrupt(v, &dummy) != -1 )
    3.11 +    if ( vlapic_has_interrupt(v) != -1 )
    3.12          return 1;
    3.13  
    3.14      /* PIC */
    3.15 @@ -267,6 +266,9 @@ int get_intr_vector(struct vcpu* v, int 
    3.16  
    3.17  int is_irq_masked(struct vcpu *v, int irq)
    3.18  {
    3.19 +    if ( is_lvtt(v, irq) )
    3.20 +        return !is_lvtt_enabled(v);
    3.21 +
    3.22      if ( v->domain->arch.hvm_domain.irq.vpic[irq >> 3].imr & (1 << (irq & 7))
    3.23              && domain_vioapic(v->domain)->redirtbl[irq].fields.mask )
    3.24          return 1;
     4.1 --- a/xen/arch/x86/hvm/svm/intr.c	Wed Dec 20 10:37:23 2006 +0000
     4.2 +++ b/xen/arch/x86/hvm/svm/intr.c	Wed Dec 20 10:41:33 2006 +0000
     4.3 @@ -141,7 +141,7 @@ asmlinkage void svm_intr_assist(void)
     4.4          break;
     4.5      }
     4.6  
     4.7 -    hvm_interrupt_post(v, intr_vector, intr_type);
     4.8 +    pt_intr_post(v, intr_vector, intr_type);
     4.9  }
    4.10  
    4.11  /*
     5.1 --- a/xen/arch/x86/hvm/vlapic.c	Wed Dec 20 10:37:23 2006 +0000
     5.2 +++ b/xen/arch/x86/hvm/vlapic.c	Wed Dec 20 10:41:33 2006 +0000
     5.3 @@ -39,9 +39,8 @@
     5.4  #define VLAPIC_VERSION                  0x00050014
     5.5  #define VLAPIC_LVT_NUM                  6
     5.6  
     5.7 -extern u32 get_apic_bus_cycle(void);
     5.8 -
     5.9 -#define APIC_BUS_CYCLE_NS (((s_time_t)get_apic_bus_cycle()) / 1000)
    5.10 +/* vlapic's frequence is 100 MHz */
    5.11 +#define APIC_BUS_CYCLE_NS               10
    5.12  
    5.13  #define LVT_MASK \
    5.14      APIC_LVT_MASKED | APIC_SEND_PENDING | APIC_VECTOR_MASK
    5.15 @@ -122,11 +121,6 @@ static int vlapic_test_and_set_irr(int v
    5.16      return vlapic_test_and_set_vector(vector, vlapic->regs + APIC_IRR);
    5.17  }
    5.18  
    5.19 -static void vlapic_set_irr(int vector, struct vlapic *vlapic)
    5.20 -{
    5.21 -    vlapic_set_vector(vector, vlapic->regs + APIC_IRR);
    5.22 -}
    5.23 -
    5.24  static void vlapic_clear_irr(int vector, struct vlapic *vlapic)
    5.25  {
    5.26      vlapic_clear_vector(vector, vlapic->regs + APIC_IRR);
    5.27 @@ -433,46 +427,19 @@ static void vlapic_ipi(struct vlapic *vl
    5.28  
    5.29  static uint32_t vlapic_get_tmcct(struct vlapic *vlapic)
    5.30  {
    5.31 -    uint32_t counter_passed;
    5.32 -    s_time_t passed, now = NOW();
    5.33 -    uint32_t tmcct = vlapic_get_reg(vlapic, APIC_TMCCT);
    5.34 -
    5.35 -    if ( unlikely(now <= vlapic->timer_last_update) )
    5.36 -    {
    5.37 -        passed = ~0x0LL - vlapic->timer_last_update + now;
    5.38 -        HVM_DBG_LOG(DBG_LEVEL_VLAPIC, "time elapsed.");
    5.39 -    }
    5.40 -    else
    5.41 -        passed = now - vlapic->timer_last_update;
    5.42 -
    5.43 -    counter_passed = passed / (APIC_BUS_CYCLE_NS * vlapic->timer_divisor);
    5.44 -
    5.45 -    tmcct -= counter_passed;
    5.46 +    struct vcpu *v = current;
    5.47 +    uint32_t tmcct, tmict = vlapic_get_reg(vlapic, APIC_TMICT);
    5.48 +    uint64_t counter_passed;
    5.49  
    5.50 -    if ( tmcct <= 0 )
    5.51 -    {
    5.52 -        if ( unlikely(!vlapic_lvtt_period(vlapic)) )
    5.53 -        {
    5.54 -            tmcct =  0;
    5.55 -            /* FIXME: should we add interrupt here? */
    5.56 -        }
    5.57 -        else
    5.58 -        {
    5.59 -            do {
    5.60 -                tmcct += vlapic_get_reg(vlapic, APIC_TMICT);
    5.61 -            } while ( tmcct <= 0 );
    5.62 -        }
    5.63 -    }
    5.64 -
    5.65 -    vlapic->timer_last_update = now;
    5.66 -    vlapic_set_reg(vlapic, APIC_TMCCT, tmcct);
    5.67 +    counter_passed = (hvm_get_guest_time(v) - vlapic->pt.last_plt_gtime) // TSC
    5.68 +                     * 1000000000ULL / ticks_per_sec(v) // NS
    5.69 +                     / APIC_BUS_CYCLE_NS / vlapic->timer_divisor;
    5.70 +    tmcct = tmict - counter_passed;
    5.71  
    5.72      HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
    5.73 -      "timer initial count 0x%x, timer current count 0x%x, "
    5.74 -      "update 0x%016"PRIx64", now 0x%016"PRIx64", offset 0x%x.",
    5.75 -      vlapic_get_reg(vlapic, APIC_TMICT),
    5.76 -      vlapic_get_reg(vlapic, APIC_TMCCT),
    5.77 -      vlapic->timer_last_update, now, counter_passed);
    5.78 +                "timer initial count %d, timer current count %d, "
    5.79 +                "offset %"PRId64".",
    5.80 +                tmict, tmcct, counter_passed);
    5.81  
    5.82      return tmcct;
    5.83  }
    5.84 @@ -486,6 +453,9 @@ static void vlapic_set_tdcr(struct vlapi
    5.85      /* Update the demangled timer_divisor. */
    5.86      val = ((val & 3) | ((val & 8) >> 1)) + 1;
    5.87      vlapic->timer_divisor = 1 << (val & 7);
    5.88 +
    5.89 +    HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
    5.90 +                "vlapic_set_tdcr timer_divisor: %d.", vlapic->timer_divisor);
    5.91  }
    5.92  
    5.93  static void vlapic_read_aligned(struct vlapic *vlapic, unsigned int offset,
    5.94 @@ -577,6 +547,7 @@ static void vlapic_write(struct vcpu *v,
    5.95       * According to the IA32 Manual, all accesses should be 32 bits.
    5.96       * Some OSes do 8- or 16-byte accesses, however.
    5.97       */
    5.98 +    val &= 0xffffffff;
    5.99      if ( len != 4 )
   5.100      {
   5.101          unsigned int tmp;
   5.102 @@ -671,6 +642,7 @@ static void vlapic_write(struct vcpu *v,
   5.103          break;
   5.104  
   5.105      case APIC_LVTT:         /* LVT Timer Reg */
   5.106 +        vlapic->pt.irq = val & APIC_VECTOR_MASK;
   5.107      case APIC_LVTTHMR:      /* LVT Thermal Monitor */
   5.108      case APIC_LVTPC:        /* LVT Performance Counter */
   5.109      case APIC_LVT0:         /* LVT LINT0 Reg */
   5.110 @@ -684,25 +656,16 @@ static void vlapic_write(struct vcpu *v,
   5.111  
   5.112      case APIC_TMICT:
   5.113      {
   5.114 -        s_time_t now = NOW(), offset;
   5.115 -
   5.116 -        stop_timer(&vlapic->vlapic_timer);
   5.117 +        uint64_t period = APIC_BUS_CYCLE_NS * (uint32_t)val * vlapic->timer_divisor;
   5.118  
   5.119          vlapic_set_reg(vlapic, APIC_TMICT, val);
   5.120 -        vlapic_set_reg(vlapic, APIC_TMCCT, val);
   5.121 -        vlapic->timer_last_update = now;
   5.122 -
   5.123 -        offset = APIC_BUS_CYCLE_NS * vlapic->timer_divisor * val;
   5.124 -
   5.125 -        set_timer(&vlapic->vlapic_timer, now + offset);
   5.126 +        create_periodic_time(&vlapic->pt, period, vlapic->pt.irq,
   5.127 +                             vlapic_lvtt_period(vlapic), NULL, vlapic);
   5.128  
   5.129          HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
   5.130 -                    "bus cycle is %"PRId64"ns, now 0x%016"PRIx64", "
   5.131 -                    "timer initial count 0x%x, offset 0x%016"PRIx64", "
   5.132 -                    "expire @ 0x%016"PRIx64".",
   5.133 -                    APIC_BUS_CYCLE_NS, now,
   5.134 -                    vlapic_get_reg(vlapic, APIC_TMICT),
   5.135 -                    offset, now + offset);
   5.136 +                    "bus cycle is %uns, "
   5.137 +                    "initial count %lu, period %"PRIu64"ns",
   5.138 +                    APIC_BUS_CYCLE_NS, val, period);
   5.139      }
   5.140      break;
   5.141  
   5.142 @@ -753,48 +716,6 @@ void vlapic_msr_set(struct vlapic *vlapi
   5.143                  "apic base msr is 0x%016"PRIx64".", vlapic->apic_base_msr);
   5.144  }
   5.145  
   5.146 -void vlapic_timer_fn(void *data)
   5.147 -{
   5.148 -    struct vlapic *vlapic = data;
   5.149 -    uint32_t timer_vector;
   5.150 -    s_time_t now;
   5.151 -
   5.152 -    if ( unlikely(!vlapic_enabled(vlapic) ||
   5.153 -                  !vlapic_lvt_enabled(vlapic, APIC_LVTT)) )
   5.154 -        return;
   5.155 -
   5.156 -    timer_vector = vlapic_lvt_vector(vlapic, APIC_LVTT);
   5.157 -    now = NOW();
   5.158 -
   5.159 -    vlapic->timer_last_update = now;
   5.160 -
   5.161 -    if ( vlapic_test_and_set_irr(timer_vector, vlapic) )
   5.162 -        vlapic->timer_pending_count++;
   5.163 -
   5.164 -    if ( vlapic_lvtt_period(vlapic) )
   5.165 -    {
   5.166 -        s_time_t offset;
   5.167 -        uint32_t tmict = vlapic_get_reg(vlapic, APIC_TMICT);
   5.168 -
   5.169 -        vlapic_set_reg(vlapic, APIC_TMCCT, tmict);
   5.170 -
   5.171 -        offset = APIC_BUS_CYCLE_NS * vlapic->timer_divisor * tmict;
   5.172 -
   5.173 -        set_timer(&vlapic->vlapic_timer, now + offset);
   5.174 -    }
   5.175 -    else
   5.176 -        vlapic_set_reg(vlapic, APIC_TMCCT, 0);
   5.177 -
   5.178 -    vcpu_kick(vlapic_vcpu(vlapic));
   5.179 -
   5.180 -    HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER,
   5.181 -                "now 0x%016"PRIx64", expire @ 0x%016"PRIx64", "
   5.182 -                "timer initial count 0x%x, timer current count 0x%x.",
   5.183 -                now, vlapic->vlapic_timer.expires,
   5.184 -                vlapic_get_reg(vlapic, APIC_TMICT),
   5.185 -                vlapic_get_reg(vlapic, APIC_TMCCT));
   5.186 -}
   5.187 -
   5.188  int vlapic_accept_pic_intr(struct vcpu *v)
   5.189  {
   5.190      struct vlapic *vlapic = vcpu_vlapic(v);
   5.191 @@ -809,7 +730,7 @@ int vlapic_accept_pic_intr(struct vcpu *
   5.192               vlapic_hw_disabled(vlapic)));
   5.193  }
   5.194  
   5.195 -int cpu_get_apic_interrupt(struct vcpu *v, int *mode)
   5.196 +int vlapic_has_interrupt(struct vcpu *v)
   5.197  {
   5.198      struct vlapic *vlapic = vcpu_vlapic(v);
   5.199      int highest_irr;
   5.200 @@ -822,42 +743,22 @@ int cpu_get_apic_interrupt(struct vcpu *
   5.201           ((highest_irr & 0xF0) <= vlapic_get_ppr(vlapic)) )
   5.202          return -1;
   5.203  
   5.204 -    *mode = APIC_DM_FIXED;
   5.205      return highest_irr;
   5.206  }
   5.207  
   5.208 -void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode)
   5.209 +int cpu_get_apic_interrupt(struct vcpu *v, int *mode)
   5.210  {
   5.211 +    int vector = vlapic_has_interrupt(v);
   5.212      struct vlapic *vlapic = vcpu_vlapic(v);
   5.213  
   5.214 -    switch ( deliver_mode )
   5.215 -    {
   5.216 -    case APIC_DM_FIXED:
   5.217 -    case APIC_DM_LOWEST:
   5.218 -        vlapic_set_vector(vector, vlapic->regs + APIC_ISR);
   5.219 -        vlapic_clear_irr(vector, vlapic);
   5.220 -        if ( (vector == vlapic_lvt_vector(vlapic, APIC_LVTT)) &&
   5.221 -             (vlapic->timer_pending_count != 0) )
   5.222 -        {
   5.223 -            vlapic->timer_pending_count--;
   5.224 -            vlapic_set_irr(vector, vlapic);
   5.225 -        }
   5.226 -        break;
   5.227 +    if ( vector == -1 )
   5.228 +        return -1;
   5.229 + 
   5.230 +    vlapic_set_vector(vector, vlapic->regs + APIC_ISR);
   5.231 +    vlapic_clear_irr(vector, vlapic);
   5.232  
   5.233 -    case APIC_DM_REMRD:
   5.234 -        gdprintk(XENLOG_WARNING, "Ignoring delivery mode 3.\n");
   5.235 -        break;
   5.236 -
   5.237 -    case APIC_DM_SMI:
   5.238 -    case APIC_DM_NMI:
   5.239 -    case APIC_DM_INIT:
   5.240 -    case APIC_DM_STARTUP:
   5.241 -        break;
   5.242 -
   5.243 -    default:
   5.244 -        gdprintk(XENLOG_WARNING, "Invalid delivery mode\n");
   5.245 -        break;
   5.246 -    }
   5.247 +    *mode = APIC_DM_FIXED;
   5.248 +    return vector;
   5.249  }
   5.250  
   5.251  /* Reset the VLPAIC back to its power-on/reset state. */
   5.252 @@ -918,8 +819,7 @@ int vlapic_init(struct vcpu *v)
   5.253      if ( v->vcpu_id == 0 )
   5.254          vlapic->apic_base_msr |= MSR_IA32_APICBASE_BSP;
   5.255  
   5.256 -    init_timer(&vlapic->vlapic_timer,
   5.257 -                  vlapic_timer_fn, vlapic, v->processor);
   5.258 +    init_timer(&vlapic->pt.timer, pt_timer_fn, &vlapic->pt, v->processor);
   5.259  
   5.260      return 0;
   5.261  }
   5.262 @@ -928,7 +828,22 @@ void vlapic_destroy(struct vcpu *v)
   5.263  {
   5.264      struct vlapic *vlapic = vcpu_vlapic(v);
   5.265  
   5.266 -    kill_timer(&vlapic->vlapic_timer);
   5.267 +    kill_timer(&vlapic->pt.timer);
   5.268      unmap_domain_page_global(vlapic->regs);
   5.269      free_domheap_page(vlapic->regs_page);
   5.270  }
   5.271 +
   5.272 +int is_lvtt(struct vcpu *v, int vector)
   5.273 +{
   5.274 +    return vcpu_vlapic(v)->pt.enabled &&
   5.275 +           vector == vlapic_lvt_vector(vcpu_vlapic(v), APIC_LVTT);
   5.276 +}
   5.277 +
   5.278 +int is_lvtt_enabled(struct vcpu *v)
   5.279 +{
   5.280 +    if ( unlikely(!vlapic_enabled(vcpu_vlapic(v))) ||
   5.281 +            !vlapic_lvt_enabled(vcpu_vlapic(v), APIC_LVTT)) 
   5.282 +        return 0;
   5.283 +
   5.284 +    return 1;
   5.285 +}
     6.1 --- a/xen/arch/x86/hvm/vmx/intr.c	Wed Dec 20 10:37:23 2006 +0000
     6.2 +++ b/xen/arch/x86/hvm/vmx/intr.c	Wed Dec 20 10:41:33 2006 +0000
     6.3 @@ -175,8 +175,8 @@ asmlinkage void vmx_intr_assist(void)
     6.4          BUG();
     6.5          break;
     6.6      }
     6.7 -    
     6.8 -    hvm_interrupt_post(v, highest_vector, intr_type);
     6.9 +
    6.10 +    pt_intr_post(v, highest_vector, intr_type);
    6.11  }
    6.12  
    6.13  /*
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/xen/arch/x86/hvm/vpt.c	Wed Dec 20 10:41:33 2006 +0000
     7.3 @@ -0,0 +1,231 @@
     7.4 +/*
     7.5 + * vpt.c: Virtual Platform Timer
     7.6 + *
     7.7 + * Copyright (c) 2006, Xiaowei Yang, Intel Corporation.
     7.8 + *
     7.9 + * This program is free software; you can redistribute it and/or modify it
    7.10 + * under the terms and conditions of the GNU General Public License,
    7.11 + * version 2, as published by the Free Software Foundation.
    7.12 + *
    7.13 + * This program is distributed in the hope it will be useful, but WITHOUT
    7.14 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    7.15 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
    7.16 + * more details.
    7.17 + *
    7.18 + * You should have received a copy of the GNU General Public License along with
    7.19 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
    7.20 + * Place - Suite 330, Boston, MA 02111-1307 USA.
    7.21 + *
    7.22 + */
    7.23 +#include <xen/time.h>
    7.24 +#include <asm/hvm/support.h>
    7.25 +#include <asm/hvm/vpt.h>
    7.26 +#include <asm/event.h>
    7.27 +
    7.28 +static __inline__ void missed_ticks(struct periodic_time *pt)
    7.29 +{
    7.30 +    s_time_t missed_ticks;
    7.31 +
    7.32 +    missed_ticks = NOW() - pt->scheduled;
    7.33 +    if ( missed_ticks > 0 ) 
    7.34 +    {
    7.35 +        missed_ticks = missed_ticks / (s_time_t) pt->period + 1;
    7.36 +        if ( missed_ticks > 1000 )
    7.37 +        {
    7.38 +            /* TODO: Adjust guest time together */
    7.39 +            pt->pending_intr_nr++;
    7.40 +        }
    7.41 +        else
    7.42 +        {
    7.43 +            pt->pending_intr_nr += missed_ticks;
    7.44 +        }
    7.45 +        pt->scheduled += missed_ticks * pt->period;
    7.46 +    }
    7.47 +}
    7.48 +
    7.49 +void pt_freeze_time(struct vcpu *v)
    7.50 +{
    7.51 +    struct list_head *head = &v->arch.hvm_vcpu.tm_list;
    7.52 +    struct list_head *list;
    7.53 +    struct periodic_time *pt;
    7.54 +
    7.55 +    if ( test_bit(_VCPUF_blocked, &v->vcpu_flags) )
    7.56 +        return;
    7.57 +
    7.58 +    v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v);
    7.59 +
    7.60 +    list_for_each( list, head )
    7.61 +    {
    7.62 +        pt = list_entry(list, struct periodic_time, list);
    7.63 +        stop_timer(&pt->timer);
    7.64 +    }
    7.65 +}
    7.66 +
    7.67 +void pt_thaw_time(struct vcpu *v)
    7.68 +{
    7.69 +    struct list_head *head = &v->arch.hvm_vcpu.tm_list;
    7.70 +    struct list_head *list;
    7.71 +    struct periodic_time *pt;
    7.72 +
    7.73 +    if ( v->arch.hvm_vcpu.guest_time )
    7.74 +    {
    7.75 +        hvm_set_guest_time(v, v->arch.hvm_vcpu.guest_time);
    7.76 +        v->arch.hvm_vcpu.guest_time = 0;
    7.77 +
    7.78 +        list_for_each( list, head )
    7.79 +        {
    7.80 +            pt = list_entry(list, struct periodic_time, list);
    7.81 +            missed_ticks(pt);
    7.82 +            set_timer(&pt->timer, pt->scheduled);
    7.83 +        }
    7.84 +    }
    7.85 +}
    7.86 +
    7.87 +/* Hook function for the platform periodic time */
    7.88 +void pt_timer_fn(void *data)
    7.89 +{
    7.90 +    struct periodic_time *pt = data;
    7.91 +
    7.92 +    pt->pending_intr_nr++;
    7.93 +    pt->scheduled += pt->period;
    7.94 +
    7.95 +    missed_ticks(pt);
    7.96 +
    7.97 +    if ( !pt->one_shot )
    7.98 +        set_timer(&pt->timer, pt->scheduled);
    7.99 +
   7.100 +    vcpu_kick(pt->vcpu);
   7.101 +}
   7.102 +
   7.103 +void pt_update_irq(struct vcpu *v)
   7.104 +{
   7.105 +    struct list_head *head = &v->arch.hvm_vcpu.tm_list;
   7.106 +    struct list_head *list;
   7.107 +    struct periodic_time *pt;
   7.108 +    uint64_t max_lag = -1ULL;
   7.109 +    int irq = -1;
   7.110 +
   7.111 +    list_for_each( list, head )
   7.112 +    {
   7.113 +        pt = list_entry(list, struct periodic_time, list);
   7.114 +        if ( !is_irq_masked(v, pt->irq) && pt->pending_intr_nr 
   7.115 +                && pt->last_plt_gtime + pt->period < max_lag )
   7.116 +        {
   7.117 +            max_lag = pt->last_plt_gtime + pt->period;
   7.118 +            irq = pt->irq;
   7.119 +        }
   7.120 +    }
   7.121 +
   7.122 +    if ( is_lvtt(v, irq) )
   7.123 +        vlapic_set_irq(vcpu_vlapic(v), irq, 0);
   7.124 +    else if ( irq >= 0 )
   7.125 +    {
   7.126 +        hvm_isa_irq_deassert(v->domain, irq);
   7.127 +        hvm_isa_irq_assert(v->domain, irq);
   7.128 +    }
   7.129 +}
   7.130 +
   7.131 +struct periodic_time *is_pt_irq(struct vcpu *v, int vector, int type)
   7.132 +{
   7.133 +    struct list_head *head = &v->arch.hvm_vcpu.tm_list;
   7.134 +    struct list_head *list;
   7.135 +    struct periodic_time *pt;
   7.136 +    struct RTCState *rtc = &v->domain->arch.hvm_domain.pl_time.vrtc;
   7.137 +    int vec;
   7.138 +
   7.139 +    list_for_each( list, head )
   7.140 +    {
   7.141 +        pt = list_entry(list, struct periodic_time, list);
   7.142 +        if ( !pt->pending_intr_nr )
   7.143 +            continue;
   7.144 +
   7.145 +        if ( is_lvtt(v, pt->irq) )
   7.146 +        {
   7.147 +            if (pt->irq == vector)
   7.148 +                return pt;
   7.149 +            else
   7.150 +                continue;
   7.151 +        }
   7.152 +
   7.153 +        vec = get_intr_vector(v, pt->irq, type);
   7.154 +
   7.155 +        /* RTC irq need special care */
   7.156 +        if ( vector != vec || (pt->irq == 8 && !is_rtc_periodic_irq(rtc)) )
   7.157 +            continue;
   7.158 +
   7.159 +        return pt;
   7.160 +    }
   7.161 +
   7.162 +    return NULL;
   7.163 +}
   7.164 +
   7.165 +void pt_intr_post(struct vcpu *v, int vector, int type)
   7.166 +{
   7.167 +    struct periodic_time *pt = is_pt_irq(v, vector, type);
   7.168 +
   7.169 +    if (pt == NULL)
   7.170 +        return;
   7.171 +
   7.172 +    pt->pending_intr_nr--;
   7.173 +    pt->last_plt_gtime += pt->period_cycles;
   7.174 +    hvm_set_guest_time(pt->vcpu, pt->last_plt_gtime);
   7.175 +
   7.176 +    if (pt->cb)
   7.177 +        pt->cb(pt->vcpu, pt->priv);
   7.178 +}
   7.179 +
   7.180 +/* If pt is enabled, discard pending intr */
   7.181 +void pt_reset(struct vcpu *v)
   7.182 +{
   7.183 +    struct list_head *head = &v->arch.hvm_vcpu.tm_list;
   7.184 +    struct list_head *list;
   7.185 +    struct periodic_time *pt;
   7.186 +
   7.187 +    list_for_each( list, head )
   7.188 +    {
   7.189 +	pt = list_entry(list, struct periodic_time, list);
   7.190 +	if ( pt->enabled )
   7.191 +        {
   7.192 +            pt->pending_intr_nr = 0;
   7.193 +            pt->last_plt_gtime = hvm_get_guest_time(pt->vcpu);
   7.194 +            pt->scheduled = NOW() + pt->period;
   7.195 +            set_timer(&pt->timer, pt->scheduled);
   7.196 +        }
   7.197 +    }
   7.198 +}
   7.199 +
   7.200 +void create_periodic_time(struct periodic_time *pt, uint64_t period,
   7.201 +                          uint8_t irq, char one_shot, time_cb *cb, void *data)
   7.202 +{
   7.203 +    destroy_periodic_time(pt);
   7.204 +
   7.205 +    pt->enabled = 1;
   7.206 +    if (period < 900000) /* < 0.9 ms */
   7.207 +    {
   7.208 +        printk("HVM_PlatformTime: program too small period %"PRIu64"\n", period);
   7.209 +        period = 900000; /* force to 0.9ms */
   7.210 +    }
   7.211 +    pt->period = period;
   7.212 +    pt->vcpu = current;
   7.213 +    pt->last_plt_gtime = hvm_get_guest_time(pt->vcpu);
   7.214 +    pt->irq = irq;
   7.215 +    pt->period_cycles = (u64)period * cpu_khz / 1000000L;
   7.216 +    pt->one_shot = one_shot;
   7.217 +    pt->scheduled = NOW() + period;
   7.218 +    pt->cb = cb;
   7.219 +    pt->priv = data;
   7.220 +
   7.221 +    list_add(&pt->list, &current->arch.hvm_vcpu.tm_list);
   7.222 +    set_timer(&pt->timer, pt->scheduled);
   7.223 +}
   7.224 +
   7.225 +void destroy_periodic_time(struct periodic_time *pt)
   7.226 +{
   7.227 +    if ( pt->enabled )
   7.228 +    {
   7.229 +        pt->enabled = 0;
   7.230 +        pt->pending_intr_nr = 0;
   7.231 +        list_del(&pt->list);
   7.232 +        stop_timer(&pt->timer);
   7.233 +    }
   7.234 +}
     8.1 --- a/xen/include/asm-x86/hvm/vlapic.h	Wed Dec 20 10:37:23 2006 +0000
     8.2 +++ b/xen/include/asm-x86/hvm/vlapic.h	Wed Dec 20 10:41:33 2006 +0000
     8.3 @@ -23,6 +23,7 @@
     8.4  
     8.5  #include <asm/msr.h>
     8.6  #include <public/hvm/ioreq.h>
     8.7 +#include <asm/hvm/vpt.h>
     8.8  
     8.9  #define MAX_VECTOR      256
    8.10  
    8.11 @@ -49,14 +50,14 @@
    8.12  #define vlapic_enabled(vlapic)      (!vlapic_disabled(vlapic))
    8.13  
    8.14  struct vlapic {
    8.15 -    uint64_t           apic_base_msr;
    8.16 -    uint32_t           disabled; /* VLAPIC_xx_DISABLED */
    8.17 -    uint32_t           timer_divisor;
    8.18 -    struct timer       vlapic_timer;
    8.19 -    int                timer_pending_count;
    8.20 -    s_time_t           timer_last_update;
    8.21 -    struct page_info   *regs_page;
    8.22 -    void               *regs;
    8.23 +    uint64_t             apic_base_msr;
    8.24 +    uint32_t             disabled; /* VLAPIC_xx_DISABLED */
    8.25 +    uint32_t             timer_divisor;
    8.26 +    struct periodic_time pt;
    8.27 +    int                  timer_pending_count;
    8.28 +    s_time_t             timer_last_update;
    8.29 +    struct page_info     *regs_page;
    8.30 +    void                 *regs;
    8.31  };
    8.32  
    8.33  static inline uint32_t vlapic_get_reg(struct vlapic *vlapic, uint32_t reg)
    8.34 @@ -70,13 +71,11 @@ static inline void vlapic_set_reg(
    8.35      *((uint32_t *)(vlapic->regs + reg)) = val;
    8.36  }
    8.37  
    8.38 -
    8.39  int vlapic_set_irq(struct vlapic *vlapic, uint8_t vec, uint8_t trig);
    8.40  
    8.41 -void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode);
    8.42 -
    8.43  int vlapic_find_highest_irr(struct vlapic *vlapic);
    8.44  
    8.45 +int vlapic_has_interrupt(struct vcpu *v);
    8.46  int cpu_get_apic_interrupt(struct vcpu *v, int *mode);
    8.47  
    8.48  int  vlapic_init(struct vcpu *v);
    8.49 @@ -91,4 +90,7 @@ struct vlapic *apic_round_robin(
    8.50  
    8.51  int vlapic_match_logical_addr(struct vlapic *vlapic, uint8_t mda);
    8.52  
    8.53 +int is_lvtt(struct vcpu *v, int vector);
    8.54 +int is_lvtt_enabled(struct vcpu *v);
    8.55 +
    8.56  #endif /* __ASM_X86_HVM_VLAPIC_H__ */
     9.1 --- a/xen/include/asm-x86/hvm/vpt.h	Wed Dec 20 10:37:23 2006 +0000
     9.2 +++ b/xen/include/asm-x86/hvm/vpt.h	Wed Dec 20 10:41:33 2006 +0000
     9.3 @@ -42,10 +42,10 @@ struct periodic_time {
     9.4      struct list_head list;
     9.5      char enabled;
     9.6      char one_shot;              /* one shot time */
     9.7 -    int irq;
     9.8 +    u8 irq;
     9.9      struct vcpu *vcpu;          /* vcpu timer interrupt delivers to */
    9.10      u32 pending_intr_nr;        /* the couner for pending timer interrupts */
    9.11 -    u32 period;                 /* frequency in ns */
    9.12 +    u64 period;                 /* frequency in ns */
    9.13      u64 period_cycles;          /* frequency in cpu cycles */
    9.14      s_time_t scheduled;         /* scheduled timer interrupt */
    9.15      u64 last_plt_gtime;         /* platform time when last IRQ is injected */
    9.16 @@ -115,8 +115,8 @@ void pt_update_irq(struct vcpu *v);
    9.17  struct periodic_time *is_pt_irq(struct vcpu *v, int vector, int type);
    9.18  void pt_intr_post(struct vcpu *v, int vector, int type);
    9.19  void pt_reset(struct vcpu *v);
    9.20 -void create_periodic_time(struct periodic_time *pt, u32 period, char irq, 
    9.21 -                          char one_shot, time_cb *cb, void *data);
    9.22 +void create_periodic_time(struct periodic_time *pt, uint64_t period,
    9.23 +                          uint8_t irq, char one_shot, time_cb *cb, void *data);
    9.24  void destroy_periodic_time(struct periodic_time *pt);
    9.25  
    9.26  int pv_pit_handler(int port, int data, int write);