mirror of
https://github.com/qemu/qemu.git
synced 2026-07-08 17:56:38 +00:00
arm: virt: add support for WDAT based watchdog
Add WDAT handling for sbsa-gwdt on arm/virt machine. WDAT mode is enabled by 'wdat' option: ex: "-device sbsa-gwdt,wdat=on" When WDAT is enabled: - Build the WDAT ACPI table instead of the GTDT watchdog entry, since they are mutually exclusive due to different timer resolution (WDAT uses 1 kHz vs GTDT's system counter frequency). - Skip FDT watchdog node creation, as the DT-based Linux driver would use the system counter frequency which doesn't match the WDAT-mode 1 kHz clock. Signed-off-by: Igor Mammedov <imammedo@redhat.com> Reviewed-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Message-ID: <20260702145856.1539572-8-imammedo@redhat.com>
This commit is contained in:
committed by
Michael S. Tsirkin
parent
beadd272c1
commit
285bc90d5b
@@ -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
|
||||
""""""""""""""""""""""""""""""""
|
||||
|
||||
|
||||
@@ -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);
|
||||
{
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user