diff options
author | Jan Beulich <jbeulich@suse.com> | 2013-01-08 10:18:59 +0100 |
---|---|---|
committer | Jan Beulich <jbeulich@suse.com> | 2013-01-08 10:18:59 +0100 |
commit | e4668268816d9f58b10fe9bf0111120e64c0ad32 (patch) | |
tree | 34d0e388ec78dc7043aaad8022c827b33b91f8d4 | |
parent | d1f99b7bedf3c7edf7d3c68b88faad09f8fd6e84 (diff) | |
download | xen-e4668268816d9f58b10fe9bf0111120e64c0ad32.tar.gz xen-e4668268816d9f58b10fe9bf0111120e64c0ad32.tar.bz2 xen-e4668268816d9f58b10fe9bf0111120e64c0ad32.zip |
x86/HPET: fix FSB interrupt masking
HPET_TN_FSB is not really suitable for masking interrupts - it merely
switches between the two delivery methods. The right way of masking is
through the HPET_TN_ENABLE bit (which really is an interrupt enable,
not a counter enable or some such). This is even more so with certain
chip sets not even allowing HPET_TN_FSB to be cleared on some of the
channels.
Further, all the setup of the channel should happen before actually
enabling the interrupt, which requires splitting legacy and FSB logic.
Finally this also fixes an S3 resume problem (HPET_TN_FSB did not get
set in hpet_broadcast_resume(), and hpet_msi_unmask() doesn't get
called from the general resume code either afaict).
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Keir Fraser <keir@xen.org>
xen-unstable changeset: 26183:c139ca92edca
xen-unstable date: Thu Nov 22 09:03:23 UTC 2012
-rw-r--r-- | xen/arch/x86/hpet.c | 18 | ||||
-rw-r--r-- | xen/include/asm-x86/hpet.h | 1 |
2 files changed, 10 insertions, 9 deletions
diff --git a/xen/arch/x86/hpet.c b/xen/arch/x86/hpet.c index 7ee7730c20..87a4cb42d1 100644 --- a/xen/arch/x86/hpet.c +++ b/xen/arch/x86/hpet.c @@ -262,7 +262,7 @@ static void hpet_msi_unmask(unsigned int irq) ch = &hpet_events[ch_idx]; cfg = hpet_read32(HPET_Tn_CFG(ch->idx)); - cfg |= HPET_TN_FSB; + cfg |= HPET_TN_ENABLE; hpet_write32(cfg, HPET_Tn_CFG(ch->idx)); } @@ -276,7 +276,7 @@ static void hpet_msi_mask(unsigned int irq) ch = &hpet_events[ch_idx]; cfg = hpet_read32(HPET_Tn_CFG(ch->idx)); - cfg &= ~HPET_TN_FSB; + cfg &= ~HPET_TN_ENABLE; hpet_write32(cfg, HPET_Tn_CFG(ch->idx)); } @@ -367,8 +367,14 @@ static int hpet_setup_msi_irq(unsigned int irq) int ret; struct msi_msg msg; struct hpet_event_channel *ch = &hpet_events[irq_to_channel(irq)]; + u32 cfg = hpet_read32(HPET_Tn_CFG(ch->idx)); irq_desc_t *desc = irq_to_desc(irq); + /* set HPET Tn as oneshot */ + cfg &= ~(HPET_TN_LEVEL | HPET_TN_PERIODIC); + cfg |= HPET_TN_FSB | HPET_TN_32BIT; + hpet_write32(cfg, HPET_Tn_CFG(ch->idx)); + if ( desc->handler == &no_irq_type ) { desc->handler = &hpet_msi_type; @@ -593,12 +599,6 @@ void hpet_broadcast_init(void) 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; @@ -626,7 +626,7 @@ void hpet_broadcast_init(void) /* set HPET T0 as oneshot */ cfg = hpet_read32(HPET_T0_CFG); - cfg &= ~HPET_TN_PERIODIC; + cfg &= ~(HPET_TN_LEVEL | HPET_TN_PERIODIC); cfg |= HPET_TN_ENABLE | HPET_TN_32BIT; hpet_write32(cfg, HPET_T0_CFG); diff --git a/xen/include/asm-x86/hpet.h b/xen/include/asm-x86/hpet.h index 2f18ba0283..22a1c2900a 100644 --- a/xen/include/asm-x86/hpet.h +++ b/xen/include/asm-x86/hpet.h @@ -42,6 +42,7 @@ #define HPET_LEGACY_8254 2 #define HPET_LEGACY_RTC 8 +#define HPET_TN_LEVEL 0x002 #define HPET_TN_ENABLE 0x004 #define HPET_TN_PERIODIC 0x008 #define HPET_TN_PERIODIC_CAP 0x010 |