Skip to content

Commit ad9d2cd

Browse files
visitorckwgeertu
authored andcommitted
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>
1 parent cbd3b8e commit ad9d2cd

4 files changed

Lines changed: 139 additions & 0 deletions

File tree

MAINTAINERS

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21441,6 +21441,12 @@ S: Maintained
2144121441
F: drivers/firmware/qemu_fw_cfg.c
2144221442
F: include/uapi/linux/qemu_fw_cfg.h
2144321443

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+
2144421450
QLOGIC QL41xxx FCOE DRIVER
2144521451
M: Saurav Kashyap <skashyap@marvell.com>
2144621452
M: Javed Hasan <jhasan@marvell.com>

drivers/power/reset/Kconfig

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,4 +354,14 @@ config POWER_MLXBF
354354
help
355355
This driver supports reset or low power mode handling for Mellanox BlueField.
356356

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+
357367
endif

drivers/power/reset/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,4 @@ obj-$(CONFIG_SYSCON_REBOOT_MODE) += syscon-reboot-mode.o
4141
obj-$(CONFIG_POWER_RESET_SC27XX) += sc27xx-poweroff.o
4242
obj-$(CONFIG_NVMEM_REBOOT_MODE) += nvmem-reboot-mode.o
4343
obj-$(CONFIG_POWER_MLXBF) += pwr-mlxbf.o
44+
obj-$(CONFIG_POWER_RESET_QEMU_VIRT_CTRL) += qemu-virt-ctrl.o
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
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");

0 commit comments

Comments
 (0)