From: Andrew Cooper <andrew.cooper3@citrix.com>
To: Xen-devel <xen-devel@lists.xenproject.org>
Cc: "Andrew Cooper" <andrew.cooper3@citrix.com>,
"Jan Beulich" <JBeulich@suse.com>,
"Roger Pau Monné" <roger.pau@citrix.com>, "Wei Liu" <wl@xen.org>,
"Ian Jackson" <iwj@xenproject.org>,
"Marek Marczykowski-Górecki" <marmarek@invisiblethingslab.com>,
"Frédéric Pierret" <frederic.pierret@qubes-os.org>
Subject: [PATCH v2 1/3] x86/hpet: Factor hpet_enable_legacy_replacement_mode() out of hpet_setup()
Date: Fri, 26 Mar 2021 18:59:45 +0000 [thread overview]
Message-ID: <20210326185947.23243-2-andrew.cooper3@citrix.com> (raw)
In-Reply-To: <20210326185947.23243-1-andrew.cooper3@citrix.com>
... in preparation to introduce a second caller.
No functional change.
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
---
CC: Jan Beulich <JBeulich@suse.com>
CC: Roger Pau Monné <roger.pau@citrix.com>
CC: Wei Liu <wl@xen.org>
CC: Ian Jackson <iwj@xenproject.org>
CC: Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
CC: Frédéric Pierret <frederic.pierret@qubes-os.org>
For 4.15. Pre-req for trying to unbreak AMD Ryzen 1800X systems.
v2:
* s/u64/uint64_t/
* Drop id local variable
---
xen/arch/x86/hpet.c | 116 ++++++++++++++++++++++++---------------------
xen/include/asm-x86/hpet.h | 6 +++
2 files changed, 68 insertions(+), 54 deletions(-)
diff --git a/xen/arch/x86/hpet.c b/xen/arch/x86/hpet.c
index 1ff005fb4a..c1d04f184f 100644
--- a/xen/arch/x86/hpet.c
+++ b/xen/arch/x86/hpet.c
@@ -754,11 +754,70 @@ int hpet_legacy_irq_tick(void)
}
static u32 *hpet_boot_cfg;
+static uint64_t __initdata hpet_rate;
+
+bool __init hpet_enable_legacy_replacement_mode(void)
+{
+ unsigned int cfg, c0_cfg, ticks, count;
+
+ if ( !hpet_rate ||
+ !(hpet_read32(HPET_ID) & HPET_ID_LEGSUP) ||
+ ((cfg = hpet_read32(HPET_CFG)) & HPET_CFG_LEGACY) )
+ return false;
+
+ /* Stop the main counter. */
+ hpet_write32(cfg & ~HPET_CFG_ENABLE, HPET_CFG);
+
+ /* Reconfigure channel 0 to be 32bit periodic. */
+ c0_cfg = hpet_read32(HPET_Tn_CFG(0));
+ c0_cfg |= (HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL |
+ HPET_TN_32BIT);
+ hpet_write32(c0_cfg, HPET_Tn_CFG(0));
+
+ /*
+ * The exact period doesn't have to match a legacy PIT. All we need
+ * is an interrupt queued up via the IO-APIC to check routing.
+ *
+ * Use HZ as the frequency.
+ */
+ ticks = ((SECONDS(1) / HZ) * div_sc(hpet_rate, SECONDS(1), 32)) >> 32;
+
+ count = hpet_read32(HPET_COUNTER);
+
+ /*
+ * HPET_TN_SETVAL above is atrociously documented in the spec.
+ *
+ * Periodic HPET channels have a main comparator register, and
+ * separate "accumulator" register. Despite being named accumulator
+ * in the spec, this is not an accurate description of its behaviour
+ * or purpose.
+ *
+ * Each time an interrupt is generated, the "accumulator" register is
+ * re-added to the comparator set up the new period.
+ *
+ * Normally, writes to the CMP register update both registers.
+ * However, under these semantics, it is impossible to set up a
+ * periodic timer correctly without the main HPET counter being at 0.
+ *
+ * Instead, HPET_TN_SETVAL is a self-clearing control bit which we can
+ * use for periodic timers to mean that the second write to CMP
+ * updates the accumulator only, and not the absolute comparator
+ * value.
+ *
+ * This lets us set a period when the main counter isn't at 0.
+ */
+ hpet_write32(count + ticks, HPET_Tn_CMP(0));
+ hpet_write32(ticks, HPET_Tn_CMP(0));
+
+ /* Restart the main counter, and legacy mode. */
+ hpet_write32(cfg | HPET_CFG_ENABLE | HPET_CFG_LEGACY, HPET_CFG);
+
+ return true;
+}
u64 __init hpet_setup(void)
{
- static u64 __initdata hpet_rate;
- unsigned int hpet_id, hpet_period, hpet_cfg;
+ unsigned int hpet_id, hpet_period;
unsigned int last, rem;
if ( hpet_rate )
@@ -805,58 +864,7 @@ u64 __init hpet_setup(void)
* Reconfigure the HPET into legacy mode to re-establish the timer
* interrupt.
*/
- if ( hpet_id & HPET_ID_LEGSUP &&
- !((hpet_cfg = hpet_read32(HPET_CFG)) & HPET_CFG_LEGACY) )
- {
- unsigned int c0_cfg, ticks, count;
-
- /* Stop the main counter. */
- hpet_write32(hpet_cfg & ~HPET_CFG_ENABLE, HPET_CFG);
-
- /* Reconfigure channel 0 to be 32bit periodic. */
- c0_cfg = hpet_read32(HPET_Tn_CFG(0));
- c0_cfg |= (HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL |
- HPET_TN_32BIT);
- hpet_write32(c0_cfg, HPET_Tn_CFG(0));
-
- /*
- * The exact period doesn't have to match a legacy PIT. All we need
- * is an interrupt queued up via the IO-APIC to check routing.
- *
- * Use HZ as the frequency.
- */
- ticks = ((SECONDS(1) / HZ) * div_sc(hpet_rate, SECONDS(1), 32)) >> 32;
-
- count = hpet_read32(HPET_COUNTER);
-
- /*
- * HPET_TN_SETVAL above is atrociously documented in the spec.
- *
- * Periodic HPET channels have a main comparator register, and
- * separate "accumulator" register. Despite being named accumulator
- * in the spec, this is not an accurate description of its behaviour
- * or purpose.
- *
- * Each time an interrupt is generated, the "accumulator" register is
- * re-added to the comparator set up the new period.
- *
- * Normally, writes to the CMP register update both registers.
- * However, under these semantics, it is impossible to set up a
- * periodic timer correctly without the main HPET counter being at 0.
- *
- * Instead, HPET_TN_SETVAL is a self-clearing control bit which we can
- * use for periodic timers to mean that the second write to CMP
- * updates the accumulator only, and not the absolute comparator
- * value.
- *
- * This lets us set a period when the main counter isn't at 0.
- */
- hpet_write32(count + ticks, HPET_Tn_CMP(0));
- hpet_write32(ticks, HPET_Tn_CMP(0));
-
- /* Restart the main counter, and legacy mode. */
- hpet_write32(hpet_cfg | HPET_CFG_ENABLE | HPET_CFG_LEGACY, HPET_CFG);
- }
+ hpet_enable_legacy_replacement_mode();
return hpet_rate;
}
diff --git a/xen/include/asm-x86/hpet.h b/xen/include/asm-x86/hpet.h
index fb6bf05065..50176de3d2 100644
--- a/xen/include/asm-x86/hpet.h
+++ b/xen/include/asm-x86/hpet.h
@@ -73,6 +73,12 @@ void hpet_disable(void);
int hpet_legacy_irq_tick(void);
/*
+ * Try to enable HPET Legacy Replacement mode. Returns a boolean indicating
+ * whether the HPET configuration was changed.
+ */
+bool hpet_enable_legacy_replacement_mode(void);
+
+/*
* Temporarily use an HPET event counter for timer interrupt handling,
* rather than using the LAPIC timer. Used for Cx state entry.
*/
--
2.11.0
next prev parent reply other threads:[~2021-03-26 19:00 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-03-26 18:59 [PATCH for-4.15 v2 0/3] x86/hpet: Try to unbreak Ryzen 1800X systems Andrew Cooper
2021-03-26 18:59 ` Andrew Cooper [this message]
2021-03-26 18:59 ` [PATCH v2 2/3] x86/hpet: Don't enable legacy replacement mode unconditionally Andrew Cooper
2021-03-29 11:40 ` Roger Pau Monné
2021-03-26 18:59 ` [PATCH v2 3/3] x86/hpet: Restore old configuration if Legacy Replacement mode doesn't help Andrew Cooper
2021-03-29 9:23 ` Jan Beulich
2021-03-29 12:37 ` Roger Pau Monné
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=20210326185947.23243-2-andrew.cooper3@citrix.com \
--to=andrew.cooper3@citrix.com \
--cc=JBeulich@suse.com \
--cc=frederic.pierret@qubes-os.org \
--cc=iwj@xenproject.org \
--cc=marmarek@invisiblethingslab.com \
--cc=roger.pau@citrix.com \
--cc=wl@xen.org \
--cc=xen-devel@lists.xenproject.org \
/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;
as well as URLs for NNTP newsgroup(s).