git: db16856110cb - main - xen/acpi: implement hook to notify Xen about entering sleep state
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 27 Feb 2026 07:41:43 UTC
The branch main has been updated by royger:
URL: https://cgit.FreeBSD.org/src/commit/?id=db16856110cbdbdfdc3c8d44edae1b3a7463198e
commit db16856110cbdbdfdc3c8d44edae1b3a7463198e
Author: Roger Pau Monné <royger@FreeBSD.org>
AuthorDate: 2026-02-24 20:23:08 +0000
Commit: Roger Pau Monné <royger@FreeBSD.org>
CommitDate: 2026-02-27 07:39:11 +0000
xen/acpi: implement hook to notify Xen about entering sleep state
This is required so that ACPI power-off (entering S5) works as expected, as
the ACPI PM1a and PM1b blocks might not be accessible by dom0 directly.
Additionally, Xen also needs to do cleanup before entering a sleep state,
so it needs to be notified about it.
With this patch FreeBSD dom0 now powers off the host correctly:
acpi0: Powering system off...
(XEN) [ 85.686598] arch/x86/hvm/emulate.c:415:d0v0 fixup p2m mapping for page fedc6 added
(XEN) [ 85.687606] arch/x86/hvm/emulate.c:415:d0v0 fixup p2m mapping for page fbc10 added
(XEN) [ 85.692357] Preparing system for ACPI S5 state.
(XEN) [ 85.692702] Disabling non-boot CPUs ...
(XEN) [ 85.694471] Broke affinity for IRQ9, new: {0-7}
[...]
(XEN) [ 85.903118] Entering ACPI S5 state.
Should be a non-functional change when not running as a Xen dom0.
Reviewed by: kib
Sponsored by: Citrix Systems R&D
MFC after: 2 weeks
Differential revision: https://reviews.freebsd.org/D55504
---
sys/conf/files | 1 +
sys/dev/acpica/Osd/OsdHardware.c | 13 +++++++
sys/dev/acpica/acpivar.h | 13 +++++++
sys/dev/xen/acpi/xen-acpi.c | 75 ++++++++++++++++++++++++++++++++++++++++
4 files changed, 102 insertions(+)
diff --git a/sys/conf/files b/sys/conf/files
index 4913efebf00d..632fddef2cb5 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3578,6 +3578,7 @@ dev/xdma/xdma_mbuf.c optional xdma
dev/xdma/xdma_queue.c optional xdma
dev/xdma/xdma_sg.c optional xdma
dev/xdma/xdma_sglist.c optional xdma
+dev/xen/acpi/xen-acpi.c optional xenhvm
dev/xen/balloon/balloon.c optional xenhvm
dev/xen/blkfront/blkfront.c optional xenhvm
dev/xen/blkback/blkback.c optional xenhvm
diff --git a/sys/dev/acpica/Osd/OsdHardware.c b/sys/dev/acpica/Osd/OsdHardware.c
index fbaf76d2a91a..4252cbc63222 100644
--- a/sys/dev/acpica/Osd/OsdHardware.c
+++ b/sys/dev/acpica/Osd/OsdHardware.c
@@ -37,6 +37,8 @@
extern int acpi_susp_bounce;
+int (*acpi_prepare_sleep)(uint8_t state, uint32_t a, uint32_t b, bool ext);
+
ACPI_STATUS
AcpiOsEnterSleep(UINT8 SleepState, UINT32 RegaValue, UINT32 RegbValue)
{
@@ -45,6 +47,17 @@ AcpiOsEnterSleep(UINT8 SleepState, UINT32 RegaValue, UINT32 RegbValue)
if (acpi_susp_bounce)
return (AE_CTRL_TERMINATE);
+ if (acpi_prepare_sleep != NULL)
+ {
+ int ret = acpi_prepare_sleep(SleepState, RegaValue, RegbValue,
+ ACPI_REDUCED_HARDWARE ? true : AcpiGbl_ReducedHardware);
+
+ if (ret < 0)
+ return (AE_ERROR);
+ if (ret > 0)
+ return (AE_CTRL_TERMINATE);
+ }
+
return (AE_OK);
}
diff --git a/sys/dev/acpica/acpivar.h b/sys/dev/acpica/acpivar.h
index aa8d5bd0971f..b86c6c1aa3c6 100644
--- a/sys/dev/acpica/acpivar.h
+++ b/sys/dev/acpica/acpivar.h
@@ -610,6 +610,19 @@ int acpi_pxm_parse(device_t dev);
int acpi_map_pxm_to_vm_domainid(int pxm);
bus_get_cpus_t acpi_get_cpus;
+/*
+ * Hook for ACPI sleep routine.
+ */
+extern int (*acpi_prepare_sleep)(uint8_t state, uint32_t a, uint32_t b,
+ bool ext);
+
+static inline void
+acpi_set_prepare_sleep(
+ int (*hook)(uint8_t state, uint32_t a, uint32_t b, bool ext))
+{
+ acpi_prepare_sleep = hook;
+}
+
#ifdef __aarch64__
/*
* ARM specific ACPI interfaces, relating to IORT table.
diff --git a/sys/dev/xen/acpi/xen-acpi.c b/sys/dev/xen/acpi/xen-acpi.c
new file mode 100644
index 000000000000..1e46883e2c86
--- /dev/null
+++ b/sys/dev/xen/acpi/xen-acpi.c
@@ -0,0 +1,75 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 Citrix Systems R&D
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include "opt_acpi.h"
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/kobj.h>
+
+#include <machine/_inttypes.h>
+
+#include <contrib/dev/acpica/include/acpi.h>
+#include <contrib/dev/acpica/include/accommon.h>
+
+#include <dev/acpica/acpivar.h>
+
+#include <xen/xen-os.h>
+
+static int prepare_sleep_state(uint8_t state, uint32_t a, uint32_t b, bool ext)
+{
+ struct xen_platform_op op = {
+ .cmd = XENPF_enter_acpi_sleep,
+ .interface_version = XENPF_INTERFACE_VERSION,
+ .u.enter_acpi_sleep.val_a = a,
+ .u.enter_acpi_sleep.val_b = b,
+ .u.enter_acpi_sleep.sleep_state = state,
+ .u.enter_acpi_sleep.flags =
+ ext ? XENPF_ACPI_SLEEP_EXTENDED : 0,
+ };
+ int error;
+
+ error = HYPERVISOR_platform_op(&op);
+ if (error)
+ printf("Xen notify ACPI sleep failed - "
+ "State %#x A %#x B %#x: %d\n", state, a, b, error);
+
+ return (error ? error : 1);
+}
+
+static int init_xen_acpi_sleep(void *arg)
+{
+ if (!xen_initial_domain())
+ return (0);
+
+ acpi_set_prepare_sleep(&prepare_sleep_state);
+ return (0);
+}
+
+SYSINIT(xen_sleep, SI_SUB_CONFIGURE, SI_ORDER_ANY, init_xen_acpi_sleep, NULL);