direct-io.hg

changeset 12470:5f7b5e5ca14b

[HVM] Decouple the RTC from the PIT periodic timer
Signed-off-by: Tim Deegan <Tim.Deegan@xensource.com>
author Tim Deegan <Tim.Deegan@xensource.com>
date Thu Nov 16 17:07:23 2006 +0000 (2006-11-16)
parents 992723a0ceb1
children cf98903ebb22
files xen/arch/x86/hvm/hvm.c xen/arch/x86/hvm/i8259.c xen/arch/x86/hvm/rtc.c xen/arch/x86/hvm/svm/svm.c xen/arch/x86/hvm/vioapic.c xen/arch/x86/hvm/vmx/vmcs.c xen/arch/x86/hvm/vmx/vmx.c xen/include/asm-x86/hvm/hvm.h xen/include/asm-x86/hvm/vmx/vmx.h xen/include/asm-x86/hvm/vpt.h
line diff
     1.1 --- a/xen/arch/x86/hvm/hvm.c	Thu Nov 16 15:20:05 2006 +0000
     1.2 +++ b/xen/arch/x86/hvm/hvm.c	Thu Nov 16 17:07:23 2006 +0000
     1.3 @@ -74,6 +74,20 @@ void hvm_set_guest_time(struct vcpu *v, 
     1.4      hvm_funcs.set_tsc_offset(v, v->arch.hvm_vcpu.cache_tsc_offset);
     1.5  }
     1.6  
     1.7 +void hvm_migrate_timers(struct vcpu *v)
     1.8 +{
     1.9 +    struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
    1.10 +    struct PMTState *vpmt = &v->domain->arch.hvm_domain.pl_time.vpmt;
    1.11 +
    1.12 +    if ( pt->enabled )
    1.13 +    {
    1.14 +        migrate_timer(&pt->timer, v->processor);
    1.15 +    }
    1.16 +    migrate_timer(&vcpu_vlapic(v)->vlapic_timer, v->processor);
    1.17 +    migrate_timer(&vpmt->timer, v->processor);
    1.18 +    rtc_migrate_timers(v);
    1.19 +}
    1.20 +
    1.21  void hvm_do_resume(struct vcpu *v)
    1.22  {
    1.23      ioreq_t *p;
    1.24 @@ -92,6 +106,9 @@ void hvm_do_resume(struct vcpu *v)
    1.25          pickup_deactive_ticks(pt);
    1.26      }
    1.27  
    1.28 +    /* Re-enable the RTC timer if needed */
    1.29 +    rtc_thaw(v);
    1.30 +
    1.31      /* NB. Optimised for common case (p->state == STATE_IOREQ_NONE). */
    1.32      p = &get_vio(v->domain, v->vcpu_id)->vp_ioreq;
    1.33      while ( p->state != STATE_IOREQ_NONE )
     2.1 --- a/xen/arch/x86/hvm/i8259.c	Thu Nov 16 15:20:05 2006 +0000
     2.2 +++ b/xen/arch/x86/hvm/i8259.c	Thu Nov 16 17:07:23 2006 +0000
     2.3 @@ -536,8 +536,6 @@ int is_periodic_irq(struct vcpu *v, int 
     2.4      int vec;
     2.5      struct periodic_time *pt =
     2.6          &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
     2.7 -    struct RTCState *vrtc =
     2.8 -        &(v->domain->arch.hvm_domain.pl_time.vrtc);
     2.9  
    2.10      if (pt->irq == 0) { /* Is it pit irq? */
    2.11          if (type == APIC_DM_EXTINT)
    2.12 @@ -549,16 +547,6 @@ int is_periodic_irq(struct vcpu *v, int 
    2.13              return 1;
    2.14      }
    2.15  
    2.16 -    if (pt->irq == 8) { /* Or rtc irq? */
    2.17 -        if (type == APIC_DM_EXTINT)
    2.18 -            vec = domain_vpic(v->domain)->pics[1].irq_base;
    2.19 -        else
    2.20 -            vec = domain_vioapic(v->domain)->redirtbl[8].fields.vector;
    2.21 -
    2.22 -        if (irq == vec)
    2.23 -            return is_rtc_periodic_irq(vrtc);
    2.24 -    }
    2.25 -
    2.26      return 0;
    2.27  }
    2.28  
     3.1 --- a/xen/arch/x86/hvm/rtc.c	Thu Nov 16 15:20:05 2006 +0000
     3.2 +++ b/xen/arch/x86/hvm/rtc.c	Thu Nov 16 17:07:23 2006 +0000
     3.3 @@ -30,40 +30,43 @@
     3.4  
     3.5  /* #define DEBUG_RTC */
     3.6  
     3.7 -void rtc_periodic_cb(struct vcpu *v, void *opaque)
     3.8 +/* Callback that fires the RTC's periodic interrupt */
     3.9 +void rtc_pie_callback(void *opaque)
    3.10  {
    3.11      RTCState *s = opaque;
    3.12 -    s->cmos_data[RTC_REG_C] |= 0xc0;
    3.13 +    struct hvm_domain *plat = &s->vcpu->domain->arch.hvm_domain;
    3.14 +    struct vpic       *pic  = &plat->vpic;
    3.15 +    /* Record that we have fired */
    3.16 +    s->cmos_data[RTC_REG_C] |= (RTC_IRQF|RTC_PF); /* 0xc0 */
    3.17 +    /* Fire */
    3.18 +    pic_set_irq(pic, s->irq, 1);
    3.19 +    /* Remember to fire again */
    3.20 +    s->next_pie = NOW() + s->period;
    3.21 +    set_timer(&s->pie_timer, s->next_pie);
    3.22  }
    3.23  
    3.24 -int is_rtc_periodic_irq(void *opaque)
    3.25 -{
    3.26 -    RTCState *s = opaque;
    3.27 -    return !(s->cmos_data[RTC_REG_C] & RTC_AF || 
    3.28 -           s->cmos_data[RTC_REG_C] & RTC_UF);
    3.29 -}
    3.30 -
    3.31 -static void rtc_timer_update(RTCState *s, int64_t current_time)
    3.32 +/* Enable/configure/disable the periodic timer based on the RTC_PIE and
    3.33 + * RTC_RATE_SELECT settings */
    3.34 +static void rtc_timer_update(RTCState *s)
    3.35  {
    3.36      int period_code; 
    3.37      int period;
    3.38  
    3.39 -    period_code = s->cmos_data[RTC_REG_A] & 0x0f;
    3.40 +    period_code = s->cmos_data[RTC_REG_A] & RTC_RATE_SELECT;
    3.41      if (period_code != 0 && (s->cmos_data[RTC_REG_B] & RTC_PIE)) {
    3.42          if (period_code <= 2)
    3.43              period_code += 7;
    3.44          
    3.45          period = 1 << (period_code - 1); /* period in 32 Khz cycles */
    3.46          period = DIV_ROUND((period * 1000000000ULL), 32768); /* period in ns */
    3.47 -
    3.48 +        s->period = period;
    3.49  #ifdef DEBUG_RTC
    3.50          printk("HVM_RTC: period = %uns\n", period);
    3.51  #endif
    3.52 -
    3.53 -        s->pt = create_periodic_time(period, RTC_IRQ, 0, rtc_periodic_cb, s);
    3.54 -    } else if (s->pt) {
    3.55 -        destroy_periodic_time(s->pt);
    3.56 -        s->pt = NULL;
    3.57 +        s->next_pie = NOW() + s->period;
    3.58 +        set_timer(&s->pie_timer, s->next_pie);
    3.59 +    } else {
    3.60 +        stop_timer(&s->pie_timer);
    3.61      }
    3.62  }
    3.63  
    3.64 @@ -105,7 +108,7 @@ static int rtc_ioport_write(void *opaque
    3.65              /* UIP bit is read only */
    3.66              s->cmos_data[RTC_REG_A] = (data & ~RTC_UIP) |
    3.67                  (s->cmos_data[RTC_REG_A] & RTC_UIP);
    3.68 -            rtc_timer_update(s, hvm_get_clock(s->vcpu));
    3.69 +            rtc_timer_update(s);
    3.70              break;
    3.71          case RTC_REG_B:
    3.72              if (data & RTC_SET) {
    3.73 @@ -119,14 +122,14 @@ static int rtc_ioport_write(void *opaque
    3.74                  }
    3.75              }
    3.76              s->cmos_data[RTC_REG_B] = data;
    3.77 -            rtc_timer_update(s, hvm_get_clock(s->vcpu));
    3.78 +            rtc_timer_update(s);
    3.79              break;
    3.80          case RTC_REG_C:
    3.81          case RTC_REG_D:
    3.82              /* cannot write to them */
    3.83              break;
    3.84 +        }
    3.85          return 1;
    3.86 -        }
    3.87      }
    3.88      return 0;
    3.89  }
    3.90 @@ -172,7 +175,7 @@ static void rtc_copy_date(RTCState *s)
    3.91  
    3.92      s->cmos_data[RTC_SECONDS] = to_bcd(s, tm->tm_sec);
    3.93      s->cmos_data[RTC_MINUTES] = to_bcd(s, tm->tm_min);
    3.94 -    if (s->cmos_data[RTC_REG_B] & 0x02) {
    3.95 +    if (s->cmos_data[RTC_REG_B] & RTC_24H) {
    3.96          /* 24 hour format */
    3.97          s->cmos_data[RTC_HOURS] = to_bcd(s, tm->tm_hour);
    3.98      } else {
    3.99 @@ -245,7 +248,7 @@ static void rtc_update_second(void *opaq
   3.100      RTCState *s = opaque;
   3.101  
   3.102      /* if the oscillator is not in normal operation, we do not update */
   3.103 -    if ((s->cmos_data[RTC_REG_A] & 0x70) != 0x20) {
   3.104 +    if ((s->cmos_data[RTC_REG_A] & RTC_DIV_CTL) != RTC_REF_CLCK_32KHZ) {
   3.105          s->next_second_time += 1000000000ULL;
   3.106          set_timer(&s->second_timer, s->next_second_time);
   3.107      } else {
   3.108 @@ -361,22 +364,48 @@ static int handle_rtc_io(ioreq_t *p)
   3.109      return 0;
   3.110  }
   3.111  
   3.112 +/* Stop the periodic interrupts from this RTC */
   3.113 +void rtc_freeze(struct vcpu *v)
   3.114 +{
   3.115 +    RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc;
   3.116 +    stop_timer(&s->pie_timer);
   3.117 +}
   3.118 +
   3.119 +/* Start them again */
   3.120 +void rtc_thaw(struct vcpu *v)
   3.121 +{
   3.122 +    RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc;
   3.123 +    if ( (s->cmos_data[RTC_REG_A] & RTC_RATE_SELECT) /* Period is not zero */
   3.124 +         && (s->cmos_data[RTC_REG_B] & RTC_PIE) ) 
   3.125 +        set_timer(&s->pie_timer, s->next_pie);
   3.126 +}
   3.127 +
   3.128 +/* Move the RTC timers on to this vcpu's current cpu */
   3.129 +void rtc_migrate_timers(struct vcpu *v)
   3.130 +{
   3.131 +    RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc;
   3.132 +    migrate_timer(&s->second_timer, v->processor);
   3.133 +    migrate_timer(&s->second_timer2, v->processor);
   3.134 +    migrate_timer(&s->pie_timer, v->processor);
   3.135 +}
   3.136 +
   3.137  void rtc_init(struct vcpu *v, int base, int irq)
   3.138  {
   3.139      RTCState *s = &v->domain->arch.hvm_domain.pl_time.vrtc;
   3.140  
   3.141      s->vcpu = v;
   3.142      s->irq = irq;
   3.143 -    s->cmos_data[RTC_REG_A] = 0x26;
   3.144 -    s->cmos_data[RTC_REG_B] = 0x02;
   3.145 -    s->cmos_data[RTC_REG_C] = 0x00;
   3.146 -    s->cmos_data[RTC_REG_D] = 0x80;
   3.147 +    s->cmos_data[RTC_REG_A] = RTC_REF_CLCK_32KHZ | 6; /* ~1kHz */
   3.148 +    s->cmos_data[RTC_REG_B] = RTC_24H;
   3.149 +    s->cmos_data[RTC_REG_C] = 0;
   3.150 +    s->cmos_data[RTC_REG_D] = RTC_VRT;
   3.151  
   3.152      s->current_tm = gmtime(get_localtime(v->domain));
   3.153      rtc_copy_date(s);
   3.154  
   3.155      init_timer(&s->second_timer, rtc_update_second, s, v->processor);
   3.156      init_timer(&s->second_timer2, rtc_update_second2, s, v->processor);
   3.157 +    init_timer(&s->pie_timer, rtc_pie_callback, s, v->processor);
   3.158  
   3.159      s->next_second_time = NOW() + 1000000000ULL;
   3.160      set_timer(&s->second_timer2, s->next_second_time);
   3.161 @@ -390,4 +419,5 @@ void rtc_deinit(struct domain *d)
   3.162  
   3.163      kill_timer(&s->second_timer);
   3.164      kill_timer(&s->second_timer2);
   3.165 +    kill_timer(&s->pie_timer);
   3.166  }
     4.1 --- a/xen/arch/x86/hvm/svm/svm.c	Thu Nov 16 15:20:05 2006 +0000
     4.2 +++ b/xen/arch/x86/hvm/svm/svm.c	Thu Nov 16 17:07:23 2006 +0000
     4.3 @@ -723,7 +723,10 @@ static void svm_freeze_time(struct vcpu 
     4.4              && !v->arch.hvm_vcpu.guest_time ) {
     4.5          v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v);
     4.6          if ( test_bit(_VCPUF_blocked, &v->vcpu_flags) )
     4.7 +        {
     4.8              stop_timer(&pt->timer);
     4.9 +            rtc_freeze(v);
    4.10 +        }
    4.11      }
    4.12  }
    4.13  
    4.14 @@ -850,24 +853,6 @@ int start_svm(void)
    4.15  }
    4.16  
    4.17  
    4.18 -static void svm_migrate_timers(struct vcpu *v)
    4.19 -{
    4.20 -    struct periodic_time *pt = 
    4.21 -        &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
    4.22 -    struct RTCState *vrtc = &v->domain->arch.hvm_domain.pl_time.vrtc;
    4.23 -    struct PMTState *vpmt = &v->domain->arch.hvm_domain.pl_time.vpmt;
    4.24 -
    4.25 -    if ( pt->enabled )
    4.26 -    {
    4.27 -        migrate_timer(&pt->timer, v->processor);
    4.28 -    }
    4.29 -    migrate_timer(&vcpu_vlapic(v)->vlapic_timer, v->processor);
    4.30 -    migrate_timer(&vrtc->second_timer, v->processor);
    4.31 -    migrate_timer(&vrtc->second_timer2, v->processor);
    4.32 -    migrate_timer(&vpmt->timer, v->processor);
    4.33 -}
    4.34 -
    4.35 -
    4.36  void arch_svm_do_resume(struct vcpu *v) 
    4.37  {
    4.38      /* pinning VCPU to a different core? */
    4.39 @@ -880,7 +865,7 @@ void arch_svm_do_resume(struct vcpu *v)
    4.40              printk("VCPU core pinned: %d to %d\n", 
    4.41                     v->arch.hvm_svm.launch_core, smp_processor_id() );
    4.42          v->arch.hvm_svm.launch_core = smp_processor_id();
    4.43 -        svm_migrate_timers( v );
    4.44 +        hvm_migrate_timers( v );
    4.45          hvm_do_resume( v );
    4.46          reset_stack_and_jump( svm_asm_do_resume );
    4.47      }
     5.1 --- a/xen/arch/x86/hvm/vioapic.c	Thu Nov 16 15:20:05 2006 +0000
     5.2 +++ b/xen/arch/x86/hvm/vioapic.c	Thu Nov 16 17:07:23 2006 +0000
     5.3 @@ -471,8 +471,8 @@ void vioapic_set_irq(struct domain *d, i
     5.4      struct vioapic *vioapic = domain_vioapic(d);
     5.5      uint32_t bit;
     5.6  
     5.7 -    HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_set_irq "
     5.8 -                "irq %x level %x\n", irq, level);
     5.9 +    HVM_DBG_LOG(DBG_LEVEL_IOAPIC, "ioapic_set_irq irq %x level %x", 
    5.10 +                irq, level);
    5.11  
    5.12      if ( (irq < 0) || (irq >= VIOAPIC_NUM_PINS) )
    5.13          return;
     6.1 --- a/xen/arch/x86/hvm/vmx/vmcs.c	Thu Nov 16 15:20:05 2006 +0000
     6.2 +++ b/xen/arch/x86/hvm/vmx/vmcs.c	Thu Nov 16 17:07:23 2006 +0000
     6.3 @@ -486,7 +486,7 @@ void arch_vmx_do_resume(struct vcpu *v)
     6.4      {
     6.5          vmx_clear_vmcs(v);
     6.6          vmx_load_vmcs(v);
     6.7 -        vmx_migrate_timers(v);
     6.8 +        hvm_migrate_timers(v);
     6.9          vmx_set_host_env(v);
    6.10      }
    6.11  
     7.1 --- a/xen/arch/x86/hvm/vmx/vmx.c	Thu Nov 16 15:20:05 2006 +0000
     7.2 +++ b/xen/arch/x86/hvm/vmx/vmx.c	Thu Nov 16 17:07:23 2006 +0000
     7.3 @@ -376,14 +376,18 @@ static inline void vmx_restore_dr(struct
     7.4  
     7.5  static void vmx_freeze_time(struct vcpu *v)
     7.6  {
     7.7 -    struct periodic_time *pt=&v->domain->arch.hvm_domain.pl_time.periodic_tm;
     7.8 +    struct hvm_domain *plat = &v->domain->arch.hvm_domain;
     7.9 +    struct periodic_time *pt = &plat->pl_time.periodic_tm;
    7.10  
    7.11      if ( pt->enabled && pt->first_injected
    7.12              && (v->vcpu_id == pt->bind_vcpu)
    7.13              && !v->arch.hvm_vcpu.guest_time ) {
    7.14          v->arch.hvm_vcpu.guest_time = hvm_get_guest_time(v);
    7.15          if ( !test_bit(_VCPUF_blocked, &v->vcpu_flags) )
    7.16 +        {
    7.17              stop_timer(&pt->timer);
    7.18 +            rtc_freeze(v);
    7.19 +        }
    7.20      }
    7.21  }
    7.22  
    7.23 @@ -409,22 +413,6 @@ static void stop_vmx(void)
    7.24      clear_in_cr4(X86_CR4_VMXE);
    7.25  }
    7.26  
    7.27 -void vmx_migrate_timers(struct vcpu *v)
    7.28 -{
    7.29 -    struct periodic_time *pt = &v->domain->arch.hvm_domain.pl_time.periodic_tm;
    7.30 -    struct RTCState *vrtc = &v->domain->arch.hvm_domain.pl_time.vrtc;
    7.31 -    struct PMTState *vpmt = &v->domain->arch.hvm_domain.pl_time.vpmt;
    7.32 -
    7.33 -    if ( pt->enabled )
    7.34 -    {
    7.35 -        migrate_timer(&pt->timer, v->processor);
    7.36 -    }
    7.37 -    migrate_timer(&vcpu_vlapic(v)->vlapic_timer, v->processor);
    7.38 -    migrate_timer(&vrtc->second_timer, v->processor);
    7.39 -    migrate_timer(&vrtc->second_timer2, v->processor);
    7.40 -    migrate_timer(&vpmt->timer, v->processor);
    7.41 -}
    7.42 -
    7.43  static void vmx_store_cpu_guest_regs(
    7.44      struct vcpu *v, struct cpu_user_regs *regs, unsigned long *crs)
    7.45  {
     8.1 --- a/xen/include/asm-x86/hvm/hvm.h	Thu Nov 16 15:20:05 2006 +0000
     8.2 +++ b/xen/include/asm-x86/hvm/hvm.h	Thu Nov 16 17:07:23 2006 +0000
     8.3 @@ -161,6 +161,7 @@ hvm_get_guest_ctrl_reg(struct vcpu *v, u
     8.4  
     8.5  void hvm_stts(struct vcpu *v);
     8.6  void hvm_set_guest_time(struct vcpu *v, u64 gtime);
     8.7 +void hvm_migrate_timers(struct vcpu *v);
     8.8  void hvm_do_resume(struct vcpu *v);
     8.9  
    8.10  static inline void
     9.1 --- a/xen/include/asm-x86/hvm/vmx/vmx.h	Thu Nov 16 15:20:05 2006 +0000
     9.2 +++ b/xen/include/asm-x86/hvm/vmx/vmx.h	Thu Nov 16 17:07:23 2006 +0000
     9.3 @@ -29,7 +29,6 @@
     9.4  extern void vmx_asm_vmexit_handler(struct cpu_user_regs);
     9.5  extern void vmx_asm_do_vmentry(void);
     9.6  extern void vmx_intr_assist(void);
     9.7 -extern void vmx_migrate_timers(struct vcpu *v);
     9.8  extern void arch_vmx_do_resume(struct vcpu *);
     9.9  extern void set_guest_time(struct vcpu *v, u64 gtime);
    9.10  
    10.1 --- a/xen/include/asm-x86/hvm/vpt.h	Thu Nov 16 15:20:05 2006 +0000
    10.2 +++ b/xen/include/asm-x86/hvm/vpt.h	Thu Nov 16 17:07:23 2006 +0000
    10.3 @@ -67,8 +67,10 @@ typedef struct RTCState {
    10.4      int64_t next_second_time;
    10.5      struct timer second_timer;
    10.6      struct timer second_timer2;
    10.7 +    struct timer pie_timer;
    10.8 +    int period;
    10.9 +    s_time_t next_pie;
   10.10      struct vcpu      *vcpu;
   10.11 -    struct periodic_time *pt;
   10.12  } RTCState;
   10.13  
   10.14  #define FREQUENCE_PMTIMER  3579545
   10.15 @@ -143,9 +145,11 @@ extern void destroy_periodic_time(struct
   10.16  void pit_init(struct vcpu *v, unsigned long cpu_khz);
   10.17  void rtc_init(struct vcpu *v, int base, int irq);
   10.18  void rtc_deinit(struct domain *d);
   10.19 +void rtc_freeze(struct vcpu *v);
   10.20 +void rtc_thaw(struct vcpu *v);
   10.21 +void rtc_migrate_timers(struct vcpu *v);
   10.22  void pmtimer_init(struct vcpu *v, int base);
   10.23  void pmtimer_deinit(struct domain *d);
   10.24 -int is_rtc_periodic_irq(void *opaque);
   10.25  void pt_timer_fn(void *data);
   10.26  void pit_time_fired(struct vcpu *v, void *priv);
   10.27