aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2013-01-08 10:18:59 +0100
committerJan Beulich <jbeulich@suse.com>2013-01-08 10:18:59 +0100
commite4668268816d9f58b10fe9bf0111120e64c0ad32 (patch)
tree34d0e388ec78dc7043aaad8022c827b33b91f8d4
parentd1f99b7bedf3c7edf7d3c68b88faad09f8fd6e84 (diff)
downloadxen-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.c18
-rw-r--r--xen/include/asm-x86/hpet.h1
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