ia64/xen-unstable

changeset 19424:1dd7b640d953

CPUIDLE: enable MSI capable HPET for timer broadcast

The HPET broadcast was default not enabled because the old code use
HPET channel 0 in legacy replacing mode which will hide both PIT & RTC
irqs and cause issues if RTC is needed in some cases. The upstream
default broadcast timer is PIT, which is in periodic mode (100HZ) and
would be expensive to be used as oneshot. MSI capable HPET is coming
into being. It is capable to deliver interrupt through FSB directly,
and has no side effect.

This patch extends support for MSI HPET based on original legacy HPET
code. The broadcast timer selection logic becomes: 1. if MSI capable HPET
available, use multiple HPET channels (no more than possible cpu num)
in MSI mode; 2. else if legacy replacing mode available for HPET &
'hpetbroadcast' option is given in cmd line, use HPET channel 0 in
legacy mode; 3 else use PIT.

While entering broadcast, it gets a hpet channel (look for a spare one
first, if failing allocate a shared one), attach to current cpu, setup
the irq affinity & broadcast cpumask. While exiting broadcast, it
detach the used hpet channel and try to change the owner if the
broadcast mask is not empty. Some optimizations(static affinity) were
done for (MSI HPET channels >= possible cpu num) case.

A new hw_interrupt_controller 'HPET_MSI' is created for HPET MSI
interrupt handling.

Signed-off-by: Wei Gang <gang.wei@intel.com>=
author Keir Fraser <keir.fraser@citrix.com>
date Fri Mar 20 12:33:55 2009 +0000 (2009-03-20)
parents 538a64b1ed63
children 6a069ea7149b
files xen/arch/x86/hpet.c xen/arch/x86/msi.c xen/arch/x86/time.c xen/include/asm-x86/hpet.h
line diff
     1.1 --- a/xen/arch/x86/hpet.c	Fri Mar 20 12:09:20 2009 +0000
     1.2 +++ b/xen/arch/x86/hpet.c	Fri Mar 20 12:33:55 2009 +0000
     1.3 @@ -10,13 +10,21 @@
     1.4  #include <xen/timer.h>
     1.5  #include <xen/smp.h>
     1.6  #include <xen/softirq.h>
     1.7 +#include <xen/irq.h>
     1.8  #include <asm/fixmap.h>
     1.9  #include <asm/div64.h>
    1.10  #include <asm/hpet.h>
    1.11 +#include <asm/msi.h>
    1.12 +#include <mach_apic.h>
    1.13  
    1.14  #define MAX_DELTA_NS MILLISECS(10*1000)
    1.15  #define MIN_DELTA_NS MICROSECS(20)
    1.16  
    1.17 +#define MAX_HPET_NUM 32
    1.18 +
    1.19 +#define HPET_EVT_USED_BIT   2
    1.20 +#define HPET_EVT_USED       (1 << HPET_EVT_USED_BIT)
    1.21 +
    1.22  struct hpet_event_channel
    1.23  {
    1.24      unsigned long mult;
    1.25 @@ -25,11 +33,31 @@ struct hpet_event_channel
    1.26      cpumask_t     cpumask;
    1.27      spinlock_t    lock;
    1.28      void          (*event_handler)(struct hpet_event_channel *);
    1.29 -};
    1.30 -static struct hpet_event_channel hpet_event;
    1.31 +
    1.32 +    unsigned int idx;   /* physical channel idx */
    1.33 +    int cpu;            /* msi target */
    1.34 +    unsigned int vector;/* msi vector */
    1.35 +    unsigned int flags; /* HPET_EVT_x */
    1.36 +} __cacheline_aligned;
    1.37 +static struct hpet_event_channel legacy_hpet_event;
    1.38 +static struct hpet_event_channel hpet_events[MAX_HPET_NUM];
    1.39 +static unsigned int num_hpets_used; /* msi hpet channels used for broadcast */
    1.40 +
    1.41 +DEFINE_PER_CPU(struct hpet_event_channel *, cpu_bc_channel);
    1.42 +
    1.43 +static int vector_channel[NR_IRQS] = {[0 ... NR_IRQS-1] = -1};
    1.44 +
    1.45 +#define vector_to_channel(vector)   vector_channel[vector]
    1.46  
    1.47  unsigned long hpet_address;
    1.48  
    1.49 +void msi_compose_msg(struct pci_dev *pdev, int vector, struct msi_msg *msg);
    1.50 +
    1.51 +/* force_hpet_broadcast: if true, force using hpet_broadcast to fix lapic stop
    1.52 +   issue for deep C state with pit disabled */
    1.53 +int force_hpet_broadcast;
    1.54 +boolean_param("hpetbroadcast", force_hpet_broadcast);
    1.55 +
    1.56  /*
    1.57   * Calculate a multiplication factor for scaled math, which is used to convert
    1.58   * nanoseconds based values to clock ticks:
    1.59 @@ -63,7 +91,7 @@ static inline unsigned long ns2ticks(uns
    1.60      return (unsigned long) tmp;
    1.61  }
    1.62  
    1.63 -static int hpet_legacy_next_event(unsigned long delta)
    1.64 +static int hpet_next_event(unsigned long delta, int timer)
    1.65  {
    1.66      uint32_t cnt, cmp;
    1.67      unsigned long flags;
    1.68 @@ -71,7 +99,7 @@ static int hpet_legacy_next_event(unsign
    1.69      local_irq_save(flags);
    1.70      cnt = hpet_read32(HPET_COUNTER);
    1.71      cmp = cnt + delta;
    1.72 -    hpet_write32(cmp, HPET_T0_CMP);
    1.73 +    hpet_write32(cmp, HPET_Tn_CMP(timer));
    1.74      cmp = hpet_read32(HPET_COUNTER);
    1.75      local_irq_restore(flags);
    1.76  
    1.77 @@ -101,7 +129,7 @@ static int reprogram_hpet_evt_channel(
    1.78      if ( expire == STIME_MAX )
    1.79      {
    1.80          /* We assume it will take a long time for the timer to wrap. */
    1.81 -        hpet_write32(0, HPET_T0_CMP);
    1.82 +        hpet_write32(0, HPET_Tn_CMP(ch->idx));
    1.83          return 0;
    1.84      }
    1.85  
    1.86 @@ -109,11 +137,11 @@ static int reprogram_hpet_evt_channel(
    1.87      delta = max_t(int64_t, delta, MIN_DELTA_NS);
    1.88      delta = ns2ticks(delta, ch->shift, ch->mult);
    1.89  
    1.90 -    ret = hpet_legacy_next_event(delta);
    1.91 +    ret = hpet_next_event(delta, ch->idx);
    1.92      while ( ret && force )
    1.93      {
    1.94          delta += delta;
    1.95 -        ret = hpet_legacy_next_event(delta);
    1.96 +        ret = hpet_next_event(delta, ch->idx);
    1.97      }
    1.98  
    1.99      return ret;
   1.100 @@ -172,17 +200,335 @@ again:
   1.101      spin_unlock_irq(&ch->lock);
   1.102  }
   1.103  
   1.104 +static void hpet_interrupt_handler(int vector, void *data,
   1.105 +        struct cpu_user_regs *regs)
   1.106 +{
   1.107 +    struct hpet_event_channel *ch = (struct hpet_event_channel *)data;
   1.108 +    if ( !ch->event_handler )
   1.109 +    {
   1.110 +        printk(XENLOG_WARNING "Spurious HPET timer interrupt on HPET timer %d\n", ch->idx);
   1.111 +        return;
   1.112 +    }
   1.113 +
   1.114 +    ch->event_handler(ch);
   1.115 +}
   1.116 +
   1.117 +static void hpet_msi_unmask(unsigned int vector)
   1.118 +{
   1.119 +    unsigned long cfg;
   1.120 +    int ch_idx = vector_to_channel(vector);
   1.121 +    struct hpet_event_channel *ch;
   1.122 +
   1.123 +    BUG_ON(ch_idx < 0);
   1.124 +    ch = &hpet_events[ch_idx];
   1.125 +
   1.126 +    cfg = hpet_read32(HPET_Tn_CFG(ch->idx));
   1.127 +    cfg |= HPET_TN_FSB;
   1.128 +    hpet_write32(cfg, HPET_Tn_CFG(ch->idx));
   1.129 +}
   1.130 +
   1.131 +static void hpet_msi_mask(unsigned int vector)
   1.132 +{
   1.133 +    unsigned long cfg;
   1.134 +    int ch_idx = vector_to_channel(vector);
   1.135 +    struct hpet_event_channel *ch;
   1.136 +
   1.137 +    BUG_ON(ch_idx < 0);
   1.138 +    ch = &hpet_events[ch_idx];
   1.139 +
   1.140 +    cfg = hpet_read32(HPET_Tn_CFG(ch->idx));
   1.141 +    cfg &= ~HPET_TN_FSB;
   1.142 +    hpet_write32(cfg, HPET_Tn_CFG(ch->idx));
   1.143 +}
   1.144 +
   1.145 +static void hpet_msi_write(unsigned int vector, struct msi_msg *msg)
   1.146 +{
   1.147 +    int ch_idx = vector_to_channel(vector);
   1.148 +    struct hpet_event_channel *ch;
   1.149 +
   1.150 +    BUG_ON(ch_idx < 0);
   1.151 +    ch = &hpet_events[ch_idx];
   1.152 +
   1.153 +    hpet_write32(msg->data, HPET_Tn_ROUTE(ch->idx));
   1.154 +    hpet_write32(msg->address_lo, HPET_Tn_ROUTE(ch->idx) + 4);
   1.155 +}
   1.156 +
   1.157 +static void hpet_msi_read(unsigned int vector, struct msi_msg *msg)
   1.158 +{
   1.159 +    int ch_idx = vector_to_channel(vector);
   1.160 +    struct hpet_event_channel *ch;
   1.161 +
   1.162 +    BUG_ON(ch_idx < 0);
   1.163 +    ch = &hpet_events[ch_idx];
   1.164 +
   1.165 +    msg->data = hpet_read32(HPET_Tn_ROUTE(ch->idx));
   1.166 +    msg->address_lo = hpet_read32(HPET_Tn_ROUTE(ch->idx) + 4);
   1.167 +    msg->address_hi = 0;
   1.168 +}
   1.169 +
   1.170 +static unsigned int hpet_msi_startup(unsigned int vector)
   1.171 +{
   1.172 +    hpet_msi_unmask(vector);
   1.173 +    return 0;
   1.174 +}
   1.175 +
   1.176 +static void hpet_msi_shutdown(unsigned int vector)
   1.177 +{
   1.178 +    hpet_msi_mask(vector);
   1.179 +}
   1.180 +
   1.181 +static void hpet_msi_ack(unsigned int vector)
   1.182 +{
   1.183 +    ack_APIC_irq();
   1.184 +}
   1.185 +
   1.186 +static void hpet_msi_end(unsigned int vector)
   1.187 +{
   1.188 +}
   1.189 +
   1.190 +static void hpet_msi_set_affinity(unsigned int vector, cpumask_t mask)
   1.191 +{
   1.192 +    struct msi_msg msg;
   1.193 +    unsigned int dest;
   1.194 +    cpumask_t tmp;
   1.195 +
   1.196 +    cpus_and(tmp, mask, cpu_online_map);
   1.197 +    if ( cpus_empty(tmp) )
   1.198 +        mask = TARGET_CPUS;
   1.199 +
   1.200 +    dest = cpu_mask_to_apicid(mask);
   1.201 +
   1.202 +    hpet_msi_read(vector, &msg);
   1.203 +
   1.204 +    msg.data &= ~MSI_DATA_VECTOR_MASK;
   1.205 +    msg.data |= MSI_DATA_VECTOR(vector);
   1.206 +    msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
   1.207 +    msg.address_lo |= MSI_ADDR_DEST_ID(dest);
   1.208 +
   1.209 +    hpet_msi_write(vector, &msg);
   1.210 +    irq_desc[vector].affinity = mask;
   1.211 +}
   1.212 +
   1.213 +/*
   1.214 + * IRQ Chip for MSI HPET Devices,
   1.215 + */
   1.216 +static struct hw_interrupt_type hpet_msi_type = {
   1.217 +    .typename   = "HPET-MSI",
   1.218 +    .startup    = hpet_msi_startup,
   1.219 +    .shutdown   = hpet_msi_shutdown,
   1.220 +    .enable	    = hpet_msi_unmask,
   1.221 +    .disable    = hpet_msi_mask,
   1.222 +    .ack        = hpet_msi_ack,
   1.223 +    .end        = hpet_msi_end,
   1.224 +    .set_affinity   = hpet_msi_set_affinity,
   1.225 +};
   1.226 +
   1.227 +static int hpet_setup_msi_irq(unsigned int vector)
   1.228 +{
   1.229 +    int ret;
   1.230 +    struct msi_msg msg;
   1.231 +    struct hpet_event_channel *ch = &hpet_events[vector_to_channel(vector)];
   1.232 +
   1.233 +    irq_desc[vector].handler = &hpet_msi_type;
   1.234 +    ret = request_irq_vector(vector, hpet_interrupt_handler,
   1.235 +                      0, "HPET", ch);
   1.236 +    if ( ret < 0 )
   1.237 +        return ret;
   1.238 +
   1.239 +    msi_compose_msg(NULL, vector, &msg);
   1.240 +    hpet_msi_write(vector, &msg);
   1.241 +
   1.242 +    return 0;
   1.243 +}
   1.244 +
   1.245 +static int hpet_assign_irq(struct hpet_event_channel *ch)
   1.246 +{
   1.247 +    unsigned int vector;
   1.248 +
   1.249 +    vector = assign_irq_vector(AUTO_ASSIGN_IRQ);
   1.250 +    if ( !vector )
   1.251 +        return -EINVAL;
   1.252 +
   1.253 +    irq_vector[vector] = vector;
   1.254 +    vector_irq[vector] = vector;
   1.255 +    vector_channel[vector] = ch - &hpet_events[0];
   1.256 +
   1.257 +    if ( hpet_setup_msi_irq(vector) )
   1.258 +    {
   1.259 +        irq_vector[vector] = 0;
   1.260 +        vector_irq[vector] = FREE_TO_ASSIGN_IRQ;
   1.261 +        vector_channel[vector] = -1;
   1.262 +        return -EINVAL;
   1.263 +    }
   1.264 +
   1.265 +    ch->vector = vector;
   1.266 +    return 0;
   1.267 +}
   1.268 +
   1.269 +static int hpet_fsb_cap_lookup(void)
   1.270 +{
   1.271 +    unsigned int id;
   1.272 +    unsigned int num_chs, num_chs_used;
   1.273 +    int i;
   1.274 +
   1.275 +    id = hpet_read32(HPET_ID);
   1.276 +
   1.277 +    num_chs = ((id & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT);
   1.278 +    num_chs++; /* Value read out starts from 0 */
   1.279 +
   1.280 +    num_chs_used = 0;
   1.281 +    for ( i = 0; i < num_chs; i++ )
   1.282 +    {
   1.283 +        struct hpet_event_channel *ch = &hpet_events[num_chs_used];
   1.284 +        unsigned long cfg = hpet_read32(HPET_Tn_CFG(i));
   1.285 +
   1.286 +        /* Only consider HPET timer with MSI support */
   1.287 +        if ( !(cfg & HPET_TN_FSB_CAP) )
   1.288 +            continue;
   1.289 +
   1.290 +        ch->flags = 0;
   1.291 +        ch->idx = i;
   1.292 +
   1.293 +        if ( hpet_assign_irq(ch) )
   1.294 +            continue;
   1.295 +
   1.296 +        /* set default irq affinity */
   1.297 +        ch->cpu = num_chs_used;
   1.298 +        per_cpu(cpu_bc_channel, ch->cpu) = ch;
   1.299 +        irq_desc[ch->vector].handler->
   1.300 +            set_affinity(ch->vector, cpumask_of_cpu(ch->cpu));
   1.301 +
   1.302 +        num_chs_used++;
   1.303 +
   1.304 +        if ( num_chs_used == num_possible_cpus() )
   1.305 +            break;
   1.306 +    }
   1.307 +
   1.308 +    printk(XENLOG_INFO
   1.309 +           "HPET: %d timers in total, %d timers will be used for broadcast\n",
   1.310 +           num_chs, num_chs_used);
   1.311 +
   1.312 +    return num_chs_used;
   1.313 +}
   1.314 +
   1.315 +static int next_channel;
   1.316 +static spinlock_t next_lock = SPIN_LOCK_UNLOCKED;
   1.317 +
   1.318 +static struct hpet_event_channel *hpet_get_channel(int cpu)
   1.319 +{
   1.320 +    int i;
   1.321 +    int next;
   1.322 +    struct hpet_event_channel *ch;
   1.323 +
   1.324 +    spin_lock(&next_lock);
   1.325 +    next = next_channel = (next_channel + 1) % num_hpets_used;
   1.326 +    spin_unlock(&next_lock);
   1.327 +
   1.328 +    /* try unused channel first */
   1.329 +    for ( i = next; i < next + num_hpets_used; i++ )
   1.330 +    {
   1.331 +        ch = &hpet_events[i % num_hpets_used];
   1.332 +        if ( !test_and_set_bit(HPET_EVT_USED_BIT, &ch->flags) )
   1.333 +        {
   1.334 +            ch->cpu = cpu;
   1.335 +            return ch;
   1.336 +        }
   1.337 +    }
   1.338 +
   1.339 +    /* share a in-use channel */
   1.340 +    ch = &hpet_events[next];
   1.341 +    if ( !test_and_set_bit(HPET_EVT_USED_BIT, &ch->flags) )
   1.342 +        ch->cpu = cpu;
   1.343 +
   1.344 +    return ch;
   1.345 +}
   1.346 +
   1.347 +static void hpet_attach_channel_share(int cpu, struct hpet_event_channel *ch)
   1.348 +{
   1.349 +    per_cpu(cpu_bc_channel, cpu) = ch;
   1.350 +
   1.351 +    /* try to be the channel owner again while holding the lock */
   1.352 +    if ( !test_and_set_bit(HPET_EVT_USED_BIT, &ch->flags) )
   1.353 +        ch->cpu = cpu;
   1.354 +
   1.355 +    if ( ch->cpu != cpu )
   1.356 +        return;
   1.357 +
   1.358 +    /* set irq affinity */
   1.359 +    irq_desc[ch->vector].handler->
   1.360 +        set_affinity(ch->vector, cpumask_of_cpu(ch->cpu));
   1.361 +}
   1.362 +
   1.363 +static void hpet_detach_channel_share(int cpu)
   1.364 +{
   1.365 +    struct hpet_event_channel *ch = per_cpu(cpu_bc_channel, cpu);
   1.366 +
   1.367 +    per_cpu(cpu_bc_channel, cpu) = NULL;
   1.368 +
   1.369 +    if ( cpu != ch->cpu )
   1.370 +        return;
   1.371 +
   1.372 +    if ( cpus_empty(ch->cpumask) )
   1.373 +    {
   1.374 +        ch->cpu = -1;
   1.375 +        clear_bit(HPET_EVT_USED_BIT, &ch->flags);
   1.376 +        return;
   1.377 +    }
   1.378 +
   1.379 +    ch->cpu = first_cpu(ch->cpumask);
   1.380 +    /* set irq affinity */
   1.381 +    irq_desc[ch->vector].handler->
   1.382 +        set_affinity(ch->vector, cpumask_of_cpu(ch->cpu));
   1.383 +}
   1.384 +
   1.385 +static void (*hpet_attach_channel)(int cpu, struct hpet_event_channel *ch);
   1.386 +static void (*hpet_detach_channel)(int cpu);
   1.387 +
   1.388  void hpet_broadcast_init(void)
   1.389  {
   1.390      u64 hpet_rate;
   1.391      u32 hpet_id, cfg;
   1.392 +    int i;
   1.393  
   1.394      hpet_rate = hpet_setup();
   1.395      if ( hpet_rate == 0 )
   1.396          return;
   1.397  
   1.398 +    num_hpets_used = hpet_fsb_cap_lookup();
   1.399 +    if ( num_hpets_used > 0 )
   1.400 +    {
   1.401 +        /* Stop HPET legacy interrupts */
   1.402 +        cfg = hpet_read32(HPET_CFG);
   1.403 +        cfg &= ~HPET_CFG_LEGACY;
   1.404 +        hpet_write32(cfg, HPET_CFG);
   1.405 +
   1.406 +        for ( i = 0; i < num_hpets_used; i++ )
   1.407 +        {
   1.408 +            /* set HPET Tn as oneshot */
   1.409 +            cfg = hpet_read32(HPET_Tn_CFG(hpet_events[i].idx));
   1.410 +            cfg &= ~HPET_TN_PERIODIC;
   1.411 +            cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
   1.412 +            hpet_write32(cfg, HPET_Tn_CFG(hpet_events[i].idx));
   1.413 +  
   1.414 +            hpet_events[i].mult = div_sc((unsigned long)hpet_rate,
   1.415 +                                         1000000000ul, 32);
   1.416 +            hpet_events[i].shift = 32;
   1.417 +            hpet_events[i].next_event = STIME_MAX;
   1.418 +            hpet_events[i].event_handler = handle_hpet_broadcast;
   1.419 +            spin_lock_init(&hpet_events[i].lock);
   1.420 +        }
   1.421 +
   1.422 +        if ( num_hpets_used < num_possible_cpus() )
   1.423 +        {
   1.424 +            hpet_attach_channel = hpet_attach_channel_share;
   1.425 +            hpet_detach_channel = hpet_detach_channel_share;
   1.426 +        }
   1.427 +
   1.428 +        return;
   1.429 +    }
   1.430 +
   1.431      hpet_id = hpet_read32(HPET_ID);
   1.432 -    if ( !(hpet_id & HPET_ID_LEGSUP) )
   1.433 +    if ( !(hpet_id & HPET_ID_LEGSUP) || !force_hpet_broadcast )
   1.434          return;
   1.435  
   1.436      /* Start HPET legacy interrupts */
   1.437 @@ -200,23 +546,36 @@ void hpet_broadcast_init(void)
   1.438       * The period is a femto seconds value. We need to calculate the scaled
   1.439       * math multiplication factor for nanosecond to hpet tick conversion.
   1.440       */
   1.441 -    hpet_event.mult = div_sc((unsigned long)hpet_rate, 1000000000ul, 32);
   1.442 -    hpet_event.shift = 32;
   1.443 -    hpet_event.next_event = STIME_MAX;
   1.444 -    hpet_event.event_handler = handle_hpet_broadcast;
   1.445 -    spin_lock_init(&hpet_event.lock);
   1.446 +    legacy_hpet_event.mult = div_sc((unsigned long)hpet_rate, 1000000000ul, 32);
   1.447 +    legacy_hpet_event.shift = 32;
   1.448 +    legacy_hpet_event.next_event = STIME_MAX;
   1.449 +    legacy_hpet_event.event_handler = handle_hpet_broadcast;
   1.450 +    legacy_hpet_event.idx = 0;
   1.451 +    legacy_hpet_event.flags = 0;
   1.452 +    spin_lock_init(&legacy_hpet_event.lock);
   1.453 +
   1.454 +    for_each_cpu(i)
   1.455 +        per_cpu(cpu_bc_channel, i) = &legacy_hpet_event;
   1.456  }
   1.457  
   1.458  void hpet_broadcast_enter(void)
   1.459  {
   1.460 -    struct hpet_event_channel *ch = &hpet_event;
   1.461 +    int cpu = smp_processor_id();
   1.462 +    struct hpet_event_channel *ch = per_cpu(cpu_bc_channel, cpu);
   1.463 +
   1.464 +    if ( !ch )
   1.465 +        ch = hpet_get_channel(cpu);
   1.466 +    BUG_ON( !ch );
   1.467  
   1.468      ASSERT(!local_irq_is_enabled());
   1.469      spin_lock(&ch->lock);
   1.470  
   1.471 +    if ( hpet_attach_channel )
   1.472 +        hpet_attach_channel(cpu, ch);
   1.473 +
   1.474      disable_APIC_timer();
   1.475  
   1.476 -    cpu_set(smp_processor_id(), ch->cpumask);
   1.477 +    cpu_set(cpu, ch->cpumask);
   1.478  
   1.479      /* reprogram if current cpu expire time is nearer */
   1.480      if ( this_cpu(timer_deadline) < ch->next_event )
   1.481 @@ -227,8 +586,10 @@ void hpet_broadcast_enter(void)
   1.482  
   1.483  void hpet_broadcast_exit(void)
   1.484  {
   1.485 -    struct hpet_event_channel *ch = &hpet_event;
   1.486      int cpu = smp_processor_id();
   1.487 +    struct hpet_event_channel *ch = per_cpu(cpu_bc_channel, cpu);
   1.488 +
   1.489 +    BUG_ON( !ch );
   1.490  
   1.491      spin_lock_irq(&ch->lock);
   1.492  
   1.493 @@ -246,19 +607,23 @@ void hpet_broadcast_exit(void)
   1.494              reprogram_hpet_evt_channel(ch, STIME_MAX, 0, 0);
   1.495      }
   1.496  
   1.497 +    if ( hpet_detach_channel )
   1.498 +        hpet_detach_channel(cpu);
   1.499 +
   1.500      spin_unlock_irq(&ch->lock);
   1.501  }
   1.502  
   1.503  int hpet_broadcast_is_available(void)
   1.504  {
   1.505 -    return (hpet_event.event_handler == handle_hpet_broadcast);
   1.506 +    return (legacy_hpet_event.event_handler == handle_hpet_broadcast
   1.507 +            || num_hpets_used > 0);
   1.508  }
   1.509  
   1.510  int hpet_legacy_irq_tick(void)
   1.511  {
   1.512 -    if ( !hpet_event.event_handler )
   1.513 +    if ( !legacy_hpet_event.event_handler )
   1.514          return 0;
   1.515 -    hpet_event.event_handler(&hpet_event);
   1.516 +    legacy_hpet_event.event_handler(&legacy_hpet_event);
   1.517      return 1;
   1.518  }
   1.519  
     2.1 --- a/xen/arch/x86/msi.c	Fri Mar 20 12:09:20 2009 +0000
     2.2 +++ b/xen/arch/x86/msi.c	Fri Mar 20 12:33:55 2009 +0000
     2.3 @@ -116,7 +116,7 @@ static void msix_put_fixmap(struct pci_d
     2.4  /*
     2.5   * MSI message composition
     2.6   */
     2.7 -static void msi_compose_msg(struct pci_dev *pdev, int vector,
     2.8 +void msi_compose_msg(struct pci_dev *pdev, int vector,
     2.9                              struct msi_msg *msg)
    2.10  {
    2.11      unsigned dest;
     3.1 --- a/xen/arch/x86/time.c	Fri Mar 20 12:09:20 2009 +0000
     3.2 +++ b/xen/arch/x86/time.c	Fri Mar 20 12:33:55 2009 +0000
     3.3 @@ -1233,24 +1233,19 @@ void __init early_time_init(void)
     3.4      setup_irq(0, &irq0);
     3.5  }
     3.6  
     3.7 -/* force_hpet_broadcast: if true, force using hpet_broadcast to fix lapic stop
     3.8 -   issue for deep C state with pit disabled */
     3.9 -static int force_hpet_broadcast;
    3.10 -boolean_param("hpetbroadcast", force_hpet_broadcast);
    3.11 -
    3.12  /* keep pit enabled for pit_broadcast working while cpuidle enabled */
    3.13  static int disable_pit_irq(void)
    3.14  {
    3.15 -    if ( using_pit || !cpu_has_apic || (xen_cpuidle && !force_hpet_broadcast) )
    3.16 +    if ( using_pit || !cpu_has_apic )
    3.17          return 0;
    3.18  
    3.19      /*
    3.20       * If we do not rely on PIT CH0 then we can use HPET for one-shot timer 
    3.21       * emulation when entering deep C states.
    3.22       * XXX dom0 may rely on RTC interrupt delivery, so only enable
    3.23 -     * hpet_broadcast if force_hpet_broadcast.
    3.24 +     * hpet_broadcast if FSB mode available or if force_hpet_broadcast.
    3.25       */
    3.26 -    if ( xen_cpuidle && force_hpet_broadcast )
    3.27 +    if ( xen_cpuidle )
    3.28      {
    3.29          hpet_broadcast_init();
    3.30          if ( !hpet_broadcast_is_available() )
     4.1 --- a/xen/include/asm-x86/hpet.h	Fri Mar 20 12:09:20 2009 +0000
     4.2 +++ b/xen/include/asm-x86/hpet.h	Fri Mar 20 12:33:55 2009 +0000
     4.3 @@ -47,6 +47,11 @@
     4.4  #define HPET_TN_PERIODIC_CAP	0x010
     4.5  #define HPET_TN_SETVAL		0x040
     4.6  #define HPET_TN_32BIT		0x100
     4.7 +#define HPET_TN_ROUTE		0x3e00
     4.8 +#define HPET_TN_FSB		0x4000
     4.9 +#define HPET_TN_FSB_CAP		0x8000
    4.10 +#define HPET_TN_ROUTE_SHIFT	9
    4.11 +
    4.12  
    4.13  #define hpet_read32(x)    \
    4.14      (*(volatile u32 *)(fix_to_virt(FIX_HPET_BASE) + (x)))