From: Igor Mammedov <imammedo@redhat.com>
To: qemu-devel@nongnu.org
Cc: mst@redhat.com, eauger@redhat.com, peter.maydell@linaro.org,
shannon.zhaosl@gmail.com, rad@semihalf.com,
leif.lindholm@oss.qualcomm.com, qemu-arm@nongnu.org
Subject: [PATCH v3 04/17] arm: virt: create sbsa-gwdt watchdog
Date: Wed, 24 Jun 2026 12:28:17 +0200 [thread overview]
Message-ID: <20260624102830.1355552-5-imammedo@redhat.com> (raw)
In-Reply-To: <20260624102830.1355552-1-imammedo@redhat.com>
Allow to use SBSA generic watchdog with virt machine type.
(includes conditional generation of corresponding FDT and
ACPI GTDT descriptors)
Use '-device sbsa-gwdt' to command line to enable it.
Instead of using dynamic sysbus infra to wire up MMIO/IRQ/FDT,
statically assign resources in machine's mem/irq maps and wire
them up at device (pre_)plug handlers. It's similar to dynamic
sysbus wiring, modulo resources are nailed down statically,
and wiring is limited to virt machine only.
(Benefit is that tests don't break anymore on rebase due to
address being stable)
Tested with Fedora 43:
FDT: -M virt,acpi=off -device sbsa-gwdt
ACPI: -M virt -device sbsa-gwdt
Note:
Windows sees GTDT, initializes watchdog but instead pinging WRR
it sets/advances WOR to way too large value, so it's never going
to trigger watchdog reboot (it's Windows driver issue though).
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
---
v3:
- (Eric) assign MMIO/IRQ statically and abandon most of
dynamic sysbus machinery.
- (Peter) set watchdog freq to system clock explicitly,
machine version compat won't work in case host is not runing
1GHz clock. (Tested on Jetson machine)
---
include/hw/arm/virt.h | 3 +++
hw/arm/Kconfig | 1 +
hw/arm/virt-acpi-build.c | 29 +++++++++++++++++++++++++++--
hw/arm/virt.c | 37 +++++++++++++++++++++++++++++++++++++
hw/core/sysbus-fdt.c | 2 ++
hw/watchdog/sbsa_gwdt.c | 1 +
6 files changed, 71 insertions(+), 2 deletions(-)
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 171d44c644..22e66d1a11 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -97,6 +97,9 @@ enum {
VIRT_NVDIMM_ACPI,
VIRT_PVTIME,
VIRT_ACPI_PCIHP,
+ VIRT_GWDT_WS0,
+ VIRT_GWDT_REFRESH,
+ VIRT_GWDT_CONTROL,
VIRT_LOWMEMMAP_LAST,
};
diff --git a/hw/arm/Kconfig b/hw/arm/Kconfig
index 500bfdfe2a..962a39247c 100644
--- a/hw/arm/Kconfig
+++ b/hw/arm/Kconfig
@@ -36,6 +36,7 @@ config ARM_VIRT
select VIRTIO_MEM_SUPPORTED
select ACPI_CXL
select ACPI_HMAT
+ select WDT_SBSA
config CUBIEBOARD
bool
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 99490aa7b1..f5b3b4ce48 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -64,6 +64,7 @@
#include "hw/virtio/virtio-acpi.h"
#include "target/arm/cpu.h"
#include "target/arm/multiprocessing.h"
+#include "hw/watchdog/sbsa_gwdt.h"
#include "smmuv3-accel.h"
#include "tegra241-cmdqv.h"
@@ -868,6 +869,8 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
const uint32_t irqflags = 0; /* Interrupt is Level triggered */
AcpiTable table = { .sig = "GTDT", .rev = 3, .oem_id = vms->oem_id,
.oem_table_id = vms->oem_table_id };
+ uint32_t gtdt_start = table_data->len;
+ Object *wdt = object_resolve_type_unambiguous(TYPE_WDT_SBSA, NULL);
acpi_table_begin(&table, table_data);
@@ -898,10 +901,15 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
build_append_int_noprefix(table_data, irqflags, 4);
/* CntReadBase Physical address */
build_append_int_noprefix(table_data, 0xFFFFFFFFFFFFFFFF, 8);
+
/* Platform Timer Count */
- build_append_int_noprefix(table_data, 0, 4);
+ build_append_int_noprefix(table_data, wdt ? 1 : 0, 4);
/* Platform Timer Offset */
- build_append_int_noprefix(table_data, 0, 4);
+ build_append_int_noprefix(table_data,
+ wdt ? (table_data->len - gtdt_start) +
+ 4 + 4 + 4 /* len of this & following 2 fields to skip */
+ : 0, 4);
+
if (vms->ns_el2_virt_timer_irq) {
/* Virtual EL2 Timer GSIV */
build_append_int_noprefix(table_data, ARCH_TIMER_NS_EL2_VIRT_IRQ, 4);
@@ -911,6 +919,23 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms)
build_append_int_noprefix(table_data, 0, 4);
build_append_int_noprefix(table_data, 0, 4);
}
+
+ /* ACPI 6.5 spec: 5.2.25.2 ARM Generic Watchdog Structure (Table 5-124) */
+ if (wdt) {
+ hwaddr rbase = vms->memmap[VIRT_GWDT_REFRESH].base;
+ hwaddr cbase = vms->memmap[VIRT_GWDT_CONTROL].base;
+ int irq = ARM_SPI_BASE + vms->irqmap[VIRT_GWDT_WS0];
+
+ build_append_int_noprefix(table_data, 1 /* Type: Watchdog GT */, 1);
+ build_append_int_noprefix(table_data, 28 /* Length */, 2);
+ build_append_int_noprefix(table_data, 0, 1); /* Reserved */
+ /* RefreshFrame Physical Address */
+ build_append_int_noprefix(table_data, rbase, 8);
+ /* WatchdogControlFrame Physical Address */
+ build_append_int_noprefix(table_data, cbase, 8);
+ build_append_int_noprefix(table_data, irq, 4); /* Watchdog Timer GSIV */
+ build_append_int_noprefix(table_data, 0, 4); /* Watchdog Timer Flags */
+ }
acpi_table_end(linker, &table);
}
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index d8d27f2ef6..aacf9b7251 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -95,6 +95,7 @@
#include "hw/cxl/cxl.h"
#include "hw/cxl/cxl_host.h"
#include "qemu/guest-random.h"
+#include "hw/watchdog/sbsa_gwdt.h"
static GlobalProperty arm_virt_compat_defaults[] = {
{ TYPE_VIRTIO_IOMMU_PCI, "aw-bits", "48" },
@@ -214,6 +215,8 @@ static const MemMapEntry base_memmap[] = {
/* ...repeating for a total of NUM_VIRTIO_TRANSPORTS, each of that size */
[VIRT_PLATFORM_BUS] = { 0x0c000000, 0x02000000 },
[VIRT_SECURE_MEM] = { 0x0e000000, 0x01000000 },
+ [VIRT_GWDT_REFRESH] = { 0x0f000000, 0x00001000 },
+ [VIRT_GWDT_CONTROL] = { 0x0f001000, 0x00001000 },
[VIRT_PCIE_MMIO] = { 0x10000000, 0x2eff0000 },
[VIRT_PCIE_PIO] = { 0x3eff0000, 0x00010000 },
[VIRT_PCIE_ECAM] = { 0x3f000000, 0x01000000 },
@@ -267,6 +270,7 @@ static const int a15irqmap[] = {
[VIRT_MMIO] = 16, /* ...to 16 + NUM_VIRTIO_TRANSPORTS - 1 */
[VIRT_GIC_V2M] = 48, /* ...to 48 + NUM_GICV2M_SPIS - 1 */
[VIRT_SMMU] = 74, /* ...to 74 + NUM_SMMU_IRQS - 1 */
+ [VIRT_GWDT_WS0] = 10,
[VIRT_PLATFORM_BUS] = 112, /* ...to 112 + PLATFORM_BUS_NUM_IRQS -1 */
};
@@ -3820,6 +3824,10 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev,
qlist_append_str(reserved_regions, resv_prop_str);
qdev_prop_set_array(dev, "reserved-regions", reserved_regions);
g_free(resv_prop_str);
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_WDT_SBSA)) {
+ uint64_t cntfrq = object_property_get_int(OBJECT(qemu_get_cpu(0)),
+ "cntfrq", &error_abort);
+ qdev_prop_set_uint64(dev, "clock-frequency", cntfrq);
} else if (object_dynamic_cast(OBJECT(dev), TYPE_ARM_SMMUV3)) {
if (vms->legacy_smmuv3_present || vms->iommu == VIRT_IOMMU_VIRTIO) {
error_setg(errp, "virt machine already has %s set. "
@@ -3871,6 +3879,34 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev,
{
VirtMachineState *vms = VIRT_MACHINE(hotplug_dev);
+ if (object_dynamic_cast(OBJECT(dev), TYPE_WDT_SBSA)) {
+ SysBusDevice *s = SYS_BUS_DEVICE(dev);
+ MachineState *ms = MACHINE(vms);
+ hwaddr rbase = vms->memmap[VIRT_GWDT_REFRESH].base;
+ hwaddr cbase = vms->memmap[VIRT_GWDT_CONTROL].base;
+ int irq = vms->irqmap[VIRT_GWDT_WS0];
+
+ sysbus_mmio_map(s, 0, rbase);
+ sysbus_mmio_map(s, 1, cbase);
+ sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq));
+
+ {
+ char *nodename = g_strdup_printf("/watchdog@%" PRIx64, cbase);
+
+ qemu_fdt_add_subnode(ms->fdt, nodename);
+ qemu_fdt_setprop_string(ms->fdt, nodename,
+ "compatible", "arm,sbsa-gwdt");
+ qemu_fdt_setprop_sized_cells(ms->fdt, nodename, "reg",
+ 2, cbase, 2, SBSA_GWDT_CMMIO_SIZE,
+ 2, rbase, 2, SBSA_GWDT_RMMIO_SIZE);
+ qemu_fdt_setprop_cells(ms->fdt, nodename, "interrupts",
+ GIC_FDT_IRQ_TYPE_SPI, irq,
+ GIC_FDT_IRQ_FLAGS_LEVEL_HI);
+ qemu_fdt_setprop_cell(ms->fdt, nodename, "timeout-sec", 30);
+ g_free(nodename);
+ }
+ }
+
if (vms->platform_bus_dev) {
MachineClass *mc = MACHINE_GET_CLASS(vms);
@@ -4123,6 +4159,7 @@ static void virt_machine_class_init(ObjectClass *oc, const void *data)
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_RAMFB_DEVICE);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_UEFI_VARS_SYSBUS);
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_ARM_SMMUV3);
+ machine_class_allow_dynamic_sysbus_dev(mc, TYPE_WDT_SBSA);
#ifdef CONFIG_TPM
machine_class_allow_dynamic_sysbus_dev(mc, TYPE_TPM_TIS_SYSBUS);
#endif
diff --git a/hw/core/sysbus-fdt.c b/hw/core/sysbus-fdt.c
index 89d0c46445..12238570b5 100644
--- a/hw/core/sysbus-fdt.c
+++ b/hw/core/sysbus-fdt.c
@@ -36,6 +36,7 @@
#include "hw/display/ramfb.h"
#include "hw/uefi/var-service-api.h"
#include "hw/arm/fdt.h"
+#include "hw/watchdog/sbsa_gwdt.h"
/*
* internal struct that contains the information to create dynamic
@@ -140,6 +141,7 @@ static const BindingEntry bindings[] = {
TYPE_BINDING(TYPE_ARM_SMMUV3, no_fdt_node),
TYPE_BINDING(TYPE_RAMFB_DEVICE, no_fdt_node),
TYPE_BINDING(TYPE_UEFI_VARS_SYSBUS, add_uefi_vars_node),
+ TYPE_BINDING(TYPE_WDT_SBSA, no_fdt_node),
TYPE_BINDING("", NULL), /* last element */
};
diff --git a/hw/watchdog/sbsa_gwdt.c b/hw/watchdog/sbsa_gwdt.c
index acb970e8b3..c4dd8005b7 100644
--- a/hw/watchdog/sbsa_gwdt.c
+++ b/hw/watchdog/sbsa_gwdt.c
@@ -285,6 +285,7 @@ static void wdt_sbsa_gwdt_class_init(ObjectClass *klass, const void *data)
dc->realize = wdt_sbsa_gwdt_realize;
device_class_set_legacy_reset(dc, wdt_sbsa_gwdt_reset);
dc->hotpluggable = false;
+ dc->user_creatable = true;
set_bit(DEVICE_CATEGORY_WATCHDOG, dc->categories);
dc->vmsd = &vmstate_sbsa_gwdt;
dc->desc = "SBSA-compliant generic watchdog device";
--
2.47.3
next prev parent reply other threads:[~2026-06-24 10:29 UTC|newest]
Thread overview: 32+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-24 10:28 [PATCH v3 00/17] Add watchdog support to arm/virt board Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 01/17] arm: sbsa_gwdt: fixup default "clock-frequency" Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 02/17] arm: add tracing events to sbsa_gwdt Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 03/17] arm: sbsa_gwdt: rename device type to sbsa-gwdt Igor Mammedov
2026-06-29 8:12 ` Eric Auger
2026-06-24 10:28 ` Igor Mammedov [this message]
2026-06-29 8:37 ` [PATCH v3 04/17] arm: virt: create sbsa-gwdt watchdog Eric Auger
2026-06-29 13:36 ` Igor Mammedov
2026-07-01 11:57 ` Eric Auger
2026-07-01 13:24 ` Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 05/17] arm: sbsa-gwdt: add 'wdat' option Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 06/17] acpi: introduce WDAT table for GWDT Igor Mammedov
2026-06-29 12:07 ` Eric Auger
2026-06-24 10:28 ` [PATCH v3 07/17] arm: virt: add support for WDAT based watchdog Igor Mammedov
2026-06-29 12:15 ` Eric Auger
2026-06-24 10:28 ` [PATCH v3 08/17] tests: acpi: arm/virt: whitelist new WDAT table Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 09/17] tests: acpi: arm/virt: add WDAT table test case Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 10/17] tests: acpi: arm/virt: update expected WDAT blob Igor Mammedov
2026-06-29 12:16 ` Eric Auger
2026-06-24 10:28 ` [PATCH v3 11/17] tests: acpi: arm/virt: whitelist GTDT table Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 12/17] tests: acpi: arm/virt: add GTDT watchdog table test case Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 13/17] tests: acpi: arm/virt: update expected GTDT blob Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 14/17] sbsa-gwdt: reduce code ident Igor Mammedov
2026-06-24 10:28 ` [PATCH v3 15/17] sbsa-gwdt: move all foo_REFRESH logic under REFRESH condition Igor Mammedov
2026-06-29 14:03 ` Eric Auger
2026-06-29 14:51 ` Peter Maydell
2026-06-24 10:28 ` [PATCH v3 16/17] sbsa-gwdt: reschedule timer on direct WCV load Igor Mammedov
2026-06-29 14:08 ` Eric Auger
2026-06-24 10:28 ` [PATCH v3 17/17] sbsa-gwdt: limit compare_value to INT64_MAX Igor Mammedov
2026-06-29 14:10 ` Eric Auger
2026-06-29 14:48 ` Peter Maydell
2026-06-30 12:14 ` Igor Mammedov
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260624102830.1355552-5-imammedo@redhat.com \
--to=imammedo@redhat.com \
--cc=eauger@redhat.com \
--cc=leif.lindholm@oss.qualcomm.com \
--cc=mst@redhat.com \
--cc=peter.maydell@linaro.org \
--cc=qemu-arm@nongnu.org \
--cc=qemu-devel@nongnu.org \
--cc=rad@semihalf.com \
--cc=shannon.zhaosl@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.