89 lines
3.3 KiB
Diff
89 lines
3.3 KiB
Diff
|
# HG changeset patch
|
||
|
# User Jan Beulich <jbeulich@suse.com>
|
||
|
# Date 1353575003 -3600
|
||
|
# Node ID c139ca92edca2fab8ec95deb7fd9e4246c3fe28d
|
||
|
# Parent af6b72a224e99a4a516fbc2eecc06ada569304e8
|
||
|
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>
|
||
|
|
||
|
--- a/xen/arch/x86/hpet.c
|
||
|
+++ b/xen/arch/x86/hpet.c
|
||
|
@@ -236,7 +236,7 @@ static void hpet_msi_unmask(struct irq_d
|
||
|
struct hpet_event_channel *ch = desc->action->dev_id;
|
||
|
|
||
|
cfg = hpet_read32(HPET_Tn_CFG(ch->idx));
|
||
|
- cfg |= HPET_TN_FSB;
|
||
|
+ cfg |= HPET_TN_ENABLE;
|
||
|
hpet_write32(cfg, HPET_Tn_CFG(ch->idx));
|
||
|
}
|
||
|
|
||
|
@@ -246,7 +246,7 @@ static void hpet_msi_mask(struct irq_des
|
||
|
struct hpet_event_channel *ch = desc->action->dev_id;
|
||
|
|
||
|
cfg = hpet_read32(HPET_Tn_CFG(ch->idx));
|
||
|
- cfg &= ~HPET_TN_FSB;
|
||
|
+ cfg &= ~HPET_TN_ENABLE;
|
||
|
hpet_write32(cfg, HPET_Tn_CFG(ch->idx));
|
||
|
}
|
||
|
|
||
|
@@ -319,8 +319,14 @@ static void __hpet_setup_msi_irq(struct
|
||
|
static int __init hpet_setup_msi_irq(unsigned int irq, struct hpet_event_channel *ch)
|
||
|
{
|
||
|
int ret;
|
||
|
+ 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));
|
||
|
+
|
||
|
desc->handler = &hpet_msi_type;
|
||
|
ret = request_irq(irq, hpet_interrupt_handler, 0, "HPET", ch);
|
||
|
if ( ret < 0 )
|
||
|
@@ -541,11 +547,14 @@ void __init hpet_broadcast_init(void)
|
||
|
|
||
|
for ( i = 0; i < n; i++ )
|
||
|
{
|
||
|
- /* set HPET Tn as oneshot */
|
||
|
- cfg = hpet_read32(HPET_Tn_CFG(hpet_events[i].idx));
|
||
|
- cfg &= ~(HPET_TN_LEVEL | HPET_TN_PERIODIC);
|
||
|
- cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
|
||
|
- hpet_write32(cfg, HPET_Tn_CFG(hpet_events[i].idx));
|
||
|
+ if ( i == 0 && (cfg & HPET_CFG_LEGACY) )
|
||
|
+ {
|
||
|
+ /* set HPET T0 as oneshot */
|
||
|
+ cfg = hpet_read32(HPET_Tn_CFG(0));
|
||
|
+ cfg &= ~(HPET_TN_LEVEL | HPET_TN_PERIODIC);
|
||
|
+ cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
|
||
|
+ hpet_write32(cfg, HPET_Tn_CFG(0));
|
||
|
+ }
|
||
|
|
||
|
/*
|
||
|
* The period is a femto seconds value. We need to calculate the scaled
|
||
|
@@ -602,6 +611,8 @@ void hpet_broadcast_resume(void)
|
||
|
cfg = hpet_read32(HPET_Tn_CFG(hpet_events[i].idx));
|
||
|
cfg &= ~(HPET_TN_LEVEL | HPET_TN_PERIODIC);
|
||
|
cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
|
||
|
+ if ( !(hpet_events[i].flags & HPET_EVT_LEGACY) )
|
||
|
+ cfg |= HPET_TN_FSB;
|
||
|
hpet_write32(cfg, HPET_Tn_CFG(hpet_events[i].idx));
|
||
|
|
||
|
hpet_events[i].next_event = STIME_MAX;
|