|
@@ -217,6 +217,26 @@ static const VMStateDescription vmstate_cpuhp_state = {
|
|
|
}
|
|
|
};
|
|
|
|
|
|
+static bool vmstate_test_use_pcihp(void *opaque)
|
|
|
+{
|
|
|
+ ICH9LPCPMRegs *s = opaque;
|
|
|
+
|
|
|
+ return s->use_acpi_hotplug_bridge;
|
|
|
+}
|
|
|
+
|
|
|
+static const VMStateDescription vmstate_pcihp_state = {
|
|
|
+ .name = "ich9_pm/pcihp",
|
|
|
+ .version_id = 1,
|
|
|
+ .minimum_version_id = 1,
|
|
|
+ .needed = vmstate_test_use_pcihp,
|
|
|
+ .fields = (VMStateField[]) {
|
|
|
+ VMSTATE_PCI_HOTPLUG(acpi_pci_hotplug,
|
|
|
+ ICH9LPCPMRegs,
|
|
|
+ NULL, NULL),
|
|
|
+ VMSTATE_END_OF_LIST()
|
|
|
+ }
|
|
|
+};
|
|
|
+
|
|
|
const VMStateDescription vmstate_ich9_pm = {
|
|
|
.name = "ich9_pm",
|
|
|
.version_id = 1,
|
|
@@ -238,6 +258,7 @@ const VMStateDescription vmstate_ich9_pm = {
|
|
|
&vmstate_memhp_state,
|
|
|
&vmstate_tco_io_state,
|
|
|
&vmstate_cpuhp_state,
|
|
|
+ &vmstate_pcihp_state,
|
|
|
NULL
|
|
|
}
|
|
|
};
|
|
@@ -259,6 +280,10 @@ static void pm_reset(void *opaque)
|
|
|
}
|
|
|
pm->smi_en_wmask = ~0;
|
|
|
|
|
|
+ if (pm->use_acpi_hotplug_bridge) {
|
|
|
+ acpi_pcihp_reset(&pm->acpi_pci_hotplug, true);
|
|
|
+ }
|
|
|
+
|
|
|
acpi_update_sci(&pm->acpi_regs, pm->irq);
|
|
|
}
|
|
|
|
|
@@ -297,6 +322,18 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm,
|
|
|
pm->enable_tco = true;
|
|
|
acpi_pm_tco_init(&pm->tco_regs, &pm->io);
|
|
|
|
|
|
+ if (pm->use_acpi_hotplug_bridge) {
|
|
|
+ acpi_pcihp_init(OBJECT(lpc_pci),
|
|
|
+ &pm->acpi_pci_hotplug,
|
|
|
+ pci_get_bus(lpc_pci),
|
|
|
+ pci_address_space_io(lpc_pci),
|
|
|
+ true,
|
|
|
+ ACPI_PCIHP_ADDR_ICH9);
|
|
|
+
|
|
|
+ qbus_set_hotplug_handler(BUS(pci_get_bus(lpc_pci)),
|
|
|
+ OBJECT(lpc_pci));
|
|
|
+ }
|
|
|
+
|
|
|
pm->irq = sci_irq;
|
|
|
qemu_register_reset(pm_reset, pm);
|
|
|
pm->powerdown_notifier.notify = pm_powerdown_req;
|
|
@@ -368,6 +405,20 @@ static void ich9_pm_set_enable_tco(Object *obj, bool value, Error **errp)
|
|
|
s->pm.enable_tco = value;
|
|
|
}
|
|
|
|
|
|
+static bool ich9_pm_get_acpi_pci_hotplug(Object *obj, Error **errp)
|
|
|
+{
|
|
|
+ ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
|
|
|
+
|
|
|
+ return s->pm.use_acpi_hotplug_bridge;
|
|
|
+}
|
|
|
+
|
|
|
+static void ich9_pm_set_acpi_pci_hotplug(Object *obj, bool value, Error **errp)
|
|
|
+{
|
|
|
+ ICH9LPCState *s = ICH9_LPC_DEVICE(obj);
|
|
|
+
|
|
|
+ s->pm.use_acpi_hotplug_bridge = value;
|
|
|
+}
|
|
|
+
|
|
|
void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm)
|
|
|
{
|
|
|
static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN;
|
|
@@ -376,6 +427,7 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm)
|
|
|
pm->disable_s3 = 0;
|
|
|
pm->disable_s4 = 0;
|
|
|
pm->s4_val = 2;
|
|
|
+ pm->use_acpi_hotplug_bridge = false;
|
|
|
|
|
|
object_property_add_uint32_ptr(obj, ACPI_PM_PROP_PM_IO_BASE,
|
|
|
&pm->pm_io_base, OBJ_PROP_FLAG_READ);
|
|
@@ -399,6 +451,9 @@ void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm)
|
|
|
object_property_add_bool(obj, ACPI_PM_PROP_TCO_ENABLED,
|
|
|
ich9_pm_get_enable_tco,
|
|
|
ich9_pm_set_enable_tco);
|
|
|
+ object_property_add_bool(obj, "acpi-pci-hotplug-with-bridge-support",
|
|
|
+ ich9_pm_get_acpi_pci_hotplug,
|
|
|
+ ich9_pm_set_acpi_pci_hotplug);
|
|
|
}
|
|
|
|
|
|
void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|
@@ -406,6 +461,11 @@ void ich9_pm_device_pre_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|
|
{
|
|
|
ICH9LPCState *lpc = ICH9_LPC_DEVICE(hotplug_dev);
|
|
|
|
|
|
+ if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
|
|
|
+ acpi_pcihp_device_pre_plug_cb(hotplug_dev, dev, errp);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
if (object_dynamic_cast(OBJECT(dev), TYPE_PC_DIMM) &&
|
|
|
!lpc->pm.acpi_memory_hotplug.is_enabled) {
|
|
|
error_setg(errp,
|
|
@@ -441,6 +501,9 @@ void ich9_pm_device_plug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|
|
} else {
|
|
|
acpi_cpu_plug_cb(hotplug_dev, &lpc->pm.cpuhp_state, dev, errp);
|
|
|
}
|
|
|
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
|
|
|
+ acpi_pcihp_device_plug_cb(hotplug_dev, &lpc->pm.acpi_pci_hotplug,
|
|
|
+ dev, errp);
|
|
|
} else {
|
|
|
error_setg(errp, "acpi: device plug request for not supported device"
|
|
|
" type: %s", object_get_typename(OBJECT(dev)));
|
|
@@ -473,6 +536,10 @@ void ich9_pm_device_unplug_request_cb(HotplugHandler *hotplug_dev,
|
|
|
|
|
|
acpi_cpu_unplug_request_cb(hotplug_dev, &lpc->pm.cpuhp_state,
|
|
|
dev, errp);
|
|
|
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
|
|
|
+ acpi_pcihp_device_unplug_request_cb(hotplug_dev,
|
|
|
+ &lpc->pm.acpi_pci_hotplug,
|
|
|
+ dev, errp);
|
|
|
} else {
|
|
|
error_setg(errp, "acpi: device unplug request for not supported device"
|
|
|
" type: %s", object_get_typename(OBJECT(dev)));
|
|
@@ -490,6 +557,9 @@ void ich9_pm_device_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|
|
} else if (object_dynamic_cast(OBJECT(dev), TYPE_CPU) &&
|
|
|
!lpc->pm.cpu_hotplug_legacy) {
|
|
|
acpi_cpu_unplug_cb(&lpc->pm.cpuhp_state, dev, errp);
|
|
|
+ } else if (object_dynamic_cast(OBJECT(dev), TYPE_PCI_DEVICE)) {
|
|
|
+ acpi_pcihp_device_unplug_cb(hotplug_dev, &lpc->pm.acpi_pci_hotplug,
|
|
|
+ dev, errp);
|
|
|
} else {
|
|
|
error_setg(errp, "acpi: device unplug for not supported device"
|
|
|
" type: %s", object_get_typename(OBJECT(dev)));
|