diff options
author | Jan Beulich <jbeulich@novell.com> | 2011-03-12 13:19:34 +0000 |
---|---|---|
committer | Jan Beulich <jbeulich@novell.com> | 2011-03-12 13:19:34 +0000 |
commit | b927089900d45335c861e49cfb4e66a8d8c8ccea (patch) | |
tree | 788aefe3c1cd04e72a7c36a72a26d0d8c11fc909 /xen/arch/x86/hpet.c | |
parent | 8fb98708308bec25d9e80c7ebe0360cb95fc11f9 (diff) | |
download | xen-b927089900d45335c861e49cfb4e66a8d8c8ccea.tar.gz xen-b927089900d45335c861e49cfb4e66a8d8c8ccea.tar.bz2 xen-b927089900d45335c861e49cfb4e66a8d8c8ccea.zip |
x86/HPET: cleanup
- separate init and resume code paths (so that the [larger] init parts
can go init .init.* sections)
- drop the separate legacy_hpet_event object, as we can easily re-use
the first slot of hpet_events[] for that purpose (the whole array is
otherwise unused when the legacy code is being used)
- use section placement attributes where reasonable
Signed-off-by: Jan Beulich <jbeulich@novell.com>
Acked-by: Wei Gang <gang.wei@intel.com>
Diffstat (limited to 'xen/arch/x86/hpet.c')
-rw-r--r-- | xen/arch/x86/hpet.c | 274 |
1 files changed, 155 insertions, 119 deletions
diff --git a/xen/arch/x86/hpet.c b/xen/arch/x86/hpet.c index 6fc7a35586..42a2879c76 100644 --- a/xen/arch/x86/hpet.c +++ b/xen/arch/x86/hpet.c @@ -27,6 +27,8 @@ #define HPET_EVT_USED (1 << HPET_EVT_USED_BIT) #define HPET_EVT_DISABLE_BIT 1 #define HPET_EVT_DISABLE (1 << HPET_EVT_DISABLE_BIT) +#define HPET_EVT_LEGACY_BIT 2 +#define HPET_EVT_LEGACY (1 << HPET_EVT_LEGACY_BIT) struct hpet_event_channel { @@ -54,18 +56,18 @@ struct hpet_event_channel int irq; /* msi irq */ unsigned int flags; /* HPET_EVT_x */ } __cacheline_aligned; -static struct hpet_event_channel legacy_hpet_event; static struct hpet_event_channel hpet_events[MAX_HPET_NUM] = { [0 ... MAX_HPET_NUM-1].irq = -1 }; -static unsigned int num_hpets_used; /* msi hpet channels used for broadcast */ -DEFINE_PER_CPU(struct hpet_event_channel *, cpu_bc_channel); +/* msi hpet channels used for broadcast */ +static unsigned int __read_mostly num_hpets_used; -static int *irq_channel; +DEFINE_PER_CPU(struct hpet_event_channel *, cpu_bc_channel); +static int *__read_mostly irq_channel; #define irq_to_channel(irq) irq_channel[irq] -unsigned long hpet_address; +unsigned long __read_mostly hpet_address; /* * force_hpet_broadcast: by default legacy hpet broadcast will be stopped @@ -362,58 +364,50 @@ static hw_irq_controller hpet_msi_type = { .set_affinity = hpet_msi_set_affinity, }; -static int hpet_setup_msi_irq(unsigned int irq) +static void __hpet_setup_msi_irq(unsigned int irq) { - int ret; struct msi_msg msg; - struct hpet_event_channel *ch = &hpet_events[irq_to_channel(irq)]; - irq_desc_t *desc = irq_to_desc(irq); - - if ( desc->handler == &no_irq_type ) - { - desc->handler = &hpet_msi_type; - ret = request_irq(irq, hpet_interrupt_handler, - 0, "HPET", ch); - if ( ret < 0 ) - return ret; - } - else if ( desc->handler != &hpet_msi_type ) - { - return -EINVAL; - } msi_compose_msg(NULL, irq, &msg); hpet_msi_write(irq, &msg); +} + +static int __init hpet_setup_msi_irq(unsigned int irq) +{ + int ret; + irq_desc_t *desc = irq_to_desc(irq); + + desc->handler = &hpet_msi_type; + ret = request_irq(irq, hpet_interrupt_handler, + 0, "HPET", hpet_events + irq_channel[irq]); + if ( ret < 0 ) + return ret; + + __hpet_setup_msi_irq(irq); return 0; } -static int hpet_assign_irq(struct hpet_event_channel *ch) +static int __init hpet_assign_irq(unsigned int idx) { - int irq = ch->irq; + int irq; - if ( irq < 0 ) - { - if ( (irq = create_irq()) < 0 ) - return irq; + if ( (irq = create_irq()) < 0 ) + return irq; - irq_channel[irq] = ch - &hpet_events[0]; - ch->irq = irq; - } + irq_channel[irq] = idx; - /* hpet_setup_msi_irq should also be called for S3 resuming */ if ( hpet_setup_msi_irq(irq) ) { destroy_irq(irq); irq_channel[irq] = -1; - ch->irq = -1; return -EINVAL; } - return 0; + return irq; } -static int hpet_fsb_cap_lookup(void) +static int __init hpet_fsb_cap_lookup(void) { unsigned int id; unsigned int num_chs, num_chs_used; @@ -445,7 +439,7 @@ static int hpet_fsb_cap_lookup(void) ch->flags = 0; ch->idx = i; - if ( hpet_assign_irq(ch) ) + if ( (ch->irq = hpet_assign_irq(num_chs_used)) < 0 ) continue; num_chs_used++; @@ -468,7 +462,7 @@ static struct hpet_event_channel *hpet_get_channel(int cpu) struct hpet_event_channel *ch; if ( num_hpets_used == 0 ) - return &legacy_hpet_event; + return hpet_events; spin_lock(&next_lock); next = next_channel = (next_channel + 1) % num_hpets_used; @@ -536,7 +530,7 @@ static void hpet_detach_channel(int cpu, struct hpet_event_channel *ch) #include <asm/mc146818rtc.h> -void (*pv_rtc_handler)(unsigned int port, uint8_t value); +void (*__read_mostly pv_rtc_handler)(unsigned int port, uint8_t value); static void handle_rtc_once(unsigned int port, uint8_t value) { @@ -559,87 +553,114 @@ static void handle_rtc_once(unsigned int port, uint8_t value) } } -void hpet_broadcast_init(void) +void __init hpet_broadcast_init(void) { - u64 hpet_rate; + u64 hpet_rate = hpet_setup(); u32 hpet_id, cfg; - int i; + unsigned int i, n; - if ( irq_channel == NULL ) - { - irq_channel = xmalloc_array(int, nr_irqs); - BUG_ON(irq_channel == NULL); - for ( i = 0; i < nr_irqs; i++ ) - irq_channel[i] = -1; - } - - hpet_rate = hpet_setup(); if ( hpet_rate == 0 ) return; + irq_channel = xmalloc_array(int, nr_irqs); + BUG_ON(irq_channel == NULL); + for ( i = 0; i < nr_irqs; i++ ) + irq_channel[i] = -1; + + cfg = hpet_read32(HPET_CFG); + num_hpets_used = hpet_fsb_cap_lookup(); if ( num_hpets_used > 0 ) { /* Stop HPET legacy interrupts */ - cfg = hpet_read32(HPET_CFG); cfg &= ~HPET_CFG_LEGACY; - hpet_write32(cfg, HPET_CFG); + n = num_hpets_used; + } + else + { + xfree(irq_channel); + irq_channel = NULL; - for ( i = 0; i < num_hpets_used; i++ ) - { - /* set HPET Tn as oneshot */ - cfg = hpet_read32(HPET_Tn_CFG(hpet_events[i].idx)); - cfg &= ~HPET_TN_PERIODIC; - cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; - hpet_write32(cfg, HPET_Tn_CFG(hpet_events[i].idx)); - - hpet_events[i].mult = div_sc((unsigned long)hpet_rate, - 1000000000ul, 32); - hpet_events[i].shift = 32; - hpet_events[i].next_event = STIME_MAX; - spin_lock_init(&hpet_events[i].lock); - rwlock_init(&hpet_events[i].cpumask_lock); - wmb(); - hpet_events[i].event_handler = handle_hpet_broadcast; - } + hpet_id = hpet_read32(HPET_ID); + if ( !(hpet_id & HPET_ID_LEGSUP) ) + return; - return; + /* Start HPET legacy interrupts */ + cfg |= HPET_CFG_LEGACY; + n = 1; + hpet_events->idx = 0; + + if ( !force_hpet_broadcast ) + pv_rtc_handler = handle_rtc_once; } - if ( legacy_hpet_event.flags & HPET_EVT_DISABLE ) - return; + hpet_write32(cfg, HPET_CFG); - hpet_id = hpet_read32(HPET_ID); - if ( !(hpet_id & HPET_ID_LEGSUP) ) - return; + for ( i = 0; i < n; i++ ) + { + /* set HPET Tn as oneshot */ + cfg = hpet_read32(HPET_Tn_CFG(hpet_events[i].idx)); + cfg &= ~HPET_TN_PERIODIC; + cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; + hpet_write32(cfg, HPET_Tn_CFG(hpet_events[i].idx)); + + /* + * The period is a femto seconds value. We need to calculate the scaled + * math multiplication factor for nanosecond to hpet tick conversion. + */ + hpet_events[i].mult = div_sc((unsigned long)hpet_rate, + 1000000000ul, 32); + hpet_events[i].shift = 32; + hpet_events[i].next_event = STIME_MAX; + spin_lock_init(&hpet_events[i].lock); + rwlock_init(&hpet_events[i].cpumask_lock); + wmb(); + hpet_events[i].event_handler = handle_hpet_broadcast; + } + + if ( !num_hpets_used ) + hpet_events->flags = HPET_EVT_LEGACY; +} + +void hpet_broadcast_resume(void) +{ + u32 cfg; + unsigned int i, n; + + hpet_resume(); - /* Start HPET legacy interrupts */ cfg = hpet_read32(HPET_CFG); - cfg |= HPET_CFG_LEGACY; + + if ( num_hpets_used > 0 ) + { + /* Stop HPET legacy interrupts */ + cfg &= ~HPET_CFG_LEGACY; + n = num_hpets_used; + } + else if ( hpet_events->flags & HPET_EVT_DISABLE ) + return; + else + { + /* Start HPET legacy interrupts */ + cfg |= HPET_CFG_LEGACY; + n = 1; + } + hpet_write32(cfg, HPET_CFG); - /* set HPET T0 as oneshot */ - cfg = hpet_read32(HPET_T0_CFG); - cfg &= ~HPET_TN_PERIODIC; - cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; - hpet_write32(cfg, HPET_T0_CFG); + for ( i = 0; i < n; i++ ) + { + if ( hpet_events[i].irq >= 0 ) + __hpet_setup_msi_irq(hpet_events[i].irq); - /* - * The period is a femto seconds value. We need to calculate the scaled - * math multiplication factor for nanosecond to hpet tick conversion. - */ - legacy_hpet_event.mult = div_sc((unsigned long)hpet_rate, 1000000000ul, 32); - legacy_hpet_event.shift = 32; - legacy_hpet_event.next_event = STIME_MAX; - legacy_hpet_event.idx = 0; - legacy_hpet_event.flags = 0; - spin_lock_init(&legacy_hpet_event.lock); - rwlock_init(&legacy_hpet_event.cpumask_lock); - wmb(); - legacy_hpet_event.event_handler = handle_hpet_broadcast; + /* set HPET Tn as oneshot */ + cfg = hpet_read32(HPET_Tn_CFG(hpet_events[i].idx)); + cfg &= ~HPET_TN_PERIODIC; + cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; + hpet_write32(cfg, HPET_Tn_CFG(hpet_events[i].idx)); - if ( !force_hpet_broadcast ) - pv_rtc_handler = handle_rtc_once; + hpet_events[i].next_event = STIME_MAX; + } } void hpet_disable_legacy_broadcast(void) @@ -647,21 +668,24 @@ void hpet_disable_legacy_broadcast(void) u32 cfg; unsigned long flags; - spin_lock_irqsave(&legacy_hpet_event.lock, flags); + if ( !(hpet_events->flags & HPET_EVT_LEGACY) ) + return; - legacy_hpet_event.flags |= HPET_EVT_DISABLE; + spin_lock_irqsave(&hpet_events->lock, flags); + + hpet_events->flags |= HPET_EVT_DISABLE; /* disable HPET T0 */ - cfg = hpet_read32(HPET_T0_CFG); + cfg = hpet_read32(HPET_Tn_CFG(0)); cfg &= ~HPET_TN_ENABLE; - hpet_write32(cfg, HPET_T0_CFG); + hpet_write32(cfg, HPET_Tn_CFG(0)); /* Stop HPET legacy interrupts */ cfg = hpet_read32(HPET_CFG); cfg &= ~HPET_CFG_LEGACY; hpet_write32(cfg, HPET_CFG); - spin_unlock_irqrestore(&legacy_hpet_event.lock, flags); + spin_unlock_irqrestore(&hpet_events->lock, flags); smp_send_event_check_mask(&cpu_online_map); } @@ -679,7 +703,7 @@ void hpet_broadcast_enter(void) ASSERT(!local_irq_is_enabled()); - if ( ch != &legacy_hpet_event ) + if ( !(ch->flags & HPET_EVT_LEGACY) ) { spin_lock(&ch->lock); hpet_attach_channel(cpu, ch); @@ -717,7 +741,7 @@ void hpet_broadcast_exit(void) cpu_clear(cpu, ch->cpumask); read_unlock_irq(&ch->cpumask_lock); - if ( ch != &legacy_hpet_event ) + if ( !(ch->flags & HPET_EVT_LEGACY) ) { spin_lock_irq(&ch->lock); hpet_detach_channel(cpu, ch); @@ -727,7 +751,7 @@ void hpet_broadcast_exit(void) int hpet_broadcast_is_available(void) { - return (legacy_hpet_event.event_handler == handle_hpet_broadcast + return ((hpet_events->flags & HPET_EVT_LEGACY) || num_hpets_used > 0); } @@ -735,22 +759,20 @@ int hpet_legacy_irq_tick(void) { this_cpu(irq_count)--; - if ( !legacy_hpet_event.event_handler ) + if ( (hpet_events->flags & (HPET_EVT_DISABLE|HPET_EVT_LEGACY)) != + HPET_EVT_LEGACY ) return 0; - legacy_hpet_event.event_handler(&legacy_hpet_event); + hpet_events->event_handler(hpet_events); return 1; } -u64 hpet_setup(void) +u64 __init hpet_setup(void) { - static u64 hpet_rate; - static u32 system_reset_latch; - u32 hpet_id, hpet_period, cfg; - int i; + static u64 __initdata hpet_rate; + u32 hpet_id, hpet_period; - if ( system_reset_latch == system_reset_counter ) + if ( hpet_rate ) return hpet_rate; - system_reset_latch = system_reset_counter; if ( hpet_address == 0 ) return 0; @@ -772,10 +794,29 @@ u64 hpet_setup(void) return 0; } + hpet_resume(); + + hpet_rate = 1000000000000000ULL; /* 10^15 */ + (void)do_div(hpet_rate, hpet_period); + + return hpet_rate; +} + +void hpet_resume(void) +{ + static u32 system_reset_latch; + u32 hpet_id, cfg; + unsigned int i; + + if ( system_reset_latch == system_reset_counter ) + return; + system_reset_latch = system_reset_counter; + cfg = hpet_read32(HPET_CFG); cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY); hpet_write32(cfg, HPET_CFG); + hpet_id = hpet_read32(HPET_ID); for ( i = 0; i <= ((hpet_id >> 8) & 31); i++ ) { cfg = hpet_read32(HPET_Tn_CFG(i)); @@ -786,9 +827,4 @@ u64 hpet_setup(void) cfg = hpet_read32(HPET_CFG); cfg |= HPET_CFG_ENABLE; hpet_write32(cfg, HPET_CFG); - - hpet_rate = 1000000000000000ULL; /* 10^15 */ - (void)do_div(hpet_rate, hpet_period); - - return hpet_rate; } |