Hi Mykola,

On 02/06/2025 10:04, Mykola Kvach wrote:
CAUTION: This message has originated from an External Source. Please use proper 
judgment and caution when opening attachments, clicking links, or responding to 
this email.


From: Mirela Simonovic <mirela.simono...@aggios.com>

Timer interrupts must be disabled while the system is suspended to prevent
spurious wake-ups. Suspending the timers involves disabling both the EL1
physical timer and the EL2 hypervisor timer. Resuming consists of raising
the TIMER_SOFTIRQ, which prompts the generic timer code to reprogram the
EL2 timer as needed. Re-enabling of the EL1 timer is left to the entity
that uses it.

Introduce a new helper, disable_physical_timers, to encapsulate disabling
of the physical timers.

Signed-off-by: Mirela Simonovic <mirela.simono...@aggios.com>
Signed-off-by: Saeed Nowshadi <saeed.nowsh...@xilinx.com>
Signed-off-by: Mykola Kvach <mykola_kv...@epam.com>
---
Changes in V4:
   - Rephrased comment and commit message for better clarity
   - Created separate function for disabling physical timers

Changes in V3:
   - time_suspend and time_resume are now conditionally compiled
     under CONFIG_SYSTEM_SUSPEND
---
  xen/arch/arm/include/asm/time.h |  5 +++++
  xen/arch/arm/time.c             | 38 +++++++++++++++++++++++++++------
  2 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/xen/arch/arm/include/asm/time.h b/xen/arch/arm/include/asm/time.h
index 49ad8c1a6d..f4fd0c6af5 100644
--- a/xen/arch/arm/include/asm/time.h
+++ b/xen/arch/arm/include/asm/time.h
@@ -108,6 +108,11 @@ void preinit_xen_time(void);

  void force_update_vcpu_system_time(struct vcpu *v);

+#ifdef CONFIG_SYSTEM_SUSPEND
+void time_suspend(void);
+void time_resume(void);
+#endif /* CONFIG_SYSTEM_SUSPEND */
+
  #endif /* __ARM_TIME_H__ */
  /*
   * Local variables:
diff --git a/xen/arch/arm/time.c b/xen/arch/arm/time.c
index e74d30d258..ad984fdfdd 100644
--- a/xen/arch/arm/time.c
+++ b/xen/arch/arm/time.c
@@ -303,6 +303,14 @@ static void check_timer_irq_cfg(unsigned int irq, const 
char *which)
             "WARNING: %s-timer IRQ%u is not level triggered.\n", which, irq);
  }

+/* Disable physical timers for EL1 and EL2 on the current CPU */
+static inline void disable_physical_timers(void)
+{
+    WRITE_SYSREG(0, CNTP_CTL_EL0);    /* Physical timer disabled */
+    WRITE_SYSREG(0, CNTHP_CTL_EL2);   /* Hypervisor's timer disabled */
+    isb();
+}
+
  /* Set up the timer interrupt on this CPU */
  void init_timer_interrupt(void)
  {
@@ -310,9 +318,7 @@ void init_timer_interrupt(void)
      WRITE_SYSREG64(0, CNTVOFF_EL2);     /* No VM-specific offset */
      /* Do not let the VMs program the physical timer, only read the physical 
counter */
      WRITE_SYSREG(CNTHCTL_EL2_EL1PCTEN, CNTHCTL_EL2);
-    WRITE_SYSREG(0, CNTP_CTL_EL0);    /* Physical timer disabled */
-    WRITE_SYSREG(0, CNTHP_CTL_EL2);   /* Hypervisor's timer disabled */
-    isb();
+    disable_physical_timers();

      request_irq(timer_irq[TIMER_HYP_PPI], 0, htimer_interrupt,
                  "hyptimer", NULL);
@@ -330,9 +336,7 @@ void init_timer_interrupt(void)
   */
  static void deinit_timer_interrupt(void)
  {
-    WRITE_SYSREG(0, CNTP_CTL_EL0);    /* Disable physical timer */
-    WRITE_SYSREG(0, CNTHP_CTL_EL2);   /* Disable hypervisor's timer */
-    isb();
+    disable_physical_timers();

      release_irq(timer_irq[TIMER_HYP_PPI], NULL);
      release_irq(timer_irq[TIMER_VIRT_PPI], NULL);
@@ -372,6 +376,28 @@ void domain_set_time_offset(struct domain *d, int64_t 
time_offset_seconds)
      /* XXX update guest visible wallclock time */
  }

+#ifdef CONFIG_SYSTEM_SUSPEND
+
+void time_suspend(void)
+{
+    disable_physical_timers();
+}
+
+void time_resume(void)
+{
+    /*
+     * Raising the timer softirq triggers generic code to call reprogram_timer
+     * with the correct timeout (not known here).
+     *
+     * No further action is needed to restore timekeeping after power down,
+     * since the system counter is unaffected. See ARM DDI 0487 L.a, D12.1.2
+     * "The system counter must be implemented in an always-on power domain."
+     */
+    raise_softirq(TIMER_SOFTIRQ);
+}
+
+#endif /* CONFIG_SYSTEM_SUSPEND */
+
  static int cpu_time_callback(struct notifier_block *nfb,
                               unsigned long action,
                               void *hcpu)
A question. Do you see CPU_DYING gets invoked during platform suspend ? I wonder how this code path is invoked with

time_suspend()

- Ayan

--
2.48.1



Reply via email to