mirror of
https://git.proxmox.com/git/pve-qemu
synced 2025-08-18 05:56:58 +00:00

As reported in the community forum [0][1], QEMU processes for Linux guests would consume more CPU on the host after an update to QEMU 9.2. The issue was reproduced and bisecting pointed to QEMU commit f0ccf77078 ("hpet: fix and cleanup persistence of interrupt status"). Some quick experimentation suggests that in particular the last part is responsible for the issue: > - the timer must be kept running even if not enabled, in > order to set the ISR flag, so writes to HPET_TN_CFG must > not call hpet_del_timer() Users confirmed that setting the hpet=off machine flag works around the issue[0]. For Windows (7 or later) guests, the flag is already disabled, because of issues in the past [2]. Upstream suggested reverting the relevant patches for now [3], because other issues were reported too. All except commit 5895879aca ("hpet: remove unnecessary variable "index"") are actually dependent on each other for cleanly reverting f0ccf77078, and while not strictly required, that one was reverted too for completeness. [0]: https://forum.proxmox.com/threads/163694/ [1]: https://forum.proxmox.com/threads/161849/post-756793 [2]: https://lists.proxmox.com/pipermail/pve-devel/2012-December/004958.html [3]: https://lore.kernel.org/qemu-devel/CABgObfaKJ5NFVKmYLFmu4C0iZZLJJtcWksLCzyA0tBoz0koZ4A@mail.gmail.com/ Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
121 lines
4.7 KiB
Diff
121 lines
4.7 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Fiona Ebner <f.ebner@proxmox.com>
|
|
Date: Wed, 19 Mar 2025 17:31:13 +0100
|
|
Subject: [PATCH] Revert "hpet: fix and cleanup persistence of interrupt
|
|
status"
|
|
|
|
This reverts commit f0ccf770789e48b7a73497b465fdc892d28c1339.
|
|
|
|
Signed-off-by: Fiona Ebner <f.ebner@proxmox.com>
|
|
---
|
|
hw/timer/hpet.c | 60 ++++++++++++++++---------------------------------
|
|
1 file changed, 19 insertions(+), 41 deletions(-)
|
|
|
|
diff --git a/hw/timer/hpet.c b/hw/timer/hpet.c
|
|
index 509986c0a9..402cc960f0 100644
|
|
--- a/hw/timer/hpet.c
|
|
+++ b/hw/timer/hpet.c
|
|
@@ -196,31 +196,21 @@ static void update_irq(struct HPETTimer *timer, int set)
|
|
}
|
|
s = timer->state;
|
|
mask = 1 << timer->tn;
|
|
-
|
|
- if (set && (timer->config & HPET_TN_TYPE_LEVEL)) {
|
|
- /*
|
|
- * If HPET_TN_ENABLE bit is 0, "the timer will still operate and
|
|
- * generate appropriate status bits, but will not cause an interrupt"
|
|
- */
|
|
- s->isr |= mask;
|
|
- } else {
|
|
+ if (!set || !timer_enabled(timer) || !hpet_enabled(timer->state)) {
|
|
s->isr &= ~mask;
|
|
- }
|
|
-
|
|
- if (set && timer_enabled(timer) && hpet_enabled(s)) {
|
|
- if (timer_fsb_route(timer)) {
|
|
- address_space_stl_le(&address_space_memory, timer->fsb >> 32,
|
|
- timer->fsb & 0xffffffff, MEMTXATTRS_UNSPECIFIED,
|
|
- NULL);
|
|
- } else if (timer->config & HPET_TN_TYPE_LEVEL) {
|
|
- qemu_irq_raise(s->irqs[route]);
|
|
- } else {
|
|
- qemu_irq_pulse(s->irqs[route]);
|
|
- }
|
|
- } else {
|
|
if (!timer_fsb_route(timer)) {
|
|
qemu_irq_lower(s->irqs[route]);
|
|
}
|
|
+ } else if (timer_fsb_route(timer)) {
|
|
+ address_space_stl_le(&address_space_memory, timer->fsb >> 32,
|
|
+ timer->fsb & 0xffffffff, MEMTXATTRS_UNSPECIFIED,
|
|
+ NULL);
|
|
+ } else if (timer->config & HPET_TN_TYPE_LEVEL) {
|
|
+ s->isr |= mask;
|
|
+ qemu_irq_raise(s->irqs[route]);
|
|
+ } else {
|
|
+ s->isr &= ~mask;
|
|
+ qemu_irq_pulse(s->irqs[route]);
|
|
}
|
|
}
|
|
|
|
@@ -424,13 +414,8 @@ static void hpet_set_timer(HPETTimer *t)
|
|
|
|
static void hpet_del_timer(HPETTimer *t)
|
|
{
|
|
- HPETState *s = t->state;
|
|
timer_del(t->qemu_timer);
|
|
-
|
|
- if (s->isr & (1 << t->tn)) {
|
|
- /* For level-triggered interrupt, this leaves ISR set but lowers irq. */
|
|
- update_irq(t, 1);
|
|
- }
|
|
+ update_irq(t, 0);
|
|
}
|
|
|
|
static uint64_t hpet_ram_read(void *opaque, hwaddr addr,
|
|
@@ -530,26 +515,20 @@ static void hpet_ram_write(void *opaque, hwaddr addr,
|
|
switch ((addr - 0x100) % 0x20) {
|
|
case HPET_TN_CFG:
|
|
trace_hpet_ram_write_tn_cfg();
|
|
- if (deactivating_bit(old_val, new_val, HPET_TN_TYPE_LEVEL)) {
|
|
- /*
|
|
- * Do this before changing timer->config; otherwise, if
|
|
- * HPET_TN_FSB is set, update_irq will not lower the qemu_irq.
|
|
- */
|
|
+ if (activating_bit(old_val, new_val, HPET_TN_FSB_ENABLE)) {
|
|
update_irq(timer, 0);
|
|
}
|
|
val = hpet_fixup_reg(new_val, old_val, HPET_TN_CFG_WRITE_MASK);
|
|
timer->config = (timer->config & 0xffffffff00000000ULL) | val;
|
|
- if (activating_bit(old_val, new_val, HPET_TN_ENABLE)
|
|
- && (s->isr & (1 << timer_id))) {
|
|
- update_irq(timer, 1);
|
|
- }
|
|
-
|
|
if (new_val & HPET_TN_32BIT) {
|
|
timer->cmp = (uint32_t)timer->cmp;
|
|
timer->period = (uint32_t)timer->period;
|
|
}
|
|
- if (hpet_enabled(s)) {
|
|
+ if (activating_bit(old_val, new_val, HPET_TN_ENABLE) &&
|
|
+ hpet_enabled(s)) {
|
|
hpet_set_timer(timer);
|
|
+ } else if (deactivating_bit(old_val, new_val, HPET_TN_ENABLE)) {
|
|
+ hpet_del_timer(timer);
|
|
}
|
|
break;
|
|
case HPET_TN_CFG + 4: // Interrupt capabilities
|
|
@@ -627,10 +606,9 @@ static void hpet_ram_write(void *opaque, hwaddr addr,
|
|
s->hpet_offset =
|
|
ticks_to_ns(s->hpet_counter) - qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
|
|
for (i = 0; i < s->num_timers; i++) {
|
|
- if (timer_enabled(&s->timer[i]) && (s->isr & (1 << i))) {
|
|
- update_irq(&s->timer[i], 1);
|
|
+ if ((&s->timer[i])->cmp != ~0ULL) {
|
|
+ hpet_set_timer(&s->timer[i]);
|
|
}
|
|
- hpet_set_timer(&s->timer[i]);
|
|
}
|
|
} else if (deactivating_bit(old_val, new_val, HPET_CFG_ENABLE)) {
|
|
/* Halt main counter and disable interrupt generation. */
|