From: Igor Mammedov <imammedo@redhat.com>
To: kvm@vger.kernel.org
Cc: pbonzini@redhat.com
Subject: [kvm-unit-tests PATCH 1/2] x86/apic: separate reporting from actual measurements
Date: Tue, 28 Apr 2026 15:35:23 +0200 [thread overview]
Message-ID: <20260428133524.3628482-2-imammedo@redhat.com> (raw)
In-Reply-To: <20260428133524.3628482-1-imammedo@redhat.com>
Move report() calls to the end of the function so that serial I/O
does not interfere with timer measurements.
While at it, wrap the test body in a for loop as preparation
for adding retry logic to deal with failures due to large
enough vCPU stalls.
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
x86/apic.c | 109 +++++++++++++++++++++++++++++++----------------------
1 file changed, 63 insertions(+), 46 deletions(-)
diff --git a/x86/apic.c b/x86/apic.c
index 0a52e9a4..d4eb8e11 100644
--- a/x86/apic.c
+++ b/x86/apic.c
@@ -573,62 +573,79 @@ static inline void apic_change_mode(unsigned long new_mode)
static void test_apic_change_mode(void)
{
- uint32_t tmict = 0x999999;
+ const uint32_t tmict_values[] = {
+ 0x999999, /* ~10ms */
+ };
+ int retry, max_retries = ARRAY_SIZE(tmict_values);
+ uint32_t tmict;
+ bool tmict_reset = false, o_nonzero = false, o_reached_zero = false;
+ bool p_nonzero = false, p_not_reset = false, p_after_wrap = false;
+ bool p2o_not_reset = false, p2o_reached_zero = false, p2o_stay_zero = false;
printf("starting apic change mode\n");
- apic_write(APIC_TMICT, tmict);
+ for (retry = 0; retry < max_retries; retry++) {
+ tmict = tmict_values[retry];
+ apic_write(APIC_TMICT, tmict);
+ apic_change_mode(APIC_LVT_TIMER_PERIODIC);
+ tmict_reset = apic_read(APIC_TMICT) == tmict;
- apic_change_mode(APIC_LVT_TIMER_PERIODIC);
+ /* Testing one-shot */
+ apic_change_mode(APIC_LVT_TIMER_ONESHOT);
+ apic_write(APIC_TMICT, tmict);
+ o_nonzero = apic_read(APIC_TMCCT);
- report(apic_read(APIC_TMICT) == tmict, "TMICT value reset");
+ wait_until_tmcct_is_zero(tmict, false);
+ o_reached_zero = !apic_read(APIC_TMCCT);
- /* Testing one-shot */
- apic_change_mode(APIC_LVT_TIMER_ONESHOT);
- apic_write(APIC_TMICT, tmict);
- report(apic_read(APIC_TMCCT), "TMCCT should have a non-zero value");
+ /*
+ * Write TMICT before changing mode from one-shot to periodic
+ * TMCCT should be reset to TMICT periodicly
+ */
+ apic_write(APIC_TMICT, tmict);
+ wait_until_tmcct_is_zero(tmict, true);
+ apic_change_mode(APIC_LVT_TIMER_PERIODIC);
+ p_nonzero = apic_read(APIC_TMCCT);
- wait_until_tmcct_is_zero(tmict, false);
- report(!apic_read(APIC_TMCCT), "TMCCT should have reached 0");
+ /*
+ * After the change of mode, the counter should not be reset
+ * and continue counting down from where it was
+ */
+ p_not_reset = apic_read(APIC_TMCCT) < (tmict / 2);
+ /*
+ * Specifically wait for timer wrap around and skip 0.
+ * Under KVM lapic there is a possibility that a small amount
+ * of consecutive TMCCR reads return 0 while hrtimer is reset
+ * in an async callback
+ */
+ wait_until_tmcct_wrap_around(tmict, false);
+ p_after_wrap = apic_read(APIC_TMCCT) > (tmict / 2);
- /*
- * Write TMICT before changing mode from one-shot to periodic TMCCT should
- * be reset to TMICT periodicly
- */
- apic_write(APIC_TMICT, tmict);
- wait_until_tmcct_is_zero(tmict, true);
- apic_change_mode(APIC_LVT_TIMER_PERIODIC);
- report(apic_read(APIC_TMCCT), "TMCCT should have a non-zero value");
+ wait_until_tmcct_is_zero(tmict, true);
+ /*
+ * Keep the same TMICT and change timer mode to one-shot
+ * TMCCT should be > 0 and count-down to 0
+ */
+ apic_change_mode(APIC_LVT_TIMER_ONESHOT);
+ p2o_not_reset = apic_read(APIC_TMCCT) < (tmict / 2);
- /*
- * After the change of mode, the counter should not be reset and continue
- * counting down from where it was
- */
- report(apic_read(APIC_TMCCT) < (tmict / 2),
- "TMCCT should not be reset to TMICT value");
- /*
- * Specifically wait for timer wrap around and skip 0.
- * Under KVM lapic there is a possibility that a small amount of consecutive
- * TMCCR reads return 0 while hrtimer is reset in an async callback
- */
- wait_until_tmcct_wrap_around(tmict, false);
- report(apic_read(APIC_TMCCT) > (tmict / 2),
- "TMCCT should be reset to the initial-count");
+ wait_until_tmcct_is_zero(tmict, false);
+ p2o_reached_zero = !apic_read(APIC_TMCCT);
- wait_until_tmcct_is_zero(tmict, true);
- /*
- * Keep the same TMICT and change timer mode to one-shot
- * TMCCT should be > 0 and count-down to 0
- */
- apic_change_mode(APIC_LVT_TIMER_ONESHOT);
- report(apic_read(APIC_TMCCT) < (tmict / 2),
- "TMCCT should not be reset to init");
- wait_until_tmcct_is_zero(tmict, false);
- report(!apic_read(APIC_TMCCT), "TMCCT should have reach zero");
-
- /* now tmcct == 0 and tmict != 0 */
- apic_change_mode(APIC_LVT_TIMER_PERIODIC);
- report(!apic_read(APIC_TMCCT), "TMCCT should stay at zero");
+ /* now tmcct == 0 and tmict != 0 */
+ apic_change_mode(APIC_LVT_TIMER_PERIODIC);
+ p2o_stay_zero = !apic_read(APIC_TMCCT);
+ }
+
+ report(tmict_reset, "TMICT value reset");
+ report(o_nonzero, "one-shot: TMCCT should have a non-zero value");
+ report(o_reached_zero, "one-shot: TMCCT should have reached 0");
+ report(p_nonzero, "periodic: TMCCT should have a non-zero value");
+ report(p_not_reset, "TMCCT should not be reset to TMICT value");
+ report(p_after_wrap, "TMCCT should be reset to the initial-count");
+ report(p2o_not_reset, "TMCCT should not be reset to init");
+ report(p2o_reached_zero, "TMCCT should have reach zero");
+ report(p2o_stay_zero, "TMCCT should stay at zero");
}
#define KVM_HC_SEND_IPI 10
--
2.47.3
next prev parent reply other threads:[~2026-04-28 13:35 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-04-28 13:35 [kvm-unit-tests PATCH 0/2] x86/apic: fix false test_apic_change_mode failures on stalled vCPUs Igor Mammedov
2026-04-28 13:35 ` Igor Mammedov [this message]
2026-04-28 13:35 ` [kvm-unit-tests PATCH 2/2] x86/apic: add retry logic to test_apic_change_mode Igor Mammedov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260428133524.3628482-2-imammedo@redhat.com \
--to=imammedo@redhat.com \
--cc=kvm@vger.kernel.org \
--cc=pbonzini@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox