direct-io.hg

changeset 12337:617c187322ab

[HVM] Clean up two small APIC TDCR issues.

First, only save the bits that can be set, so that on a subsequent
read can't see MBZ bits as set. Next, be sure to initialize the
timer_divide_count, which is derived from the TDCR. This avoids a
potential divide-by-zero elsewhere in the code.

The original patch was provided by Ben Thomas <ben@virtualiron.com>.
This modified version refactors the code slightly and renames
timer_divide_count to timer_divisor.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Thu Nov 09 17:53:05 2006 +0000 (2006-11-09)
parents 5a9b79981a35
children 452010ddef24
files xen/arch/x86/hvm/vlapic.c xen/include/asm-x86/hvm/vlapic.h
line diff
     1.1 --- a/xen/arch/x86/hvm/vlapic.c	Thu Nov 09 17:28:12 2006 +0000
     1.2 +++ b/xen/arch/x86/hvm/vlapic.c	Thu Nov 09 17:53:05 2006 +0000
     1.3 @@ -495,8 +495,7 @@ static uint32_t vlapic_get_tmcct(struct 
     1.4      else
     1.5          passed = now - vlapic->timer_last_update;
     1.6  
     1.7 -    counter_passed = passed /
     1.8 -      (APIC_BUS_CYCLE_NS * vlapic->timer_divide_count);
     1.9 +    counter_passed = passed / (APIC_BUS_CYCLE_NS * vlapic->timer_divisor);
    1.10  
    1.11      tmcct -= counter_passed;
    1.12  
    1.13 @@ -528,10 +527,21 @@ static uint32_t vlapic_get_tmcct(struct 
    1.14      return tmcct;
    1.15  }
    1.16  
    1.17 +static void vlapic_set_tdcr(struct vlapic *vlapic, unsigned int val)
    1.18 +{
    1.19 +    /* Only bits 0, 1 and 3 are settable; others are MBZ. */
    1.20 +    val &= 0xb;
    1.21 +    vlapic_set_reg(vlapic, APIC_TDCR, val);
    1.22 +
    1.23 +    /* Update the demangled timer_divisor. */
    1.24 +    val = ((val & 3) | ((val & 8) >> 1)) + 1;
    1.25 +    vlapic->timer_divisor = 1 << (val & 7);
    1.26 +}
    1.27 +
    1.28  static void vlapic_read_aligned(struct vlapic *vlapic, unsigned int offset,
    1.29                           unsigned int len, unsigned int *result)
    1.30  {
    1.31 -    ASSERT(len == 4 && offset > 0 && offset <= APIC_TDCR);
    1.32 +    ASSERT((len == 4) && (offset > 0) && (offset <= APIC_TDCR));
    1.33  
    1.34      *result = 0;
    1.35  
    1.36 @@ -563,7 +573,7 @@ static unsigned long vlapic_read(struct 
    1.37      struct vlapic *vlapic = vcpu_vlapic(v);
    1.38      unsigned int offset = address - vlapic->base_address;
    1.39  
    1.40 -    if ( offset > APIC_TDCR)
    1.41 +    if ( offset > APIC_TDCR )
    1.42          return 0;
    1.43  
    1.44      /* some bugs on kernel cause read this with byte*/
    1.45 @@ -760,8 +770,7 @@ static void vlapic_write(struct vcpu *v,
    1.46          vlapic_set_reg(vlapic, APIC_TMCCT, val);
    1.47          vlapic->timer_last_update = now;
    1.48  
    1.49 -        offset = APIC_BUS_CYCLE_NS *
    1.50 -            vlapic->timer_divide_count * val;
    1.51 +        offset = APIC_BUS_CYCLE_NS * vlapic->timer_divisor * val;
    1.52  
    1.53          set_timer(&vlapic->vlapic_timer, now + offset);
    1.54  
    1.55 @@ -776,19 +785,10 @@ static void vlapic_write(struct vcpu *v,
    1.56      break;
    1.57  
    1.58      case APIC_TDCR:
    1.59 -    {
    1.60 -        unsigned int tmp1, tmp2;
    1.61 -
    1.62 -        tmp1 = val & 0xf;
    1.63 -        tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1;
    1.64 -        vlapic->timer_divide_count = 0x1 << (tmp2 & 0x7);
    1.65 -
    1.66 -        vlapic_set_reg(vlapic, APIC_TDCR, val);
    1.67 -
    1.68 -        HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divide count is 0x%x",
    1.69 -                    vlapic->timer_divide_count);
    1.70 -    }
    1.71 -    break;
    1.72 +        vlapic_set_tdcr(vlapic, val & 0xb);
    1.73 +        HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divisor is 0x%x",
    1.74 +                    vlapic->timer_divisor);
    1.75 +        break;
    1.76  
    1.77      default:
    1.78          gdprintk(XENLOG_WARNING, 
    1.79 @@ -852,8 +852,7 @@ void vlapic_timer_fn(void *data)
    1.80  
    1.81          vlapic_set_reg(vlapic, APIC_TMCCT, tmict);
    1.82  
    1.83 -        offset = APIC_BUS_CYCLE_NS *
    1.84 -                 vlapic->timer_divide_count * tmict;
    1.85 +        offset = APIC_BUS_CYCLE_NS * vlapic->timer_divisor * tmict;
    1.86  
    1.87          set_timer(&vlapic->vlapic_timer, now + offset);
    1.88      }
    1.89 @@ -967,6 +966,8 @@ static int vlapic_reset(struct vlapic *v
    1.90  
    1.91      vlapic->flush_tpr_threshold = 0;
    1.92  
    1.93 +    vlapic_set_tdcr(vlapic, 0);
    1.94 +
    1.95      vlapic->base_address = vlapic->apic_base_msr &
    1.96                             MSR_IA32_APICBASE_BASE;
    1.97  
     2.1 --- a/xen/include/asm-x86/hvm/vlapic.h	Thu Nov 09 17:28:12 2006 +0000
     2.2 +++ b/xen/include/asm-x86/hvm/vlapic.h	Thu Nov 09 17:53:05 2006 +0000
     2.3 @@ -49,7 +49,7 @@ struct vlapic {
     2.4      uint32_t           status;
     2.5      uint64_t           apic_base_msr;
     2.6      unsigned long      base_address;
     2.7 -    uint32_t           timer_divide_count;
     2.8 +    uint32_t           timer_divisor;
     2.9      struct timer       vlapic_timer;
    2.10      int                timer_pending_count;
    2.11      int                flush_tpr_threshold;