diff --git a/docs/system/arm/virt.rst b/docs/system/arm/virt.rst index bf5a9c8f6c..5f6dd17978 100644 --- a/docs/system/arm/virt.rst +++ b/docs/system/arm/virt.rst @@ -323,6 +323,21 @@ using ``-device sbsa-gwdt``. It is only supported on the virt machine, which wires up statically assigned MMIO regions and IRQs via machine-specific plug handlers. +Two modes are available: + +Native mode (default) + The watchdog is described via the ACPI GTDT table and FDT, using + the system counter frequency. Example:: + + -device sbsa-gwdt + +WDAT mode + The watchdog is described via the ACPI WDAT table (no FDT node), + using a 1 kHz timer frequency. WDAT and GTDT watchdog entries are + mutually exclusive. Example:: + + -device sbsa-gwdt,wdat=on + Linux guest kernel configuration """""""""""""""""""""""""""""""" diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c index f5b3b4ce48..f6386088b6 100644 --- a/hw/arm/virt-acpi-build.c +++ b/hw/arm/virt-acpi-build.c @@ -65,6 +65,7 @@ #include "target/arm/cpu.h" #include "target/arm/multiprocessing.h" #include "hw/watchdog/sbsa_gwdt.h" +#include "hw/acpi/wdat-gwdt.h" #include "smmuv3-accel.h" #include "tegra241-cmdqv.h" @@ -859,7 +860,8 @@ build_srat(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) * 5.2.25 Generic Timer Description Table (GTDT) */ static void -build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) +build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms, + bool add_watchdog) { /* * Table 5-117 Flag Definitions @@ -870,7 +872,6 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) 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); @@ -903,12 +904,12 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) build_append_int_noprefix(table_data, 0xFFFFFFFFFFFFFFFF, 8); /* Platform Timer Count */ - build_append_int_noprefix(table_data, wdt ? 1 : 0, 4); + build_append_int_noprefix(table_data, add_watchdog ? 1 : 0, 4); /* Platform Timer Offset */ 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); + add_watchdog ? (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 */ @@ -921,7 +922,7 @@ build_gtdt(GArray *table_data, BIOSLinker *linker, VirtMachineState *vms) } /* ACPI 6.5 spec: 5.2.25.2 ARM Generic Watchdog Structure (Table 5-124) */ - if (wdt) { + if (add_watchdog) { 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]; @@ -1332,13 +1333,19 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) VirtMachineClass *vmc = VIRT_MACHINE_GET_CLASS(vms); GArray *table_offsets; unsigned dsdt, xsdt; + bool has_wdat = false; GArray *tables_blob = tables->table_data; MachineState *ms = MACHINE(vms); CPUCoreCaches caches[CPU_MAX_CACHES]; unsigned int num_caches; + Object *wdt = object_resolve_type_unambiguous(TYPE_WDT_SBSA, NULL); num_caches = virt_get_caches(vms, caches); + if (wdt) { + has_wdat = object_property_get_bool(wdt, "wdat", &error_abort); + } + table_offsets = g_array_new(false, true /* clear */, sizeof(uint32_t)); @@ -1357,6 +1364,17 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) acpi_add_table(table_offsets, tables_blob); build_madt(tables_blob, tables->linker, vms); + acpi_add_table(table_offsets, tables_blob); + if (wdt && has_wdat) { + uint64_t freq = object_property_get_uint(wdt, "clock-frequency", + &error_abort); + build_gwdt_wdat(tables_blob, tables->linker, + vms->oem_id, vms->oem_table_id, + vms->memmap[VIRT_GWDT_REFRESH].base, + vms->memmap[VIRT_GWDT_CONTROL].base, + freq); + } + if (!vmc->no_cpu_topology) { acpi_add_table(table_offsets, tables_blob); build_pptt(tables_blob, tables->linker, ms, vms->oem_id, @@ -1364,7 +1382,7 @@ void virt_acpi_build(VirtMachineState *vms, AcpiBuildTables *tables) } acpi_add_table(table_offsets, tables_blob); - build_gtdt(tables_blob, tables->linker, vms); + build_gtdt(tables_blob, tables->linker, vms, wdt && !has_wdat); acpi_add_table(table_offsets, tables_blob); { diff --git a/hw/arm/virt.c b/hw/arm/virt.c index eabc5274d5..fb916c341b 100644 --- a/hw/arm/virt.c +++ b/hw/arm/virt.c @@ -3846,10 +3846,12 @@ static void virt_machine_device_pre_plug_cb(HotplugHandler *hotplug_dev, 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); + if (!object_property_get_bool(OBJECT(dev), "wdat", &error_abort)) { + uint64_t cntfrq = object_property_get_int(OBJECT(qemu_get_cpu(0)), + "cntfrq", &error_abort); - qdev_prop_set_uint64(dev, "clock-frequency", cntfrq); + 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. " @@ -3911,7 +3913,9 @@ static void virt_machine_device_plug_cb(HotplugHandler *hotplug_dev, sysbus_mmio_map(s, 1, cbase); sysbus_connect_irq(s, 0, qdev_get_gpio_in(vms->gic, irq)); - create_gwdt_dt_bindings(vms); + if (!object_property_get_bool(OBJECT(dev), "wdat", &error_abort)) { + create_gwdt_dt_bindings(vms); + } } if (vms->platform_bus_dev) {