diff options
-rw-r--r-- | tools/firmware/hvmloader/acpi/static_tables.c | 12 | ||||
-rw-r--r-- | xen/arch/x86/hvm/rtc.c | 19 |
2 files changed, 23 insertions, 8 deletions
diff --git a/tools/firmware/hvmloader/acpi/static_tables.c b/tools/firmware/hvmloader/acpi/static_tables.c index f98c8d2d10..323ae3124c 100644 --- a/tools/firmware/hvmloader/acpi/static_tables.c +++ b/tools/firmware/hvmloader/acpi/static_tables.c @@ -136,11 +136,15 @@ struct acpi_20_rsdp Rsdp = { .length = sizeof(struct acpi_20_rsdp) }; -#define ACPI_WAET_RTC_GOOD 0x00000001 -#define ACPI_WAET_PM_TIMER_GOOD 0x00000002 +#define ACPI_WAET_RTC_NO_ACK (1<<0) /* RTC requires no int acknowledge */ +#define ACPI_WAET_TIMER_ONE_READ (1<<1) /* PM timer requires only one read */ -#define ACPI_WAET_FLAGS (ACPI_WAET_RTC_GOOD | \ - ACPI_WAET_PM_TIMER_GOOD) +/* + * The state of the RTC flag getting passed to the guest must be in + * sync with the mode selection in the hypervisor RTC emulation code. + */ +#define ACPI_WAET_FLAGS (ACPI_WAET_RTC_NO_ACK | \ + ACPI_WAET_TIMER_ONE_READ) struct acpi_20_waet Waet = { .header = { diff --git a/xen/arch/x86/hvm/rtc.c b/xen/arch/x86/hvm/rtc.c index 77b380f287..d1a6848fbb 100644 --- a/xen/arch/x86/hvm/rtc.c +++ b/xen/arch/x86/hvm/rtc.c @@ -45,6 +45,15 @@ #define epoch_year 1900 #define get_year(x) (x + epoch_year) +enum rtc_mode { + rtc_mode_no_ack, + rtc_mode_strict +}; + +/* This must be in sync with how hvmloader sets the ACPI WAET flags. */ +#define mode_is(d, m) ((void)(d), rtc_mode_##m == rtc_mode_no_ack) +#define rtc_mode_is(s, m) mode_is(vrtc_domain(s), m) + static void rtc_copy_date(RTCState *s); static void rtc_set_time(RTCState *s); static inline int from_bcd(RTCState *s, int a); @@ -54,7 +63,7 @@ static void rtc_update_irq(RTCState *s) { ASSERT(spin_is_locked(&s->lock)); - if ( s->hw.cmos_data[RTC_REG_C] & RTC_IRQF ) + if ( rtc_mode_is(s, strict) && (s->hw.cmos_data[RTC_REG_C] & RTC_IRQF) ) return; /* IRQ is raised if any source is both raised & enabled */ @@ -64,6 +73,8 @@ static void rtc_update_irq(RTCState *s) return; s->hw.cmos_data[RTC_REG_C] |= RTC_IRQF; + if ( rtc_mode_is(s, no_ack) ) + hvm_isa_irq_deassert(vrtc_domain(s), RTC_IRQ); hvm_isa_irq_assert(vrtc_domain(s), RTC_IRQ); } @@ -73,8 +84,8 @@ bool_t rtc_periodic_interrupt(void *opaque) bool_t ret; spin_lock(&s->lock); - ret = !(s->hw.cmos_data[RTC_REG_C] & RTC_IRQF); - if ( !(s->hw.cmos_data[RTC_REG_C] & RTC_PF) ) + ret = rtc_mode_is(s, no_ack) || !(s->hw.cmos_data[RTC_REG_C] & RTC_IRQF); + if ( rtc_mode_is(s, no_ack) || !(s->hw.cmos_data[RTC_REG_C] & RTC_PF) ) { s->hw.cmos_data[RTC_REG_C] |= RTC_PF; rtc_update_irq(s); @@ -633,7 +644,7 @@ static uint32_t rtc_ioport_read(RTCState *s, uint32_t addr) case RTC_REG_C: ret = s->hw.cmos_data[s->hw.cmos_index]; s->hw.cmos_data[RTC_REG_C] = 0x00; - if ( ret & RTC_IRQF ) + if ( (ret & RTC_IRQF) && !rtc_mode_is(s, no_ack) ) hvm_isa_irq_deassert(d, RTC_IRQ); rtc_update_irq(s); check_update_timer(s); |