How to fix this chicken & egg issue?
Signed-off-by: Eric Auger <eric.au...@redhat.com>
---
v1 -> v2:
- use ACPI_PCIHP_REGION_NAME
---
include/hw/arm/virt.h | 1 +
hw/arm/virt-acpi-build.c | 1 +
hw/arm/virt.c | 42 +++++++++++++++++++++++++++++++++++-----
3 files changed, 39 insertions(+), 5 deletions(-)
diff --git a/include/hw/arm/virt.h b/include/hw/arm/virt.h
index 1b2e2e1284..a4c4e3a67a 100644
--- a/include/hw/arm/virt.h
+++ b/include/hw/arm/virt.h
@@ -35,6 +35,7 @@
#include "hw/boards.h"
#include "hw/arm/boot.h"
#include "hw/arm/bsa.h"
+#include "hw/acpi/pcihp.h"
#include "hw/block/flash.h"
#include "system/kvm.h"
#include "hw/intc/arm_gicv3_common.h"
diff --git a/hw/arm/virt-acpi-build.c b/hw/arm/virt-acpi-build.c
index 9d88ffc318..cd49f67d60 100644
--- a/hw/arm/virt-acpi-build.c
+++ b/hw/arm/virt-acpi-build.c
@@ -44,6 +44,7 @@
#include "hw/acpi/generic_event_device.h"
#include "hw/acpi/tpm.h"
#include "hw/acpi/hmat.h"
+#include "hw/acpi/pcihp.h"
#include "hw/pci/pcie_host.h"
#include "hw/pci/pci.h"
#include "hw/pci/pci_bus.h"
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
index 4aa40c8e8b..cdcff0a984 100644
--- a/hw/arm/virt.c
+++ b/hw/arm/virt.c
@@ -682,6 +682,8 @@ static inline DeviceState *create_acpi_ged(VirtMachineState
*vms)
{
DeviceState *dev;
MachineState *ms = MACHINE(vms);
+ SysBusDevice *sbdev;
+
int irq = vms->irqmap[VIRT_ACPI_GED];
uint32_t event = ACPI_GED_PWR_DOWN_EVT;
@@ -693,12 +695,28 @@ static inline DeviceState
*create_acpi_ged(VirtMachineState *vms)
event |= ACPI_GED_NVDIMM_HOTPLUG_EVT;
}
+ if (vms->acpi_pcihp) {
+ event |= ACPI_GED_PCI_HOTPLUG_EVT;
+ }
+
dev = qdev_new(TYPE_ACPI_GED);
qdev_prop_set_uint32(dev, "ged-event", event);
- sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+ sbdev = SYS_BUS_DEVICE(dev);
+ sysbus_realize_and_unref(sbdev, &error_fatal);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, vms->memmap[VIRT_ACPI_GED].base);
- sysbus_mmio_map(SYS_BUS_DEVICE(dev), 1,
vms->memmap[VIRT_PCDIMM_ACPI].base);
+ sysbus_mmio_map(sbdev, 0, vms->memmap[VIRT_ACPI_GED].base);
+ sysbus_mmio_map(sbdev, 1, vms->memmap[VIRT_PCDIMM_ACPI].base);
Perhaps move out sbdev renaming into a separate patch, as it's not really
related.
+ if (vms->acpi_pcihp) {
+ AcpiGedState *acpi_ged_state = ACPI_GED(dev);
+ int i;
+
+ i = sysbus_mmio_map_name(sbdev, ACPI_PCIHP_REGION_NAME,
+ vms->memmap[VIRT_ACPI_PCIHP].base);
I don't like mix of old way (index based) above and new name based mapping,
can we use the same, please?
+ assert(i >= 0);
g_assert(sysbus_mmio_map_name...) to get more meaning-full crash
that is not compiled out.
+ acpi_pcihp_init(OBJECT(dev), &acpi_ged_state->pcihp_state,
+ vms->bus, sysbus_mmio_get_region(sbdev, i), 0);
hmm, looks broken..
region mapping must happen after acpi_pcihp_init().
if we after making sysbus_mmio_map() sane and easier to use
(which is a bit on tangent to this series).
We could feed sysbus owner device a memory map (ex: name based),
and then use [pre_]plug handlers on sysbus to map children
automatically.
That will alleviate need to do all mapping manually in every board.
(frankly speaking it deserves its own series, with tree wide cleanup).
As it is I'd use old index based approach like the rest.
(unless you feel adventurous about sysbus refactoring)
+ acpi_ged_state->pcihp_state.use_acpi_hotplug_bridge = true;
+ }
sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, qdev_get_gpio_in(vms->gic,
irq));
return dev;
@@ -1758,6 +1776,13 @@ void virt_machine_done(Notifier *notifier, void *data)
pci_bus_add_fw_cfg_extra_pci_roots(vms->fw_cfg, vms->bus,
&error_abort);
+
+ if (vms->acpi_pcihp) {
+ AcpiGedState *acpi_ged_state = ACPI_GED(vms->acpi_dev);
+
+ acpi_pcihp_reset(&acpi_ged_state->pcihp_state);
+ }
+
virt_acpi_setup(vms);
virt_build_smbios(vms);
}
@@ -2395,8 +2420,6 @@ static void machvirt_init(MachineState *machine)
create_rtc(vms);
- create_pcie(vms);
-
if (has_ged && aarch64 && firmware_loaded && virt_is_acpi_enabled(vms)) {
vms->acpi_pcihp &= !vmc->no_acpi_pcihp;
vms->acpi_dev = create_acpi_ged(vms);
@@ -2405,6 +2428,15 @@ static void machvirt_init(MachineState *machine)
create_gpio_devices(vms, VIRT_GPIO, sysmem);
}
+ create_pcie(vms);
+
+ if (vms->acpi_dev) {
+ AcpiGedState *acpi_ged_state = ACPI_GED(vms->acpi_dev);
+
+ acpi_ged_state = ACPI_GED(vms->acpi_dev);
+ acpi_ged_state->pcihp_state.root = vms->bus;
+ }
+
if (vms->secure && !vmc->no_secure_gpio) {
create_gpio_devices(vms, VIRT_SECURE_GPIO, secure_sysmem);
}
I don't like pulling acpi_pcihp_init()/reset (and issues it causes) into board
code,
on x86 it's a part of host bridge device model.
The same should apply to GED device.
The only thing board has to do is map regions into IO space like we do
everywhere else.
with current code, may be add link<pci_bus> property to GED,
and set it before GED realize in create_acpi_ged(),
then just follow existing sysbus_mmio_map() pattern.