You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by ac...@apache.org on 2024/09/13 12:28:14 UTC
(nuttx) branch master updated: arch/intel64/hpet: add FSB interrupts support and support for 32-bit mode
This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new d6a6a0a7cc arch/intel64/hpet: add FSB interrupts support and support for 32-bit mode
d6a6a0a7cc is described below
commit d6a6a0a7cc3cd7e64feb84ebd3e5b42440ef89f0
Author: p-szafonimateusz <p-...@xiaomi.com>
AuthorDate: Thu Jun 27 09:26:23 2024 +0200
arch/intel64/hpet: add FSB interrupts support and support for 32-bit mode
These are changes to make HPET work with ACRN hypervisor:
- FSB interrupt delivery (which works like PCI MSI)
- 32-bit mode support
Signed-off-by: p-szafonimateusz <p-...@xiaomi.com>
---
arch/x86_64/include/hpet.h | 6 +--
arch/x86_64/src/intel64/Kconfig | 12 +++++
arch/x86_64/src/intel64/intel64_hpet.c | 90 +++++++++++++++++++++++++++++++
arch/x86_64/src/intel64/intel64_oneshot.c | 45 ++++++++++++++--
4 files changed, 147 insertions(+), 6 deletions(-)
diff --git a/arch/x86_64/include/hpet.h b/arch/x86_64/include/hpet.h
index 40627c82ef..0d4dff70f4 100644
--- a/arch/x86_64/include/hpet.h
+++ b/arch/x86_64/include/hpet.h
@@ -55,8 +55,8 @@
/* General Configuration Register */
-#define HPET_GCONF_LEGERT (1 << 0) /* Bit 0: LegacyReplacement Route */
-#define HPET_GCONF_ENABLE (1 << 1) /* Bit 1: Overall Enable */
+#define HPET_GCONF_ENABLE (1 << 0) /* Bit 0: Overall Enable */
+#define HPET_GCONF_LEGERT (1 << 1) /* Bit 1: LegacyReplacement Route */
/* General Interrupt Status Register */
@@ -86,7 +86,7 @@
#define HPET_TFSB_INT_VAL_SHIFT (0)
#define HPET_TFSB_INT_VAL_MASK (0x00000000ffffffff)
-#define HPET_TFSB_INT_ADDR_SHIFT (31)
+#define HPET_TFSB_INT_ADDR_SHIFT (32)
#define HPET_TFSB_INT_ADDR_MASK (0xffffffff00000000)
/* HPET register space */
diff --git a/arch/x86_64/src/intel64/Kconfig b/arch/x86_64/src/intel64/Kconfig
index 3d28782b55..e8a17fde9e 100644
--- a/arch/x86_64/src/intel64/Kconfig
+++ b/arch/x86_64/src/intel64/Kconfig
@@ -116,6 +116,18 @@ config INTEL64_HPET_BASE
Configure base address for HPET. In the future, we can get this address from
the ACPI table if ACPI support is enabled.
+config INTEL64_HPET_32BIT
+ bool "HPET is 32bit"
+ default n
+ ---help---
+ Configure HPET in 32-bit mode.
+
+config INTEL64_HPET_FSB
+ bool "HPET use FSB for interrupt"
+ default n
+ ---help---
+ Use FSB for interrupt (works like MSI interrupts).
+
config ARCH_INTEL64_HPET_ALARM_CHAN
int "HPET timer alarm channel"
depends on ARCH_INTEL64_HPET_ALARM
diff --git a/arch/x86_64/src/intel64/intel64_hpet.c b/arch/x86_64/src/intel64/intel64_hpet.c
index c906fa3b86..9bf3ce35b7 100644
--- a/arch/x86_64/src/intel64/intel64_hpet.c
+++ b/arch/x86_64/src/intel64/intel64_hpet.c
@@ -35,6 +35,14 @@
#include "intel64_hpet.h"
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#define X86_64_MAR_DEST 0xfee00000
+#define X86_64_MDR_TYPE 0x4000
+#define X86_64_MDR_CPUID_SHIFT 12
+
/****************************************************************************
* Private Types
****************************************************************************/
@@ -341,6 +349,11 @@ static int intel64_hpet_setisr(struct intel64_tim_dev_s *dev, uint8_t timer,
regval &= ~HPET_TCONF_PERCAP;
}
+#ifdef CONFIG_INTEL64_HPET_FSB
+ /* FSB works only with edge triggered mode */
+
+ regval &= ~HPET_TCONF_INTTYPE;
+#else
/* Route interrupts */
regval |= HPET_TCONF_INTROUTE(irq - IRQ0);
@@ -352,10 +365,15 @@ static int intel64_hpet_setisr(struct intel64_tim_dev_s *dev, uint8_t timer,
*/
regval |= HPET_TCONF_INTTYPE;
+#endif
/* Set 64-bit mode */
+#ifdef CONFIG_INTEL64_HPET_32BIT
+ regval |= HPET_TCONF_32MODE;
+#else
regval &= ~HPET_TCONF_32MODE;
+#endif
/* Write Timer configuration */
@@ -419,6 +437,72 @@ static void intel64_hpet_disint(struct intel64_tim_dev_s *dev, uint8_t tim)
intel64_hpet_putreg(hpet, HPET_TCONF_OFFSET(tim), regval);
}
+#ifdef CONFIG_INTEL64_HPET_FSB
+/****************************************************************************
+ * Name: intel64_hpet_fsb
+ *
+ * Description:
+ * Configure HPET with FSB interrupts.
+ *
+ ****************************************************************************/
+
+static void intel64_hpet_fsb(struct intel64_hpet_s *hpet)
+{
+ uint64_t regval;
+ uint64_t fsb_val;
+ uint64_t fsb_addr;
+ int vect;
+ int irq;
+ int i;
+
+ /* Disable legacy routing */
+
+ intel64_hpet_putreg(hpet, HPET_GCONF_OFFSET, 0);
+
+ /* Configure timers */
+
+ for (i = 0; i < hpet->timers; i++)
+ {
+ /* Allocate MSI vector */
+
+ vect = 1;
+ irq = up_alloc_irq_msi(&vect);
+ if (irq < 0 && vect != 1)
+ {
+ tmrerr("failed to allocate MSI for timer %d\n", i);
+ ASSERT(0);
+ }
+
+ /* Configure FSB */
+
+ fsb_addr = X86_64_MAR_DEST |
+ (up_apic_cpu_id() << X86_64_MDR_CPUID_SHIFT);
+ fsb_val = X86_64_MDR_TYPE | irq;
+
+ regval = fsb_addr << HPET_TFSB_INT_ADDR_SHIFT;
+ regval |= fsb_val << HPET_TFSB_INT_VAL_SHIFT;
+
+ intel64_hpet_putreg(hpet, HPET_TFSB_OFFSET(i), regval);
+
+ /* Enable FSB */
+
+ regval = intel64_hpet_getreg(hpet, HPET_TCONF_OFFSET(i));
+ if (!(regval & HPET_TCONF_FSBCAP))
+ {
+ tmrerr("FSB not supported for timer %d\n", i);
+ ASSERT(0);
+ }
+
+ intel64_hpet_putreg(hpet, HPET_TCONF_OFFSET(i),
+ regval | HPET_TCONF_FSBEN);
+
+ /* Store irq number */
+
+ hpet->chans[i].irq = irq;
+ }
+}
+#endif
+
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -462,6 +546,11 @@ struct intel64_tim_dev_s *intel64_hpet_init(uint64_t base)
hpet->ops = &g_intel64_hpet_ops;
+#ifdef CONFIG_INTEL64_HPET_FSB
+ /* Allocate and configure FSB for timers */
+
+ intel64_hpet_fsb(hpet);
+#else
if (regval & HPET_GCAPID_LEGROUTE)
{
/* Configure legacy mode.
@@ -479,6 +568,7 @@ struct intel64_tim_dev_s *intel64_hpet_init(uint64_t base)
ASSERT(0);
}
+#endif
/* Enable HPET */
diff --git a/arch/x86_64/src/intel64/intel64_oneshot.c b/arch/x86_64/src/intel64/intel64_oneshot.c
index 6646c3934b..3abc96ef36 100644
--- a/arch/x86_64/src/intel64/intel64_oneshot.c
+++ b/arch/x86_64/src/intel64/intel64_oneshot.c
@@ -79,16 +79,24 @@ static int intel64_oneshot_handler(int irg_num, void * context, void *arg)
void *oneshot_arg;
oneshot_handler_t oneshot_handler;
- tmrinfo("Expired...\n");
- DEBUGASSERT(oneshot != NULL && oneshot->handler);
+ DEBUGASSERT(oneshot != NULL);
- if (INTEL64_TIM_GETINT(oneshot->tch, oneshot->chan))
+ /* Additional check for spurious interrupts. We can't check interrupt
+ * status here, because it doesn't work for FSB which is edge tirggered
+ */
+
+ if (oneshot->running)
{
+ DEBUGASSERT(oneshot->handler);
+ tmrinfo("Expired...\n");
+
+#ifndef CONFIG_INTEL64_HPET_FSB
/* Disable any further interrupts. */
INTEL64_TIM_DISABLEINT(oneshot->tch, oneshot->chan);
INTEL64_TIM_SETISR(oneshot->tch, oneshot->chan, NULL, NULL, false);
INTEL64_TIM_ACKINT(oneshot->tch, oneshot->chan);
+#endif
/* The timer is no longer running */
@@ -103,6 +111,10 @@ static int intel64_oneshot_handler(int irg_num, void * context, void *arg)
oneshot_handler(oneshot_arg);
}
+ else
+ {
+ tmrinfo("Spurious...\n");
+ }
return OK;
}
@@ -204,6 +216,27 @@ int intel64_oneshot_initialize(struct intel64_oneshot_s *oneshot, int chan,
oneshot->handler = NULL;
oneshot->arg = NULL;
+#ifdef CONFIG_INTEL64_HPET_FSB
+ /* IMPORTENT: HPET in edge triggered mode is broken on some hardware
+ * and generate spurious interrupts when we enable timer. On the other
+ * hand FSB works only with edge triggered mode.
+ *
+ * We use the following work around for this:
+ * 1. enable interrupts now for FSB so we can catch initial spurious
+ * interrupt.
+ * 2. NEVER disable interrupts, so we avoid spurious interrupt when we
+ * re-enabled interrupt.
+ * 3. The previous step requires that we must filter out unwanted
+ * interrupts for 32-bit mode HPET, that will happen with HPET
+ * period interval.
+ */
+
+ INTEL64_TIM_SETISR(oneshot->tch, oneshot->chan, intel64_oneshot_handler,
+ oneshot, false);
+ INTEL64_TIM_SETCOMPARE(oneshot->tch, oneshot->chan, 0);
+ INTEL64_TIM_ENABLEINT(oneshot->tch, oneshot->chan);
+#endif
+
/* Assign a callback handler to the oneshot */
return intel64_allocate_handler(oneshot);
@@ -304,21 +337,25 @@ int intel64_oneshot_start(struct intel64_oneshot_s *oneshot,
compare = (usec * (uint64_t)oneshot->frequency) / USEC_PER_SEC;
+#ifndef CONFIG_INTEL64_HPET_FSB
/* Set up to receive the callback when the interrupt occurs */
INTEL64_TIM_SETISR(oneshot->tch, oneshot->chan, intel64_oneshot_handler,
oneshot, false);
+#endif
/* Set comparator ahed of the current counter */
compare += INTEL64_TIM_GETCOUNTER(oneshot->tch);
INTEL64_TIM_SETCOMPARE(oneshot->tch, oneshot->chan, compare);
+#ifndef CONFIG_INTEL64_HPET_FSB
/* Enable interrupts. We should get the callback when the interrupt
* occurs.
*/
INTEL64_TIM_ENABLEINT(oneshot->tch, oneshot->chan);
+#endif
oneshot->running = true;
spin_unlock_irqrestore(&g_oneshot_spin, flags);
@@ -384,10 +421,12 @@ int intel64_oneshot_cancel(struct intel64_oneshot_s *oneshot,
counter = INTEL64_TIM_GETCOUNTER(oneshot->tch);
compare = INTEL64_TIM_GETCOMPARE(oneshot->tch, oneshot->chan);
+#ifndef CONFIG_INTEL64_HPET_FSB
/* Now we can disable the interrupt and stop the timer. */
INTEL64_TIM_DISABLEINT(oneshot->tch, oneshot->chan);
INTEL64_TIM_SETISR(oneshot->tch, oneshot->chan, NULL, NULL, false);
+#endif
oneshot->running = false;
oneshot->handler = NULL;