Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

power: reset: Add QEMU virt-ctrl driver

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@gmail.com>
Acked-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Link: https://patch.msgid.link/20260412211952.3564033-2-visitorckw@gmail.com
Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>

authored by

Kuan-Wei Chiu and committed by
Geert Uytterhoeven
ad9d2cd0 cbd3b8ef

+139
+6
MAINTAINERS
··· 21441 21441 F: drivers/firmware/qemu_fw_cfg.c 21442 21442 F: include/uapi/linux/qemu_fw_cfg.h 21443 21443 21444 + QEMU VIRT MACHINE SYSTEM CONTROLLER DRIVER 21445 + M: Kuan-Wei Chiu <visitorckw@gmail.com> 21446 + L: linux-pm@vger.kernel.org 21447 + S: Maintained 21448 + F: drivers/power/reset/qemu-virt-ctrl.c 21449 + 21444 21450 QLOGIC QL41xxx FCOE DRIVER 21445 21451 M: Saurav Kashyap <skashyap@marvell.com> 21446 21452 M: Javed Hasan <jhasan@marvell.com>
+10
drivers/power/reset/Kconfig
··· 354 354 help 355 355 This driver supports reset or low power mode handling for Mellanox BlueField. 356 356 357 + config POWER_RESET_QEMU_VIRT_CTRL 358 + tristate "QEMU Virt Machine System Controller" 359 + depends on HAS_IOMEM 360 + help 361 + This driver supports the system reset and power off functionality 362 + provided by the QEMU 'virt-ctrl' device. 363 + 364 + Say Y here if you are running Linux on a QEMU virtual machine that 365 + provides this controller, such as the m68k virt machine. 366 + 357 367 endif
+1
drivers/power/reset/Makefile
··· 41 41 obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o 42 42 obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o 43 43 obj-$(CONFIG_POWER_MLXBF) += pwr-mlxbf.o 44 + obj-$(CONFIG_POWER_RESET_QEMU_VIRT_CTRL) += qemu-virt-ctrl.o
+122
drivers/power/reset/qemu-virt-ctrl.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * QEMU Virt Machine System Controller Driver 4 + * 5 + * Copyright (C) 2026 Kuan-Wei Chiu <visitorckw@gmail.com> 6 + */ 7 + 8 + #include <linux/io.h> 9 + #include <linux/module.h> 10 + #include <linux/mod_devicetable.h> 11 + #include <linux/platform_device.h> 12 + #include <linux/reboot.h> 13 + 14 + /* Registers */ 15 + #define VIRT_CTRL_REG_FEATURES 0x00 16 + #define VIRT_CTRL_REG_CMD 0x04 17 + 18 + /* Commands */ 19 + #define CMD_NOOP 0 20 + #define CMD_RESET 1 21 + #define CMD_HALT 2 22 + #define CMD_PANIC 3 23 + 24 + struct qemu_virt_ctrl { 25 + void __iomem *base; 26 + struct notifier_block reboot_nb; 27 + }; 28 + 29 + static inline void virt_ctrl_write32(u32 val, void __iomem *addr) 30 + { 31 + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) 32 + iowrite32be(val, addr); 33 + else 34 + iowrite32(val, addr); 35 + } 36 + 37 + static int qemu_virt_ctrl_power_off(struct sys_off_data *data) 38 + { 39 + struct qemu_virt_ctrl *ctrl = data->cb_data; 40 + 41 + virt_ctrl_write32(CMD_HALT, ctrl->base + VIRT_CTRL_REG_CMD); 42 + 43 + return NOTIFY_DONE; 44 + } 45 + 46 + static int qemu_virt_ctrl_restart(struct sys_off_data *data) 47 + { 48 + struct qemu_virt_ctrl *ctrl = data->cb_data; 49 + 50 + virt_ctrl_write32(CMD_RESET, ctrl->base + VIRT_CTRL_REG_CMD); 51 + 52 + return NOTIFY_DONE; 53 + } 54 + 55 + static int qemu_virt_ctrl_reboot_notify(struct notifier_block *nb, 56 + unsigned long action, void *data) 57 + { 58 + struct qemu_virt_ctrl *ctrl = container_of(nb, struct qemu_virt_ctrl, reboot_nb); 59 + 60 + if (action == SYS_HALT) 61 + virt_ctrl_write32(CMD_HALT, ctrl->base + VIRT_CTRL_REG_CMD); 62 + 63 + return NOTIFY_DONE; 64 + } 65 + 66 + static int qemu_virt_ctrl_probe(struct platform_device *pdev) 67 + { 68 + struct qemu_virt_ctrl *ctrl; 69 + int ret; 70 + 71 + ctrl = devm_kzalloc(&pdev->dev, sizeof(*ctrl), GFP_KERNEL); 72 + if (!ctrl) 73 + return -ENOMEM; 74 + 75 + ctrl->base = devm_platform_ioremap_resource(pdev, 0); 76 + if (IS_ERR(ctrl->base)) 77 + return PTR_ERR(ctrl->base); 78 + 79 + ret = devm_register_sys_off_handler(&pdev->dev, 80 + SYS_OFF_MODE_RESTART, 81 + SYS_OFF_PRIO_DEFAULT, 82 + qemu_virt_ctrl_restart, 83 + ctrl); 84 + if (ret) 85 + return dev_err_probe(&pdev->dev, ret, 86 + "cannot register restart handler\n"); 87 + 88 + ret = devm_register_sys_off_handler(&pdev->dev, 89 + SYS_OFF_MODE_POWER_OFF, 90 + SYS_OFF_PRIO_DEFAULT, 91 + qemu_virt_ctrl_power_off, 92 + ctrl); 93 + if (ret) 94 + return dev_err_probe(&pdev->dev, ret, 95 + "cannot register power-off handler\n"); 96 + 97 + ctrl->reboot_nb.notifier_call = qemu_virt_ctrl_reboot_notify; 98 + ret = devm_register_reboot_notifier(&pdev->dev, &ctrl->reboot_nb); 99 + if (ret) 100 + return dev_err_probe(&pdev->dev, ret, "cannot register reboot notifier\n"); 101 + 102 + return 0; 103 + } 104 + 105 + static const struct platform_device_id qemu_virt_ctrl_id[] = { 106 + { "qemu-virt-ctrl", 0 }, 107 + { } 108 + }; 109 + MODULE_DEVICE_TABLE(platform, qemu_virt_ctrl_id); 110 + 111 + static struct platform_driver qemu_virt_ctrl_driver = { 112 + .probe = qemu_virt_ctrl_probe, 113 + .driver = { 114 + .name = "qemu-virt-ctrl", 115 + }, 116 + .id_table = qemu_virt_ctrl_id, 117 + }; 118 + module_platform_driver(qemu_virt_ctrl_driver); 119 + 120 + MODULE_AUTHOR("Kuan-Wei Chiu <visitorckw@gmail.com>"); 121 + MODULE_DESCRIPTION("QEMU Virt Machine System Controller Driver"); 122 + MODULE_LICENSE("GPL");