Hi, On Mon, Jan 12, 2026 at 06:22:56PM +0000, Kuan-Wei Chiu wrote: > Add a new driver for the 'virt-ctrl' device found on QEMU virt machines > (e.g. m68k). This device provides a simple interface for system reset > and power off [1]. > > This driver registers a restart handler for system reboot and sets the > global pm_power_off callback for system shutdown. It is designed to be > generic and can be reused by other architectures utilizing this QEMU > device. > > Link: https://gitlab.com/qemu-project/qemu/-/blob/v10.2.0/hw/misc/virt_ctrl.c [1] > Signed-off-by: Kuan-Wei Chiu > --- > MAINTAINERS | 6 ++ > drivers/power/reset/Kconfig | 10 +++ > drivers/power/reset/Makefile | 1 + > drivers/power/reset/qemu-virt-ctrl.c | 98 ++++++++++++++++++++++++++++ > 4 files changed, 115 insertions(+) > create mode 100644 drivers/power/reset/qemu-virt-ctrl.c > > diff --git a/MAINTAINERS b/MAINTAINERS > index 0d044a58cbfe..2586e4162304 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -21179,6 +21179,12 @@ S: Maintained > F: drivers/firmware/qemu_fw_cfg.c > F: include/uapi/linux/qemu_fw_cfg.h > > +QEMU VIRT MACHINE SYSTEM CONTROLLER DRIVER > +M: Kuan-Wei Chiu > +L: linux-pm@vger.kernel.org > +S: Maintained > +F: drivers/power/reset/qemu-virt-ctrl.c > + > QLOGIC QL41xxx FCOE DRIVER > M: Saurav Kashyap > M: Javed Hasan > diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig > index f6c1bcbb57de..1ca1c2913cbc 100644 > --- a/drivers/power/reset/Kconfig > +++ b/drivers/power/reset/Kconfig > @@ -354,4 +354,14 @@ config POWER_MLXBF > help > This driver supports reset or low power mode handling for Mellanox BlueField. > > +config POWER_RESET_QEMU_VIRT_CTRL > + bool "QEMU Virt Machine System Controller" > + depends on HAS_IOMEM > + help > + This driver supports the system reset and power off functionality > + provided by the QEMU 'virt-ctrl' device. > + > + Say Y here if you are running Linux on a QEMU virtual machine that > + provides this controller, such as the m68k virt machine. > + > endif > diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile > index 0e4ae6f6b5c5..d7ae97241a83 100644 > --- a/drivers/power/reset/Makefile > +++ b/drivers/power/reset/Makefile > @@ -41,3 +41,4 @@ obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o > obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o > obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o > obj-$(CONFIG_POWER_MLXBF) += pwr-mlxbf.o > +obj-$(CONFIG_POWER_RESET_QEMU_VIRT_CTRL) += qemu-virt-ctrl.o > diff --git a/drivers/power/reset/qemu-virt-ctrl.c b/drivers/power/reset/qemu-virt-ctrl.c > new file mode 100644 > index 000000000000..f1acd22172ce > --- /dev/null > +++ b/drivers/power/reset/qemu-virt-ctrl.c > @@ -0,0 +1,98 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * QEMU Virt Machine System Controller Driver > + * > + * Copyright (C) 2026 Kuan-Wei Chiu > + */ > + > +#include > +#include > +#include > +#include > + > +/* Registers */ > +#define VIRT_CTRL_REG_FEATURES 0x00 > +#define VIRT_CTRL_REG_CMD 0x04 > + > +/* Commands */ > +#define CMD_NOOP 0 > +#define CMD_RESET 1 > +#define CMD_HALT 2 > +#define CMD_PANIC 3 > + > +struct qemu_virt_ctrl { > + void __iomem *base; > + struct notifier_block restart_nb; > +}; > + > +static void __iomem *qemu_virt_ctrl_base; > + > +static void qemu_virt_ctrl_power_off(void) > +{ > + if (qemu_virt_ctrl_base) > + iowrite32be(CMD_HALT, qemu_virt_ctrl_base + VIRT_CTRL_REG_CMD); > +} > + > +static int qemu_virt_ctrl_restart(struct notifier_block *nb, unsigned long action, > + void *data) > +{ > + struct qemu_virt_ctrl *vc = container_of(nb, struct qemu_virt_ctrl, restart_nb); > + > + iowrite32be(CMD_RESET, vc->base + VIRT_CTRL_REG_CMD); > + > + return NOTIFY_DONE; > +} > + > +static int qemu_virt_ctrl_probe(struct platform_device *pdev) > +{ > + struct qemu_virt_ctrl *vc; > + int ret; > + > + vc = devm_kzalloc(&pdev->dev, sizeof(*vc), GFP_KERNEL); > + if (!vc) > + return -ENOMEM; > + > + vc->base = devm_platform_ioremap_resource(pdev, 0); > + if (IS_ERR(vc->base)) > + return PTR_ERR(vc->base); > + > + qemu_virt_ctrl_base = vc->base; > + > + vc->restart_nb.notifier_call = qemu_virt_ctrl_restart; > + vc->restart_nb.priority = 128; > + > + ret = register_restart_handler(&vc->restart_nb); > + if (ret) > + return dev_err_probe(&pdev->dev, ret, > + "cannot register restart handler\n"); Please use devm_register_sys_off_handler(). > + if (!pm_power_off) > + pm_power_off = qemu_virt_ctrl_power_off; same. > + platform_set_drvdata(pdev, vc); > + > + return 0; > +} > + > +static void qemu_virt_ctrl_remove(struct platform_device *pdev) > +{ > + struct qemu_virt_ctrl *vc = platform_get_drvdata(pdev); > + > + unregister_restart_handler(&vc->restart_nb); > + > + if (pm_power_off == qemu_virt_ctrl_power_off) > + pm_power_off = NULL; > +} > + > +static struct platform_driver qemu_virt_ctrl_driver = { > + .probe = qemu_virt_ctrl_probe, > + .remove = qemu_virt_ctrl_remove, > + .driver = { > + .name = "qemu-virt-ctrl", > + }, > +}; > +module_platform_driver(qemu_virt_ctrl_driver); > + > +MODULE_AUTHOR("Kuan-Wei Chiu "); > +MODULE_DESCRIPTION("QEMU Virt Machine System Controller Driver"); > +MODULE_LICENSE("GPL"); You mark this as module_platform_driver() and add MODULE_*, but the Kconfig option is bool. To be usable as a module it is missing setup of .id_table in the platform_driver struct for auto-loading. Greetings, -- Sebastian