Re: [PATCH v3 1/2] power: reset: Add QEMU virt-ctrl driver
From: Sebastian Reichel
Date: Thu Apr 02 2026 - 17:55:37 EST
Hi,
On Sun, Feb 22, 2026 at 05:32:24PM +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 utilizes the modern system-off API to register callbacks
> for both system restart and power off. It also registers a reboot
> notifier to catch SYS_HALT events, ensuring that LINUX_REBOOT_CMD_HALT
> is properly handled. 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 <visitorckw@xxxxxxxxx>
> ---
I think this should be merged with the second patch via the m68k
tree:
Acked-by: Sebastian Reichel <sebastian.reichel@xxxxxxxxxxxxx>
Greetings,
-- Sebastian
> Changes in v3:
> - Add a reboot notifier to handle SYS_HALT.
> - Implement virt_ctrl_write32() to handle native endianness.
>
> I noticed devm_register_sys_off_handler() currently lacks a
> SYS_OFF_MODE_HALT. Therefore, I registered a standard reboot notifier
> for SYS_HALT, while keeping restart and power-off on the sys-off API.
>
> MAINTAINERS | 6 ++
> drivers/power/reset/Kconfig | 10 +++
> drivers/power/reset/Makefile | 1 +
> drivers/power/reset/qemu-virt-ctrl.c | 122 +++++++++++++++++++++++++++
> 4 files changed, 139 insertions(+)
> create mode 100644 drivers/power/reset/qemu-virt-ctrl.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 55af015174a5..aa9eb8540637 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -21441,6 +21441,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 <visitorckw@xxxxxxxxx>
> +L: linux-pm@xxxxxxxxxxxxxxx
> +S: Maintained
> +F: drivers/power/reset/qemu-virt-ctrl.c
> +
> QLOGIC QL41xxx FCOE DRIVER
> M: Saurav Kashyap <skashyap@xxxxxxxxxxx>
> M: Javed Hasan <jhasan@xxxxxxxxxxx>
> diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
> index f6c1bcbb57de..99e3334726a5 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
> + tristate "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..f40d04afd4e3
> --- /dev/null
> +++ b/drivers/power/reset/qemu-virt-ctrl.c
> @@ -0,0 +1,122 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * QEMU Virt Machine System Controller Driver
> + *
> + * Copyright (C) 2026 Kuan-Wei Chiu <visitorckw@xxxxxxxxx>
> + */
> +
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/platform_device.h>
> +#include <linux/reboot.h>
> +
> +/* 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 reboot_nb;
> +};
> +
> +static inline void virt_ctrl_write32(u32 val, void __iomem *addr)
> +{
> + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
> + iowrite32be(val, addr);
> + else
> + iowrite32(val, addr);
> +}
> +
> +static int qemu_virt_ctrl_power_off(struct sys_off_data *data)
> +{
> + void __iomem *base = data->cb_data;
> +
> + virt_ctrl_write32(CMD_HALT, base + VIRT_CTRL_REG_CMD);
> +
> + return NOTIFY_DONE;
> +}
> +
> +static int qemu_virt_ctrl_restart(struct sys_off_data *data)
> +{
> + void __iomem *base = data->cb_data;
> +
> + virt_ctrl_write32(CMD_RESET, base + VIRT_CTRL_REG_CMD);
> +
> + return NOTIFY_DONE;
> +}
> +
> +static int qemu_virt_ctrl_reboot_notify(struct notifier_block *nb,
> + unsigned long action, void *data)
> +{
> + struct qemu_virt_ctrl *ctrl = container_of(nb, struct qemu_virt_ctrl, reboot_nb);
> +
> + if (action == SYS_HALT)
> + virt_ctrl_write32(CMD_HALT, ctrl->base + VIRT_CTRL_REG_CMD);
> +
> + return NOTIFY_DONE;
> +}
> +
> +static int qemu_virt_ctrl_probe(struct platform_device *pdev)
> +{
> + struct qemu_virt_ctrl *ctrl;
> + int ret;
> +
> + ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL);
> + if (!ctrl)
> + return -ENOMEM;
> +
> + ctrl->base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(ctrl->base))
> + return PTR_ERR(ctrl->base);
> +
> + ret = devm_register_sys_off_handler(&pdev->dev,
> + SYS_OFF_MODE_RESTART,
> + SYS_OFF_PRIO_DEFAULT,
> + qemu_virt_ctrl_restart,
> + ctrl->base);
> + if (ret)
> + return dev_err_probe(&pdev->dev, ret,
> + "cannot register restart handler\n");
> +
> + ret = devm_register_sys_off_handler(&pdev->dev,
> + SYS_OFF_MODE_POWER_OFF,
> + SYS_OFF_PRIO_DEFAULT,
> + qemu_virt_ctrl_power_off,
> + ctrl->base);
> + if (ret)
> + return dev_err_probe(&pdev->dev, ret,
> + "cannot register power-off handler\n");
> +
> + ctrl->reboot_nb.notifier_call = qemu_virt_ctrl_reboot_notify;
> + ret = devm_register_reboot_notifier(&pdev->dev, &ctrl->reboot_nb);
> + if (ret)
> + return dev_err_probe(&pdev->dev, ret, "cannot register reboot notifier\n");
> +
> + return 0;
> +}
> +
> +static const struct platform_device_id qemu_virt_ctrl_id[] = {
> + { "qemu-virt-ctrl", 0 },
> + { }
> +};
> +MODULE_DEVICE_TABLE(platform, qemu_virt_ctrl_id);
> +
> +static struct platform_driver qemu_virt_ctrl_driver = {
> + .probe = qemu_virt_ctrl_probe,
> + .driver = {
> + .name = "qemu-virt-ctrl",
> + },
> + .id_table = qemu_virt_ctrl_id,
> +};
> +module_platform_driver(qemu_virt_ctrl_driver);
> +
> +MODULE_AUTHOR("Kuan-Wei Chiu <visitorckw@xxxxxxxxx>");
> +MODULE_DESCRIPTION("QEMU Virt Machine System Controller Driver");
> +MODULE_LICENSE("GPL");
> --
> 2.53.0.345.g96ddfc5eaa-goog
>
Attachment:
signature.asc
Description: PGP signature