|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v5 07/12] xen/arm: Add support for system suspend triggered by hardware domain
From: Mirela Simonovic <mirela.simonovic@xxxxxxxxxx>
Trigger Xen suspend when the hardware domain initiates suspend via
SHUTDOWN_suspend. Redirect system suspend to CPU#0 to ensure the
suspend logic runs on the boot CPU, as required.
Introduce full suspend/resume infrastructure gated by CONFIG_SYSTEM_SUSPEND,
including logic to:
- disable and enable non-boot physical CPUs
- freeze and thaw domains
- suspend and resume the GIC, timer and console
- maintain system state before and after suspend
Remove the restriction in the PSCI interface preventing suspend from the
hardware domain.
Select HAS_SYSTEM_SUSPEND for ARM_64.
Signed-off-by: Mirela Simonovic <mirela.simonovic@xxxxxxxxxx>
Signed-off-by: Saeed Nowshadi <saeed.nowshadi@xxxxxxxxxx>
Signed-off-by: Mykyta Poturai <mykyta_poturai@xxxxxxxx>
Signed-off-by: Mykola Kvach <mykola_kvach@xxxxxxxx>
---
Changes in v5:
- select HAS_SYSTEM_SUSPEND in ARM_64 instead of ARM
- check llc_coloring_enabled instead of LLC_COLORING during the selection
of HAS_SYSTEM_SUSPEND config
- call host_system_suspend from guest PSCI system suspend instead of
arch_domain_shutdown, reducing the complexity of the new code
- update some comments
Changes introduced in V4:
- drop code for saving and restoring VCPU context (for more information
refer part 1 of patch series)
- remove IOMMU suspend and resume calls until they will be implemented
- move system suspend logic to arch_domain_shutdown, invoked from
domain_shutdown
- apply minor fixes such as renaming functions, updating comments, and
modifying the commit message to reflect these changes
- add console_end_sync to resume path after system suspend
Changes introduced in V3:
- merge changes from other commits into this patch (previously stashed):
1) disable/enable non-boot physical CPUs and freeze/thaw domains during
suspend/resume
2) suspend/resume the timer, GIC, console, IOMMU, and hardware domain
---
xen/arch/arm/Kconfig | 1 +
xen/arch/arm/Makefile | 1 +
xen/arch/arm/include/asm/suspend.h | 22 +++++
xen/arch/arm/suspend.c | 151 +++++++++++++++++++++++++++++
xen/arch/arm/vpsci.c | 12 ++-
xen/common/domain.c | 4 +
6 files changed, 190 insertions(+), 1 deletion(-)
create mode 100644 xen/arch/arm/include/asm/suspend.h
create mode 100644 xen/arch/arm/suspend.c
diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
index a0c8160474..ccdbaa5bc3 100644
--- a/xen/arch/arm/Kconfig
+++ b/xen/arch/arm/Kconfig
@@ -8,6 +8,7 @@ config ARM_64
depends on !ARM_32
select 64BIT
select HAS_FAST_MULTIPLY
+ select HAS_SYSTEM_SUSPEND if UNSUPPORTED
select HAS_VPCI_GUEST_SUPPORT if PCI_PASSTHROUGH
config ARM
diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index f833cdf207..3f6247adee 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -51,6 +51,7 @@ obj-y += setup.o
obj-y += shutdown.o
obj-y += smp.o
obj-y += smpboot.o
+obj-$(CONFIG_SYSTEM_SUSPEND) += suspend.o
obj-$(CONFIG_SYSCTL) += sysctl.o
obj-y += time.o
obj-y += traps.o
diff --git a/xen/arch/arm/include/asm/suspend.h
b/xen/arch/arm/include/asm/suspend.h
new file mode 100644
index 0000000000..78d0e2383b
--- /dev/null
+++ b/xen/arch/arm/include/asm/suspend.h
@@ -0,0 +1,22 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef __ASM_ARM_SUSPEND_H__
+#define __ASM_ARM_SUSPEND_H__
+
+#ifdef CONFIG_SYSTEM_SUSPEND
+
+int host_system_suspend(void);
+
+#endif /* CONFIG_SYSTEM_SUSPEND */
+
+#endif /* __ASM_ARM_SUSPEND_H__ */
+
+ /*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/suspend.c b/xen/arch/arm/suspend.c
new file mode 100644
index 0000000000..abf4b928ce
--- /dev/null
+++ b/xen/arch/arm/suspend.c
@@ -0,0 +1,151 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#include <xen/console.h>
+#include <xen/cpu.h>
+#include <xen/llc-coloring.h>
+#include <xen/sched.h>
+
+/*
+ * TODO list:
+ * - Test system suspend with LLC_COLORING enabled and verify functionality
+ * - Implement IOMMU suspend/resume handlers and integrate them
+ * into the suspend/resume path (IPMMU and SMMU)
+ * - Enable "xl suspend" support on ARM architecture
+ * - Properly disable Xen timer watchdog from relevant services
+ * - Add suspend/resume CI test for ARM (QEMU if feasible)
+ * - Investigate feasibility and need for implementing system suspend on ARM32
+ */
+
+/* Xen suspend. Note: data is not used (suspend is the suspend to RAM) */
+static long system_suspend(void *data)
+{
+ int status;
+ unsigned long flags;
+
+ BUG_ON(system_state != SYS_STATE_active);
+
+ system_state = SYS_STATE_suspend;
+ freeze_domains();
+ scheduler_disable();
+
+ /*
+ * Non-boot CPUs have to be disabled on suspend and enabled on resume
+ * (hotplug-based mechanism). Disabling non-boot CPUs will lead to PSCI
+ * CPU_OFF to be called by each non-boot CPU. Depending on the underlying
+ * platform capabilities, this may lead to the physical powering down of
+ * CPUs. Tested on Xilinx Zynq Ultrascale+ MPSoC (including power down of
+ * each non-boot CPU).
+ */
+ status = disable_nonboot_cpus();
+ if ( status )
+ {
+ system_state = SYS_STATE_resume;
+ goto resume_nonboot_cpus;
+ }
+
+ time_suspend();
+
+ local_irq_save(flags);
+ status = gic_suspend();
+ if ( status )
+ {
+ system_state = SYS_STATE_resume;
+ goto resume_irqs;
+ }
+
+ printk("Xen suspending...\n");
+
+ console_start_sync();
+ status = console_suspend();
+ if ( status )
+ {
+ dprintk(XENLOG_ERR, "Failed to suspend the console, err=%d\n", status);
+ system_state = SYS_STATE_resume;
+ goto resume_console;
+ }
+
+ /*
+ * Enable identity mapping before entering suspend to simplify
+ * the resume path
+ */
+ update_boot_mapping(true);
+
+ system_state = SYS_STATE_resume;
+ update_boot_mapping(false);
+
+ resume_console:
+ console_resume();
+ console_end_sync();
+
+ gic_resume();
+
+ resume_irqs:
+ local_irq_restore(flags);
+ time_resume();
+
+ resume_nonboot_cpus:
+ /*
+ * The rcu_barrier() has to be added to ensure that the per cpu area is
+ * freed before a non-boot CPU tries to initialize it (_free_percpu_area()
+ * has to be called before the init_percpu_area()). This scenario occurs
+ * when non-boot CPUs are hot-unplugged on suspend and hotplugged on
resume.
+ */
+ rcu_barrier();
+ enable_nonboot_cpus();
+ scheduler_enable();
+ thaw_domains();
+
+ system_state = SYS_STATE_active;
+
+ /* The resume of hardware domain should always follow Xen's resume. */
+ domain_resume(hardware_domain);
+
+ printk("Resume (status %d)\n", status);
+ return status;
+}
+
+int host_system_suspend(void)
+{
+ int status;
+
+ /* TODO: drop check after verification that features can work together */
+ if ( llc_coloring_enabled )
+ {
+ dprintk(XENLOG_ERR,
+ "System suspend is not supported with LLC_COLORING enabled\n");
+ return -ENOSYS;
+ }
+
+ /*
+ * system_suspend should be called when Dom0 finalizes the suspend
+ * procedure from its boot core (VCPU#0). However, Dom0's VCPU#0 could
+ * be mapped to any PCPU (this function could be executed by any PCPU).
+ * The suspend procedure has to be finalized by the PCPU#0 (non-boot
+ * PCPUs will be disabled during the suspend).
+ */
+ status = continue_hypercall_on_cpu(0, system_suspend, NULL);
+
+ /*
+ * If an error happened, there is nothing that needs to be done here
+ * because the system_suspend always returns in fully functional state
+ * no matter what the outcome of suspend procedure is. If the system
+ * suspended successfully the function will return 0 after the resume.
+ * Otherwise, if an error is returned it means Xen did not suspended,
+ * but it is still in the same state as if the system_suspend was never
+ * called. We dump a debug message in case of an error for debugging/
+ * logging purpose.
+ */
+ if ( status )
+ dprintk(XENLOG_ERR, "Failed to suspend, errno=%d\n", status);
+
+ return status;
+}
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/xen/arch/arm/vpsci.c b/xen/arch/arm/vpsci.c
index 67d369a8a2..757e719ea7 100644
--- a/xen/arch/arm/vpsci.c
+++ b/xen/arch/arm/vpsci.c
@@ -4,6 +4,7 @@
#include <xen/types.h>
#include <asm/current.h>
+#include <asm/suspend.h>
#include <asm/vgic.h>
#include <asm/vpsci.h>
#include <asm/event.h>
@@ -214,9 +215,10 @@ static int32_t do_psci_1_0_system_suspend(register_t
epoint, register_t cid)
struct vcpu *v;
struct domain *d = current->domain;
- /* SYSTEM_SUSPEND is not supported for the hardware domain yet */
+#ifndef CONFIG_SYSTEM_SUSPEND
if ( is_hardware_domain(d) )
return PSCI_NOT_SUPPORTED;
+#endif
/* Ensure that all CPUs other than the calling one are offline */
domain_lock(d);
@@ -234,6 +236,14 @@ static int32_t do_psci_1_0_system_suspend(register_t
epoint, register_t cid)
if ( rc )
return PSCI_DENIED;
+#ifdef CONFIG_SYSTEM_SUSPEND
+ if ( is_hardware_domain(d) && host_system_suspend() )
+ {
+ domain_resume_nopause(d);
+ return PSCI_DENIED;
+ }
+#endif
+
rc = do_setup_vcpu_ctx(current, epoint, cid);
if ( rc != PSCI_SUCCESS )
{
diff --git a/xen/common/domain.c b/xen/common/domain.c
index c3609b0cb0..414a691242 100644
--- a/xen/common/domain.c
+++ b/xen/common/domain.c
@@ -1311,7 +1311,11 @@ int domain_shutdown(struct domain *d, u8 reason)
d->shutdown_code = reason;
reason = d->shutdown_code;
+#if defined(CONFIG_SYSTEM_SUSPEND) && defined(CONFIG_ARM)
+ if ( reason != SHUTDOWN_suspend && is_hardware_domain(d) )
+#else
if ( is_hardware_domain(d) )
+#endif
hwdom_shutdown(reason);
if ( d->is_shutting_down )
--
2.48.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |